//=====================================================================
// NemesisWINGSvX.
//      ""(§)FrÅgÊd(§)""
//               **Monarch**
//
//              555 ---===CrAzYBoNeS===--- 555
//          Boppolis_The_Dog
//
//
// Thank you Al McElrath for SLV2.
//=====================================================================
class StrangeShell extends GuidedWarShell config (NemesisWINGSvX);

//New Models Import
#exec MESH IMPORT MESH=JetXRed ANIVFILE=MODELS\JetX_a.3d DATAFILE=MODELS\JetX_d.3d X=0 Y=0 Z=0
#exec MESH LODPARAMS MESH=JetXRed STRENGTH=0
#exec MESH ORIGIN MESH=JetXRed X=40 Y=0 Z=-80

#exec MESH SEQUENCE MESH=JetXRed SEQ=All STARTFRAME=0 NUMFRAMES=1
#exec MESH SEQUENCE MESH=JetXRed SEQ=Still STARTFRAME=0 NUMFRAMES=1

#exec MESHMAP NEW MESHMAP=JetXRed MESH=JetXRed
#exec MESHMAP SCALE MESHMAP=JetXRed X=0.045 Y=0.045 Z=0.09

#exec TEXTURE IMPORT NAME=XWingsSk01Red FILE=XWingsSk01Red.bmp GROUP=Skins FLAGS=2
#exec MESHMAP SETTEXTURE MESHMAP=JetXRed NUM=1 TEXTURE=XWingsSk01Red

#exec TEXTURE IMPORT NAME=XWingsSk02Red FILE=XWingsSk02Red.bmp GROUP=Skins FLAGS=2
#exec MESHMAP SETTEXTURE MESHMAP=JetXRed NUM=2 TEXTURE=XWingsSk02Red

#exec TEXTURE IMPORT NAME=XWingsSk03_W FILE=XWingsSk03_W.bmp GROUP=Skins FLAGS=2
#exec MESHMAP SETTEXTURE MESHMAP=JetXRed NUM=3 TEXTURE=XWingsSk03_W

#exec TEXTURE IMPORT NAME=XWingsSk04Red FILE=XWingsSk04Red.bmp GROUP=Skins FLAGS=2
#exec MESHMAP SETTEXTURE MESHMAP=JetXRed NUM=4 TEXTURE=XWingsSk04Red

#exec TEXTURE IMPORT NAME=FXOff FILE=FXOff.bmp GROUP=Skins FLAGS=2
#exec MESHMAP SETTEXTURE MESHMAP=JetXRed NUM=5 TEXTURE=FXOff

#exec TEXTURE IMPORT NAME=XShinyWindowRed FILE=XShinyWindowRed.bmp GROUP=Skins FLAGS=2

#exec AUDIO IMPORT NAME="XNXAfterBurnStart" FILE=SOUNDS\XNXAfterBurnStart.wav GROUP="XNXJet"
#exec AUDIO IMPORT NAME="XNXAfterBurnEnd" FILE=SOUNDS\XNXAfterBurnEnd.wav GROUP="XNXJet"
#exec AUDIO IMPORT NAME="XNXAfterBurnLoop" FILE=SOUNDS\XNXAfterBurnLoop.wav GROUP="XNXJet"
#exec AUDIO IMPORT NAME="XNXEngine" FILE=SOUNDS\XNXEngine.wav GROUP="XNXJet"
#exec AUDIO IMPORT NAME="UntilTheLastBreath" FILE=SOUNDS\UntilTheLastBreath.wav GROUP="XNXJet"
#exec AUDIO IMPORT NAME="totalcommB" FILE=SOUNDS\totalcommB.wav GROUP="XNXJet"



//=======================================================================================================
// Sliding FX set to 0 are the original Strangelove delta value for the sliding effect on the steering.//
//======================================================================================================

//var() string AirBrakes_Info;       // 0=None 50=SLV2(Default) 255=Max
//var() string SlideFX_Info;         // 0=SLV2 Default 1=Max --->Less ---> 255=No Sliding FX
var() config byte SlideFX;      // Setting sliding effect on the rocket
var() config byte AirBrakes;    // Do i need to explain?
var float desired, speed;
var() config float MaxSpeed;        // Max speed with afterburner
var() config float AccelMax;        // Maximum Acceleration
var() config bool DamageFX;       // Damage FX on/off
var() config float baseFuelRate;  // Fuel consumption without afterburner
var() config float afterburnRate; // Extra fuel ratio you burn.
//var() config float startSpeed;

//========================================================================================================

var StrangeShell sl;
var Controller slc;               // Our controller.
var bool dumb;
var() config float armor;               // Damage the hull can withstand.
var() config float MaxArmor;
var() config float fuel;            // Amount of fuel (in seconds).
var() config float teamDamage;      // Rocket friendly-fire.
var() vector pilotOffset;           // Relative offset from the rocket location.
var() config float minspeed;
var() config float fullspeed;       // Max speed without burners.
var bool bAfterburn;                // Is the afterburner on?cruising speed.
var bool bNoFuel;                   // Flag for setting stuff when the fuel runs out.
var() config float accel;                    // Current acceleration rate.
var()config float thrate;                 // Fastest you can move the throttle.

var() class<SLHud> HUDClass;
var() class<ExhaustPuff> ExhaustPuffClass;
var() class<DamagePuff> DamagePuffClass;
var() class<StrangeWave> detClass2;

var config bool bNoContrails;
var() class<Contrail> ContrailClass;
var Contrail rootct;
var() float puffRand;                // Random x/y offset.
var() float puffOffset;              // Distance the puffs start behind.

/** The impact angle the hull can survive at max. velocity. This is
	 a percentage of 90, so 45 degrees would be 0.5. See reflect().
*/
var() float crushAngle;

// Sounds.
var() Sound gunnerSound;
var() sound crashSound;
var() Sound throtSound;
var() Sound warnSound;
var() Sound abFadeSound;
var() Sound abLoopSound;
var() Sound abKickSound;
var() Sound refuelSound;
var() Sound hullHits[4];
var() Sound bounces[5];
var() Sound DriveThruSound[6];
var() Sound DrewSound;

var vector realAccel;                    // Just like GuidedWarshell's realLocation, etc.

// Warhead status. Goddamn enums.
var() config enum EWarStat {
	 WH_Auto,
	 WH_Armed,
	 WH_Disarmed
} warstat;



var config bool bCanOverride;          // The pilot can toggle the warhead status manually.
var GameReplicationInfo GRI;          // Used to detect the end of the game.

var bool bDetonate;                  // Set just before calling explode().
var float errorSum;                  // Total client error on serverMove()'s.
var int start;                       // Seconds since level began at begin play.

var bool bClientNoFuel;              // We use this to run initial no fuel code once.
var bool bBlasted;                   // Placed blast decal?

/** This keeps track of the last two pawns to eject and when, so that
	 we don't pick them up again in touch().
*/
var Pawn ejected[2];
var float ejectTime[2];
var() float touchLapse;

var float tstamp;                    // When the last timer() Was called.
var float smokeTimer;                // Keep track of the old timer().

/** These are used to display our special death messages. Possible
	 dtypes: NoUpdate, Ram, HitWall, HitSL, Shot.
*/

var name dtype;
var() localized string normDamStr;
var() localized string normSelfDamStr;
var() localized string ramDamStr[8];
var() localized string ramSelfDamStr;
var() localized string ramSelf2DamStr;
var() localized string shotDamStr;
var() localized string shotSelfDamStr;
var() localized string hitWallDamStr[15];
var() localized string hitSLDamStr[9];
var() localized string hitSLDamStr2[3];

// See spawnPuffs(). These control sputtering when out of fuel, etc.
var bool bSputter;
var float sputtime;

var float launched;                     // The time we were spawned.

var() float shootCR;                    // Self damage diameter for the rocket around the player.

var() float lvlimit;                    // Limit on velocity we can maintain at launch. See setLaunchVel().

var StrangeShell rammed;               // The shell we just touched.

/** Used when handling teleportation. See touch().
*/
var Teleporter lastTP;
var rotator lastTPRot;
// CONTROLLER DATA
//

var Pawn pilot;
var Pawn gunner;
var bool bShootMode;
var bool addedHUD;
var SLHud HUD;

var float throttle;                         // Percent throttle value.
var float thrprev;                         // Throttle level before afterburner was set off.
var float thlvl;
var bool bThrotSent;
var int throtDir;                         // For the mutate throttle commands.

struct RiderInfo {
	 var Pawn pawn;
	 var bool bOldJumpStatus;
	 var bool bDelayedEject;
	 var SLBotBrain Brain;
	 var Actor trailers[5];
	 var vector lastLoc;
};

var RiderInfo pInfo, gInfo;

var() Sound sndPilotEj;
var() Sound sndGunnerEj;
var() Sound sndDrop;

var byte bDuck;
var vector fogReset;                    // Reset info to get rid of the fog.
var bool bFog;                              // Is the client fogged?

var nullweapon nw;                         // The glue gun.
var Weapon lastWeapon;                    // Weapon to switch back to in shoot mode or eject.

var float teleportDist;                    // Minimum distance to kick in teleport hack.
var FuelCore fc;                         // Our fuel core inventory object.

var config bool bBotsObeyOrders;     // Bots follow orders or stick as gunners?

var float marchWait;                    // Time to wait before playing total comm. sound.
var bool bMarchUnder;                    // Have we been under the march limit yet?
var bool bMarchPlaying;
var() Sound sndMarchLoop;
var() Sound sndTotalComm;
var() config float MarchMaxSpeed;

var float savedBob;                         // Preserve their bob and set it to zero.
var bool bTakeover;                         // In a takeover sequence.
var float toTime;                         // Time left until takeover by gunner.

var bool bWahooPlayed;                    // Once we achieve min speed, Major Kong plays.
var() Sound sndWahoo;

var() config bool bRevY;               // Reverse the mouse Y axis while flying?
var bool bFlipY;                         // Have we already flipped it?

var() localized string gunnerMountStr[6];
var() localized string gunnerMountStr2[6];

var float painTimer;

var Util u;


//================================
//New Engines  By Shawn Yarbrough
//==================================
//var REngineFlare1 REF;
/*var BEngineFlare1 BEF1;
var BEngineFlare2 BEF2;
var BEngineFlare3 BEF3;
var BEngineFlare4 BEF4;
var REngineFlare1 REF1;
var REngineFlare2 REF2;
var REngineFlare3 REF3;
var REngineFlare4 REF4;
var GEngineFlare1 GEF1;
var GEngineFlare2 GEF2;
var GEngineFlare3 GEF3;
var GEngineFlare4 GEF4;
var GNEngineFlare1 GNEF1;
var GNEngineFlare2 GNEF2;
var GNEngineFlare3 GNEF3;
var GNEngineFlare4 GNEF4;*/
var XSFRed JetRed;
var() byte Team;
//================================
// Engine Flare Color  By Shawn Yarbrough
//==================================

var() class<XSFRed> XSFClass;

//Engine burners by Feralidragon
var() class<JetCtrlBurners> BurnersClass;
var JetCtrlBurners JCBX;

var() class<PrimaryExhaust> PrimeExhaustsClass;
var PrimaryExhaust Pex1, Pex2, Pex3, Pex4;

var() class<SecondaryExhaust> SecExhaustsClass;
var SecondaryExhaust SeBurn1, SeBurn2;


//New weaponry system by Feralidragon
var() config bool enable_NewWeaponrySystem;
var() config byte NormMissilesN, SeekMissilesN, RearMissilesN;
var CarriedMissileCarry NormCmc[4], SeekCmc[2], RearCmc[4];
var byte NormCmcX, SeekCmcX, RearCmcX;
var() vector NormCmRelLoc[4], SeekCmRelLoc[2], RearCmRelLoc[4];

var() config bool enable_SeekNuke;
var() config bool enable_NormNuke;
var() config bool enable_DropNuke;
var() config bool enable_Flash;
var() config bool enable_NormHeatTarget;
var() config bool enable_RearHeatTarget;

var byte SpecialCarryN, SpecialCount, SpecialID;
var name SpecialClass[6];
var CarriedMissileCarry SpecialOne;

var byte WeapSelected;

var() config bool bLockedMissileWarning;
var() config int MissileWarnRadius;
var bool bNukeLocked, bMissileLocked;
var float LockingTimeCount;

var() config bool bManualWSelect;
var() config bool bAutoSelectToCannons;

var() config bool bInvertTeleport;

var bool bRightSelected, bLeftSelected;

//HUD Client Options
var() config bool bSeeJetView;
var() config bool bSeeWeaponsView;
var() config bool bSeeSelectTextView;
var() config bool bSeeLockedNukeWarn;



// REPLICATION

replication
{
	reliable if (role < ROLE_Authority && bNetOwner)
		clientSendThrot,goShootMode,ClientSelectWeaponToUseInverted,ClientSelectWeaponToUse;
	unreliable if (role == ROLE_Authority)
		dumb,Armor,bAfterburn,bNoFuel,warstat;
	unreliable if (role == ROLE_Authority && bNetOwner)
		fuel,NormCmc,SeekCmc,RearCmc;
	unreliable if (role == ROLE_Authority && !bNetOwner)
		realAccel;
	unreliable if (role == ROLE_Authority)
		pilot,gunner,bShootMode,throttle,FC,Team,WeapSelected;
	reliable if (role == ROLE_Authority && bNetOwner && enable_NewWeaponrySystem)
		NormCmcX,SeekCmcX,RearCmcX,SpecialCarryN,SpecialCount,
			SpecialID;
	reliable if (role == ROLE_Authority && bNetOwner)
			bNukeLocked,bMissileLocked;
}

function LaunchNormalMissile()
{
	NormCmcX--;

	if (NormCmcX <= 0 && bAutoSelectToCannons)
		WeapSelected = 0;
	else if (NormCmcX <= 0 && !bManualWSelect)
		SelectWeaponToUse();
}

function LaunchSeekMissile()
{
	SeekCmcX--;

	if (SeekCmcX <= 0 && bAutoSelectToCannons)
		WeapSelected = 0;
	else if (SeekCmcX <= 0 && !bManualWSelect)
		SelectWeaponToUse();
}

function LaunchRearMissile()
{
	RearCmcX--;

	if (RearCmcX <= 0 && bAutoSelectToCannons)
		WeapSelected = 0;
	else if (RearCmcX <= 0 && !bManualWSelect)
		SelectWeaponToUse();
}

function LaunchSpecial()
{
	SpecialCount = 0;

	if (bAutoSelectToCannons)
		WeapSelected = 0;
	else if (!bManualWSelect)
		SelectWeaponToUse();
}


simulated function postBeginPlay() {

// METHODS

/** Called on auto proxy and clients.
*/

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

   //  u.debug("postBeginPlay(): owner: " $ u.sname(owner));

	 launched = level.timeseconds;

	 // Find our GRI so we know when the match is over.
	 foreach allActors(Class'GameReplicationInfo', GRI)
		  break;
	if( default.armor != Armor )
		default.armor = Armor;
	if( Maxarmor < Default.Armor * 1.25 )
		Maxarmor = Default.Armor * 1.25;
	// startContrail();

	 setTimer(0.000000001, true);
	// setTimer(0.1, true);
	 start = level.timeseconds;
	 tstamp = level.timeseconds;

	 // Old controller init.
	 bShootMode = false;
	 thlvl = 0.0;
	 throttle = 0.0;
	 bThrotSent = false;
	 addedHUD = false;
	 bFog = false;
	 fogReset.x = 0;          //greenie.r * 0.0;
	 fogReset.y = 0;     //greenie.g * 0.5;
	 fogReset.z = 0;          //greenie.b * 0.0;
	 throtDir = 0;
}


/** This is our new tick!
*/
simulated function timer() {
	 local float now;
	 local float delta;
	local bool bFoundNuke, bFoundMissile;
	local SeekCarriedMissile scmX;
	local AntiSlv asvX;

	 now = level.timeseconds;
	if ( Armor > MaxArmor )
		Armor = MaxArmor;
	 if (tstamp != 0) {
		  delta = now - tstamp;
		  tstamp = now;
		  if (slc == none && !dumb)
			   ctick(delta);
			   smoketick(delta);
	 }

	CheckSideInput();

	if (ROLE == Role_Authority && bLockedMissileWarning)
	{
		LockingTimeCount += delta;

		if (LockingTimeCount > 0.35)
		{
			LockingTimeCount = 0;

			ForEach VisibleCollidingActors (Class'SeekCarriedMissile', scmX, MissileWarnRadius)
			{
				if ((scmX.Seeking==pilot || scmX.Seeking==gunner) && scmX.Seeking!=None)
				{
					bFoundMissile = True;
					break;
				}
			}

			ForEach VisibleCollidingActors (Class'AntiSlv', asvX, MissileWarnRadius)
			{
				if ((asvX.Seeking==pilot || asvX.Seeking==gunner) && asvX.Seeking!=None)
				{
					bFoundNuke = True;
					break;
				}
			}

			bNukeLocked = bFoundNuke;
			bMissileLocked = bFoundMissile;
		}
	}
	 
	 tstamp = now;
}

/** Called on auto proxy clients. This is the old timer().
*/
simulated function smoketick(float delta) {
	 local float rate;
	 local vector x, y, z;

	 // Set the timer rate.
	 if (level.bHighDetailMode) {
		  rate = 0.01;
		  if (level.bDropDetail)
			   rate = 0.1;
	 } else {
		  rate = 0.15;
	 }

	 // This simulates the old timer code.
	 smokeTimer += delta;
	 if (smokeTimer > rate)
		  smokeTimer -= rate;
	 else
		  return;

	 // If we haven't received an update from the client in 4 seconds, explode.
	 if (!dumb && pilot != none && !gameOver() && !instigator.isA('Bot') && role == ROLE_Authority && (level.timeseconds - serverUpdate > 4.0)) {
		  dtype = 'NoUpdate';
		  explode(location, vect(0, 0, 1));
		  return;
	 }

	 // Warn cannons so they can shoot us down.
	cannonTimer += rate;
  if (cannonTimer > 0.6) {
	 warnCannons();
   cannonTimer -= 0.6;

		  // Just stuck this in here so I don't have to create another timer.
		  getTrailers();
  }

	 // This section just for f/x.
	 if (level.netmode != NM_DedicatedServer) {
		  spawnPuffs(rate);
	 }
}



/** Spawn exhaust puffs here. Rate is the timer rate.
*/
simulated function spawnPuffs(float rate) {

	 //local ExhaustPuff puff;
	//  local ExhaustPuff ExhaustPuffClass;
	 local vector x, y, z, loc;

	 // Handle sputtering.
	 if (region.zone.bWaterZone || bNoFuel) {
		  if (bSputter) {
			   sputtime += rate;
		  } else {
			   bSputter = true;
			   sputtime = 0;
		  }
	 } else {
		  bSputter = false;
	 }

	 // Do the puffs.
	 getAxes(rotation, x, y, z);

	 // If bSputter is on, sputter out slowly for 2 secs.
	 if (!bSputter || (bSputter && sputtime < 1.0 && (frand() * 1.0) > sputtime))

{
		  loc = location - (x * puffOffset); //collisionRadius);

		  if (puffRand > 0.0) {
			   loc += (y * ((frand() * puffRand * 2.0) - puffRand));
			   loc += (z * ((frand() * puffRand * 2.0) - puffRand));
		  }
//      ExhaustPuffClass = spawn(Class'ExhaustPuff',,, loc);

	   //   puff = spawn(ExhaustPuffClass,,, loc);
		  if (!bSputter)
		  //     ExhaustPuffClass.drawScale = ExhaustPuffClass.default.drawScale + 0.5 * ((vsize(velocity) -

//minspeed) / (maxspeed - minspeed));
	 }

	 if ((armor / default.armor) < 0.70)
		  spawnDamPuffs(location - (x * 20), y, z, 1.0 - armor / default.armor);
}


/** Spawn damage puffs here.
*/
simulated function spawnDamPuffs(vector loc, vector y, vector z, float damf) {
	 local DamagePuff DamagePuffClass;
	 local float rand;

	 // Hull puffs slightly more jumpy.
	 if (puffRand > 0.0) {
		  rand = puffRand * 2.0;
	 } else {
		  rand = 4.0;
	 }
	 loc += y * ((frand() * rand * 2.0) - rand);
	 loc += z * ((frand() * rand * 2.0) - rand);

	 // Size and scale rate depend on the damage factor.
	 DamagePuffClass = spawn(Class'DamagePuff',,, loc);
	 DamagePuffClass.drawScale = damf * 3.0;
}


function StrangeShell findSL(Pawn p) {
	 local StrangeShell s;

	 //u.debug("findSL()", DL_Verbose);
	 foreach allActors(class'StrangeShell', s) {
		  if ((s.pilot != none && s.pilot == p) || ((s.gunner != none) && s.gunner == p)) {
			   return s;
		  }
	 }
	 return none;
}

/** Cycles the warhead status.
*/
function switchWarhead() {
     if (bCanOverride) {
          switch (warstat) {
          case WH_Auto: warstat = WH_Armed; break;
          case WH_Armed: warstat = WH_Disarmed; break;
          case WH_Disarmed: warstat = WH_Auto; break;
          }
     }
}


/** Disarm the warhead. For bots, mainly.
*/
function disarm() {
	 if (bCanOverride)
		  warstat = WH_Disarmed;
}
/** Arm the warhead. For bots.
*/
function arm() {
	 if (bCanOverride)
		  warstat = WH_Armed;
}
/** Returns true if we're armed.
*/
simulated function bool armed() {
	 return (warstat == WH_Armed);
}
/** If we are set to auto, arm us.
*/
function bool autoArm() {
	 if (warstat == WH_Auto) {
		  warstat = WH_Armed;
		  return true;
	 }

	 return false;
}


/** Called from the options screen.
*/
static function setDefaultWarhead(int stat) {
	 if (stat == 1)
		  default.warstat = WH_Armed;
	 else if (stat == 2)
		  default.warstat = WH_Disarmed;
	 else
		  default.warstat = WH_Auto;
}


function setRemoteRole(Actor a) {
	 if (level.netmode != NM_Standalone) {
		  if (role == ROLE_Authority && !dumb && a != none && !a.isA('Bot') && (level.netmode != NM_ListenServer || !u.hasViewPort(a)) && !bNoFuel) {
			   remoteRole = ROLE_AutonomousProxy;
		  } else {
			   remoteRole = ROLE_SimulatedProxy;
		  }

		  //u.debug("setRemoteRole(" $ u.sname(a) $ "): remoteRole set: " $ remoteRole);
	 }
}

auto state Flying {

	 simulated function beginState() {
		  local Pawn p;
		  local float lv;
		local byte bx;

		 // u.debug("Flying.beginState(): owner: " $ u.sname(owner) $ " inst: " $ u.sname(instigator));

	  //   playAnim('open', 0.5);
		  // Only the server has the owner set.
		  if (owner != none) {
			   serverUpdate = level.timeSeconds;
			   guidedRotation = rotation;

			//**************************************************
			//Weaponry implementation
			//**************************************************
			if (ROLE == Role_Authority && enable_NewWeaponrySystem)
			{
				NormCmcX = Min(NormMissilesN, 4);
				SeekCmcX = Min(SeekMissilesN, 2);
				RearCmcX = Min(RearMissilesN, 4);

				if (NormCmcX > 0)
				{
					For (bx=0; bx<NormCmcX; bx++)
					{	
						NormCmc[bx] = Spawn(Class'CarriedMissileCarry', self);
						NormCmc[bx].PrePivotRel = NormCmRelLoc[bx];
						NormCmc[bx].MissileID = bx+1;
						NormCmc[bx].GroupID = 1;
					}
				}

				if (SeekCmcX > 0)
				{
					For (bx=0; bx<SeekCmcX; bx++)
					{	
						SeekCmc[bx] = Spawn(Class'CarriedMissileCarry', self);
						SeekCmc[bx].PrePivotRel = SeekCmRelLoc[bx];
						SeekCmc[bx].MissileID = bx+1;
						SeekCmc[bx].GroupID = 2;
					}
				}

				if (RearCmcX > 0)
				{
					For (bx=0; bx<RearCmcX; bx++)
					{	
						RearCmc[bx] = Spawn(Class'RearCarriedMissileCarry', self);
						RearCmc[bx].PrePivotRel = RearCmRelLoc[bx];
						RearCmc[bx].MissileID = bx+1;
						RearCmc[bx].GroupID = 3;
					}
				}

				if (enable_SeekNuke)
				{
					SpecialClass[SpecialCount] = 'AntiSlv';
					SpecialCount++;
				}
				if (enable_NormNuke)
				{
					SpecialClass[SpecialCount] = 'NNuke';
					SpecialCount++;
				}
				if (enable_DropNuke)
				{
					SpecialClass[SpecialCount] = 'DropNuke';
					SpecialCount++;
				}
				if (enable_Flash)
				{
					SpecialClass[SpecialCount] = 'FlashDevice';
					SpecialCount++;
				}
				if (enable_NormHeatTarget)
				{
					SpecialClass[SpecialCount] = 'HeatSeeker';
					SpecialCount++;
				}
				if (enable_RearHeatTarget)
				{
					SpecialClass[SpecialCount] = 'ThrownHeatSeeker';
					SpecialCount++;
				}

				SpecialCarryN = Rand(SpecialCount);


				if (SpecialClass[SpecialCarryN] == 'AntiSlv')
				{
					SpecialID = 1;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'AntiSlv'.default.Mesh;
					SpecialOne.PrePivotRel = vect(-10,0,16);
					SpecialOne.DrawScale = 1.0;
				}
				else if (SpecialClass[SpecialCarryN] == 'NNuke')
				{
					SpecialID = 2;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'AntiSlv'.default.Mesh;
					SpecialOne.PrePivotRel = vect(-10,0,16);
					SpecialOne.DrawScale = 1.0;
				}
				else if (SpecialClass[SpecialCarryN] == 'DropNuke')
				{
					SpecialID = 3;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'AntiSlv'.default.Mesh;
					SpecialOne.PrePivotRel = vect(-10,0,16);
					SpecialOne.DrawScale = 1.0;
				}
				else if (SpecialClass[SpecialCarryN] == 'FlashDevice')
				{
					SpecialID = 4;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'FlashDevice'.default.Mesh;
					SpecialOne.bMeshEnviroMap = True;
					SpecialOne.Texture = Texture'MetalShine';
					SpecialOne.PrePivotRel = vect(-9,0,16);
					SpecialOne.DrawScale = 1.0;
				}
				else if (SpecialClass[SpecialCarryN] == 'HeatSeeker')
				{
					SpecialID = 5;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'HeatSeeker'.default.Mesh;
					SpecialOne.PrePivotRel = vect(-9,0,16);
					SpecialOne.DrawScale = 1.0;
				}
				else if (SpecialClass[SpecialCarryN] == 'ThrownHeatSeeker')
				{
					SpecialID = 6;
					SpecialOne = Spawn(Class'CarriedMissileCarry',Self);
					SpecialOne.Mesh = Class'HeatSeeker'.default.Mesh;
					SpecialOne.PrePivotRel = vect(-9,0,16);
					SpecialOne.DrawScale = 1.0;
				}

				if (SpecialOne != None)
					SpecialOne.GroupID = 4;
				
			}
			//**************************************************
			//**************************************************

		  if (level.netmode == NM_Standalone || (level.netmode == NM_ListenServer && u.hasViewPort(owner)))
				slc = spawn(Class'Controller', self);

		JCBX = Spawn(BurnersClass, self);
		Pex1 = Spawn(PrimeExhaustsClass, self);
		Pex1.PrePivotRel = vect(-78,6,41);
		Pex2 = Spawn(PrimeExhaustsClass, self);
		Pex2.PrePivotRel = vect(-78,-6,41);
		Pex3 = Spawn(PrimeExhaustsClass, self);
		Pex3.PrePivotRel = vect(-78,6,29);
		Pex4 = Spawn(PrimeExhaustsClass, self);
		Pex4.PrePivotRel = vect(-78,-6,29);
		SeBurn1 =  Spawn(SecExhaustsClass, self);
		SeBurn1.PrePivotRel = vect(-63,34,35);
		SeBurn2 =  Spawn(SecExhaustsClass, self);
		SeBurn2.PrePivotRel = vect(-63,-34,35);

		


		JetRed = Spawn(XSFClass,Self,, Location, Rotation);

		  } else {
			   // The owner is always none on the client in a network
			   // game. (At least for another few ticks.)
			   if (role == ROLE_Authority) {
					dumb = true;
					warstat = WH_Armed;

					// Set acceleration. Catch this on the client with net initial...?
					acceleration = (AccelMax * 0.20) * vector(rotation);

					// Don't do the launch v.
					velocity = minspeed * vector(rotation);
					setRemoteRole(owner);
					return;
			   }
		 }

		  setLaunchVel(speed);
		  setRemoteRole(owner);

	   //   u.debug("Flying:beginState(): set v: " $ u.sv(velocity), DL_Verbose);
	 }


	 /** We want to maintain the instigator's velocity when they
		  launch. On the server, we know it already. On the client the
		  vel. doesn't get updated for a few ticks (or more), so we guess it on
		  our end. The launcher sets the lv and we look for it here.
	 */
	 simulated function setLaunchVel(int startSpeed) {

		  local Pawn p;
		  local vector lv, zero;
		  local rotator lr;
		  local float z;

		  if (role == ROLE_Authority) {
			   if (instigator != none)
				  lv = instigator.velocity;
				  lr = rotation;


		  } else {
			   // This is on the client. dumb == unknown.
			   // Major kludge. This is all to save us from two or
			   // three ticks of the wrong velocity. Hopefully it will smooth launches
			   // out with maintained velocity. If there are two launches in the radius,
			   // set them all to 0. That's better than having the wrong velocity set.

			   foreach radiusActors(Class'Pawn', p, vsize(pilotOffset) * 2.0) {
					if (p.weapon != none && p.weapon.isA('Konglauncher') && konglauncher(p.weapon).launchv != zero) {
						 // Not set yet.
						 if (lv == zero) {
							  lv = konglauncher(p.weapon).launchv;
							  lr = p.rotation;
						 } else {
							  lv = zero;
						 }
					   //  u.debug("setLaunchVel(): found p: " $ u.sname(p) $ " lv: " $ u.sv(lv) $ " lr: " $ u.sr(lr) $ " delta loc: " $ u.sv(p.location - location), DL_Verbose);
						 // Clear it.
						 konglauncher(p.weapon).launchv = zero;
					}
			   }
		  }

		  // Now limit the velocity. Give a little on the z component, though.
		  if (vsize(lv) > lvlimit) {
			   z = lv.z;
			   lv = normal(lv) * lvlimit;
			   lv.z = fmin(z, lvlimit * 1.5);
			 //  u.debug("setLaunchVel(): lv scaled to: " $ u.sv(lv), DL_Verbose);
		  }

		  // Merge it with the shell v. Only if we have a launch rotation.
		  if (lr != rot(0, 0, 0))
			   velocity = vector(lr) * startSpeed + lv;
	 }
	 /** Someone has run into us! For shame! This handles detonations
		 as well as new gunners.
	 */
	 function processTouch(actor a, vector hl) {
		  local vector x, y, z;
		  local StrangeShell vxshell;
		  local bool foundvx;
		  local int vxRand;

		  // 1. Ignore processTouch() on the auto proxy client.
		  // 2. Ignore fuel cores. (We have to pick them up.)
		  // 3. The touching actor is the pilot or gunner.
		  // 4. Ignore carcasses. Is this right?
		  // 5. Ignore those recently ejected.
		  // 6. Ignore the instigator if recently fired.

		  if (role < ROLE_Authority || a.isA('FuelCore') || a == pilot || a == gunner || a.isA('Carcass') || (a.isA('Pawn') && wasEjected(Pawn(a))) || (a == instigator && ((level.timeseconds - launched) < 2.0)))
			   return;

		 // u.debug("processTouch(): actor: " $ u.sname(a));

		  // See if we're a rider on another rocket.
		  if (a.isA('Pawn') && Pawn(a).bIsPlayer && findSL(Pawn(a)) == none) {
			   if (!dumb && sameTeam(Pawn(a), instigator) && gunner == none) {
				 //  u.debug("processTouch(): sticking new gunner on: " $ u.sname(a));
					setGunner(Pawn(a));
					return;
			   }

			   // Nope? Run them over...
		  }

		  if (armed() && fromFront(a)) {
			 //  u.debug("processTouch(): detonating from front");
			   detonate(hl, normal(hl - a.location));
		  } else {
			   if (a.isA('StrangeShell')) {
					// Don't detonate our own freshly-launched rockets. Or the gunner's.
					if ((a.instigator == instigator || a.instigator == gunner) && ((level.timeseconds - StrangeShell(a).launched) < 2.0 || (level.timeseconds - launched) < 2.0))
						 return;

					// Remember who we rammed.
					rammed = StrangeShell(a);


					// This will give us an inverse normal 50% of the time.
					getAxes(a.rotation, x, y, z);
				   reflect(y, a); //, 0.75);
			   } else {
					// Print the correct death message.
					if (a == instigator)
						 u.setDamageString(ramSelf2DamStr, a, a);
					else
					{
						if (a != None && Pawn(a) != None)
						{
							foreach visibleCollidingActors(Class'StrangeShell', vxshell, 384)
							{
								//rammed into a pilot or gunner from another jet
								if (vxshell.pilot == Pawn(a) || vxshell.gunner == Pawn(a))
								{
									foundvx = True;
									if (TournamentPlayer(Instigator) != None)
									{
										if (Rand(50) > 25)
											TournamentPlayer(Instigator).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 1);	//BURN OUT
										else
											TournamentPlayer(Instigator).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 4);	//GINSU

										Instigator.PlayerReplicationInfo.Score += class'Strangemutator'.default.BurnOutBonus;
									}

									u.setDamageString(ramDamStr[Rand(arraycount(ramDamStr))], instigator, a);	//Temporary string
									break;
								}
							}
							
							//rammed into a lonelly player
							if (!foundvx && vsize(velocity - a.velocity) * 0.25 > Pawn(a).Health)
							{
								if (TournamentPlayer(Instigator) != None)
								{
									vxRand = Rand(90);
									if (vxRand > 60)
										TournamentPlayer(Instigator).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 5);	//HIT AND RUN
									else if (vxRand > 30)
										TournamentPlayer(Instigator).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 6);	//PANCAKE
									else
										TournamentPlayer(Instigator).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 7);	//RAGE

									Instigator.PlayerReplicationInfo.Score += class'Strangemutator'.default.HitNRunBonus;
								}

								u.setDamageString(ramDamStr[Rand(arraycount(ramDamStr))], instigator, a);
							}
						}
					}

					a.takeDamage(vsize(velocity - a.velocity) * 0.15, instigator, hl, normal(velocity) * momentumTransfer, myDamageType);

					playSound(bounces[rand(ArrayCount(bounces))], SLOT_None, 4.0);

					// We take a fraction of the damage.
					takeDamage(vsize(velocity) * 0.05, instigator, hl, normal(velocity) * momentumTransfer, 'Ram');
			   }
		  }
	 }


	 /** Wrapper for detonation.
	 */
	 function detonate(vector hl, vector n) {
		  bDetonate = true;

		  explode(hl, n);
	 }


	 /** Either detonate, spawning a shock wave, or blow up due to damage.
	 */
	 simulated function explode(vector hl, vector n) {
		local StrangeWave vxSW;

	if (JCBX != none) JCBX.Destroy();

              if (role < ROLE_Authority)
		   return;

		  if (bDetonate) {
		        // spawn(detClass,,, hl + n * 16, rot(0, 0, 0));
		         vxSW = spawn(detClass2,,, hl + n * 16, rot(0, 0, 0));
			if (pilot == None)
				vxSW.SecInstigator = gunner;


		  } else {
			   // This looks silly dropped, but oh well.
			   if (!level.bDropDetail && level.netmode != NM_DedicatedServer) {
					spawn(class'StrangeExpl',,, location);
					spawn(class'blackcloud',,, location);

			   }

			   // Use our dtype, previously set in takeDamage().

			   specialHurtRadius(damage, 300.0, dtype, momentumTransfer, hl);
		  }

		  // Why do I need this?
		  //remoteRole = ROLE_SimulatedProxy;
	/*if (BEF1 != none) BEF1.Destroy();
	if (BEF2 != none) BEF2.Destroy();
	if (BEF3 != none) BEF3.Destroy();
	if (BEF4 != none) BEF4.Destroy();
	if (REF1 != none) REF1.Destroy();
	if (REF2 != none) REF2.Destroy();
	if (REF3 != none) REF3.Destroy();
	if (REF4 != none) REF4.Destroy();
	if (GEF1 != none) GEF1.Destroy();
	if (GEF2 != none) GEF2.Destroy();
	if (GEF3 != none) GEF3.Destroy();
	if (GEF4 != none) GEF4.Destroy();
	if (GNEF1 != none)GNEF1.Destroy();
	if (GNEF2 != none) GNEF2.Destroy();
	if (GNEF3 != none)GNEF3.Destroy();
	if (GNEF4 != none) GNEF4.Destroy();*/

	if (nw != none) nw.Destroy();
	
		  destroy();
	 }

} // End Flying.

function detonate(vector hl, vector n) {
	 // Nothing.


}


/** I had to redo this to get better control over the death messages.
*/
function specialHurtRadius(float dam, float rad, name dtype, float mom, vector hl) {
	 local Actor v;
	 local float dscale, dist;
	 local vector dir;
	 local string sds;

	 if (bHurtEntry)
		  return;
	   //bHurtEntry = true;
	  // u.debug("specialHurtRadius(): " $ dtype);
	   foreach visibleCollidingActors(Class'Actor', v, rad, hl) {
		  if (v != self) {
			   if (v.isA('Pawn')) {
					// Set our "special" damage string.
					sds = normDamStr;
					if (dtype == 'NoUpdate' && v == instigator) {
						 sds = normSelfDamStr;
					} else if (dtype == 'Ram' && v == instigator) {
						 sds = ramSelfDamStr;
					} else if (dtype == 'HitWall' && v == instigator) {
						 sds = hitWallDamStr[Rand(ArrayCount(hitWallDamStr))];
					} else if (dtype == 'HitSL') {
						 // No rammed or ram pilot?
						 if (rammed == none || rammed.pilot == none) {

							  if (v == instigator)
								   sds = hitSLDamStr[rand(arrayCount(hitSLDamStr))];
						 } else {
							  if (v == rammed.pilot) {
								   sds = hitSLDamStr2[rand(arraycount(hitSLDamStr2))];
							  } else if (v == instigator) {
								   // This will print a blank line. Oh well.
								   sds = " ";

							  }
						 }
					} else if (dtype == 'Shot') {
						 if (v == instigator) {
							  sds = shotSelfDamStr;
						 } else if (v == pilot || v == gunner) {

							  sds = shotDamStr;
						 }
					}
					  u.setDamageString(sds, instigator, v);
			   }
			   dir = v.location - hl;
			   dist = fmax(1, vsize(dir));
			   dir = dir / dist;
			   dscale = 1 - fmax(0, (dist - v.collisionRadius) / rad);
			   v.takeDamage(dscale * dam, instigator, v.location - 0.5 * (v.collisionHeight + v.collisionRadius) * dir, dscale * mom * dir, myDamageType);
		  }
		continue;
	}
	bHurtEntry = true;

}

/** Store this guy. He just ejected. If we have 3 ejects within
	 the eject lapse, then we lose whoever was in the first
	 slot. So be it.
*/
function storeEject(Pawn p) {
	 local float time;
	 time = level.timeseconds;
	 if (ejected[1] == none || (time - ejectTime[1]) > touchLapse) {
		  ejected[1] = p;
	 p.bHidden=False;
	 p.Visibility = p.Default.Visibility;
	 p.SetDefaultDisplayProperties();
		  ejectTime[1] = time;
	 } else {
		  ejected[0] = p;
	 p.bHidden=False;
	 p.Visibility = p.Default.Visibility;
	 P.SetDefaultDisplayProperties();
		  ejectTime[0] = time;
	 }
}

/** Was this guy recently ejected?
*/
function bool wasEjected(Pawn p) {
	 if (ejected[0] == p && (level.timeseconds - ejectTime[0]) <= touchLapse)
		   return true;
	  else if (ejected[1] == p && (level.timeseconds - ejectTime[1]) <= touchLapse)
		return true;

	 return false;
}


/** Returns true if they are in front of us. Roughly.
*/
function bool fromFront(Actor a) {
	 local vector dir, x, y, z;

	 if (a != none) {
			dir = normal(a.location - location);
			getAxes(rotator(velocity), x, y, z);
			// Is this like 45 degrees? Not sure...
		  return ((dir dot x) > 0.7);
	 } else {
		  return false;
	   }
}
/** Spit out some sparks.
*/
simulated function sparks(int dam) {
	 local int isparks;
	 if (level.netmode != NM_DedicatedServer) {
		  for (isparks = min(15, dam / 2); isparks > 0; isparks--)
			   spawn(Class'SLSparker');
	 }
}

/* if taking damage from the front, there should be a chance of
	 detonation - if armed.
	 Should this be singular? No. As an example, imagine our rocket
	 bumps into another rocket. We take a slight bit of damage, but the
	 other rocket explodes. Their explosion causes us massive damage. If
	 this function were singular, we'd be left unscathed. What we do is, if
	 our armor's already depleted, we return so we don't explode again.
*/

function takeDamage(int dam, Pawn i, vector hl, vector m, name dtype) {
     if (HUD != none) {
          HUD.shake(dam * 0.25);
     }

     if (armor < 0) {
          return;
     }

     sparks(dam);


     if (role < ROLE_Authority)
          return;

     // The instigator is what team we're on.
     if (i != instigator && sameTeam(i, instigator))
          dam *= teamDamage;

     armor -= dam;

     // Explode, either by shot damage or accidental (heh) detonation.
     if (armor <= 0 || (armed() && fromFront(i) && frand() < 0.40)) {

          // Reset the instigator so that whoever shot us gets credit.

          if (i != none && i != pilot)
               instigator = i;

	  if (i != None && TournamentPlayer(i) != None && (pilot != None || gunner != None))
	  {
		if (dtype == 'TopGun')
		{
			TournamentPlayer(i).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 12); //TOP GUN
			i.PlayerReplicationInfo.Score += class'Strangemutator'.default.TopGunBonus;
		}
	  	else if (dtype != 'NoUpdate' && dtype != 'Ram' && dtype != 'HitWall' && dtype != 'HitSL' && dtype != 'SpecialDamage' && dtype != 'RedeemerDeath' && dtype != 'TopGun' && VSize(hl - i.Location) > class'Strangemutator'.default.EagleEyeMinDist)
		{
			TournamentPlayer(i).ReceiveLocalizedMessage( Class'vxSpecialFragEvent', 3);	//EAGLE EYE
			i.PlayerReplicationInfo.Score += class'Strangemutator'.default.EagleEyeBonus;
		}
	  }

          if (armed()) {
               detonate(hl, vect(0, 0, 1));
          } else {

               // If it's not one of these, we were shot down.
               if (dtype != 'HitWall' && dtype != 'HitSL' && dtype != 'Ram')
                    self.dtype = 'Shot';


               playSound(crashSound, SLOT_None, 8.0);

               explode(hl, vect(0, 0, 1));
          }

     } else {
          // Just a scratch. Play the dent sound.
          //if (type != 'HitWall')
               playSound(hullHits[rand(arrayCount(hullHits))], SLOT_None, 6.0);
     }
}


/** This will get called on the client when we switch to sim proxy.
*/
simulated function hitWall(vector hn, Actor wall) {
     local float dam;
     local DirectionalBlast db;

     if (armed()) {
          // Blast decal.
          spawnBlast(true, location, hn);

          if (role == ROLE_Authority) {
               if ((Mover(wall) != none) && Mover(wall).bDamageTriggered)


                    // Bogus damage type.
                    wall.takeDamage(damage, instigator, location, normal(velocity) * momentumTransfer, 'RocketCrash');

               makeNoise(1.0);
               detonate(location + explowallout * hn, hn);
          }

          // Don't call hitwall again.
          setPhysics(PHYS_None);

          // warstat == 1 code adapted from Projectile.hitWall().
          //super.hitWall(hn, wall);

     } else {
          dam = reflect(hn, wall);


          if (level.netmode != NM_DedicatedServer) {
               db = spawn(Class'DScar', self);
               if (db != none) {
                    db.drawScale *= (dam * 0.03);
                    db.directionalAttach(velocity, hn);
               }
          }
     }




}


/** We have hit something. hn is the hit normal. Returns the amount of
	 damage inflicted.
	 In SL-SL collisions, this resets the velocity, which affects the
	 second rocket's reflect() call. FIX.
*/
simulated function float reflect(vector hn, Actor a, optional float soften) {

	 local float theta;
	 local vector nv, x, y, z;
	 local float relv;
	 local float dam;

	 if (soften == 0.0)
		  soften = 1.0;

	 // Default is hit wall.
	 if (a.isA('StrangeShell'))

		  dtype = 'HitSL';
	 else
		  dtype = 'HitWall';

	 // Angle of impact. 1 is head on. Near 0 is losing a coat of
	 // paint. Sometimes we're passed an inverse normal for simplicity, so
	 // take the abs().
	 theta = abs(normal(velocity) dot hn);
	 relv = vsize(velocity - a.velocity);

	 // Average the angle and speed components. 100.0 is usually the
	 // default armor (max. damage). 1000.0 is usually maxspeed. The
	 // angle counts twice as much.
	 dam = ((2.0 * (theta / crushAngle) + (relv / 1000.0)) / 3.0) * 100.0 * soften;

	 // Theta causes up to a 40% reduction in speed.

	 nv = mirrorVectorByNormal(velocity, hn) * (1.0 - 0.40 * theta);

	 if (soften < 1.0)
		  velocity = (velocity * (1.0 - soften) + nv * soften);
	 else
		  velocity = nv;

	 // Use the new velocity. Could we find a better hit location to use?
	 if (role == ROLE_Authority) {
		  takeDamage(dam + (rand(10) - 5), instigator, location, normal(velocity) * momentumTransfer, dtype);

		  // Don't piss off CSHP. Server only.
		  if (pilot != none) {
			   pilot.clientSetRotation(rotator(velocity));
		  }
	 }

	 guidedRotation = rotator(velocity);

	 // This'll never happen.
	 if (bNoFuel)
		  spin();

	 playSound(bounces[rand(ArrayCount(bounces))], SLOT_None, 4.0);

	 return dam;
}
simulated function float arccos(float x) {
	 return atan((sqrt(1 - x ^ 2)) / x);
}
/** Toggles the afterburners.
*/
function Afterburn()
{
	if (bNoFuel)
		return;

	if (bAfterburn)
	{
		playSound(abFadeSound, SLOT_None, 20.0);
		bAfterburn = false;
		throttle = thrprev;
	}
	else 
	{
		playSound(abKickSound, SLOT_None, 20.0);
		bAfterburn = true;
		thrprev = throttle;
		throttle = 1.5;
	}
	updateSound(1);

	/*if (pawn(owner).PlayerReplicationInfo.Team == 0)
	{
	if (bAfterburn)
	{
			bAfterburn = false;
			throttle = thrprev;
			/*REF1.drawScale = 0.4;
			REF2.drawScale = 0.4;
			REF3.drawScale = 0.4;
			REF4.drawScale = 0.4;*/
		} else {
			bAfterburn = true;
			thrprev = throttle;
			throttle = 1.5;
			/*REF1.drawScale = 0.8;
			REF2.drawScale = 0.8;
			REF3.drawScale = 0.8;
			REF4.drawScale = 0.8;*/
	}
		updateSound(0);
	}
	else  if (pawn(owner).PlayerReplicationInfo.Team == 1)
	{
	if (bAfterburn)
	{
		bAfterburn = false;
		throttle = thrprev;
		/*BEF1.drawScale = 0.4;
		BEF2.drawScale = 0.4;
		BEF3.drawScale = 0.4;
		BEF4.drawScale = 0.4;*/
	} else {
		bAfterburn = true;
		thrprev = throttle;
		throttle = 1.5;
		/*BEF1.drawScale = 0.8;
		BEF2.drawScale = 0.8;
		BEF3.drawScale = 0.8;
		BEF4.drawScale = 0.8;*/
	}
		updateSound(0);
	}
	else  if (pawn(owner).PlayerReplicationInfo.Team == 2)
	{
	if (bAfterburn)
	{
		bAfterburn = false;
		throttle = thrprev;
		/*GEF1.drawScale = 0.4;
		GEF2.drawScale = 0.4;
		GEF3.drawScale = 0.4;
		GEF4.drawScale = 0.4;*/
	} else {
		bAfterburn = true;
		thrprev = throttle;
		throttle = 1.5;
		/*GEF1.drawScale = 0.8;
		GEF2.drawScale = 0.8;
		GEF3.drawScale = 0.8;
		GEF4.drawScale = 0.8;*/
	}
		updateSound(0);
	}
	else  if (pawn(owner).PlayerReplicationInfo.Team == 3)
	{
	if (bAfterburn)
	{
		bAfterburn = false;
		throttle = thrprev;
		/*GNEF1.drawScale = 0.4;
		GNEF2.drawScale = 0.4;
		GNEF3.drawScale = 0.4;
		GNEF4.drawScale = 0.4;*/
	} else {
		bAfterburn = true;
		thrprev = throttle;
		throttle = 1.5;
		/*GNEF1.drawScale = 0.8;
		GNEF2.drawScale = 0.8;
		GNEF3.drawScale = 0.8;
		GNEF4.drawScale = 0.8;*/
	}
		updateSound(0);
	}*/
}

function newOwner(Actor o) {
	// u.debug("newOwner(" $ u.sname(o) $ ")");
	 setOwner(o);
}

/** Returns true if the game's over.
*/
simulated function bool gameOver() {
	 return (GRI != none && GRI.gameEndedComments != "");
}
/** Handles fuel usage. Called from the controller's tick()
	 function. Midair (after no-fuel condition) refueling does not work
	 yet. FIX.
*/
simulated function burnFuel(float delta) {
	 local float fr;
	 local float dffx;
	 local bool DamageFX;
	 //local float RocketArmor;
	// u.debug("burnFuel(): current fuel: " $ fuel, DL_Verbose);

	 // Don't burn fuel after game's over.
	 if (gameOver())
		  return;

	 // Burn fuel. Only do this on the server and owner client. The
	 // owner client only does this to render the fuel gauge.
	 if (role == ROLE_Authority || (u != None && u.hasViewport(pilot))) {
		  if (fuel > 0.0)

			   {
			   if (DamageFX == true)
					dffx = (armor / default.armor);

			   if (DamageFX != true)
					dffx = 1;
					dffx = (armor / default.armor);
					fr = (baseFuelRate / dffx);
					if (bAfterburn)
					fr *= afterburnRate;
					fuel = fmax(0.0, fuel - fr * delta);
					return;

			   }


		  // Try to refuel. The client refuels, but doesn't ditch a pod.
		  if (fuel == 0.0) {
			   if (!refuel() && role == ROLE_Authority)
					bNoFuel = true;
			   else

		  }

	 }

	 // We don't really know we're out of fuel until the server sets
	 // bNoFuel to true. We only run this "out of fuel" code once.

	 if (bNoFuel) {
		  if (!bClientNoFuel) {
			  // u.debug("burnFuel(): Uh oh, no fuel.");
			   // Cut the engines yo.
			   updateSound(0);
			   // We should be falling down...
			   setRemoteRole(pilot);
			   setPhysics(PHYS_Falling);
			   if (pilot != None)
			  	pilot.bHidden=false;
			   noFuel();
			   spin();
			   bClientNoFuel = true;
		  }
	 }
}

/** This gets called when the shell runs out of fuel.
*/
function noFuel() {
	if (pilot != None)
	{
	     eject(pilot, 0, true);
	}
	if (gunner != None)
	{
	     eject(gunner, 0, true);
	}
	if (pilot != None)
	{
	     pilot.bHidden = false;
	}
	if (gunner != None)
	{
	     gunner.bHidden = false;
	}
}


simulated function spin() {
	 randspin(rand(10000) + 10000);
}


/** This handles refueling from carried fuel cores. It is called on
	 both (owner) client and server, but the "no fuel" condition is
	 passed to the client from bNoFuel on the rocket.
*/
simulated function bool refuel() {

	 if (pilot != none) {

		  if (fc != none && fc.ammoAmount > 0) {

			   if (role == ROLE_Authority)
					fc.useAmmo(1);

			   playSound(refuelSound, SLOT_None, 1.0);
			   fuel = default.fuel;
			   return true;
		  }
	 }
	 return false;
}


	 // If the game's over... freeze. Damnit this only works for players and guided rockets (fine).
simulated function tick(float delta) {

	 if  (bNoFuel)
		  return;
	 if (dumb) {
		  burnFuel(delta);
		  return;
	}

	 if (GRI != none && GRI.gameEndedComments != "") {
		 setPhysics(PHYS_None);
		  velocity = vect(0, 0, 0);
		 return;
	}

	 // The role is still auto on non-viewport clients. Duh. Took me

	 // this long to figure that out. Can't test for sim proxy on the client.
	 if (level.netmode == NM_Client && ((instigator != None && instigator.isA('Bot')) || (u != None && !u.hasViewPort(instigator))))   {
		  updateSimProxy();
		  return;

	 // WTF is this? When does this happen? FIX.
	 } else if ((level.netmode != NM_Standalone) && (remoteRole == ROLE_AutonomousProxy)) {
		  return;
	 }

	 // if server updated client position, client needs to replay moves after the update
	 if (bUpdatePosition)
		  clientUpdatePosition();

	 // Keep goin straight if we're dead!
	 if (guided())
	 if (pInfo.brain != none && pInfo.brain.bGuiding)
			guidedRotation = pInfo.brain.getGuidedRotation();
		 else
			guidedRotation = pilot.viewRotation;
	 if (role == ROLE_AutonomousProxy)
		   autoMove(delta);
	 else
		  moveRocket(delta, velocity, guidedRotation);
}
simulated function updateSimProxy() {
	 if (updateReal(realLocation, location, 20.0)) {
		// u.debug("updateSimProxy: real loc: delta: " $ vsize(realLocation - location), DL_Verbose);
		  setLocation(realLocation);
		  realLocation = vect(0, 0, 0);
	 }
	 if (updateReal(realVelocity, velocity, 0.0)) {
	   // u.debug("updateSimProxy: real vel: delta: " $ vsize(realVelocity - velocity), DL_Verbose);
		  velocity = realVelocity;
		  // Aproximate the rotation on sim proxies (no roll).
		  setRotation(rotator(velocity));
		  realVelocity = vect(0, 0, 0);
	 }
	 if (updateReal(realAccel, acceleration, 0.0)) {
	   //  u.debug("updateSimProxy: real acc: delta: " $ vsize(realAccel - acceleration), DL_Verbose);
		  acceleration = realAccel;
		  realAccel = vect(0, 0, 0);
	}
}
simulated function bool updateReal(vector v1, vector v2, float mindelta) {
	 return (v1 != vect(0, 0, 0) && vsize(v1 - v2) > mindelta);
}
/** Auto proxy movement. Called from tick(). Calls serverMove().
*/
function autoMove(float delta) {
	 local SavedMove nm;

	 // Send the move to the server. Skip move if too soon.
	 if (clientBuffer < 0) {
		  clientBuffer += delta;
		  moveRocket(delta, velocity, guidedRotation);
		  return;
	 } else {
			clientBuffer = clientBuffer + delta - 80.0 / PlayerPawn(instigator).player.currentNetSpeed;
	 }
	  // I'm a client, so I'll save my moves in case I need to replay
	 // them. Get a SavedMove actor to store the movement in.
	 if (savedMoves == none) {
		  savedMoves = getFreeMove();
		  nm = savedMoves;
	 } else {
		  nm = savedMoves;
		  while (nm.NextMove != none)
		  nm = nm.nextMove;
		  nm.nextMove = getFreeMove();
		  nm = nm.nextMove;
	 }
	 nm.timestamp = level.timeseconds;
	 nm.delta = delta;
	 nm.velocity = velocity;
	 nm.setRotation(guidedRotation);
	 moveRocket(delta, velocity, guidedRotation);
	 serverMove(level.timeseconds, location, nm.rotation.pitch, nm.rotation.yaw);
}
/** Is there a pilot and is he conscious?
*/
simulated function bool guided() {
	 return (pilot != none && !bShootMode && pilot.health > 0);
}
/** Server replicates this to the client.
*/
simulated function clientAdjustPosition(float ts, float nlx, float nly, float nlz, float nvx, float nvy, float nvz) {
	 super.clientAdjustPosition(ts, nlx, nly, nlz, nvx, nvy, nvz);
	// u.debug("clientAdjustPosition(): new v: " $ vsize(velocity), DL_Verbose);
}
/** Had to modify this slightly.
*/
simulated function clientUpdatePosition() {
	 local SavedMove curm;
	 bUpdatePosition = false;
	 curm = savedMoves;
	 while (curm != none) {
		  if (curm.timestamp <= currentTimeStamp) {
			   savedMoves = curm.nextMove;
			   curm.nextMove = freeMoves;
			   freeMoves = curm;
			   freeMoves.clear();
			   curm = savedMoves;
		  } else {

			   // Use the current velocity, not the stored one!
			   moveRocket(curm.delta, velocity, curm.rotation);
			   curm = curm.nextMove;
		  }
	 }
	 //u.debug("clientUpdatePosition(): updated v: " $ vsize(velocity), DL_Verbose);
	 //super.clientUpdatePosition();
}
/** Client replicates this to the server. Called only from tick().
*/
function serverMove(float ts, vector clientloc, int pitch, int yaw) {
	 local float clientErr, delta;
	 local vector dloc;

	 if (currentTimeStamp >= ts)
		  return;

	 if (currentTimeStamp > 0)
		  delta = ts - currentTimeStamp;
	 currentTimeStamp = ts;
	 guidedRotation.pitch = pitch;
	 guidedRotation.yaw = yaw;

	 if (delta > 0)
		  moveRocket(delta, velocity, guidedRotation);


	 if (level.timeseconds - lastUpdateTime > 0.4) { //0.3) {
		//  u.debug("serverMove(): sec since last update: " $ (level.timeseconds - lastUpdateTime), DL_Verbose);
		  clientErr = 10000;
	 } else if (level.timeseconds - lastUpdateTime > 0.07) {
		  dloc = location - clientloc;

		  clientErr = dloc dot dloc;
		  errorSum += clientErr;
	 }

	 // If client has accumulated a noticeable positional error, correct him.
	 if (clientErr > 3) {
		  lastUpdateTime = level.timeseconds;
		//  u.debug("serverMove(): sending updated pos: clientErr: " $ clientErr, DL_Verbose);
		  clientAdjustPosition(ts, location.x, location.y, location.z, velocity.x, velocity.y, velocity.z);

	 }

	 //super.serverMove(ts, clientloc, pitch, yaw);
}

/** This clamps the guide rotation to 90 degree turns. We don't want
	 exact 180 turns else the rocket may shoot straight up or down.
	 Also clamp pitch to below 16384. The yaw goes wild past that.
*/
simulated function rotator adjustGuideRot(rotator gr, rotator rr) {
	 local float dyaw, pitch;
	 local rotator newr;

	 // This returns the last known guide rotation, i.e. straight. :)
	 if (!guided() || pilot.isA('Bot'))
		  return gr;
	 dyaw = (pilot.viewRotation.yaw & 65535) - (rr.yaw & 65535);
	 pitch = gr.pitch;
	 u.centerRotComp(dyaw);
	 u.centerRotComp(pitch);
	 newr = gr;
	 newr.yaw = rr.yaw + clamp(dyaw, -16384, 16384);
	 newr.pitch = clamp(pitch, -16384, 16384);

	 return newr;
}
/** Actually moves the rocket based on the passed criteria. Eventually
	 calls autonomousPhysics().
*/
simulated function moveRocket(float delta, vector cv, rotator gr) {
	 local vector deltav;
	 local int maxroll, oldroll, rollmag;
	 local float smoothRoll;
	 local vector oldv, x, y, z;

	// u.debug("moveRocket(): delta: " $ delta $ " cv: " $ vsize(cv) $ " gr: " $ u.sr(gr), DL_Verbose);


	 if (lastTP != none) {
		  if (lastTPRot != rotation) {
			 //  u.debug("moveRocket(): teleported! new rot: " $ u.sr(rotation), DL_Verbose);


			if (bInvertTeleport)
			{
			   	cv = vsize(velocity) * vector(rotation);
			   	velocity = cv;
			   	gr = rotation;
			}
		  }
		  lastTP = none;

		 //tartContrail();
	 }

	 serverUpdate = level.timeseconds;
	 oldroll = (rotation.roll & 65535);
	 oldv = cv;

	 // This is our steering component. Its strength is based on the
	 // current velocity. At higher speeds it's lower.
	 // Sliding effects adjustable or if 0 use delta
	 if (SlideFX !=0)
	 deltav = vector(adjustGuideRot(gr, rotator(cv))) * ((MaxSpeed + 700) - vsize(cv)) * (((SlideFX * 0.001568) + 0.05) * (armor / default.armor));
	 else
	 deltav = vector(adjustGuideRot(gr, rotator(cv))) * ((MaxSpeed + 700) - vsize(cv)) * delta;

	 // Here, we blend the current velocity (momentum) and the steering
	 // vector from above to get the sliding effect.
	 velocity = normal(cv + deltav) * vsize(cv);
	 // Handle the rolling.
	 maxroll = 65536 * 0.25;
	 getAxes(gr, x, y, z);
	 rollmag = int(10 * (y dot (velocity - oldv)) / delta);

	 if (rollmag > 0)
		  gr.roll = min(maxroll, rollmag);

	 else
		  gr.roll = max(65536 - maxroll, 65536 + rollmag);

	 // Smoothly change the rotation.
	 if (gr.roll > 32768) {
		  if (oldroll < 32768)
			   oldroll += 65536;

	 } else if (oldroll > 32768)
		  oldroll -= 65536;

	 smoothroll = fmin(1.0, 2.0 * delta);
	 gr.roll = gr.roll * smoothroll + oldroll * (1 - smoothroll);

	 setRotation(gr);

	 /** Normally an auto proxy does not move based on its physical
		  properties like acceleration and velocity unless you tell it to. We
		  only want to call autoPhysics() if it's a network game (where the
		  auto proxy role is used). And, on listen servers, only if it's not the
		  local viewport.

		  The auto proxy role shows up on all the clients, so we can't
		  specifically test for it. So we test netmodes, viewport (if a listen
		  server), and pilot (for dumb fires and ejected pilots).
	 */
	 // Do autonomous physics if:
	 // We're not playing standalone and...
	 if ((level.netmode != NM_Standalone) &&
		  // If we're a listen server, there's no viewport (remote player) and...
		  (level.netmode != NM_ListenServer || !u.hasViewPort(instigator)) &&
		  (!instigator.isA('Bot')) &&
		  // We have a pilot.
		  (pilot != none)) {

		 // u.debug("moveRocket(): auto physics", DL_Verbose);
		  autonomousPhysics(delta);
	 }

	 if (role == ROLE_Authority) {
		  realLocation = location;
		  realVelocity = velocity;
		  realAccel = acceleration;
	 }

}

function float damageadjust ( float hullarmor )
{
	local float armult;
	armult = 1;
	if ( hullarmor <= default.armor * 0.75 )
		armult = 1.25;
	if ( hullarmor <= default.armor * 0.5 )
		armult = 1.5;

	if ( hullarmor <= default.armor * 0.30 )
		armult = 1.9;
	if( hullarmor < default.armor )
		hullarmor = Fmin( ( hullarmor / default.armor )*armult , default.armor ) ;
	return hullarmor;
}

simulated function destroyed() {
	local Pawn p;
	local nullweapon nw;

	if (level.netmode != NM_DedicatedServer && !level.bDropDetail) //here
		spawnWreckage();

	if ( JetRed != none )
	{
		if (nw != none)
			nw.Destroy();
                JetRed.destroy();
		/*if (REF1 != none)
		{		
			REF1.destroy();
		}
		if (REF2 != None)
		{		
			REF2.destroy();
		}*/
		
		if (p != None)
		{
			p.bHidden=false;		
		}
		if (nw != none)
			nw.Destroy();
	}

	if (role == ROLE_Authority)
		if (level.netmode != NM_Standalone)
		if (nw != none)
			nw.Destroy();

		// Let the bot brain know how we died.
		clearRider(pilot, pInfo, dtype);
		clearRider(gunner, gInfo);
		if (p != None)
			p.bHidden=false;
	   // g.bHidden=false;
		if (gunner != None)
		 	gunner.bHidden=false;

//  if (rootct != none)
//      rootct.end();

	if (JCBX != none) JCBX.Destroy();
	
     if ( JetRed != none )
	{
		if (nw != none)
			nw.Destroy();
		/*if (REF1 != none)
		{		
			REF1.destroy();
		}
		if (REF2 != None)
		{		
			REF2.destroy();
		}*/
                JetRed.destroy();		
		if (p != None)
		{
			p.bHidden=false;		
		}
		if (nw != none)
			nw.Destroy();
	}

	if (nw != None)
		nw.Destroy();

	spawnBlast();
	super.destroyed();

	if (p != None)
		p.bHidden=false;
	//g.bHidden=false;
	if (gunner != None)
	 	gunner.bHidden=false;
	}

/** Two cases: 1. We're calling this from hitwall() - use the supplied
	 hit location and normal. 2. On the client, destroyed() has been called

	 before a hitwall. In the off chance (likely on a LAN) that the destroy
	 notification arrives from the server before the hitwall is called on
	 the client, we need to spawn our own decal.
*/
simulated function spawnBlast(optional bool havev, optional vector hitl, optional vector hitn) {

	 local vector x, y, z, hl, hn;


	 local Actor wall;

   //  u.debug("spawnBlast()", DL_Verbose);

	 if (bBlasted || level.netmode == NM_DedicatedServer)
		  return;

	 if (havev) {
		  hl = hitl;
		  hn = hitn;

	 } else if (role < ROLE_Authority && level.netmode != NM_Standalone) {
		  getAxes(rotation, x, y, z);
		  wall = trace(hl, hn, location + x * 200, location, false);
		  if (wall == none)
			   return;
	 }

	 

	 bBlasted = true;
}


simulated function spawnWreckage() {
	 local int i;
	 local Wreckage w;
	 local int num;
	 num = 5 + rand(10);
	 for (i = 0; i < num; i++) {
		  w = spawn(class'Wreckage',,, location, rotator(vrand()));
			  w.eject(velocity * 1.0 + (vrand() * vsize(velocity) * 1.0));
	 }
}

/** Set the gunner.
*/
function setGunner(Pawn g) {

	 local string s;
	 local Inventory IG;

	 gunner = g;
	 g.SetDefaultDisplayProperties();
	 IG = g.FindInventoryType(class'UT_ShieldBelt');
	 if ( (IG != None) && (UT_Shieldbelt(IG).MyEffect != None) )
		 UT_Shieldbelt(IG).MyEffect.bHidden = True;
		  g.SetDisplayProperties(ERenderStyle.STY_Translucent, FireTexture'unrealshare.Belt_fx.Invis', true, true);
		  g.Visibility = 10;
		  g.bHidden=True;
		  g.playSound(gunnerSound, SLOT_None, 4.0 * g.soundDampening);
	 setupRider(g, gInfo);

	 if (pilot != none)
		  s = gunnerMountStr[rand(arrayCount(gunnerMountStr))];
	 else
		  s = gunnerMountStr2[rand(arrayCount(gunnerMountStr2))];;

	 broadcastMessage(u.parseKillString(s, g, pilot, true));
}

/** Sets up the controller for a new pilot. Usually called just after
	 the controller is spawned.
*/
function setPilot(Pawn p, optional Skynet Skynet, optional Skynode launchsn) {

	 local Inventory IP;
	 pilot = p;

//=====================================================================
// Sets Pilots display to Invisable and if has shieldbelt it is also
// Invisable.
//
	 p.SetDefaultDisplayProperties();
	 IP = p.FindInventoryType(class'UT_ShieldBelt');
	 if ( (IP != None) && (UT_Shieldbelt(IP).MyEffect != None) )
		 UT_Shieldbelt(IP).MyEffect.bHidden = True;
	 p.SetDisplayProperties(ERenderStyle.STY_Translucent, FireTexture'unrealshare.Belt_fx.Invis', true, true);
	 p.bHidden=True;
//====================================================================
	 setupRider(p, pInfo, Skynet, launchsn);
	 if (p.isA('PlayerPawn')) {
		  savedBob = PlayerPawn(p).bob;
		  PlayerPawn(p).bob = 0;
		  // So we can fire while ducking and not go straight to shoot mode.
		  // Uh, okay. It's a "feature" now.
		  // bDuck = PlayerPawn(p).bDuck;
	 } else if (p.isA('Bot')) {
		  // Bot need to go slow.
		  throttle = 0.1;
	 }

	 // Save fc for the HUD.
	 fc = FuelCore(p.findInventoryType(class'FuelCore'));
	 // We do this just to init the shoot mode stuff.
	 bShootMode = true;
	 goShootMode();
}

function setupRider(Pawn p, out RiderInfo info, optional Skynet Skynet, optional Skynode launchsn) {
	 local StrangeShell sl;
	// u.debug("setupRider(" $ u.sname(p) $ ")");
	 info.pawn = p;
	 // Check if we were previously the pilot or gunner of another SL.
	 foreach radiusActors(class'StrangeShell', sl, 250) {
		  if (sl != self) {
			   if (sl.pilot == p)
					sl.clearRider(p, sl.pInfo);
			   if (sl.gunner == p)
					sl.clearRider(p, sl.gInfo);
		  }
	 }
	 if (p.isA('PlayerPawn'))
		  info.bOldJumpStatus = PlayerPawn(p).bJumpStatus;
	 info.bDelayedEject = false;
	 if (p.isA('Bot')) {
		info.brain = spawn(Class'SLBotBrain');
		  info.brain.setBot(Bot(p), self, Skynet, launchsn);
	 } else {
		  info.brain = none;
	 }
	 info.lastLoc = vect(0, 0, 0);
	 p.bWarping = true;
	 //p.bCollideWorld = false;
	 giveJD(p);
}

simulated function Pawn getPilot() {
	 return pilot;
}
/** Gunner accessor.
*/

simulated function Pawn getGunner() {
	 return gunner;
}
/** this should probably be called toggleShootMode(). */


function goShootMode() {

	 local Inventory IPSM;

	 if (role < ROLE_Authority)
			   return;


		 // u.debug("goShootMode()");

		  bShootMode = !bShootMode;

	 if (pilot.isA('PlayerPawn')) {
		//  adjustGlow();
		//  pilot.bHidden=true;
		  pilot.clientSetRotation(rotation);


	 }

	 if (bShootMode)
		  setCollisionSize(shootCR, default.collisionHeight);
	 else
		  setCollisionSize(default.collisionRadius, default.collisionHeight);
	 if (pilot != none)
		  handleInv(false);
//=====================================================================
// Sets Pilot display to Invisable and if has shieldbelt it is also
// Invisable if Pilot goes to shoot mode.
//
	 pilot.SetDefaultDisplayProperties();
	 IPSM = Pilot.FindInventoryType(class'UT_ShieldBelt');
	 if ( (IPSM != None) && (UT_Shieldbelt(IPSM).MyEffect != None) )
		   UT_Shieldbelt(IPSM).MyEffect.bHidden = True;
	 pilot.SetDisplayProperties(ERenderStyle.STY_Translucent, FireTexture'unrealshare.Belt_fx.Invis', true, true);
	 pilot.bHidden=True;
//====================================================================
}



/** While riding the rocket you can't shoot unless you're in shoot
	 mode, so we give you a useless 'null weapon' that doesn't really
	 do anything.
**/
function handleInv(bool ejected) {
	// u.debug("handleInv(" $ ejected $ "): weapon:" $ u.sname(pilot.weapon) $ " last:" $ u.sname(lastWeapon));

	 if (bShootMode || ejected) {
		  // I don't know in what case it's none. If they're dead?
		  if (pilot.weapon != none) {
			   // Hopefully this is always right.
			   if (pilot.weapon.isA('nullweapon')) {
					pilot.weapon = none;
					pilot.deleteInventory(nw);
					pilot.pendingWeapon = lastWeapon;
					pilot.changedWeapon();
					lastWeapon = none;
			   } else {
					u.err("handleInv(): Switching weapon back, but current is not a null.");
			   }
		  }
	   } else {
			// Store the previous weapon.
			lastWeapon = pilot.weapon;
			if (nw == none)
			   nw = createnullweapon();
			// Give it to them.
			nw.giveTo(pilot);
			pilot.pendingWeapon = nw;
		  //pilot.weapon.gotoState('DownWeapon');
		  pilot.changedWeapon();
	 }
}


/** We don't need to check for arena mutators anymore. Mine takes care
	 of it - screw everyone else's. :)
*/
function nullweapon createnullweapon() {

	 local nullweapon nw;
	nw = spawn(class'nullweapon', self);
	nw.sl = self;
	 return nw;
}
simulated function addHUD (PlayerPawn P)
{
	local SLHUD M;
	if ( U.UTPureOn(P) )
	{
		foreach AllActors(Class'SLHUD',M)
		{
			goto JL0081;
			continue;
JL0081:
		}
	}
	else
	{
		M=SLHUD(U.getHUDMutator(P,HUDClass.Name));
	}
	if ( M != None )
	{
		M.Reset(self);
	}
	else
	{

		Spawn(HUDClass,self);
	}
	addedHUD=True;
}


/** This is the old controller tick().
*/
simulated function ctick(float delta) {
	// u.debug("ctick(): loc: " $ u.sv(location) $ " ticked: " $ (bTicked == level.bTicked) $ " pilot: " $ u.sname(pilot) $ " gunner: " $ u.sname(gunner), DL_Normal, 5.0);

	 if (gunner != none) {
		  if (slc == none && level.netmode == NM_Client && u.hasViewPort(gunner))
			   slc = spawn(Class'Controller', self);
	 }
		  // -10 is a fudge factor...
		  if (!bWahooPlayed && vsize(velocity) >= (minspeed - 10)) {
			   playSound(sndWahoo, SLOT_None, 3.0);
			   bWahooPlayed = true;
		  }
		  // Here so client will get this call.
		  if (!addedHUD && u.hasViewPort(pilot))
			   addHUD(PlayerPawn(pilot));
  //   }
	 if (role == ROLE_Authority) {
		  handleEjects(pilot, pInfo);
		   handleEjects(gunner, gInfo);
	   }
	 // The dedicated server receives goShootMode() calls from the client.

	 if (level.netmode != NM_DedicatedServer && pilot != none && pilot.isA('PlayerPawn')) {
		  if (PlayerPawn(pilot).bDuck != bDuck) {
			   PlayerPawn(pilot).bDuck = 0;
			   bDuck = 0;
			 //  u.debug("tick(): calling goShootMode()");
			   goShootMode();
		  }
	 }
	 if (pilot != none)
		  adjustThrot(delta);
	 updateSound(delta);
	 if (bAfterburn && gunner != none && PlayerPawn(gunner) != none) {
		  PlayerPawn(gunner).shakeView(delta, 400, 7.5);
	 }
	 if (role >= ROLE_AutonomousProxy)
		  accelerate(delta);
	 // Limit this to being executed on pilot and gunner clients only? FIX.
	 // This is broken. Can't switch owners and auto proxies on the fly.
	 //takeover(delta);
	 burnFuel(delta);
	 // Last but not least, the heart and soul...
	 updateRiders();
}
function handleEjects(Pawn p, RiderInfo info) {
	 if (p != none) {
		  if (p.health <= 0) {
			   clearRider(p, info, 'Shot');
		p.bHidden = false;
		  } else if (info.bDelayedEject) {
			   eject(p);
		p.bHidden = false;
		  } else if (level.netmode != NM_Standalone && jumped(p, info)) {

			   eject(p);
	p.bHidden = false;
		 

		  }
	 }
}
/** d == 0 means this we're switching modes.

*/
simulated function updateSound(float d) {
	 // The drop sound overrides all others. We set it manually in eject().

	 if (ambientSound == sndDrop) {
		  soundRadius = 64.0;
		  soundVolume = 255;
		  soundPitch = 64.0;
		  return;
	 }

	 if (updateMarch(d))
		  return;
	 // Adjust ambient pitch and volume.
	 soundPitch = 24 + 40 * (vsize(velocity) / MaxSpeed);
	 if (bNoFuel) {
		  if (d == 0)
			   playSound(abFadeSound, SLOT_None, 20.0);

		  ambientSound = none;
	 } else if (bAfterburn) {
		  if (d == 0)
		  	playSound(abKickSound, SLOT_None, 20.0);

		  ambientSound = abLoopSound;
		  soundRadius = 128;
		  soundVolume = 255;

	 } else {
		  if (d == 0)
			   playSound(abFadeSound, SLOT_None, 20.0);

		  soundRadius = 64;
		  soundVolume = Min(255, 150 + 55 * (vsize(velocity) / MaxSpeed));
		  ambientSound = default.ambientSound;
	 }
}

simulated function bool updateMarch (float Delta)
{
	local int shields;
	local Inventory i;

	if ( pilot == None )
	{
		return False;
	}
	shields=0;
	i=pilot.Inventory;
JL0028:
	if ( i != None )
	{
		if ( i.bIsAnArmor )
		{
			shields += i.Charge;
		}
		i=i.Inventory;
		goto JL0028;
	}
	if ( (pilot.Health >= 199) && (shields >= 150) && (Armor >= Default.Armor) ) {

			bMarchPlaying=True;

			MaxSpeed = Class'StrangeShell'.default.MarchMaxSpeed;
			SlideFX = 255;

		//if ( bMarchUnder ) {

			if ( marchWait != -1.00 )
			{
				if ( marchWait > 4.50 )
				{

						playSound(sndTotalComm, SLOT_None, 1.0);

					marchWait=-1.00;
				}
				else
				{
					marchWait += Delta;
				}
			}
			AmbientSound=sndMarchLoop;
			SoundVolume=255;
			SoundPitch=64;
			return True;
		//}
	}

	else
	{
		MaxSpeed = Class'StrangeShell'.default.MaxSpeed;
		SlideFX = Class'StrangeShell'.default.SlideFX;
		bMarchUnder=True;
		marchWait=0.00;
		bMarchPlaying=False;
	}
	return False;
}


/** Loop for updating trailers.
*/

simulated function getTrailers() {
	 if (role == ROLE_AutonomousProxy || level.netmode == NM_StandAlone) {
		  findTrailers(pilot, pInfo);
		  findTrailers(gunner, gInfo);
	 }
}
simulated function findTrailers(Pawn p, out RiderInfo info) {
	 local Actor t;
	 local int i;

   //  u.debug("findTrailers(" $ u.sname(p) $ ")", DL_Verbose);

	 i = 0;
	 info.trailers[i] = none;
	 if (p != none) {
		  foreach p.childActors(class'Actor', t) {
			   if (t.physics == PHYS_Trailer) {

					info.trailers[i] = t;
					i++;
			   }
			   // We can only hold so many...
			   if (i == arrayCount(info.trailers))
					break;
		  }
	 }
}
/** Set the acceleration based on the throttle level.
*/
simulated function accelerate(float delta) {
	 local float max, amax;
	 //local float desired, speed;
	 local float dfx;

	 if (DamageFX == true)
		  dfx = (armor / default.armor);
	 if (DamageFX != true)
		  dfx = 1;
	 if (dfx >= 0.65)
		  {
		  if (bAfterburn)
			   {
			   max = MaxSpeed;

			   }
	 else
		  if (!bAfterburn)

			   {
			   max = fullspeed;
			   }

		  }
	 if (dfx < 0.65)
		  {
		  if (bAfterburn)
			   {
			   max = (MaxSpeed * 0.85);

			   }

	 else
		  if (!bAfterburn)

			   {
			   max = (fullspeed * 0.80);

			   }
	 }

	 // Both the pilot and gunner add drag and reduce the max speed.

	 speed = vsize(velocity);
	 desired = lerp(fmin(throttle, 1.0), minspeed, max);
	 amax = (AccelMax * dfx);

	/*log("Desired speed = "$int(desired));
	log("Current speed = "$int(speed));
	log("Max speed = "$Int(max));
	log("--------------------------------");*/


	 if (desired < speed)
		  // No reverse jets!
		  amax *= ((AirBrakes * -0.0098) * dfx); // Airbrakes ratio. (0 to -3)
	 if (bAfterburn)
	 	amax *= (2.0 * (dfx * 2));

	 // If we're close, just zero it.
	 if (abs(speed - desired) < 0.5)
		  acceleration = vect(0, 0, 0);

	 else
		  // Within 50, slow down.
		  acceleration = vector(rotation) * (fmin(abs(speed - desired) / 50.0, 1.0) * amax);
}
/** Called on the client to determine what's up with the
	 throttle. Adjustments are sent to the server with clientSendThrot()
	 when let go.
*/


simulated function adjustThrot(float delta) {
	 if (pilot.isA('PlayerPawn') && ViewPort(PlayerPawn(pilot).player) != none && !bAfterburn) {
		  if ((PlayerPawn(pilot).bWasForward || throtDir == 1) && thlvl < 1.0) {
			   thlvl = fmin(thlvl + delta * thrate, 1.0);
			   bThrotSent = false;
		  } else if ((PlayerPawn(pilot).bWasBack || throtDir == -1) && thlvl > 0.0) {
			   thlvl = fmax(thlvl - delta * thrate, 0.0);
			   bThrotSent = false;
		  } else {
			   // Did they let go?
			   if (!bThrotSent) {
					//if (role < ROLE_Authority) {
						 clientSendThrot(thlvl);
					//} else {
						 //throttle = thlvl;
					//}
					bThrotSent = true;
			   }
		  }

		  if (thlvl == 0.0 || thlvl == 1.0)
			   throtDir = 0;
	 }

	/*if (PlayerPawn(pilot) != None)
	{
		if (PlayerPawn(pilot).bWasRight && !bRightSelected)
		{
			SelectWeaponToUseInverted();
			bRightSelected = True;
		}
		else if (PlayerPawn(pilot).bWasLeft && !bLeftSelected)
		{
			SelectWeaponToUse();
			bLeftSelected = True;
		}

		if (!PlayerPawn(pilot).bWasRight && bRightSelected)
			bRightSelected = False;
		if (!PlayerPawn(pilot).bWasLeft && bLeftSelected)
			bLeftSelected = False;
	}*/
}

/** Client sends the adjusted throttle result to the server.

*/
function clientSendThrot(float thr) {

	// u.debug("clientSendThrot(" $ thr $ ")");
	 // Make sure they're sending a valid throttle.
	 throttle = FClamp(thr, 0.0, 1.0);
}

/** Client sends the adjusted throttle result to the server.
*/
simulated function updateRiders() {


     local vector x, y, z, loc;
     // Minimum safe distance.

     local float d, mx, my, th;
      local Pawn p;
     // This positions the rider slightly behind and above the
     // rocket's center, so it looks between their legs.



     getAxes(rotation, x, y, z);
     loc = location;

     if (pilot != none) {


          // Hmm, this sorta works. FIX.
          if (pilot.isA('PlayerPawn') && PlayerPawn(pilot).isInState('FeigningDeath')) {


               //PlayerPawn(pilot).rise();
               PlayerPawn(pilot).gotoState('PlayerWalking');
               PlayerPawn(pilot).weapon = nw;
          }

          loc += x * pilotOffset.x;     // + 50);   //(FireOffset.Y - 95) * Y
          loc += y * pilotOffset.y;
          loc += z * pilotOffset.z;

          // Adjust z for speed. Hug the rocket.
          loc -= z * (10 * vsize(velocity) / MaxSpeed);

          // Brain controls the rotation, not the bot.
          // CSHP - Only update rotation if the authority.
          if (pilot.isA('Bot') && !bShootMode && role == ROLE_Authority) {
               pilot.clientSetRotation(rotation);



          }



          updateRider(pilot, pInfo, loc);
     }
     // The closest way to pack two vertically oriented cylinders along
     // a line, depending on the the angle of the line:
     //
     // case 1: side by side (x is fixed - mx)

     // case 2: stacked (y is fixed - my).
     //
     // We have theta, solve for the hypotenuse.




     if (gunner != none) {




          if (pilot != none) {
               loc = pilot.location;

               // Min x and y distances.
              /*mx = (pilot.collisionRadius * 3 + gunner.collisionRadius);
              my = (pilot.collisionHeight * 3 + gunner.collisionHeight);


              //    mx = (pilot.collisionRadius + gunner.collisionRadius);



                //   my = (pilot.collisionHeight + gunner.collisionHeight);

               th = rotation.pitch / 10430.2192;

               if ((mx * tan(th)) < my) {
                    // Side by side.
                    d = mx / cos(th);
               } else {
                    // Stacked.
                    d = my / sin(th);

               }

               d += 1; // FUDGE FACTOR
               loc += x * -d;*/

		loc += FMax(pilot.collisionRadius + gunner.collisionRadius, pilot.collisionHeight + gunner.collisionHeight)*vect(-1,0,0) >> pilot.Rotation;
          } else {
               // Just use the gunner's collision radius to guesstimate the pilot's.
               loc = location;

              /* loc += x * pilotOffset.x; // - gunner.collisionRadius);
               loc += y * pilotOffset.y;

               loc += z * pilotOffset.z;*/

		loc += pilotOffset >> Rotation;
          }

          //updateRider(gunner, gInfo, loc);
	  //add a Z=+14 offset to gunner
	  updateRider(gunner, gInfo, loc + vect(0,0,14));
     }

}

simulated function updateRider(Pawn p, RiderInfo info, vector loc) {
     local EPhysics phys;

     // In order to intercept jump commands (with JumpDetector), we
     // have to set this to walking. Only for standalone games.
     if (level.netmode == NM_Standalone) {
          phys = PHYS_Walking;
     } else {
          phys = PHYS_None;


     }


     info.lastLoc = p.location;
     p.setLocation(loc);
     //p.move(loc - p.location);
     p.velocity = velocity;

     updateTrailers(p, info);
     p.setPhysics(phys);
}


/** We need to update any trailers because we just moved their
     owner. We don't need to update the trailer if it hasn't been ticked
     yet, though.

*/
simulated function updateTrailers(Pawn p, RiderInfo info) {
     local int i;


     for (i = 0; i < arrayCount(info.trailers) && info.trailers[i] != none; i++)

          if (info.trailers[i] != none && info.trailers[i].bTicked)
               info.trailers[i].autonomousPhysics(0);

}


/** Ejects somebody. In standalone games we have to suppress the jump
     velocity to keep the behavior consistent with net games. We can't do
     that here because it's set in PlayerPawn.doJump() *after*
    Inventory.ownerJumped() is called. So we wait one tick and do the
    eject which resets the velocity.
*/
function eject(Actor a, optional int delay, optional bool bForced) {

     local vector x, y, z, loc;
  //   u.debug("eject(" $ u.sname(a) $ ")", DL_Normal);

     if (a != none) {
          if (delay > 0) {
            //  u.debug("eject(): delaying one tick", DL_Normal);
               if (a == pilot)
                    pInfo.bDelayedEject = true;
               else
                    gInfo.bDelayedEject = true;

          } else {
               // We aren't setting the velocity on eject
               // anymore. Every tick.
               // In standalone games, the rider has PHYS_Walking
               // set, which limits their velocity. We need to reset
               // it here, and the velocity.
               if (level.netmode == NM_Standalone) {
                    resetPhysics(Pawn(a));

                    a.velocity = velocity;
               }

               // Add a little sideways dismount motion.
               getAxes(a.rotation, x, y, z);


               a.velocity += y * 100;

               if (a == pilot) {
                    if (!bForced) {

                         ambientSound = sndDrop;

                         a.playSound(sndPilotEj, SLOT_None, 4.0 * Pawn(a).soundDampening);

                         // We're ejecting. Time to arm the donuts.
                        autoArm();
                    }
                    clearRider(pilot, pInfo);
               } else {
                    // Gunner.
                    if (!bForced)
                         a.playSound(sndGunnerEj, SLOT_None, 4.0 * Pawn(a).soundDampening);
                    clearRider(gunner, gInfo);
               }



          }
     }
}


/** Removes the pilot. Normally called from eject(). If called from
     StrangeShell.destroy(), we are passed the damage type when we were


     destroyed.
*/
function clearRider(Pawn p, RiderInfo info, optional name dtype) {


     if (p == none)
          return;

    // u.debug("clearRider(" $ u.sname(p) $ ")");


     if (p == pilot) {
          handleInv(true);

          if (pilot.isA('PlayerPawn')) {
               PlayerPawn(pilot).bob = savedBob;

               if (!u.hasViewPort(pilot) && bFlipY) {

                    PlayerPawn(pilot).bInvertMouse = !(PlayerPawn(pilot).bInvertMouse);

                    bFlipY = false;
               }
          }

          // If they're in shoot mode, let them keep the same rotation.
          if (!bShootMode)
               pilot.clientSetRotation(rotation);

          // Reset the fog is it's on. Might not be if we're in shoot mode.
        //  if (bFog)
//               adjustGlow();


          // Hmm, iffy. Need to unset the owner so we can get the "real" data.
          newOwner(none);
          remoteRole = ROLE_SimulatedProxy;
          pilot = none;

     } else if (p == gunner) {
          gunner = none;

     } else {
          u.err("clearRider(): Tried to clear a non-rider!");
          return;
     }



     if (p.isA('Bot')) {
          if (info.brain != none) {


               if (dtype != '')
                    info.brain.deathBy(dtype);


               info.brain.destroy();



          }
          p.bCanFly = false;

          p.bCanWalk = true;
     }
     p.bWarping = false;


     //p.bCollideWorld = true;
     resetPhysics(p);
     clearJD(p);
     storeEject(p);

}


/**
     Reset a pawn's physics based on what type of zone it's in.
*/
function resetPhysics(Pawn a) {
     local EPhysics phys;

     if (a.region.zone.bWaterZone) {

          phys = PHYS_Swimming;
     } else {
          phys = PHYS_Falling;
     }

     a.setPhysics(phys);
}


/** Only used for standalone games. Gives the pawn an inventory item
     which detects jumps and calls eject. Other netmodes use
     bJumpStatus.
*/
/** Returns true in network games if they've jumped.
*/
function bool jumped(Pawn p, RiderInfo info) {

	return (p != none && p.isA('PlayerPawn') && PlayerPawn(p).bJumpStatus != info.bOldJumpStatus);
}

function giveJD(Pawn p) {

     local JumpDetector jd;



     if (p.isA('PlayerPawn') && (level.netmode == NM_Standalone || (level.netmode == NM_ListenServer && u.hasViewPort(p)))) {
        //  u.debug("giveJD(" $ u.sname(p) $ ")");

          jd = spawn(class'JumpDetector', self);
          jd.giveTo(p);
          jd.sl = self;

     }
}
/** Clears the jump detector.
*/
function clearJD(Pawn p) {
     local Inventory i;

    // u.debug("clearJD(" $ u.sname(p) $ ")");

     if (level.netmode == NM_Standalone) {
          i = p.inventory;
          while (i != none) {
               if (i.isA('JumpDetector')) {
                    i.destroy();
                    return;
               }
               i = i.inventory;
          }
     }

}

function WarnCannons()
{
     local Pawn P;

     for ( P=Level.Pawnlist; P!=None; P=P.NextPawn )
          if ( P.IsA('TeamCannon') && !P.IsInState('TrackWarhead') && P.LineOfSightTo(self) )
          {
               P.target = self;
               P.GotoState('TrackWarhead');
          }
}

//=================================================================
// Addded in case player dies in flight and Player display dosent reset
//
function pawnHealth() {

if ( Pawn(Owner).Health <= 0 );
          Pawn(Owner).bHidden=False;
          Pawn(Owner).Visibility = Pawn(Owner).Default.Visibility;
          Pawn(Owner).SetDefaultDisplayProperties();
}

//=======================================================================


simulated function bool sameTeam(Pawn p, Pawn p2) {
     return (p != none && p2 != none && level.game.isA('TeamGamePlus') && p.bIsPlayer && p2.bIsPlayer && p.playerReplicationInfo.team == p2.playerReplicationInfo.team);


}

simulated function CheckSideInput()
{
	if (PlayerPawn(pilot) != None)
	{
		if (PlayerPawn(pilot).bWasRight && !bRightSelected)
		{
			ClientSelectWeaponToUseInverted();
			bRightSelected = True;
		}
		else if (PlayerPawn(pilot).bWasLeft && !bLeftSelected)
		{
			ClientSelectWeaponToUse();
			bLeftSelected = True;
		}

		if (!PlayerPawn(pilot).bWasRight && bRightSelected)
			bRightSelected = False;
		if (!PlayerPawn(pilot).bWasLeft && bLeftSelected)
			bLeftSelected = False;
	}
}

function SelectWeaponToUse()
{
	if (WeapSelected >= 4)
		WeapSelected = 0;
	else
		WeapSelected++;

	if (!bManualWSelect)
	{
	if (WeapSelected == 1 && NormCmcX <= 0)
		WeapSelected = 2;
	if (WeapSelected == 2 && SeekCmcX <= 0)
		WeapSelected = 3;
	if (WeapSelected == 3 && RearCmcX <= 0)
		WeapSelected = 4;
	if (WeapSelected == 4 && SpecialCount <= 0)
		WeapSelected = 0;
	}
}

function ClientSelectWeaponToUse()
{
	if (WeapSelected >= 4)
		WeapSelected = 0;
	else
		WeapSelected++;

	
	if (!bManualWSelect)
	{
	if (WeapSelected == 1 && NormCmcX <= 0)
		WeapSelected = 2;
	if (WeapSelected == 2 && SeekCmcX <= 0)
		WeapSelected = 3;
	if (WeapSelected == 3 && RearCmcX <= 0)
		WeapSelected = 4;
	if (WeapSelected == 4 && SpecialCount <= 0)
		WeapSelected = 0;
	}
}

function ClientSelectWeaponToUseInverted()
{
	if (WeapSelected == 0)
		WeapSelected = 4;
	else
		WeapSelected--;

	
	if (!bManualWSelect)
	{
	if (WeapSelected == 4 && SpecialCount <= 0)
		WeapSelected = 3;
	if (WeapSelected == 3 && RearCmcX <= 0)
		WeapSelected = 2;
	if (WeapSelected == 2 && SeekCmcX <= 0)
		WeapSelected = 1;
	if (WeapSelected == 1 && NormCmcX <= 0)
		WeapSelected = 0;
	}
}

defaultproperties
{
     SlideFX=255
     AirBrakes=255
     speed=170.000000
     MaxSpeed=1500.000000
     AccelMax=200.000000
     DamageFX=True
     baseFuelRate=1.000000
     afterburnRate=1.700000
     Armor=150.000000
     MaxArmor=500.000000
     fuel=120.000000
     pilotOffset=(X=15.500000,Z=35.000000)
     minspeed=170.000000
     fullspeed=1150.000000
     thrate=2.200000
     HUDClass=Class'SLHud'
     ExhaustPuffClass=Class'ExhaustPuff'
     DamagePuffClass=Class'DamagePuff'
     detClass2=Class'StrangeWave'
     bNoContrails=True
     ContrailClass=Class'contrail'
     puffOffset=70.000000
     crushAngle=0.350000
     gunnerSound=Sound'SLV2Sounds.Rocket.gunnermount'
     crashSound=Sound'SLV2Sounds.Rocket.crash'
     warnSound=Sound'SLV2Sounds.Rocket.Warning'
     abFadeSound=Sound'XNXAfterBurnEnd'
     abLoopSound=Sound'XNXAfterBurnLoop'
     abKickSound=Sound'XNXAfterBurnStart'
     refuelSound=Sound'SLV2Sounds.Rocket.refuel'
     hullHits(0)=Sound'SLV2Sounds.Rocket.hullhit'
     hullHits(1)=Sound'SLV2Sounds.Rocket.hullhit2'
     hullHits(2)=Sound'SLV2Sounds.Rocket.hullhit3'
     hullHits(3)=Sound'SLV2Sounds.Rocket.hullhit4'
     bounces(0)=Sound'SLV2Sounds.Rocket.Bounce'
     bounces(1)=Sound'SLV2Sounds.Rocket.bounce2'
     bounces(2)=Sound'SLV2Sounds.Rocket.bounce3'
     bounces(3)=Sound'SLV2Sounds.Rocket.bounce4'
     bounces(4)=Sound'SLV2Sounds.Rocket.bounce5'
     bCanOverride=True
     touchLapse=2.000000
     normDamStr="%o got more holes in %oop than a horse trader's mule."
     normSelfDamStr="%k just got owned by his own Rocket."
     ramDamStr(0)="%o stood in the way and got splattered by %k."
	ramDamStr(1)="%o tried to cross the street to %ks Venom-X."
	ramDamStr(2)="%k painted %kpa Venom-X with %os blood."
	ramDamStr(3)="%k scattered %os guts all over the floor."
	ramDamStr(4)="%o didn't see %k coming."
	ramDamStr(5)="%o offered %oopself to %ks Venom-X."
	ramDamStr(6)="%k smashed a little bug called %o."
	ramDamStr(7)="%o thought %k was just picking %oop up."
     ramSelfDamStr="%k needs an Eye Test."
     ramSelf2DamStr="That's what %k gets for treating %kpa Rocket like a toy."
     shotDamStr="%k took the Venom-X out from %os crotch, OUCH!"
     shotSelfDamStr="%k just owned %kopself."
     hitWallDamStr(0)="%k wasn't looking where %kkh was going."
     	hitWallDamStr(1)="%k needs to learn how to NOT fly like a moron."
	hitWallDamStr(2)="%k hasn't realized that the Venom-X is NOT a Taxi."
	hitWallDamStr(3)="%k scratched the door like a kitty."
	hitWallDamStr(4)="VW just recruited %k as a Dummy for the crash tests."
	hitWallDamStr(5)="Standing ovation for %ks reckless maneuver against the wall."
	hitWallDamStr(6)="%ks teammates wish %kkh was on the opposite team."
	hitWallDamStr(7)="%k should take a break instead of breaking into walls."
	hitWallDamStr(8)="Looks like %k has been taking lessons from Spazzy."
	hitWallDamStr(9)="%k just got %kopself 'Spazzed'."
	hitWallDamStr(10)="The wall was already there %k."
	hitWallDamStr(11)="%k forgot to activate %kpa 'ghost' cheat."
	hitWallDamStr(12)="%k loves walls."
	hitWallDamStr(13)="%k got an accident with %kpa Venom-X."
	hitWallDamStr(14)="%k thought %kkh could drill through the wall."
     hitSLDamStr(0)="%k being an idiot, smacked into an unmanned Rocket."
     	hitSLDamStr(1)="%k flies like a complete retard"
     	hitSLDamStr(2)="%k acting like a moron, knocked %kopself into an unmanned Rocket."
     	hitSLDamStr(3)="%k got splattered by a rogue jet."
     	hitSLDamStr(4)="%k needs to learn how to NOT fly into another jet."
	hitSLDamStr(5)="%k keeps %kpa sunglasses even when flying a Venom-X."
	hitSLDamStr(6)="%ks Insurance is going to rise dramatically next year."
	hitSLDamStr(7)="%k is going to complain about the Venom-X lag."
	hitSLDamStr(8)="Standing ovation for %ks reckless maneuver."
     hitSLDamStr2(0)="%k and %o had a few problems NOT smacking into eachother."
	hitSLDamStr2(1)="%k and %o were flying without a License."
	hitSLDamStr2(2)="Authorities suspect %k or %o could have been drinking."
     lvlimit=600.000000
     sndPilotEj=Sound'SLV2Sounds.Rocket.piloteject'
     sndGunnerEj=Sound'SLV2Sounds.Rocket.gunnereject'
     sndDrop=Sound'SLV2Sounds.Rocket.dropalarm'
     bBotsObeyOrders=True
     sndMarchLoop=Sound'UntilTheLastBreath'
     sndTotalComm=Sound'totalcommB'
     sndWahoo=Sound'SLV2Sounds.kongl.wahoo'
     gunnerMountStr(0)="%k hitches a lift on %os Venom-X!"
     	gunnerMountStr(1)="%k kicks back and relaxes on %os Venom-X!"
     	gunnerMountStr(2)="%k has decided to take a ride on %os Venom-X!"
	gunnerMountStr(3)="%o gives %k a ride in %opa taxi!"
	gunnerMountStr(4)="%k realized it's best attacking together with %o!"
	gunnerMountStr(5)="%o picked up %k!"
     gunnerMountStr2(0)="%k leaps onto a rogue Venom-X!"
     	gunnerMountStr2(1)="%k commandeers a rogue Venom-X."
     	gunnerMountStr2(2)="%k tames a maverick Venom-X."
	gunnerMountStr2(3)="%k didn't pay the Taxi fare."
	gunnerMountStr2(4)="%k is now the king of a rogue jet."
	gunnerMountStr2(5)="%k took a free ride from a not piloted jet."
     MyDamageType=SpecialDamage
     ImpactSound=Sound'SLV2Sounds.Rocket.detonate'
     MiscSound=Sound'SLV2Sounds.Rocket.crash'
     bCanTeleport=True
     bOwnerNoSee=True
     LifeSpan=0.000000
     LODBias=1.000000
     Texture=None
     Mesh=JetXRed
     DrawScale=3.200000
     bGameRelevant=False
     SoundRadius=40
     SoundVolume=215
     CollisionRadius=25.000000
     CollisionHeight=2.000000
     bBounce=True
     bFixedRotationDir=True
     NetPriority=3.500000
     Texture=XShinyWindowRed
     AmbientSound=XNXEngine
     BurnersClass=Class'RedJetCtrlBurners';
     PrimeExhaustsClass=Class'RedPrimaryExhaust'
     SecExhaustsClass=Class'RedSecondaryExhaust';
     enable_NewWeaponrySystem=True
     NormMissilesN=4
     SeekMissilesN=2
     RearMissilesN=4
     enable_SeekNuke=True
     enable_NormNuke=True
     enable_DropNuke=True
     enable_Flash=True
     enable_NormHeatTarget=True
     enable_RearHeatTarget=True
     XSFClass=Class'XSFRed'
     NormCmRelLoc(3)=(X=-77.000000,Y=-92.000000,Z=28.000000)
     NormCmRelLoc(2)=(X=-77.000000,Y=92.000000,Z=28.000000)
     NormCmRelLoc(1)=(X=-77.000000,Y=-78.000000,Z=28.000000)
     NormCmRelLoc(0)=(X=-77.000000,Y=78.000000,Z=28.000000)
     SeekCmRelLoc(1)=(X=-36.000000,Y=-52.000000,Z=21.000000)
     SeekCmRelLoc(0)=(X=-36.000000,Y=52.000000,Z=21.000000)
     RearCmRelLoc(3)=(X=-35.000000,Y=-16.000000,Z=18.000000)
     RearCmRelLoc(2)=(X=-35.000000,Y=16.000000,Z=18.000000)
     RearCmRelLoc(1)=(X=-35.000000,Y=-7.000000,Z=15.000000)
     RearCmRelLoc(0)=(X=-35.000000,Y=7.000000,Z=15.000000)
     LightType=LT_Steady
     LightRadius=20
     LightBrightness=100
     LightSaturation=0
     LightHue=0
     bLockedMissileWarning=True
     MissileWarnRadius=3000
     MarchMaxSpeed=2000.000000
     bAutoSelectToCannons=True
     bSeeJetView=False
     bSeeWeaponsView=False
     bSeeSelectTextView=False
     bSeeLockedNukeWarn=True
}