
init()
{
	thread ww2x\_wwx_logfile::Log("Planes");

	level endon("wwx_stop_ambient_fx");

	lastapteam = 2;		// set to 2 so it won't run the first time

	while(!level.wwx_gameover)
	{
		wait 10; // give the planes an extra chance to finish

		players = getentarray("player", "classname");

		if(players.size < 1) continue;

		delay = (randomInt(level.wwx_planes_delay_max - level.wwx_planes_delay_min) + level.wwx_planes_delay_min) - 10;
		
		if(delay < 20) delay = 20;
		
		wait delay / 3;

		if(level.wwx_planes_flak && level.wwx_flakison)
		{
			level notify("stop_flak");
			level.wwx_flakison = false;
		}

		wait (delay / 3) * 2;

		// set up plane amount (normal)
		apcount = randomInt(level.wwx_planes_max - level.wwx_planes_min) + level.wwx_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.wwx_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.wwx_allieapinsky += apcount;
		else level.wwx_axisapinsky += apcount;
				
		apstpoint = [];
		apenpoint = [];
		apposinmap = [];

		if(level.wwx_air_raid) thread ww2x\_wwx_utils::playSoundLoc("air_raid",(0,0,0));

		if(level.wwx_planes_flak && !level.wwx_flakison)
		{
			for(flak=0;flak<level.wwx_flakfx;flak++)
				thread ww2x\_wwx_skyeffects::flakfx();

			wait 10;
		}
			
		for(i=0;i<apcount;i++)
		{
			if(randomInt(100) < 30)
			{
				x = level.wwx_playArea_Max[0] + randomInt(level.wwx_playArea_Width);
				y = level.wwx_playArea_Max[1] + randomInt(level.wwx_playArea_Length);
				z = level.wwx_mapArea_Max[2] - randomInt(200);
			}
			else
			{
				x = level.wwx_playArea_Min[0] + randomInt(level.wwx_playArea_Width);
				y = level.wwx_playArea_Min[1] + randomInt(level.wwx_playArea_Length);
				z = level.wwx_mapArea_Max[2] - randomInt(200);
			}

			// override height on maps with bad skyboxes
			if(level.wwx_currentmap == "mp_carentan" || level.wwx_currentmap == "mp_decoy" || level.wwx_currentmap == "mp_railyard" || level.wwx_currentmap == "mp_toujane") z = level.wwx_mapArea_PlaneZ - randomInt(50);
                     else if(level.wwx_planes_altitude) z = level.wwx_planes_altitude - randomInt(50);
                     else z = level.wwx_mapArea_Max[2] - randomInt(50);

			stenpos = getapsten((x,y,z),apflangle);
			stenpos2 = getapsten((stenpos[1]),apflangle);
			
			if(stenpos2[10] == 1) stenpos[1] = stenpos2[1];

			apstpoint[i] = stenpos[0];
			apenpoint[i] = stenpos[1];
			apposinmap[i] = (x,y,z);

			// create the plane
			wait randomInt(3) + 2;
			thread planestart(apflangle, apstpoint[i], apenpoint[i], apteam, apposinmap[i]);
		}
		
		// check for teamplay to keep things even
		if(level.wwx_teamplay) lastapteam = apteam;
	}
}

planestart(apflangle, apstpoint, apenpoint, apteam, apposinmap)
{
	thread ww2x\_wwx_logfile::Log("planestart");

	apmodel = [];
	apsoundchoice = [];

	if(apteam == 0)
	{
		// plane models
		apmodel[0] = "xmodel/vehicle_stuka_flying";
		apmodel[1] = "xmodel/vehicle_condor";

		// plane names
		apname[0] = &"VEHICLES_STUKA";
		apname[1] = &"VEHICLES_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";

		// plane names
		apname[0] = &"VEHICLES_SPITFIRE";
		apname[1] = &"VEHICLES_P51MUSTANG";

		// 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; // bomber

	plane = spawn("script_model", (0,0,0));
	plane setModel(apmodel[aprand]);
	plane hide();

	if(apteam == 0 && planetype == 0) plane.angles = plane.angles + (10,apflangle,0);
	else plane.angles = plane.angles + (0,apflangle,0);

	plane.origin = apstpoint;
	plane show();
	plane.identity = "plane";
	plane.name = apname[aprand];
	planecrash = false;
	randomcrash = false;
	isbomber = false;
	crashpos = (-1000,-1000,-2000);

	if(level.wwx_planes >= 2)
	{
		if(randomInt(100) < 40)
		{
			isbomber = true;
			planecrash = false;
			apspeed = randomInt(250) + 250;	
		}
	}

	if(randomInt(100) < 25) // 25% chance plane will crash
	{
		if(randomInt(100) < 50)
		{
			planecrash = true;
			isbomber = false;
			crashpos = apenpoint - (0,0,apenpoint[2]);
			apenpoint = crashpos;
		}
		else
		{
			randomcrash = true;
			planecrash = false;
		}
	}

	plane.crashpos = crashpos;
	plane.smoke = false;
	plane.playapdivesound = false;
	plane.health = 200 + randomInt(100);	// plane starting health	
	plane.smhealth = plane.health - 100;		// when planes health drops below this, turn on smoke!

	// set speed
	apspeed = randomInt(250) + 300; // fighters
	if(apteam == 0 && planetype == 1) apspeed = randomInt(250) + 200; // bombers

	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);

	//plane thread apdamagecalc(apteam,planetype);

	// flighttime
	flighttime = int(timespeedcalc(apspeed, apstpoint, apenpoint));
	plane moveto(apenpoint, flighttime);

	rollpos = undefined;
	rollneg = undefined;

	if(flighttime >= 4)
	{
		switch(randomInt(3))
		{
			case 0:	{ plane rotateroll(45,flighttime,3,1); rollpos = 1; break; }
			case 1: { plane rotateroll(-45,flighttime,3,1); rollneg = 1; break; }
		}
	}

	if(level.wwx_planes >= 2 && isbomber) plane thread bombsetup(flighttime, apteam, planetype);
	
	for(i=0;i<((flighttime/3)*2);i+=0.1)
	{
		if(planecrash)
		{
			if(!plane.smoke) plane.smoke = true;
			
			speed = apspeed + randomInt(50) + 50;
			plane airplanecrash(undefined, speed, apteam,planetype, crashpos, false);
			return;
		}

		if(planecrash && distance(plane.crashpos, plane.origin) < 3000 && !plane.playapdivesound)
		{
			plane.playapdivesound = true;
			plane.apdivesound playloopsound("plane_dive");
		}

		if(flighttime > (flighttime/2))
		{
			if(isdefined(rollpos)) plane rotateroll(-90,(flighttime/2),1,1);
			if(isdefined(rollneg)) plane rotateroll(90,(flighttime/2),1,1);
		}

		if(distance(level.wwx_playArea_Centre, plane.origin) < 3000 && randomcrash)
		{
			playfx(level.wwx_effect["flak_flash"], plane.origin - (0, 200, 0));
			plane playsound("plane_explosion_2");
			wait 0.2;
			playfx(level.wwx_effect["flak_smoke"], plane.origin - (0, 200, 0));
			wait 0.2;
			playfx(level.wwx_effect["flak_dust"], plane.origin - (0, 200, 0));
			wait 0.5;			
			plane.apdivesound playloopsound("plane_dive");
			playfx(level.wwx_effect["plane_explosion"], plane.origin);
			plane playsound("plane_explosion_2");
			wait 0.5;
			playfx(level.wwx_effect["plane_explosion"], plane.origin);
			speed = randomInt(200) + 200;
			plane airplanecrash(undefined, speed, apteam,planetype, undefined, true);
			return;
		}
		
		if(plane.smoke) playfx(level.wwx_effect["plane_smoke"], plane.origin);
		wait 0.05;
		if(plane.smoke) playfx(level.wwx_effect["plane_smoke"], plane.origin);
		wait 0.05;
	}

	rolltime = flighttime / 3;

	// has survived?, victory roll for fighters and bank for bombers but not every time!
	if(!rolltime <= 0)
	{
		if(planetype != 1)
		{
			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;
			}
		}
		else
		{
			switch(randomInt(5))
			{
				case 0:	{ plane rotateroll(45,rolltime,rolltime/2,rolltime/2); break; }
				case 1: { plane rotateroll(-45,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.wwx_axisapinsky--;
	else level.wwx_allieapinsky--;

	if(isdefined(plane)) plane delete();
}

getapsten(startpos, angle)
{
	thread ww2x\_wwx_logfile::Log("getapsten");

	forwardvector = anglestoforward( (0,angle,0) );
	backpos = startpos + ([[level.wwx_vectormulti]](forwardvector,-30000));
	frontpos = startpos + ([[level.wwx_vectormulti]](forwardvector,30000));
	fronthit = 0;

	trace = bulletTrace(startpos,backpos,false,undefined);
	if(trace["fraction"] != 1) start = trace["position"];
	else start = backpos;

	trace = bulletTrace(startpos,frontpos,false,undefined);
	if(trace["fraction"] != 1)
	{
		endpoint = trace["position"];
		font_hit = 1;
	}
	else endpoint = frontpos;

	startpos = start + ([[level.wwx_vectormulti]](forwardvector,-3000));
	endpoint = endpoint + ([[level.wwx_vectormulti]](forwardvector,3000));
	stenpos[0] = startpos;
	stenpos[1] = endpoint;
	stenpos[10] = fronthit;
	return stenpos;
}

airplanecrash(attacker, speed, apteam,planetype, crashpos, forced)
{
	thread ww2x\_wwx_logfile::Log("airplanecrash");

	self.fire = 1;

	if(!isdefined(attacker)) self.fire = 0;
	else if(randomInt(100) > 50) self.fire = 1;

	angle = self.angles;
	
	if(forced) pitch = randomInt(25) + 25;
	else pitch = randomInt(4) + 4;

	yaw = randomInt(50)  - 25;
	roll = 200 - randomInt(400);
	angle_start = angle + (pitch,yaw,0);
	forwardvector = anglestoforward(angle_start);              

	if(isdefined(crashpos))
	{
		if(randomInt(100) < 50)
			endpoint = crashpos;
		else
		{
			x = int((crashpos[0]) / 8);
			y = int((crashpos[1]) / 8);
			
			endpoint = crashpos - (x, y, 100);
		}
	}
	else
	{
		endpoint = self.origin + ([[level.wwx_vectormulti]](forwardvector,30000));
	
		trace=bulletTrace(self.origin,endpoint, true, undefined);
		if(trace["fraction"] < 1 && trace["position"][2] > level.wwx_mapArea_Min[2] - 500) endpoint = trace["position"];
		else endpoint = self.origin + ([[level.wwx_vectormulti]](forwardvector,100));
	}

	falltime = timespeedcalc(speed, self.origin, endpoint);
	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.wwx_effect["plane_smoke"], self.origin);

			if(self.fire == 1) playfx(level.wwx_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 sound 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.wwx_planes == 3)
				self thread ww2x\_wwx_utils::scriptedfxradiusdamage(self, undefined, "MOD_EXPLOSIVE", "plane_mp", level.wwx_planecrash_radius, 500, 300, "plane_explosion", undefined, true, true, true);
	
			playfx(level.wwx_effect["plane_smoke"], self.origin);
	
			if(exp != 2)
			{
				wait 0.3;
				wait randomFloat(1);
			}
			else
			{
				wait 0.3;
				wait randomFloat(2);
			}
		}
	}

	// points system ( 2 points for fighters )
	if(isdefined(attacker))
	{
		if(isPlayer(attacker))
		{
			if(apteam == 0)
				spteam = "axis";
			else
			{
				spteam = "allies";
				planetype = planetype + 3;
			}
			
			if(spteam == attacker.pers["team"] && level.wwx_teamplay)
			{
				iprintln(level.adminname + "^7: ^8" + attacker.name + "^2 has shot down his own teams " + self.name + "!");

				if(apteam == 0 && planetype < 2 || apteam == 1 && planetype < 5) attacker setpoints(-2);
				else attacker setpoints(-1);
						
			}
			else	if(spteam != attacker.pers["team"] || !level.wwx_teamplay)
			{
				txt = getnation(planetype);
				iprintln(level.adminname + "^7: ^8" + attacker.name + "^2 has shot down " + txt + " " + self.name + "!");

				if(apteam == 0 && planetype < 2 || apteam == 1 && planetype < 5) attacker setpoints(2);
				else attacker setpoints(1);
			}
		}
	}

	if(apteam == 0) level.wwx_axisapinsky--;
	else level.wwx_allieapinsky--;

	level.wwx_planescrashed++;
	if(level.wwx_planescrashed > 4)
	{
		self hide();
		self delete();
		return;
	}

	self planeCrashSmokeFX();
	level.wwx_planescrashed--;
	self delete();
}

planeCrashSmokeFX()
{
	self thread ww2x\_wwx_utils::hotSpot(self.origin, 120, "MOD_EXPLOSIVE", "plane_mp");

	for(i = 0; i < 25; i++)
	{
		playfx(level.wwx_effect["planecrash_fire"], self.origin);
		wait 0.5;
		playfx(level.wwx_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.wwx_effect["planecrash_smoke"], position);
		wait 0.5;
		if(i < 15) playfx(level.wwx_effect["planecrash_ball"], position);
		wait 0.5;
	}
}

setpoints(points)
{
	thread ww2x\_wwx_logfile::Log("setpoints");

	if(isplayer(self))
	{
		if(level.wwx_currentgt == "ctf" ||  level.wwx_currentgt == "lts" || level.wwx_currentgt == "sd") self.pers["score"] += points;
		else self.score += points;
	}

	if(level.wwx_teamplay)
	{
		teamscore = getTeamScore(self.pers["team"]);
		teamscore += points;
		setTeamScore(self.pers["team"], teamscore);
	}
}

apdamagecalc(apteam,planetype)
{
	thread ww2x\_wwx_logfile::Log("apdamagecalc");
	level endon("map_ended");

	//self settakedamage(true);
	who = undefined;

	while(self.health > 0)
	{
		self waittill ("damage", dmg, who, dir, point, mod);

		if(!isPlayer(who))
			continue;

		if(mod == "MOD_PISTOL_BULLET" ||
		mod == "MOD_RIFLE_BULLET" ||
		mod == "MOD_PROJECTILE" ||
		mod == "MOD_PROJECTILE_SPLASH" ||
		mod == "MOD_GRENADE" ||
		mod == "MOD_GRENADE_SPLASH" ||
		mod == "MOD_ARTILLERY" ||
		mod == "MOD_ARTILLERY_SPLASH" ||
		mod == "MOD_FLAME")
		{
			self.health -= dmg;

			if(self.health <= self.smhealth)
				self.smoke = 1;
		}
	}

	if(apteam == 0) self notify("axisplane_done");
	if(apteam == 1) self notify("allieplane_done");

	speed = randomInt(150) + 150;
	self airplanecrash(who, speed, apteam,planetype);
	wait 1;

	if(isdefined(self)) self delete();
	return;
}

// bomb routines
bombsetup(time, apteam, planetype)
{
	wait randomInt(time - int(time/2)) + 1;

	bombcount = 0;
	bombno = randomInt(4) + 4;

	while(bombcount < bombno)
	{
		self thread dropthebombs(time, apteam, planetype);
		bombcount++;
		wait 0.75;
	}
}

dropthebombs(time, apteam, planetype)
{
	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.wwx_vectormulti]](forwardvector,360));

	// get the impact point
	trace = bulletTrace(startpoint,(endorigin[0],endorigin[1],endorigin[2] - 2048), true, self);                   
	if(trace["fraction"] < 1) endorigin = trace["position"];
	else 	endorigin = (endorigin[0],endorigin[1], level.wwx_mapArea_Min[2]);

	// bomb falltime
	falltime = timespeedcalc(350, startpoint, endorigin);
	if(falltime <= 0.1) 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.wwx_planes == 3)
		bomb thread ww2x\_wwx_utils::scriptedfxradiusdamage(bomb, undefined, "MOD_EXPLOSIVE", "planebomb_mp", level.wwx_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();
}

timespeedcalc(speed,startpoint,endpoint)
{
	// do not allow negative values
	if(speed < 1)
		return 0.1;

	abstand = distance(startpoint,endpoint);
	falltime = (abstand/speed)/4;

	// do not allow negative values
	if(falltime < 0) falltime = 0.1;

	return falltime;
}

getnation(planetype)
{
	txt ="";

	switch(planetype)
	{
		case 0:
			txt = "a german";
			break;

		case 1:
			txt = "an allied";
			break;
	}

	return txt;
}