#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() )
		{
			if ( self.subclass == "moon" )
			{
				MoveStandCombatMoon();
			}
			else			
			{
				MoveStandCombatNormal();
			}		
		}	
		else
		{			
			if ( self.subclass == "moon" )
			{
				MoveStandNoncombatMoon();
			}
			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
			if ( self.subclass == "moon" )
			{
				MoveCrouchRunMoon();
			}
			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 anim.animsets.move[ "run" ][ "straight" ];
		
	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 anim.animsets.move[ "run" ][ "crouch" ];
		
	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 set_move_anim_start_point();
		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();
}

//blend differently than MoveStandCombatNormal based on a dvar. This is done so cqb blend can be changed on the moon.
MoveStandCombatMoon()
{

	rate = GetMovePlaybackRate();
	
	run_anim_blend = 0.8;
	if ( IsDefined( self.run_blend_finish_time ) )
	{
		run_anim_blend = self.run_blend_finish_time;
		self.run_blend_finish_time = undefined;
	}
	
	run_blend_str = GetDvar("scr_run_blend");
	if(run_blend_str != "")
	{
		run_anim_blend = Float(run_blend_str);
	}
		
	self setanimknob( %combatrun, 1.0, run_anim_blend, 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, run_anim_blend );
		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, run_anim_blend, 1, true );
		self set_move_anim_start_point();
		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( get_run_aim_tracking_anim_by_name( "add_aim_down" ) );
	self setAnimLimited( get_run_aim_tracking_anim_by_name( "add_aim_left" ) );
	self setAnimLimited( get_run_aim_tracking_anim_by_name( "add_aim_right" ) );
	self setAnimLimited( get_run_aim_tracking_anim_by_name( "add_aim_up" ) );

	self animscripts\shared::trackLoop( %w_aim_2, %w_aim_4, %w_aim_6, %w_aim_8 );
}

get_run_aim_tracking_anim_by_name( name )
{
	assert( IsDefined( name ) );
	assert( IsDefined( anim.animsets.runAimTracking[name] ) ); 
	
	if( IsDefined( self.customRunAimTrackingAnimset ) && IsDefined( self.customRunAimTrackingAnimset[name] ) )
	{
		return self.customRunAimTrackingAnimset[name];
	}
	else
	{
		return anim.animsets.runAimTracking[name];
	}
}

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();
	
	combat_run_blend = 0.2;
	self setanimknoball( %combatrun, %body, 1, combat_run_blend, rate );

	if ( self ShouldSprint() )
		runAnim = GetSprintAnim();
	else
		runAnim = GetRunAnim();
		
	run_anim_blend = 0.3;
	
	if ( self.stairsState == "none" )
	{
		transTime = 0.3;	// 0.3 because it pops when the AI goes from combat to noncombat
		if ( IsDefined( self.run_blend_finish_time ) )
		{
			transTime = self.run_blend_finish_time;
			self.run_blend_finish_time = undefined;
		}
	}
	else
	{
		transTime = 0.1;	// need to transition to stairs quickly
	}
	
	self setflaggedanimknob( "runanim", runAnim, 1, transTime, 1, true );
	self set_move_anim_start_point();
	self SetMoveNonForwardAnims( moveAnim( "move_b" ), moveAnim( "move_l" ), moveAnim( "move_r" ) );
	self thread SetCombatStandMoveAnimWeights( "run" );

	animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
}

//same as MoveStandNoncombatNormal, but by splitting this out we can have different blends for the moon actors.
MoveStandNoncombatMoon()
{
	self endon( "movemode" );

	self clearanim( %combatrun, 0.6 );

	rate = GetMovePlaybackRate();
	
	run_anim_blend = 0.8;
	
	if ( IsDefined( self.run_blend_finish_time ) )
	{
		run_anim_blend = self.run_blend_finish_time;
		self.run_blend_finish_time = undefined;
	}
	
	//TagCC<NOTE>: want to eventually get past using this, and delete.
	run_blend_str = GetDvar("scr_run_blend");
	if(run_blend_str != "")
	{
		run_anim_blend = Float(run_blend_str);
	}	
	
	self setanimknoball( %combatrun, %body, 1, run_anim_blend, rate );

	if ( self ShouldSprint() )
		runAnim = GetSprintAnim();
	else
		runAnim = GetRunAnim();

	if ( self.stairsState != "none" )
	{
		run_anim_blend = 0.1;	// need to transition to stairs quickly
	}
	
	self setflaggedanimknob( "runanim", runAnim, 1, run_anim_blend, 1, true );
	self set_move_anim_start_point();
	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();
	
	run_anim_blend = 0.4;
	if ( IsDefined( self.run_blend_finish_time ) )
	{
		run_anim_blend = self.run_blend_finish_time;
		self.run_blend_finish_time = undefined;
	}

	self setanimknob( forward_anim, 1, run_anim_blend );

	self thread UpdateMoveAnimWeights( "crouchrun", forward_anim, anim.animsets.move[ "run" ][ "crouch_b" ], anim.animsets.move[ "run" ][ "crouch_l" ], anim.animsets.move[ "run" ][ "crouch_r" ] );

	self setflaggedanimknoball( "runanim", %crouchrun, %body, 1, 0.2, self.moveplaybackrate );

	animscripts\shared::DoNoteTracksForTime( 0.2, "runanim" );
}

MoveCrouchRunMoon()
{
	self endon( "movemode" );

	// Play the appropriately weighted crouchrun animations for the direction he's moving
	forward_anim = GetCrouchRunAnim();
	
	run_anim_blend = 0.8;
	
	if ( IsDefined( self.run_blend_finish_time ) )
	{
		run_anim_blend = self.run_blend_finish_time;
		self.run_blend_finish_time = undefined;
	}
	
	run_blend_str = GetDvar("scr_run_blend");
	if(run_blend_str != "")
	{
		run_anim_blend = Float(run_blend_str);
	}

	self setanimknob( forward_anim, 1, run_anim_blend );

	self thread UpdateMoveAnimWeights( "crouchrun", forward_anim, anim.animsets.move[ "run" ][ "crouch_b" ], anim.animsets.move[ "run" ][ "crouch_l" ], anim.animsets.move[ "run" ][ "crouch_r"] );

	self setflaggedanimknoball( "runanim", %crouchrun, %body, 1, run_anim_blend, 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( GetRunAnim() ) / 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 );
}

