940 lines
24 KiB
Plaintext
940 lines
24 KiB
Plaintext
#include animscripts\Utility;
|
|
#include animscripts\Combat_Utility;
|
|
#include animscripts\SetPoseMovement;
|
|
#include common_scripts\utility;
|
|
#using_animtree( "generic_human" );
|
|
|
|
MoveRun()
|
|
{
|
|
desiredPose = [[ self.choosePoseFunc ]]( "stand" );
|
|
|
|
switch( desiredPose )
|
|
{
|
|
case "stand":
|
|
if ( BeginStandRun() )// returns false( and does nothing ) if we're already stand - running
|
|
return;
|
|
|
|
if ( isDefined( self.run_overrideanim ) )
|
|
{
|
|
animscripts\move::MoveStandMoveOverride( self.run_overrideanim, self.run_override_weights );
|
|
return;
|
|
}
|
|
|
|
if ( changeWeaponStandRun() )
|
|
return;
|
|
|
|
if ( ReloadStandRun() )
|
|
return;
|
|
|
|
if ( self animscripts\utility::IsInCombat() )
|
|
MoveStandCombatNormal();
|
|
else
|
|
MoveStandNoncombatNormal();
|
|
break;
|
|
|
|
case "crouch":
|
|
if ( BeginCrouchRun() )// returns false( and does nothing ) if we're already crouch - running
|
|
return;
|
|
|
|
if ( isDefined( self.crouchrun_combatanim ) )
|
|
MoveCrouchRunOverride();
|
|
else
|
|
MoveCrouchRunNormal();
|
|
break;
|
|
|
|
default:
|
|
assert( desiredPose == "prone" );
|
|
if ( BeginProneRun() )// returns false( and does nothing ) if we're already prone - running
|
|
return;
|
|
|
|
ProneCrawl();
|
|
break;
|
|
}
|
|
}
|
|
|
|
GetRunAnim()
|
|
{
|
|
if ( !isdefined( self.a.moveAnimSet ) )
|
|
return %run_lowready_F;
|
|
|
|
if ( !self.faceMotion )
|
|
{
|
|
if ( self.stairsState == "none" || abs( self getMotionAngle() ) > 45 )
|
|
return moveAnim( "move_f" );
|
|
}
|
|
|
|
if ( self.stairsState == "up" )
|
|
return moveAnim( "stairs_up" );
|
|
else if ( self.stairsState == "down" )
|
|
return moveAnim( "stairs_down" );
|
|
|
|
return moveAnim( "straight" );
|
|
}
|
|
|
|
GetCrouchRunAnim()
|
|
{
|
|
if ( !isdefined( self.a.moveAnimSet ) )
|
|
return %crouch_fastwalk_F;
|
|
|
|
return moveAnim( "crouch" );
|
|
}
|
|
|
|
|
|
ProneCrawl()
|
|
{
|
|
self.a.movement = "run";
|
|
self setflaggedanimknob( "runanim", moveAnim( "prone" ), 1, .3, self.moveplaybackrate );
|
|
animscripts\shared::DoNoteTracksForTime( 0.25, "runanim" );
|
|
}
|
|
|
|
|
|
InitRunNGun()
|
|
{
|
|
if ( !isdefined( self.runNGun ) )
|
|
{
|
|
self notify( "stop_move_anim_update" );
|
|
self.update_move_anim_type = undefined;
|
|
|
|
self clearanim( %combatrun_backward, 0.2 );
|
|
self clearanim( %combatrun_right, 0.2 );
|
|
self clearanim( %combatrun_left, 0.2 );
|
|
|
|
self clearanim( %w_aim_2, 0.2 );
|
|
self clearanim( %w_aim_4, 0.2 );
|
|
self clearanim( %w_aim_6, 0.2 );
|
|
self clearanim( %w_aim_8, 0.2 );
|
|
|
|
self.runNGun = true;
|
|
}
|
|
}
|
|
|
|
StopRunNGun()
|
|
{
|
|
if ( isdefined( self.runNGun ) )
|
|
{
|
|
self clearanim( %run_n_gun, 0.2 );
|
|
self.runNGun = undefined;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
RunNGun( validTarget )
|
|
{
|
|
if ( validTarget )
|
|
{
|
|
enemyyaw = self GetPredictedYawToEnemy( 0.2 );
|
|
leftWeight = enemyyaw < 0;
|
|
}
|
|
else
|
|
{
|
|
enemyyaw = 0;
|
|
leftWeight = self.runNGunWeight < 0;
|
|
}
|
|
|
|
rightWeight = 1 - leftWeight;
|
|
|
|
maxRunNGunAngle = self.maxRunNGunAngle;
|
|
runNGunTransitionPoint = self.runNGunTransitionPoint;
|
|
runNGunIncrement = self.runNGunIncrement;
|
|
|
|
if ( !validTarget || ( squared( enemyyaw ) > maxRunNGunAngle * maxRunNGunAngle ) )
|
|
{
|
|
// phase out run n gun
|
|
self clearAnim( %add_fire, 0 );
|
|
if ( squared( self.runNGunWeight ) < runNGunIncrement * runNGunIncrement )
|
|
{
|
|
self.runNGunWeight = 0;
|
|
self.runNGun = undefined;
|
|
return false;
|
|
}
|
|
else if ( self.runNGunWeight > 0 )
|
|
{
|
|
self.runNGunWeight = self.runNGunWeight - runNGunIncrement;
|
|
}
|
|
else
|
|
{
|
|
self.runNGunWeight = self.runNGunWeight + runNGunIncrement;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newWeight = enemyyaw / maxRunNGunAngle;
|
|
diff = newWeight - self.runNGunWeight;
|
|
|
|
if ( abs( diff ) < runNGunTransitionPoint * 0.7 )
|
|
self.runNGunWeight = newWeight;
|
|
else if ( diff > 0 )
|
|
self.runNGunWeight = self.runNGunWeight + runNGunIncrement;
|
|
else
|
|
self.runNGunWeight = self.runNGunWeight - runNGunIncrement;
|
|
}
|
|
|
|
InitRunNGun();
|
|
|
|
absRunNGunWeight = abs( self.runNGunWeight );
|
|
|
|
if ( absRunNGunWeight > runNGunTransitionPoint )
|
|
{
|
|
weight = ( absRunNGunWeight - runNGunTransitionPoint ) / runNGunTransitionPoint;
|
|
weight = clamp( weight, 0, 1 );
|
|
|
|
self clearanim( self.runNGunAnims[ "F" ], 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "L" ], ( 1.0 - weight ) * leftWeight, 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "R" ], ( 1.0 - weight ) * rightWeight, 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "LB" ], weight * leftWeight, 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "RB" ], weight * rightWeight, 0.2 );
|
|
}
|
|
else
|
|
{
|
|
weight = clamp( absRunNGunWeight / runNGunTransitionPoint, 0, 1 );
|
|
|
|
self setAnimLimited( self.runNGunAnims[ "F" ], 1.0 - weight, 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "L" ], weight * leftWeight, 0.2 );
|
|
self setAnimLimited( self.runNGunAnims[ "R" ], weight * rightWeight, 0.2 );
|
|
|
|
if ( runNGunTransitionPoint < 1 )
|
|
{
|
|
self clearanim( self.runNGunAnims[ "LB" ], 0.2 );
|
|
self clearanim( self.runNGunAnims[ "RB" ], 0.2 );
|
|
}
|
|
}
|
|
|
|
self setFlaggedAnimKnob( "runanim", %run_n_gun, 1, 0.3, 0.8 );
|
|
|
|
self.a.allowedPartialReloadOnTheRunTime = gettime() + 500;
|
|
|
|
if ( validTarget && isplayer( self.enemy ) )
|
|
self updatePlayerSightAccuracy();
|
|
|
|
return true;
|
|
}
|
|
|
|
RunNGun_Backward()
|
|
{
|
|
// we don't blend the running-backward animation because it
|
|
// doesn't blend well with the run-left and run-right animations.
|
|
// it's also easier to just play one animation than rework everything
|
|
// to consider the possibility of multiple "backwards" animations
|
|
|
|
InitRunNGun();
|
|
|
|
self setFlaggedAnimKnob( "runanim", %combatwalk_B, 1, 0.3, 0.8 );
|
|
|
|
if ( isplayer( self.enemy ) )
|
|
self updatePlayerSightAccuracy();
|
|
|
|
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
|
|
|
self thread stopShootWhileMovingThreads();
|
|
|
|
self clearAnim( %combatwalk_B, 0.2 );
|
|
}
|
|
|
|
|
|
ReactToBulletsInterruptCheck()
|
|
{
|
|
self endon( "killanimscript" );
|
|
|
|
while ( 1 )
|
|
{
|
|
wait 0.2;
|
|
|
|
if ( !isdefined( self.reactingToBullet ) )
|
|
break;
|
|
|
|
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.pathGoalPos, self.origin ) < squared( 80 ) )
|
|
{
|
|
EndRunningReactToBullets();
|
|
self notify( "interrupt_react_to_bullet" );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
EndRunningReactToBullets()
|
|
{
|
|
self orientmode( "face default" );
|
|
self.reactingToBullet = undefined;
|
|
self.requestReactToBullet = undefined;
|
|
}
|
|
|
|
RunningReactToBullets()
|
|
{
|
|
self.aim_while_moving_thread = undefined;
|
|
self notify( "end_face_enemy_tracking" );
|
|
|
|
/#
|
|
assert( !isdefined( self.trackLoopThread ) );
|
|
self.trackLoopThread = undefined;
|
|
#/
|
|
|
|
self endon( "interrupt_react_to_bullet" );
|
|
|
|
self.reactingToBullet = true;
|
|
self orientmode( "face motion" );
|
|
|
|
reactAnimIndex = randomint( anim.runningReactToBullets.size );
|
|
if ( reactAnimIndex == anim.lastRunningReactAnim )
|
|
reactAnimIndex = ( reactAnimIndex + 1 ) % anim.runningReactToBullets.size;
|
|
|
|
anim.lastRunningReactAnim = reactAnimIndex;
|
|
|
|
reactAnim = anim.runningReactToBullets[ reactAnimIndex ];
|
|
self setFlaggedAnimKnobRestart( "reactanim", reactAnim, 1, 0.5 );
|
|
|
|
self thread ReactToBulletsInterruptCheck();
|
|
self animscripts\shared::DoNoteTracks( "reactanim" );
|
|
|
|
EndRunningReactToBullets();
|
|
}
|
|
|
|
|
|
CustomRunningReactToBullets()
|
|
{
|
|
self.aim_while_moving_thread = undefined;
|
|
self notify( "end_face_enemy_tracking" );
|
|
|
|
/#
|
|
assert( !isdefined( self.trackLoopThread ) );
|
|
self.trackLoopThread = undefined;
|
|
#/
|
|
|
|
self.reactingToBullet = true;
|
|
self orientmode( "face motion" );
|
|
|
|
assert( isdefined( self.run_overrideBulletReact ) );
|
|
|
|
reactAnimIndex = randomint( self.run_overrideBulletReact.size );
|
|
reactAnim = self.run_overrideBulletReact[ reactAnimIndex ];
|
|
|
|
self setFlaggedAnimKnobRestart( "reactanim", reactAnim, 1, 0.5 );
|
|
self thread ReactToBulletsInterruptCheck();
|
|
self animscripts\shared::DoNoteTracks( "reactanim" );
|
|
|
|
EndRunningReactToBullets();
|
|
}
|
|
|
|
|
|
GetSprintAnim()
|
|
{
|
|
sprintAnim = undefined;
|
|
|
|
if ( isdefined( self.grenade ) )
|
|
sprintAnim = moveAnim( "sprint_short" );
|
|
|
|
if ( !isdefined( sprintAnim ) )
|
|
sprintAnim = moveAnim( "sprint" );
|
|
|
|
return sprintAnim;
|
|
}
|
|
|
|
ShouldSprint()
|
|
{
|
|
if ( isdefined( self.sprint ) )
|
|
return true;
|
|
|
|
if ( isdefined( self.grenade ) && isdefined( self.enemy ) && self.frontShieldAngleCos == 1 )
|
|
return ( distanceSquared( self.origin, self.enemy.origin ) > 300 * 300 );
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
ShouldSprintForVariation()
|
|
{
|
|
if ( isdefined( self.neverSprintForVariation ) )
|
|
return false;
|
|
|
|
if ( !self.faceMotion || self.stairsState != "none" )
|
|
return false;
|
|
|
|
time = gettime();
|
|
|
|
if ( isdefined( self.dangerSprintTime ) )
|
|
{
|
|
if ( time < self.dangerSprintTime )
|
|
return true;
|
|
|
|
// if already sprinted, don't do it again for at least 5 seconds
|
|
if ( time - self.dangerSprintTime < 6000 )
|
|
return false;
|
|
}
|
|
|
|
if ( !isdefined( self.enemy ) || !isSentient( self.enemy ) )
|
|
return false;
|
|
|
|
if ( randomInt( 100 ) < 25 && ( self lastKnownTime( self.enemy ) + 2000 ) > time )
|
|
{
|
|
self.dangerSprintTime = time + 2000 + randomint( 1000 );
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
GetMovePlaybackRate()
|
|
{
|
|
rate = self.moveplaybackrate;
|
|
|
|
if ( self.lookaheadHitsStairs && self.stairsState == "none" && self.lookaheadDist < 300 )
|
|
rate *= 0.75;
|
|
|
|
return rate;
|
|
}
|
|
|
|
MoveStandCombatNormal()
|
|
{
|
|
//self clearanim( %walk_and_run_loops, 0.2 );
|
|
|
|
rate = GetMovePlaybackRate();
|
|
|
|
self setanimknob( %combatrun, 1.0, 0.5, rate );
|
|
|
|
decidedAnimation = false;
|
|
|
|
if ( isdefined( self.requestReactToBullet ) && gettime() - self.requestReactToBullet < 100 && randomFloat( 1 ) < self.a.reactToBulletChance )
|
|
{
|
|
StopRunNGun();
|
|
RunningReactToBullets();
|
|
return;
|
|
}
|
|
|
|
if ( self ShouldSprint() )
|
|
{
|
|
self setFlaggedAnimKnob( "runanim", GetSprintAnim(), 1, 0.5 );
|
|
decidedAnimation = true;
|
|
}
|
|
else if ( isdefined( self.enemy ) && animscripts\move::MayShootWhileMoving() )
|
|
{
|
|
runShootWhileMovingThreads();
|
|
|
|
if ( !self.faceMotion )
|
|
{
|
|
self thread faceEnemyAimTracking();
|
|
}
|
|
else if ( ( self.shootStyle != "none" && !isdefined( self.noRunNGun ) ) )
|
|
{
|
|
self notify( "end_face_enemy_tracking" );
|
|
self.aim_while_moving_thread = undefined;
|
|
|
|
/#
|
|
assert( !isdefined( self.trackLoopThread ) );
|
|
self.trackLoopThread = undefined;
|
|
#/
|
|
|
|
if ( CanShootWhileRunningForward() )
|
|
{
|
|
decidedAnimation = self RunNGun( true );
|
|
}
|
|
else if ( CanShootWhileRunningBackward() )
|
|
{
|
|
self RunNGun_Backward();
|
|
return;
|
|
}
|
|
}
|
|
else if ( isdefined( self.runNGunWeight ) && self.runNGunWeight != 0 )
|
|
{
|
|
// can't shoot enemy anymore but still need to clear out runNGun
|
|
decidedAnimation = self RunNGun( false );
|
|
}
|
|
}
|
|
else if ( isdefined( self.runNGunWeight ) && self.runNGunWeight != 0 )
|
|
{
|
|
decidedAnimation = self RunNGun( false );
|
|
}
|
|
|
|
if ( !decidedAnimation )
|
|
{
|
|
StopRunNGun();
|
|
|
|
if ( isdefined( self.requestReactToBullet ) && gettime() - self.requestReactToBullet < 100 && self.a.reactToBulletChance != 0 )
|
|
{
|
|
RunningReactToBullets();
|
|
return;
|
|
}
|
|
|
|
if ( ShouldSprintForVariation() )
|
|
runAnim = moveAnim( "sprint_short" );
|
|
else
|
|
runAnim = GetRunAnim();
|
|
|
|
self setFlaggedAnimKnobLimited( "runanim", runAnim, 1, 0.1, 1, true );
|
|
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ), self.sideStepRate );
|
|
|
|
// Play the appropriately weighted run animations for the direction he's moving
|
|
self thread SetCombatStandMoveAnimWeights( "run" );
|
|
}
|
|
|
|
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
|
|
|
self thread stopShootWhileMovingThreads();
|
|
}
|
|
|
|
faceEnemyAimTracking()
|
|
{
|
|
self notify( "want_aim_while_moving" );
|
|
|
|
assert( isdefined( self.aim_while_moving_thread ) == isdefined( self.trackLoopThread ) );
|
|
assertex( !isdefined( self.trackLoopThread ) || (self.trackLoopThreadType == "faceEnemyAimTracking"), self.trackLoopThreadType );
|
|
|
|
if ( isdefined( self.aim_while_moving_thread ) )
|
|
return;
|
|
|
|
self.aim_while_moving_thread = true;
|
|
|
|
/#
|
|
self.trackLoopThread = thisthread;
|
|
self.trackLoopThreadType = "faceEnemyAimTracking";
|
|
#/
|
|
|
|
self endon( "killanimscript" );
|
|
self endon( "end_face_enemy_tracking" );
|
|
|
|
self setDefaultAimLimits();
|
|
|
|
self setAnimLimited( %walk_aim_2 );
|
|
self setAnimLimited( %walk_aim_4 );
|
|
self setAnimLimited( %walk_aim_6 );
|
|
self setAnimLimited( %walk_aim_8 );
|
|
|
|
self animscripts\shared::trackLoop( %w_aim_2, %w_aim_4, %w_aim_6, %w_aim_8 );
|
|
}
|
|
|
|
endFaceEnemyAimTracking()
|
|
{
|
|
self.aim_while_moving_thread = undefined;
|
|
self notify( "end_face_enemy_tracking" );
|
|
|
|
/#
|
|
assert( !isdefined( self.trackLoopThread ) );
|
|
self.trackLoopThread = undefined;
|
|
#/
|
|
}
|
|
|
|
runShootWhileMovingThreads()
|
|
{
|
|
self notify( "want_shoot_while_moving" );
|
|
|
|
if ( isdefined( self.shoot_while_moving_thread ) )
|
|
return;
|
|
self.shoot_while_moving_thread = true;
|
|
|
|
self thread RunDecideWhatAndHowToShoot();
|
|
self thread RunShootWhileMoving();
|
|
}
|
|
|
|
stopShootWhileMovingThreads()// we don't stop them if we shoot while moving again
|
|
{
|
|
self endon( "killanimscript" );
|
|
self endon( "want_shoot_while_moving" );
|
|
self endon( "want_aim_while_moving" );
|
|
|
|
wait .05;
|
|
|
|
self notify( "end_shoot_while_moving" );
|
|
self notify( "end_face_enemy_tracking" );
|
|
self.shoot_while_moving_thread = undefined;
|
|
self.aim_while_moving_thread = undefined;
|
|
|
|
/#
|
|
assert( !isdefined( self.trackLoopThread ) );
|
|
self.trackLoopThread = undefined;
|
|
#/
|
|
|
|
self.runNGun = undefined;
|
|
}
|
|
|
|
|
|
RunDecideWhatAndHowToShoot()
|
|
{
|
|
self endon( "killanimscript" );
|
|
self endon( "end_shoot_while_moving" );
|
|
self animscripts\shoot_behavior::decideWhatAndHowToShoot( "normal" );
|
|
}
|
|
RunShootWhileMoving()
|
|
{
|
|
self endon( "killanimscript" );
|
|
self endon( "end_shoot_while_moving" );
|
|
self animscripts\move::shootWhileMoving();
|
|
}
|
|
|
|
aimedSomewhatAtEnemy()
|
|
{
|
|
weaponAngles = self getMuzzleAngle();
|
|
anglesToShootPos = vectorToAngles( self.enemy getShootAtPos() - self getMuzzlePos() );
|
|
|
|
if ( AbsAngleClamp180( weaponAngles[ 1 ] - anglesToShootPos[ 1 ] ) > 15 )
|
|
return false;
|
|
|
|
return AbsAngleClamp180( weaponAngles[ 0 ] - anglesToShootPos[ 0 ] ) <= 20;
|
|
}
|
|
|
|
CanShootWhileRunningForward()
|
|
{
|
|
// continue runNGun if runNGunWeight != 0
|
|
if ( ( !isdefined( self.runNGunWeight ) || self.runNGunWeight == 0 ) && abs( self getMotionAngle() ) > self.maxRunNGunAngle )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
CanShootWhileRunningBackward()
|
|
{
|
|
if ( 180 - abs( self getMotionAngle() ) >= 45 )
|
|
return false;
|
|
|
|
enemyyaw = self GetPredictedYawToEnemy( 0.2 );
|
|
if ( abs( enemyyaw ) > 30 )
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
CanShootWhileRunning()
|
|
{
|
|
return animscripts\move::MayShootWhileMoving() && isdefined( self.enemy ) && ( CanShootWhileRunningForward() || CanShootWhileRunningBackward() );
|
|
}
|
|
|
|
GetPredictedYawToEnemy( lookAheadTime )
|
|
{
|
|
assert( isdefined( self.enemy ) );
|
|
|
|
selfPredictedPos = self.origin;
|
|
moveAngle = self.angles[ 1 ] + self getMotionAngle();
|
|
selfPredictedPos += ( cos( moveAngle ), sin( moveAngle ), 0 ) * length( self.velocity ) * lookAheadTime;
|
|
|
|
yaw = self.angles[ 1 ] - VectorToYaw( self.enemy.origin - selfPredictedPos );
|
|
yaw = AngleClamp180( yaw );
|
|
return yaw;
|
|
}
|
|
|
|
MoveStandNoncombatNormal()
|
|
{
|
|
self endon( "movemode" );
|
|
|
|
self clearanim( %combatrun, 0.6 );
|
|
|
|
rate = GetMovePlaybackRate();
|
|
|
|
self setanimknoball( %combatrun, %body, 1, 0.2, rate );
|
|
|
|
if ( self ShouldSprint() )
|
|
runAnim = GetSprintAnim();
|
|
else
|
|
runAnim = GetRunAnim();
|
|
|
|
if ( self.stairsState == "none" )
|
|
transTime = 0.3; // 0.3 because it pops when the AI goes from combat to noncombat
|
|
else
|
|
transTime = 0.1; // need to transition to stairs quickly
|
|
|
|
self setflaggedanimknob( "runanim", runAnim, 1, transTime, 1, true );
|
|
|
|
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
|
self thread SetCombatStandMoveAnimWeights( "run" );
|
|
|
|
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
|
}
|
|
|
|
MoveCrouchRunOverride()
|
|
{
|
|
self endon( "movemode" );
|
|
|
|
self setflaggedanimknoball( "runanim", self.crouchrun_combatanim, %body, 1, 0.4, self.moveplaybackrate );
|
|
animscripts\shared::DoNoteTracks( "runanim" );
|
|
}
|
|
|
|
MoveCrouchRunNormal()
|
|
{
|
|
self endon( "movemode" );
|
|
|
|
// Play the appropriately weighted crouchrun animations for the direction he's moving
|
|
forward_anim = GetCrouchRunAnim();
|
|
|
|
self setanimknob( forward_anim, 1, 0.4 );
|
|
|
|
self thread UpdateMoveAnimWeights( "crouchrun", forward_anim, %crouch_fastwalk_B, %crouch_fastwalk_L, %crouch_fastwalk_R );
|
|
|
|
self setflaggedanimknoball( "runanim", %crouchrun, %body, 1, 0.2, self.moveplaybackrate );
|
|
|
|
animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
|
|
}
|
|
|
|
ReloadStandRun()
|
|
{
|
|
reloadIfEmpty = isdefined( self.a.allowedPartialReloadOnTheRunTime ) && self.a.allowedPartialReloadOnTheRunTime > gettime();
|
|
reloadIfEmpty = reloadIfEmpty || ( isdefined( self.enemy ) && distanceSquared( self.origin, self.enemy.origin ) < 256 * 256 );
|
|
if ( reloadIfEmpty )
|
|
{
|
|
if ( !self NeedToReload( 0 ) )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
if ( !self NeedToReload( .5 ) )
|
|
return false;
|
|
}
|
|
|
|
if ( isdefined( self.grenade ) )
|
|
return false;
|
|
|
|
if ( !self.faceMotion || self.stairsState != "none" )
|
|
return false;
|
|
|
|
// if not allowed to shoot, not allowed to reload
|
|
if ( isdefined( self.dontShootWhileMoving ) || isdefined( self.noRunReload ) )
|
|
return false;
|
|
|
|
if ( self CanShootWhileRunning() && !self NeedToReload( 0 ) )
|
|
return false;
|
|
|
|
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.origin, self.pathGoalPos ) < 256 * 256 )
|
|
return false;
|
|
|
|
motionAngle = AngleClamp180( self getMotionAngle() );
|
|
|
|
// want to be running forward; otherwise we won't see the animation play!
|
|
if ( abs( motionAngle ) > 25 )
|
|
return false;
|
|
|
|
if ( !usingRifleLikeWeapon() )
|
|
return false;
|
|
|
|
// need to restart the run cycle because the reload animation has to be played from start to finish!
|
|
// the goal is to play it only when we're near the end of the run cycle.
|
|
if ( !runLoopIsNearBeginning() )
|
|
return false;
|
|
|
|
// call in a separate function so we can cleanup if we get an endon
|
|
ReloadStandRunInternal();
|
|
|
|
// notify "abort_reload" in case the reload didn't finish, maybe due to "movemode" notify. works with handleDropClip() in shared.gsc
|
|
self notify( "abort_reload" );
|
|
|
|
self orientmode( "face default" );
|
|
|
|
return true;
|
|
}
|
|
|
|
ReloadStandRunInternal()
|
|
{
|
|
self endon( "movemode" );
|
|
|
|
self orientmode( "face motion" );
|
|
|
|
flagName = "reload_" + getUniqueFlagNameIndex();
|
|
|
|
self setFlaggedAnimKnobAllRestart( flagName, %run_lowready_reload, %body, 1, 0.25 );
|
|
|
|
self.update_move_front_bias = true;
|
|
|
|
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
|
self thread SetCombatStandMoveAnimWeights( "run" );
|
|
animscripts\shared::DoNoteTracks( flagName );
|
|
|
|
self.update_move_front_bias = undefined;
|
|
}
|
|
|
|
runLoopIsNearBeginning()
|
|
{
|
|
// there are actually 3 loops (left foot, right foot) in one animation loop.
|
|
|
|
animfraction = self getAnimTime( %walk_and_run_loops );
|
|
loopLength = getAnimLength( %run_lowready_F ) / 3.0;
|
|
animfraction *= 3.0;
|
|
if ( animfraction > 3 )
|
|
animfraction -= 2.0;
|
|
else if ( animfraction > 2 )
|
|
animfraction -= 1.0;
|
|
|
|
if ( animfraction < .15 / loopLength )
|
|
return true;
|
|
if ( animfraction > 1 - .3 / loopLength )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
SetMoveNonForwardAnims( backAnim, leftAnim, rightAnim, rate )
|
|
{
|
|
if ( !isdefined( rate ) )
|
|
rate = 1;
|
|
|
|
self setAnimKnobLimited( backAnim, 1, 0.1, rate, true );
|
|
self setAnimKnobLimited( leftAnim, 1, 0.1, rate, true );
|
|
self setAnimKnobLimited( rightAnim, 1, 0.1, rate, true );
|
|
}
|
|
|
|
SetCombatStandMoveAnimWeights( moveAnimType )
|
|
{
|
|
UpdateMoveAnimWeights( moveAnimType, %combatrun_forward, %combatrun_backward, %combatrun_left, %combatrun_right );
|
|
}
|
|
|
|
UpdateMoveAnimWeights( moveAnimType, frontAnim, backAnim, leftAnim, rightAnim )
|
|
{
|
|
if ( isdefined( self.update_move_anim_type ) && self.update_move_anim_type == moveAnimType )
|
|
return;
|
|
|
|
self notify( "stop_move_anim_update" );
|
|
|
|
self.update_move_anim_type = moveAnimType;
|
|
self.wasFacingMotion = undefined;
|
|
|
|
self endon( "killanimscript" );
|
|
self endon( "move_interrupt" );
|
|
self endon( "stop_move_anim_update" );
|
|
|
|
for ( ;; )
|
|
{
|
|
UpdateRunWeightsOnce( frontAnim, backAnim, leftAnim, rightAnim );
|
|
wait .05;
|
|
waittillframeend;
|
|
}
|
|
}
|
|
|
|
UpdateRunWeightsOnce( frontAnim, backAnim, leftAnim, rightAnim )
|
|
{
|
|
//assert( !isdefined( self.runNGun ) || isdefined( self.update_move_front_bias ) );
|
|
|
|
if ( self.faceMotion && !self shouldCQB() && !isdefined( self.update_move_front_bias ) )
|
|
{
|
|
// once you start to face motion, don't need to change weights
|
|
if ( !isdefined( self.wasFacingMotion ) )
|
|
{
|
|
self.wasFacingMotion = 1;
|
|
self setanim( frontAnim, 1, 0.2, 1, true );
|
|
self setanim( backAnim, 0, 0.2, 1, true );
|
|
self setanim( leftAnim, 0, 0.2, 1, true );
|
|
self setanim( rightAnim, 0, 0.2, 1, true );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
self.wasFacingMotion = undefined;
|
|
|
|
// Play the appropriately weighted animations for the direction he's moving.
|
|
animWeights = animscripts\utility::QuadrantAnimWeights( self getMotionAngle() );
|
|
|
|
if ( isdefined( self.update_move_front_bias ) )
|
|
{
|
|
animWeights[ "back" ] = 0.0;
|
|
if ( animWeights[ "front" ] < .2 )
|
|
animWeights[ "front" ] = .2;
|
|
}
|
|
|
|
self setanim( frontAnim, animWeights[ "front" ], 0.2, 1, true );
|
|
self setanim( backAnim, animWeights[ "back" ], 0.2, 1, true );
|
|
self setanim( leftAnim, animWeights[ "left" ], 0.2, 1, true );
|
|
self setanim( rightAnim, animWeights[ "right" ], 0.2, 1, true );
|
|
}
|
|
}
|
|
|
|
|
|
// change our weapon while running if we want to and can
|
|
changeWeaponStandRun()
|
|
{
|
|
// right now this only handles shotguns, but it could do other things too
|
|
wantShotgun = ( isdefined( self.wantShotgun ) && self.wantShotgun );
|
|
usingShotgun = isShotgun( self.weapon );
|
|
if ( wantShotgun == usingShotgun )
|
|
return false;
|
|
|
|
if ( !isdefined( self.pathGoalPos ) || distanceSquared( self.origin, self.pathGoalPos ) < 256 * 256 )
|
|
return false;
|
|
|
|
if ( usingSidearm() )
|
|
return false;
|
|
assert( self.weapon == self.primaryweapon || self.weapon == self.secondaryweapon );
|
|
|
|
if ( self.weapon == self.primaryweapon )
|
|
{
|
|
if ( !wantShotgun )
|
|
return false;
|
|
if ( isShotgun( self.secondaryweapon ) )
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
assert( self.weapon == self.secondaryweapon );
|
|
|
|
if ( wantShotgun )
|
|
return false;
|
|
if ( isShotgun( self.primaryweapon ) )
|
|
return false;
|
|
}
|
|
|
|
// want to be running forward; otherwise we won't see the animation play!
|
|
motionAngle = AngleClamp180( self getMotionAngle() );
|
|
if ( abs( motionAngle ) > 25 )
|
|
return false;
|
|
|
|
if ( !runLoopIsNearBeginning() )
|
|
return false;
|
|
|
|
if ( wantShotgun )
|
|
shotgunSwitchStandRunInternal( "shotgunPullout", %shotgun_CQBrun_pullout, "gun_2_chest", "none", self.secondaryweapon, "shotgun_pickup" );
|
|
else
|
|
shotgunSwitchStandRunInternal( "shotgunPutaway", %shotgun_CQBrun_putaway, "gun_2_back", "back", self.primaryweapon, "shotgun_pickup" );
|
|
|
|
self notify( "switchEnded" );
|
|
|
|
return true;
|
|
}
|
|
|
|
shotgunSwitchStandRunInternal( flagName, switchAnim, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack )
|
|
{
|
|
self endon( "movemode" );
|
|
|
|
self setFlaggedAnimKnobAllRestart( flagName, switchAnim, %body, 1, 0.25 );
|
|
|
|
self.update_move_front_bias = true;
|
|
|
|
self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
|
|
self thread SetCombatStandMoveAnimWeights( "run" );
|
|
|
|
self thread watchShotgunSwitchNotetracks( flagName, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack );
|
|
|
|
animscripts\shared::DoNoteTracksForTimeIntercept( getAnimLength( switchAnim ) - 0.25, flagName, ::interceptNotetracksForWeaponSwitch );
|
|
|
|
self.update_move_front_bias = undefined;
|
|
}
|
|
|
|
interceptNotetracksForWeaponSwitch( notetrack )
|
|
{
|
|
if ( notetrack == "gun_2_chest" || notetrack == "gun_2_back" )
|
|
return true;// "don't do the default behavior for this notetrack"
|
|
}
|
|
|
|
watchShotgunSwitchNotetracks( flagName, dropGunNotetrack, putGunOnTag, newGun, pickupNewGunNotetrack )
|
|
{
|
|
self endon( "killanimscript" );
|
|
self endon( "movemode" );
|
|
self endon( "switchEnded" );
|
|
|
|
self waittillmatch( flagName, dropGunNotetrack );
|
|
|
|
animscripts\shared::placeWeaponOn( self.weapon, putGunOnTag );
|
|
self thread shotgunSwitchFinish( newGun );
|
|
|
|
self waittillmatch( flagName, pickupNewGunNotetrack );
|
|
self notify( "complete_weapon_switch" );
|
|
}
|
|
|
|
shotgunSwitchFinish( newGun )
|
|
{
|
|
self endon( "death" );
|
|
|
|
self waittill_any( "killanimscript", "movemode", "switchEnded", "complete_weapon_switch" );
|
|
|
|
self.lastweapon = self.weapon;
|
|
|
|
animscripts\shared::placeWeaponOn( newGun, "right" );
|
|
assert( self.weapon == newGun );// placeWeaponOn should have handled this
|
|
|
|
// reset ammo (assume fully loaded weapon)
|
|
self.bulletsInClip = weaponClipSize( self.weapon );
|
|
}
|
|
|