#include common_scripts\utility;
#include maps\_utility;
#include maps\_anim;
#include maps\_stealth_utility;
#include maps\_stealth_shared_utilities;

stealth_visibility_friendly_main()
{
	self friendly_init();
	self thread friendly_visibility_logic();
}

/************************************************************************************************************/
/*												FRIENDLY LOGIC												*/
/************************************************************************************************************/
friendly_visibility_logic()
{
	self endon( "death" );
	self endon( "pain_death" );

	current_stance_func = self._stealth.logic.current_stance_func;

	//for right now - we only do this for player...the system actually looks good doing it for player only,
	//but maybe in the future we'll want to change this...if we do theres a bunch of evaluation stuff 
	//based on stance in the _behavior script that will have to be changed.
	if ( isPlayer( self ) )
		self thread player_movespeed_calc_loop();

	while ( 1 )
	{
		self ent_flag_wait( "_stealth_enabled" );

		//find the current stance
		self [[ current_stance_func ]]();
		
		assert( ent_flag( "_stealth_enabled" ) );	// there should be no wait in the above current_stance_func

		//now compute maxVisibleDist based on current awareness level, stance, and movement speed
		self.maxVisibleDist = self friendly_compute_score();

		//maxVisibleDist is not under the _stealth struct because it's actually an AI value that
		//code reads - this decides how visible you are to enemies

		wait .05;
	}
}

friendly_getvelocity()
{
	return length( self getVelocity() );
}

player_getvelocity_pc()
{
	velocity = length( self getVelocity() );

	stance = self._stealth.logic.stance;

	add = [];
	add[ "stand" ] = 30;
	add[ "crouch" ] = 15;
	add[ "prone" ] = 4;

	sub = [];
	sub[ "stand" ] = 40;
	sub[ "crouch" ] = 25;
	sub[ "prone" ] = 10;

	if ( !velocity )
		self._stealth.logic.player_pc_velocity = 0;
	else if ( velocity > 	self._stealth.logic.player_pc_velocity )
	{
		self._stealth.logic.player_pc_velocity += add[ stance ];
		if ( self._stealth.logic.player_pc_velocity > velocity )
			self._stealth.logic.player_pc_velocity = velocity;
	}
	else if ( velocity < 	self._stealth.logic.player_pc_velocity )
	{
		self._stealth.logic.player_pc_velocity -= sub[ stance ];
		if ( self._stealth.logic.player_pc_velocity < 0 )
			self._stealth.logic.player_pc_velocity = 0;
	}

	//println( self._stealth.logic.player_pc_velocity );
	return self._stealth.logic.player_pc_velocity;
}

friendly_compute_score( stance )
{
	if ( !isdefined( stance ) )
		stance = self._stealth.logic.stance;
		
	if ( stance == "back" )
		stance = "prone";

	detection_level = level._stealth.logic.detection_level;

	score_range = level._stealth.logic.detect_range[ detection_level ][ stance ];

	if ( self ent_flag( "_stealth_in_shadow" ) )
	{
		score_range *= .5;
		if ( score_range < level._stealth.logic.detect_range[ "hidden" ][ "prone" ] )
			score_range = level._stealth.logic.detect_range[ "hidden" ][ "prone" ];
	}

	score_move = self._stealth.logic.movespeed_multiplier[ detection_level ][ stance ];
	if ( isdefined( self._stealth_move_detection_cap ) && score_move > self._stealth_move_detection_cap )
		score_move = self._stealth_move_detection_cap;

	return( score_range + score_move );
}

friendly_getstance_ai()
{
	return self.a.pose;
}

friendly_getangles_ai()
{
	return self.angles;
}

friendly_compute_stances_ai()
{
	self._stealth.logic.stance = self [[ self._stealth.logic.getstance_func ]]();
	self._stealth.logic.oldstance = self._stealth.logic.stance;
}

/************************************************************************************************************/
/*												PLAYER LOGIC												*/
/************************************************************************************************************/
player_movespeed_calc_loop()
{
	self endon( "death" );
	self endon( "pain_death" );

	angles_func = self._stealth.logic.getangles_func;
	velocity_func = self._stealth.logic.getvelocity_func;
	oldangles = self [[ angles_func ]]();

	while ( 1 )
	{
		self ent_flag_wait( "_stealth_enabled" );

		score = undefined;

		//if he's in shadow - movement has no effect
		if ( self ent_flag( "_stealth_in_shadow" ) )
		{
			score = 0;
		}
		else
		{
			score = self [[ velocity_func ]]();
		}

		//self._stealth.logic.movespeed_multiplier[ "hidden" ][ "stand" ]	
		foreach ( statename, state in self._stealth.logic.movespeed_multiplier )
		{
			foreach ( stancename, stance in state )
			{
				stance = score * self._stealth.logic.movespeed_scale[ statename ][ stancename ];
			}
		}

		oldangles = self [[ angles_func ]]();
		wait .1;
	}
}

friendly_getstance_player()
{
	return self getstance();
}

friendly_getangles_player()
{
	return self getplayerangles();
}

friendly_compute_stances_player()
{
	stance = self [[ self._stealth.logic.getstance_func ]]();

	//first - are we going through a stance change?  if so - then forget this part entirely...because
	//this is the logic that tells us whether to go through a stance change or not, and if we calculate
	//it when we're already going through one...then the timer gets reset every frmae and we'll never ever
	//come out of this state
	if ( !self._stealth.logic.stance_change )
	{
		//is our current stance the same as our old stance? if not, then figure out if we were moving up
		//of moving down...if moving down
		switch( stance )
		{
			case "prone":
				if ( self._stealth.logic.oldstance != "prone" )
					self._stealth.logic.stance_change = self._stealth.logic.stance_change_time;
				break;
			case "crouch":
				if ( self._stealth.logic.oldstance == "stand" )
					self._stealth.logic.stance_change = self._stealth.logic.stance_change_time;
				break;
		}
	}
	//ok so this means we're moving down...if so then make our current stance actually our 
	//old stance over .2 seconds until we actually get to the lower stance in the game
	//we do this because the player is still moving at a high speed when he goes
	//into a lower stance - which messes with the movespeed multiplier calculation
	//so we want to delay it a moment to give the player a chance to slow down
	if ( self._stealth.logic.stance_change )
	{
		self._stealth.logic.stance = self._stealth.logic.oldstance;
		// fuckin retarded floating point miscaclculation that i need to detect for...this will
		// never hit 0 - it will hit an incredibly small number, then go negative...ghey
		if ( self._stealth.logic.stance_change > .05 )
			self._stealth.logic.stance_change -= .05;
		else
		{
			self._stealth.logic.stance_change = 0;
			self._stealth.logic.stance = stance;
			self._stealth.logic.oldstance = stance;
		}
	}
	//otherwise lets set our stance to the current stance...and make our old stance also the current stance
	//we can set the old stance at the same time, because we already decided above that either our old stance
	//was the same stance, or that we just finished go through a stance change, and either way - it's safe to set 
	//the old stance
	else
	{
		self._stealth.logic.stance = stance;
		self._stealth.logic.oldstance = stance;
	}
}

/************************************************************************************************************/
/*													SETUP													*/
/************************************************************************************************************/
friendly_init()
{
	self ent_flag_init( "_stealth_in_shadow" );
	self ent_flag_init( "_stealth_enabled" );
	self ent_flag_set( "_stealth_enabled" );

	assertex( !isdefined( self._stealth ), "you called maps\_stealth_logic::friendly_init() twice on the same ai or player" );

	self._stealth = spawnstruct();
	self._stealth.logic = spawnstruct();

	if ( isPlayer( self ) )
	{
		self._stealth.logic.getstance_func 		 = ::friendly_getstance_player;
		self._stealth.logic.getangles_func 		 = ::friendly_getangles_player;
		if ( level._Console )
			self._stealth.logic.getvelocity_func	 = ::friendly_getvelocity;
		else
		{
			self._stealth.logic.getvelocity_func	 = ::player_getvelocity_pc;
			self._stealth.logic.player_pc_velocity 	 = 0;
		}
		self._stealth.logic.current_stance_func = ::friendly_compute_stances_player;
	}
	else
	{
		self._stealth.logic.getstance_func 		 = ::friendly_getstance_ai;
		self._stealth.logic.getangles_func 		 = ::friendly_getangles_ai;
		self._stealth.logic.getvelocity_func	 = ::friendly_getvelocity;
		self._stealth.logic.current_stance_func = ::friendly_compute_stances_ai;
	}

	self._stealth.logic.stance_change_time 	 = .2;
	self._stealth.logic.stance_change	 	 = 0;
	self._stealth.logic.oldstance 			 = self [[ self._stealth.logic.getstance_func ]]();
	self._stealth.logic.stance 				 = self [[ self._stealth.logic.getstance_func ]]();

	self._stealth.logic.spotted_list 	 = [];

	self._stealth.logic.movespeed_multiplier = [];
	self._stealth.logic.movespeed_scale = [];

	self._stealth.logic.movespeed_multiplier[ "hidden" ] = [];
	self._stealth.logic.movespeed_multiplier[ "hidden" ][ "prone" ] 	 = 0;
	self._stealth.logic.movespeed_multiplier[ "hidden" ][ "crouch" ] 	 = 0;
	self._stealth.logic.movespeed_multiplier[ "hidden" ][ "stand" ] 	 = 0;

	self._stealth.logic.movespeed_multiplier[ "spotted" ] = [];
	self._stealth.logic.movespeed_multiplier[ "spotted" ][ "prone" ] 	 = 0;
	self._stealth.logic.movespeed_multiplier[ "spotted" ][ "crouch" ] 	 = 0;
	self._stealth.logic.movespeed_multiplier[ "spotted" ][ "stand" ] 	 = 0;

	friendly_default_movespeed_scale();
}

/************************************************************************************************************/
/*												UTILITIES													*/
/************************************************************************************************************/

friendly_default_movespeed_scale()
{
	hidden = [];
	hidden[ "prone" ]	 = 3;
	hidden[ "crouch" ]	 = 2;
	hidden[ "stand" ]	 = 2;

	spotted = [];
	spotted[ "prone" ]	 = 2;
	spotted[ "crouch" ]	 = 2;
	spotted[ "stand" ]	 = 2;

	self friendly_set_movespeed_scale( hidden, spotted );
}

friendly_set_movespeed_scale( hidden, spotted )
{
	if ( isdefined( hidden ) )
	{
		self._stealth.logic.movespeed_scale[ "hidden" ][ "prone" ] 		 = hidden[ "prone" ];
		self._stealth.logic.movespeed_scale[ "hidden" ][ "crouch" ] 	 = hidden[ "crouch" ];
		self._stealth.logic.movespeed_scale[ "hidden" ][ "stand" ] 		 = hidden[ "stand" ];
	}
	if ( isdefined( spotted ) )
	{
		self._stealth.logic.movespeed_scale[ "spotted" ][ "prone" ] 	 = spotted[ "prone" ];
		self._stealth.logic.movespeed_scale[ "spotted" ][ "crouch" ] 	 = spotted[ "crouch" ];
		self._stealth.logic.movespeed_scale[ "spotted" ][ "stand" ] 	 = spotted[ "stand" ];
	}
}