//=====================================================================
// NemesisWINGSvX.
//      ""(§)FrÅgÊd(§)""
//               **Monarch**
//
//              555 ---===CrAzYBoNeS===--- 555
//          Boppolis_The_Dog
//
//
// Thank you Al McElrath for SLV2.
//=====================================================================
/** HUD overlay when piloting. Inserted as a HUD mutator at
	launch.
	To anyone reading this: This is sludge layered upon sludge. No
	attempt has been made to make it readable or configurable. For the
	next version...
*/
class SLHUD extends SLMutator config (NemesisWINGSvX);

// IMPORTS
//
/*#exec TEXTURE IMPORT NAME=CannonsIc FILE=NXWeaponsHUD\CannonsIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=CannonsSelect FILE=NXWeaponsHUD\CannonsSelect.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=DropNukeIc FILE=NXWeaponsHUD\DropNukeIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=FlashIc FILE=NXWeaponsHUD\FlashIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=HeatTargetIc FILE=NXWeaponsHUD\HeatTargetIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=HeatTargetRearIc FILE=NXWeaponsHUD\HeatTargetRearIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=MissileIc01 FILE=NXWeaponsHUD\MissileIc01.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=MissileIc02 FILE=NXWeaponsHUD\MissileIc02.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=MissileIc03 FILE=NXWeaponsHUD\MissileIc03.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=MissileIc04 FILE=NXWeaponsHUD\MissileIc04.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=MissilesSelect FILE=NXWeaponsHUD\MissilesSelect.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=NormalNukeIc FILE=NXWeaponsHUD\NormalNukeIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=NXJetIcon FILE=NXWeaponsHUD\NXJetIcon.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=RearIc01 FILE=NXWeaponsHUD\RearIc01.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=RearIc02 FILE=NXWeaponsHUD\RearIc02.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=RearIc03 FILE=NXWeaponsHUD\RearIc03.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=RearIc04 FILE=NXWeaponsHUD\RearIc04.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=RearMissilesSelect FILE=NXWeaponsHUD\RearMissilesSelect.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=SeekIc01 FILE=NXWeaponsHUD\SeekIc01.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=SeekIc02 FILE=NXWeaponsHUD\SeekIc02.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=SeekMissilesSelect FILE=NXWeaponsHUD\SeekMissilesSelect.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=SeekNukeIc FILE=NXWeaponsHUD\SeekNukeIc.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=SpecialSelected FILE=NXWeaponsHUD\SpecialSelected.bmp GROUP=Icons MIPS=OFF
#exec TEXTURE IMPORT NAME=NXJetFuelSys FILE=NXWeaponsHUD\NXJetFuelSys.bmp GROUP=Icons MIPS=OFF*/

#exec TEXTURE IMPORT NAME=vXIcon FILE=vXIcon.bmp GROUP=Icons MIPS=OFF

#exec OBJ LOAD FILE=Textures\NXWeaponsHUD.utx PACKAGE=NemesisWINGSvX.NXWeaponsHUD

#exec OBJ LOAD FILE=..\Textures\SLV2Textures.utx PACKAGE=SLV2Textures

// DATA
//

var StrangeShell sl;                // The controller.
var() color col1;                   // Main HUD color.
var() color col2;                   // Bluish color for the gauges.
var() color col3;                   // White color for debugging, etc.
var() color col4;                   // Reddish color to draw the keys in.
var() float lucent;                 // Factor to lighten some parts of the HUD.
var() float fade;                   // Fade time in seconds for the reticule.
var() float warnBlink;              // Timer rate for warning blink.
var() float warnLvl;                // Warnings go off at this level.
/* Various fonts.
*/
var Font font, lgFont;
var Font debugFont;

var() float u2m;

var bool bInit;
var float screenFade;               // Screen (green) fades in.

//var bool in;                      // Fading in or out?
//var float reticuleFade;
//var float hudFadeIn;

var float shakemag;                 // Magnitude of shaking, in pixels.
var int shakex;                     // For afterburner shakes.
var int shakey;                     // For afterburner shakes.
var() float shakeRate;              // Rate at which shaking subsides.

var int skewx, skewy;

var bool bWarned;                   // Single alarm bell for fuel low with cores.
var bool bAlarm;                    // Flips the color in timer().

var() config bool bShowKeys;        // Show the keys initially?
var float keysFade;                 // Fading out.
var int keysSlide;                  // Slide in.
var() string keys[6];               // Key texts.
var float keymax;                   // Max key string length.
var int keysUp;                     // If they don't fit on the right, knock them up a bit.

/** Level gauges.
*/
var HUDLevel throLvl, veloLvl, hullLvl, fuelLvl, coreLvl;
var int retw, reth;
var float retScale;
var int indw, indh;

var int slide;                      // Used for sliding in and out of shoot mode.

//var bool bNoShoot;
//var() color noShootColor;
//var float nsFade;

var Canvas c;
var Stylus yy;

var Util u;

//Weaponry system variables
var float WeapFade1, WeapFade2, WeapFade3;
var bool bWeapRise1, bWeapRise2;

struct NMissilesInfo
{
	var bool bThere;
	var float BlinkTime;
	var texture IcTex;
};

struct SMissilesInfo
{
	var bool bThere;
	var float BlinkTime;
	var texture IcTex;
};

struct RMissilesInfo
{
	var bool bThere;
	var float BlinkTime;
	var texture IcTex;
};

var() NMissilesInfo NormMInfo[4];
var() SMissilesInfo SeekMInfo[2];
var() RMissilesInfo RearMInfo[4];

var() texture WeapSelTex[5];

var color WhiteC, BlackC;

var bool SpecialbThere;
var float SpecialBlink;

var texture SpecialIc[6];

var() texture NXVisualIcon;


// METHODS
//

function postBeginPlay() {
	local Font lg, sm;

	u = spawn(Class'Util', self);
	u.setDebugLevel(DL_Verbose);

	u.debug("postBeginPlay()");


	sl = StrangeShell(owner);

	sl.HUD = self;
	ho = PlayerPawn(sl.getPilot());


	register();

	// Gunner may get a (takeover) HUD if the rider ejects.
	/* Takeovers off for now.
	if (ho == none && sl.gunner != none) {
		ho = PlayerPawn(sl.gunner);
	}
	*/

	//reticuleFade = 0.0;
	//in = true;

	screenFade = 0.0;
	slide = -1;

	lg = class'Fontlib'.static.getFont(FS_Slick, true);
	sm = class'Fontlib'.static.getFont(FS_Slick, false);

	font = sm;
	lgFont = class'Fontlib'.static.getFont(FS_Title);
	debugFont = class'Fontlib'.static.getFont(FS_Normal);

	throLvl = spawn(class'HUDLevel', self);
	throLvl.init(0, "THRO", "%", lg, sm);

	veloLvl = spawn(class'HUDLevel', self);
	veloLvl.init(0, "VELO", "m/s", lg, sm, throLvl);

	hullLvl = spawn(class'HUDLevel', self);
	hullLvl.init(0.20, "HULL", "%", lg, sm, veloLvl);

	fuelLvl = spawn(class'HUDLevel', self);
	fuelLvl.init(0.20, "FUEL", "", lg, sm, hullLvl);
	//fuelLvl.label2 = "CORES";

	coreLvl = spawn(class'HUDLevel', self);
	coreLvl.init(0, "CORES", "", lg, sm, fuelLvl);
	coreLvl.bNoFitLabels = true;


	yy = spawn(Class'Stylus', self);
}


function init(Canvas c) {
	local int x, y;
	local int w, h;

	u.debug("init()");

	// Only slide in from first init() call.
	if (slide == -1) {
		slide = c.clipx;
		keysSlide = -1;
	}

	/*
	if (clipx < 640) {
		retw = 64;
		reth = 24;
	} else if (clipx <= 800) {
		retw = 128;
		reth = 32;
	} else {
		retw = 256;
		reth = 48;
	}
	*/



	retw = max(128, c.clipx * 0.16);
	reth = retw * 0.25;

	indw = 70; // Reset in drawIndicators().
	indh = reth - 13;

	x = (c.clipx + retw) * 0.5;
	y = (c.clipy - reth) * 0.5 + 2;

	w = reth; //32;
	h = reth - 4; //28;

	throLvl.position(x, y, w, h);
	veloLvl.position(x + (w + 1) * 1, y, w, h);
	hullLvl.position(x + (w + 1) * 2, y, w, h);
	fuelLvl.position(x + (w + 1) * 3, y, w, h);
	coreLvl.position(x + (w + 1) * 4, y, w / 4, h);

	bInit = true;
}


function Reset (optional StrangeShell newsl)
{
	if ( newsl != None )
	{
		SetOwner(newsl);
	}
	sl=StrangeShell(Owner);
	sl.HUD=self;
	ho=PlayerPawn(sl.getPilot());
	if ( (newsl == None) ||  !U.UTPureOn(ho) )
	{
		Register();
	}
	screenFade=0.00;
	Slide=-1;
	bInit=False;
	GotoState('Norm');
}
auto state Norm {
	function beginState() {
		u.debug("Norm:beginState()");
		bAlarm = false;
		bWarned = false;
	}
}


state Warning {
	function beginState() {
		u.debug("Warning:beginState()");
		alarm();
		setTimer(warnBlink, false);
	}


	function timer() {
		alarm();
	}

	function alarm() {
		u.debug("Warning:alarm(): bAlarm: " $ bAlarm $ " alarms: fuel: " $ fuelLvl.alarmOn() $ " hull: " $ hullLvl.alarmOn());

		if (fuelLvl.alarmOn() || hullLvl.alarmOn()) {
			bAlarm = !bAlarm;

			if (bAlarm) {
				// If we're low on fuel and we have cores, only play the alarm once.
				if (!bWarned || hullLvl.alarmOn() || coreLvl.realLvl == 0) {
					ho.playSound(sl.warnSound, SLOT_None, 1.0);
					 bWarned = true;
				}
			}

			setTimer(warnBlink, false);
		} else {
			gotoState('Norm');
		}
	}
}


/** Destroys us.
*/
function bool noMore() {
	if (sl == none || sl.getPilot() == none || sl.bDestroyed ) {
		u.debug("noMore(): destroying");
		destroy();
		return true;
	}

	return false;
}


function postRender(Canvas c) {
	local int i;
	local vector x, y, z;
	local float Scale;
	local byte bx;
	local int JetDrawX, JetDrawY, SelYIni;
	local float SelTextX, SelTextY, OldSeltTextY;
	local string SelText;
	local byte DarkVal, BrightVal;

	// Screen center point.
	local int pods;
	local string vstr;
	local float xl, yl;

	if (noMore())
		return;

	// Store the canvas! We use it throughout, without passing it
	// between functions.
	self.c = c;

	// Behind view? No HUD.
	if (ho.bBehindView)
		return;

	// Takeover HUD? Don't need to be init'ed.
	/* Off for now.
	if (ho == sl.gunner) {
		yy.setCanvas(c);
		c.font = lgFont;

		// Fade the last second.
		c.drawColor = col4 * fmin(1.0, sl.toTime);
		vstr = "EMERGENCY TAKEOVER IN " $ left(sl.toTime, 3);

		c.textSize(vstr, xl, yl);
		yy.drawFrame(yy.cx - 2, yy.cy - 82, xl + 4, yl + 2, 1, true, true);
		c.setPos(yy.cx, yy.cy - 80);
		yy.drawText(vstr);

		// Kind of a hack, but not bad.
		//reinit();
		return;
	}
	*/

	// setCanvas returns true on a resize.
	if (yy.setCanvas(c) || !bInit)
		init(c);

	// Total commitment!
	if (sl.bMarchPlaying) {
		col1 = col3;
	} else {
		col1 = default.col1;
	}

	// TAKE THIS OUT LATER. FIX.
	/*
	c.setPos(100, 200);
	c.font = debugFont;
	c.drawText("dot dot: " $ normal(vector(sl.getPilot().viewRotation)) dot normal(sl.velocity));
	c.drawText("dyaw: " $ (sl.getPilot().viewRotation.yaw & 65535) - (rotator(sl.velocity).yaw & 65535));
	*/

	c.style = ERenderStyle.STY_Translucent;

	// No need to draw the HUD if it's off screen.
	if ((sl.bShootMode || sl.getPilot()  != ho) && slide == yy.clipx) {

		return;
	}

	// Visor is high detail only.
	if (level.bHighDetailMode) {
		c.drawColor = col3 * 0.7;
		yy.setPos(yy.cx - retw / 2.0 - indw - 40, yy.cy - (reth * 2.0) / 2.0);
		c.style = ERenderStyle.STY_Modulated;
		c.drawRect(Texture'SLV2Textures.slhud.visor', yy.clipx - c.curx, reth * 2.0);
	}

	if (level.bHighDetailMode) {
		c.style = ERenderStyle.STY_Translucent;
	} else {
		c.style = ERenderStyle.STY_Normal;
	}

	if (Class'Util'.default.bExpires) {
		c.drawColor = col3 * screenFade;
		vstr = "NOT FOR PUBLIC RELEASE. AUTHORIZED USE ONLY. " $ Class'Util'.static.getVersionString();
		c.font = debugFont;
		c.textSize(vstr, xl, yl);
		yy.setPos(yy.clipx - (6 + xl), yy.cy + reth / 2 + 4);
		yy.drawText(vstr);
	}

	// Draw the hijacked keys.
	if (bShowKeys)
		drawKeys();

	// Indicator lights!
	drawIndicators(yy.cx - retw / 2 - indw, yy.cy + reth / 2.0 - indh);
	drawHRot(yy.cx - retw / 2 - indw, yy.cy - reth / 2.0);
	//drawVRot(yy.cx - retw / 2 - indw - 32, yy.cy - reth / 2.0);


	// The levels get their first color choice from the existing
	// canvas color. Need to set it here.
	c.drawColor = col1;

	// Throttle level.
	throLvl.render(yy);
	veloLvl.render(yy);
	hullLvl.render(yy);
	fuelLvl.render(yy);

	if (sl.fc != none && sl.fc.getAmmo() > 0) {
		// Normally this would fuck things up, but we're the last gauge.
		c.drawColor = col2;
		coreLvl.render(yy);
	}

	drawReticule(yy.cx - retw / 2.0, yy.cy - reth / 2.0);


	// Targets!
	drawTargets();

	drawLogo(yy, yy.cx - retw / 2 - indw, yy.cy - reth / 2);

	
	//************************************************
	//New weaponry hud system (by Feralidragon)
	//************************************************

	if (!sl.bShootMode)
	{
		c.Reset();
		//Scale = c.ClipX/640;
		Scale = 1;
		//c.Style = ERenderStyle.STY_Translucent;
		c.Style = ERenderStyle.STY_Normal;

		JetDrawX = 256 + shakex;
		JetDrawY = 256 + shakey;
		
		//Draw Jet
		if (sl.bSeeJetView)
		{
		//c.DrawColor = WhiteC;
		c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);


		if ((sl.armor / sl.default.armor) < 0.40)
		{
			c.DrawColor.R = 255;
			c.DrawColor.G = WeapFade2 * 127 / 1.5;
			c.DrawColor.B = WeapFade2 * 127 / 1.5;
		}
		else if ((sl.armor / sl.default.armor) < 0.70)
		{
			c.DrawColor.R = 255;
			c.DrawColor.G = (WeapFade2 * 127 / 1.5) + 128;
			c.DrawColor.B = (WeapFade2 * 127 / 1.5) + 64;
		}

		c.DrawIcon(Texture'NXJetIcon', Scale);

		//Draw engines in case of low fuel
		c.DrawColor = WhiteC;

		if (bWarned)
		{
			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawColor.R = 255;
			c.DrawColor.G = WeapFade3 * 255 / 1.5;
			c.DrawColor.B = WeapFade3 * 255 / 1.5;
			c.DrawIcon(Texture'NXJetFuelSys', Scale);
		}
		else if (sl.bMarchPlaying)
		{
			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawColor.G = 255;
			c.DrawColor.R = WeapFade1 * 255 / 0.2;
			c.DrawColor.B = WeapFade1 * 255 / 0.2;
			c.DrawIcon(Texture'NXJetFuelSys', Scale);
		}
		}

		if (sl.bSeeWeaponsView)
		{
		//Draw cannons
		c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
		c.DrawColor = BlackC;
		c.DrawColor.G = 192;
		c.DrawIcon(Texture'CannonsIc', Scale);

		//Draw Normal Missiles
		For (bx=0; bx<4; bx++)
		{
			c.DrawColor = WhiteC;

			if (bx < sl.NormMissilesN)
			{
				c.DrawColor = BlackC;

				if (bx < sl.NormCmcX)
					c.DrawColor.B = 255;
				else if (NormMInfo[bx].bThere && bx >= sl.NormCmcX)
				{
					NormMInfo[bx].bThere = False;
					NormMInfo[bx].BlinkTime = 2.0;
				}
				else if (NormMInfo[bx].BlinkTime > 0)
				{
					c.DrawColor.B = 255;
					c.DrawColor.R = WeapFade1 * 255 / 0.2;
					c.DrawColor.G = WeapFade1 * 255 / 0.2;
				}
				else
					c.DrawColor = WhiteC;
			}

			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawIcon(NormMInfo[bx].IcTex, Scale);
		}

		//Draw Seek Missiles
		For (bx=0; bx<2; bx++)
		{
			c.DrawColor = WhiteC;

			if (bx < sl.SeekMissilesN)
			{
				c.DrawColor = BlackC;

				if (bx < sl.SeekCmcX)
					c.DrawColor.G = 255;
				else if (SeekMInfo[bx].bThere && bx >= sl.SeekCmcX)
				{
					SeekMInfo[bx].bThere = False;
					SeekMInfo[bx].BlinkTime = 2.0;
				}
				else if (SeekMInfo[bx].BlinkTime > 0)
				{
					c.DrawColor.G = 255;
					c.DrawColor.R = WeapFade1 * 255 / 0.2;
					c.DrawColor.B = WeapFade1 * 255 / 0.2;
				}
				else
					c.DrawColor = WhiteC;
			}

			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawIcon(SeekMInfo[bx].IcTex, Scale);
		}

		//Draw Rear Missiles
		For (bx=0; bx<4; bx++)
		{
			c.DrawColor = WhiteC;

			if (bx < sl.RearMissilesN)
			{
				c.DrawColor = BlackC;

				if (bx < sl.RearCmcX)
					c.DrawColor.B = 255;
				else if (RearMInfo[bx].bThere && bx >= sl.RearCmcX)
				{
					RearMInfo[bx].bThere = False;
					RearMInfo[bx].BlinkTime = 2.0;
				}
				else if (RearMInfo[bx].BlinkTime > 0)
				{
					c.DrawColor.B = 255;
					c.DrawColor.R = WeapFade1 * 255 / 0.2;
					c.DrawColor.G = WeapFade1 * 255 / 0.2;
				}
				else
					c.DrawColor = WhiteC;
			}

			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawIcon(RearMInfo[bx].IcTex, Scale);
		}

		//Draw Special Item (Nuke or countermeasure)
		c.DrawColor = WhiteC;

		if (sl.SpecialID > 0)
		{
			c.DrawColor = BlackC;

			if (sl.SpecialCount > 0)
			{
				c.DrawColor.G = 255;
				c.DrawColor.B = 255;
			}
			else if (SpecialbThere && sl.SpecialCount <= 0)
			{
				SpecialbThere = False;
				SpecialBlink = 2.0;
			}
			else if (SpecialBlink > 0)
			{
				c.DrawColor.B = 255;
				c.DrawColor.G = 255;
				c.DrawColor.R = WeapFade1 * 255 / 0.2;
			}
			else
				c.DrawColor = WhiteC;

			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawIcon(SpecialIc[sl.SpecialCarryN], Scale);
		}
		else
		{
			c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
			c.DrawIcon(Texture'NormalNukeIc', Scale);
		}

		//Draw selected weapon icon
		c.DrawColor.R = 255;
		c.DrawColor.B = 0;
		c.DrawColor.G = 255;

		c.SetPos(c.ClipX - JetDrawX*Scale, c.ClipY - JetDrawY*Scale);
		c.DrawIcon(WeapSelTex[sl.WeapSelected], Scale);
		}

	
		//Draw text relating to weapon selected
		if (sl.bSeeSelectTextView)
		{
		//c.Font = class'Fontlib'.static.getFont(FS_Slick, false);
		c.Font = class'Fontlib'.static.getFont(FS_Title, False);
		c.Style = ERenderStyle.STY_Translucent;
		SelYIni = 64;
		DarkVal = 90;
		BrightVal = 255;

		For (bx=0; bx<5; bx++)
		{
			c.DrawColor = BlackC;

			if (bx == 0)
			{
				if (sl.WeapSelected == 0)
					c.DrawColor.G = BrightVal;
				else
					c.DrawColor.G = DarkVal;

				if (Class'NullWeapon'.default.UseMachineGunsCannonsStyle)
					SelText = "Machine Guns [infinite ammo]";
				else
					SelText = "Pulse Cannons [infinite ammo]";
			}
			else if (bx == 1)
			{
				if (sl.WeapSelected == 1)
				{
					if (sl.NormCmcX > 0)
						c.DrawColor.G = BrightVal;
					else
						c.DrawColor.R = BrightVal;
					
				}
				else
				{
					if (sl.NormCmcX > 0)
						c.DrawColor.G = DarkVal;
					else
						c.DrawColor.R = DarkVal;
				}

				SelText = "Normal Missiles ["$int(sl.NormCmcX)$" remaining]";
			}
			else if (bx == 2)
			{
				if (sl.WeapSelected == 2)
				{
					if (sl.SeekCmcX > 0)
						c.DrawColor.G = BrightVal;
					else
						c.DrawColor.R = BrightVal;
					
				}
				else
				{
					if (sl.SeekCmcX > 0)
						c.DrawColor.G = DarkVal;
					else
						c.DrawColor.R = DarkVal;
				}

				SelText = "Seeking Missiles ["$int(sl.SeekCmcX)$" remaining]";
			}
			else if (bx == 3)
			{
				if (sl.WeapSelected == 3)
				{
					if (sl.RearCmcX > 0)
						c.DrawColor.G = BrightVal;
					else
						c.DrawColor.R = BrightVal;
					
				}
				else
				{
					if (sl.RearCmcX > 0)
						c.DrawColor.G = DarkVal;
					else
						c.DrawColor.R = DarkVal;
				}

				SelText = "Rear Missiles ["$int(sl.RearCmcX)$" remaining]";
			}
			else if (bx == 4)
			{
				if (sl.WeapSelected == 4)
				{
					if (sl.SpecialCount > 0)
					{
						c.DrawColor.G = BrightVal;
						SelText = "[available]";
					}
					else
					{
						c.DrawColor.R = BrightVal;
						SelText = "[unavailable]";
					}

				}
				else
				{
					if (sl.SpecialCount > 0)
					{
						c.DrawColor.G = DarkVal;
						SelText = "[available]";
					}
					else
					{
						c.DrawColor.R = DarkVal;
						SelText = "[unavailable]";
					}
				}

				if (sl.SpecialID == 1)
					SelText = "Seeking Nuclear Missile "$SelText;
				else if (sl.SpecialID == 2)
					SelText = "Normal Nuclear Missile "$SelText;
				else if (sl.SpecialID == 3)
					SelText = "Dropable Nuclear Missile "$SelText;
				else if (sl.SpecialID == 4)
					SelText = "Flash Device "$SelText;
				else if (sl.SpecialID == 5)
					SelText = "Dropable Heat Decoy "$SelText;
				else if (sl.SpecialID == 6)
					SelText = "Rear Impulse Heat Decoy "$SelText;
			}

			c.StrLen(SelText, SelTextX, SelTextY);
			c.SetPos(c.ClipX/2 - SelTextX/2 + Shakex, c.ClipY/2 + SelYIni*Scale + OldSeltTextY + Shakey);
			OldSeltTextY += (SelTextY + 2);
			c.DrawText(SelText);
		}
		}

		//Missile Locked
		if (sl.bSeeLockedNukeWarn)
		{
		if (sl.bNukeLocked || sl.bMissileLocked)
		{
			if (sl.bNukeLocked)
				SelText = "! INCOMING LOCKED NUCLEAR MISSILE !";
			else
				SelText = "! INCOMING LOCKED SEEKING MISSILE !";

			c.DrawColor = BlackC;
			c.DrawColor.R = WeapFade1 * 255 / 0.2;
			c.Font = class'Fontlib'.static.getFont(FS_Title, True);
			c.Style = ERenderStyle.STY_Translucent;
			c.StrLen(SelText, SelTextX, SelTextY);
			c.SetPos(c.ClipX/2 - SelTextX/2 + Shakex, c.ClipY/2 - 48*Scale + Shakey);
			c.DrawText(SelText);
		}
		}
	}

	//************************************************
	//************************************************


	// Keep going down the chain.
	if (nextHUDMutator != none)
		nextHUDMutator.postRender(c);
}

function CheckWeaponsStatus(float DeltaTime)
{
local byte bx;

	//Missiles usage fade blink
	if (bWeapRise1)
		WeapFade1 += DeltaTime;
	else
		WeapFade1 -= DeltaTime;

	if (WeapFade1 >= 0.2 && bWeapRise1)
	{
		bWeapRise1 = False;
		WeapFade1 = 0.2;
	}
	else if (WeapFade1 <= 0 && !bWeapRise1)
	{
		bWeapRise1 = True;
		WeapFade1 = 0;
	}

	//Jet status fuel and damage fade blink
	WeapFade2 += DeltaTime;
	
	if (WeapFade2 >= 1.5)
		WeapFade2 = 0;

	WeapFade3 -= DeltaTime;
	
	if (WeapFade3 <= 0)
		WeapFade3 = 1.5;

	For (bx=0; bx<4; bx++)
	{
		if (NormMInfo[bx].BlinkTime > 0)
			NormMInfo[bx].BlinkTime -= DeltaTime;
		if (NormMInfo[bx].BlinkTime < 0)
			NormMInfo[bx].BlinkTime = 0;

		if (RearMInfo[bx].BlinkTime > 0)
			RearMInfo[bx].BlinkTime -= DeltaTime;
		if (RearMInfo[bx].BlinkTime < 0)
			RearMInfo[bx].BlinkTime = 0;
	}
	
	For (bx=0; bx<2; bx++)
	{
		if (SeekMInfo[bx].BlinkTime > 0)
			SeekMInfo[bx].BlinkTime -= DeltaTime;
		if (SeekMInfo[bx].BlinkTime < 0)
			SeekMInfo[bx].BlinkTime = 0;
	}

	if (SpecialBlink > 0)
		SpecialBlink -= DeltaTime;
	if (SpecialBlink < 0)
		SpecialBlink = 0;
		
}


function drawLogo(Stylus s, int x, int y) {
	local int style;
	local color whitemf;

	whitemf.R = 255;
	whitemf.G = 255;
	whitemf.B = 255;

	//c.drawColor = whitemf * screenFade;
	c.drawColor = col1 * screenFade;
	s.setPos(x - 48, y);
  c.drawRect(NXVisualIcon, 48, 48);
	c.drawColor = col1 * screenFade * 0.20;
	if (reth > 32)
		// Missing lower right.
		style = 3;

	s.drawFrame(x - 21, y, 21, 32, style);
}
/*
function drawLogo(Stylus s, int x, int y) {
	local int style;

	c.drawColor = col1 * screenFade;
	s.setPos(x - 32, y);
	c.drawRect(Texture'SLV2Textures.slhud.logo', 32, 32);

	c.drawColor = col1 * screenFade * 0.20;
	if (reth > 32)
		// Missing lower right.
		style = 3;

	s.drawFrame(x - 21, y, 21, 32, style);
}
*/

/** Let the player know what the hijacked key settings are. The box
	initially slides in from the left and then fades out.

	This has been hacked around so much. It needs to be cleaned out.
*/
function drawKeys() {
	local int x, y, i;
	local float xl, yl;
	local bool fill;

	local int sep;
	local String rstr;

	if (keysFade > 0 || keysSlide == -1) {
		x = -1 - keysSlide;
		y = (c.clipy - reth) / 2.0 - keysUp;

		c.font = lgFont;
		// get the yl
		c.textSize(keys[0], xl, yl);

		for (i = 0; i < arrayCount(keys); i++) {

			// If we haven't set the max yet, don't draw anything.
			if (keysSlide >= 0) {
				c.setPos(x + 6, y + 2 + (yl - 1) * i);
				sep = instr(keys[i], "(");

				c.drawColor = col4 * fmin(1.0, keysFade);
				if (sep == -1) {
					// Title.
					yy.drawText(keys[i]);
				} else {
					// Key name.
					c.drawColor = c.drawColor * 0.6;
					yy.drawText(left(keys[i], sep));

					// Function.
					c.drawColor = col4 * fmin(1.0, keysFade);
					rstr = right(keys[i], len(keys[i]) - sep);
					c.textSize(left(keys[i], sep), xl, yl);
					c.setPos(x + 6 + xl, c.cury);
					yy.drawText(rstr);
				}
			} else {
				c.textSize(keys[i], xl, yl);
				if (xl > keymax)
					keymax = xl;
			}

		}

		// We'll miss the first pass, but that's alright, as we'll be
		// offscreen. FIX? Doesn't take into account max skew.
		if (((yy.clipx - retw) / 2.0) - indw - 30 < keymax) {
			keysUp = (yl - 1) * arrayCount(keys) + 4 + reth / 2.0;
		} else {
			keysUp = 0;
		}

		if (keysSlide >= 0) {
			fill = level.bHighDetailMode;
			if (fill)
				c.drawColor = col4 * (fmin(1.0, keysFade) / 4.0);
			yy.drawFrame(x, y, keymax + 8, (yl - 1) * arrayCount(keys) + 2, 1, fill, true);
		} else {
			keysSlide = keymax + x + 6;
			// This makes is so it sticks longer.
			keysFade = 7.0;
		}
	}
}


function drawReticule(int x, int y) {
	local int sret;
	local int cx, cy;
	local color col, retcol;
	local int w;

	cx = x + retw / 2;
	cy = y + reth / 2;

	if (level.bHighDetailMode) {
		col = col1 * 0.2 * screenFade;
	} else {
		col = col1 * screenFade;
	}
	retcol = col1 * (1.0 - retScale) * screenFade;

	c.drawColor = col;

	yy.setPos(cx, cy - 8);
	yy.pix(1, 6);
	yy.setPos(cx, cy + 2);
	yy.pix(1, 6);

	yy.drawFrame(x, y, retw, reth, 4);

	c.drawColor = retcol;

	if (sl.bMarchPlaying) {
		yy.setPos(x + 4, y + 4);
		c.font = font;
		yy.drawText("TOTAL COMMITMENT");
		return;
	}

	// The rounding makes it looks nicer - more centered. We take the
	// sides in by one pixel so it doesn't overlap the frame in low detail mode.
	w = retw - 2;
	yy.drawFrame(x + 1 + round(((1.0 - retScale) * w) * 0.5), y + round(((1.0 - retScale) * reth) * 0.5), round(w * retScale), round(reth * retScale), 1);

}


function drawHRot(int x, int y) {
	local float dpp;
	local float xl, yl;
	local float head, left;
	local int i;
	local float edgeFade;

	dpp = 1.0;

	c.font = font;

	head = toHeading(rotator(sl.velocity).yaw);
	left = head - indw * 0.5 * dpp;

	if (level.bHighDetailMode) {
		c.drawColor = col1 * lucent * screenFade;
		yy.drawFrame(x, y, indw, reth - indh - 1, 3, true);
	}

	for (i = (left / 15) * 15; i < ((head - left) + head); i += 15) {
		if (i >= left) {
			//edgeFade = 1.0 - (abs(head - i) / (indw * 0.5));
			edgeFade = (abs(head - i) / dpp);

			// Ugh. This part is hardcoded for indw.
			if (edgeFade > 20) {
				edgeFade = fmax(0.0, 1.0 - ((edgeFade - 20) / 10.0));
			} else {
				edgeFade = 1.0;
			}

			yy.setPos(x + (i - left) * dpp, y + 1);
			if (i % 45 == 0) {
				c.drawColor = col1 * 0.4 * screenFade * edgeFade;
				yy.pix(1, 3);
				c.textSize(i, xl, yl);
				yy.setPos(x + (i - left) * dpp - (xl * 0.5), y + 6);
				yy.drawText(i);
			} else {
				c.drawColor = col1 * lucent * screenFade * edgeFade;
				yy.pix(1, 2);
			}
		}
	}

	c.textSize(int(head), xl, yl);
	yy.setPos(x + indw / 2.0 - xl * 0.5, y + 6);
	c.drawColor = col1 * screenFade;
	yy.drawText(int(head));
}


function float toHeading(int yaw) {
	if (yaw < 0) {
		yaw = 65535 + yaw;
	}

	return (yaw / 65535.0) * 360.0;
}


function drawVRot(int x, int y) {
	c.drawColor = col1 * lucent * screenFade;
	yy.drawFrame(x, y, 32, reth, 0, true);

	c.drawColor = col1 * screenFade;
}

function drawIndicators(int x, int y) {
	local float xl, yl;
	local string whs;
	local color on, off;

	whs = "WARHEAD: ";

	c.font = font;
	c.textSize("h", xl, yl);

	/* FIX?
	if (indh < yl * 3) {
		c.font = font;
		c.textSize("h", xl, yl);
	}
	*/

	c.textSize(whs $ "DISARMED", xl, yl);
	indw = xl + 20;

	if (level.bHighDetailMode) {
		on = col1 * screenFade;
		off = col1 * lucent * screenFade;

		c.drawColor = off;
		yy.drawFrame(x, y, indw, indh, 2, true);
	} else {
		on = col1 * screenFade;
		off = col1 * 0.5 * screenFade;
	}

	// Vertically center them.
	y += (indh - yl * 3) / 2;

	c.textSize(whs $ "DISARMED", xl, yl);

	c.drawColor = on;
	yy.setPos(x + 4, y + 1);
	switch (sl.warstat) {
	case WH_Auto:
		yy.drawText(whs $ "AUTO");
		break;
	case WH_Armed:
		yy.drawText(whs $ "ARMED");
		break;
	case WH_Disarmed:
		yy.drawText(whs $ "DISARMED");
		break;
	}

	yy.setPos(x + 4, y + yl);
	if (sl.gunner == none) {
		c.drawColor = off;
	} else {
		c.drawColor = on;
	}
	yy.drawText("GUNNER ONBOARD");

	yy.setPos(x + 4, y + yl * 2 - 1);
	if (sl.bAfterburn) {
		c.drawColor = on;
	} else {
		c.drawColor = off;
	}
	yy.drawText("AFTERBURNERS ON");
}

/*
function drawIndicators(int x, int y) {
	local float xl, yl;
	local string whs;
	local color on, off;

	whs = "JETSTATUS: ";

	c.font = font;
	c.textSize("h", xl, yl);

	c.textSize(whs $ "DISARMED", xl, yl);
	indw = xl + 20;

	if (level.bHighDetailMode) {
		on = col1 * screenFade;
		off = col1 * lucent * screenFade;

		c.drawColor = off;
		yy.drawFrame(x, y, indw, indh, 2, true);
	} else {
		on = col1 * screenFade;
		off = col1 * 0.5 * screenFade;
	}

	// Vertically center them.
	y += (indh - yl * 3) / 2;

	c.textSize(whs $ "DISARMED", xl, yl);

	c.drawColor = on;
	yy.setPos(x + 4, y + 1);

	switch (KL.jetweapon) {
	case WH_Cannons:
		yy.drawText(whs $ "CANNONS");
		break;
	case WH_Rockets:
		yy.drawText(whs $ "STINGERS");
		break;
	case WH_Nuker:
		yy.drawText(whs $ "BOMBS");
		break;
	}

	yy.setPos(x + 4, y + yl);
	if (sl.gunner == none) {
		c.drawColor = off;
	} else {
		c.drawColor = on;
	}
	yy.drawText("GUNNER ONBOARD");

	yy.setPos(x + 4, y + yl * 2 - 1);
	if (sl.bAfterburn) {
		c.drawColor = on;
	} else {
		c.drawColor = off;
	}
	yy.drawText("AFTERBURNERS ON");
}

  */
function drawTargets() {
	local Pawn p;
	local Inventory i;
	local vector x, y, z;

	getaxes(ho.viewRotation, x, y, z);
	c.font = font;

	foreach sl.visibleCollidingActors(class'Pawn', p, 3000,, true) {
		drawTarget(p, x, y, z);
	}

	foreach sl.visibleCollidingActors(class'Inventory', i, 3000,, true) {
		drawTarget(i, x, y, z);
	}
}


/** Inspired by Botpack.GuidedWarshell.
*/
function drawTarget(Actor a, vector x, vector y, vector z) {
	local float da, dist;
	local int xpos, ypos;
	local vector dir;
	local Color color;

	dir = a.location - sl.location;
	dist = vsize(dir);
	dir = normal(dir);

	// 1.0 is the middle, 0.7 is edge of screen.
	da = dir dot x;
	if (da > 0.94) {
		if (a.isA('Inventory')) {
			color = col2;
		} else {
			color = col4;
		}

		xpos = 0.5 * yy.clipx * (1 + 1.4 * (dir dot y));
		ypos = 0.5 * yy.clipy * (1 - 1.4 * (dir dot z));

		// Closer is brighter.
		c.drawColor = color * screenFade * ((da - 0.94) / 0.06) * fclamp((3000.0 - dist) / 1000.0, 0.0, 1.0);

		yy.drawFrame(xpos - 8, ypos - 8, 16, 16, 1);
		yy.setPos(xpos - 8, ypos + 9);
		yy.drawText(int((dist * u2m)) $ "m");
		//drawText("x:" $ (dir dot y) $ " y:" $ (dir dot z));
	}
}


function gunnerDisplay(Canvas c, Bot b) {
	c.drawColor = col1;
	c.font = lgFont;
	c.setPos(20, yy.cy + 40);
	yy.drawText("bot gunner: health: " $ b.health $ " orders: " $ b.orders $ " order object: " $ b.orderObject $ " state: " $ b.getStateName() $ " move target: " $ b.moveTarget);
}


/** This takes the difference between the direction of the rocket and
	the rotation, and skews the HUD. We scale the yaw delta based on
	the pitch. The pitch is locked in StrangeShell.adjustGuideRotation()
	to 16384. That 18000 jive messes with this.
*/
function setSkew() {
	local float pitch;
	local float dyaw, dpitch;
	local float maxd;
	local int maxskew;

	maxd = 16384.0;
	maxskew = yy.clipx / 8;

	dyaw = (rotator(sl.velocity).yaw & 65535) - (sl.rotation.yaw & 65535);

	pitch = sl.rotation.pitch & 65535;
	dpitch = pitch - (rotator(sl.velocity).pitch & 65535);

	u.centerRotComp(dyaw);
	u.centerRotComp(dpitch);
	u.centerRotComp(pitch);

	// This is unecessary since we're clamping the guide rotation to
	// below 16384, but it looks nicer anyway.
	dyaw = dyaw * (1.0 - fmin(abs(pitch) / maxd, 1.0));

	skewx = clamp(int(((dyaw / maxd) * maxskew) + 0.5), -maxskew, maxskew);
	skewy = clamp(int(((dpitch / maxd) * maxskew) + 0.5), -maxskew, maxskew);

	u.debug("setSkew(): skewx: " $ skewx $ " dyaw: " $ dyaw $ " pitch: " $ pitch);
}


/** Tick. Updates timers and stuff.
*/
function tick(float delta) {
	if (noMore())
		return;

	register();

	// Don't go any further.
	if (!bInit)
		return;

	// Update gauges.
	if (sl.bAfterburn)
		throLvl.update(delta, 1.5, "100");
	else
		throLvl.update(delta, sl.thlvl, string(int(sl.thlvl * 100)));

		veloLvl.update(delta, vsize(sl.velocity) / sl.fullspeed, int(u2m * vsize(sl.velocity)));
		hullLvl.update(delta, sl.armor / sl.default.armor, int(sl.armor));
		fuelLvl.update(delta, sl.fuel / sl.default.fuel, int(sl.fuel));

	if (sl.fc != none)
		coreLvl.update(delta, float(sl.fc.getAmmo()) / sl.fc.getMaxAmmo(), sl.fc.getAmmo());

	// Alarm check.
	if (fuelLvl.alarmOn() || hullLvl.alarmOn())
		gotoState('Warning');

	if (sl.bShootMode || sl.getPilot() != ho) {
		if (slide < yy.clipx) {
			slide = fmin(yy.clipx, slide + yy.clipx * 3.0 * delta);
		} else {
			// This was a hack and a crutch anyway.
			//updateNoShoot(delta);

			// No need to update anything else - the HUD is off screen.
			return;
		}
	} else {
		// Reset this.
		//nsFade = 0.0;

		if (slide > 0) {
			slide = fmax(0, slide - yy.clipx * 2.0 * delta);
		}
	}

	// Keys.
	if (bShowKeys) {
		if (keysSlide > 0) {
			keysSlide = max(0, keysSlide - delta * 300.0); // keys slide rate
		} else if (keysFade > 0) {
			keysFade = fmax(0.0, keysFade - delta * 0.5); // keys fade rate
		}
	}


	if (slide == 0 && screenFade < 1.0) {
		screenFade = fmin(1.0, (screenFade + delta * 0.5)); // + frand() * 0.01);
	}

	retScale += delta * fade * (vsize(sl.velocity) / ((sl.maxSpeed + sl.minSpeed) / 2.0));

	if (retScale > 1.0)
		retScale = 0.0;

	setOffsets(delta);

	CheckWeaponsStatus(delta);
}


function setOffsets(float delta) {
	// Handle HUD shaking.
	if (shakemag > 0.0) {
		shakemag = fmax(0.0, shakemag - delta * shakeRate);
	}

	if (sl.bAfterburn && shakemag < 3) {
		shakemag = 3.0;
	}

	if (shakemag > 0) {
		shakex = (rand(shakemag) - shakemag / 2.0);
		shakey = (rand(shakemag) - shakemag / 2.0);
	} else {
		shakex = 0;
		shakey = 0;
	}

	setSkew();

	yy.setOffsets(shakex + slide + skewx, shakey + skewy);
}


function shake(int sev) {
	if (!sl.bShootMode) {
		// Sometimes the shaking gets out of control...
		shakemag = min(shakemag + sev, 90);
	}
}


function int round(float f) {
	return int(0.5 + f);
}


/** Destroy us. But first take us out of the HUD mutator list.
*/
function destroyed() {
	local Mutator m;

	u.debug("destroyed()", DL_Normal);

	if (ho != none && ho.myHUD != none) {
		m = ho.myHUD.HUDMutator;

		if (m != none) {
			u.debug("first hudmut: " $ m);
			if (m.isA('SLHUD')) {
				if (m == self) {
					ho.myHUD.HUDMutator = m.nextHUDMutator;
				}
			} else {
				while (m.nextHUDMutator != none) {
					u.debug("next hudmut: " $ m);
					if (m.nextHUDMutator == self) {
						m.nextHUDMutator = m.nextHUDMutator.nextHUDMutator;
					}
					m = m.nextHUDMutator;
				}
			}
		}
	}



	super.destroyed();
}

defaultproperties
{
     col1=(R=80,G=150,B=10)
     col2=(R=100,G=30,B=30)
     col3=(R=110,G=10,B=10)
     col4=(R=130,G=40,B=40)
     lucent=0.200000
     fade=1.600000
     warnBlink=1.000000
     warnLvl=0.250000
     u2m=0.024500
     shakeRate=15.000000
     keys(0)="*** WINGS RX4W ***"
     keys(1)="Jump (Eject)"
     keys(2)="Forward/Back (Throttle)"
     keys(3)="Scroll mouse wheel (RX4W NextWeapon)"
     keys(4)="Fire (Shoot/change W'head status)"
     keys(5)="Alt Fire (afterburner)"
WhiteC=(R=255,G=255,B=255)
BlackC=(R=0,G=0,B=0)
NormMInfo(3)=(bThere=True,IcTex=MissileIc01)
NormMInfo(2)=(bThere=True,IcTex=MissileIc02)
NormMInfo(1)=(bThere=True,IcTex=MissileIc03)
NormMInfo(0)=(bThere=True,IcTex=MissileIc04)
SeekMInfo(1)=(bThere=True,IcTex=SeekIc01)
SeekMInfo(0)=(bThere=True,IcTex=SeekIc02)
RearMInfo(3)=(bThere=True,IcTex=RearIc01)
RearMInfo(2)=(bThere=True,IcTex=RearIc02)
RearMInfo(1)=(bThere=True,IcTex=RearIc03)
RearMInfo(0)=(bThere=True,IcTex=RearIc04)
WeapSelTex(0)=CannonsSelect
WeapSelTex(1)=MissilesSelect
WeapSelTex(2)=SeekMissilesSelect
WeapSelTex(3)=RearMissilesSelect
WeapSelTex(4)=SpecialSelected
SpecialbThere=True
SpecialIc(0)=SeekNukeIc
SpecialIc(1)=NormalNukeIc
SpecialIc(2)=DropNukeIc
SpecialIc(3)=FlashIc
SpecialIc(4)=HeatTargetIc
SpecialIc(5)=HeatTargetRearIc
NXVisualIcon=vXIcon
}
