#include animscripts\combat_utility;
#include animscripts\utility;
#include animscripts\shared;
#include common_scripts\utility;
#using_animtree( "generic_human" );


// TODO:
// - figure out why aiming range is incorrect (aiming arc seems a bit off)

main()
{
	self endon( "killanimscript" );
    animscripts\utility::initialize( "cover_prone" );

	// TODO: run cover crouch or exposed crouch
	if ( weaponClass( self.weapon ) == "rocketlauncher" )
	{
		animscripts\combat::main();
		return;
	}

	if ( isDefined( self.a.arrivalType ) && self.a.arrivalType == "prone_saw" )
	{
		assert( isDefined( self.node.turretInfo ) );
		self animscripts\cover_wall::useSelfPlacedTurret( "saw_bipod_prone", "weapon_saw_MG_Setup" );
	}
	else if ( isDefined( self.node.turret ) )
	{
		self animscripts\cover_wall::useStationaryTurret();
	}

	// if we're too close to our enemy, stand up
	// (285 happens to be the same distance at which we leave cover and go into exposed if our enemy approaches)
	if ( isDefined( self.enemy ) && lengthSquared( self.origin - self.enemy.origin ) < squared( 512 ) )
	{
		self thread animscripts\combat::main();
		return;
	}

	self setup_cover_prone();

    self.coverNode = self.node;
	self OrientMode( "face angle", self.coverNode.angles[ 1 ] );

	self.a.goingToProneAim = true;
	self setProneAnimNodes( -45, 45, %prone_legs_down, %exposed_modern, %prone_legs_up );
	if ( self.a.pose != "prone" )
		self prone_transitionTo( "prone" );
	else
		self EnterProneWrapper( 0 );

	self thread aimIdleThread();
	
	setupProneAim( 0.2 );
	self setAnim( %prone_aim_5, 1, 0.1 );
	
	// face the direction of our covernode
	self OrientMode( "face angle", self.coverNode.angles[ 1 ] );
	self animmode( "zonly_physics" );

	self proneCombatMainLoop();

	self notify( "stop_deciding_how_to_shoot" );

}

end_script()
{
	self.a.goingToProneAim = undefined;
}

idleThread()
{
	self endon( "killanimscript" );
	self endon( "kill_idle_thread" );
	for ( ;; )
	{
		idleAnim = animArrayPickRandom( "prone_idle" );
		self setflaggedanimlimited( "idle", idleAnim );
		self waittillmatch( "idle", "end" );
		self clearanim( idleAnim, .2 );
	}
}

UpdateProneWrapper( time )
{
	self UpdateProne( %prone_aim_feet_45up, %prone_aim_feet_45down, 1, time, 1 );
	self setanim( %exposed_aiming, 1, .2 );
}

proneCombatMainLoop()
{
	self endon( "killanimscript" );	

	self thread trackShootEntOrPos();

//	self thread ReacquireWhenNecessary();

	self thread animscripts\shoot_behavior::decideWhatAndHowToShoot( "normal" );

//	self resetGiveUpOnEnemyTime();

	desynched = ( gettime() > 2500 );

	//prof_begin("prone_combat");

	for ( ;; )
	{
		self animscripts\utility::IsInCombat();// reset our in - combat state

		self UpdateProneWrapper( 0.05 );

		if ( !desynched )
		{
			wait( 0.05 + randomfloat( 1.5 ) );
			desynched = true;
			continue;
		}

		if ( !isdefined( self.shootPos ) )
		{
			assert( !isdefined( self.shootEnt ) );
			if ( considerThrowGrenade() )
				continue;

			wait( 0.05 );
			continue;
		}

		assert( isdefined( self.shootPos ) );// we can use self.shootPos after this point.
//		self resetGiveUpOnEnemyTime();

		// if we're too close to our enemy, stand up
		// (285 happens to be the same distance at which we leave cover and go into exposed if our enemy approaches)
		distSqToShootPos = lengthsquared( self.origin - self.shootPos );

		if ( self.a.pose != "crouch" && self isStanceAllowed( "crouch" ) && distSqToShootPos < squared( 400 ) )
		{
			if ( distSqToShootPos < squared( 285 ) )
			{
				prone_transitionTo( "crouch" );
				self thread animscripts\combat::main();
				return;
			}
		}

		if ( considerThrowGrenade() )// TODO: make considerThrowGrenade work with shootPos rather than only self.enemy
			continue;

		if ( self proneReload( 0 ) )
			continue;

		if ( aimedAtShootEntOrPos() )
		{
			shootUntilShootBehaviorChange();
			self clearAnim( %add_fire, .2 );
			continue;
		}

		// idleThread() is running, so just waiting a bit will cause us to idle
		wait( 0.05 );
	}

	//prof_end("prone_combat");
}




proneReload( threshold )
{
	return Reload( threshold, self animArray( "reload" ) );
}


setup_cover_prone()
{
	self setDefaultAimLimits( self.node );

	anim_array = [];

	anim_array[ "straight_level" ] = %prone_aim_5;

	anim_array[ "fire" ] = %prone_fire_1;
	anim_array[ "semi2" ] = %prone_fire_burst;
	anim_array[ "semi3" ] = %prone_fire_burst;
	anim_array[ "semi4" ] = %prone_fire_burst;
	anim_array[ "semi5" ] = %prone_fire_burst;

	anim_array[ "single" ] = array( %prone_fire_1 );
	anim_array[ "continuous" ] = array( %nx_tp_stand_exposed_stream_01 );

	anim_array[ "burst2" ] = %prone_fire_burst;// ( will be limited to 2 shots )
	anim_array[ "burst3" ] = %prone_fire_burst;
	anim_array[ "burst4" ] = %prone_fire_burst;
	anim_array[ "burst5" ] = %prone_fire_burst;
	anim_array[ "burst6" ] = %prone_fire_burst;

	anim_array[ "reload" ] = %prone_reload;

	anim_array[ "look" ] = array( %prone_twitch_look, %prone_twitch_lookfast, %prone_twitch_lookup );

	anim_array[ "grenade_safe" ] = array( %prone_grenade_A, %prone_grenade_A );
	anim_array[ "grenade_exposed" ] = array( %prone_grenade_A, %prone_grenade_A );

	anim_array[ "exposed_idle" ] = array( %prone_idle );

	anim_array[ "hide_to_look" ] = %coverstand_look_moveup;
	anim_array[ "look_idle" ] = %coverstand_look_idle;
	anim_array[ "look_to_hide" ] = %coverstand_look_movedown;
	anim_array[ "look_to_hide_fast" ] = %coverstand_look_movedown_fast;

	anim_array[ "stand_2_prone" ] = %stand_2_prone_nodelta;
	anim_array[ "crouch_2_prone" ] = %crouch_2_prone;
	anim_array[ "prone_2_stand" ] = %prone_2_stand_nodelta;
	anim_array[ "prone_2_crouch" ] = %prone_2_crouch;
	anim_array[ "stand_2_prone_firing" ] = %stand_2_prone_firing;
	anim_array[ "crouch_2_prone_firing" ] = %crouch_2_prone_firing;
	anim_array[ "prone_2_stand_firing" ] = %prone_2_stand_firing;
	anim_array[ "prone_2_crouch_firing" ] = %prone_2_crouch_firing;

	self.a.array = anim_array;
}


tryThrowingGrenade( throwAt, safe )
{
	theanim = undefined;
	if ( isdefined( safe ) && safe )
		theanim = animArrayPickRandom( "grenade_safe" );
	else
		theanim = animArrayPickRandom( "grenade_exposed" );

	self animMode( "zonly_physics" );// Unlatch the feet
	self.keepClaimedNodeIfValid = true;

	armOffset = ( 32, 20, 64 );// needs fixing!
	threwGrenade = TryGrenade( throwAt, theanim );

	self.keepClaimedNodeIfValid = false;
	return threwGrenade;
}


considerThrowGrenade()
{
	if ( isdefined( anim.throwGrenadeAtPlayerASAP ) && isAlive( level._player ) )
	{
		if ( tryThrowingGrenade( level._player, 200 ) )
			return true;
	}

	if ( isdefined( self.enemy ) )
		return tryThrowingGrenade( self.enemy, 850 );

	return false;
}

shouldFireWhileChangingPose()
{
	if ( !isdefined( self.weapon ) || !WeaponIsAuto( self.weapon ) )
		return false;
	
	if ( isdefined( self.node ) && distanceSquared( self.origin, self.node.origin ) < 16 * 16 )
		return false;// we're on a node and can't use an animation with a delta
	if ( isDefined( self.enemy ) && self canSee( self.enemy ) && !isdefined( self.grenade ) && self getAimYawToShootEntOrPos() < 20 )
		return animscripts\move::MayShootWhileMoving();
	return false;
}

prone_transitionTo( newPose )
{
	if ( newPose == self.a.pose )
		return;

	self clearanim( %root, .3 );

	self endFireAndAnimIdleThread();

	if ( shouldFireWhileChangingPose() )
		transAnim = animArray( self.a.pose + "_2_" + newPose + "_firing" );
	else
		transAnim = animArray( self.a.pose + "_2_" + newPose );

	if ( newPose == "prone" )
	{
		// this is crucial. if it doesn't have this notetrack, we won't call enterProneWrapper!
		assert( animHasNotetrack( transAnim, "anim_pose = \"prone\"" ) );
	}

	self setFlaggedAnimKnobAllRestart( "trans", transAnim, %body, 1, .2, 1.0 );
	animscripts\shared::DoNoteTracks( "trans" );

	assert( self.a.pose == newPose );

	self setAnimKnobAllRestart( animarray( "straight_level" ), %body, 1, .25 );
	setupProneAim( .25 );
}

finishNoteTracks( animname )
{
	self endon( "killanimscript" );
	animscripts\shared::DoNoteTracks( animname );
}


setupProneAim( transTime )
{
	self setAnimKnobAll( %prone_aim_5, %body, 1, transTime );
	self setAnimLimited( %prone_aim_2_add, 1, transTime );
	self setAnimLimited( %prone_aim_4_add, 1, transTime );
	self setAnimLimited( %prone_aim_6_add, 1, transTime );
	self setAnimLimited( %prone_aim_8_add, 1, transTime );
}


proneTo( newPose, rate )
{
	assert( self.a.pose == "prone" );

//	self OrientMode( "face angle", self.angles[1] );
	self clearanim( %root, .3 );

	transAnim = undefined;

	if ( shouldFireWhileChangingPose() )
	{
		if ( newPose == "crouch" )
			transAnim = %prone_2_crouch_firing;
		else if ( newPose == "stand" )
			transAnim = %prone_2_stand_firing;
	}
	else
	{
		if ( newPose == "crouch" )
			transAnim = %prone_2_crouch;
		else if ( newPose == "stand" )
			transAnim = %prone_2_stand_nodelta;
	}
	
	if ( isdefined( self.prone_anim_override ) )
		transAnim = self.prone_anim_override;
	if ( isdefined( self.prone_rate_override ) )
		rate = self.prone_rate_override;

	assert( isDefined( transAnim ) );

	if ( !isdefined( rate ) )
		rate = 1;
	
	self ExitProneWrapper( getAnimLength( transAnim ) / 2 );
	self setFlaggedAnimKnobAllRestart( "trans", transAnim, %body, 1, .2, rate );
	animscripts\shared::DoNoteTracks( "trans" );

	self clearAnim( transAnim, 0.1 );

	assert( self.a.pose == newPose );
//	self.a.pose = newPose; // failsafe
}
