#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include common_scripts\utility;
#include maps\mp\killstreaks\_assaultdrone_ai;
#include maps\mp\killstreaks\_drone_common;

PAINT_DRAW_TIME = .5;
	
DAMAGE_FADE_TIME = 1.0;

CONST_Rocket_AmmoMax = 3;
CONST_Rocket_Shot_Interval = 1;
CONST_Rocket_Reload_Interval = 5;

CONST_C4_EXPLODE_DIST = 200;

/#
SCR_CONST_DEBUG_ENABLE_AI			= false;
SCR_CONST_DEBUG_ENABLE_MG			= false;
SCR_CONST_DEBUG_ENABLE_ROCKETS		= false;
SCR_CONST_DEBUG_ENABLE_HARDENED		= false;
SCR_CONST_DEBUG_ENABLE_AR_HUD		= false;
SCR_CONST_DEBUG_ENABLE_CLOAK		= false;
SCR_CONST_DEBUG_INFINITE			= false;
#/

init()
{
/#
	SetDvarIfUninitialized( "scr_drone_assault_infinite", 0 );
#/
	
	level._effect[ "assault_c4_explode" ] 	= LoadFX( "vfx/vehicle/vehicle_assault_drone_rocket" );
	level._effect[ "remote_tank_explode" ]	= LoadFX( "vfx/explosion/vehicle_assault_drone_death" );
	level._effect[ "c4_forward_blur" ]		  = LoadFX( "vfx/unique/forward_view_radial_blur" );
	level._effect[ "assault_drone_exhaust" ]  = LoadFX( "vfx/vehicle/vehicle_mp_assault_drone_exhaust" );
	level._effect[ "assault_drone_thruster" ] = LoadFX( "vfx/vehicle/vehicle_mp_assault_drone_thruster" );
	level._effect[ "assault_drone_marker" ] = LoadFX( "vfx/ui/vfx_marker_drone_assault" );
	level._effect[ "assault_drone_exhaust_bottom" ]  = LoadFX( "vfx/vehicle/vehicle_mp_assault_drone_exhaust" );
	
	level.killStreakFuncs[ "assault_ugv" ] = ::tryUseAssaultDrone;
	
	level.killstreakWieldWeapons["drone_assault_remote_turret_mp"] = "assault_ugv";
	level.killstreakWieldWeapons["ugv_missile_mp"] = "assault_ugv";
	level.killstreakWieldWeapons["assaultdrone_c4_mp"] = "assault_ugv";
	level.killstreakWieldWeapons["killstreak_terrace_mp"] = "mp_terrace";
		
	thread assault_vehicle_ai_init();
	
	game["dialog"][ "ks_adrone_destroyed" ] = "ks_adrone_destroyed";
}		

getDroneSpawnPoint( modules ) // self == player
{
	spawnOrigin = undefined;
	spawnAngles = undefined;
	placementOK = undefined;
	
	results = SpawnStruct();
	results.placementOK = true;

	if ( array_contains( modules, "mp_terrace" ) )
	{
		orbit_initial_ent = GetEnt( "killstreak_orbit_initial", "targetname" );
		orbit_lookat_ent = GetEnt( "killstreak_orbit_lookat", "targetname" );
		if ( IsDefined( orbit_initial_ent ) && IsDefined( orbit_lookat_ent ) )
		{
			results.origin = orbit_initial_ent.origin;
			results.angles = VectorToAngles( orbit_lookat_ent.origin - orbit_initial_ent.origin );
		}
		else
		{
			spawn_loc = GetStruct( "mp_terrace_killstreak_start", "targetname" );
			results.origin = spawn_loc.origin;
			results.angles = spawn_loc.angles;
		}
	}
	else
	{
		results = droneGetSpawnPoint();
	}
	
	return results;
}

tryUseAssaultDrone( lifeId, modules ) // self == player
{ 		
	// Horde Mode - If the player already has an aerial drone, kill it to replace it with this new one
	if( IsDefined ( level.isHorde ) && level.isHorde )
		if ( IsDefined ( self.aerialDrone ) )
			self.aerialDrone notify ( "death" );
	
	numIncomingVehicles = 1;
	
	if( currentActiveVehicleCount() >= maxVehiclesAllowed() || ( ( level.fauxVehicleCount + numIncomingVehicles ) >= maxVehiclesAllowed() ) )
	{
		//"Too many vehicles already in the area."
		self IPrintLnBold( &"MP_TOO_MANY_VEHICLES" );
		return false;
	}
	
	// increment the faux vehicle count before we spawn the vehicle so no other vehicles try to spawn
	incrementFauxVehicleCount();
	
	results = getDroneSpawnPoint( modules );
	if ( !results.placementOK )
	{
		//"Drone Placement Invalid"
		self IPrintLnBold( &"MP_DRONE_PLACEMENT_INVALID" );
		decrementFauxVehicleCount();
		return false;
	}
	
	hasAIOption	= array_contains( modules, "assault_ugv_ai" );
/#	
	hasAIOption	= hasAIOption || SCR_CONST_DEBUG_ENABLE_AI;
#/	
	
	if ( !hasAIOption )
	{
		result = self maps\mp\killstreaks\_killstreaks::initRideKillstreak( "assault_ugv" );
		if ( result != "success" )
		{
			decrementFauxVehicleCount();
			return false;
		}
		self setUsingRemote( "assault_ugv" );
	}
	
	droneInstance = self CreateAssaultUav( lifeId, modules, results.origin, results.angles );
		
	if( IsDefined( droneInstance ) )
	{
		if ( array_contains( modules, "mp_terrace" ) )
		{
			self maps\mp\_matchdata::logKillstreakEvent( "mp_terrace", self.origin );
			self thread teamPlayerCardSplash( "used_mp_terrace", self );
		}
		else
		{
			self maps\mp\_matchdata::logKillstreakEvent( "assault_ugv", self.origin );
			self thread teamPlayerCardSplash( "used_assault_ugv", self );
			
		}
		
		if( IsDefined ( level.isHorde ) && level.isHorde )
			self.aerialDrone = droneInstance;
		
		return true;
	}
	else
	{
		// decrement the faux vehicle count since this failed to spawn
		return false;
	}
}


////=================================================================================================================//
////												UAV SETUP					                                     //
////=================================================================================================================//

CreateAssaultUav( lifeId, modules, spawnOrigin, spawnAngles )
{	
	// Choose vehicle type and lifespan based on modules
	hasTurret	= array_contains( modules, "assault_ugv_mg" ) || array_contains( modules, "assault_ugv_rockets" ) || array_contains( modules, "mp_terrace" );
/#	
	hasTurret	= hasTurret || SCR_CONST_DEBUG_ENABLE_MG || SCR_CONST_DEBUG_ENABLE_ROCKETS;
#/	
	mp_terrace 	= array_contains( modules, "mp_terrace" );
	
	vehType 	= "assault_uav_mp";
	lifespan 	= 30;

	if ( hasTurret )
	{
		vehType 	= "mg_assault_uav_mp";		// Slightly slower top speed
		lifespan 	= 45;
	}

/#
	if ( GetDvar( "scr_assault_drone_time", "0" ) != "0" )
		lifespan = GetDvarFloat( "scr_assault_drone_time" );
#/	

//	modelType = "model_tracking_drone_mp";
//	modelType = "vehicle_atlas_aerial_drone_01_assult_mp_static_clr_01";
	modelType = "vehicle_atlas_aerial_drone_01_assult_mp_noturret_clr_50p";
	if ( !hasTurret )
		modelType = "vehicle_atlas_aerial_drone_01_patrol_mp_static_clr_01_50p";
	
	if ( mp_terrace )
	{
		vehType 	= "assault_uav_mp_terrace";
//		modelType 	= "vehicle_atlas_aerial_drone_01_assult_mp_static_clr_01_50p";
		modelType 	= "vehicle_sniper_drone_cloak_mp";
		lifespan 	= 30;
	}
	
	vehicle = spawnHelicopter( self, spawnOrigin, spawnAngles, vehType, modelType );
	if ( !IsDefined( vehicle ) )
		return;
	
	// Set up the shadow ent on the vehicle (vehicle can be hidden to a player when driving)
//	vehicle.shadowEnt = Spawn( "script_model", spawnOrigin );
//	vehicle.shadowEnt.angles = vehicle.angles;
//	vehicle.shadowEnt SetModel( "vehicle_atlas_aerial_drone_01_assult_mp_static_shadow_50p" );
//	vehicle.shadowEnt LinkTo( vehicle, "tag_origin", ( 0, 0, 0 ), ( 0, 0, 0 ) );
//	vehicle.shadowEnt SetContents( 0 );
	
	thread SetupCommonAssaultDroneProperties( vehicle, lifeId, lifespan, modules );
	
	vehicle.getStingerTargetPosFunc = ::assault_drone_stinger_target_pos;
	
	return vehicle;
}

assault_drone_stinger_target_pos()
{
	return self GetTagOrigin( "tag_origin" );
}

setupPlayerCommands( drone )
{
	if ( IsBot( self ) )
		return;
	
	if ( IsDefined( drone ) && drone.hasAIOption )
		return;
	
	self NotifyOnPlayerCommand( "FirePrimaryWeapon", "+attack" );
	self NotifyOnPlayerCommand( "FirePrimaryWeapon", "+attack_akimbo_accessible" );
	self NotifyOnPlayerCommand( "FireSecondaryWeapon", "+speed_throw" );
	self NotifyOnPlayerCommand( "FireSecondaryWeapon", "+toggleads_throw" );
	self NotifyOnPlayerCommand( "FireSecondaryWeapon", "+ads_akimbo_accessible" );

	if ( IsDefined( drone ) && drone.hasCloak )
	{
		self NotifyOnPlayerCommand( "Cloak", "+usereload" );
		self NotifyOnPlayerCommand( "Cloak", "+activate" );
	}
}

disablePlayercommands( drone )
{
	if ( IsBot( self ) )
		return;

	if ( IsDefined( drone ) && drone.hasAIOption )
		return;

	self NotifyOnPlayerCommandRemove( "FirePrimaryWeapon", "+attack" );
	self NotifyOnPlayerCommandRemove( "FirePrimaryWeapon", "+attack_akimbo_accessible" );
	self NotifyOnPlayerCommandRemove( "FireSecondaryWeapon", "+speed_throw" );
	self NotifyOnPlayerCommandRemove( "FireSecondaryWeapon", "+toggleads_throw" );
	self NotifyOnPlayerCommandRemove( "FireSecondaryWeapon", "+ads_akimbo_accessible" );
	if ( IsDefined( drone ) && drone.hasCloak )
	{
		self NotifyOnPlayerCommandRemove( "Cloak", "+usereload" );
		self NotifyOnPlayerCommandRemove( "Cloak", "+activate" );
	}
}

SetupCommonAssaultDroneProperties( vehicle, lifeId, lifespan, modules )
{
	vehicle MakeUnusable();
	vehicle MakeVehicleSolidCapsule( 23, 23, 23 );

	vehicle.lifeId 		= lifeId;
	vehicle.team 		= self.team;
	vehicle.owner 		= self;
	vehicle.maxHealth 	= 250; 
	vehicle.destroyed 	= false;
	vehicle.vehicleType = "drone_assault";

	vehicle make_entity_sentient_mp( self.team );

	// Module options
	vehicle.modules 	= modules;
	vehicle.mp_terrace 	= array_contains( modules, "mp_terrace" );
	
	vehicle.hardened 	= array_contains( modules, "assault_ugv_hardened" );
/#	
	vehicle.hardened	= vehicle.hardened || SCR_CONST_DEBUG_ENABLE_HARDENED;
#/	
	vehicle.hasMG 		= array_contains( modules, "assault_ugv_mg" ) || vehicle.mp_terrace;
/#	
	vehicle.hasMG		= vehicle.hasMG || SCR_CONST_DEBUG_ENABLE_MG;
#/	
	vehicle.hasRockets 	= array_contains( modules, "assault_ugv_rockets" );
/#	
	vehicle.hasRockets	= vehicle.hasRockets || SCR_CONST_DEBUG_ENABLE_ROCKETS;
#/		
	vehicle.hasCloak 	= array_contains( modules, "assault_ugv_cloak" );
/#	
	vehicle.hasCloak	= vehicle.hasCloak || SCR_CONST_DEBUG_ENABLE_CLOAK;
#/	
	vehicle.hasAIOption	= array_contains( modules, "assault_ugv_ai" );
/#	
	vehicle.hasAIOption	= vehicle.hasAIOption || SCR_CONST_DEBUG_ENABLE_AI;
#/	
	vehicle.hasARHud 	= array_contains( modules, "assault_ugv_ar_hud" ) || vehicle.mp_terrace;
/#	
	vehicle.hasARHud	= vehicle.hasARHud || SCR_CONST_DEBUG_ENABLE_AR_HUD;
#/	
	vehicle.hasTurret 	= ( vehicle.hasMG || vehicle.hasRockets );
	vehicle.endTime 	= GetTime() + lifespan * 1000;

	if ( vehicle.hardened )
		vehicle.maxHealth = Int( vehicle.maxHealth * 1.3 ); // 30% health boost
	
	if ( !vehicle.hasAIOption )
	{
		self setupPlayerCommands( vehicle );
		self thread notify_assault_drone_on_player_command( vehicle );
	}

	vehicle SetCanDamage( true );
	vehicle.empGrenaded	= false;
	vehicle.damageFade 	= DAMAGE_FADE_TIME;
	
	vehicle thread maps\mp\gametypes\_damage::setEntityDamageCallback( vehicle.maxHealth, undefined, ::onAssaultDroneDeath, maps\mp\killstreaks\_aerial_utility::heli_ModifyDamage, true );
	
	vehicle Ghost();
	self thread droneSetupCloaking( vehicle, vehicle.hasCloak );
	if( vehicle.hasCloak )
	{
		self thread droneCloakReady( vehicle, vehicle.hasCloak );
	}

	self.using_remote_tank = !vehicle.hasAIOption;
	self.hasAIAssaultDrone = vehicle.hasAIOption;
	
	
	if ( !vehicle.hasAIOption )
	{
		self PlayerStartUsingAssaultVehicle( vehicle );
		self thread AssaultHudSetup( vehicle );	
		self thread MonitorUavSafeArea( vehicle );
	}
	else
	{
		self thread AIStartUsingAssaultVehicle( vehicle );
	}
	
	self thread MonitorPlayerDisconnect( vehicle );
	self thread AssaultHandleDeath( vehicle );
	self thread MonitorPlayerSwitchTeams( vehicle );
	self thread MonitorPlayerGameEnded( vehicle );
	self thread playerWatchForDroneEMP( vehicle );
	
	if ( vehicle.mp_terrace )
	{
		orbit_ent = GetEnt( "killstreak_orbit_origin", "targetname" );
		orbit_initial = GetEnt( "killstreak_orbit_initial", "targetname" );
		orbit_lookat = GetEnt( "killstreak_orbit_lookat", "targetname" );
		
		if ( IsDefined( orbit_ent ) && IsDefined( orbit_initial ) && IsDefined( orbit_lookat ) )
			vehicle SetOrbiterEnts( self, orbit_ent, orbit_initial, orbit_lookat );
	}
	
	if ( !vehicle.mp_terrace )
	{
		self thread playerHandleExhaustFx( vehicle, "assault_drone_exhaust", "TAG_EXHAUST_REAR", "assaultDroneHunterKiller" );
		self thread playerHandleExhaustFx( vehicle, "assault_drone_exhaust_bottom", "tag_exhaust_lt" );
		self thread playerHandleExhaustFx( vehicle, "assault_drone_exhaust_bottom", "tag_exhaust_rt" );
	}
	
	//if I am a drone class in coop - don't run the timeout warning
	if ( !isdefined ( level.isHorde ) || ( isdefined ( level.isHorde ) && self GetClientOmnvar ( "ui_horde_player_class" ) != "drone" ) )
		self thread AssaultHandleTimeoutWarning( vehicle, lifespan );
	self AssaultVehicleMonitorWeapons( vehicle );	

	self thread updateShootingLocation( vehicle, getfx( "assault_drone_marker" ) );

	self thread debug_Show_origin( vehicle );
	
	data = SpawnStruct();
	data.validateAccurateTouching = true;
	data.deathOverrideCallback = ::override_drone_platform_death;
	vehicle thread maps\mp\_movers::handle_moving_platforms( data );
	
	return vehicle;	
}

override_drone_platform_death( data )
{
	self notify( "death" );
}

debug_show_origin( vehicle )
{
/*	self endon( "disconnect" );
	vehicle endon( "death" );
	
	while( 1 )
	{
		Sphere( vehicle.origin, 2.0, (1,0,0), false, 20 );
		
		tag_origin_pos = vehicle GetTagOrigin( "tag_origin" );
		Sphere( tag_origin_pos, 2.0, (0,1,0), false, 20 );
		
		waitframe();
	}*/
}

notify_assault_drone_on_player_command(vehicle)
{
	self endon( "disconnect" );
	vehicle endon( "death" );
	
	while( 1 )
	{
		result = self waittill_any_return( "FirePrimaryWeapon", "FireSecondaryWeapon", "Cloak" );
		if ( isDefined( result ) )
		{
			vehicle notify( result );
		}
	}
}

PlayerStartUsingAssaultVehicle( vehicle ) // self == tank
{
	owner = self;

	if ( getDvarInt( "camera_thirdPerson" ) )
		owner setThirdPersonDOF( false );

	owner playerSaveAngles();
	
	if ( !vehicle.mp_terrace ) // Terrace is 1st-person
		owner CameraLinkTo( vehicle, "tag_origin" );
		
	owner RemoteControlVehicle( vehicle );
	
	owner thread setDroneVisionAndLightSetPerMap( 1.5, vehicle );
	
	owner.using_remote_tank = true;
	
	return true;
}

AssaultVehicleMonitorWeapons( vehicle )
{
	if ( vehicle.hasTurret )
		self thread SpawnMgTurret( vehicle );
	else
		self thread WaitForC4Detonation( vehicle );
	
	if ( vehicle.hasRockets )
		self thread SetupRockets( vehicle );
	
	self thread AssaultPlayerExit( vehicle );
}

////=================================================================================================================//
////											C4 DETONATION MECHANIC		            	   		                 //
////=================================================================================================================//

GetAssaultVehicleC4Radius()
{
	return CONST_C4_EXPLODE_DIST;
}

WaitForC4Detonation( vehicle )
{
	level endon( "game_ended" );
	vehicle endon( "death" );
	
	if ( !vehicle.hasAIOption )
		self thread playerHudOutlinesHunterKiller( vehicle );
	
	wait 2;
	
	vehicle waittill( "FirePrimaryWeapon" );
	
	self notify( "ForceUncloak" );
	
	self playerDoHunterKillerBehavior( vehicle );
	
	vehicle RadiusDamage( vehicle.origin + ( 0, 0, 50 ), GetAssaultVehicleC4Radius(), 200, 200, self, "MOD_EXPLOSIVE", "AssaultDrone_C4_mp" );
	PlayFX( getfx( "assault_c4_explode" ), vehicle.origin );
	
	vehicle notify( "death" );
}

playerHudOutlinesHunterKiller( vehicle )
{
	foreach ( player in level.players )
	{
		if ( self.team != player.team && !player _hasPerk( "specialty_blindeye" ) )
		{
			player HudOutlineEnableForClient( self, 0, true );
		}
	}
	
	vehicle waittill( "death" );
	
	if ( !IsDefined( self ) )
		return;
	
	foreach ( player in level.players )
	{
		if ( self.team != player.team )
		{
			player HudOutlineDisableForClient( self );
		}
	}
}

onPlayerConnectHunterKiller( vehicle )
{
	vehicle endon( "death" );
	
	while ( true )
	{
		level waittill( "connected", player );
		
		if ( !IsDefined( self ) )
			return;
		
		if ( self.team != player.team )
			player thread onPlayerSpawnedHunterKiller();
	}
}

onPlayerSpawnedHunterKiller( vehicleOwner )
{
	self endon( "disconnect" );

	self waittill( "spawned_player" );			
	
	if ( IsDefined( vehicleOwner ) )
		self HudOutlineEnableForClient( vehicleOwner, 0, true ); 
}

playerDoHunterKillerBehavior( vehicle ) // self == player
{
	MAX_TIME_TO_EXPLODE = 7000;
	DIST_TO_CAM_UNLINK_SQ = 150 * 150;
	DIST_TO_EXPLODE_SQ = 60 * 60;
	
	self notify( "assaultDroneHunterKiller" );
	vehicle.hunterKiller = true;
	
	if ( vehicle.hasAIOption )
		start = vehicle.origin;
	else
		start = self GetViewOrigin( true );
	end = vehicle.targetEnt.origin;
	dir = VectorNormalize( end - start );
	end = start + ( dir * 20000 );
	trace = BulletTrace( start, end, false, vehicle, false, false, true, false, false );
		
	goal = trace[ "position" ];
	distSq = DistanceSquared( vehicle.origin, goal );
	if ( distSq > DIST_TO_EXPLODE_SQ )
	{
		fxEnt = undefined;
		if ( vehicle.hasAIOption )
		{
			pos = vehicle.origin;
			ang = vehicle.angles;
		}
		else
		{
			pos = self GetViewOrigin( true );
			ang = self GetPlayerAngles();
			vehicle.camLinkEnt = Spawn( "script_model", pos );
			vehicle.camLinkEnt SetModel( "tag_player" );
			vehicle.camLinkEnt.angles = ang;
			vehicle.camLinkEnt LinkTo( vehicle, "tag_origin" );
			waitframe();
			self PlayerLinkWeaponViewToDelta( vehicle.camLinkEnt, "tag_player", 1, 0, 0, 0, 0, true );
			self PlayerLinkedSetViewZnear( false );
			self RemoteControlVehicleOff();
			Earthquake( 0.2, 1, pos, 100 );
			fxEnt = SpawnFXForClient( getfx( "c4_forward_blur" ), pos, self );
			TriggerFX( fxEnt );
		}
		StopFXOnTag( getfx( "assault_drone_exhaust" ), vehicle, "TAG_EXHAUST_REAR" );
		vehicle notify( "stopShootLocationUpdate" );
		vehicle SetOtherEnt( undefined );
		vehicle Vehicle_Teleport( vehicle.origin, vehicle.angles, false, false );
		waitframe();
		self thread playerPlayTargetFX( vehicle, goal );
		self thread playerPlayThrusterSound( vehicle );
		endTime = GetTime() + MAX_TIME_TO_EXPLODE;
		speed = 120;
		accel = speed * 4 / 5;
		vehicle Vehicle_SetSpeed( speed, accel );
		vehicle SetVehGoalPos( goal, false );
		vehicle.staticLevelWaitTime = 0.3;
		vehicle.alwaysStaticOut = true;
		vehicle SetContents( 0 );
		
		waitframe();
	    PlayFXOnTag( getfx( "assault_drone_thruster" ), vehicle, "TAG_EXHAUST_REAR" );
		distSq = DistanceSquared( vehicle.origin, goal );
		while ( GetTime() < endTime && distSq > DIST_TO_CAM_UNLINK_SQ )
		{
			waitframe();
			distSq = DistanceSquared( vehicle.origin, goal );
			GlassRadiusDamage( vehicle.origin, 70, 200, 200 );
		}
		if ( !vehicle.hasAIOption )
			vehicle.camLinkEnt Unlink();
		while ( GetTime() < endTime && distSq > DIST_TO_EXPLODE_SQ )
		{
			waitframe();
			distSq = DistanceSquared( vehicle.origin, goal );
			GlassRadiusDamage( vehicle.origin, 70, 200, 200 );
		}
		
		vehicle Vehicle_SetSpeedImmediate( 0 );
		
		if ( !vehicle.hasAIOption )
		{
			fxEnt Delete();
		}
	}
}

playerPlayThrusterSound( vehicle )
{
	soundEnt = Spawn( "script_model", vehicle.origin );
	soundEnt LinkTo( vehicle, "tag_origin" );
	soundEnt Hide();
	foreach ( player in level.players )
	{
		if ( self == player )
			continue;
		
		soundEnt ShowToPlayer( player );
	}
	soundEnt PlaySoundOnMovingEnt( "assault_drn_kamikaze_boost_npc" );
	
	self PlayLocalSound( "assault_drn_kamikaze_boost_plr" );
	
	wait 2;
	
	soundEnt Delete();
}

playerPlayTargetFX( vehicle, targetPos ) // self == player
{
	groundEnt = spawn( "script_model", targetPos );
	groundEnt setModel( "tag_origin" );
	groundEnt.angles = ( -90, 0, 0 );

	PlayFXOnTagForClients( getfx( "assault_drone_marker" ), groundEnt, "tag_origin", self );
	
	vehicle waittill( "death" );
	
	StopFXOnTag( getfx( "assault_drone_marker" ), groundEnt, "tag_origin" );
	waitframe();
	groundEnt Delete();
}

////=================================================================================================================//
////											MG TURRET MECHANIC			            	   		                 //
////=================================================================================================================//

SpawnMgTurret( vehicle )
{
	vehicle endon( "death" );
	self endon( "disconnect" );
		
	turretType = "drone_assault_remote_turret_mp";
	turretModel = "vehicle_atlas_aerial_drone_01_mp_turret_50p";
	dropPitch = 0.0;
	
	tagName = "tag_origin";
	tagOriginOffset = ( 0, 0, 0 );
	tagAngleOffset = ( 0, 0, 0 );
	
	if ( vehicle.mp_terrace )
	{
		turretType = "killstreak_terrace_mp";
		turretModel = "vehicle_sniper_drone_turret_mp_cloak";
	}
	
	turretAttachTagOrigin = vehicle GetTagOrigin( tagName );
	
	mgTurret = SpawnTurret( "misc_turret", turretAttachTagOrigin, turretType, false );
	mgTurret.angles = vehicle.angles;
	mgTurret SetModel( turretModel );
	mgTurret SetDefaultDropPitch( dropPitch );
	mgTurret LinkTo( vehicle, tagName, tagOriginOffset, tagAngleOffset );
	mgTurret.owner = self;
	mgTurret.health = 99999;
	mgTurret SetCanDamage( false );
	mgTurret SetCanRadiusDamage( false );
	mgTurret.tank = vehicle;
	mgTurret MakeUnusable();
	
	if ( vehicle.hasAIOption )
		mgTurret.killCamEnt = vehicle;

	vehicle.mgTurret = mgTurret;	
	vehicle.mgTurret SetMode( "sentry_manual" );
	vehicle.mgTurret SetSentryOwner( self );
	vehicle.mgTurret SetTurretMinimapVisible( false );	
	// Set this when we create it
//	vehicle.mgTurret SetTargetEntity( vehicle.targetEnt );
	vehicle.mgTurret CloakingEnable();
	
	if ( !vehicle.hasMG )
		vehicle.mgTurret TurretFireDisable();

	if ( vehicle.mp_terrace )
	{
	//	self EnableSlowAim( .2, .3, 0.66, 0.35 );
		self EnableSlowAim( .2, .3, 0.8, 0.8 );
		self thread terrace_turret_fx( vehicle );
	}
	
	if ( !vehicle.hasAIOption )
	{
		if ( vehicle.mp_terrace ) // No delay for terrace -- the normal drones with guns are on a tag in third person and the camera moves there instantly.  The terrace drone is in 1st person and requires that the player be controlling the turret before the camera moves from the player.
			self thread control_turret_after_delay( vehicle, 0.0 );
		else
			self thread control_turret_after_delay( vehicle, 1.6 ); // wait for freeze controls to lift
	}

	self thread delete_turret_on_death( vehicle );
	
	if ( vehicle.hasCloak && vehicle.hasMG )
		self thread watchMGFireUncloak( vehicle );
}

control_turret_after_delay( vehicle, delay_time )
{
	dropPitch = 0.0;
	
	if ( delay_time > 0 )
		wait( delay_time );
	
	if ( IsDefined( self ) && IsDefined( vehicle ) && IsDefined( vehicle.mgTurret ) )
		self RemoteControlTurret( vehicle.mgTurret, dropPitch );
}

watchMGFireUncloak( vehicle )
{
	vehicle endon( "death" );
	self endon( "disconnect" );

	while ( true )
	{
		vehicle waittill ( "FirePrimaryWeapon" );		
		self notify( "ForceUncloak" );
	}
}

terrace_turret_fx( vehicle )
{
	vehicle endon( "death" );
	level endon( "game_ended" );
	
	waitframe();
	
	// Attach FX
	PlayFXOnTagForClients( level._effect[ "sniper_drone_thruster_view" ], vehicle.mgTurret, "tag_fx2", self );
	waitframe();
	PlayFXOnTagForClients( level._effect[ "sniper_drone_wind_marker" ], vehicle.mgTurret, "tag_fx1", self );
}

delete_turret_on_death( vehicle )
{
	vehicle waittill( "death" );
	
	if ( IsDefined( self ) )
	{
		self RemoteControlTurretOff( vehicle.mgTurret );
		self ThermalVisionFOFOverlayOff();
	}

	if ( vehicle.mp_terrace )
	{
		StopFXOnTag( level._effect[ "sniper_drone_thruster_view" ], vehicle.mgTurret, "tag_fx2" );
		StopFXOnTag( level._effect[ "sniper_drone_wind_marker" ], vehicle.mgTurret, "tag_fx1" );
	}
	
	vehicle.mgTurret Delete();
}

////=================================================================================================================//
////												ROCKET MECHANIC			            	   		                 //
////=================================================================================================================//

SetupRockets( vehicle )
{
	vehicle endon( "death" );
	self endon( "disconnect" );
	
	vehicle.RocketAmmo = CONST_Rocket_AmmoMax;
	
	if ( self GetClientOmnvar( "ui_assaultdrone_toggle" ) )
		self SetClientOmnvar( "ui_assaultdrone_rockets", vehicle.RocketAmmo );
		
	while( 1 )
	{
		if ( vehicle.hasMG )
			vehicle waittill ( "FireSecondaryWeapon" );
		else
			vehicle waittill ( "FirePrimaryWeapon" );
		
		self notify( "ForceUncloak" );
		
		Earthquake( 0.3, 1, vehicle.origin, 500 );
		self PlayRumbleOnEntity( "damage_heavy" );
		missile_tag_origin = vehicle.mgTurret GetTagOrigin( "tag_flash" );
		missile_end = vehicle.TargetEnt.origin;
		
		if ( vehicle.hasAIOption )
			assault_velocity = vehicle Vehicle_GetVelocity();
		else
			assault_velocity = vehicle GetEntityVelocity();

		missile = MagicBullet( "ugv_missile_mp", missile_tag_origin + assault_velocity / 10, missile_end, self );
		
		missile Missile_SetTargetEnt( vehicle.TargetEnt );
		missile Missile_SetFlightmodeDirect();
		
		if ( vehicle.hasAIOption )
			missile.killCamEnt = vehicle;
		
		vehicle.RocketAmmo--;
		
		if( vehicle.RocketAmmo > 0 )
		{
			self SetClientOmnvar( "ui_assaultdrone_rockets", vehicle.RocketAmmo );
			wait CONST_Rocket_Shot_Interval;
		}
		else
		{
			// Reload
			// TODO: Play a reload sound
			self SetClientOmnvar( "ui_assaultdrone_rockets", 4 ); // Reloading
			wait CONST_Rocket_Reload_Interval;
			vehicle.RocketAmmo = CONST_Rocket_AmmoMax;
			self SetClientOmnvar( "ui_assaultdrone_rockets", vehicle.RocketAmmo );
		}
	}
}

////=================================================================================================================//
////												UGV & UAV HUD			            	   		                 //
////=================================================================================================================//

AssaultHudSetup( vehicle )
{
	vehicle endon( "death" );
	self endon( "disconnect" );
	
	// Ensure the omnvars have been reset
	AssaultHudRemove( vehicle );
	
	wait( 0.5 );
	
	// Add the overlay
	self SetClientOmnvar( "ui_assaultdrone_toggle", true );
		
	// Anyone spectating this player should be forced into first person
	if ( vehicle.mp_terrace )
		self ForceFirstPersonWhenFollowed();
		
	self maps\mp\killstreaks\_aerial_utility::playerEnableStreakStatic();

	self SetClientOmnvar( "ui_assaultdrone_countdown", 	vehicle.endTime );
/#	
	if ( SCR_CONST_DEBUG_INFINITE || GetDvarInt( "scr_drone_assault_infinite", 0 ) )
		self SetClientOmnvar( "ui_assaultdrone_countdown", 0 );
#/	
	
	// C4
	if ( !vehicle.hasTurret )
		self SetClientOmnvar( "ui_assaultdrone_weapon", 2 );
	else if ( vehicle.mp_terrace )
		self SetClientOmnvar( "ui_assaultdrone_weapon", 3 );
	else if ( vehicle.hasMG )
		self SetClientOmnvar( "ui_assaultdrone_weapon", 1 );
	
	if ( vehicle.hasRockets && IsDefined( vehicle.RocketAmmo ) )
		self SetClientOmnvar( "ui_assaultdrone_rockets", vehicle.RocketAmmo );
	
	if ( vehicle.hasCloak )
		self SetClientOmnvar( "ui_drone_cloak", 2 );
	if ( isdefined ( level.isHorde ) && level.isHorde && self GetClientOmnvar ( "ui_horde_player_class" ) == "drone" )
		self SetClientOmnvar( "ui_horde_drone_heal", 1 );

	if ( vehicle.hasARHud )
		self ThermalVisionFOFOverlayOn();
}

AssaultHudRemove( vehicle )
{
	self SetClientOmnvar( "ui_assaultdrone_toggle", false );
	self SetClientOmnvar( "ui_assaultdrone_countdown", 0 );
	self SetClientOmnvar( "ui_drone_cloak", 0 );
	self SetClientOmnvar( "ui_drone_cloak_time", 0 );
	self SetClientOmnvar( "ui_drone_cloak_cooldown", 0 );
	self SetClientOmnvar( "ui_assaultdrone_weapon", 0 );
	self SetClientOmnvar( "ui_assaultdrone_rockets", 0 );
	self maps\mp\killstreaks\_aerial_utility::playerDisableStreakStatic();
	
	if ( vehicle.mp_terrace )
		self DisableForceFirstPersonWhenFollowed();
}

////=================================================================================================================//
////										DAMAGE AND TIMEOUT MECHANIC			               		                 //
////=================================================================================================================//

MonitorUavSafeArea( vehicle )
{
	self endon( "assaultStreakComplete" );
	
	if ( vehicle.mp_terrace )
		return;
	
	self thread maps\mp\killstreaks\_aerial_utility::playerHandleBoundaryStatic( vehicle, "assaultStreakComplete" );
	self thread maps\mp\killstreaks\_aerial_utility::playerHandleKillVehicle( vehicle, "assaultStreakComplete" );
	
	vehicle waittill( "outOfBounds" );
			
	wait 2;
	
	vehicle notify( "death" );
}

MonitorPlayerDisconnect( vehicle )
{
	self endon( "StopWaitForDisconnect" );
	vehicle endon( "death" );
	
	self waittill( "disconnect" );
	
	vehicle notify( "death" );
}

MonitorPlayerSwitchTeams( vehicle )
{
	self endon( "assaultStreakComplete" );

	self waittill_any( "joined_team", "joined_spectators" );
	
	vehicle notify( "death" );
}

MonitorPlayerGameEnded( vehicle )
{
	self endon( "assaultStreakComplete" );
	
	level waittill( "game_ended" );
	
	vehicle notify( "death" );
}

onAssaultDroneDeath( attacker, weapon, meansOfDeath, damage  )
{
	self notify( "death", attacker, meansOfDeath, weapon );
	
	if( IsDefined( level.isHorde ) && level.isHorde && IsDefined( attacker.ishordeenemysentry ) && attacker.ishordeenemysentry )
		return;
	
	if ( self.mp_terrace )
	{
		self maps\mp\gametypes\_damage::onKillstreakKilled( attacker, weapon, meansOfDeath, damage, "map_killstreak_destroyed", undefined, "callout_destroyed_terrace_sniper_drone", true );
	}
	else
	{
		self maps\mp\gametypes\_damage::onKillstreakKilled( attacker, weapon, meansOfDeath, damage, "assault_drone_destroyed", undefined, "callout_destroyed_drone_assault", true );
	}
}


AssaultHandleTimeoutWarning( vehicle, lifespan )
{
	vehicle endon ( "death" );	
	
/#	
	if ( SCR_CONST_DEBUG_INFINITE || GetDvarInt( "scr_drone_assault_infinite", 0 ) )
		return;
#/	

	maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( lifeSpan - 10 );
	
	timeout = 10;
	
	while( timeout != 0 )
	{
		if ( !vehicle.hasAIOption )
			vehicle PlaySound( "mp_warbird_outofbounds_warning" );	
		timeout -= 1;
		wait 1;
	}
	
	if ( IsDefined( vehicle.hunterKiller ) )
		return;
	
	vehicle notify( "death" );
}

AssaultHandleDeath( vehicle ) // self == player
{
	entNum = vehicle GetEntityNumber();
		
	vehicle droneAddToGlobalList( entNum );
	
	vehicle waittill ( "death", attacker );
	
	if ( IsDefined( vehicle.camLinkEnt ) )
	    vehicle.camLinkEnt Unlink();
	
	if ( IsDefined( vehicle ) )
		vehicle Ghost(); // Still send over the network
	
	if ( IsDefined( vehicle.mgTurret ) )
		vehicle.mgTurret Ghost(); // Still send over the network

	if ( IsDefined( self ) && !vehicle.hasAIOption )
		self freezeControlsWrapper( true );
	
	self notify( "assaultStreakComplete" );
	self notify( "StopWaitForDisconnect" );
	
	vehicle PlaySound( "assault_drn_death" );		
	PlayFX( level._effect[ "remote_tank_explode" ], vehicle.origin );
		
	vehicle droneRemoveFromGlobalList( entNum );

	if ( IsDefined( self ) && !vehicle.hasTurret && !vehicle.hasAIOption && !level.gameEnded )
	{
		wait 1;
		self maps\mp\killstreaks\_aerial_utility::playerShowFullStatic();
		wait 0.8;
		maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone();
	}
	
	if ( IsDefined( self ) && IsDefined( attacker ) && self != attacker )
		self thread leaderDialogOnPlayer( "ks_adrone_destroyed", undefined, undefined, self.origin );
	
	if ( !vehicle.hasAIOption )
	{
		if ( IsDefined( self ) && !level.gameEnded )
			self freezeControlsWrapper( false );
		
		// make sure the owner gets out
		// there's a bug where you can get stuck in a black screen because the player and ReconUgv die at the same time and that ends scripts that would reset the view
		if ( IsDefined( self ) && ( self.using_remote_tank || self isUsingRemote() ) )
		{		
			self AssaultSetInactivity( vehicle );
			self.using_remote_tank = false;
		}
	}
	else
	{
		if ( isdefined ( self ) )
			self.hasAIAssaultDrone = false;
	}

	// decrement the faux vehicle count right before it is deleted this way we know for sure it is gone
	decrementFauxVehicleCount();
	
//	if ( IsDefined( vehicle.shadowEnt ) )
//		vehicle.shadowEnt delete();
	
	if ( IsDefined( vehicle.camLinkEnt ) )
	    vehicle.camLinkEnt Delete();
	
	vehicle delete();	
}

AssaultSetInactivity( AssaultVeh )
{
	if( !IsDefined( AssaultVeh ) )
		return;

	owner = self;
				
	if( IsDefined( owner.using_remote_tank ) && owner.using_remote_tank )
	{
		owner notify( "end_remote" );
		
		owner DisableSlowAim();
		owner RemoteControlVehicleOff( AssaultVeh );
		owner ThermalVisionFOFOverlayOff();
		self thread removeDroneVisionAndLightSetPerMap( 1.5 );
		owner Unlink();

		if ( owner isUsingRemote() && !level.gameEnded )
			owner clearUsingRemote();
		
		owner switch_back_to_player_weapon();
		owner playerRestoreAngles();
		
		owner disablePlayercommands( AssaultVeh );

		thread AssaultHudRemove( AssaultVeh );
		if ( getDvarInt( "camera_thirdPerson" ) )
			owner setThirdPersonDOF( true );				

		// just in case the tank is killed before you can get in it, the initRideKillstreak() does _disableUsability() and we unfortunately kill the thread on death
		if( IsDefined( owner.disabledUsability ) && owner.disabledUsability )
			owner _enableUsability();

		owner.using_remote_tank = false;
	}
}

switch_back_to_player_weapon()
{
	killstreakWeapon = getKillstreakWeapon( "orbitalsupport" );
	self TakeWeapon( killstreakWeapon );
	
	self EnableWeaponSwitch();
	self SwitchToWeapon( self getLastWeapon() );
}

AssaultPlayerExit( vehicle ) // self == tank
{
	if( !IsDefined( self ) )
		return;

	owner = self;

	level endon( "game_ended" );
	owner endon ( "disconnect" );
	owner endon( "assaultDroneHunterKiller" );
	vehicle endon ( "death" );

	while( true )
	{
		timeUsed = 0;
		while( !vehicle.hasAIOption && owner UseButtonPressed() )
		{	
			timeUsed += 0.05;
			if( timeUsed > 0.75 )
			{	
				vehicle notify( "death" );
				return;
			}
			wait( 0.05 );
		}
		wait( 0.05 );
	}
}
