#using scripts\codescripts\struct;

#using scripts\shared\array_shared;
#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\killstreaks_shared;
#using scripts\shared\math_shared;
#using scripts\shared\statemachine_shared;
#using scripts\shared\system_shared;
#using scripts\shared\turret_shared;
#using scripts\shared\util_shared;
#using scripts\shared\vehicle_ai_shared;
#using scripts\shared\vehicle_death_shared;
#using scripts\shared\vehicle_shared;

#using scripts\mp\_util;
#using scripts\mp\gametypes\_shellshock;
#using scripts\mp\killstreaks\_killstreakrules;
#using scripts\mp\killstreaks\_airsupport;
#using scripts\mp\killstreaks\_killstreaks;
#using scripts\mp\killstreaks\_remote_weapons;
#using scripts\mp\teams\_teams;
#using scripts\shared\weapons\_heatseekingmissile;

  
                                                                                                   	  	                                                                    	                     	                 	                                                                         	                       	                                                      	                                                      	                                                       	                                                                                                  	                                                                                                                 	                                                   	                	                                          	                                      	       	  	             	                                                     	                                                                             	                         	                                                                	                                                             	                                                             	                                                                                      	                                                         	                                                         	                                                               	                                                               	                                                   	                                                                	                                                     	                                                	                                                	                                                        	                                                                                                  	                                                                             	                                            	                                                                                    	                                          	                     	                                              	                                        	                 	   
                                             
    	   	                                                                                                                                         	                                	                                                                                                                                                                                                                                                                                                                                                                    	        	     	              	    	   	               	                                              	                                                           	                               	                     	                                                                                                           	                                                                 	                                                              	                                                                                                                                             	                            	                                     	                                       	                                                                                                              	   	                  	       	                                                    	                   	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            	                                                                                                 	                                    	                                                                                        	           	                        	                                            	                                             	                                                   	                                                             	                                                         	                                                                    	                                                                                                                                                                                                                                	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  	    	         	                                                              	                                                          	                                   	                                   	                                                    	                                       	                                           	     	                                                                                                                                                                                                                                                      	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	                                                               	        	                                                                                                                              	                                                                                                                     	                               	                                                      	                          
       
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         	   	                                                                                                                                                                                                                                  	                                                                                                                                                                                                                                                                                                                                                                                                                                                   
                                                                                                            	  	  	              	   	                                                                                                                                       	                                                                                                                                                            	                                                                                                                                                                

#precache( "fx", "explosions/fx_vexp_wasp_gibb_death" );

#namespace flak_drone;
	



function init()
{
	clientfield::register( "vehicle", "flak_drone_camo", 1, 3, "int" );
	
	vehicle::add_main_callback( "veh_flak_drone_mp", &InitFlakDrone );
}

function InitFlakDrone()
{
	self.health = self.healthdefault;
	self vehicle::friendly_fire_shield();
	self EnableAimAssist();
	self SetNearGoalNotifyDist( ( 40 ) );
	self SetHoverParams( ( 50.0 ), ( 75.0 ), ( 100.0 ) );
	self SetVehicleAvoidance( true );
	self.fovcosine = 0; // +/-90 degrees = 180
	self.fovcosinebusy = 0;	//+/- 55 degrees = 110 fov
	self.vehAirCraftCollisionEnabled = true;
	self.goalRadius = 999999;
	self.goalHeight = 999999;
	self SetGoal( self.origin, false, self.goalRadius, self.goalHeight );
	self thread vehicle_ai::nudge_collision();
	
	self.overrideVehicleDamage = &FlakDroneDamageOverride;
	
	self vehicle_ai::init_state_machine_for_role( "default" );
    self vehicle_ai::get_state_callbacks( "combat" ).enter_func = &state_combat_enter;
    self vehicle_ai::get_state_callbacks( "combat" ).update_func = &state_combat_update;
   	self vehicle_ai::get_state_callbacks( "off" ).enter_func = &state_off_enter;
   	self vehicle_ai::get_state_callbacks( "off" ).update_func = &state_off_update;
    self vehicle_ai::get_state_callbacks( "death" ).update_func = &state_death_update;
    
	self vehicle_ai::StartInitialState( "off" );
}
	
function state_off_enter( params )
{
}

function state_off_update( params )
{
	self endon( "change_state" );
	self endon( "death" );

	while( !isdefined( self.parent ) )
	{
		wait( 0.1 ); //Wait for parent to be setup
	}
	
	self.parent endon( "death" );
	
	while( true )
	{
		self SetSpeed( ( 400 ) );
		
		if( ( isdefined( self.inpain ) && self.inpain ) )
		{
			wait( ( 0.1 ) );
		}
		
		self ClearLookAtEnt();
		
		self.current_pathto_pos = undefined;
		
		queryOrigin = self.parent.origin + ( 0, 0, ( -75 ) );
		queryResult = PositionQuery_Source_Navigation( queryOrigin, 
		                                               ( 25 ), 
		                                               ( 75 ), 
		                                               ( 40 ), 
		                                               ( 40 ), 
		                                               self );
		
		if( isdefined( queryResult ) )
		{
			PositionQuery_Filter_DistanceToGoal( queryResult, self );
			vehicle_ai::PositionQuery_Filter_OutOfGoalAnchor( queryResult );
		
			best_point = undefined;
			best_score = -999999;
		
			foreach ( point in queryResult.data )
			{
				randomScore = randomFloatRange( 0, 100 );
				distToOriginScore = point.distToOrigin2D * 0.2;
				
				point.score += randomScore + distToOriginScore;
				/#    if ( !isdefined( point._scoreDebug ) )    {     point._scoreDebug = [];    }    point._scoreDebug[ "distToOrigin" ] = distToOriginScore;    #/    point.score += distToOriginScore;;
				
				if ( point.score > best_score )
				{
					best_score = point.score;
					best_point = point;
				}
			}
		
			self vehicle_ai::PositionQuery_DebugScores( queryResult );
		
			if( isdefined( best_point ) )
			{
				self.current_pathto_pos = best_point.origin;	
			}
		}
		
		if( IsDefined( self.current_pathto_pos ) )
		{
			self UpdateFlakDroneSpeed();
			if( self SetVehGoalPos( self.current_pathto_pos, true, false ) )
			{
				self playsound ("veh_wasp_vox");
			}
			else
			{
				self SetSpeed( ( 400 ) * 3 );
				self.current_pathto_pos = self GetClosestPointOnNavVolume( self.origin, 999999 );
				self SetVehGoalPos( self.current_pathto_pos, true, false );
			}
		}
		else
		{
			if( isDefined( self.parent.heliGoalPos ) )
			{
				self.current_pathto_pos = self.parent.heliGoalPos;
			}
			else
			{
				self.current_pathto_pos = queryOrigin;
			}
			self UpdateFlakDroneSpeed();
			self SetVehGoalPos( self.current_pathto_pos, true, false );
		}
			
		wait RandomFloatRange( ( .1 ), ( .2 ) );
	}
}

function UpdateFlakDroneSpeed() // self == flak drone
{
	desiredSpeed = ( 400 );

	if ( isdefined( self.parent ) )
	{
		parentSpeed = self.parent GetSpeed();
		desiredSpeed = parentSpeed * 0.9; // lag a little back
		if ( Distance2DSquared( self.parent.origin, self.origin ) > ( (36) * (36) ) ) // match parent speed if too far from parent
		{
			if ( isdefined( self.current_pathto_pos ) )
			{
				flakDroneDistanceToGoalSquared = Distance2DSquared( self.origin, self.current_pathto_pos );
				parentDistanceToGoalSquared = Distance2DSquared( self.parent.origin, self.current_pathto_pos );
				if ( flakDroneDistanceToGoalSquared > parentDistanceToGoalSquared )
				{
					desiredSpeed = parentSpeed * 1.3;
				}
				else
				{
					desiredSpeed = parentSpeed * 0.8;					
				}
			}
		}
	}

	self SetSpeed( max( desiredSpeed, 10 ) );
}

function state_combat_enter( params )
{
}

function state_combat_update( params )
{
	drone = self;
	drone endon( "change_state" );
	drone endon( "death" );
	
	drone thread SpawnFlakRocket( drone.incoming_missile, drone.origin, drone.parent );
	drone Ghost();
}

function SpawnFlakRocket( missile, spawnPos, parent )
{
	drone = self;
	
	missile endon("death");
	missile Missile_SetTarget( parent );
	
	rocket = MagicBullet( GetWeapon( "flak_drone_rocket" ), spawnPos, missile.origin, parent, missile );
	rocket.team = parent.team;
	rocket setTeam( parent.team );
	rocket clientfield::set( "enemyvehicle", 1 );
	rocket Missile_SetTarget( missile );
	missile thread CleanupAfterMissileDeath( rocket, drone ); // sometimes missile gets destroyed by the rocket
	
	curDist = Distance( missile.origin, rocket.origin ); // note: algorithm requires distance (not distance squared)

	tooCloseToPredictedParent = false;

/#
	debug_draw = GetDvarInt( "scr_flak_drone_debug_trails", 0 );
	debug_duration = GetDvarInt( "scr_flak_drone_debug_trails_duration", 20 * 20 ); // duration in number of server frames
#/

	while( true )
	{
		{wait(.05);};
		
		prevDist = curDist;
		
		if ( isdefined( rocket ) )
		{
			curDist = Distance( missile.origin, rocket.origin ); // can't use DistanceSquared() here
			
			distDelta = prevDist - curDist;
			
			predictedDist = curDist - distDelta;
		}
		
/#
		if ( debug_draw && isdefined( missile ) )
			util::debug_sphere( missile.origin, 6, ( 0.9, 0, 0 ), 0.9, debug_duration ); // small red sphere for missile trail
		
		if ( debug_draw && isdefined( rocket ) )
			util::debug_sphere( rocket.origin, 6, ( 0, 0, 0.9 ), 0.9, debug_duration ); // small blue spheres for flak drone trail (as rocket)
#/

		if ( isdefined( parent ) )
		{
			parentVelocity = parent GetVelocity();
			parentPredictedLocation = parent.origin + ( parentVelocity * 0.05 );
			missileVelocity = missile GetVelocity();
			missilePredictedLocation = missile.origin + ( missileVelocity * 0.05 );
			if ( DistanceSquared( parentPredictedLocation, missilePredictedLocation ) < ( (1000) * (1000) )
			    || DistanceSquared( parent.origin, missilePredictedLocation ) < ( (1000) * (1000) ) )
			{
				tooCloseToPredictedParent = true;
			}
		}

		if( ( predictedDist < 0 ) || ( curDist > prevDist ) || tooCloseToPredictedParent || !isdefined( rocket ) )
		{
/#
			if ( debug_draw && isdefined( parent ) )
			{
				if ( tooCloseToPredictedParent && ! ( ( predictedDist < 0 ) || ( curDist > prevDist ) ) )
				{
					util::debug_sphere( parent.origin, 18, ( 0.9, 0, 0.9 ), 0.9, debug_duration ); // large purple sphere means too close to parent
				}
				else
				{
					util::debug_sphere( parent.origin, 18, ( 0, 0.9, 0 ), 0.9, debug_duration ); // large green sphere means intercepted
				}
			}
#/
			
			if ( isdefined( rocket ) )
			{
				rocket detonate();
			}
			missile thread heatseekingmissile::_missileDetonate( missile.target_attacker, missile.target_weapon, missile.target_weapon.explosionradius, 10, 20 );			
			return;
		}	
	}	
}

function CleanupAfterMissileDeath( rocket, flak_drone )
{
	missile = self;
	missile waittill( "death" );
	
	wait 0.5; // make sure explosions fire off before deleting
	
	if ( isdefined( rocket ) )
	{
		rocket delete();
	}
	
	if ( isdefined( flak_drone ) )
	{
		flak_drone delete();
	}
}

function state_death_update( params )
{
	self endon( "death" );
	doGibbedDeath = false;
	
	if( isdefined( self.death_info ) )
	{
		if( isdefined( self.death_info.weapon ) )
		{
			if( self.death_info.weapon.dogibbing || self.death_info.weapon.doannihilate )
			{
				doGibbedDeath = true;
			}
		}
		if( isdefined( self.death_info.meansOfDeath ) )
		{
			meansOfDeath = self.death_info.meansOfDeath;
			if( meansOfDeath == "MOD_EXPLOSIVE" || meansOfDeath == "MOD_GRENADE_SPLASH" || meansOfDeath == "MOD_PROJECTILE_SPLASH" || meansOfDeath == "MOD_PROJECTILE" )
			{
				doGibbedDeath = true;
			}
		}
	}
	
	if( doGibbedDeath )
	{
		self playsound ("veh_wasp_gibbed");
		PlayFxOnTag( "explosions/fx_vexp_wasp_gibb_death", self, "tag_origin" );
		self Ghost();
		self NotSolid();
		
		wait( 5 );
		if( isdefined( self ) )
		{
			self Delete();
		}
	}
	else
	{
		self vehicle_death::flipping_shooting_death();
	}
}

function drone_pain_for_time( time, stablizeParam, restoreLookPoint )
{
	self endon( "death" );
	
	self.painStartTime = GetTime();

	if ( !( isdefined( self.inpain ) && self.inpain ) )
	{
		self.inpain = true;

		while ( GetTime() < self.painStartTime + time * 1000 )
		{
			self SetVehVelocity( self.velocity * stablizeParam );
			self SetAngularVelocity( self GetAngularVelocity() * stablizeParam );
			wait 0.1;
		}

		if ( isdefined( restoreLookPoint ) )
		{
			restoreLookEnt = Spawn( "script_model", restoreLookPoint );
			restoreLookEnt SetModel( "tag_origin" );

			self ClearLookAtEnt();
			self SetLookAtEnt( restoreLookEnt );
			self setTurretTargetEnt( restoreLookEnt );
			wait 1.5;

			self ClearLookAtEnt();
			self ClearTurretTarget();
			restoreLookEnt delete();
		}

		self.inpain = false;
	}
}

function drone_pain( eAttacker, damageType, hitPoint, hitDirection, hitLocationInfo, partName )
{
	if ( !( isdefined( self.inpain ) && self.inpain ) )
	{
		yaw_vel = math::randomSign() * RandomFloatRange( 280, 320 );

		ang_vel = self GetAngularVelocity();
		ang_vel += ( RandomFloatRange( -120, -100 ), yaw_vel, RandomFloatRange( -200, 200 ) );
		self SetAngularVelocity( ang_vel );

		self thread drone_pain_for_time( 0.8, 0.7 );
	}
}

function FlakDroneDamageOverride( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, weapon, vPoint, vDir, sHitLoc, vDamageOrigin, psOffsetTime, damageFromUnderneath, modelIndex, partName, vSurfaceNormal )
{
	if( sMeansOfDeath == "MOD_TRIGGER_HURT" )
		return 0;
	
	if( isdefined( eAttacker ) && isdefined( eAttacker.team ) && eAttacker.team != self.team )
	{
		drone_pain( eAttacker, sMeansOfDeath, vPoint, vDir, sHitLoc, partName );
	}

	return iDamage;
}

function Spawn( parent, onDeathCallback )
{
	if( !IsNavVolumeLoaded() )
	{
		/# IPrintLnBold( "Error: NavVolume Not Loaded" ); #/
		return undefined;
	}
	
	spawnPoint = parent.origin + ( 0, 0, -50 );
	
	drone = SpawnVehicle( "veh_flak_drone_mp", spawnPoint, parent.angles, "dynamic_spawn_ai" );
	drone.death_callback = onDeathCallback;
	drone configureTeam( parent, false );
	drone thread WatchGameEvents();
	drone thread WatchDeath();
	drone thread WatchParentDeath();
	drone thread WatchParentMissiles();
	return drone;
}

function configureTeam( parent, isHacked )
{
	drone = self;
	drone.team = parent.team;
	drone SetTeam( parent.team );
	if ( isHacked ) 
	{
		drone clientfield::set( "enemyvehicle", 2 );
	}
	else
	{
		drone clientfield::set( "enemyvehicle", 1 );
	}
	drone.parent = parent;
	
}

function WatchGameEvents()
{
	drone = self;
	drone endon( "death" );
	
	drone.parent.owner util::waittill_any( "game_ended", "emp_jammed", "disconnect", "joined_team" );
	drone Shutdown( true );
}

function WatchDeath()
{
	drone = self;
	drone.parent endon( "death" );
	
	drone waittill( "death" );
	drone Shutdown( true );
}

function WatchParentDeath()
{
	drone = self;
	drone endon( "death" );
	
	drone.parent waittill( "death" );
	drone Shutdown( true );
}

function WatchParentMissiles()
{
	drone = self;
	drone endon( "death" );
	drone.parent endon( "death" );
	
	drone.parent waittill( "stinger_fired_at_me", missile, weapon, attacker );

	drone.incoming_missile = missile;
	drone.incoming_missile.target_weapon = weapon;
	drone.incoming_missile.target_attacker = attacker;
	drone vehicle_ai::set_state( "combat" );
}

function SetCamoState( state )
{
	self clientfield::set( "flak_drone_camo", state );
}

function Shutdown( explode )
{
	drone = self;
	
	if( isdefined( drone.death_callback ) )
	{
		drone.parent thread [[ drone.death_callback ]]();
	}
	
	if( isdefined( drone ) && !isdefined( drone.parent ) )
	{
		drone Ghost();
		drone NotSolid();
		wait( 5 );
		if( isdefined( drone ) )
			drone Delete();
	}
		
	if( isdefined( drone ) )
	{
		if( explode )
		{
			drone DoDamage( drone.health + 1000, drone.origin, drone, drone, "none", "MOD_EXPLOSIVE" );	
		}
		else
		{
			drone Delete();
		}
	}
}
