iw6-scripts-dev/maps/mp/agents/alien/_alien_jump.gsc
2024-12-11 11:28:08 +01:00

776 lines
24 KiB
Plaintext

//
// _alien_jump.gsc
//
// Common jump functionality.
// Jump is called from multiple states. It does not correspond to any particular anim state.
//
#include maps\mp\agents\_scriptedAgents;
Jump( startPos, startAngles, endPos, endAngles, nextPos, jumpCBs, scriptableName )
{
maps\mp\agents\alien\_alien_anim_utils::turnTowardsVector( endPos - startPos );
oldTurnRate = self ScrAgentGetMaxTurnSpeed();
self thread JumpInternal( startPos, startAngles, endPos, endAngles, nextPos, jumpCBs, scriptableName );
self waittill( "jump_finished" );
self JumpCleanup( oldTurnRate, endAngles );
}
JumpCleanup( oldTurnRate, endAngles )
{
self ScrAgentSetAnimScale( 1.0, 1.0 );
self ScrAgentSetMaxTurnSpeed( oldTurnRate );
if ( self maps\mp\alien\_utility::is_normal_upright( AnglesToUp( endAngles ) ) )
{
self ScrAgentSetPhysicsMode( "gravity" );
self.oriented = false;
self.ignoreme = false;
}
else
{
self ScrAgentSetPhysicsMode( "noclip" );
self.oriented = true;
self.ignoreme = true;
}
}
JumpInternal( startPos, startAngles, endPos, endAngles, nextPos, jumpCBs, scriptableName )
{
self endon( "death" );
self endon ("killanimscript" );
self maps\mp\agents\alien\_alien_anim_utils::turnTowardsVector( endPos - startPos );
if ( isDefined ( scriptableName ) )
maps\mp\agents\alien\_alien_anim_utils::resetScriptable( scriptableName, endPos );
self.trajectoryActive = false;
// figure out initial jump stuff
jumpAnimStates = SpawnStruct();
jumpInfo = self GetJumpInfo( startPos, startAngles, endPos, endAngles, nextPos );
self GetJumpAnimStates( jumpInfo, jumpAnimStates );
if ( IsDefined( jumpCBs ) && IsDefined( jumpCBs.fnSetAnimStates ) )
self [[ jumpCBs.fnSetAnimStates ]]( jumpInfo, jumpAnimStates );
anglesToEnd = GetJumpStartAngles( startPos, startAngles, endPos );
self ScrAgentSetPhysicsMode( "noclip" );
self ScrAgentSetOrientMode( "face angle abs", anglesToEnd );
t = 0;
beginAnim = self GetAnimEntry( jumpAnimStates.launchAnimState, jumpAnimStates.launchAnimEntry );
/////////////
// calculate the landing point such that the final position is at our goal
endAnim = self GetAnimEntry( jumpAnimStates.landAnimState, jumpAnimStates.landAnimEntry );
endFinish = GetNotetrackTimes( endAnim, "finish" );
if ( endFinish.size > 0 )
{
endAnimLength = endFinish[0] * GetAnimLength( endAnim );
}
else
{
endAnimLength = GetAnimLength( endAnim );
}
endAnimTime = endAnimLength / jumpAnimStates.playbackRate;
endLandMoveFrame = floor( endAnimTime * 20.0 );
endLandMoveTime = (endLandMoveFrame / 20.0) / endAnimTime;
endLand = GetNotetrackTimes( endAnim, "stop_teleport" );
if ( endLand.size > 0 )
{
endLandTime = endLand[0] * endAnimTime;
beginLandMoveFrame = ceil( endLandTime * 20.0 );
beginLandMoveTime = (beginLandMoveFrame / 20.0) / endAnimTime;
endLandMove = GetMoveDelta( endAnim, beginLandMoveTime, endLandMoveTime );
}
else
{
endLandTime = 0.8 * endAnimTime;
beginLandMoveFrame = ceil( endLandTime * 20.0 );
beginLandMoveTime = (beginLandMoveFrame / 20.0) / endAnimTime;
endLandMove = GetMoveDelta( endAnim, beginLandMoveTime, endLandMoveTime );
}
endAngles = GetJumpEndAngles( startPos, endPos, endAngles );
endLandMoveRot = RotateVector( endLandMove, endAngles );
endLandOrigin = endPos - endLandMoveRot;
/////////////
// jump begin
self ScrAgentSetAnimMode( "anim deltas" );
self PlaySoundOnMovingEnt( get_jump_SFX_alias() );
if ( AnimHasNotetrack( beginAnim, "start_teleport" ) )
{
self PlayAnimNAtRateUntilNotetrack(jumpAnimStates.launchAnimState,
jumpAnimStates.launchAnimEntry,
jumpAnimStates.playbackRate,
"jump_launch",
"start_teleport" );
}
else
{
self PlayAnimNAtRateForTime(jumpAnimStates.launchAnimState,
jumpAnimStates.launchAnimEntry,
jumpAnimStates.playabackRate,
0.5 * GetAnimLength( beginAnim ) / jumpAnimStates.playbackRate );
}
/////////////
// do the trajectory
startTime = gettime();
t = self ScrAgentDoTrajectory( self.origin, endLandOrigin, jumpInfo.jumpSpeed2D );
self.trajectoryActive = true;
/////////////
// Handle pain
self endon( "jump_pain_interrupt" );
self thread JumpPain( t, endPos );
self notify( "jump_launching" ); // for cloaker jump
/////////////
// orient the agent to the plane of the landing position
oldTurnRate = self ScrAgentGetMaxTurnSpeed();
self thread jumpOrient( jumpInfo, endAngles, oldTurnRate, t );
/////////////
// finish the launch animation
self WaitUntilNotetrack( "jump_launch", "end" );
beginTime = ( gettime() - startTime ) / 1000;
/////////////
// calculate the time to spend in the air
loopTime = t - beginTime - endLandTime;
/////////////
// jump loop
if ( loopTime > 0 )
{
self PlayAnimNAtRateForTime(jumpAnimStates.inAirAnimState,
jumpAnimStates.inAirAnimEntry,
jumpAnimStates.playbackRate,
loopTime );
}
/////////////
// jump land
// Allow a last minute animState change
if ( IsDefined( jumpCBs ) && IsDefined( jumpCBs.fnLandAnimStateChoice ) )
self [[ jumpCBs.fnLandAnimStateChoice ]]( jumpInfo, jumpAnimStates );
self SetAnimState( jumpAnimStates.landAnimState, jumpAnimStates.landAnimEntry, jumpAnimStates.playbackRate );
self waittill( "traverse_complete" );
self.trajectoryActive = false;
if ( isDefined ( scriptableName ) )
maps\mp\agents\alien\_alien_anim_utils::playAnimOnScriptable( scriptableName, endPos );
self ScrAgentSetAnimScale( 1.0, 0.0 );
self ScrAgentSetMaxTurnSpeed( 20.28318 ); // 2 pi
self ScrAgentSetAnimMode( "anim deltas" );
// make sure our rotation ends up at endAngles.
// this would be even better if it was accounting for rotating entirely to the
// direction of the next negotiation node
self ScrAgentSetOrientMode( "face angle abs", endAngles );
self thread waitForLandImpact( "jump_land" );
self WaitUntilNotetrack( "jump_land", "end" );
self ScrAgentSetAnimScale( 1.0, 1.0 );
/////////////
// yay!
//delta_from_goal = endPos - self.origin;
//iprintln( "Jump Delta: " + delta_from_goal );
self SetOrigin( endPos, false ); // Boo!
self notify( "jump_finished" );
}
waitForLandImpact( animName )
{
alienType = self maps\mp\alien\_utility::get_alien_type();
switch( alienType )
{
case "elite":
self WaitUntilNotetrack( animName, "jump_land_impact" );
maps\mp\agents\alien\_alien_elite::on_jump_impact();
break;
default:
break;
}
}
jumpOrient( jumpInfo, endAngles, oldTurnRate, timeInAir )
{
self endon( "death" );
UPRIGHT_VECTOR = ( 0, 0, 1 );
UPRIGHT_DOT = 0.85;
startUpright = maps\mp\alien\_utility::is_normal_upright( jumpInfo.startUpVector );
endUpright = maps\mp\alien\_utility::is_normal_upright( jumpInfo.endUpVector );
if ( startUpright && !endUpright )
{
start_orient_time = 0.5;
end_orient_time = 1.0;
}
else if ( !startUpright && endUpright )
{
start_orient_time = 0.0;
end_orient_time = 0.5;
}
else
{
start_orient_time = 0.0;
end_orient_time = 1.0;
}
total_orient_time = end_orient_time - start_orient_time;
if ( start_orient_time > 0 )
{
wait ( timeInAir * start_orient_time );
}
threshold = 1.0;
if ( DistanceSquared( self.angles, endAngles ) > threshold )
{
anglesDelta = AnglesDelta( self.angles, endAngles );
turnRate = anglesDelta / ( timeInAir * total_orient_time );
turnRate = turnRate * 3.1415926 / 180.0; // deg to rad
turnRate = turnRate / 20; // rads per frame
self ScrAgentSetMaxTurnSpeed( turnRate );
}
self ScrAgentSetOrientMode( "face angle abs", endAngles );
}
GetJumpInfo( startPos, startAngles, endPos, endAngles, nextPos )
{
jumpInfo = SpawnStruct();
startToEnd = endPos - startPos;
startToEnd2D = startToEnd * ( 1, 1, 0 );
startToEnd2D = VectorNormalize( startToEnd2D );
AssertEx( IsDefined( level.alienAnimData.jumpLaunchGroundDelta ), "Jump launch table has not been initialized" );
jumpInfo.launchOrigin = startPos + startToEnd2D * level.alienAnimData.jumpLaunchGroundDelta;
jumpInfo.landOrigin = endPos;
jumpInfo.jumpVector = jumpInfo.landOrigin - jumpInfo.launchOrigin;
jumpInfo.jumpVector2D = jumpInfo.jumpVector * ( 1, 1, 0 );
jumpInfo.jumpDistance2D = Length( jumpInfo.jumpVector2D );
AssertEx( jumpInfo.jumpDistance2D != 0, "Trying to jump vertically. This is not handled." );
jumpInfo.jumpDirection2D = jumpInfo.jumpVector2D / jumpInfo.jumpDistance2D;
if ( IsDefined( nextPos ) )
jumpInfo.landVector = nextPos - endPos;
else if ( IsDefined( self.enemy ) )
jumpInfo.landVector = self.enemy.origin - endPos;
else
jumpInfo.landVector = AnglesToForward( self.angles );
jumpInfo.startAngles = GetJumpAngles( jumpInfo.jumpVector, AnglesToUp( startAngles ) );
jumpInfo.endAngles = GetJumpAngles( jumpInfo.jumpVector, AnglesToUp( endAngles ) );
jumpInfo.startUpVector = AnglesToUp( jumpInfo.startAngles );
jumpInfo.endUpVector = AnglesToUp( jumpInfo.endAngles );
GetJumpVelocity( jumpInfo );
return jumpInfo;
}
GetJumpAngles( jumpVector, vUp )
{
forwardVector = maps\mp\agents\alien\_alien_anim_utils::ProjectVectorToPlane( jumpVector, vUp );
right = VectorCross( forwardVector, vUp );
angles = AxisToAngles( forwardVector, right, vUp );
return angles;
}
//GetLaunchAngle( speed, gravity, x, y )
//{
// // From: http://en.wikipedia.org/wiki/Trajectory_of_a_projectile
// val = speed * speed * speed * speed - gravity * ( gravity * x * x + 2 * y * speed * speed );
// AssertEx ( val >= 0, "The given velocity is unable to reach the target. Increase the velocity." );
//
// //requiredAngleHigh = ATan( ( speed * speed + Sqrt( val ) ) / ( gravity * x ) );
// requiredAngleLow = ATan( ( speed * speed - Sqrt( val ) ) / ( gravity * x ) );
//
// return requiredAngleLow;
//}
//GetMinimumLaunchSpeed( gravity, x, y )
//{
// // From: http://en.wikipedia.org/wiki/Range_of_a_projectile
// // This code calculates the minimum speed required to reach a point by assuming
// // the point being reached is the maximum range of the projectile fired at the
// // desired velocity. The result is derived from the equation for the maximum
// // range of a projectile: Range = ( vel / g ) * sqrt( vel ^ 2 + 2 * g * height )
// a = 2 * gravity * y;
// b = gravity * gravity * x * x;
//
// result = Sqrt( (a + Sqrt( a * a + 4 * b ) ) / 2 );
//
// return result;
//}
GetJumpVelocity( jumpInfo )
{
x = jumpInfo.jumpDistance2D;
y = jumpInfo.jumpVector[ 2 ];
isWallJump = !maps\mp\alien\_utility::is_normal_upright( jumpInfo.endUpVector );
g = GetJumpGravity( isWallJump );
MIN_JUMP_SPEED_MULTIPLIER = 1.01;
minJumpSpeed = TrajectoryCalculateMinimumVelocity( jumpInfo.launchOrigin, jumpInfo.landOrigin, g );//GetMinimumLaunchSpeed( g, x, y );
jumpSpeedMultiplier = GetJumpSpeedMultiplier( isWallJump );
jumpSpeed = minJumpSpeed * MIN_JUMP_SPEED_MULTIPLIER * jumpSpeedMultiplier;
AssertEx( jumpSpeed != 0, "Trying to jump but the jump doesn't go anywhere." );
jumpAngle = TrajectoryCalculateExitAngle( jumpSpeed, g, x, y );//GetLaunchAngle( jumpSpeed, g, x, y );
jumpAngleCos = Cos( jumpAngle );
AssertEx( jumpAngleCos != 0, "Trying to jump vertically. This is not handled." );
jumpInfo.jumpTime = jumpInfo.jumpDistance2D / ( jumpSpeed * jumpAngleCos );
gravityVector = g * ( 0, 0, -1 );
jumpInfo.launchVelocity = TrajectoryCalculateInitialVelocity( jumpInfo.launchOrigin, jumpInfo.landOrigin, gravityVector, jumpInfo.jumpTime ); //(jumpInfo.jumpVector - 0.5 * gravityVector * jumpInfo.jumpTime * jumpInfo.jumpTime) / jumpInfo.jumpTime;
jumpInfo.launchVelocity2D = jumpInfo.launchVelocity * ( 1, 1, 0 );
jumpInfo.jumpSpeed2D = Length( jumpInfo.launchVelocity2D );
}
GetJumpSpeedMultiplier( is_wall_jump )
{
if ( IsDefined( self.melee_jumping ) && self.melee_jumping )
{
AssertEx( IsDefined( level.alien_jump_melee_speed, "Alien jump speed is not defined" ) );
return level.alien_jump_melee_speed;
}
else if ( is_wall_jump )
{
return GetDvarFloat( "agent_jumpWallSpeed" );
}
else
{
return GetDvarFloat( "agent_jumpSpeed" );
}
}
GetJumpGravity( is_wall_jump )
{
if ( IsDefined( self.melee_jumping ) && self.melee_jumping )
{
AssertEx( IsDefined( level.alien_jump_melee_gravity, "Alien jump gravity is not defined" ) );
return level.alien_jump_melee_gravity;
}
else if ( is_wall_jump )
{
return GetDvarFloat( "agent_jumpWallGravity" );
}
else
{
return GetDvarFloat( "agent_jumpGravity" );
}
}
GetJumpPlaybackRate( jumpInfo, animStates )
{
AssertEx( jumpInfo.jumpTime != 0);
launchAnim = self GetAnimEntry( animStates.launchAnimState, animStates.launchAnimEntry );
inAirAnim = self GetAnimEntry( animStates.inAirAnimState, animStates.inAirAnimEntry );
landAnim = self GetAnimEntry( animStates.landAnimState, animStates.landAnimEntry );
launchAnimLength = GetAnimLength( launchAnim );
launchAnimInAirTime = launchAnimLength * 0.5;
launchAnimTakeoff = GetNotetrackTimes( launchAnim, "start_teleport" );
if ( IsDefined( launchAnimTakeoff ) && launchAnimTakeoff.size > 0 )
launchAnimInAirTime = launchAnimLength - launchAnimTakeoff[0] * launchAnimLength;
Assert( launchAnimInAirTime < launchAnimLength );
landAnimLength = GetAnimLength( landAnim );
landAnimInAirTime = landAnimLength * 0.5;
landAnimArrive = GetNotetrackTimes( landAnim, "stop_teleport" );
if ( IsDefined( landAnimArrive ) && landAnimArrive.size > 0 )
landAnimInAirTime = landAnimArrive[0] * landAnimLength;
Assert( landAnimInAirTime < landAnimLength );
inAirAnimLength = GetAnimLength( inAirAnim );
Assert( inAirAnimLength > 0 );
// calculate how long the physics needs to run and round up to the nearest frame
// this ensures that the trajectory finishes before we move out of the trajectory
// anim mode
trajectoryFrameCount = ceil( jumpInfo.jumpTime * 20.0 );
trajectoryPhysicsTime = trajectoryFrameCount / 20.0;
// calculate the amount to scale all animations to achieve the required time in the air
trajectoryAnimTime = inAirAnimLength + launchAnimInAirTime + landAnimInAirTime;
trajectoryAnimScale = trajectoryAnimTime / trajectoryPhysicsTime;
// add a two frames of trim since the in air animation will play for a fixed time
// and that time may straddle a frame boundary on both ends
inAirAnimTime = inAirAnimLength / trajectoryAnimScale + 0.1;
inAirAnimScale = inAirAnimLength / inAirAnimTime;
return inAirAnimScale;
}
GetJumpAnimStates( jumpInfo, animStates )
{
animStates.launchAnimState = GetLaunchAnimState( jumpInfo );
animStates.launchAnimEntry = GetLaunchAnimEntry( jumpInfo, animStates.launchAnimState );
animStates.landAnimState = GetLandAnimState( jumpInfo );
animStates.landAnimEntry = GetLandAnimEntry( jumpInfo, animStates.landAnimState );
animStates.inAirAnimState = GetInAirAnimState( jumpInfo, animStates.launchAnimState, animStates.landAnimState );
animStates.inAirAnimEntry = GetInAirAnimEntry( jumpInfo, animStates.launchAnimState, animStates.landAnimState );
animStates.playbackRate = self GetJumpPlaybackRate( jumpInfo, animStates );
}
GetJumpStartAngles( startPos, startAngles, endPos )
{
startUp = AnglesToUp( startAngles );
startForward = VectorNormalize( endPos - startPos );
if ( VectorDot( startUp, startForward ) > 0.98 )
startForward = ( 0, 0, 1 );
startLeft = VectorCross( startUp, startForward );
startForward = VectorCross( startLeft, startUp );
return AxisToAngles( startForward, -1 * startLeft, startUp );
}
GetLaunchAnimState( jumpInfo )
{
LEVEL_DEGREE_RANGE = 20;
cosLimitForLevel = Cos( 90 - LEVEL_DEGREE_RANGE );
startToEnd = VectorNormalize( jumpInfo.jumpVector );
startToEndDotUp = VectorDot( startToEnd, jumpInfo.startUpVector );
if ( abs( startToEndDotUp ) <= cosLimitForLevel )
{
return "jump_launch_level";
}
else if ( startToEndDotUp > 0 )
{
return "jump_launch_up";
}
else if ( startToEndDotUp < 0 )
{
return "jump_launch_down";
}
}
GetLaunchAnimEntry( jumpInfo, launchAnimState )
{
launchDirection = VectorNormalize( jumpInfo.launchVelocity );
launchDirection = RotateVector( launchDirection, jumpInfo.startAngles );
AssertEx( IsDefined( level.alienAnimData.jumpLaunchDirection ), "Alien jump table has not been initialized" );
AssertEx( IsDefined( level.alienAnimData.jumpLaunchDirection[ launchAnimState ] ),
"Alien jump table has not been initialized for launch state " + launchAnimState );
launchEntryCount = self GetAnimEntryCount( launchAnimState );
AssertEx( launchEntryCount > 0, "Alien launch state " + launchAnimState + " as no animations." );
launchEntry = 0;
AssertEx( IsDefined( level.alienAnimData.jumpLaunchDirection[ launchAnimState ][ launchEntry ] ),
"Alien launch entry " + launchEntry + " for state " + launchAnimState + " has no direction." );
launchEntryDot = VectorDot( level.alienAnimData.jumpLaunchDirection[ launchAnimState ][ launchEntry ], launchDirection );
for ( nextLaunchEntry = 1; nextLaunchEntry < launchEntryCount; nextLaunchEntry++ )
{
AssertEx( IsDefined( level.alienAnimData.jumpLaunchDirection[ launchAnimState ][ nextLaunchEntry ] ),
"Alien launch entry " + nextLaunchEntry + " for state " + launchAnimState + " has no direction." );
nextLaunchEntryDot = VectorDot( level.alienAnimData.jumpLaunchDirection[ launchAnimState ][ nextLaunchEntry ], launchDirection );
if ( nextLaunchEntryDot > launchEntryDot )
{
launchEntry = nextLaunchEntry;
launchEntryDot = nextLaunchEntryDot;
}
}
return launchEntry;
}
GetInAirAnimState( jumpInfo, launchAnimState, landAnimState )
{
return "jump_in_air";
}
GetInAirAnimEntry( jumpInfo, launchAnimState, landAnimState )
{
AssertEx( IsDefined( level.alienAnimData.inAirAnimEntry ), "Alien in air table has not been initialized" );
AssertEx( IsDefined( level.alienAnimData.inAirAnimEntry[ launchAnimState ] ),
"Alien in air table has not been initialized for launch state " + launchAnimState );
AssertEx( IsDefined( level.alienAnimData.inAirAnimEntry[ launchAnimState ][ landAnimState ] ),
"Alien in air table has not been initialized for launch state " + launchAnimState + " and land anim state " + landAnimState );
return level.alienAnimData.inAirAnimEntry[ launchAnimState ][ landAnimState ];
}
GetJumpEndAngles( startPos, endPos, endAngles )
{
endUp = AnglesToUp( endAngles );
endForward = VectorNormalize( endPos - startPos );
if ( VectorDot( endUp, endForward ) > 0.98 )
endForward = ( 0, 0, 1 );
endLeft = VectorCross( endUp, endForward );
endForward = VectorCross( endLeft, endUp );
return AxisToAngles( endForward, -1 * endLeft, endUp );
}
GetLandAnimState( jumpInfo )
{
jumpVectorLength = length( jumpInfo.jumpVector );
PITCH_THRESHOLD = 0.342; // sin(20)
if ( !maps\mp\alien\_utility::is_normal_upright( jumpInfo.endUpVector ) )
{
WORLD_UP = ( 0, 0, 1 );
pitch = VectorDot( jumpInfo.jumpVector, WORLD_UP ) / jumpVectorLength;
if ( pitch > PITCH_THRESHOLD )
{
return "jump_land_sidewall_low";
}
else
{
return "jump_land_sidewall_high";
}
}
pitch = VectorDot( jumpInfo.jumpVector, jumpInfo.endUpVector ) / jumpVectorLength;
if ( pitch > PITCH_THRESHOLD )
{
return "jump_land_down";
}
else if ( pitch < ( PITCH_THRESHOLD * -1 ) )
{
return "jump_land_up";
}
else
{
return "jump_land_level";
}
}
GetLandAnimEntry( jumpInfo, landAnimState )
{
incomingVectorWithoutNormal = maps\mp\agents\alien\_alien_anim_utils::ProjectVectorToPlane( jumpInfo.jumpVector, jumpInfo.endUpVector );
outgoingVectorWithoutNormal = maps\mp\agents\alien\_alien_anim_utils::ProjectVectorToPlane( jumpInfo.landVector, jumpInfo.endUpVector );
thirdVector = incomingVectorWithoutNormal - outgoingVectorWithoutNormal;
outgoingRightVector = VectorCross( outgoingVectorWithoutNormal, jumpInfo.endUpVector );
outgoingRightVectorWithoutNormal = VectorNormalize( maps\mp\agents\alien\_alien_anim_utils::ProjectVectorToPlane( outgoingRightVector, jumpInfo.endUpVector ) ) * 100;
projectionIncomingToOutgoingRight = VectorDot ( incomingVectorWithoutNormal * -1, outgoingRightVectorWithoutNormal );
//Law of cosine
a = Length( incomingVectorWithoutNormal );
b = Length( outgoingVectorWithoutNormal );
c = Length( thirdVector );
MIN_LENGTH = 0.001;
// Edge case: Return forward;
if ( a < MIN_LENGTH || b < MIN_LENGTH )
{
return 1;
}
ratio = ( a * a + b * b - c * c ) / ( 2 * a * b );
if ( ratio <= -1 )
{
return 6;
}
else if ( ratio >= 1 )
{
return 1;
}
else
{
rotatedYaw = Acos( ratio );
if ( projectionIncomingToOutgoingRight > 0 ) //Entering from the right
{
if ( 0 <= rotatedYaw && rotatedYaw < 22.5 )
{
return 1;
}
else if ( 22.5 <= rotatedYaw && rotatedYaw < 67.5 )
{
return 2;
}
else if ( 67.5 <= rotatedYaw && rotatedYaw < 112.5 )
{
return 4;
}
else if ( 112.5 <= rotatedYaw && rotatedYaw < 157.5 )
{
return 7;
}
else
{
return 6;
}
}
else //Entering from the left
{
if ( 0 <= rotatedYaw && rotatedYaw < 22.5 )
{
return 1;
}
else if ( 22.5 <= rotatedYaw && rotatedYaw < 67.5 )
{
return 0;
}
else if ( 67.5 <= rotatedYaw && rotatedYaw < 112.5 )
{
return 3;
}
else if ( 112.5 <= rotatedYaw && rotatedYaw < 157.5 )
{
return 5;
}
else
{
return 6;
}
}
}
}
JumpPain( duration, endPos )
{
self endon( "death" );
self endon( "killanimscript" );
self endon( "jump_finished" );
start_time = gettime();
duration_msec = duration*1000;
self waittill( "jump_pain", damageDirection, hitLocation, iDamage, stun );
// Make sure we're still jumping
if ( !self.trajectoryActive )
{
return; // Too late!
}
// Stop normal jump animations and play the pain
self notify( "jump_pain_interrupt" );
jump_pain_state = self maps\mp\agents\alien\_alien_anim_utils::getPainAnimState( "jump_pain", iDamage, stun );
jump_pain_index = self maps\mp\agents\alien\_alien_anim_utils::getPainAnimIndex( "jump", damageDirection, hitLocation );
damage_degree = self maps\mp\agents\alien\_alien_anim_utils::getDamageDegree( iDamage, stun );
jump_end_time_sec = start_time * 0.001 + duration;
PlayInAirJumpPainAnims( jump_pain_state, jump_pain_index, jump_end_time_sec, damage_degree );
self ScrAgentSetAnimScale( 1.0, 0.0 );
self ScrAgentSetAnimMode( "anim deltas" );
// this would be even better if it was accounting for rotating entirely to the
// direction of the next negotiation node
self ScrAgentSetOrientMode( "face angle abs", self.angles );
impact_pain_anim = self GetImpactPainAnimState( damage_degree );
impact_pain_index = self maps\mp\agents\alien\_alien_anim_utils::GetImpactPainAnimIndex( jump_pain_index );
self SetAnimState( impact_pain_anim, impact_pain_index, 1.0 );
self WaitUntilNotetrack( impact_pain_anim, "code_move" );
self notify ( "jump_finished" );
}
PlayInAirJumpPainAnims( jump_pain_state, jump_pain_entry, jump_end_time_sec, damage_degree )
{
self endon( "death" );
self endon( "killanimscript" );
self endon( "jump_finished" );
self SetAnimState( jump_pain_state, jump_pain_entry, 1.0 );
msg = self common_scripts\utility::waittill_any_return( "jump_pain", "traverse_complete" );
if ( msg == "traverse_complete" )
return;
idle_time_remaining = jump_end_time_sec - GetTime() * 0.001;
if ( idle_time_remaining > 0 )
{
MAX_RATE_SCALE = 2.0;
jump_pain_idle_state = self GetJumpPainIdleAnimState( damage_degree );
jump_pain_idle_anim = self GetAnimEntry( jump_pain_idle_state, jump_pain_entry );
jump_pain_idle_anim_length = GetAnimLength( jump_pain_idle_anim );
jump_pain_idle_rate = Min( MAX_RATE_SCALE, jump_pain_idle_anim_length / idle_time_remaining );
self SetAnimState( jump_pain_idle_state, jump_pain_entry, jump_pain_idle_rate );
}
self waittill( "traverse_complete" );
}
GetJumpPainIdleAnimState( damage_degree )
{
return ( "jump_pain_idle_" + damage_degree );
}
GetImpactPainAnimState( damage_degree )
{
return ( "jump_impact_pain_" + damage_degree );
}
get_jump_SFX_alias()
{
switch( maps\mp\alien\_utility::get_alien_type() )
{
case "elite":
return "null"; // "No sound is better than the wrong sound" - Tim S.
case "spitter":
return "spitter_jump";
case "seeder":
return "seed_jump";
case "gargoyle":
return "gg_jump";
default:
return "alien_jump";
}
}