#include maps\_vehicle;
#include maps\_utility;
#include maps\_helicopter_globals;
#include common_scripts\utility;

evasive_think( vehicle )
{
	vehicle endon( "death" );
	while ( vehicle.health > 0 )
	{
		vehicle waittill( "missile_lock", enemyVehicle );

		points = evasive_createManeuvers( vehicle, "random" );
		evasive_startManeuvers( vehicle, points );

		wait 0.05;
	}
}

evasive_createManeuvers( vehicle, maneuverName )
{
	assert( isdefined( maneuverName ) );

	/* evasive_addPoint params:
	forward			- units forward/back
	side			- units left/right
	up				- units up/down
	goalYawMethod	- can be "average", "forward", or "none"
						none (default): always points towards the next point
						average: finds an angle between the forward direction and the goal direction
						forward: chopper will always face the direction it was originally moving
	*/

	switch( maneuverName )
	{
		case"strafe_left_right":
			// swerve & strafe ( right then left )
			vehicle evasive_addPoint( 3000, -1500, 500, "average" );
			vehicle evasive_addPoint( 6000, 3000, -700, "average" );
			vehicle evasive_addPoint( 3000, -1500, 200, "average" );
			break;

		case "strafe_right_left":
			// swerve & strafe ( right then left )
			vehicle evasive_addPoint( 3000, 1500, 500, "average" );
			vehicle evasive_addPoint( 6000, -3000, -700, "average" );
			vehicle evasive_addPoint( 3000, 1500, 200, "average" );
			break;

		case "360_clockwise":
			// 360 circle back around ( clockwise )
			vehicle evasive_addPoint( 1500, 1500, 200, "none" );
			vehicle evasive_addPoint( 0, 1500, 200, "none" );
			vehicle evasive_addPoint( -1500, 1500, 200, "none" );
			vehicle evasive_addPoint( -1500, 0, 0, "none" );
			vehicle evasive_addPoint( -1000, -1000, -200, "none" );
			vehicle evasive_addPoint( 0, -1000, -200, "none" );
			vehicle evasive_addPoint( 1000, -1000, -200, "none" );
			break;

		case "360_counter_clockwise":
			vehicle evasive_addPoint( 1500, -1500, 200, "none" );
			vehicle evasive_addPoint( 0, -1500, 200, "none" );
			vehicle evasive_addPoint( -1500, -1500, 200, "none" );
			vehicle evasive_addPoint( -1500, 0, 0, "none" );
			vehicle evasive_addPoint( -1000, 1000, -200, "none" );
			vehicle evasive_addPoint( 0, 1000, -200, "none" );
			vehicle evasive_addPoint( 1000, 1000, -200, "none" );
			break;

		case "random":
			maneuverNameList = [];
			maneuverNameList[ 0 ] = "strafe_left_right";
			maneuverNameList[ 1 ] = "strafe_right_left";
			maneuverNameList[ 2 ] = "360_clockwise";
			maneuverNameList[ 3 ] = "360_counter_clockwise";
			return evasive_createManeuvers( vehicle, maneuverNameList[ randomint( maneuverNameList.size ) ] );
	}

	points = evasive_getAllPoints( vehicle );
	return points;
}

evasive_startManeuvers( vehicle, points )
{
	vehicle notify( "taking_evasive_actions" );
	vehicle endon( "taking_evasive_actions" );
	vehicle endon( "death" );

	vehicle notify( "evasive_action_done" );

	thread evasive_endManeuvers( vehicle );

	if ( getdvar( "cobrapilot_debug" ) == "1" )
		vehicle evasive_drawPoints( points );

	vehicle setNearGoalNotifyDist( 1500 );
	vehicle Vehicle_SetSpeed( 100, 30, 30 );

	forwardYaw = vehicle.angles[ 1 ];

	for ( i = 1 ; i < points.size ; i++ )
	{
		//prof_begin( "cobrapilot_ai" );

		if ( isdefined( points[ i + 1 ] ) )
			evadeDirectionYaw = vectorToAngles( points[ i + 1 ][ "pos" ] - points[ i ][ "pos" ] );
		else
			evadeDirectionYaw = ( 0, forwardYaw, 0 );

		// determine goal yaw angle
		goalYawAngle = evadeDirectionYaw[ 1 ];
		if ( points[ i ][ "goalYawMethod" ] == "average" )
			goalYawAngle = ( ( evadeDirectionYaw[ 1 ] + forwardYaw ) / 2 );
		else if ( points[ i ][ "goalYawMethod" ] == "forward" )
			goalYawAngle = vehicle.angles[ 1 ];

		//prof_end( "cobrapilot_ai" );

		//draw line to represent target yaw
		if ( getdvar( "cobrapilot_debug" ) == "1" )
			thread draw_line_until_notify( points[ i ][ "pos" ], points[ i ][ "pos" ] + ( vector_multiply( anglesToForward( ( 0, goalYawAngle, 0 ) ), 250 ) ), 1.0, 1.0, 0.2, vehicle, "evasive_action_done" );

		vehicle setTargetYaw( goalYawAngle );

		vehicle thread setvehgoalpos_wrap( points[ i ][ "pos" ], false );
		vehicle waittill( "near_goal" );
	}

	vehicle notify( "evasive_action_done" );

	vehicle thread vehicle_resumepath();
}

evasive_endManeuvers( vehicle )
{
	vehicle notify( "end_maneuvers" );
	vehicle endon( "end_maneuvers" );
	vehicle endon( "evasive_action_done" );
	vehicle endon( "death" );

	vehicle waittill( "missile_lock_ended" );
	vehicle thread vehicle_resumepath();
}

evasive_addPoint( forward, side, up, goalYawMethod )
{
	if ( !isdefined( self.evasive_points ) )
	{
		self.evasive_points = [];
		self.evasive_points[ 0 ][ "pos" ] = self.origin;
		self.evasive_points[ 0 ][ "ang" ] = ( 0, self.angles[ 1 ], 0 );
	}

	index = self.evasive_points.size;

	if ( !isdefined( goalYawMethod ) )
		goalYawMethod = "none";

	if ( !isdefined( up ) )
		up = 0;

	self.evasive_points[ index ][ "forward" ] = forward;
	self.evasive_points[ index ][ "side" ] = side;
	self.evasive_points[ index ][ "up" ] = up;

	//prof_begin( "cobrapilot_ai" );

	vec_forward = anglesToForward( self.evasive_points[ 0 ][ "ang" ] );
	vec_right = anglesToRight( self.evasive_points[ 0 ][ "ang" ] );

	self.evasive_points[ index ][ "pos" ] = self.evasive_points[ index - 1 ][ "pos" ] + ( vector_multiply( vec_forward, self.evasive_points[ index ][ "forward" ] ) ) + ( vector_multiply( vec_right, self.evasive_points[ index ][ "side" ] ) ) + ( 0, 0, up );
	self.evasive_points[ index ][ "goalYawMethod" ] = goalYawMethod;

	//prof_end( "cobrapilot_ai" );
}

evasive_getAllPoints( vehicle )
{
	points = vehicle.evasive_points;
	vehicle.evasive_points = undefined;
	return points;
}

evasive_drawPoints( points )
{
	for ( i = 1 ; i < points.size ; i++ )
		thread draw_line_until_notify( points[ i - 1 ][ "pos" ], points[ i ][ "pos" ], 1.0, 0.2, 0.2, self, "evasive_action_done" );
}

wingman_think( vehicle )
{
	vehicle endon( "death" );
	level.playervehicle endon( "death" );

	dist_forward = 2200;
	dist_side 	 = 1500;
	dist_up 	 = 0;

	goalPosUpdateTime = 1.0;

	wingmanSpeedScale = 1.2;
	wingmanBaseAcceleration = 50;
	wingmanBaseDeceleration = 60;

	vehHelicopter_GetSpeedTime = 2000;
	vehHelicopter_CurrentSpeed = getPlayerHeliSpeed();
	vehHelicopter_OldSpeed = 0.0;
	vehHelicopter_OldSpeedTime = getTime();

	// put the wingman at it's goal at the start of the level
	goalPos = wingman_getGoalPos( dist_forward, dist_side, dist_up );
	vehicle Vehicle_SetSpeed( 30, 20, 20 );
	vehicle setTargetYaw( level.playervehicle.angles[ 1 ] );
	vehicle setVehGoalPos( goalPos, true );

	for ( ;; )
	{
		//prof_begin( "cobrapilot_ai" );

		/*******************************************************/
		/*** get the point where the wingman should hang out ***/
		/*******************************************************/

		goalPos = wingman_getGoalPos( dist_forward, dist_side, dist_up );

		if ( getdvar( "cobrapilot_debug" ) == "1" )
		{
			thread draw_line_for_time( level.playervehicle.origin, goalPos, 0, 1, 0, goalPosUpdateTime );
			thread draw_line_for_time( level.playervehicle.origin, vehicle.origin, 0, 0, 1, goalPosUpdateTime );
			thread draw_line_for_time( vehicle.origin, goalPos, 1, 1, 0, goalPosUpdateTime );
		}

		/************************************************************************************************/
		/*** save records of what the players speed was 3 seconds ago to that the wingman can keep up ***/
		/************************************************************************************************/
		time = getTime();
		if ( time >= vehHelicopter_OldSpeedTime + vehHelicopter_GetSpeedTime )
		{
			vehHelicopter_OldSpeedTime = time;
			vehHelicopter_OldSpeed = vehHelicopter_CurrentSpeed;
			vehHelicopter_CurrentSpeed = getPlayerHeliSpeed();
		}

		/***********************************************************************************************/
		/*** set wingmans goal position and target yaw here based on the players speed from the past ***/
		/***********************************************************************************************/
		bGoToGoal = false;
		wingmanSpeed = 0;

		if ( vehHelicopter_OldSpeed > 20 )
		{
			wingmanSpeed = vehHelicopter_OldSpeed;
			bGoToGoal = true;
		}
		else if ( ( vehHelicopter_OldSpeed <= 20 ) && ( getPlayerHeliSpeed() > 20 ) )
		{
			wingmanSpeed = getPlayerHeliSpeed();
			bGoToGoal = true;
		}

		if ( bGoToGoal && ( wingmanSpeed > 0 ) )
		{
			wingmanSpeed *= wingmanSpeedScale;
			accel = wingmanBaseAcceleration;
			decel = wingmanBaseDeceleration;
			if ( accel >= wingmanSpeed / 2 )
				accel = ( wingmanSpeed / 2 );
			if ( decel >= wingmanSpeed / 2 )
				decel = ( wingmanSpeed / 2 );

			vehicle Vehicle_SetSpeed( wingmanSpeed, accel, decel );

			vehicle setTargetYaw( level.playervehicle.angles[ 1 ] );

			bStop = false;
			if ( getPlayerHeliSpeed() <= 30 )
				bStop = true;

			if ( getdvar( "cobrapilot_debug" ) == "1" )
				iprintln( "wingman speed: " + wingmanSpeed + " : " + bStop );

			vehicle setVehGoalPos( goalPos, bStop );
		}

		/***********************************************************************************************/
		/***********************************************************************************************/
		/***********************************************************************************************/

		//prof_end( "cobrapilot_ai" );

		wait goalPosUpdateTime;
	}
}

wingman_getGoalPos( dist_forward, dist_side, dist_up )
{
	vec_forward = anglesToForward( flat_angle( level.playervehicle.angles ) );
	vec_right = anglesToRight( flat_angle( level.playervehicle.angles ) );
	goalPos = level.playervehicle.origin + ( vector_multiply( vec_forward, dist_forward ) ) + ( vector_multiply( vec_right, dist_side ) ) + ( 0, 0, dist_up );
	return goalPos;
}

getPlayerHeliSpeed()
{
	return level.playervehicle vehicle_getspeed();
}