#include maps/mp/_scoreevents;
#include maps/mp/gametypes/_globallogic_audio;
#include maps/mp/_popups;
#include maps/mp/gametypes/_damagefeedback;
#include maps/mp/gametypes/_globallogic_player;
#include maps/mp/gametypes/_weaponobjects;
#include maps/mp/_heatseekingmissile;
#include maps/mp/killstreaks/_killstreakrules;
#include maps/mp/_challenges;
#include maps/mp/gametypes/_hostmigration;
#include maps/mp/killstreaks/_radar;
#include maps/mp/gametypes/_spawnlogic;
#include maps/mp/gametypes/_battlechatter_mp;
#include maps/mp/killstreaks/_airsupport;
#include common_scripts/utility;
#include maps/mp/gametypes/_hud_util;
#include maps/mp/_utility;

init()
{
	level.spyplanemodel = "veh_t6_drone_uav";
	level.counteruavmodel = "veh_t6_drone_cuav";
	level.u2_maxhealth = 700;
	level.spyplane = [];
	level.spyplaneentrancetime = 5;
	level.spyplaneexittime = 10;
	level.counteruavweapon = "counteruav_mp";
	level.counteruavlength = 25;
	precachemodel( level.spyplanemodel );
	precachemodel( level.counteruavmodel );
	level.counteruavplaneentrancetime = 5;
	level.counteruavplaneexittime = 10;
	level.counteruavlight = loadfx( "vehicle/light/fx_cuav_lights_red" );
	level.uavlight = loadfx( "vehicle/light/fx_u2_lights_red" );
	level.fx_spyplane_afterburner = loadfx( "vehicle/exhaust/fx_exhaust_u2_spyplane_afterburner" );
	level.fx_spyplane_burner = loadfx( "vehicle/exhaust/fx_exhaust_u2_spyplane_burner" );
	level.fx_cuav_afterburner = loadfx( "vehicle/exhaust/fx_exhaust_cuav_afterburner" );
	level.fx_cuav_burner = loadfx( "vehicle/exhaust/fx_exhaust_cuav_burner" );
	level.satelliteheight = 10000;
	level.satelliteflydistance = 10000;
	level.fx_u2_damage_trail = loadfx( "trail/fx_trail_u2_plane_damage_mp" );
	level.fx_u2_explode = loadfx( "vehicle/vexplosion/fx_vexplode_u2_exp_mp" );
	minimaporigins = getentarray( "minimap_corner", "targetname" );
	if ( minimaporigins.size )
	{
		uavorigin = maps/mp/gametypes/_spawnlogic::findboxcenter( minimaporigins[ 0 ].origin, minimaporigins[ 1 ].origin );
	}
	else
	{
		uavorigin = ( 0, 0, 1 );
	}
	if ( level.script == "mp_hydro" )
	{
		uavorigin += vectorScale( ( 0, 0, 1 ), 1200 );
	}
	if ( level.teambased )
	{
		_a54 = level.teams;
		_k54 = getFirstArrayKey( _a54 );
		while ( isDefined( _k54 ) )
		{
			team = _a54[ _k54 ];
			level.activeuavs[ team ] = 0;
			level.activecounteruavs[ team ] = 0;
			level.activesatellites[ team ] = 0;
			_k54 = getNextArrayKey( _a54, _k54 );
		}
	}
	else level.activeuavs = [];
	level.activecounteruavs = [];
	level.activesatellites = [];
	level.uavrig = spawn( "script_model", uavorigin + vectorScale( ( 0, 0, 1 ), 1100 ) );
	level.uavrig setmodel( "tag_origin" );
	level.uavrig.angles = vectorScale( ( 0, 0, 1 ), 115 );
	level.uavrig hide();
	level.uavrig thread rotateuavrig( 1 );
	level.uavrig thread swayuavrig();
	level.counteruavrig = spawn( "script_model", uavorigin + vectorScale( ( 0, 0, 1 ), 1500 ) );
	level.counteruavrig setmodel( "tag_origin" );
	level.counteruavrig.angles = vectorScale( ( 0, 0, 1 ), 115 );
	level.counteruavrig hide();
	level.counteruavrig thread rotateuavrig( 0 );
	level.counteruavrig thread swayuavrig();
	level thread uavtracker();
	level thread onplayerconnect();
}

onplayerconnect()
{
	for ( ;; )
	{
		level waittill( "connected", player );
		player.entnum = player getentitynumber();
		level.activeuavs[ player.entnum ] = 0;
		level.activecounteruavs[ player.entnum ] = 0;
		level.activesatellites[ player.entnum ] = 0;
		if ( level.teambased == 0 || level.multiteam == 1 )
		{
			player thread watchffaandmultiteamspawn();
		}
	}
}

watchffaandmultiteamspawn()
{
	self endon( "disconnect" );
	for ( ;; )
	{
		self waittill( "spawned_player" );
		level notify( "uav_update" );
	}
}

rotateuavrig( clockwise )
{
	turn = 360;
	if ( clockwise )
	{
		turn = -360;
	}
	for ( ;; )
	{
		if ( !clockwise )
		{
			self rotateyaw( turn, 40 );
			wait 40;
			continue;
		}
		else
		{
			self rotateyaw( turn, 60 );
			wait 60;
		}
	}
}

swayuavrig()
{
	centerorigin = self.origin;
	for ( ;; )
	{
		z = randomintrange( -200, -100 );
		time = randomintrange( 3, 6 );
		self moveto( centerorigin + ( 0, 0, z ), time, 1, 1 );
		wait time;
		z = randomintrange( 100, 200 );
		time = randomintrange( 3, 6 );
		self moveto( centerorigin + ( 0, 0, z ), time, 1, 1 );
		wait time;
	}
}

callcounteruav( type, displaymessage, killstreak_id )
{
	timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage );
	iscounter = 1;
	counteruavplane = generateplane( self, timeinair, iscounter );
	if ( !isDefined( counteruavplane ) )
	{
		return 0;
	}
	counteruavplane thread counteruav_watchfor_gamerules_destruction( self );
	counteruavplane setclientflag( 11 );
	counteruavplane addactivecounteruav();
	self.counteruavtime = getTime();
	counteruavplane thread playcounterspyplanefx();
	counteruavplane thread counteruavplane_death_waiter();
	counteruavplane thread counteruavplane_timeout( timeinair, self );
	counteruavplane thread plane_damage_monitor( 0 );
	counteruavplane thread plane_health();
	counteruavplane.killstreak_id = killstreak_id;
	counteruavplane.iscounter = 1;
	counteruavplane playloopsound( "veh_uav_engine_loop", 1 );
	return 1;
}

callspyplane( type, displaymessage, killstreak_id )
{
	timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage );
	iscounter = 0;
	spyplane = generateplane( self, timeinair, iscounter );
	if ( !isDefined( spyplane ) )
	{
		return 0;
	}
	spyplane thread spyplane_watchfor_gamerules_destruction( self );
	spyplane addactiveuav();
	self.uavtime = getTime();
	spyplane.leaving = 0;
	spyplane thread playspyplanefx();
	spyplane thread spyplane_timeout( timeinair, self );
	spyplane thread spyplane_death_waiter();
	spyplane thread plane_damage_monitor( 1 );
	spyplane thread plane_health();
	spyplane.killstreak_id = killstreak_id;
	spyplane.iscounter = 0;
	spyplane playloopsound( "veh_uav_engine_loop", 1 );
	return 1;
}

callsatellite( type, displaymessage, killstreak_id )
{
	timeinair = self maps/mp/killstreaks/_radar::useradaritem( type, self.team, displaymessage );
	satellite = spawn( "script_model", level.mapcenter + ( 0 - level.satelliteflydistance, 0, level.satelliteheight ) );
	satellite setmodel( "tag_origin" );
	satellite moveto( level.mapcenter + ( level.satelliteflydistance, 0, level.satelliteheight ), timeinair );
	satellite.owner = self;
	satellite.team = self.team;
	satellite setteam( self.team );
	satellite setowner( self );
	satellite.targetname = "satellite";
	satellite addactivesatellite();
	self.satellitetime = getTime();
	satellite thread satellite_timeout( timeinair, self );
	satellite thread satellite_watchfor_gamerules_destruction( self );
	satellite.iscounter = 0;
	if ( level.teambased )
	{
		satellite thread updatevisibility();
	}
	satellite.killstreak_id = killstreak_id;
	return 1;
}

spyplane_watchfor_gamerules_destruction( player )
{
	self endon( "death" );
	self endon( "crashing" );
	self endon( "delete" );
	player waittill_any( "joined_team", "disconnect", "joined_spectators" );
	self spyplane_death();
}

counteruav_watchfor_gamerules_destruction( player )
{
	self endon( "death" );
	self endon( "crashing" );
	self endon( "delete" );
	player waittill_any( "joined_team", "disconnect", "joined_spectators" );
	maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
	self counteruavplane_death();
}

satellite_watchfor_gamerules_destruction( player )
{
	self endon( "death" );
	self endon( "delete" );
	player waittill_any( "joined_team", "disconnect", "joined_spectators" );
	maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
	self removeactivesatellite();
	self delete();
}

addactivecounteruav()
{
	if ( level.teambased )
	{
		self.owner.activecounteruavs++;
		level.activecounteruavs[ self.team ]++;
		_a284 = level.teams;
		_k284 = getFirstArrayKey( _a284 );
		while ( isDefined( _k284 ) )
		{
			team = _a284[ _k284 ];
			if ( team == self.team )
			{
			}
			else
			{
				if ( level.activesatellites[ team ] > 0 )
				{
					self.owner maps/mp/_challenges::blockedsatellite();
				}
			}
			_k284 = getNextArrayKey( _a284, _k284 );
		}
	}
	else /#
	assert( isDefined( self.owner.entnum ) );
#/
	if ( !isDefined( self.owner.entnum ) )
	{
		self.owner.entnum = self.owner getentitynumber();
	}
	level.activecounteruavs[ self.owner.entnum ]++;
	keys = getarraykeys( level.activecounteruavs );
	i = 0;
	while ( i < keys.size )
	{
		if ( keys[ i ] == self.owner.entnum )
		{
			i++;
			continue;
		}
		else
		{
			if ( level.activecounteruavs[ keys[ i ] ] )
			{
				self.owner maps/mp/_challenges::blockedsatellite();
				break;
			}
		}
		else
		{
			i++;
		}
	}
	level notify( "uav_update" );
}

addactiveuav()
{
	if ( level.teambased )
	{
		self.owner.activeuavs++;
		level.activeuavs[ self.team ]++;
	}
	else
	{
/#
		assert( isDefined( self.owner.entnum ) );
#/
		if ( !isDefined( self.owner.entnum ) )
		{
			self.owner.entnum = self.owner getentitynumber();
		}
		level.activeuavs[ self.owner.entnum ]++;
	}
	level notify( "uav_update" );
}

addactivesatellite()
{
	if ( level.teambased )
	{
		self.owner.activesatellites++;
		level.activesatellites[ self.team ]++;
	}
	else
	{
/#
		assert( isDefined( self.owner.entnum ) );
#/
		if ( !isDefined( self.owner.entnum ) )
		{
			self.owner.entnum = self.owner getentitynumber();
		}
		level.activesatellites[ self.owner.entnum ]++;
	}
	level notify( "uav_update" );
}

removeactiveuav()
{
	if ( level.teambased )
	{
		if ( isDefined( self.owner ) && self.owner.spawntime < self.birthtime )
		{
			self.owner.activeuavs--;

/#
			assert( self.owner.activeuavs >= 0 );
#/
			if ( self.owner.activeuavs < 0 )
			{
				self.owner.activeuavs = 0;
			}
		}
		level.activeuavs[ self.team ]--;

/#
		assert( level.activeuavs[ self.team ] >= 0 );
#/
		if ( level.activeuavs[ self.team ] < 0 )
		{
			level.activeuavs[ self.team ] = 0;
		}
	}
	else
	{
		if ( isDefined( self.owner ) )
		{
/#
			assert( isDefined( self.owner.entnum ) );
#/
			if ( !isDefined( self.owner.entnum ) )
			{
				self.owner.entnum = self.owner getentitynumber();
			}
			level.activeuavs[ self.owner.entnum ]--;

/#
			assert( level.activeuavs[ self.owner.entnum ] >= 0 );
#/
			if ( level.activeuavs[ self.owner.entnum ] < 0 )
			{
				level.activeuavs[ self.owner.entnum ] = 0;
			}
		}
	}
	maps/mp/killstreaks/_killstreakrules::killstreakstop( "radar_mp", self.team, self.killstreak_id );
	level notify( "uav_update" );
}

removeactivecounteruav()
{
	if ( level.teambased )
	{
		if ( isDefined( self.owner ) && self.owner.spawntime < self.birthtime )
		{
			self.owner.activecounteruavs--;

/#
			assert( self.owner.activecounteruavs >= 0 );
#/
			if ( self.owner.activecounteruavs < 0 )
			{
				self.owner.activecounteruavs = 0;
			}
		}
		level.activecounteruavs[ self.team ]--;

/#
		assert( level.activecounteruavs[ self.team ] >= 0 );
#/
		if ( level.activecounteruavs[ self.team ] < 0 )
		{
			level.activecounteruavs[ self.team ] = 0;
		}
	}
	else
	{
		if ( isDefined( self.owner ) )
		{
/#
			assert( isDefined( self.owner.entnum ) );
#/
			if ( !isDefined( self.owner.entnum ) )
			{
				self.owner.entnum = self.owner getentitynumber();
			}
			level.activecounteruavs[ self.owner.entnum ]--;

/#
			assert( level.activecounteruavs[ self.owner.entnum ] >= 0 );
#/
			if ( level.activecounteruavs[ self.owner.entnum ] < 0 )
			{
				level.activecounteruavs[ self.owner.entnum ] = 0;
			}
		}
	}
	maps/mp/killstreaks/_killstreakrules::killstreakstop( "counteruav_mp", self.team, self.killstreak_id );
	level notify( "uav_update" );
}

removeactivesatellite()
{
	if ( level.teambased )
	{
		if ( self.owner.spawntime < self.birthtime && isDefined( self.owner ) )
		{
			self.owner.activesatellites--;

/#
			assert( self.owner.activesatellites >= 0 );
#/
			if ( self.owner.activesatellites < 0 )
			{
				self.owner.activesatellites = 0;
			}
		}
		level.activesatellites[ self.team ]--;

/#
		assert( level.activesatellites[ self.team ] >= 0 );
#/
		if ( level.activesatellites[ self.team ] < 0 )
		{
			level.activesatellites[ self.team ] = 0;
		}
	}
	else
	{
		if ( isDefined( self.owner ) )
		{
/#
			assert( isDefined( self.owner.entnum ) );
#/
			if ( !isDefined( self.owner.entnum ) )
			{
				self.owner.entnum = self.owner getentitynumber();
			}
			level.activesatellites[ self.owner.entnum ]--;

/#
			assert( level.activesatellites[ self.owner.entnum ] >= 0 );
#/
			if ( level.activesatellites[ self.owner.entnum ] < 0 )
			{
				level.activesatellites[ self.owner.entnum ] = 0;
			}
		}
	}
	maps/mp/killstreaks/_killstreakrules::killstreakstop( "radardirection_mp", self.team, self.killstreak_id );
	level notify( "uav_update" );
}

playspyplanefx()
{
	wait 0,1;
	playfxontag( level.fx_spyplane_burner, self, "tag_origin" );
}

playspyplaneafterburnerfx()
{
	self endon( "death" );
	wait 0,1;
	playfxontag( level.fx_spyplane_afterburner, self, "tag_origin" );
}

playcounterspyplanefx()
{
	wait 0,1;
	if ( isDefined( self ) )
	{
		playfxontag( level.fx_cuav_burner, self, "tag_origin" );
	}
}

playcounterspyplaneafterburnerfx()
{
	self endon( "death" );
	wait 0,1;
	playfxontag( level.fx_cuav_afterburner, self, "tag_origin" );
}

playuavpilotdialog( dialog, owner, delaytime )
{
	if ( isDefined( delaytime ) )
	{
		wait delaytime;
	}
	self.pilotvoicenumber = owner.bcvoicenumber + 1;
	soundalias = level.teamprefix[ owner.team ] + self.pilotvoicenumber + "_" + dialog;
	while ( isDefined( owner.pilotisspeaking ) )
	{
		while ( owner.pilotisspeaking )
		{
			while ( owner.pilotisspeaking )
			{
				wait 0,2;
			}
		}
	}
	if ( isDefined( owner ) )
	{
		owner playlocalsound( soundalias );
		owner.pilotisspeaking = 1;
		owner thread waitplaybacktime( soundalias );
		owner waittill_any( soundalias, "death", "disconnect" );
		owner.pilotisspeaking = 0;
	}
}

generateplane( owner, timeinair, iscounter )
{
	uavrig = level.uavrig;
	attach_angle = -90;
	if ( iscounter )
	{
		uavrig = level.counteruavrig;
		attach_angle = 90;
	}
	plane = spawn( "script_model", uavrig gettagorigin( "tag_origin" ) );
	if ( iscounter )
	{
		plane setmodel( level.counteruavmodel );
		plane.targetname = "counteruav";
	}
	else
	{
		plane setmodel( level.spyplanemodel );
		plane.targetname = "uav";
	}
	plane setteam( owner.team );
	plane setowner( owner );
	target_set( plane );
	plane thread play_light_fx( iscounter );
	plane.owner = owner;
	plane.team = owner.team;
	plane thread updatevisibility();
	plane thread maps/mp/_heatseekingmissile::missiletarget_proximitydetonateincomingmissile( "crashing" );
	level.plane[ self.team ] = plane;
	plane.health_low = level.u2_maxhealth * 0,4;
	plane.maxhealth = level.u2_maxhealth;
	plane.health = 99999;
	plane.rocketdamageoneshot = level.u2_maxhealth + 1;
	plane.rocketdamagetwoshot = ( level.u2_maxhealth / 2 ) + 1;
	plane setdrawinfrared( 1 );
	zoffset = randomintrange( 4000, 5000 );
	angle = randomint( 360 );
	if ( iscounter )
	{
		radiusoffset = randomint( 1000 ) + 3000;
	}
	else
	{
		radiusoffset = randomint( 1000 ) + 4000;
	}
	xoffset = cos( angle ) * radiusoffset;
	yoffset = sin( angle ) * radiusoffset;
	anglevector = vectornormalize( ( xoffset, yoffset, zoffset ) );
	anglevector *= randomintrange( 4000, 5000 );
	if ( iscounter )
	{
		plane linkto( uavrig, "tag_origin", anglevector, ( 0, angle + attach_angle, -10 ) );
	}
	else
	{
		plane linkto( uavrig, "tag_origin", anglevector, ( 0, angle + attach_angle, 0 ) );
	}
	return plane;
}

play_light_fx( iscounter )
{
	self endon( "death" );
	wait 0,1;
	if ( iscounter )
	{
		playfxontag( level.counteruavlight, self, "tag_origin" );
	}
	else
	{
		playfxontag( level.uavlight, self, "tag_origin" );
	}
}

updatevisibility()
{
	self endon( "death" );
	for ( ;; )
	{
		if ( level.teambased )
		{
			self setvisibletoallexceptteam( self.team );
		}
		else
		{
			self setvisibletoall();
			self setinvisibletoplayer( self.owner );
		}
		level waittill( "joined_team" );
	}
}

debugline( frompoint, topoint, color, durationframes )
{
/#
	i = 0;
	while ( i < ( durationframes * 20 ) )
	{
		line( frompoint, topoint, color );
		wait 0,05;
		i++;
#/
	}
}

plane_damage_monitor( isspyplane )
{
	self endon( "death" );
	self endon( "crashing" );
	self endon( "delete" );
	self setcandamage( 1 );
	self.damagetaken = 0;
	for ( ;; )
	{
		self waittill( "damage", damage, attacker, direction, point, type, tagname, modelname, partname, weapon );
		if ( !isDefined( attacker ) || !isplayer( attacker ) )
		{
			continue;
		}
		else
		{
			friendlyfire = maps/mp/gametypes/_weaponobjects::friendlyfirecheck( self.owner, attacker );
			if ( !friendlyfire )
			{
				break;
			}
			else if ( isDefined( self.owner ) && attacker == self.owner )
			{
				break;
			}
			else
			{
				isvalidattacker = 1;
				if ( level.teambased )
				{
					if ( isDefined( attacker.team ) )
					{
						isvalidattacker = attacker.team != self.team;
					}
				}
				if ( !isvalidattacker )
				{
					break;
				}
				else
				{
					if ( maps/mp/gametypes/_globallogic_player::dodamagefeedback( weapon, attacker ) )
					{
						attacker thread maps/mp/gametypes/_damagefeedback::updatedamagefeedback( type );
					}
					self.attacker = attacker;
					switch( type )
					{
						case "MOD_PISTOL_BULLET":
						case "MOD_RIFLE_BULLET":
							if ( attacker hasperk( "specialty_armorpiercing" ) )
							{
								self.damagetaken += int( damage * level.cac_armorpiercing_data );
							}
							else
							{
								self.damagetaken += damage;
							}
							break;
						case "MOD_PROJECTILE":
							self.damagetaken += self.rocketdamageoneshot;
							break;
						default:
							self.damagetaken += damage;
							break;
					}
					self.health += damage;
					if ( self.damagetaken > self.maxhealth )
					{
						killstreakreference = "radar_mp";
						if ( !isspyplane )
						{
							killstreakreference = "counteruav_mp";
						}
						attacker notify( "destroyed_spyplane" );
						weaponstatname = "destroyed";
						switch( weapon )
						{
							case "auto_tow_mp":
							case "tow_turret_drop_mp":
							case "tow_turret_mp":
								weaponstatname = "kills";
								break;
						}
						attacker addweaponstat( weapon, weaponstatname, 1 );
						level.globalkillstreaksdestroyed++;
						attacker addweaponstat( killstreakreference, "destroyed", 1 );
						maps/mp/_challenges::destroyedaircraft( attacker, weapon );
						if ( isspyplane )
						{
							level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_DESTROYED_UAV", attacker );
							if ( isDefined( self.owner ) )
							{
								self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "uav_destroyed", "item_destroyed" );
							}
							if ( !isDefined( self.owner ) || self.owner isenemyplayer( attacker ) )
							{
								thread maps/mp/_scoreevents::processscoreevent( "destroyed_uav", attacker, self.owner, weapon );
								attacker maps/mp/_challenges::addflyswatterstat( weapon, self );
								break;
							}
							spyplane_death();
						}
						else
						{
							level thread maps/mp/_popups::displayteammessagetoall( &"KILLSTREAK_DESTROYED_COUNTERUAV", attacker );
							if ( isDefined( self.owner ) )
							{
								self.owner maps/mp/gametypes/_globallogic_audio::leaderdialogonplayer( "cuav_destroyed", "item_destroyed" );
							}
							if ( !isDefined( self.owner ) || self.owner isenemyplayer( attacker ) )
							{
								thread maps/mp/_scoreevents::processscoreevent( "destroyed_counter_uav", attacker, self.owner, weapon );
								attacker maps/mp/_challenges::addflyswatterstat( weapon, self );
								break;
							}
							counteruavplane_death();
						}
						return;
					}
				}
			}
		}
	}
}

plane_health()
{
	self endon( "death" );
	self endon( "crashing" );
	self.currentstate = "ok";
	self.laststate = "ok";
	while ( self.currentstate != "leaving" )
	{
		if ( self.damagetaken >= self.health_low )
		{
			self.currentstate = "damaged";
		}
		if ( self.currentstate == "damaged" && self.laststate != "damaged" )
		{
			self.laststate = self.currentstate;
			self thread playdamagefx();
		}
/#
		debug_print3d_simple( "Health: " + ( self.maxhealth - self.damagetaken ), self, vectorScale( ( 0, 0, 1 ), 100 ), 20 );
#/
		wait 1;
	}
}

playdamagefx()
{
	self endon( "death" );
	self endon( "crashing" );
	playfxontag( level.fx_u2_damage_trail, self, "tag_body" );
}

u2_crash()
{
	self notify( "crashing" );
	playfxontag( level.fx_u2_explode, self, "tag_origin" );
	wait 0,1;
	self setmodel( "tag_origin" );
	wait 0,2;
	self notify( "delete" );
	self delete();
}

counteruavplane_death_waiter()
{
	self endon( "delete" );
	self endon( "leaving" );
	self waittill( "death" );
	counteruavplane_death();
}

spyplane_death_waiter()
{
	self endon( "delete" );
	self endon( "leaving" );
	self waittill( "death" );
	spyplane_death();
}

counteruavplane_death()
{
	self clearclientflag( 11 );
	self playsound( "evt_helicopter_midair_exp" );
	self removeactivecounteruav();
	target_remove( self );
	self thread u2_crash();
}

spyplane_death()
{
	self playsound( "evt_helicopter_midair_exp" );
	if ( !self.leaving )
	{
		self removeactiveuav();
	}
	target_remove( self );
	self thread u2_crash();
}

counteruavplane_timeout( timeinair, owner )
{
	self endon( "death" );
	self endon( "delete" );
	maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
	timeremaining = timeinair * 1000;
	self waittilltimeoutmigrationaware( timeremaining, owner );
	self clearclientflag( 11 );
	self plane_leave();
	wait level.counteruavplaneexittime;
	self removeactivecounteruav();
	target_remove( self );
	self delete();
}

satellite_timeout( timeinair, owner )
{
	self endon( "death" );
	self endon( "delete" );
	maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
	timeremaining = timeinair * 1000;
	self waittilltimeoutmigrationaware( timeremaining, owner );
	self removeactivesatellite();
	self delete();
}

watchforemp()
{
	self endon( "death" );
	self endon( "delete" );
	self waittill( "emp_deployed", attacker );
	weapon = "emp_mp";
	maps/mp/_challenges::destroyedaircraft( attacker, weapon );
	thread maps/mp/_scoreevents::processscoreevent( "destroyed_satellite", attacker, self.owner, weapon );
	attacker maps/mp/_challenges::addflyswatterstat( weapon, self );
	self removeactivesatellite();
	self delete();
}

spyplane_timeout( timeinair, owner )
{
	self endon( "death" );
	self endon( "delete" );
	self endon( "crashing" );
	maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
	timeremaining = timeinair * 1000;
	self waittilltimeoutmigrationaware( timeremaining, owner );
	self plane_leave();
	self.leaving = 1;
	self removeactiveuav();
	wait level.spyplaneexittime;
	target_remove( self );
	self delete();
}

waittilltimeoutmigrationaware( timeremaining, owner )
{
	owner endon( "disconnect" );
	for ( ;; )
	{
		self.endtime = getTime() + timeremaining;
		event = level waittill_any_timeout( timeremaining / 1000, "game_ended", "host_migration_begin" );
		if ( event != "host_migration_begin" )
		{
			return;
		}
		else timeremaining = self.endtime - getTime();
		if ( timeremaining <= 0 )
		{
			return;
		}
		else
		{
			maps/mp/gametypes/_hostmigration::waittillhostmigrationdone();
		}
	}
}

planestoploop( time )
{
	self endon( "death" );
	wait time;
	self stoploopsound();
}

plane_leave()
{
	self unlink();
	if ( isDefined( self.iscounter ) && self.iscounter )
	{
		self thread playcounterspyplaneafterburnerfx();
		self playsound( "veh_kls_uav_afterburner" );
		self thread play_light_fx( 1 );
		self thread planestoploop( 1 );
	}
	else
	{
		self thread playspyplaneafterburnerfx();
		self playsound( "veh_kls_spy_afterburner" );
		self thread play_light_fx( 0 );
		self thread planestoploop( 1 );
	}
	self.currentstate = "leaving";
	if ( self.laststate == "damaged" )
	{
		playfxontag( level.fx_u2_damage_trail, self, "tag_body" );
	}
	mult = getdvarintdefault( "scr_spymult", 20000 );
	tries = 10;
	yaw = 0;
	while ( tries > 0 )
	{
		exitvector = anglesToForward( self.angles + ( 0, yaw, 0 ) ) * 20000;
		if ( isDefined( self.iscounter ) && self.iscounter )
		{
			self thread playcounterspyplanefx();
			exitvector *= 1;
		}
		exitpoint = ( self.origin[ 0 ] + exitvector[ 0 ], self.origin[ 1 ] + exitvector[ 1 ], self.origin[ 2 ] - 2500 );
		exitpoint = self.origin + exitvector;
		nfz = crossesnoflyzone( self.origin, exitpoint );
		if ( isDefined( nfz ) )
		{
			if ( tries != 1 )
			{
				if ( ( tries % 2 ) == 1 )
				{
					yaw *= -1;
					tries--;
					continue;
				}
				else
				{
					yaw += 10;
					yaw *= -1;
				}
			}
			tries--;

			continue;
		}
		else
		{
			tries = 0;
		}
	}
	self thread flattenyaw( self.angles[ 1 ] + yaw );
	if ( self.angles[ 2 ] != 0 )
	{
		self thread flattenroll();
	}
	self moveto( exitpoint, level.spyplaneexittime, 0, 0 );
	self notify( "leaving" );
}

flattenroll()
{
	self endon( "death" );
	while ( self.angles[ 2 ] < 0 )
	{
		self.angles = ( self.angles[ 0 ], self.angles[ 1 ], self.angles[ 2 ] + 2,5 );
		wait 0,05;
	}
}

flattenyaw( goal )
{
	self endon( "death" );
	increment = 3;
	if ( self.angles[ 1 ] > goal )
	{
		increment *= -1;
	}
	while ( abs( self.angles[ 1 ] - goal ) > 3 )
	{
		self.angles = ( self.angles[ 0 ], self.angles[ 1 ] + increment, self.angles[ 2 ] );
		wait 0,05;
	}
}

uavtracker()
{
	level endon( "game_ended" );
	for ( ;; )
	{
		level waittill( "uav_update" );
		if ( level.teambased )
		{
			_a1102 = level.teams;
			_k1102 = getFirstArrayKey( _a1102 );
			while ( isDefined( _k1102 ) )
			{
				team = _a1102[ _k1102 ];
				updateteamuavstatus( team );
				_k1102 = getNextArrayKey( _a1102, _k1102 );
			}
		}
		else updateplayersuavstatus();
	}
}

updateteamuavstatus( team )
{
	activeuavs = level.activeuavs[ team ];
	activesatellites = level.activesatellites[ team ];
	radarmode = 1;
	if ( activesatellites > 0 )
	{
		maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, 0 );
		maps/mp/killstreaks/_radar::setteamsatellitewrapper( team, 1 );
		return;
	}
	maps/mp/killstreaks/_radar::setteamsatellitewrapper( team, 0 );
	if ( !activeuavs )
	{
		maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, 0 );
		return;
	}
	if ( activeuavs > 1 )
	{
		radarmode = 2;
	}
	maps/mp/killstreaks/_radar::setteamspyplanewrapper( team, radarmode );
}

updateplayersuavstatus()
{
	i = 0;
	while ( i < level.players.size )
	{
		player = level.players[ i ];
/#
		assert( isDefined( player.entnum ) );
#/
		if ( !isDefined( player.entnum ) )
		{
			player.entnum = player getentitynumber();
		}
		activeuavs = level.activeuavs[ player.entnum ];
		activesatellites = level.activesatellites[ player.entnum ];
		if ( activesatellites > 0 )
		{
			player.hassatellite = 1;
			player.hasspyplane = 0;
			player setclientuivisibilityflag( "radar_client", 1 );
			i++;
			continue;
		}
		else player.hassatellite = 0;
		if ( activeuavs == 0 && isDefined( player.pers[ "hasRadar" ] ) && !player.pers[ "hasRadar" ] )
		{
			player.hasspyplane = 0;
			player setclientuivisibilityflag( "radar_client", 0 );
			i++;
			continue;
		}
		else
		{
			if ( activeuavs > 1 )
			{
				spyplaneupdatespeed = 2;
			}
			else
			{
				spyplaneupdatespeed = 1;
			}
			player setclientuivisibilityflag( "radar_client", 1 );
			player.hasspyplane = spyplaneupdatespeed;
		}
		i++;
	}
}
