#include maps\mp\_utility;
#include common_scripts\utility;
#include maps\mp\_audio;


/*
	Orbital
	Objective: 	Score points for your team by eliminating players on the opposing team
	Map ends:	When one team reaches the score limit, or time limit is reached
	Respawning:	No wait / Near teammates / From Orbital Ships

	Level requirements
	------------------
		Spawnpoints:
			classname:		mp_tdm_spawn
			All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies
			at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies.

		Spectator Spawnpoints:
			classname:		mp_global_intermission
			Spectators spawn from these and intermission is viewed from these positions.
			Atleast one is required, any more and they are randomly chosen between.

		Drop Pod Volumes:
			classname:		trigger_multiple
			targetname:		drop_pod_volume
			These volumes are used to deermine if the point of impact for the drop pod is a valid location to spawn.
			If the POI is within the volume, the spawn is valid so only place these volumes in places that you want players
			to be able to spawn. If the POI is not within any of the drop pod volumes, it looks for the closest path node
			within a radius of 256 units and trys to spawn the player there. If no node is found, player is killed.
			Atleast one is required, though you can place as many as you would like. It is not required to have all of the
			trigger brushes as part of the same entity.	
			
		Air Strike Height:
			classname:		script_origin
			targetname:		airstrikeheight
			This entity is used to determine the height of the Orbital Ships. The Orbital Ship's height set to be X units
			above the script_origin's height based on level.orbital_ships.extra_height. We may need tp look into a better way of
			doing this if it is not consistant enough across all maps.
			
		Bad Spawn Overlay:
			classname:				script_brushmodel
			targetname:				orbital_bad_spawn_overlay
			script_gameobjectname:	orbital
			script_gametype_tdm:	0
			These brushes are shown to the player while they are in the orbital ship and while drop podding into the map.
			These show the player where they are unable to spawn. Things like rooftops or areas outside of the playable area
			that look like they might be ok to spawn at. Should hopefully cut down on confusion of where it is safe to land.
*/


////==============================================================================
precacheOrbital()
////==============================================================================
{
	PreCacheModel( "tag_player" );
	PreCacheModel( "vehicle_ac130_coop" );
	PreCacheModel( "vehicle_drop_pod_base" );
	PreCacheModel( "vehicle_drop_pod_base_enemy" );

	PreCacheMpAnim( "mp_orbital_pod_base_unfold" );

	game["dialog"]["orbital_pod_destroyed"] = "orbital_pod_destroyed";
	game["dialog"]["orbital_pod_destroyed_enemy"] = "orbital_pod_destroyed_enemy";
	game["dialog"]["orbital_dropin"] = "orbital_dropin";
	game["dialog"]["orbital_notgood_tryhard"] = "orbital_notgood_tryhard";
	
//	commenting these out for now until we have a tech solution for the VFX rendering properly in all levels.
//	level.drop_pod_dome["friendly"]					= LoadFX( "vfx/unique/orbital_dome_friendly" );
//	level.drop_pod_dome["enemy"]					= LoadFX( "vfx/unique/orbital_dome_enemy" );
//	level.drop_pod_dome_ground["friendly"]			= LoadFX( "vfx/unique/orbital_dome_ground_friendly" );
//	level.drop_pod_dome_ground["enemy"]				= LoadFX( "vfx/unique/orbital_dome_ground_enemy" );
	level.drop_pod_effect["pod_base_destroyed"]		= LoadFX( "vfx/explosion/orbital_pod_base_explosion" );
	level.drop_pod_effect["dome_impact_flash"]		= LoadFX( "vfx/unique/orbital_dome_impact_flash" );
	level.drop_pod_effect["dome_shutdown_friendly"]	= LoadFX( "vfx/unique/orbital_dome_shutdown_friendly" );
	level.drop_pod_effect["dome_shutdown_enemy"]	= LoadFX( "vfx/unique/orbital_dome_shutdown_enemy" );
	level.drop_pod_effect["player_spawn_from_pod"]	= LoadFX( "vfx/ui/drop_pod_spawn_point_active" );
	level.drop_pod_effect["drop_pod_fire_flash"]	= LoadFX( "vfx/unique/orbital_drop_pod_fire_flash" );
	level.drop_pod_effect["decel_explosion"]		= LoadFX( "vfx/explosion/orbital_pod_decel_explosion" );
	level.drop_pod_effect["dome_impact"]			= LoadFX( "vfx/explosion/orbital_pod_impact_dome" );
	level.drop_pod_effect["landing_impact"]			= LoadFX( "vfx/smoke/drop_pod_landing_impact" );
	level.drop_pod_effect["drop_pod_explode"]		= LoadFX( "vfx/explosion/orbital_drop_pod_explode" );
	level.drop_pod_effect["drop_pod_spike_impact"]	= LoadFX( "vfx/weaponimpact/drop_pod_spike_impact" );
		
	current_level = GetDvar( "mapname" );
	switch ( current_level )
	{
		case "mp_refraction":
			level.drop_pod_dome["friendly"]			= LoadFX( "vfx/unique/orbital_dome_friendly_ref" );
			level.drop_pod_dome["enemy"]			= LoadFX( "vfx/unique/orbital_dome_enemy_ref" );
			level.drop_pod_dome_ground["friendly"]	= LoadFX( "vfx/unique/orbital_dome_ground_friendly_ref" );
			level.drop_pod_dome_ground["enemy"]		= LoadFX( "vfx/unique/orbital_dome_ground_enemy_ref" );
			break;
	
		default:
			level.drop_pod_dome["friendly"]			= LoadFX( "vfx/unique/orbital_dome_friendly" );
			level.drop_pod_dome["enemy"]			= LoadFX( "vfx/unique/orbital_dome_enemy" );
			level.drop_pod_dome_ground["friendly"]	= LoadFX( "vfx/unique/orbital_dome_ground_friendly" );
			level.drop_pod_dome_ground["enemy"]		= LoadFX( "vfx/unique/orbital_dome_ground_enemy" );
			break;
	}
}


/*
///ScriptDocBegin
Name: setupOribtialMode( )
Summary: Initiate Orbital assets and turns on Orbital Spawning.
Module: orbital
CallOn: Call during gameType initialization -> onStartGameType
Example: setupOribtialMode();
SPMP: MP
///ScriptDocEnd
*///==============================================================================
initializeOribtalMode()
////==============================================================================
{
	precacheOrbital();
	
	// Creating a struct for our drop pods.
	level.drop_pod = SpawnStruct();
	level.drop_pod.model = "vehicle_drop_pod_base";
	level.drop_pod.enemy_model = "vehicle_drop_pod_base_enemy";
	level.drop_pod.deploy_delay = 2;
	level.drop_pod_volume_array = GetEntArray( "drop_pod_volume", "targetname" );
	level.drop_pod_bad_spawn_overlay = GetEntArray( "orbital_bad_spawn_overlay", "targetname" );
	level.orbital_ships = SpawnStruct();
	
	// Amount of time before being forced to respawn
	level.forcerespawn_time = 15;
	
	current_level = GetDvar( "mapname" );
	
	switch ( current_level )
	{
		//=========================================
		case "mp_refraction": // special path to avoid the space elevator.

			SetDvar( "missileRemoteSteerPitchRange", "37 88" );

			level.left_loop_start = getent( "orbital_plane_left_loop_start", "targetname" );
			level.left_big_loop_start = getent( "orbital_plane_left_big_loop_start", "targetname" );
			level.right_loop_start = getent( "orbital_plane_right_loop_start", "targetname" );
			level.right_big_loop_start = getent( "orbital_plane_right_big_loop_start", "targetname" );
			
			level.left_pivot = getent( "orbital_left_loop_pivot", "targetname" );
			level.left_big_pivot = getent( "orbital_left_big_loop_pivot", "targetname" );
			level.right_pivot = getent( "orbital_right_loop_pivot", "targetname" );
			level.right_big_pivot = getent( "orbital_right_big_loop_pivot", "targetname" );
			
			level.orbital_ships.missileSpawn["target"] = getent( "orbitalMissileTarget", "targetname" );
						
			level.orbital_ships.cameraView["allies"] = Spawn ( "script_model", level.left_loop_start.origin );
			level.orbital_ships.cameraView["allies"] SetModel ( "tag_player" );
			level.orbital_ships.cameraView["allies"].angles += ( 0, 220, 0 );
			level.orbital_ships.cameraView["allies"].team = "allies";
			level.orbital_ships.cameraView["allies"] LinkToSynchronizedParent ( level.left_pivot );
			level.orbital_ships.cameraView["allies"].track = "left";
			level.orbital_ships.cameraView["allies"] hide();
			
			level.orbital_ships.cameraView["axis"] = Spawn ( "script_model", level.left_big_loop_start.origin );
			level.orbital_ships.cameraView["axis"] SetModel ( "tag_player" );
			level.orbital_ships.cameraView["axis"].angles += ( 0, 330, 0 );
			level.orbital_ships.cameraView["axis"].team = "axis";
			level.orbital_ships.cameraView["axis"] LinkToSynchronizedParent ( level.left_big_pivot );
			level.orbital_ships.cameraView["axis"].track = "left_big";
			level.orbital_ships.cameraView["axis"] hide();
			
			level.orbital_ships.ship["allies"] = Spawn ( "script_model", level.left_loop_start.origin );
			level.orbital_ships.ship["allies"] SetModel ( "vehicle_ac130_coop" );
			level.orbital_ships.ship["allies"].angles += ( 0, 220, 0 );
			level.orbital_ships.ship["allies"] LinkToSynchronizedParent ( level.orbital_ships.cameraView["allies"], "", (0,0,80), (0,0,0) );
				
			level.orbital_ships.ship["axis"] = Spawn ( "script_model", level.left_big_loop_start.origin );
			level.orbital_ships.ship["axis"] SetModel ( "vehicle_ac130_coop" );
			level.orbital_ships.ship["axis"].angles += ( 0, 330, 0 );
			level.orbital_ships.ship["axis"] LinkToSynchronizedParent ( level.orbital_ships.cameraView["axis"], "", (0,0,80), (0,0,0) );
			
			thread rotateOrbitalShipPivots();
			
			level.orbital_ships.cameraView["allies"] thread monitorTrackSwitching();
			level.orbital_ships.cameraView["axis"] thread monitorTrackSwitching();
			
			break;
			
		//=========================================
//		case "mp_laser2":
//			
//			
//			
//			break;
			
		//=========================================
		default: // all other levels
		
			SetDvar( "missileRemoteSteerPitchRange", "47 88" );
		
			// Create the Orbital Ships and start them rotating.
			height_ent = getent( "airstrikeheight", "targetname" );
			minimap_origins = getEntArray( "minimap_corner", "targetname" );
		
			if ( minimap_origins.size == 2 )
				level.orbital_ships.center = maps\mp\gametypes\_spawnlogic::findBoxCenter( minimap_origins[0].origin, minimap_origins[1].origin );
			else
				AssertMsg("unexpected number of minimap_corner ents found. " + minimap_origins.size);
			
			level.orbital_ships.dist_from_center = 3500;
			level.orbital_ships.extra_height = 2000;
			level.orbital_ships.center *= ( 1, 1, 0 );
			level.orbital_ships.center += ( 0, 0, height_ent.origin[2] + level.orbital_ships.extra_height );
			
			map_center = level.orbital_ships.center;
			angles_ally = ( 0, 0, 0 );
			angles_axis = ( 0, 180, 0 );
			
			start_point_ally = map_center + ( AnglesToForward( angles_ally ) * ( level.orbital_ships.dist_from_center ) );
			start_point_axis = map_center + ( AnglesToForward( angles_axis ) * ( level.orbital_ships.dist_from_center ) );
			
			level.orbital_ships.script_origin = Spawn ( "script_origin", level.orbital_ships.center );
			
			level.orbital_ships.cameraView["allies"] = Spawn ( "script_model", start_point_ally );
			level.orbital_ships.cameraView["allies"] SetModel ( "tag_player" );
			level.orbital_ships.cameraView["allies"].angles += ( 0, 180, 0 );
			level.orbital_ships.cameraView["allies"] LinkToSynchronizedParent ( level.orbital_ships.script_origin );
			level.orbital_ships.cameraView["allies"] hide();
			
			level.orbital_ships.cameraView["axis"] = Spawn ( "script_model", start_point_axis );
			level.orbital_ships.cameraView["axis"] SetModel ( "tag_player" );
			level.orbital_ships.cameraView["axis"].angles += ( 0, 0, 0 );
			level.orbital_ships.cameraView["axis"] LinkToSynchronizedParent ( level.orbital_ships.script_origin );
			level.orbital_ships.cameraView["axis"] hide();
				
			level.orbital_ships.missileSpawn["target"] = Spawn ( "script_origin", (level.orbital_ships.center - (0, 0, 7000)) );
			level.orbital_ships.missileSpawn["target"].targetname = "orbitalMissileTarget";
			
			level.orbital_ships.ship["allies"] = Spawn ( "script_model", start_point_ally );
			level.orbital_ships.ship["allies"] SetModel ( "vehicle_ac130_coop" );
			level.orbital_ships.ship["allies"].angles += ( 0, 180, 0 );
			level.orbital_ships.ship["allies"] LinkToSynchronizedParent ( level.orbital_ships.cameraView["allies"], "", (0,0,100), (15,0,0) );
			
			level.orbital_ships.ship["axis"] = Spawn ( "script_model", start_point_axis );
			level.orbital_ships.ship["axis"] SetModel ( "vehicle_ac130_coop" );
			level.orbital_ships.ship["axis"].angles += ( 0, 0, 0 );
			level.orbital_ships.ship["axis"] LinkToSynchronizedParent ( level.orbital_ships.cameraView["axis"], "", (0,0,100), (15,0,0) );
			
			level.orbital_ships.script_origin thread rotateOrbitalShips();
						
			break;
	}
	
	thread showDropPodBadSpawnOverlay();
	thread spawnPlayerInOrbital();
}


//==============================================================================
monitorTrackSwitching() // self == level.orbital_ships.cameraView[]
//==============================================================================
{
	level endon( "game_ended" );
	
//	level.lowest = 10000;

	self.started_bank = false;
	level.ship_pos_wait_delay = 0.5;
	switch_threshold = 4;	
	
	wait 2;
	
	while( true )
	{
		dist_to_next_track = "none";
		plane_track = self.track;
		
		switch ( plane_track )
		{
			case "right":
				dist_to_next_track = Distance( self.origin, level.left_big_loop_start.origin );
				
				if( dist_to_next_track <= 200 && self.started_bank == false )
				{
					level.ship_pos_wait_delay = 0.05;
				}
				
				if( dist_to_next_track <= switch_threshold )
				{
//					IPrintLnBold( "switching to left_big");
					self unlink();
					self.origin = level.left_big_loop_start.origin;
					self LinkToSynchronizedParent( level.left_big_pivot );
					self.track = "left_big";
					level.ship_pos_wait_delay = 0.5;
				}
				break;

			case "left_big":
				dist_to_next_track = Distance( self.origin, level.left_loop_start.origin );
				
				if( dist_to_next_track <= 200 && self.started_bank == false )
				{
					level.ship_pos_wait_delay = 0.05;
				}
				
				if( dist_to_next_track <= switch_threshold )
				{
//					IPrintLnBold( "switching to left");
					self unlink();
					self.origin = level.left_loop_start.origin;
					self LinkToSynchronizedParent( level.left_pivot );
					self.track = "left";
					level.ship_pos_wait_delay = 0.5;
				}
				break;
				
			case "left":
				dist_to_next_track = Distance( self.origin, level.right_big_loop_start.origin );
				
				if( dist_to_next_track <= 200 && self.started_bank == false )
				{
					level.ship_pos_wait_delay = 0.05;
				}			
				
				if( dist_to_next_track <= switch_threshold )
				{
//					IPrintLnBold( "switching to right_big");
					self unlink();
					self.origin = level.right_big_loop_start.origin;
					self LinkToSynchronizedParent( level.right_big_pivot );
					self.track = "right_big";
					level.ship_pos_wait_delay = 0.5;
				}
				break;
				
			case "right_big":
				dist_to_next_track = Distance( self.origin, level.right_loop_start.origin );
				
				if( dist_to_next_track <= 200 && self.started_bank == false )
				{
					level.ship_pos_wait_delay = 0.05;
				}
				
				if( dist_to_next_track <= switch_threshold )
				{
//					IPrintLnBold( "switching to right");
					self unlink();
					self.origin = level.right_loop_start.origin;
					self LinkToSynchronizedParent( level.right_pivot );
					self.track = "right";
					level.ship_pos_wait_delay = 0.5;
				}
				break;

			default:
				break;
		}
		
		level.distance = dist_to_next_track;
		
//		if( level.distance < level.lowest )
//			level.lowest = level.distance;

		wait level.ship_pos_wait_delay;
	}
}


//==============================================================================
rotateOrbitalShips()
//==============================================================================
{
	level endon( "game_ended" );
	
	while( true )
	{
		self RotateYaw( 3600, 1200 );
		wait 1199;
	}
}


//==============================================================================
rotateOrbitalShipPivots()
//==============================================================================
{
	level endon( "game_ended" );
	
	while( true )
	{
		level.left_pivot RotateYaw( -5400, 1200 );
		level.left_big_pivot RotateYaw( -700, 1200 );
		level.right_pivot RotateYaw( 5400, 1200 );
		level.right_big_pivot RotateYaw( 700, 1200 );
		
		wait 1199;
	}
}


//==============================================================================
spawnPlayerInOrbital()
//==============================================================================
{
	level endon( "game_ended" );
	
	while( true )
	{
		level waittill( "player_spawned", player );
						
		player SetClientOmnvar( "ui_orbital_toggle_hud", 1 );
		player SetClientOmnvar( "ui_orbital_is_dropping", true );
		
		if( !isbot(player) )
		{
			player DisableWeapons();
			player PlayerHide();	
			player HideViewModel();
			player thread setFovScale( 1, 0 );		    
			
			//Showing the dropping player the friendly/enemy drop pods and trophies, friendly/enemy players.
			player.isdropping = true;
			
			player thread showDropPodFX();
//			player thread showDropPodBadSpawnOverlay();
			
			player thread playerInOrbital();
			player thread waitForSpawnFinished();
		}
	}
}

//==============================================================================
showDropPodFX() // self == player
//==============================================================================
{
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );

	while( true )
	{
		hidePodFx();

		foreach( player in level.players )
		{
			if( IsDefined( player.isdropping ) )
			{
				if( player.isdropping == true )
					player showPodDroppingFXToPlayer();
				else
					player showPodGroundFXToPlayer();
			}
		}
		
		wait(0.05);
	}
}


//================================================================================
hidePodFx()
//================================================================================
{
	foreach ( player in level.players )
	{
		if( IsDefined( player.drop_pod ) )
		{
			if( isdefined( player.drop_pod.trophyFX_friendly ) )
				player.drop_pod.trophyFX_friendly hide();
		
			if( isdefined( player.drop_pod.trophyFX_enemy ) )
				player.drop_pod.trophyFX_enemy hide();
			
			if( isdefined( player.drop_pod.trophyFX_ground_friendly ) )
				player.drop_pod.trophyFX_ground_friendly hide();
		
			if( isdefined( player.drop_pod.trophyFX_ground_enemy ) )
				player.drop_pod.trophyFX_ground_enemy hide();			
		}
	}
}


//================================================================================
showPodDroppingFXToPlayer()
//================================================================================
{
	foreach ( player in level.players )
	{
		if( IsDefined( player.drop_pod ) )
		{
			if( player.team == self.team )
				if( isdefined( player.drop_pod.trophyFX_friendly ) )
					player.drop_pod.trophyFX_friendly ShowToPlayer( self );
		
			if( !( player.team == self.team ) )
				if( isdefined( player.drop_pod.trophyFX_enemy ) )
					player.drop_pod.trophyFX_enemy ShowToPlayer( self );
		}
	}
}


//================================================================================
showPodGroundFXToPlayer()
//================================================================================
{
	foreach ( player in level.players )
	{
		if( IsDefined( player.drop_pod ) )
		{
			if( player.team == self.team )
				if( isdefined( player.drop_pod.trophyFX_ground_friendly ) )
					player.drop_pod.trophyFX_ground_friendly ShowToPlayer( self );
		
			if( !( player.team == self.team ) )
				if( isdefined( player.drop_pod.trophyFX_ground_enemy ) )
					player.drop_pod.trophyFX_ground_enemy ShowToPlayer( self );
		}
	}
}


//==============================================================================
waitForSpawnFinished() // Self == player
//==============================================================================
{
	level endon( "game_ended" );
	self endon( "disconnect" );
	
	self waittill_any( "player_drop_pod_spawned", "player_spawned_at_drop_pod" );
	
	self.isdropping = false;
	self thread setOrbitalView( "off", 0 );
	
	thread hideOverlays();
	self thread destroyPlayerIcons();

}


//==============================================================================
playerInOrbital()
//==============================================================================
{
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "joined_spectators" );
	level endon( "game_ended" );

	//The player has just (re)spawned and must decide how to respawn.

	if ( !IsBot(self) )
	{
		if (!IsDefined(self.prematch_over))
		{
			self.prematch_over = false;
		}
		if (!IsDefined(self.respawn_mode))
		{
			self.respawn_mode = 0;
		}
		if (!IsDefined(self.mode_button_released))
		{
			self.mode_button_released = 0;
		}
		
		self.spawn_button_released = 0;
		self.is_linked_to_pod = false;
		self.is_linked_to_ship = false;
	
		
		if(self.prematch_over == false)
		{
			//Disable the player's weapons so he/she can't shoot from AC-130 view during the prematch countdown.
			self DisableWeapons();
			self HideViewModel();
			
			if (!self IsLinked())
			{
				//Linking the player to the AC-130 during the prematch countdown.
				self linkPlayerOrbitalShip();
			}
		}
		
		//Waiting until after the prematch countdown.
		gameFlagWait( "prematch_done" );
		
		self.prematch_over = true;
		
		//Disable the player's weapons so he/she can't shoot after the prematch countdown (we need to call DisableWeapons() again because the end of the prematch enables weapons).
		self DisableWeapons();
		self HideViewModel();
		
		//Start the force respawn timer.
		self.forcerespawn_timer = level.forcerespawn_time;
		timer_time = ( level.forcerespawn_time * 1000.0 ) + GetTime();
		
		self SetClientOmnvar( "ui_orbital_toggle_color", 0 );
		self SetClientOmnvar( "ui_orbital_timer_time", timer_time );
		
		self thread dropPodForceRespawn();
		self.forcerespawn = false;		
		
		// Default to spawn from drop pod if it exists
		if(IsDefined(self.drop_pod) && self.drop_pod.destroyed == false)
	   	{
		   	self.respawn_mode = 1;
	   	}
		
		//If the player is not a bot, wait for the player's input to decide whether to respawn at last drop pod (if available) or relaunch drop pod.
		while (1)
		{
			//Link the player view to their drop pod.
			if (IsDefined(self.drop_pod) && self.drop_pod.destroyed == false && self.respawn_mode == 1)
			{
				if (self.is_linked_to_pod == false)
				{
					//If the player is linked to something, unlink. You have to unlink the player before linking the player to something else.
					if (self IsLinked())
					{
						self Unlink();
					}
					self linkPlayerPod();
				}
			}
			//Link the player view to the AC-130 if they don't have a drop pod on the ground.
			if (!IsDefined(self.drop_pod) || self.drop_pod.destroyed == true || self.respawn_mode == 0)
			{
				if (self.is_linked_to_ship == false)
				{
					//If the player is linked to something, unlink. You have to unlink the player before linking the player to something else.
					if (self IsLinked())
					{
						self Unlink();
					}
					self linkPlayerOrbitalShip();
				}
			}
			
			//Check whether the mode-switching button has been released - we only want to register discrete button pushes when switching between Respawn Modes.
			if (!self AdsButtonPressed())
			{
				self.mode_button_released = 1;
			}
			//Check whether the drop pod launching button has been released - we only want to register discrete button pushes. We don't want players to launch by holding down the button.
			if (!self AttackButtonPressed())
			{
				self.spawn_button_released = 1;
			}
			
			//Forcing a respawn from the AC-130. Link the player view to the AC-130 and launch a new drop pod.
			if (self AdsButtonPressed() && self.mode_button_released == 1)
			{
				self.mode_button_released = 0;							
				
				if (self.respawn_mode == 0 && IsDefined(self.drop_pod) && self.drop_pod.destroyed == false)
				{
					//Drop Pod view.
					self.respawn_mode = 1;
					if (self.is_linked_to_pod == false)
					{
						//If the player is linked to something, unlink. You have to unlink the player before linking the player to something else.
						if (self IsLinked())
						{
							self Unlink();
						}
						self linkPlayerPod();
					}
				}
				else if (self.respawn_mode == 1)
				{
					//AC-130 view.
					self.respawn_mode = 0;
					if (self.is_linked_to_ship == false)
					{
						//If the player is linked to something, unlink. You have to unlink the player before linking the player to something else.
						if (self IsLinked())
						{
							self Unlink();
						}
						self linkPlayerOrbitalShip();
					}
				}
			}
			else if ((self AttackButtonPressed() && self.spawn_button_released == 1) || self.forcerespawn)
			{
				self.spawn_button_released = 0;
				
				//Respawn at existing drop pod.
				if (IsDefined(self.drop_pod) && self.drop_pod.destroyed == false && self.respawn_mode == 1 && self.is_linked_to_pod == true)
				{
					
					if( IsDefined( self.drop_pod ) )
					{
						if( isdefined( self.drop_pod.spawn_fx ) )
							self.drop_pod.spawn_fx delete();
					}
					
					player_viewangles = self GetPlayerAngles();
					//Unlink from drop pod view.
					self Unlink();
					
					//turn off the enemy trophy fx
					self notify( "player_spawned_at_drop_pod" );
					self thread setOrbitalView( "off", 0 );
					
					self SetPlayerAngles( player_viewangles );
					self SetOrigin( self.drop_pod.origin );
					self EnableWeapons();
					self playerShow();
					self ShowViewModel();
					
					return;
				}
					
				//Launch a new drop pod.
				else if( self.respawn_mode == 0 && self.is_linked_to_ship == true )
				{
					nearest_node = _fire( self.lifeId, self  );

					//turn off the enemy trophy fx
//					self notify( "player_drop_pod_spawned" );
					
					return;
				}
			}
			wait(0.05);
		}
	}
	else
	{
		self linkPlayerOrbitalShip();
		
		//This player is a bot, so just launch a new drop pod for him, as usual.
		nearest_node = _fire( self.lifeId, self  );
		
		if( isdefined( nearest_node ) )
		{
			//Teleporting the player to the nearest path node.
			self setOrigin( nearest_node.origin );
			
			//Create a new drop pod and placing it at the nearest path node.
			self createPlayerDropPod(nearest_node.origin);

			self.drop_pod thread drop_pod_handleDeath();
			
			wait 0.05;
		}
	}
}


//================================================================================
linkPlayerPod() // self == player
//================================================================================
{
	self.is_linked_to_pod = true;
	self.is_linked_to_ship = false;
	self.isdropping = false;
	
	self destroyPlayerIcons();
	self showPlayerIcons( "friendly" );
	
	self notify( "switched_to_pod_view" );
	
//	hideOverlays();
	
	self thread setOrbitalView( "pod", 0 );
	
	self DontInterpolate();
	self PlayerLinkTo( self.drop_pod.camera, "tag_player", 0 );
	
	self.drop_pod.spawn_fx = SpawnFx( level.drop_pod_effect["player_spawn_from_pod"], self.drop_pod.origin, self.drop_pod.forward );
	TriggerFX( self.drop_pod.spawn_fx );
								   
	self thread centerPodSpawnView();
}


//================================================================================
linkPlayerOrbitalShip() // self == player
//================================================================================
{
	self.is_linked_to_pod = false;
	self.is_linked_to_ship = true;
	self.isdropping = true;
	
	self destroyPlayerIcons();
	self thread showPlayerIcons( "both" );
		
	if( !IsDefined( self.is_first_drop ) )
		self.is_first_drop = false;
	else
		self thread leaderDialogOnPlayer( "orbital_dropin", undefined, undefined, self.origin );
	
	if( IsDefined( self.drop_pod ) )
	{
		self SetClientOmnvar( "ui_orbital_toggle_switch", 0 );
		
		if( isdefined( self.drop_pod.spawn_fx ) )
			self.drop_pod.spawn_fx delete();
	}
	else
	{
		self SetClientOmnvar( "ui_orbital_toggle_switch", 1 );
	}
	
	static_length = 0.3;
	self thread setOrbitalView( "ship", 0 );
	
	current_level = GetDvar( "mapname" );

	self DontInterpolate();
	switch ( current_level )
	{
		case "mp_refraction":
			self PlayerLinkTo( level.orbital_ships.cameraView[self.pers["team"]], "tag_player", 0, 180, 180, -40, 80, false );
			break;
		default:
			self PlayerLinkTo( level.orbital_ships.cameraView[self.pers["team"]], "tag_player", 1, 90, 90, -50, 80, false );
			break;	
	}
	
	self thread centerOrbitalView();
	
	self SetClientOmnvar( "ui_orbital_collision_warn", 0 );
	self thread traceCollisionWarn();
	
}


//================================================================================
unlinkPlayer()
//================================================================================
{
	self DontInterpolate();
	self ControlsUnlink();
	self CameraUnlink();
	self unlink();
	
	self FreezeControls( true );
	self EnableWeapons();
	self ShowViewModel();
//	hideOverlays();
}


//================================================================================
centerOrbitalView()
//================================================================================
{
	startPos = level.orbital_ships.cameraView[self.pers["team"]].origin;
	endPos = level.orbital_ships.missileSpawn["target"].origin;
	angles = VectorToAngles( endPos - startPos );
	
	self SetPlayerAngles( angles );	
}


//================================================================================
centerPodSpawnView()
//================================================================================
{
	startPos = self.drop_pod.camera.origin;
	endPos = level.orbital_ships.missileSpawn["target"].origin;
	angles = VectorToAngles( endPos - startPos );
	angles *= ( 0, 1, 0 );
	
	self SetPlayerAngles( angles );
}


//================================================================================
setOrbitalView( view, wait_delay )
//================================================================================
{
	self SetClientOmnvar( "ui_orbital_toggle_ship_view", 2 );
	self SetClientOmnvar( "ui_orbital_toggle_pod_view", 2 );
	self SetClientOmnvar( "ui_orbital_toggle_drop_view", 2 );
	
	wait( wait_delay );
	
	switch( view )
	{
		case "ship":
			self SetClientOmnvar( "ui_orbital_toggle_ship_view", 1 );
			break;
	
		case "pod":
			self SetClientOmnvar( "ui_orbital_collision_warn", 0 );
			self SetClientOmnvar( "ui_orbital_toggle_pod_view", 1 );
			break;

		case "drop":
			self SetClientOmnvar( "ui_orbital_toggle_drop_view", 1 );
			break;
			
		case "off":
			self SetClientOmnvar( "ui_orbital_is_dropping", false );
			
			break;			
		
		default:
			break;
	}
}


//================================================================================
traceCollisionWarn()
//================================================================================
{
	self endon( "player_drop_pod_spawned" );
	self endon( "disconnect" );
	self endon( "player_spawned_at_drop_pod" );
	self endon( "joined_team" );
	self endon( "death" );
	self endon( "switched_to_pod_view" );
	
	while ( true )
	{	
		angles = self GetPlayerAngles();
		start = self GetEye() + ( AnglesToForward( angles ) * 20 );
		end = start + ( AnglesToForward( angles ) * 30000 );
		
		trace = PlayerPhysicsTraceInfo( start, end );
		trace["position"] += (0,0,10);
		level.trace = trace;
		
		if( IsDefined( trace["position"] ) )
		{
			location = trace["position"];
			precision_spawn_good = false;
			temp_origin = Spawn( "script_origin", location );
			temp_origin.targetname = "orbital_trace_position";
		
			foreach( trigger in level.drop_pod_volume_array )
			{
				is_touching = temp_origin IsTouching( trigger );
				can_spawn = CanSpawn( location );
				
				if( is_touching && can_spawn )
				{
					precision_spawn_good = true;
					break;
				}
			}
			temp_origin delete();
			
			if( precision_spawn_good == true )
				self SetClientOmnvar( "ui_orbital_collision_warn", 0 );
			else
				self SetClientOmnvar( "ui_orbital_collision_warn", 1 );
		}
		wait 0.15;
	}
}


//================================================================================
_fire( lifeId, player )
//================================================================================
{
	player endon( "death" );
	
	static_length = 0.3;
	player thread setOrbitalView( "drop", 0 );
	thread setFovScale( 4.333, 0.1 );
	
	player destroyPlayerIcons();
	player showPlayerIcons( "friendly" );
	
	//Firing the MagicBullet from the AC-130
	if ( !IsBot(player) )
	{
		player.orbital_location = player GetEye();
		player.orbital_viewangles = player GetPlayerAngles();
		player.orbital_forward = AnglesToForward(player.orbital_viewangles);
		player.orbital_endpoint = player.orbital_location + player.orbital_forward * 5000;
		rocket = MagicBullet( "orbital_drop_pod_mp", player.orbital_location, self.orbital_endpoint, player );
		rocket thread aud_drop_pod_fire( player );
		rocket thread aud_play_rocket_travel_loops( player );
	}
	else
	{		
		player.orbital_location = level.orbital_ships.cameraView[self.pers["team"]].origin;
		startPos = level.orbital_ships.cameraView[self.pers["team"]].origin;
		endPos = level.orbital_ships.missileSpawn["target"].origin;
		player.orbital_viewangles = VectorToAngles( endPos - startPos );
		player.orbital_forward = AnglesToForward(player.orbital_viewangles);
		player.orbital_endpoint = startPos + player.orbital_forward * 5000;		
		rocket = MagicBullet( "orbital_drop_pod_mp", startPos, self.orbital_endpoint, player );
		rocket thread aud_drop_pod_fire( player );
		rocket thread aud_play_rocket_travel_loops( player );
	}

	PlayFX( level.drop_pod_effect["drop_pod_fire_flash"], player.orbital_location, player.orbital_forward );

	// Delete the player's existing drop pod if he/she has one already.
	self thread destroyPlayerDropPod();
	
	self notify( "drop_pod_spawned" );

	if ( !IsDefined( rocket ) )
		return;

	rocket.trigger = spawn( "trigger_radius", rocket.origin, 0, 128, 256);

	if (player IsLinked())
	{
		player Unlink();
		player DontInterpolate();
		player PlayerLinkTo(rocket);
	}
		
	rocket.owner = player;
	rocket.lifeId = lifeId;
	rocket.type = "orbital_drop_pod_mp";
	rocket.team = player.team;
	level.remoteMissileInProgress = true;
	rocket thread createKillCamEntity();
	player.rocket = rocket;
	
	wait 0.1;
	
	nearest_node = MissileEyes( player, rocket );	
//	rocket thread removeKillCamEntity();
	
	return nearest_node;
}

//================================================================================
setFovScale( fov_scale, delay )
//================================================================================
{
	//default viewmodel FOV = 65, default missile FOV = 15
	if( IsDefined( delay ) )
		wait delay;

	self setclientdvar( "cg_fovScale", fov_scale );
}


//================================================================================
MissileEyes( player, rocket )
//================================================================================
{
	player endon ( "joined_team" );
	player endon ( "joined_spectators" );
	player endon ( "death" );

	rocket thread Rocket_CleanupOnDeath();
	player thread Player_CleanupOnGameEnded( rocket );
	player thread Player_CleanupOnTeamChange( rocket );
	rocket thread waitForRocketImpact( player );
	rocket thread waitForRocketDeath( player );
	
	current_level = getDvar( "mapname" );
	player VisionSetMissilecamForPlayer( current_level, 0 );

	player endon ( "disconnect" );
	
	player.spawn_was_good = false;
	nearest_node = undefined;
	direction = (0,0,0);
	
	if( isDefined( rocket ) )
	{
		player CameraLinkTo( rocket, "tag_origin" );
		player ControlsLinkTo( rocket );
		
		rocket thread trackRocket( player );
		rocket thread dropPodTrophySystem();

		if( getDvarInt( "camera_thirdPerson" ) )
			player setThirdPersonDOF( false );
		
		//TODO: HANDLE DEATH, and ROCKET DEATH SEPERATLY, need to not check for nodes if trophy death, trophy death also kills player.
		player waittill_any( "rocket_impacted", "rocket_destroyed" );
		
		rocket thread aud_play_pod_impact( player );
		
		//turn off the enemy trophy fx and player marking
		player destroyPlayerIcons();
		
		player notify( "player_drop_pod_spawned" );
		
		player unlinkPlayer();
		
		// If a player gets the final kill with a hellfire, level.gameEnded will already be true at this point
		if ( !level.gameEnded || isDefined( player.finalKill ) )
		{	
			thread setFovScale( 1, 0 );
		}
		
		if ( getDvarInt( "camera_thirdPerson" ) )
			player setThirdPersonDOF( true );
	}
	else
	{
		AssertMsg( "rocket is undefined" );
	}
	
	// Controls are frozen in unlinkPlayer() so that the player will not spawn with the camera already spinning due
	// to the joystick position from controlling the pod. controls unfeeze after the freeze_delay.
	freeze_delay = 0.3;

	// Missed the Drop Pod Volumes but is near a valid pathnode (successful spawn)
	if ( player.spawn_was_good == true && IsDefined( player.nearest_node ) )
	{	
		player createPlayerDropPod( player.nearest_node.origin );
		
		player setOrigin( player.drop_pod.origin );
		player SetPlayerAngles((0, player.angles[1], 0));
		player thread unfreezeControlsDelay( freeze_delay );
		player playerShow();
		
		player.nearest_node = undefined;
		
//		player thread vmLandingImpact();
		player thread dropPodBaseUnfold();
		
		player.drop_pod thread drop_pod_handleDeath();
		player.drop_pod thread aud_drop_pod_land_success( player );
	}
	// Failed Landing/Spawn)
	else
	{
		player SetOrigin( player.impact_info["rocket_position"] );
		player thread dropPodBadSpawnDeathFX();
		player maps\mp\gametypes\_damage::addAttacker( player, player, player.rocket.killCamEnt, "orbital_drop_pod_mp", 999999, (0,0,0), player.origin, "none", 0, "MOD_EXPLOSIVE" );
		player thread unfreezeControlsDelay( freeze_delay );
		thread aud_drop_pod_land_fail( player );
		player thread maps\mp\gametypes\_damage::finishPlayerDamageWrapper( player.rocket.killCamEnt, player, 999999, 0, "MOD_EXPLOSIVE", "orbital_drop_pod_mp", player.origin, player.origin, "none", 0, 0 );	
		player thread leaderDialogOnPlayer( "orbital_notgood_tryhard", undefined, undefined, self.origin );
	}
	
	return nearest_node;
}


//================================================================================
waitForRocketImpact( player )
//================================================================================
{
	level endon( "game_ended" );
	player endon ( "joined_team" );
	player endon ( "joined_spectators" );
	player endon ( "death" );
	
	while( true )
	{
		player waittill( "projectile_impact", weaponName, position, radius, direction );

		if( weaponName == "orbital_drop_pod_mp" )
			break;
	}

	player.spawn_was_good = true;

	player notify( "rocket_impacted" );
}


//================================================================================
waitForRocketDeath( player )
//================================================================================
{
	level endon( "game_ended" );
	player endon ( "joined_team" );
	player endon ( "joined_spectators" );
	player endon ( "death" );
	
	self waittill( "death" );
	
	if( IsDefined( self ) )
		self Delete();
	
	player CameraUnlink();
	player ControlsUnlink();
	player setFovScale( 1, 0 );
	
	player notify( "rocket_destroyed" );	
}


//================================================================================
vmLandingImpact()
//================================================================================
{
	wait( 0.5 );

	self StunPlayer( 0.3 );
}


//================================================================================
dropPodBaseUnfold()
//================================================================================
{
	wait( level.drop_pod.deploy_delay - 1 );
	self.drop_pod thread dropPodSpikeImpacts();
	self.drop_pod_enemy_model thread dropPodSpikeImpacts();
	
	//this is used to because if the anim is only client side we can't shoot traces off the aligned spikes to get impact fx
	//this could be optimizated later if we find a client side way to do this.
	self.drop_pod ScriptModelPlayAnimDeltaMotion( "mp_orbital_pod_base_unfold" );
	self.drop_pod_enemy_model ScriptModelPlayAnimDeltaMotion( "mp_orbital_pod_base_unfold" );
	
}

//================================================================================
dropPodSpikeImpacts()
//================================================================================
{
	wait 0.68;
	
	spikeLength = 2;
	spikeOrg = [];
	spikeAngles = [];

	spikeOrg[0] = self GetTagOrigin("J_spike_FL");
	spikeAngles[0] = self GetTagAngles("J_spike_FL");
	
	spikeOrg[1] = self GetTagOrigin("J_spike_BL");
	spikeAngles[1] = self GetTagAngles("J_spike_BL");
	
	spikeOrg[2] = self GetTagOrigin("J_spike_BR");
	spikeAngles[2] = self GetTagAngles("J_spike_BR");
	
	spikeOrg[3] = self GetTagOrigin("J_spike_FR");
	spikeAngles[3] = self GetTagAngles("J_spike_FR");
	
	for( x=0; x < spikeOrg.size; x++ )
	{
		start = spikeOrg[x] - ( 8 * anglestoforward( spikeAngles[x] ) );
		end = spikeOrg[x] + ( spikeLength * anglestoforward( spikeAngles[x] ) );
		trace = BulletTrace(start, end, false, self);
		if ( isDefined( trace["position"] ) )
			playfx(	level.drop_pod_effect["drop_pod_spike_impact"], trace["position"], AnglesToForward( (270, 0, 0) ) );
	}
}
	
//================================================================================
trackRocket( player ) // self == rocket
//================================================================================
{
	//Endon the rocket's death.
	self endon("death");
	self.owner endon( "disconnect" );
	self.owner endon( "joined_team" );
	self.owner endon( "joined_spectators" );
	
	while( true )
	{
		player.impact_info["rocket_position"] = self.origin;
		start = self.origin;
		direction = self.angles;
		forward = AnglesToForward( direction );
		end = start + ( forward * 512 );
		
		trace = PlayerPhysicsTraceInfo( start, end );
		
		self.trigger DontInterpolate();
		self.trigger.origin = trace["position"] + (0,0,-128);
//		thread drawSphere( self.trigger.origin, 16, 30, (0,0,1) );
		
		nearest_node = self.trigger thread getNearestPathNode();
		if( IsDefined( nearest_node ) )
		{
//			thread drawSphere( nearest_node.origin, 16, 30, (1,0,0) );
//			thread drawSphere( self.trigger.origin, 16, 30, (0,1,0) );
			self.owner.nearest_node = nearest_node;
			self hide();

			playFXOnTag( level.drop_pod_effect["decel_explosion"], self, "tag_origin" );
			start = self.origin;
			end = nearest_node.origin;
			direction = VectorToAngles( end - start );
			
			self.angles = direction;
			
			self.trigger delete();
			break;
		}
		
		wait( 0.05 );
	}
}


//================================================================================
unfreezeControlsDelay( delay )
//================================================================================
{
	wait delay;
	self FreezeControls( false );
}


//================================================================================
dropPodBadSpawnDeathFX()
//================================================================================
{
	self endon( "disconnect" );

	self waittill( "death" );
	
	PlayFX( level.drop_pod_effect["drop_pod_explode"], self.origin + ( 0, 0, 10 ) );
}


//================================================================================
getNearestPathNode() // self == trigger
//================================================================================
{
	nodes = GetNodesInTrigger( self );
	
	if( isdefined( nodes ) && nodes.size > 0 )
	{
		closest_node = 0;
		temp_dist = DistanceSquared( self.origin, nodes[0].origin );
		for( i = 0; i < nodes.size; i++ )
		{
			switch ( nodes[i].type )
			{
				case "End":
				case "Begin":
				case "Cover Stand":
				case "Cover Left":
				case "Cover Right":
					nodes[i] = undefined;
					continue;
			
				default:
					break;
			}
			
			if( IsDefined( nodes[i].script_noteworthy ) )
			{
				if( nodes[i].script_noteworthy == "orbital_no_spawn" )
				{
					nodes[i] = undefined;
					continue;
				}
			}
			
			check_dist = DistanceSquared( self.origin, nodes[i].origin );
			if (check_dist < temp_dist)
			{
				temp_dist = check_dist;
				closest_node = i;
			}
		}
		return nodes[closest_node];
	}
	else
	{
		return undefined;
	}
}


//================================================================================
Rocket_CleanupOnDeath()
//================================================================================
{
	entityNumber = self getEntityNumber();
	level.rockets[ entityNumber ] = self;
	self waittill( "death" );	
	
	level.rockets[ entityNumber ] = undefined;
	
	level.remoteMissileInProgress = undefined;
}


//================================================================================
Player_CleanupOnGameEnded( rocket )
//================================================================================
{
	rocket endon( "death" );
	self endon( "death" );
	
	level waittill( "game_ended" );
	
	self ControlsUnlink();
	self CameraUnlink();

	if ( getDvarInt( "camera_thirdPerson" ) )
		self setThirdPersonDOF( true );
}


//================================================================================
Player_CleanupOnTeamChange( rocket )
//================================================================================
{
	rocket endon( "death" );
	self endon( "disconnect" );

	self waittill_any( "joined_team" , "joined_spectators" );

	if( self.team != "spectator" )
	{
		self ControlsUnlink();
		self CameraUnlink();

		if( getDvarInt( "camera_thirdPerson" ) )
			self setThirdPersonDOF( true );
	}
	
	self setFovScale( 1, 0 );
	
	level.remoteMissileInProgress = undefined;
}


//================================================================================
dropPod_CleanupOnTeamChange()
//================================================================================
{
	self.drop_pod endon( "death" );
	self waittill_any( "joined_team" , "joined_spectators" );

	self deletePlayerDropPod();
}


//================================================================================
dropPod_CleanupOnDisconnect()
//================================================================================
{
	self.drop_pod endon( "death" );
	self waittill( "disconnect" );

	self deletePlayerDropPod();
}


//================================================================================
createPlayerDropPod( coords ) // self == player
//================================================================================
{
	// Delete the player's existing drop pod if he/she has one already.
	self deletePlayerDropPod();
	
	// Creates a new drop pod for the player.
	if (!IsDefined(coords))
		AssertMsg( "createPlayerDropPod -> coords undefined!" );
	
	traceStart = coords + (0,0,32);
	traceEnd = coords + (0,0,-1024);
	trace = PlayerPhysicsTraceInfo( traceStart, traceEnd );
	location = trace["position"];
	upangles = vectorToAngles( trace["normal"] );
	forward = AnglesToForward( upangles );
	upangles += (180, 0, 0);
	
	playFx( level.drop_pod_effect["landing_impact"], location, trace["normal"] );
	self.drop_pod = spawn( "script_model", location );
	self.drop_pod.angles = upangles;
	self.drop_pod.forward = forward;
	self.drop_pod SetModel( level.drop_pod.model );
	self.drop_pod Solid();
	self.drop_pod SetCanDamage( true );
	self.drop_pod SetCanRadiusDamage( true );
	self.drop_pod.hidden = false;
	self.drop_pod.owner = self;
	self.drop_pod.destroyed = false;
	self.drop_pod.health = 999999;	//keep it from dying anywhere in code (see drop_pod_handleDamage())
	self.drop_pod.maxHealth = 100;	//this is the health we'll check (see drop_pod_handleDamage())
	self.drop_pod.damageTaken = 0;	//how much damage has it taken
	self.drop_pod Hide();
	
	self.drop_pod_enemy_model = spawn( "script_model", self.drop_pod.origin );
	self.drop_pod_enemy_model SetModel( level.drop_pod.enemy_model );
	self.drop_pod_enemy_model.angles = self.drop_pod.angles;
	self.drop_pod_enemy_model.owner = self;
	self.drop_pod_enemy_model Hide();
	self.drop_pod_enemy_model NotSolid();
	
	foreach ( player in level.players )
	{
		if( player.team == self.team )
			self.drop_pod ShowToPlayer( player );
		else
			self.drop_pod_enemy_model ShowToPlayer( player );
	}	
	
	self.drop_pod thread aud_setup_drop_pod_loop();
	
	self.drop_pod.camera = spawn( "script_model", self.drop_pod.origin );
	self.drop_pod.camera SetModel( "tag_player" );
	self.drop_pod.camera.angles = ( 0, 0, 0 );
	self.drop_pod.camera hide();
	
	self.isdropping = false;
	
	self.drop_pod thread PodSetupTrophyFX( self );
//	self.drop_pod hideOverlays();
	
	self thread dropPod_CleanupOnDisconnect();
	self thread dropPod_CleanupOnTeamChange();
}


//================================================================================
destroyPlayerDropPod() // self == player
//================================================================================
{
	// this handles cases of deletion
	if ( !isDefined( self.drop_pod ) )
		return;
	
	self endon( "player_drop_pod_spawned" );
	
	drop_pod = self.drop_pod;
	pod_destroyed = level.drop_pod_effect["pod_base_destroyed"];
	dome_shutdown_friendly = level.drop_pod_effect["dome_shutdown_friendly"];
	dome_shutdown_enemy = level.drop_pod_effect["dome_shutdown_enemy"];

	playFX( pod_destroyed, drop_pod.origin, drop_pod.forward );
	drop_pod Hide();
	self.drop_pod_enemy_model Hide();
	
	drop_pod.shutdown_fx_friendly = SpawnFx( dome_shutdown_friendly, drop_pod.origin, drop_pod.forward );
	drop_pod.shutdown_fx_enemy = SpawnFx( dome_shutdown_enemy, drop_pod.origin, drop_pod.forward );
	TriggerFX( drop_pod.shutdown_fx_friendly );
	drop_pod.shutdown_fx_friendly Hide();
	TriggerFX( drop_pod.shutdown_fx_enemy );
	drop_pod.shutdown_fx_enemy Hide();
	
	drop_pod thread aud_destroy_deployed_pod();	
	
	foreach( player in level.players )
	{
		if( player.team == self.team )
			drop_pod.shutdown_fx_friendly ShowToPlayer( player );
		else
			drop_pod.shutdown_fx_enemy ShowToPlayer( player );
	}
		
	wait( 0.7 );
		
	self deletePlayerDropPod();
}


//================================================================================
deletePlayerDropPod()
//================================================================================
{
	//Deletes the player's drop pod if it exists, along with any of the child entities.
	if( IsDefined( self.drop_pod_enemy_model ) )
	   self.drop_pod_enemy_model Delete();
	
	if( IsDefined( self.drop_pod ) )
	{		
		self deletePlayerDropPodVFX();
			
		if( IsDefined( self.drop_pod.camera ) )
			self.drop_pod.camera Delete();

		self.drop_pod Delete();
	}
}


//================================================================================
deletePlayerDropPodVFX()
//================================================================================
{
	//Deletes the player's drop pod VFX if they exist
	if (IsDefined(self.drop_pod))
	{		
		if( IsDefined( self.drop_pod.trophyFX_friendly ) )
			self.drop_pod.trophyFX_friendly delete();
		
		if( IsDefined( self.drop_pod.trophyFX_enemy ) )
			self.drop_pod.trophyFX_enemy delete();
		
		if( IsDefined( self.drop_pod.trophyFX_ground_friendly ) )
			self.drop_pod.trophyFX_ground_friendly delete();
		
		if( IsDefined( self.drop_pod.trophyFX_ground_enemy ) )
			self.drop_pod.trophyFX_ground_enemy delete();
		
		if( IsDefined( self.drop_pod.shutdown_fx_enemy ) )
			self.drop_pod.shutdown_fx_enemy delete();
		
		if( IsDefined( self.drop_pod.shutdown_fx_enemy ) )
			self.drop_pod.shutdown_fx_enemy delete();
		
		if( isdefined( self.drop_pod.spawn_fx ) )
			self.drop_pod.spawn_fx delete();
	}
}


//=======================================================
//				createKillCamEntity
//=======================================================
createKillCamEntity()
{		
	//killCamOffset = VectorNormalize(self.owner.orbital_endpoint - self.owner.orbital_location) * -200;
	
	killCamOffset = (-512,0,128);
	
	self.killCamEnt = Spawn( "script_model", self.origin );
	self.killCamEnt SetScriptMoverKillCam( "explosive" );
	self.killCamEnt LinkTo ( self, "tag_origin", killCamOffset, (0,0,0) );
	self.killCamEnt SetContents( 0 );
	self.killCamEnt.startTime = getTime();
	self.killCamEnt.isOrbitalCam = true;
}


//=======================================================
//				removeKillCamEntity
//=======================================================
removeKillCamEntity()
{
	if( IsDefined( self.killCamEnt ) )
	{
		self.killCamEnt delete();	
	}
}


//================================================================================
drop_pod_handleDeath() // self == drop_pod
//================================================================================
{
	entNum = self GetEntityNumber();

	self waittill( "death" );
	
	if( !IsDefined( self ) )
		return;
	
	self.owner thread leaderDialogOnPlayer( "orbital_pod_destroyed_enemy", undefined, undefined, self.owner.origin );
	self.owner destroyPlayerDropPod();
}


//================================================================================
dropPodTrophySystem() // self == rocket
//================================================================================
{
	self endon("death");
	self.owner endon( "disconnect" );
	self.owner endon ( "joined_team" );
	self.owner endon ( "joined_spectators" );
	
	while ( IsDefined( self ) )
	{
		foreach (player in level.players)
		{
			if ( player.team != self.owner.team )
			{
				if ( IsDefined( player.drop_pod ) )
				{
					if ( DistanceSquared( self.origin, player.drop_pod.origin ) < 40000 && self.owner.health > 0)
					{
						player.drop_pod thread dropPodTrophyKill( self, player );
					}
				}
			}
		}
				
		foreach ( trophy in level.trophies )
		{
			if( IsDefined( trophy ) )
			{
				if ( DistanceSquared( self.origin, trophy.origin ) < 40000 && trophy.owner.health > 0)
				{
					trophy thread dropPodTrophyKill( self, trophy.owner );
					
					trophy.ammo--;
					if( trophy.ammo <= 0 )
						trophy thread maps\mp\gametypes\_equipment::trophyBreak();
				}
			}
		}
		
		wait(0.05);
	}
}


//================================================================================
dropPodTrophyKill( grenade, owner )
//================================================================================
{
	grenade notify( "destroyed" );
	playFX( level.sentry_fire, self.origin + (0,0,0) , ( grenade.origin - self.origin ), AnglesToUp( self.angles ) );
	self playSound( "trophy_detect_projectile" );
	
	// do a little extra if this was a predator missile or reaper missile
	if( ( IsDefined( grenade.classname ) && grenade.classname == "rocket" ) &&
		( IsDefined( grenade.type ) && (grenade.type == "remote") ) )
	{
		if( IsDefined( grenade.type ) && grenade.type == "remote" )
		{
			// show that you destroyed a killstreak and give the streak point
			level thread maps\mp\gametypes\_missions::vehicleKilled( grenade.owner, owner, undefined, owner, undefined, "MOD_EXPLOSIVE", "trophy_mp" );
			level thread teamPlayerCardSplash( "callout_destroyed_predator_missile", owner );	
			level thread maps\mp\gametypes\_rank::awardGameEvent( "kill", owner, "trophy_mp", undefined, "MOD_EXPLOSIVE" );				
		}

		// play sound
		self thread aud_drop_pod_trophy_kill();	
	}
	
	owner thread projectileExplode( grenade, self );
//	owner maps\mp\gametypes\_missions::processChallenge( "ch_noboomforyou" );
}


//================================================================================
projectileExplode( projectile, trophy )
//================================================================================
{
	projPosition = projectile.origin;
	projType = projectile.model;
	projAngles = projectile.angles;
	proj_owner = projectile.owner;
	trophy_owner = trophy.owner;
	drop_pod = trophy_owner.drop_pod;
	
	dome_flash = level.drop_pod_effect["dome_impact_flash"];
	dome_impact = level.drop_pod_effect["dome_impact"];
	start = trophy.origin;
	end = projPosition;
	fx_angles = VectorToAngles( end - start );
	fx_forward = AnglesToForward( fx_angles );
	fx_up = AnglesToUp( fx_angles );
	
	playFX( dome_impact, projPosition, fx_forward, fx_up );
	PlayFXOnTag( dome_flash, drop_pod, "tag_origin" );
	
	waittillframeend;
	
	if(proj_owner.health <= 0)
		return;
	
	proj_owner thread setFovScale( 1, 0 );
	proj_owner unlink();
	proj_owner CameraUnlink();
	proj_owner setOrigin( projPosition );
	
	proj_owner maps\mp\gametypes\_damage::addAttacker( proj_owner, proj_owner, proj_owner.rocket.killCamEnt, "orbital_drop_pod_mp", 999999, (0,0,0), proj_owner.origin, "none", 0, "MOD_EXPLOSIVE" );
	proj_owner thread maps\mp\gametypes\_damage::finishPlayerDamageWrapper( proj_owner.rocket.killCamEnt, proj_owner, 999999, 0, "MOD_EXPLOSIVE", "orbital_drop_pod_mp", proj_owner.origin, proj_owner.origin, "none", 0, 0 );

	if( IsDefined( projectile ) )
		projectile delete();
	
	trophy thread aud_play_trophy_fire();
	RadiusDamage( projPosition, 128, 105, 10, self, "MOD_EXPLOSIVE", "trophy_mp" );

	proj_owner thread leaderDialogOnPlayer( "orbital_pod_destroyed", undefined, undefined, proj_owner.origin );
}


//================================================================================
PodSetupTrophyFX( owner )
//================================================================================
{
	self endon( "death" );
	owner endon( "disconnect" );
	owner endon ( "joined_team" );
	owner endon ( "joined_spectators" );
	
	self.trophyFX_friendly = SpawnFx( level.drop_pod_dome["friendly"], self.origin, self.forward );
	TriggerFx( self.trophyFX_friendly );
	self.trophyFX_friendly hide();
	
	self.trophyFX_enemy = SpawnFx( level.drop_pod_dome["enemy"], self.origin, self.forward );
	TriggerFx( self.trophyFX_enemy );
	self.trophyFX_enemy hide();
	
	wait( level.drop_pod.deploy_delay - 0.5 );
	
	self.trophyFX_ground_friendly = SpawnFx( level.drop_pod_dome_ground["friendly"], self.origin, self.forward );
	TriggerFx( self.trophyFX_ground_friendly );
	
	self.trophyFX_ground_enemy = SpawnFx( level.drop_pod_dome_ground["enemy"], self.origin, self.forward );
	TriggerFx( self.trophyFX_ground_enemy );
	self.trophyFX_ground_enemy hide();
	
	self thread deletePodTrophyFxOnDeath( owner );
	self thread deletePodTrophyFxOnDisconnect( owner );
	self thread deletePodTrophyFXOnTeamChange( owner );
}


//================================================================================
showPlayerIcons( team )
//================================================================================
{
	//End when the rocket crashes down and dies.
	self endon("death");
	
	
	foreach(player in level.players)
	{
		if( player == self || IsDefined( player.isdropping ) )
			continue;
		
		
		switch( team )
		{
			case "friendly":
				
				if( player.team == self.team )
					player maps\mp\_entityheadIcons::setHeadIcon( self, "ac130_hud_friendly_vehicle_target", (0, 0, 0), 4, 4, undefined, undefined, undefined, undefined, undefined, false );
				break;
			
			case "enemy":
				
				if( !( player.team == self.team ) )
					player maps\mp\_entityheadIcons::setHeadIcon( self, "hud_fofbox_hostile", (0, 0, 0), 4, 4, undefined, undefined, undefined, undefined, undefined, false );
				break;
			
			case "both":
				
				if( player.team == self.team )
				{
					player maps\mp\_entityheadIcons::setHeadIcon( self, "ac130_hud_friendly_vehicle_target", (0, 0, 0), 4, 4, undefined, undefined, undefined, undefined, undefined, false );
				}
				else
				{
					// Commenting this line out for now to see how Orbital plays without having the red boxes on enemies while dropping into the map.
					player maps\mp\_entityheadIcons::setHeadIcon( self, "hud_fofbox_hostile", (0, 0, 0), 4, 4, undefined, undefined, undefined, undefined, undefined, false );
				}
				break;
			
			default:
				break;
		}
	}
}


//Borrowed some of this script from _entityheadicons.gsc::setHeadIcon()
//================================================================================
destroyPlayerIcons() // self == player
//================================================================================
{
	level endon( "game_ended" );
	self endon( "disconnect" );
	
	foreach( player in level.players )
	{
		if( IsDefined( player.entityHeadIcons ) )
		{
			if( isDefined( player.entityHeadIcons[ self.guid ] ) )
			{
				player.entityHeadIcons[ self.guid ] destroy();
				player.entityHeadIcons[ self.guid ] = undefined;
			}
		}
	}
}


//================================================================================
showDropPodBadSpawnOverlay()
//================================================================================
{
	level endon( "game_ended" );
//	self endon( "death" );
//	self endon( "player_drop_pod_spawned" );
//	self endon( "player_spawned_at_drop_pod" );

	while( true )
	{
		hideOverlays();
		
		foreach( player in level.players )
		{
			if( IsDefined( player.isdropping ) )
				if( player.isdropping )
					player showOverlaysToPlayer();
		}
		wait(0.05);
	}
}


//================================================================================
showOverlaysToPlayer()
//================================================================================
{
	foreach( overlay in level.drop_pod_bad_spawn_overlay )
	{
		overlay ShowToPlayer( self );		
	}
}


//================================================================================
hideOverlays()
//================================================================================
{
	foreach( overlay in level.drop_pod_bad_spawn_overlay )
	{
		overlay hide();
	}
}


//================================================================================
deletePodTrophyFxOnDeath( owner )
//================================================================================
{
	owner endon( "disconnect" );
	//Wait until the drop pod that this function was called on is dead.
	self waittill( "death" );
	
	self deletePodTrophyFX();
}


//================================================================================
deletePodTrophyFXOnDisconnect( owner )
//================================================================================
{
	self endon( "death" );
	owner waittill( "disconnect" );
	
	self deletePodTrophyFX();
}


//================================================================================
deletePodTrophyFXOnTeamChange( owner )
//================================================================================
{
	self endon( "death" );
	//owner endon( "disconnect" );
	owner waittill_any( "joined_team" , "joined_spectators" );
	
	self deletePodTrophyFX();
}


//================================================================================
deletePodTrophyFX()
//================================================================================
{
	if( isdefined( self.trophyFX_friendly ) )
		self.trophyFX_friendly delete();
	
	if( isdefined( self.trophyFx_enemy ) )
		self.trophyFx_enemy delete();
}


//================================================================================
dropPodForceRespawn()
//================================================================================
{
	self endon( "death" );
	self endon( "disconnect" );
	self endon( "joined_team" );
	self endon( "joined_spectators" );
	self endon( "player_drop_pod_spawned" );
	self endon( "player_spawned_at_drop_pod" );
	level endon( "game_ended" );
	self.forcerespawn = false;
	
	if (!IsDefined(self.forcerespawn_timer))
	{
		self.forcerespawn_timer = level.forcerespawn_time;
	}
	
	while (self.forcerespawn_timer > 0)
	{
		if( self.forcerespawn_timer <= 5 )
			self SetClientOmnvar( "ui_orbital_toggle_color", 1 );
		
		self.forcerespawn_timer--;
		wait(1);
	}
	self.forcerespawn = true;
}


//================================================================================
//								AUDIO
//================================================================================
aud_play_rocket_travel_loops( player )
{
	rocket = self;
	thread snd_play_linked_loop( "orbital_drop_pod_proj", rocket );	
}

aud_play_pod_impact( player )
{
	// Handled in GDT.
	rocket = self;
}

aud_drop_pod_fire( player )
{
	rocket = self;
	player playlocalsound( "orbital_drop_pod_fire_plr" ); 
}

aud_drop_pod_land_success( player )
{
	drop_pod = self;
	thread snd_play_linked( "orbital_drop_pod_impact", drop_pod );
	player playlocalsound( "orbital_drop_pod_impact" ); 
}

aud_drop_pod_land_fail( player )
{
	drop_pod = self;
	thread snd_play_linked( "orbital_drop_pod_impact", drop_pod );
	player playlocalsound( "orbital_drop_pod_impact" ); 	
}

aud_destroy_deployed_pod()
{
	drop_pod = self;
	drop_pod playsound( "orbital_drop_pod_platform_exp" );
}

aud_drop_pod_trophy_kill()
{
	drop_pod = self;
}

aud_play_trophy_fire()
{
	trophy = self;
}

aud_setup_drop_pod_loop()
{
	thread snd_play_linked_loop( "orbital_drop_pod_platform_lp", self );
	
	self waittill("Death");
	
	if(IsDefined(self))
		self stopsounds();
}