*E@gVISwZ*@+mTR} zgNoneJumpPad ShowMessage JumpPadFX TraceGround GetAngle JumpEffects swJumpPad JumpPadDebugGetIdentifier JumpSounds CalcVelocityTouchTrigger MaxAngleMinAngleFinderMinAngleCurve JumpWait JumpEvent bTraceGround JumpAngle AM_Owned AM_ExtremesSpecialHandling AM_RandomSetFallCore JumpSound MinAngleSystem ExtraCostEngine bDirectionalbStaticCollisionHeightCollisionRadius PostTouchBroadcastMessageAcceptPostBeginPlay LevelInfo ZoneInfo TeleporterTimeGetPropertyText ReturnValueOriginBS ScriptTextiPitchZANavigationPointPlayerReplicationInfoLevelActorPhysicsPawn bEnabledTeamDesiredRotationJumpZ Location PointRegion ZoneGravitySoundOtherURLPRole Acceleration Velocity PlayerNameTag TouchingRegion InstigatorZonespeed PendingTouchClass TimeSecondsNetMode Incoming bJumpOffPawnSource TeamNumber MoveTimer Destination MoveTargetFocusBot bDisabledPackage TargetDistjumpDirPickupsBootJmpBotpack StrPropertyStructProperty EAngleModeConstUnrealINameClassProperty TextBuffer bTeamOnlyTargetZOffset TargetRandObject AngleRandAngleRandMode NameProperty JumpEffectJumpPlayerEffectEnumbClientSideEffectsObjectProperty Function bLogParams JumpTarget JumpActor bSwitchAngleRotatorVectorEventInstigatorStructRadianToDegreeDegreeToRadian RadianToURot URotToRadian DegreeToURot URotToDegreebIDFloatProperty BoolProperty IntPropertyHLHN targetloc targetdelta targetrange targetdirtargetzgravanglerangled angledmin minalpha angledtrytanrsinrcosrspeedxyspeedzpeak impactheight impactspeedzimpactspeedxy BytePropertyVel @F7 '31D+0$&<@# =AE9() C*;-N%, 6H2!LD:"K>@B8I e!0 #Y->  #a(@6B0a(#??#6P66   ?D?6;& Q 1??&  E%  81 ppppWARNING: Minimum theoretical jump angle isSD . JumpAngle=SD. Trying angle=SD%'%5<3a 6C6D3#?&?,#0?%ERROR: Could not calculate JumpSpeed'9'a(#??6?,-A=$?,&$)'(ppppppppA=SDIV=SD(IS=SD)IH=SD&T=SD?P=SD$V=SDG=SD'.Tw*  =  y::$o$  #w*-' P .M5.a-;5#5(>w.*-ERROR: Ground level not found below destination ' # `e@ @/JquEx8ttttԝXt{#UԝXԝXԝXԝXttԝXԝXԝX1tL]ԝXL]L]L]ԝXttttL]L]L]ԝXԝXtt{#Ut{#UtԝXt{#U$4B$?$@@$@?$?$B"!S S#$B"$A@4O? (ppU=[] .?w *PN=[w *{ p pW p]ppN=[W]ppD=[ Name] P/m9 !$d " K$-!-!"B-! $w./*&:./:+"  TI!-:p <;::$%'  57.2957795131 RXS wY--W- %W ,Mw *    UVYW&( Z'ez% \ 0.00549316G p.^8-r.*::$   ^ 182.04444444[$~/.C- r*::$ ::$/a0 |W  w  10r*{ERROR: Could not find destination'  -C!::+ ^w7  7 `  2!/a0 2  10   _ 0.000095873799b 10430.3783505N// ============================================================================ // swJumpPad. // // Improved JumpPad/Kicker Actor that calculates jump force automatically. // Does not require additional Trigger/LiftExit/LiftCenter actors. // Familiar placing procedure - just like Teleporters. // Path links visible in UnrealEd. // Bot support. // Can be disabled/enabled with Triggers. // Support for on-jump special effects. // Allows jump angle and destination randomisation. // Supports custom vertical gravity, ie: LowGrav mutator. // // ============================================================================ // Copyright 2005 Roman Switch` Dzieciol, neai o2.pl // http://wiki.beyondunreal.com/wiki/Switch // ============================================================================ // One-way JumpPad Tutorial: // - swJumpPads are placed like Teleporters: // - TWO swJumpPad actors are required: Source and Destination. // - In Source swJumpPad set "URL" to some name. // - In Destination swJumpPad set "Tag" to that name. // - Adjust JumpAngle if neccessary. // - Congratulations, you have set up a one-way bot-friendly JumpPad. // // ============================================================================ // Tips: // // - JumpAngle will be limited to 1-89 degrees. // // - If the JumpAngle is too low, a theoretically valid one will be calculated // ingame and warning message will be broadcasted every time someone jumps. // // - For testing precision, doublejump into JumpPad from distance, this way // you won't accidentially disrupt your jump with movement keys. // // - Ignore other Teleporter properties other than URL, it's not a teleporter. // // - If you want to change jump parameters, change them in the Source JumpPad, // not the Destination one. // // - bTraceGround requires that there are no holes under the center of // Destination JumpPad. If there is one, ie if the JumpPad is placed on edge // of a cliff, players will be launched at the ground level in the hole, ie // bottom of the cliff. To fix this move Destination JumpPad away from the // edge or disable bTraceGround. // // ============================================================================ // Angle random modes: // // AM_Random // Uses random value from range ( JumpAngle, JumpAngle+AngleRand ) // // AM_Extremes // Uses JumpAngle then JumpAngle+AngleRand then repeat. Lets suppose that // two players walk into JumpPad one after another. Player who jumped // first may arrive at target location *later* than player who jumped // second if the jump angle of second player was significatly flatter. // // AM_Owned // Team==TeamNumber uses JumpAngle, other teams use JumpAngle+AngleRand // // ============================================================================ // bLogParams acronyms: // // A = Angle // IV = Impact velocity in Z plane // IS = Impact velocity in XY plane // IH = Impact height // T = Time in ms // P = Peak height // V = Jump velocity // G = Gravity // U = URL // PN = Player Name // N = Source JumpPad name // D = Destination JumpPad name // // ============================================================================ class swJumpPad expands Teleporter; enum EAngleMode { AM_Random, AM_Extremes, AM_Owned }; // ============================================================================ // Source JumpPad Properties // ============================================================================ var(JumpPad) float JumpAngle; // Jump angle var(JumpPad) byte TeamNumber; // Team number var(JumpPad) bool bTeamOnly; // Other teams can't use it var(JumpPad) float TargetZOffset; // Target location height offset var(JumpPad) vector TargetRand; // Target location random range var(JumpPad) bool bTraceGround; // Find ground below JumpPad and use it as target location var(JumpPad) float AngleRand; // Jump angle random range var(JumpPad) EAngleMode AngleRandMode; // Jump angle random range mode var(JumpPad) bool bDisabled; // Disable, triggering JumpPad toggles this var(JumpPadFX) class JumpEffect; // Spawn this actor at JumpPad when someone jumps var(JumpPadFX) class JumpPlayerEffect; // Spawn this actor at jumping player var(JumpPadFX) name JumpEvent; // Trigger this event when someone jumps var(JumpPadFX) sound JumpSound; // Play this sound when someone jumps var(JumpPadFX) bool bClientSideEffects; // Spawn effects only on clients var(JumpPadDebug) float JumpWait; // Disable JumpPad for JumpWait seconds after jump var(JumpPadDebug) bool bLogParams; // Display jump parameters in log and ingame // ============================================================================ // Internal // ============================================================================ var Actor JumpTarget; var Actor JumpActor; var bool bSwitchAngle; var float MinAngleCurve; var float MinAngleFinder; var float MinAngle; var float MaxAngle; Const RadianToDegree = 57.2957795131; Const DegreeToRadian = 0.01745329252; Const RadianToURot = 10430.3783505; Const URotToRadian = 0.000095873799; Const DegreeToURot = 182.04444444; Const URotToDegree = 0.00549316; simulated function PostBeginPlay() { Super(NavigationPoint).PostBeginPlay(); if( URL == "" ) ExtraCost = 0; } simulated function bool Accept( actor Incoming, Actor Source ) { return false; } simulated function Trigger( Actor Other, Pawn EventInstigator ) { local int i; bEnabled = !bEnabled; if( bEnabled ) // launch any pawns already in my radius for( i=0; i<4; i++) if( Touching[i] != None ) Touch(Touching[i]); } simulated function ShowMessage( coerce string s, optional Actor A, optional bool bID ) { if( bID ) s = s $ GetIdentifier(A); if( Role == ROLE_Authority ) BroadcastMessage( s, true ); Log( s, name ); } simulated function float GetAngle( Actor Other ) { switch( AngleRandMode ) { case AM_Random: return RandRange( JumpAngle, JumpAngle+AngleRand ); case AM_Extremes: bSwitchAngle = !bSwitchAngle; return JumpAngle + AngleRand*float(bSwitchAngle); case AM_Owned: if( Pawn(Other) != None && Pawn(Other).PlayerReplicationInfo.Team != TeamNumber ) return JumpAngle+AngleRand; else return JumpAngle; } } simulated function string GetIdentifier( Actor A ) { local string S; local Pawn P; S = S @ "U=[" $URL$ "]"; P = Pawn(A); if( P != None ) { S = S @ "PN=["; if( P.PlayerReplicationInfo != None && P.PlayerReplicationInfo.PlayerName != "" ) S = S $P.PlayerReplicationInfo.PlayerName; else S = S $P.Name; S = S $ "]"; } S = S @ "N=[" $Name$ "]"; S = S @ "D=[" $JumpTarget.GetPropertyText("Name")$ "]"; return S; } simulated function vector TraceGround( vector Origin ) { local Actor A; local vector HL,HN; A = Trace( HL, HN, Origin+vect(0,0,-32768), Origin, false ); if( A != None ) { return HL; } ShowMessage( "ERROR: Ground level not found below destination",, true ); return JumpTarget.Location + vect(0,0,-1)*JumpTarget.CollisionHeight; } simulated function vector CalcVelocity( Pawn Other ) { local vector vel; local vector origin; local vector targetloc, targetdelta, targetrange; local rotator jumpdir, targetdir; local float targetdist, targetz; local float grav; local float angler, angled, pitch, angledmin, minalpha, angledtry; local float tanr, sinr, cosr; local float speed, speedxy, speedz; local float peak; local float time; local float impactheight, impactspeedz; local vector impactspeedxy; local Bot B; // Player location origin = Other.Location + vect(0,0,-1)*Other.CollisionHeight; // Target Location if( bTraceGround ) { targetloc = TraceGround(JumpTarget.Location); } else { targetloc = JumpTarget.Location + vect(0,0,-1)*JumpTarget.CollisionHeight; } targetloc += VRand()*TargetRand; targetloc.Z += TargetZOffset; // Target vars targetdelta = targetloc - origin; targetrange = targetdelta * vect(1,1,0); targetdist = VSize(targetrange); targetz = targetdelta.Z; targetdir = rotator(targetdelta); // Get gravity grav = -Region.Zone.ZoneGravity.Z; // Get Angle //JumpAngle=10; angled = FClamp(GetAngle(Other),MinAngle,MaxAngle); // Check minimum angle angledmin = FClamp(int(targetdir.Pitch * URotToDegree)+1,MinAngle,MaxAngle); if( angledmin > angled ) { minalpha = (1-(1-(angledmin / MaxAngle))**MinAngleCurve); angledtry = FClamp(angledmin+(MaxAngle-angledmin)*MinAngleFinder*minalpha,MinAngle,MaxAngle); ShowMessage( "WARNING: Minimum theoretical jump angle is" @int(angledmin)$ ". JumpAngle=" $int(angled)$ ". Trying angle=" $int(angledtry), Other, true ); angled = angledtry; } // Convert angle angler = angled * DegreeToRadian; // radians pitch = angled * DegreeToURot; // ru // Target direction jumpdir = targetdir; jumpdir.Pitch = pitch; // Speed tanr = tan(angler); speed = targetdist * Sqrt( (grav*((tanr*tanr) + 1)) / (2*(targetdist*tanr-targetz)) ); if( speed == 0 ) { ShowMessage( "ERROR: Could not calculate JumpSpeed", Other, true ); speed = Other.JumpZ; } // Velocity vel = speed * vector(jumpdir); // Velocity components speedxy = VSize(vel*vect(1,1,0)); speedz = vel.Z; // Flight time time = (speedz / grav) + sqrt((speedz*speedz)/(grav*grav)-(2*targetz)/grav); if( bLogParams ) { sinr = sin(angler); cosr = cos(angler); peak = ( (speed*speed*sinr*sinr) / (2*grav)); impactheight = peak - targetz; impactspeedxy = Normal(targetrange) * speedxy; impactspeedz = ( speedz ) - ( grav * time ); ShowMessage( "A=" $int(angled) @"IV=" $int(impactspeedz) @"IS=" $int(VSize(impactspeedxy)) @"IH=" $int(impactheight) @"T=" $int(time*1000) @"P=" $int(peak) @"V=" $int(speed) @"G=" $int(grav) , Other, true ); } // AI hints B = Bot(Other); if( B != None ) { B.Focus = JumpTarget.Location; B.MoveTarget = JumpTarget; B.MoveTimer = time-0.1; B.Destination = JumpTarget.Location; } // Update player's physics if( Other.Physics == PHYS_Walking ) { Other.SetPhysics(PHYS_Falling); } Other.Velocity = vel; Other.Acceleration = vect(0,0,0); // AI hints if( B != None ) { B.bJumpOffPawn = true; B.SetFall(); B.DesiredRotation = rotator(targetrange); } return vel; } simulated event Touch( Actor Other ) { // Accept only pawns if( !bEnabled || Pawn(Other) == None || Other.Physics == PHYS_None ) return; // Setup PostTouch PendingTouch = Other.PendingTouch; Other.PendingTouch = self; } simulated event PostTouch( Actor Other ) { local Pawn P; local Actor A; // Accept only pawns P = Pawn(Other); if( !bEnabled || P == None || P.Physics == PHYS_None ) return; if( Role == ROLE_Authority ) { // Find JumpTarget foreach AllActors( class 'Actor', A ) if( string(A.tag) ~= URL && A != Self ) JumpTarget = A; if( JumpTarget == None ) { if( URL != "" ) ShowMessage( "ERROR: Could not find destination", Other, true ); return; } // If team only, enforce it if( bTeamOnly && P.PlayerReplicationInfo.Team != TeamNumber ) return; // Do not launch again a launched player. if( Other != JumpActor || Level.TimeSeconds-JumpWait > default.JumpWait ) { JumpActor = Other; JumpWait = Level.TimeSeconds; } else return; // Launch player CalcVelocity( P ); // Broadcast event Instigator = P; if( JumpEvent != '' ) foreach AllActors( class'Actor', A, JumpEvent ) A.Trigger( self, Instigator ); // Play Sounds JumpSounds(P); } // Show effects JumpEffects(P); } simulated function JumpEffects( Pawn Other ) { if((bClientSideEffects && Level.NetMode != NM_DedicatedServer) ||(!bClientSideEffects && Role == ROLE_Authority)) { // Spawn JumpPad effect if( JumpEffect != None ) Spawn( JumpEffect, self,, Location, rotator(Other.Velocity) ); // Spawn Player effect if( JumpPlayerEffect != None ) Spawn( JumpPlayerEffect, Other,, Other.Location, rotator(Other.Velocity) ); } } function JumpSounds( Pawn Other ) { // Make noise if( JumpSound != None ) { PlaySound(JumpSound); MakeNoise(1.0); } } /* SpecialHandling is called by the navigation code when the next path has been found. It gives that path an opportunity to modify the result based on any special considerations */ function Actor SpecialHandling( Pawn Other ) { //ShowMessage( "FOUND!",, true ); return self; } // ============================================================================ // Copyright 2005 Roman Switch` Dzieciol, neai o2.pl // http://wiki.beyondunreal.com/wiki/Switch // ============================================================================ ]#5-*::$-* ::$hw4*a4 P w6*a6  P  Q 0.01745329252ad ,7w,*a,b? cf8 g__R9R;RIRpRxR*ARfRy_dR]R7RJf@RhR(J<x7A~eEI4RefIRRxQI"b:bGsjx8K3RkR)xLRbISxNeJb=xOAAfHy'RssKy&fMy,x[I?R6f>y yRCRKy IYfZfBKf\y'JVy$Rv_i_bCcRlbTM0 `&GDl&J{ z&G/ G'GS T']F `'GP m'GU y'MF E(GV R(]5 ^(J k(T2 x(J D)Gc P)G] ])GN i)GO v)GP C*GR P*GY \*G+ h*[D t*aD A+P0 N+]D Z+GT g+GQ s+Ga @,J M,GZ Y,J e,J} r,Jq ,G` K-G^ W-GX c-G_ o-G\ {-G` G.Ga S.Jw `.JXl.J z.IL G/I5 T/ODa/G. o/GW |/J H0G3 T0Jt`0I.n0Ju|0J| J1J W1Jrc1PH r1IM ~1P5 K2G[ X2J d2M5p2Jo ~2Jz K3Jn W3Jm d3Jgq3J x3G- D4J AQ4I- RDJ]_Ds|FM- oOJ^ {OJ _GPO- fSJFrSJExUJB}VT@ PWTD]WJ SkWX- ~XXWJYXUXYJ&fYJ'-EZJGrZJ ZC[JF]\J$Ip\JEyaJDNbJ14ZbbJH|JCDJ 2XcD JJWeDve- D