#include extreme\_ex_lin;

init()
{
	thread extreme\_ex_logfile::Log("Planes");

	level endon("ex_stop_ambient_fx");

	lastapteam = 2;		// set to 2 so it won't run the first time

	while(!level.ex_gameover)
	{
		wait 1; // avoid infinite loop error on continue

		players = getentarray("player", "classname");
		if(players.size == 0) continue;

		delay = (randomInt(level.ex_planes_delay_max - level.ex_planes_delay_min) + level.ex_planes_delay_min) - 10;
		if(delay < 20) delay = 20;
		
		wait(delay / 3);

		if(level.ex_planes_flak && level.ex_flakison)
		{
			level notify("stop_flak");
			level.ex_flakison = false;
		}

		wait((delay / 3) * 2);

		// set up plane amount (normal)
		apcount = randomInt(level.ex_planes_max - level.ex_planes_min) + level.ex_planes_min;
		apflangle = randomInt(360);

		// pick a plane team at random		
		if(randomInt(100) < 50) apteam = 0;
			else apteam = 1;

		// keep it balanced for teamplay
		if(level.ex_teamplay)
		{
			if(lastapteam != 2)
			{
				if(lastapteam == apteam)
				{
					if(apteam == 0) apteam = 1;
						else apteam = 0;
				}
			}
		}

		// set team definition
		if(apteam == 0) level.apteam = "axis";
			else level.apteam = "allies";

		// set planes in sky values
		if(apteam == 0) level.ex_allieapinsky += apcount;
			else level.ex_axisapinsky += apcount;
				
		apstpoint = [];
		apenpoint = [];
		apposinmap = [];

		if(level.ex_air_raid) thread extreme\_ex_utils::playSoundLoc("air_raid",(0,0,0));
		
		if(level.ex_planes_flak && !level.ex_flakison)
		{
			for(flak = 0; flak < level.ex_flakfx; flak++)
				thread extreme\_ex_skyeffects::flakfx();

			wait 10;
		}
			
		self.airplanesGlobalDelay = 0;

		for(i = 0; i < apcount; i++)
		{
			if(randomInt(100) < 30)
			{
				x = level.ex_playArea_Max[0] + randomInt(level.ex_playArea_Width);
				y = level.ex_playArea_Max[1] + randomInt(level.ex_playArea_Length);
			}
			else
			{
				x = level.ex_playArea_Min[0] + randomInt(level.ex_playArea_Width);
				y = level.ex_playArea_Min[1] + randomInt(level.ex_playArea_Length);
			}

			z = level.ex_mapArea_Max[2] - randomint(150);
			if(level.ex_planes_altitude && (level.ex_planes_altitude <= z))
				z = level.ex_planes_altitude;

			stenpos = getPlaneStartEnd( (x,y,z), apflangle );
			stenpos2 = getPlaneStartEnd( (stenpos[1]), apflangle );
			if(stenpos2[2] == 1) stenpos[1] = stenpos2[1];

			apstpoint[i] = stenpos[0];
			apenpoint[i] = stenpos[1];
			apposinmap[i] = (x,y,z);

			// create the plane
			thread planestart(apflangle, apstpoint[i], apenpoint[i], apteam, apposinmap[i]);
		}

		for(i = 0; i < apcount; i++)
			level waittill("ambplane_finished");

		// check for teamplay to keep things even
		if(level.ex_teamplay) lastapteam = apteam;
	}
}

planestart(apflangle, apstpoint, apenpoint, apteam, apposinmap)
{
	thread extreme\_ex_logfile::Log("planestart");

	self.airplanesGlobalDelay += randomFloatRange( 2, 5 );
	wait(self.airplanesGlobalDelay);

	apmodel = [];
	apsoundchoice = [];

	if(apteam == 0)
	{
		// plane models
		apmodel[0] = "xmodel/vehicle_stuka_flying";
		apmodel[1] = "xmodel/vehicle_condor";

		// plane sounds
		apsoundchoice[0] = "stuka_flyby_1";
		apsoundchoice[1] = "stuka_flyby_2";
	}
	else
	{
		// plane models
		apmodel[0] = "xmodel/vehicle_spitfire_flying";
		apmodel[1] = "xmodel/vehicle_p51_mustang";
		apmodel[2] = "xmodel/mebelle1";

		// plane sounds
		apsoundchoice[0] = "spitfire_flyby_1";
	}

	aprand = randomInt(apmodel.size);
	apsound = apsoundchoice[randomInt(apsoundchoice.size)];

	planetype = 0; // fighter
	if(apteam == 0 && aprand == 1) planetype = 1; // axis bomber
		else if(apteam == 1 && aprand == 2) planetype = 1; // allies bomber

	plane = spawn("script_model", apstpoint);
	plane setModel(apmodel[aprand]);
	if(apteam == 1 && aprand == 2)
	{
		plane.angles = plane.angles + (0, apflangle, 0);
		plane rotateyaw(90, .1);
	}
	else if(apteam == 0 && aprand == 0) plane.angles = plane.angles + (10, apflangle, 0);
		else plane.angles = plane.angles + (0, apflangle, 0);

	plane.apdivesound = spawn("script_model", (0,0,0));
	plane.apdivesound.origin = apstpoint - (0,50,0);
	plane.apdivesound linkto(plane);

	plane.apsound = spawn("script_model", (0,0,0));
	plane.apsound.origin = apstpoint - (0,50,0);
	plane.apsound linkto(plane);
	plane.apsound playloopsound(apsound);

	// set speed
	if(planetype == 0) apspeed = 40; // fighters
		else apspeed = 30; // bombers

	// flighttime
	flighttime = calcTime(apstpoint, apenpoint, apspeed);
	plane moveto(apenpoint, flighttime);

	plane.isbombing = false;
	// 10% chance plane will crash, but
	// - only fighters, because memphis has axis mixed up (and I'm too lazy to include the other bomber)
	// - only if there weren't enough crashes already (4 max)
	planecrash = false;
	if(randomInt(100) < 10 && level.ex_planescrashed < 4 && planetype == 0) planecrash = true;

	for(i = 0; i < ((flighttime/3)*2); i += 0.1)
	{
		if(!plane.isbombing && level.ex_planes >= 2 && planetype == 1 && (distance(apposinmap, plane.origin) < 1000) )
		{
			plane thread bombsetup();
			plane.isbombing = true;
		}

		if(planecrash && !plane.isbombing && (distance(level.ex_playArea_Centre, plane.origin) < 3000) )
		{
			plane thread airplanecrash(apspeed+10, apteam);
			return;
		}
		wait(0.1);
	}

	// has survived?, victory roll for fighters and bank for bombers but not every time!
	rolltime = flighttime/3;
	if(!rolltime <= 0)
	{
		if(planetype == 0)
		{
			switch(randomInt(5))
			{
				case 0:	{ plane rotateroll(360,rolltime,rolltime/2,rolltime/2); break; }
				case 1: { plane rotateroll(-360,rolltime,rolltime/2,rolltime/2); break; }
				default: break;
			}
		}
	}
	wait rolltime;

	if(isdefined(plane.apsound))
	{
		plane.apsound stopLoopSound();
		plane.apsound delete();
	}

	if(isdefined(plane.apdivesound))
	{
		plane.apdivesound stopLoopSound();
		plane.apdivesound delete();
	}

	if(apteam == 0) level.ex_axisapinsky--;
		else level.ex_allieapinsky--;

	if(isdefined(plane)) plane delete();
	level notify("ambplane_finished");
}

// bomb routines
bombsetup()
{
	wait randomInt(2) + .5;

	bombcount = 0;
	bombno = randomInt(3) + 4;

	while(bombcount < bombno)
	{
		self thread dropabomb();
		bombcount++;
		wait 0.2;
	}
}

dropabomb()
{
	if(!isdefined(self)) return;

	x = self.origin[0];
	y = self.origin[1];
	z = self.origin[2];

	startpoint = self.origin;
	forwardvector = anglestoforward(self.angles);
	endorigin = startpoint + ([[level.ex_vectormulti]](forwardvector,360));

	// get the impact point
	trace = bulletTrace(startpoint,(endorigin[0],endorigin[1],endorigin[2] - 2048), false, self);
	if(trace["fraction"] < 1) endorigin = trace["position"];
		else return; // if no proper position then skip the bomb

	// bomb falltime
	falltime = calcTime(startpoint, endorigin, 20);
	//if(falltime < 0.5) return; // abort

	// spawn the bomb and drop it
	bomb = spawn("script_model", startpoint);
	bomb.angles = self.angles + (-180 + randomint(50),0,0);
	bomb setModel("xmodel/prop_stuka_bomb");
	bomb moveto(endorigin + (0,0, - 100), falltime);

	// play the incoming sound falling sound
	bombsfx[0] = "mortar_incoming1";
	bombsfx[1] = "mortar_incoming2";
	bombsfx[2] = "mortar_incoming3";
	bombsfx[3] = "mortar_incoming4";
	bombsfx[4] = "mortar_incoming5";
	bs = randomInt(bombsfx.size);
	bomb playsound(bombsfx[bs]);

	// wait for it to hit
	wait falltime;

	// do the damage
	if(level.ex_planes == 2)
		bomb thread extreme\_ex_utils::scriptedfxradiusdamage(bomb, undefined, "MOD_EXPLOSIVE", "planebomb_mp", level.ex_planebomb_radius, 0, 0, "plane_bomb", undefined, true, true, true);

	if(level.ex_planes == 3)
		bomb thread extreme\_ex_utils::scriptedfxradiusdamage(bomb, undefined, "MOD_EXPLOSIVE", "planebomb_mp", level.ex_planebomb_radius, 500, 400, "plane_bomb", undefined, true, true, true);

	// play the explosion sound
	bombsfx[0] = "mortar_explosion1";
	bombsfx[1] = "mortar_explosion2";
	bombsfx[2] = "mortar_explosion3";
	bombsfx[3] = "mortar_explosion4";
	bombsfx[4] = "mortar_explosion5";
	bs = randomInt(bombsfx.size);
	bomb playsound(bombsfx[bs]);

	bomb hide();
	wait 1;
	bomb delete();
}

getPlaneStartEnd(targetpos, angle)
{
	forwardvector = anglestoforward( (0, angle, 0) );
	backpos = targetpos + ([[level.ex_vectormulti]](forwardvector, -30000));
	frontpos = targetpos + ([[level.ex_vectormulti]](forwardvector, 30000));
	fronthit = 0;

	trace = bulletTrace(targetpos, backpos, false, undefined);
	if(trace["fraction"] != 1) start = trace["position"];
		else start = backpos;

	trace = bulletTrace(targetpos, frontpos, false, undefined);
	if(trace["fraction"] != 1)
	{
		endpoint = trace["position"];
		fronthit = 1;
	}
	else endpoint = frontpos;

	startpos = start + ([[level.ex_vectormulti]](forwardvector, -3000));
	endpoint = endpoint + ([[level.ex_vectormulti]](forwardvector, 3000));
	stenpos[0] = startpos;
	stenpos[1] = endpoint;
	stenpos[2] = fronthit;
	return stenpos;
}

calcTime(startpos, endpos, speedvalue)
{
	distunit = 1;	// Metres
	speedunit = 1; // Metres per second
	distvalue = distance(startpos, endpos);
	distvalue = int(distvalue * 0.0254); // convert to metres
	timeinsec = (distvalue * distunit) / (speedvalue * speedunit);
	if(timeinsec <= 0) timeinsec = 0.1;
	return timeinsec;
}

airplanecrash(speed, apteam)
{
	thread extreme\_ex_logfile::Log("airplanecrash");

	level.ex_planescrashed++;

	playfx(level.ex_effect["flak_flash"], self.origin - (0, 200, 0));
	self playsound("plane_explosion_2");
	wait 0.2;
	playfx(level.ex_effect["flak_smoke"], self.origin - (0, 200, 0));
	wait 0.2;
	playfx(level.ex_effect["flak_dust"], self.origin - (0, 200, 0));
	wait 0.5;
	playfx(level.ex_effect["plane_smoke"], self.origin);
	wait 0.05;
	playfx(level.ex_effect["plane_smoke"], self.origin);
	wait 0.05;
	self.apdivesound playloopsound("plane_dive");
	playfx(level.ex_effect["plane_explosion"], self.origin);
	self playsound("plane_explosion_2");
	wait 0.5;
	playfx(level.ex_effect["plane_explosion"], self.origin);

	self.fire = 0;
	if(randomInt(100) > 50) self.fire = 1;

	angle = self.angles;
	pitch = randomInt(25) + 25;
	yaw = randomInt(50) - 25;
	roll = 200 - randomInt(400);
	angle_start = angle + (pitch,yaw,0);
	forwardvector = anglestoforward(angle_start);

	endpoint = self.origin + ([[level.ex_vectormulti]](forwardvector,30000));
	trace=bulletTrace(self.origin,endpoint, true, undefined);
	if(trace["fraction"] < 1 && trace["position"][2] > level.ex_mapArea_Min[2] - 500) endpoint = trace["position"];
		else endpoint = self.origin + ([[level.ex_vectormulti]](forwardvector,100));

	falltime = calcTime(self.origin, endpoint, speed);
	rotdone = "notdone";

	if(falltime > 1)
	{
		start_turn = 0;

		self moveto(endpoint,falltime);

		np = (pitch/(0.5/0.05));
		ny = (yaw/(0.5/0.05));
		nr = (roll/(falltime/0.05));

		for(i=0;i<falltime;i+=0.05)
		{
			if(i <= 0.5)
			{
				self.angles += (np,0,0);
				self.angles += (0,ny,0);
				self.angles += (0,0,nr);
			}
			else if(start_turn == 0)
			{
				start_turn = 1;
				self.angles += (0,0,nr);
			}

			playfx(level.ex_effect["plane_smoke"], self.origin);

			if(self.fire == 1) playfx(level.ex_effect["plane_smoke"], self.origin);

			wait 0.05;
		}
	}

	wait 0.05;

	self stoploopsound();

	if(isdefined(self.apsound))
	{
		self.apsound stopLoopSound();
		self.apsound delete();
	}

	if(isdefined(self.apdivesound))
	{
		self.apdivesound stopLoopSound();
		self.apdivesound delete();
	}

	// explosions
	hm = randomInt(2) + 1; // how many explosions, at least 1

	for(i = 0; i < 2;i++)
	{
		for(exp=0; exp < hm; exp++)
		{
			// play the incoming falling sound
			planecrashsfx[0] = "plane_explosion_1";
			planecrashsfx[1] = "plane_explosion_2";
			planecrashsfx[2] = "plane_explosion_3";
			pc = randomInt(planecrashsfx.size);
			self playsound(planecrashsfx[pc]);

			// do the damage
			if(level.ex_planes == 3)
				self thread extreme\_ex_utils::scriptedfxradiusdamage(self, undefined, "MOD_EXPLOSIVE", "plane_mp", level.ex_planecrash_radius, 500, 300, "plane_explosion", undefined, true, true, true);
	
			playfx(level.ex_effect["plane_smoke"], self.origin);
	
			if(exp != 2)
			{
				wait 0.3;
				wait randomFloat(1);
			}
			else
			{
				wait 0.3;
				wait randomFloat(2);
			}
		}
	}

	if(apteam == 0) level.ex_axisapinsky--;
		else level.ex_allieapinsky--;

	self planeCrashSmokeFX();
	self delete();
	level notify("ambplane_finished");
}

planeCrashSmokeFX()
{
	self thread extreme\_ex_utils::hotSpot(self.origin, 120, "MOD_EXPLOSIVE", "plane_mp");

	for(i = 0; i < 25; i++)
	{
		playfx(level.ex_effect["planecrash_fire"], self.origin);
		wait 0.5;
		playfx(level.ex_effect["planecrash_ball"], self.origin);
		wait 0.5;
	}

	self notify("endhotspot");
	self hide();
	thread planeCrashDelayedSmokeFX(self.origin);
}

planeCrashDelayedSmokeFX(position)
{
	for(i = 0; i < 25; i++)
	{
		playfx(level.ex_effect["planecrash_smoke"], position);
		wait 0.5;
		if(i < 15) playfx(level.ex_effect["planecrash_ball"], position);
		wait 0.5;
	}
}
