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

960 lines
23 KiB
Plaintext

#include common_scripts\utility;
#include maps\mp\agents\_scriptedAgents;
#include maps\mp\_utility;
ALLOW_SLIDE_DIST_SQR = 20.0 * 20.0;
DODGE_CHANCE_ENEMY_FACING_TOLERANCE = 0.985; // cos 10, how closely our enemy has to be looking at us
DODGE_CHANCE_ALIEN_FACING_TOLERANCE = 0.766; // cos 40, how closely we have to be facing our enemy
DODGE_CHANCE_LOOK_AT_TIME_MIN = 1000; // Time our enemy has to look at us before dodging
DODGE_CHANCE_LOOK_AT_TIME_MAX = 2000;
DODGE_CHANCE_MAX_DISTANCE_SQ = 640000.0; // 800.0 * 800.0
MIN_DODGE_DIST_SQUARED = 65536.0; // 256 * 256
main()
{
self endon( "killanimscript" );
self EnterMove();
self StartMove();
self ContinueMovement();
}
EnterMove()
{
self.bLockGoalPos = false;
self.playing_pain_animation = false;
self ScrAgentSetPhysicsMode( "gravity" );
self ScrAgentSetAnimMode( "code_move" );
}
StartMove()
{
if ( canDoStartMove())
{
switch( getStartMoveType() )
{
case "run-start":
self doRunStart();
break;
case "walk-start":
self doWalkStart();
break;
case "leap-to-run":
self doLeapToRunStart();
break;
default:
break;
}
}
}
end_script()
{
self.bLockGoalPos = false;
self.playing_pain_animation = false;
self CancelAllBut( undefined );
self ScrAgentSetAnimScale( 1, 1 );
self.previousAnimState = "move";
}
SetupMovement()
{
self.enableStop = true;
self thread WaitForMovemodeChange();
self thread WaitForJumpSoon();
self thread WaitForSharpTurn();
self thread WaitForStop();
self thread WaitForStuck();
if ( self canDodge() )
{
self thread WaitForNearMiss();
self thread WaitForDodgeChance();
}
}
ContinueMovement()
{
self SetupMovement();
// Oriented agents should maintain their orientation
if( self.oriented )
{
forward = self GetLookaheadDir();
up = AnglesToUp( self.angles );
left = VectorCross( up, forward );
forward = VectorCross( left, up );
right = (0,0,0) - left;
anglesToFace = AxisToAngles( forward, right, up );
self ScrAgentSetOrientMode( "face angle abs", anglesToFace );
self ScrAgentSetAnimMode( "code_move_slide" );
}
else
{
self ScrAgentSetOrientMode( "face motion" );
self ScrAgentSetAnimMode( "code_move" );
}
self ScrAgentSetAnimScale( self.xyanimscale, 1.0 );
self SetMoveAnim( self.moveMode );
}
WaitForMovemodeChange()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_runwalk" );
curMovement = self.moveMode;
while ( true )
{
if ( curMovement != self.moveMode )
{
self SetMoveAnim( self.moveMode );
curMovement = self.moveMode;
}
wait( 0.1 );
}
}
WaitForSharpTurn()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_sharpturn" );
self waittill( "path_dir_change", newDir );
angleIndex = GetAngleIndexFromSelfYaw( newDir );
if ( angleIndex == 4 ) // 4 means this turn wasn't sharp enough for me to care. (angle ~= 0)
{
self thread WaitForSharpTurn();
return;
}
shouldMoveStraightAhead = !( self should_do_sharp_turn() );
if ( shouldMoveStraightAhead )
angleIndex = 0;
//Try run-turn
animState = "run_turn";
turnAnim = self GetAnimEntry( animState, angleIndex );
canDoTurn = shouldMoveStraightAhead || CanDoTurnAnim( turnAnim );
if ( !canDoTurn )
{
self thread WaitForSharpTurn();
return;
}
self CancelAllBut( "sharpturn" );
self.bLockGoalPos = true;
self.enableStop = false;
if ( shouldMoveStraightAhead )
self maps\mp\agents\alien\_alien_anim_utils::turnTowardsVector( self GetLookaheadDir() );
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
self PlayAnimNAtRateUntilNotetrack( animState, angleIndex, self.moveplaybackrate, animState, "code_move" );
self ScrAgentSetOrientMode( "face motion" );
self.bLockGoalPos = false;
self ContinueMovement();
}
WaitForStop()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_stop" );
self waittill( "stop_soon" );
if ( !self shouldDoStopAnim() || self.movemode == "walk" )
{
self thread WaitForStop();
return;
}
goalPos = self GetPathGoalPos();
//assert( IsDefined( goalPos ) );
if ( !isDefined( goalPos ) )
{
self thread WaitForStop();
return;
}
meToStop = goalPos - self.origin;
finalFaceDir = getStopEndFaceDir( goalPos );
animState = getStopAnimState();
if ( self should_move_straight_ahead() )
{
animIndex = 0;
}
else
{
animIndex = getStopAnimIndex( animState, finalFaceDir );
}
stopAnim = self GetAnimEntry( animState, animIndex );
stopDelta = GetMoveDelta( stopAnim );
stopAngleDelta = GetAngleDelta( stopAnim );
// not enough room left to play the animation. abort. (i'm willing to squish/scale the anim up to 48 units.)
if ( Length( meToStop ) + 48 < Length( stopDelta ) )
{
self thread WaitForStop();
return;
}
stopData = self GetStopData( goalPos );
stopStartPos = self CalcAnimStartPos( stopData.pos, stopData.angles[1], stopDelta, stopAngleDelta );
stopStartPosDropped = self DropPosToGround( stopStartPos );
if ( !IsDefined( stopStartPosDropped ) )
{
self thread WaitForStop();
return;
}
if ( !self CanMovePointToPoint( stopData.pos, stopStartPosDropped ) )
{
self thread WaitForStop();
return;
}
self CancelAllBut( "stop", "sharpturn" );
self thread WaitForPathSet( "alienmove_endwait_pathsetwhilestopping", "alienmove_endwait_stop" );
// scale the anim if necessary, to make sure we end up where we wanted to end up.
scaleFactors = GetAnimScaleFactors( goalPos - self.origin, stopDelta );
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", VectorToAngles( meToStop ) );
self ScrAgentSetAnimScale( scaleFactors.xy, scaleFactors.z );
self PlayAnimNUntilNotetrack( animState, animIndex, animState, "end" );
self ScrAgentSetAnimScale( 1.0, 1.0 );
if ( self should_move_straight_ahead() )
self maps\mp\agents\alien\_alien_anim_utils::turnTowardsVector( self GetLookaheadDir() );
// Make sure we made it
goalPos = self GetPathGoalPos();
if ( DistanceSquared( self.origin, goalPos ) < ALLOW_SLIDE_DIST_SQR )
{
// Success
self ScrAgentSetAnimMode( "code_move_slide" );
self SetAnimState( "idle" ); // if all went well, idle state should kick in without this. if all didn't... cover it up.
return;
}
else
{
// Failure - return to move
StartMove();
ContinueMovement();
}
}
getStopEndFaceDir( goalPos )
{
if ( isDefined ( self.enemy ) )
return ( self.enemy.origin - goalPos );
return ( goalPos - self.origin );
}
getStopAnimState()
{
switch( self.movemode )
{
case "run":
case "jog":
return "run_stop";
case "walk":
return "walk_stop";
default:
AssertMsg( "Trying to get stop animState for unknown movemode: " + self.movemode );
}
}
getStopAnimIndex( animState, meToStop )
{
switch( animState )
{
case "walk_stop":
return 0;
case "run_stop":
return GetAngleIndexFromSelfYaw( meToStop );
}
}
WaitForPathSet( endOnNotify, killParentNotify )
{
self endon( "killanimscript" );
self endon( endOnNotify );
oldGoalPos = self ScrAgentGetGoalPos();
self waittill( "path_set" );
newGoalPos = self ScrAgentGetGoalPos();
if ( DistanceSquared( oldGoalPos, newGoalPos ) < 1 )
{
self thread WaitForPathSet( endOnNotify, killParentNotify );
return;
}
self notify( killParentNotify );
self ContinueMovement();
}
WaitForJumpSoon()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_jumpsoon" );
self waittill( "traverse_soon" );
self CancelAllBut( "jumpsoon" );
startNode = self GetNegotiationStartNode();
endNode = self GetNegotiationEndNode();
// Check if alien should do the run-to-leap animations
targetVector = endNode.origin - startNode.origin;
angleIndex = GetAngleIndexFromSelfYaw( endNode.origin - startNode.origin );
if ( !shouldDoLeapArrivalAnim( startNode, angleIndex ) )
{
self ContinueMovement();
return;
}
// Check if alien can move from anim start position to the start node
arrivalAnimState = "jump_launch_arrival";
arrivalAnim = self GetAnimEntry( arrivalAnimState, angleIndex );
moveDelta = GetMoveDelta( arrivalAnim );
angleYawDelta = GetAngleDelta( arrivalAnim );
if ( !self CanMovePointToPoint( self.origin, startNode.origin ) && !self.oriented )
{
self ContinueMovement();
return;
}
self thread WaitForPathSet( "alienmove_endwait_pathsetwhilejumping", "alienmove_endwait_jumpsoon" );
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
scaleFactors = GetAnimScaleFactors( startNode.origin - self.origin, moveDelta );
self ScrAgentSetAnimScale( scaleFactors.xy, scaleFactors.z );
self PlayAnimNAtRateUntilNotetrack( arrivalAnimState, angleIndex, self.moveplaybackrate, "jump_launch_arrival", "anim_will_finish" );
forward = targetVector;
up = AnglesToUp( self.angles );
left = VectorCross( up, forward );
forward = VectorCross( left, up );
right = (0,0,0) - left;
anglesToFace = AxisToAngles( forward, right, up );
self ScrAgentSetOrientMode( "face angle abs", anglesToFace );
self ScrAgentSetAnimScale( 1.0, 1.0 );
startNode = self GetNegotiationStartNode();
if ( isDefined( startNode ) && distanceSquared( self.origin, startNode.origin ) < ALLOW_SLIDE_DIST_SQR || self.oriented )
self ScrAgentSetAnimMode( "code_move_slide" ); // hope that we enter the traverse state at some point...
else
self ContinueMovement();
}
SetMoveAnim( moveMode )
{
if ( moveMode == "run" )
{
nEntries = self GetAnimEntryCount( "run" );
animWeights = [ /*01*/ 20, /*03*/ 80 ];
assert( animWeights.size == nEntries );
randIndex = maps\mp\alien\_utility::GetRandomIndex( animWeights );
assert( randIndex < nEntries );
self SetAnimState( "run", randIndex, self.moveplaybackrate );
}
else if ( moveMode == "jog" )
{
self SetAnimState( "jog", undefined, self.moveplaybackrate );
}
else if ( moveMode == "walk" )
{
self SetAnimState( "walk", undefined, self.moveplaybackrate );
}
else
{
assertmsg( "unimplemented move mode " + moveMode );
}
}
CancelAllBut( doNotCancel, doNotCancel2 )
{
cleanups = [ "runwalk", "sharpturn", "stop", "pathsetwhilestopping", "jumpsoon", "pathsetwhilejumping", "pathset", "nearmiss", "dodgechance", "stuck" ];
bCheckDoNotCancel = IsDefined( doNotCancel );
bCheckDoNotCancel2 = IsDefined( doNotCancel2 );
foreach ( cleanup in cleanups )
{
if ( bCheckDoNotCancel && cleanup == doNotCancel )
continue;
if ( bCheckDoNotCancel2 && cleanup == doNotCancel2 )
continue;
self notify( "alienmove_endwait_" + cleanup );
}
}
GetStopData( goalPos )
{
stopData = SpawnStruct();
if ( IsDefined( self.node ) )
{
stopData.pos = self.node.origin;
stopData.angles = self.node.angles;
}
else if ( isDefined( self.enemy ) )
{
stopData.pos = goalPos;
stopData.angles = vectorToAngles( self.enemy.origin - goalPos );
}
else
{
stopData.pos = goalPos;
stopData.angles = self.angles;
}
return stopData;
}
CalcAnimStartPos( stopPos, stopAngle, animDelta, animAngleDelta )
{
dAngle = stopAngle - animAngleDelta;
angles = ( 0, dAngle, 0 );
vForward = AnglesToForward( angles );
vRight = AnglesToRight( angles );
forward = vForward * animDelta[0];
right = vRight * animDelta[1];
return stopPos - forward + right;
}
onFlashbanged()
{
self DoStumble();
}
onDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset )
{
if ( IsDefined( level.dlc_can_do_pain_override_func ) )
{
painAllowed = [[level.dlc_can_do_pain_override_func]]( "move" );
if ( !painAllowed )
return;
}
if ( maps\mp\alien\_utility::is_pain_available( eAttacker,sMeansOfDeath ) )
self DoStumble( iDFlags, vDir, sHitLoc, iDamage, sMeansOfDeath, eAttacker );
}
DoStumble( iDFlags, damageDirection, hitLocation, iDamage, sMeansOfDeath, eAttacker )
{
self endon( "killanimscript" );
if ( self.playing_pain_animation )
return;
self CancelAllBut( undefined );
self.stateLocked = true;
self.playing_pain_animation = true;
is_stun = ( iDFlags & level.iDFLAGS_STUN );
if ( sMeansOfDeath == "MOD_MELEE" || is_stun )
{
animState = "pain_pushback";
animIndex = maps\mp\agents\alien\_alien_anim_utils::getPainAnimIndex( "push_back", damageDirection );
pain_notify = "pain_pushback";
}
else
{
animState = self maps\mp\agents\alien\_alien_anim_utils::getPainAnimState( "run_stumble", iDamage, is_stun );
animIndex = maps\mp\agents\alien\_alien_anim_utils::getPainAnimIndex( "run", damageDirection, hitLocation );
pain_notify = "run_stumble";
}
anime = self GetAnimEntry( animState, animIndex );
self maps\mp\alien\_utility::always_play_pain_sound( anime );
self maps\mp\alien\_utility::register_pain( anime );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
self ScrAgentSetAnimMode( "anim deltas" );
self PlayAnimNAtRateUntilNotetrack( animState, animIndex, self.movePlaybackRate, pain_notify, "code_move" );
self.playing_pain_animation = false;
self.stateLocked = false;
if ( shouldStartMove() )
self StartMove();
self ContinueMovement();
}
WaitForNearMiss( enemy )
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_nearmiss" );
DODGE_CHANCE = 0.5;
while ( true )
{
self waittill_any( "bulletwhizby", "damage" );
if( RandomFloat( 1.0 ) < DODGE_CHANCE )
continue;
if ( !self.playing_pain_animation )
{
DoDodge();
}
}
}
WaitForDodgeChance()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_dodgechance" );
currentLookAtDuration = 0.0;
currentDodgeTime = RandomIntRange( DODGE_CHANCE_LOOK_AT_TIME_MIN, DODGE_CHANCE_LOOK_AT_TIME_MAX );
lastTimeStamp = GetTime();
while ( true )
{
wait 0.1;
if ( IsAlive( self.enemy ) )
{
currentTime = GetTime();
enemyToMe = VectorNormalize( self.origin - self.enemy.origin );
enemyFacing = AnglesToForward( self.enemy.angles );
// Fail if enemy isn't looking at us
if ( VectorDot( enemytoMe, enemyFacing ) < DODGE_CHANCE_ENEMY_FACING_TOLERANCE )
{
currentLookAtDuration = 0.0;
continue;
}
currentLookAtDuration += currentTime - lastTimeStamp;
// Fail if enemy is too far away
if ( DistanceSquared( self.origin, self.enemy.origin ) > DODGE_CHANCE_MAX_DISTANCE_SQ )
{
continue;
}
// Fail if we're not navigating towards the enemy
meToEnemy = enemyToMe * -1.0;
myFacing = AnglesToForward( self.angles );
if ( VectorDot( meToEnemy, myFacing ) < DODGE_CHANCE_ALIEN_FACING_TOLERANCE )
{
continue;
}
if ( currentLookAtDuration >= currentDodgeTime && !self.playing_pain_animation )
{
DoDodge( "dodgechance" );
currentLookAtDuration = 0.0;
currentDodgeTime = RandomIntRange( DODGE_CHANCE_LOOK_AT_TIME_MIN, DODGE_CHANCE_LOOK_AT_TIME_MAX );
}
lastTimeStamp = currentTime;
}
}
}
canDodge()
{
switch( self maps\mp\alien\_utility::get_alien_type() )
{
case "elite":
case "mammoth":
case "spitter":
case "seeder":
return false;
default:
return true;
}
}
DoDodge( endwait )
{
self endon( "killanimscript" );
DODGE_FREQUENCY = 1000; // 1 second
if( IsDefined( self.last_dodge_time ) && GetTime() - self.last_dodge_time < DODGE_FREQUENCY )
return;
if ( IsAlive( self.enemy ) && DistanceSquared( self.origin, self.enemy.origin ) < MIN_DODGE_DIST_SQUARED )
return;
primary_dodge_anim_state = get_primary_dodge_anim_state();
if ( cointoss() )
{
if ( !TryDodge( primary_dodge_anim_state + "_left", endwait ) )
TryDodge( primary_dodge_anim_state + "_right", endwait );
}
else
{
if ( !TryDodge( primary_dodge_anim_state + "_right", endwait ) )
TryDodge( primary_dodge_anim_state + "_left", endwait );
}
}
get_primary_dodge_anim_state()
{
switch( self.movemode )
{
case "jog":
return "jog_dodge";
default:
return "run_dodge";
}
}
TryDodge( dodgeState, endwait )
{
MIN_DODGE_SCALE = 0.5;
dodgeEntry = self GetRandomAnimEntry( dodgeState );
dodgeAnim = self GetAnimEntry( dodgeState, dodgeEntry );
moveScale = GetSafeAnimMoveDeltaPercentage( dodgeAnim );
moveScale = min( moveScale, self.xyanimscale );
if ( moveScale < MIN_DODGE_SCALE )
return false;
self.last_dodge_time = GetTime();
self CancelAllBut( endwait );
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
self ScrAgentSetAnimScale( moveScale, 1.0 );
self PlayAnimUntilNotetrack( dodgeState, dodgeState, "end" );
self ScrAgentSetAnimScale( 1, 1 );
self ContinueMovement();
return true;
}
WaitForStuck()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_stuck" );
STUCK_DURATION = 2000.0;
nextStuckTime = GetTime() + STUCK_DURATION;
lastPos = self.origin;
STUCK_TOLERANCE = 1.0;
while ( true )
{
currentTime = GetTime();
LastDistance = Length( self.origin - lastPos );
if ( LastDistance > STUCK_TOLERANCE )
nextStuckTime = currentTime + STUCK_DURATION;
if ( nextStuckTime <= currentTime )
{
stuckLerp();
nextStuckTime = currentTime + STUCK_DURATION;
break;
}
lastPos = self.origin;
wait 0.1;
}
self ContinueMovement();
}
stuckLerp()
{
self endon( "killanimscript" );
self endon( "alienmove_endwait_stuck" );
self endon( "death" );
LERP_TIME = 0.2;
CancelAllBut( "stuck" );
currentAnim = self GetAnimEntry();
currentAnimLength = GetAnimLength( currentAnim );
currentAnimDistance = Length( GetMoveDelta( currentAnim ) );
lerpDistance = ( LERP_TIME / currentAnimLength ) * currentAnimDistance;
lerpDirection = self GetLookaheadDir();
endPos = self.origin + lerpDirection * lerpDistance;
self ScrAgentSetPhysicsMode( "noclip" );
self ScrAgentSetOrientMode( "face angle abs", VectorToAngles( lerpDirection ) );
self ScrAgentDoAnimLerp( self.origin, endPos, LERP_TIME );
wait LERP_TIME;
self SetOrigin( self.origin );
}
doWalkStart()
{
animState = "walk_start";
animIndex = GetRandomAnimEntry( animState );
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
self.bLockGoalPos = true;
self PlayAnimNAtRateUntilNotetrack( animState, animIndex, self.movePlaybackRate, animState, "code_move" );
self ScrAgentSetOrientMode( "face motion" );
self.bLockGoalPos = false;
}
doRunStart()
{
negStartNode = self GetNegotiationStartNode();
if ( IsDefined( negStartNode ) )
goalPos = negStartNode.origin;
else
goalPos = self GetPathGoalPos();
// GetPathGoalPos will return undefined if i don't have a path
if ( !IsDefined( goalPos ) )
return;
// don't play start if i have no room for the start.
if ( DistanceSquared( goalPos, self.origin ) < 100 * 100 )
return;
lookaheadDir = self GetLookaheadDir();
myVelocity = self GetVelocity();
if ( LengthSquared( myVelocity ) > 16 )
{
// don't need a start if i'm wallrunning and about to turn a corner onto another plane.
myUp = AnglesToUp( self.angles );
if ( VectorDot( myUp, (0,0,1) ) < 0.707 )
{
angleCos = VectorDot( myUp, lookaheadDir );
if ( angleCos > 0.707 || angleCos < -0.707 )
return;
}
}
self doStartMoveAnim( "run_start" );
}
doLeapToRunStart()
{
self doStartMoveAnim( "leap_to_run_start" );
}
should_move_straight_ahead()
{
switch ( self maps\mp\alien\_utility::get_alien_type() )
{
case "spitter":
case "seeder":
case "minion":
return true;
default:
return false;
}
}
should_do_sharp_turn()
{
switch ( self maps\mp\alien\_utility::get_alien_type() )
{
case "spitter":
case "seeder":
case "minion":
case "elite":
case "mammoth":
return false;
default:
return true;
}
}
doStartMoveAnim( animState )
{
if ( self should_move_straight_ahead() )
{
angleIndex = 0;
self maps\mp\agents\alien\_alien_anim_utils::turnTowardsVector( self GetLookaheadDir() );
}
else
{
angleIndex = getStartMoveAngleIndex();
}
// JohnW: Disabling trace check - mostly redundant from sharpturn traces in code
//startAnim = self GetAnimEntry( animState, angleIndex );
//startAnimTranslation = GetMoveDelta( startAnim );
//endPos = RotateVector( startAnimTranslation, self.angles ) + self.origin;
//if ( !self CanMovePointToPoint( self.origin, endPos ) )
//return;
self ScrAgentSetAnimMode( "anim deltas" );
self ScrAgentSetOrientMode( "face angle abs", self.angles );
self.bLockGoalPos = true;
self PlayAnimNAtRateUntilNotetrack( animState, angleIndex, self.movePlaybackRate, animState, "code_move" );
self ScrAgentSetOrientMode( "face motion" );
self.bLockGoalPos = false;
}
canDoStartMove()
{
if ( !isdefined( self.traverseComplete )
&& !isdefined( self.skipStartMove )
&& ( !isdefined( self.disableExits ) || self.disableExits == false ))
{
return true;
}
else
{
return false;
}
}
getStartMoveType()
{
previousAnimState = self.previousAnimState;
switch( previousAnimState )
{
case "traverse_jump":
return "leap-to-run";
default:
switch( self.movemode )
{
case "run":
return "run-start";
case "walk":
return "walk-start";
default:
return "run-start";
}
}
}
shouldDoStopAnim()
{
return ( isDefined( self.enableStop ) && self.enableStop == true );
}
shouldDoLeapArrivalAnim( startNode, angleIndex )
{
if ( startNode.type == "Jump" || startNode.type == "Jump Attack" ) // For jump nodes, always do run-to-leap animation
return true;
else if ( traversalStartFromIdle( startNode.animscript ) ) // If the traversal animation starts at the idle position, need to play run-to-leap
return true;
else if ( incomingAngleStraightAhead( self maps\mp\alien\_utility::get_alien_type(), angleIndex ) ) // For other traversals, do not play when the incoming angle is either 45 or 0
return false;
else
return true;
}
incomingAngleStraightAhead( alienType, angleIndex )
{
switch( alienType )
{
case "elite":
case "mammoth":
return ( angleIndex == 4 );
default:
return ( angleIndex == 3 || angleIndex == 4 || angleIndex == 5 );
}
}
traversalStartFromIdle( anim_script )
{
switch( anim_script )
{
case "alien_climb_up":
case "alien_climb_up_over_56":
case "climb_up_end_jump_side_l":
case "climb_up_end_jump_side_r":
case "alien_climb_up_ledge_18_run":
case "alien_climb_up_ledge_18_idle":
return true;
default:
return false;
}
}
CanDoTurnAnim( turnAnim )
{
HEIGHT_OFFSET = 16;
RADIUS_OFFSET = 10;
HEIGHT_OFFSET_COOR = ( 0, 0, 16 );
if ( !IsDefined( self GetPathGoalPos()) )
return false;
assert( isDefined( turnAnim ));
codeMoveTimes = GetNotetrackTimes( turnAnim, "code_move" );
assert( codeMoveTimes.size == 1 );
codeMoveTime = codeMoveTimes[ 0 ];
assert( codeMoveTime <= 1 );
moveDelta = GetMoveDelta( turnAnim, 0, codeMoveTime );
codeMovePoint = self LocalToWorldCoords( moveDelta );
codeMovePoint = GetGroundPosition( codeMovePoint, self.radius );
if ( !isDefined( codeMovePoint ) )
return false;
trace_passed = self AIPhysicsTracePassed( self.origin + HEIGHT_OFFSET_COOR, codeMovePoint + HEIGHT_OFFSET_COOR, self.radius - RADIUS_OFFSET, self.height - HEIGHT_OFFSET );
if ( trace_passed )
return true;
else
return false;
}
shouldStartMove()
{
angleIndex = getStartMoveAngleIndex();
return ( angleIndex < 3 || angleIndex > 5 ); //We do not want to do start move if the look ahead direction is straight ahead or 45 degree to either side
}
getStartMoveAngleIndex()
{
return GetAngleIndexFromSelfYaw( self GetLookaheadDir() );
}