init(delay)
{
	self endon("killed_player");
	self endon("disconnect");

	if(self.ex_mortar_strike) return;

	self notify("end_mortar");
	wait(0.1);
	self endon("end_mortar");

	self.ex_mortar_strike = true;

	// wait the first
	if(!isDefined(delay)) delay = level.ex_rank_mortar_first;
	wait(delay);

	while(self.ex_mortar_strike)
	{
		// let them know the mortar strike is available
		self iprintlnbold(&"MORTAR_READY");
		self teamsound("morta_ready", 1);

		//set up the on screen icon
		self hudNotify();

		//monitor for binocular fire
		self thread waitForUse();

		// wait until they use mortars
		self waittill("mortar_over");

		if(level.ex_rank_wmdtype >= 1) break;
		self iprintlnbold(&"MORTAR_RELOAD");
		self teamsound("morta_reload", 3);
		// now wait for one interval
		wait(level.ex_rank_mortar_int + randomint(10));
	}

	// stop mortars
	self.ex_mortar_strike = false;
	self notify("mortar_over");
	self notify("end_mortar");
}

waitforuse()
{
	self endon("end_waitforuse");
	self endon("killed_player");

	for(;;)
	{
		self waittill("binocular_enter");
		self thread waitForBinocUse();
		self thread binocHintHud();
		wait .2;
	}
}

waitForBinocUse()
{
	// kill dupes
	self notify("binocular_exit");
	wait(0.1);
	self endon("binocular_exit");
	self endon("mortar_fired");
	self endon("killed_player");

	// wait for use button to be pressed
	calling = false;
	for(;;)
	{
		if(isPlayer(self) && self useButtonPressed() && !calling)
		{
			calling = true;
			self thread callradio();
			self waittill ("radiodone");
		}
		wait .01;
	}
}

callradio()
{
	self endon("killed_player");

	self iprintlnbold(&"MORTAR_RADIO_IN");

	targetPos = getTargetPosition();
	friendly = friendlyInstrikezone(targetPos);

	self teamSound("morta_firemission", 3.6);
	for(i = 1; i < 4; i++) self teamSound("morta_" + randomInt(8), 0.6);
	self teamSound("morta_pointfuse", 3);

	if(isDefined(targetPos) && isDefined(friendly) && friendly == false)
	{
		self iprintlnbold(&"MORTAR_FIRED");
		self teamsound("morta_shot", 3);

		// player has used weapon
		self.usedweapons = true;

		mortars = spawn("script_origin", targetPos);
		mortars thread fireBarrage(self);

		// clear hud icon
		self hudNotifyRemove();

		// clear hint icon
		if(isdefined(self.ex_binocular_hint)) self.ex_binocular_hint destroy();

		// notify threads
		self notify("end_waitforuse");
		self notify ("mortar_fired");
	}
	else if(!isDefined(targetpos) && !isDefined(friendly))
	{
		friendly = undefined;
		self iprintlnbold(&"MORTAR_NOT_VALID");
		self teamSound("morta_novalid", 3);
	}
	else if(isDefined(friendly) && friendly == true)
	{
		friendly = undefined;
		self iprintlnbold(&"MORTAR_FRIENDLY_WARNING");
		self teamSound("morta_frndly", 3);
	}
	else if(isDefined(targetpos) && !isDefined(friendly))
	{
		friendly = undefined;
		self iprintlnbold(&"MORTAR_TO_CLOSE_WARNING");
		self teamSound("morta_tooclose", 3);
	}

	self notify("radiodone");
}

getTargetPosition()
{
	startOrigin = self getEye() + (0,0,20);
	forward = anglesToForward(self getplayerangles());
	forward = [[level.ex_vectorscale]](forward, 100000);
	endOrigin = startOrigin + forward;

	trace = bulletTrace( startOrigin, endOrigin, false, self );
	if(trace["fraction"] == 1.0 || trace["surfacetype"] == "default") return (undefined);
		else return (trace["position"]);
}

fireBarrage(owner)
{
	// drop flare
	if(level.ex_rank_wmd_flare) playfx(level.ex_effect["flare_indicator"], self.origin);
	wait(1);

	// create mortar start position (surface level)
	shellStartPos = (level.ex_playArea_Min[0],level.ex_playArea_Min[1], 0);

	// number of mortars in barrage
	shellNumber = 6;

	// play firing sounds
	for(i = 0; i < shellNumber; i++ )
	{
		self thread firingSound();
		wait(.5);
	}

	// create mortar target positions
	shellTargetPos = [];
	for(i = 0; i < shellNumber; i++ )
		shellTargetPos[i] = calcShellPos(self.origin);

	self.mortarsGlobalDelay = 0;

	// fire mortars
	for (i = 0; i < shellNumber; i++ )
		self thread fireShell(owner, shellStartPos, shellTargetPos[i]);

	// wait for all mortars to explode
	shellImpacts = 0;
	while ( shellImpacts < shellNumber )
	{
		self waittill("mortar_shell_impact");
		shellImpacts++;
	}

	owner notify ("mortar_over");
	self delete();
}

calcShellPos(targetPos)
{
	shellPos = undefined;
	iterations = 0;

	while(!isDefined(shellPos) && iterations < 5)
	{
		shellPos = targetPos;
		angle = randomFloat(360);
		radius = randomFloat(level.ex_rank_mortar_radius);
		randomOffset = (cos(angle) * radius, sin(angle) * radius, 0);
		shellPos += randomOffset;
		startOrigin = shellPos + (0, 0, 800);
		endOrigin = shellPos + (0, 0, -2048);

		trace = bulletTrace( startOrigin, endOrigin, true, undefined );
		if(trace["fraction"] < 1.0) shellPos = trace["position"];
			else shellPos = undefined;

		iterations++;
	}

	if(!isDefined(shellPos)) shellPos = targetPos;
	return shellPos;
}

fireShell(owner, shellStartPos, shellTargetPos)
{
	// calculate the height of the mortar spawn point to let shells come in at a certain angle
	//shellAngle = 80;
	//shellDist = distance(shellTargetPos, shellStartPos);
	//shellHeight = int(shellDist * tan(shellAngle));
	//shellStartPos = (shellStartPos[0], shellStartPos[1], shellHeight);
	shellStartPos = (shellTargetPos[0], shellTargetPos[1], level.ex_mapArea_Max[2]);

	self.mortarsGlobalDelay += randomFloatRange( .5, 1.5 );
	wait(self.mortarsGlobalDelay);
	wait(randomFloatRange(1.5, 2.5));

	// show visible mortar
	shell = spawn("script_model", shellStartPos);
	shell setModel("xmodel/prop_stuka_bomb");
	shell.angles = vectorToAngles(vectorNormalize(shellTargetPos - shellStartPos));

	// Play incoming sound
	shell playSound("mortar_incoming");

	// calculate time in air (s) based on distance (m) and preferred mortar speed (m/s)!
	shellSpeed = 50;
	shellInAir = calcTime(shellStartPos, shellTargetPos, shellSpeed);

	// move visible mortar (correct target to slam shells into the ground, and for more realistic FX)
	shell moveTo(shellTargetPos + (0,0,-100), shellInAir);

	// wait for mortar to hit
	wait(shellInAir);

	shell shellImpact(owner);
	self notify("mortar_shell_impact");
}

shellImpact(owner)
{
	self playSound( "mortar_explosion");

	surfaceFx = calcImpactSurface(self.origin);
	if(isPlayer(owner))
		self thread extreme\_ex_utils::scriptedfxradiusdamage(owner, undefined, "MOD_GRENADE", "mortar_mp", level.ex_mortar_radius, 500, 350, "generic", surfaceFx, true, true, true);

	self hide();
	wait(1);
	self delete();
}

friendlyInStrikeZone(targetPos)
{
	// return if friendly fire check has been disabled
	if(level.ex_frndly == 0) return false;

	// dont need to check friendly if gametype is not teamplay
	if(!level.ex_teamplay) return false;

	if(!isDefined(targetPos)) return (undefined);

	if(distance(targetPos, self.origin) <= 1000) return (undefined);

	// check if players in the same team are in targetzone
	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
	{
		if(isPlayer(self) && isPlayer(players[i]))
		{
			if(players[i].sessionstate == "playing" && players[i].pers["team"] == self.pers["team"])
			{
				if(distance(targetpos, players[i].origin) <= 1000)
					return true;
			}
		}
	}
	return false;
}

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

calcImpactSurface(targetPos)
{
	startOrigin = targetPos + (0, 0, 800);
	endOrigin = targetPos + (0, 0, -2048);

	trace = bulletTrace(startOrigin, endOrigin, true, undefined);
	if(trace["fraction"] < 1.0) surface = trace["surfacetype"];
		else surface = "dirt";

	if(!isDefined(surface)) surface = "dirt";
	return surface;
}

firingSound()
{
	players = getentarray("player", "classname");
	for(i = 0; i < players.size; i++)
		players[i] playLocalSound("mortar_fire");
}

teamSound(aliasPart, waitTime)
{
	if (self.pers["team"] == "allies")
	{
		switch(game["allies"])
		{
			case "american": {
				self playLocalSound("us_" + aliasPart);
				wait(waitTime);
				break;
			}
			case "british": {
				self playLocalSound("uk_" + aliasPart);
				wait(waitTime);
				break;
			}
			default: {
				self playLocalSound("ru_" + aliasPart);
				wait(waitTime);
				break;
			}
		}
	}
	else
	{
		self playLocalSound("ge_" + aliasPart);
		wait(waitTime);
	}
}

hudNotify()
{
	self endon("killed_player");

	self hudNotifyRemove();

	self.mortar_available_icon = newClientHudElem(self);
	self.mortar_available_icon.alignX = "center";
	self.mortar_available_icon.alignY = "middle";
	self.mortar_available_icon.x = 120;
	self.mortar_available_icon.y = 390;
	self.mortar_available_icon.alpha = 1;
	self.mortar_available_icon setShader(game["mortar"], 32, 32);

	if(!isDefined(self.ex_binocular_hint))
	{
		self.ex_binocular_hint = newClientHudElem( self );
		self.ex_binocular_hint.alignX = "center";
		self.ex_binocular_hint.alignY = "middle";
		self.ex_binocular_hint.fontScale = 1;
		self.ex_binocular_hint.x = 320;
		self.ex_binocular_hint.y = 410;

		self.ex_binocular_hint.sort = 5;
		self.ex_binocular_hint setText(&"WMD_ACTIVATE_HINT");

		// do not show hint if planting a tripwire
		if(level.ex_tweapon)
		{
			if( !self.ex_plantwire && !self.ex_defusewire && !isDefined(self.ex_actimer) ||
				self [[level.ex_getstance]](false) != 2 && !isDefined(self.ex_actimer)) self.ex_binocular_hint.alpha = 1;
			else self.ex_binocular_hint.alpha = 0;
		}
		else self.ex_binocular_hint.alpha = 1;
	}
}

hudNotifyRemove()
{
	if(isDefined(self.mortar_available_icon)) self.mortar_available_icon destroy();
}

binocHintHud()
{
	self endon("binocular_exit");

	if(!isdefined(self.ex_binocular_hint))
	{
		self.ex_binocular_hint = newClientHudElem( self );
		self.ex_binocular_hint.alignX = "center";
		self.ex_binocular_hint.alignY = "top";
		self.ex_binocular_hint.fontScale = 1;
		self.ex_binocular_hint.x = 320;
		self.ex_binocular_hint.y = 425;
		self.ex_binocular_hint.alpha = 1;
		self.ex_binocular_hint.sort = 5;
	}

	self.ex_binocular_hint setText(&"WMD_MORTAR_HINT");
	self thread mortar_binocularhint_hud_destroy2();
}

mortar_binocularhint_hud_destroy()
{
	if(isDefined(self.ex_binocular_hint)) self.ex_binocular_hint destroy();
}

mortar_binocularhint_hud_destroy2()
{
	self endon("binocular_enter");
	self endon("killed_player");
	self waittill("binocular_exit");

	if(isDefined(self.ex_binocular_hint)) self.ex_binocular_hint destroy();
}
