//=====================================================================
// NemesisWINGSv2.
//      ""(§)FrÅgÊd(§)""
//               **Monarch**
//
//              555 ---===CrAzYBoNeS===--- 555
//          Boppolis_The_Dog
//
//
// Thank you Al McElrath for SLV2.
//=====================================================================
/** Strangelove weapon superclass.
*/
class SLWeapon extends TournamentWeapon abstract;
// DATA
//

var bool bFirearm;                    // Uses firing modes, etc.
var() int hitdam;                   // Hit damage for firearms.
var SLClip clip;                    // Current clip, if ammo().bClipped.

var() bool bFakeReload;               // There's no reload anim. Use down/select.
//var SLClipFix clipfix;                // Our clip fix HUD mutator.

var() Class<EjectedBrass> brassClass;
var() Class<SLWallhit> wallhitClass;

var bool bSetProjOwner;             // If true, the owner will be set on new projectiles.
var Projectile lastProj;            // Keep track of the last projectile fired.
var vector spawnProjOffset;         // Optional projectile offset, replaces fireOffset/calcDrawOffset().

enum EFireMode {
	FM_Single,
	FM_Burst,
	FM_Auto,
};

var EFireMode fireMode;               // 0=single, 1=burst, 2=auto

var() bool bAltSwitchMode;          // Alt-fire changes the fire mode.

var() int rpm;                      // Rounds per minute.
var() float burstWait;              // How long we sleep after a burst.
var() int burstRounds;              // # of rounds in a burst.
var() int burstCount;               // Burst counter.
var bool bClear;                    // Can refire while in a burst cycle?
var bool bInitFA;                   // See clientFire().

// Recoil data.
struct RecoilInfo {
	var float base;             // The base recoil increase per shot.
	var float limit;            // Max recoil in any direction.
	var float kick;             // Additional pitch factor. See recoil().
	var float returnRate;       // Rate at which recoil is reduced per sec.
	var float smoothRate;       // Rate at which recoil is smoothed out.
	var float pvoScale;         // Produces PVO offset due to recoil.
	//var float pitchScale;     // Produces pitch offset due to recoil.
	var float accScale;         // Scales the recoil to produce an accuracy figure for traceFire().
};

var() RecoilInfo recoilData;
var vector recoilv;             // Current recoil.
var vector smoothrv;            // Current, smoothed recoil.

var bool bAlt;                      // This affects reuse of functions for alt-fire.

// Akimbo config.
var() bool bAkimbo;                 // Can be used akimbo?
var SLWeapon slave;                 // The slave weapon.
var SLWeapon master;                // The master weapon (only set on slave).
var bool bSlave;                    // Is this weapon a slave?
var bool bSetup;                    // Used for setting display props.
var bool bBringingUp;               // Brings up the slave on the client.
var() localized string slaveName;   // The name of the slave weapon.
var() byte akimboSwitchPriority;    // Switch priority of akimbo pair.
var() string leftMesh;              // The other mesh.
var() float slaveWait;
var() float slaveAltWait;
var() float slaveAcc;               // Accuracy drop for akimbo weapons.

/** Animation and Sound Struct (tm). :) Useful for putting all anim
	and sound info in one place, and not having to override a bunch of
	functions.
*/
struct ASS {
	var() name aname;
	var() float arate;
	var() float tween;
	var() Sound sound;
	var() float volume;
	var() ESoundSlot slot;
	var() bool bSkipOwner;
};

var() ASS assFire;
var() ASS assAltFire;
var() ASS assSelect;
var() ASS assDown;
var() ASS assReload;
var() ASS assIdle;
var() ASS assEmpty;
var() ASS assMode;

/** Idle properties.
*/
var() float idleLapse;
var() float idleRandom;

var() Texture xhair;

/** This weapon has no "center" handedness. Either because it has no
	center model (faces removed on left/right), or we specifically don't
	want it because this weapon can be used akimbo. Default is true.
*/
var() bool bNoCenter;

var() Texture MFVariations[6];

/** The max amount the gun will slide depending on pitch.
*/
var() float paSlide;

/** These are similar to flashY/O except these values are applied at a
	sliding amount, depending on the pitch adjustment. See pitchAdjust().
*/
var() float paFlashY, paFlashO;

/** Used to mimic another weapon's switch priority. See
	setSwitchPriority(). Also used to set autoSwitchPriority in
	postBeginPlay().





*/
var() name mimicPriorityOf;

// Info that appears next to the reticule.
var float retbar;
var string retmsg;
var string retmsg2;
var string retmsg3;
var Font retFont;
var Stylus yy;

var Util u;


// REPLICATION
//

replication {
	reliable if (role == ROLE_Authority && bNetOwner && bAkimbo)
		slave, master, bSlave, bBringingUp;

	reliable if (role == ROLE_Authority && bNetOwner)
		clip;

	reliable if (role == ROLE_Authority)
		remoteReload, updateMaxAmmo;
}


// METHODS
//

/** Starts fully loaded.
*/
simulated function postBeginPlay() {
	local Class<Weapon> c;

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

	u.debug("postBeginPlay()");

	// Set switch priorities from mimic weapon.
	if (mimicPriorityOf != '') {
		c = Class<Weapon>(dynamicLoadObject("Botpack." $ mimicPriorityOf, Class'Class'));
		if (c != none) {
			autoSwitchPriority = c.default.autoSwitchPriority;

			// The default is -1, which means if we don't specify it
			// in the subclass, it gets assigned here to the auto value.
			if (bAkimbo && akimboSwitchPriority == -1)
				akimboSwitchPriority = autoSwitchPriority;
		}
	}


	if (role < ROLE_Authority)
		return;

	super.postBeginPlay();
}


function destroyed() {
	if (slave != none)
		slave.destroy();

	super.destroyed();
}


/** Wrapper to get ammoType as a SLAmmo object.
*/
simulated function SLAmmo ammo() {
	if (ammoType == none)
		giveAmmo(Pawn(owner));

	return SLAmmo(ammoType);
}


function bool useAmmo(int num) {
	local SLAmmo a;

	a = ammo();

	if (a.bClipped) {
		return (clip != none && clip.useRound());
	} else {
		return a.useAmmo(num);
	}
}


/** This is where the client actually gets the ammoType, so let's
	update the maxAmmo, if necessary.
*/
function giveAmmo(Pawn p) {
	local int max;
	local bool bUpdate;

	if (ammoName == none)
		return;

	max = Class<SLAmmo>(ammoName).default.configMaxAmmo;
	bUpdate = (ammoType == none && max > 0);

	//super.giveAmmo(p);

	ammoType = Ammo(p.findInventoryType(ammoName));

	if (ammoType == none) {
		ammoType = spawn(ammoName);
		p.addInventory(ammoType);
		ammoType.becomeItem();
		ammoType.gotoState('Idle2');
		ammo().weaponSpawned();
	}

	/*  Normally the pickup count for a new, clipped weapon is
		1. Nothing else really makes sense unless you're running an arena
		mutator which pumps up the count. The following code allows up
		to start the weapon loaded and max out the clips in that situation.
	*/

	if (ammo().bClipped) {
		clip = ammo().defaultClip();
		pickupAmmoCount--;
	}

	ammoType.addAmmo(pickupAmmoCount);

	if (bUpdate)
		updateMaxAmmo(max);
}


/** This is called from StrangeArena to give us max ammo. This is the
	only place that maxAmmo is used as a class default var. We need to
	take into account configMaxAmmo.
*/
function maxOut() {
	local int max;

	max = Class<SLAmmo>(ammoName).default.configMaxAmmo;
	if (max > 0) {
		pickupAmmoCount = max;
	} else {
		pickupAmmoCount = Class<SLAmmo>(ammoName).default.maxAmmo;
	}
}


/** Server can update max ammo on the client.
*/
simulated function updateMaxAmmo(int max) {
	if (ammoType != none)
		ammoType.maxAmmo = max;
	ammoName.default.maxAmmo = max;
}


/** Returns the total ammo, including clip rounds.
*/
simulated function int getAmmo() {
	if (ammo() != None)
		return ammo().getAmmo();
	else
		return 0;
}


simulated function int getMaxAmmo() {
	return ammo().getMaxAmmo();
}


/** Do we have any ammo left, clipped or otherwise?
*/
simulated function bool ammoLeft() {
	return (getAmmo() > 0);
}


/** Returns true if the clip is empty, but we have ammo left.
*/
simulated function bool needReload() {
	return (ammo().bClipped && clip.empty() && ammoLeft());
}


/** This is based on the enforcer botDesireability(). It supports akimbo weapons.
*/
event float botDesireability(Pawn bot) {
	local SLWeapon has;
	local float desire;

	has = SLWeapon(bot.findInventoryType(class));
	desire = maxDesireability + bot.adjustDesireFor(self);

	if (has != none) {
		if ((!bHeldItem || bTossedOut) && bWeaponStay)
			return 0;

		if (has.slave != none) {
			if ((respawnTime < 10) && (bHidden || (has.ammoType == none) || (has.getAmmo() < has.getMaxAmmo())))
				return 0;

			// WTF does this mean? We haven't equipped it yet?
			if (has.ammoType == none)
				return 0.25 * desire;

			if (has.getAmmo() > 0)
				return fmax( 0.25 * desire, has.ammoType.maxDesireability * fmin(1, 0.15 * has.getMaxAmmo() / has.getAmmo()) );
		}
	}

	if ((bot.weapon == none) || (bot.weapon.AIRating <= 0.4))
		return 2 * desire;

	return desire;
}


/** Called from the clip fix, after drawWeapons() has been called in
	ChallengeHUD. Or before, if bSet == true.
simulated function ammoRenderFix(bool bSet) {
	if (bSet) {
		ammo().setRenderMax(clip, bSlave);
	} else {
		ammo().unsetRenderMax(clip, bSlave);
	}
}
*/


/** Sometimes the owner isn't set (initial network transfers). This is
	called before drawWeapons() in ChallengeHUD.
*/
simulated function postRender(Canvas c) {
	local ChallengeHUD hud;

	/*
	if (clipfix != none) {
		clipfix.register();
		clipfix.runFix(true);
	}
	*/

	if (owner != none) {
		hud = ChallengeHUD(PlayerPawn(owner).myHUD);

		if (hud != none) {
			c.bNoSmooth = false;

	//      if (!bSlave)
	//          drawXhair(hud, c);

			setRetMsgs();
			drawRetMsgs(c, 15 * hud.crosshairColor);

	//      if (slave != none)
	//          slave.postRender(c);
		}
	}
}


simulated function drawRetMsgs(Canvas c, Color color) {
	local int x, y, dist;
	local float w, h, xl, yl;

	// Nothing to display.
	if (retmsg == " ")
		return;

	if (yy == none)
		yy = spawn(Class'Stylus', self);
	yy.setCanvas(c);

	// Distance from ret.
	dist = 48;
	if (bSlave)
		dist = 56;

	if (retFont == none)
		retFont = class'Fontlib'.static.getFont(FS_Slick);
	if (retFont == none)
		return;

	c.font = retFont;
	c.style = ERenderStyle.STY_Translucent;
	c.drawColor = color;

	c.textSize(retmsg, xl, yl);

	w = xl;
	h = yl;
	c.textSize(retmsg2, xl, yl);
	w = fmax(w, xl);
	w = fmax(w, 50);

	if (hand() < 0) {
		x = c.clipx / 2.0 + dist;
	} else {
		x = c.clipx / 2.0 - (dist + w);
	}
	y = c.clipy / 2.0 - 20;

	if (retbar >= 0.0) {
		//c.drawColor = color * 0.7;
		yy.drawFrame(x, y, w + 2, yl + 2, 1, false);
		c.setPos(x + 1, y + 1);
		c.drawColor = color * 0.8;
		yy.pix(w * retbar, yl);
	}

	c.drawColor = color;

	c.setPos(x + 2, y + 2);
	c.drawText(retmsg);
	c.setPos(x + 2, y + yl + 3);
	c.drawText(retmsg2);

	if (retmsg3 != " ") {
		c.textSize(retmsg3, xl, yl);
		c.setPos(x + w - xl + 1, y + 2);
		c.drawText(retmsg3);
	}
}


simulated function setRetMsgs() {
	local SLAmmo a;

	retmsg = " ";
	retmsg2 = " ";
	retmsg3 = " ";

	a = ammo();

	// Client doesn't have ammo yet.
	if (a == none || (a.bClipped && clip == none))
		return;

	if (a.bClipped) {
		retbar = (float(clip.getRounds()) / clip.getMaxRounds());
		retmsg = "rnds " $ clip.getRounds();

		// If we're a a slave, only report the rounds.
		if (!bSlave)
			retmsg2 = "clips " $ a.getClips();
	} else {
		retbar = (float(getAmmo()) / getMaxAmmo());
		retmsg = "rnds " $ getAmmo();
	}
/*
	if (bFirearm && !bSlave) {
		switch (fireMode) {
		case FM_Single:
			retmsg3 = "semi";
			break;
		case FM_Burst:
			retmsg3 = "burst";
			break;
		case FM_Auto:
			retmsg3 = "auto";
			break;
		}
	}
*/
	if (isInState('Reloading')) {
		retmsg = "reloading";
		// Otherwise, it'll overlap.
		retmsg3 = " ";
	}
}


simulated function drawXhair(ChallengeHUD hud, Canvas c) {
	local float scale, w, pickd;

	if (xhair == none)
		return;

	if (c.clipx < 512)
		scale = 0.5;
	else
		scale = fmax(1, int(0.1 + c.clipx / 640.0));
	pickd = level.timeSeconds - hud.pickupTime;
	if (pickd < 0.4) {
		if (pickd < 0.2)
			scale *= (1 + 5 * pickd);
		else
			scale *= (3 - 5 * pickd);
	}

	scale += fmin(1.0, vsize(recoilv) / 1000.0);

	w = 64.0 * scale;

	if (PlayerPawn(owner).handedness == -1)

		c.setPos(0.503 * (c.clipx - w), 0.504 * (c.clipy - w));
	else if (PlayerPawn(owner).handedness == 1)
		c.setPos(0.497 * (c.clipx - w), 0.496 * (c.clipy - w));
	else
		c.setPos(0.5 * (c.clipx - w), 0.5 * (c.clipy - w));
	c.style = ERenderStyle.STY_Translucent;
	c.drawColor = 15 * hud.crosshairColor;

	c.drawTile(xhair, w, w, 0, 0, 64, 64);
}


function bool weaponSet(Pawn p) {
	u.debug("weaponSet(" $ u.sname(p) $ ")");

	if (bSlave)
		return false;
	else
		super.weaponSet(p);
}


/** This is called when we want to know which weapon we
	prefer. Usually returns the autoSwitchPriority. Based on Weapon.uc
	and enforcer.uc.
*/
function float switchPriority() {
	local int temp;

	// Never switch to the slave.
	if (bSlave)
		return -10;

	// Bots have their own scheme.
	if (!owner.isA('PlayerPawn'))
		return rateSelf(temp);

	if (ammoLeft()) {
		if (slave != none)
			return akimboSwitchPriority;
	} else {
		// Keeps us from switching through weapons without ammo.
		if (Pawn(owner).weapon == self)
			return -0.5;
		else
			return -1;
	}

	return autoSwitchPriority;
}


/** This is called when a weapon is spawned (in spawnCopy()). Most
	weapons look for a priority and set it, and if there's none, they
	insert one. We just want to mimic a UT weapon priority and leave it
	at that, for now.
*/
function setSwitchPriority(Pawn p) {
	local int i;

	if (PlayerPawn(p) != none) {
		for (i = 0; i < ArrayCount(PlayerPawn(p).weaponPriority); i++) {
			// Normally this is class.name.
			if (PlayerPawn(p).weaponPriority[i] == mimicPriorityOf) {
				autoSwitchPriority = i;
				return;
			}
		}

		// If, for whatever reason, they don't have our mimicked
		// (Botpack) class, just stick us in there.
		super.setSwitchPriority(p);
	}
}


function setDisplayProperties(ERenderStyle style, texture tex, bool bLighting, bool bEnviroMap) {
	if (!bSetup) {
		bSetup = true;
		if (slave != none)
			slave.setDisplayProperties(style, tex, bLighting, bEnviromap);
		bSetup = false;
	}
	super.setDisplayProperties(style, tex, bLighting, bEnviromap);
}


function setDefaultDisplayProperties() {
	if (!bSetup) {
		bSetup = true;
		if (slave != none)
			slave.setDefaultDisplayProperties();
		bSetup = false;
	}
	super.setDefaultDisplayProperties();
}


/** Hmm, the "this will annoy people" part really messes up the
	bots. They try to pick up weapons they don't even need. Need to
	address that before messing with it here.
*/
function bool handlePickupQuery(Inventory i) {
	local Pawn p;
	local int oldAmmo;
	local int rounds;

	u.debug("handlePickupQuery()");

	if (i.class == class) {
		// NEVER return false past this point. You'll end up with doubles.

		p = Pawn(owner);

		if (bAkimbo && slave == none) {
			// Spawn the slave weapon.
			slave = spawn(class, p);
			itemName = slaveName;
			// FIX. Generalize.
			AIRating = 0.4;
			slave.setupSlave(self, Pawn(owner).weapon == self);
		} else {

			// Can't cheat with weapon stay...
			if (Weapon(i).bWeaponStay && (!Weapon(i).bHeldItem || Weapon(i).bTossedOut))
				return true;

			/** With clipped weapons that are dropped, you can take the clip out.
			*/
			if (ammo().bClipped && SLWeapon(i).clip != none) {
				ammo().addClip(SLWeapon(i).clip);
			} else {
				// WTF is all this?????
				if (ammoType != none) {
					oldAmmo = getAmmo();
					if (ammoType.addAmmo(Weapon(i).pickupAmmoCount) && (oldAmmo == 0) && (p.weapon.class != i.class) && !p.bNeverSwitchOnPickup) {
						weaponSet(p);
					}
				}
			}
		}

		p.receiveLocalizedMessage(class'PickupMessagePlus', 0, none, none, self.class);
		i.playSound(i.pickupSound);
		if (level.game.LocalLog != none)
			level.game.LocalLog.logPickup(i, Pawn(owner));
		if (level.game.WorldLog != none)
			level.game.WorldLog.logPickup(i, Pawn(owner));
		i.setRespawn();

		return true;

	} // Same class.

	// Continue down the chain.
	if (inventory == none)
		return false;

	return inventory.handlePickupQuery(i);
}


/** bBringUp is true if we picked up this slave with another one
	already equipped.
*/
function setupSlave(SLWeapon p, bool bBringup) {
	becomeItem();

	master = p;
	bSlave = true;

//  if (bFirearm)
//      fireMode = p.fireMode;

	setDisplayProperties(p.style, p.texture, p.bUnlit, p.bMeshEnviromap);
	giveAmmo(Pawn(owner));

	if (bBringUp)
		bringUp();
	else
		gotoState('Idle2');
}


simulated function setHand(float hand) {
	u.debug("setHand(" $ int(hand) $ "): slave: " $ u.sname(slave));

	// No center? Use right.
	if (bNoCenter && hand == 0)
		hand = -1;

	if (hand == 2) {
		// Hidden!
		bHideWeapon = true;
		playerViewOffset.y = 0;
		fireOffset.Y = 0;

	} else {
		// Not hidden!
		bHideWeapon = false;

		if (slave != none)
			slave.setHand(-hand);

	/*  // Set the mesh.
		if (leftMesh != "" && hand == 1)
			setSkelMesh(SkeletalMesh(dynamicLoadObject(leftMesh, Class'SkeletalMesh')));
		else
			setSkelMesh(SkeletalMesh(default.playerViewMesh));

	*/  // We don't care about the PVO if it's not being used.
		//if (owner.isA('PlayerPawn') && Viewport(PlayerPawn(owner).player) != none)
			setPVO(hand, default.playerViewOffset);

		fireOffset.y = default.fireOffset.y * hand;
	}
}



/** Sets the playerViewOffset based on the hand.
*/
simulated function setPVO(float hand, vector def) {
	local vector pvo;

	if (hand == 0) {
		pvo.x = def.x * 0.88;
		pvo.y = -0.2 * def.y;
		pvo.z = def.z * 1.12;
	} else {
		pvo.x = def.x;
		pvo.y = def.y * hand;
		pvo.z = def.z;
	}

	pvo *= 100;

	// Set it.
	u.debug("setPVO(" $ int(hand) $ "): new pvo: " $ u.sv(pvo));
	playerViewOffset = pvo;
}


state ClientActive {

	simulated function animEnd() {
		u.debug("ClientActive:animEnd()");

		bBringingUp = false;

		if (!bSlave) {
			super.animEnd();

			if (slave != none && !isInState('ClientActive')) {
				// Heh. FIX this.
				if ((getStateName() == 'None') || (getStateName() == 'Sidearm'))
					slave.gotoState('');
				else
					slave.gotoState(getStateName());
			}
		}




	}


	simulated function beginState() {
		u.debug("ClientActive:beginState()");

		//clipHUDFix();

		setHand(hand());

		super.beginState();

		bBringingUp = false;
		if (slave != none)
			slave.gotoState('ClientActive');
	}
}


state ClientDown {

	simulated function animEnd() {
		if (!bSlave)
			super.animEnd();
	}


	simulated function EndState() {
		if (slave != none)
			slave.gotoState('');
	}
}


function bringUp() {
	u.debug("bringUp()", DL_Normal);

	//clipHUDFix();

	if (owner.isA('PlayerPawn')) {
		setHand(hand());
		PlayerPawn(owner).endZoom();
	}

	if (slave != none)
		slave.bringUp();

	bBringingUp = true;

	bWeaponUp = false;
	playSelect();
	gotoState('Active');

	//super.bringUp();
}


/** Spawns a clip fix HUD. If another weapon already has one, use it.
simulated function clipHUDFix() {
	local PlayerPawn pp;
	local Inventory i;

	if (u.legacy()) {
		if (clipfix != none) {
			clipfix.register();

		} else {
			pp = PlayerPawn(owner);
			if (pp != none && pp.myHUD != none && pp.myHUD.isA('ChallengeHUD')) {
				// Look for other SLWeapons to use their clip fix HUD.
				for (i = pp.inventory; i != none; i = i.inventory) {
					if (i.isA('SLWeapon') && SLWeapon(i).clipfix != none) {
						clipfix = SLWeapon(i).clipfix;
						return;
					}
				}

				// Need to spawn one.
				clipfix = spawn(Class'SLClipFix', pp);
			}
		}
	}
}
*/


/** This is called after the master has fired. If bWait is true,
	there is a slight pause before it fires the slave.
*/
simulated function slaveFire(bool bUseAlt, bool bWait) {
	u.debug("slaveFire(" $ bAlt $ ", " $ bWait $ ")");

	// Yes, this gets run twice for bWait == true. Tough.
	bAlt = bUseAlt;

	if (bWait) {
		gotoState('SlaveFireWait');
	} else {
		// Yes, this is silly. We want to pickup subclass behavior in the alt methods.
		if (role < ROLE_Authority) {
			if (bAlt)
				clientAltFire(0);
			else
				clientFire(0);
		} else {
			if (bAlt)








				altFire(0);

			else
				fire(0);
		}
	}
}


/** This state causes a slight random pause before the slave fires
	(after the master). See slaveFire().
*/
simulated state SlaveFireWait {

begin:
	if (bAlt) {
		sleep(slaveAltWait * frand());
	} else {
		sleep(slaveWait * frand());
	}

	slaveFire(bAlt, false);
}


/** Replicated reload function for remote clients.
*/
simulated function remoteReload() {
	reload();
}


/** Tests for ammo, starts an animation, and switches to the reload
	state.
*/
simulated function reload() {
	local SLAmmo a;

	a = ammo();

	if (a.bClipped) {
		u.debug("reload(): rounds: " $ clip.getRounds() $ " clips: " $ a.getClips(), DL_Normal);

		// If the other weapon is reloading and and we don't have more than one spare, return.
		if (mate() != none && mate().isInState('Reloading') && (a.getClips() == 1)) {
			u.debug("reload(): mate reloading");

		} else if (a.getClips() > 0) {
			// This ejects a spent clip.
			if (ammoType != none && SLAmmo(ammoType).spentClip != none)
				spawnBrass(SLAmmo(ammoType).spentClip, 0.5);

			// Again, must initiate animation before changing states. See
			// clientFire() comments.
//          playReload();

			gotoState('Reloading');

			// Handle remotes.
			if (!u.hasViewPort(owner))
				remoteReload();
		}
	}
}


/** The animation has been initiated in reload(). This state waits for
	it to finish. the client/Alt/Fire() functions are for passing fire
	commands to the slave while the primary is reloading.
*/
simulated state Reloading {
	ignores reload;

	function fire(float v) {
		if (slave != none)
			slave.fire(v);
	}


	function altFire(float v) {
		if (slave != none)
			slave.altFire(v);
	}


	simulated function bool clientFire(float v) {
		if (slave != none)
			slave.clientFire(v);
	}


	simulated function bool clientAltFire(float v) {
		if (slave != none)
			slave.clientAltFire(v);
	}


	/* Debugging.
	simulated function beginState() {
		u.debug("Reloading:beginState()");

	}

	simulated function endState() {
		u.debug("Reloading:endState()");
	}
	*/


begin:
	u.debug("Reloading:begin");

	// Finish reload anim from reload().
	finishAnim();

//  if (bFakeReload) {
	//  playAss(assSelect);
	//  finishAnim();
	//}

	if (role == ROLE_Authority) {
		clip = ammo().reload();
		finish();
	} else {
		gotoState('Idle');
	}
}


/** This initiates the anim in reload(). Reloading:begin finishes it.

simulated function playReload() {
	if (bFakeReload) {
		playAss(assDown);
	} else {
		playAss(assReload);
	}
}

*/
/** Play ASS struct. bReplicate means playSound will be called from a
	non-simulated function, which means it will be replicated to the
	relevant clients. bSkipOwner means the sound is played in a simulated
	function on the client as well as the server, so when we're
	replicating it, don't send it to the originating client.

	Returns true if the animation played.
*/
simulated function bool playAss(ASS a, optional bool bReplicate, optional bool bSkipOwner) {
	local float v;

	u.debug("playAss(): aname: " $ a.aname $ " arate: " $ u.sf(a.arate));

	if (a.sound != none && owner != none) {
		v = a.volume * Pawn(owner).soundDampening;

		if (bReplicate)
			replicateSound(a.sound, a.slot, v);
		else if (bSkipOwner || a.bSkipOwner)
			playOwnedSound(a.sound, a.slot, v);
		else
			playSound(a.sound, a.slot, v);
	}

	if (a.aname != '' && a.arate > 0) {
		if (hasAnim(a.aname)) {
			playAnim(a.aname, a.arate, a.tween);
			return true;
		} else {
			u.debug("playAss(): no anim: " $ a.aname);
		}
	}

	return false;
}


/** Not simulated, so it gets replicated.
*/
function replicateSound(Sound s, ESoundSlot slot, float vol) {
	playSound(s, slot, vol);
}


/** Primary fire.

function fire(float v) {
	local bool bWait;

	u.debug("fire(" $ u.chopf(v) $ "): bAlt: " $ bAlt, DL_Normal);

	if (ammoType == none)
		giveAmmo(Pawn(owner));

	if (ammoLeft()) {
		if (needReload()) {
			u.debug("fire(): needs reload");



			// Reload may fail silently in the the master/slave is
			// reloading. No empty sound. FIX?
			reload();

		} else {
			bWait = true;

			if (bFirearm) {
				gotoState('FAFire');
			} else {
				fire2(v);
			}
		}
	} else {
		u.debug("fire(): no ammo");

		// clientFire() isn't called, so...
		if (level.netmode == NM_Standalone || (level.netmode == NM_ListenServer && u.hasViewPort(owner)))
			playAss(assEmpty);
	}

	if (slave != none)
		slave.slaveFire(bAlt, bWait);
}

*/
/** Primary fire for non-firearms.
*/
function fire2(float v) {
	u.debug("fire2(" $ u.chopf(v) $ ")");

	if (ammoLeft()) {
		if (bAlt)
			gotoState('AltFiring');
		else
			gotoState('NormalFire');

		bCanClientFire = true;
		bPointing = true;

		if (bRapidFire || (firingSpeed > 0))
			Pawn(owner).playRecoil(firingSpeed);

		if (bInstantHit) {
			traceFire(0.0);
			useAmmo(1);
		} else {
			if (bAlt)
				projectileFire(altProjectileClass, altProjectileSpeed, bWarnTarget);
			else
				projectileFire(projectileClass, projectileSpeed, bWarnTarget);
		}

		// Run this after projectileFire() in case of spawn problems.
		if (bInstantHit || lastProj != none) {
			if (bAlt)
				playAltFiring();
			else
				playFiring();

			// Don't use ammo if the spawn failed!
			useAmmo(1);
		} else {
			finish();
		}
	}
}

/** Cycles through the fire modes.

function altFire(float v) {
	u.debug("altFire(" $ u.chopf(v) $ ")");

	if (bAltSwitchMode) {
		switchMode();
		return;
	}

	bAlt = true;
	fire(v);
}



function switchMode() {
	playAss(assMode, true);

	switch (fireMode) {
	case FM_Single:
		fireMode = FM_Burst;
		break;
	case FM_Burst:
		fireMode = FM_Auto;
		break;
	case FM_Auto:
		fireMode = FM_Single;
		break;
	}

	if (slave != none)
		slave.fireMode = fireMode;
}

*/
state Idle {

	simulated function playIdleAnim() {
		if (!isAnimating() && frand() < idleRandom)
			playAss(assIdle);
	}


	function timer() {
		playIdleAnim();
	}







	simulated function beginState() {
		u.debug("Idle.beginState()");
		setTimer(idleLapse, true);
	}


	simulated function endState() {
		u.debug("Idle.endState()");
		setTimer(0.0, false);
	}


begin:
	bPointing=false;

	// Switch to another weapon when empty.
	if (!ammoLeft())
		Pawn(owner).switchToBestWeapon();

	/* Don't refire.
	if (Pawn(owner).bFire != 0)
		fire(0.0);
	if (Pawn(owner).bAltFire != 0)
		altFire(0.0);
	*/

	disable('animEnd');
	//playIdleAnim();
}


/** FIX?
*/
state Active {

	function beginState() {
		u.debug("Active:beginState()");
		//super.beginState();
		bChangeWeapon = false;
	}


	function endState() {
		u.debug("Active:endState()");
		super.endState();
		bBringingUp = false;
	}


	function bool putDown() {
		u.debug("Active:putDown()");
		return super.putDown();

		/*
		if (bWeaponUp || (animFrame < 0.75))
			gotoState('DownWeapon');
		else
			bChangeWeapon = true;

		return true;
		*/
	}


begin:
	finishAnim();
	if (bChangeWeapon)
		gotoState('DownWeapon');
	bWeaponUp = true;
	bCanClientFire = true;

	if (!bSlave && (level.netmode != NM_Standalone) && (owner != none) && owner.isA('TournamentPlayer') && (PlayerPawn(owner).player != none) && !PlayerPawn(owner).player.isA('ViewPort')) {
		if (Pawn(owner).bFire != 0)
			TournamentPlayer(owner).sendFire(self);
		else if ( Pawn(owner).bAltFire != 0 )
			TournamentPlayer(owner).sendAltFire(self);
		else if ( !bChangeWeapon )
			TournamentPlayer(owner).updateRealWeapon(self);
	}

	finish();
}


/* WTF was I doing with this?
function timer() {
	u.debug("Global.timer()");
}
*/


/** This may not work for all subclasses, but it does for the
	sidearm. FIX?

simulated function playFAFiring(optional bool bSkipNext) {
	if (bInitFA) {
		bInitFA = false;
	} else {
		if (fireMode == FM_Single) {
			playFiring();
		} else {
			playAltFiring();
		}
	}

	if (bSkipNext)
		bInitFA = true;
}
*/

/** Firing mode for firearms. This is a dual client/server state.


simulated state FAFire {
	// Can't switch modes mid-burst!
	ignores altFire, clientAltFire; //, animEnd;

	function fire(float v) {
		u.debug("FAFire:fire(): clear: " $ bClear);

		if (bClear) {
			// Must clear the state. Not sure why.
			gotoState('');
			global.fire(v);
		}
	}


	simulated function bool clientFire(float v) {
		u.debug("FAFire:clientFire(): clear: " $ bClear);

		if (bClear) {
			// Must clear the state.
			gotoState('');
			return global.clientFire(v);
		} else {
			return false;
		}
	}


	simulated function beginState() {
		u.debug("FAFire:beginState()");
		bClear = false;
		burstCount = 0;
	}


	/* Debugging.
	simulated function endState() {
		u.debug("FAFire:endState()");
	}
	*/


begin:
	u.debug("FAFire.begin");

fireLoop:
	while (((Pawn(owner).bFire != 0 || Pawn(owner).bAltFire != 0) //&& fireMode == FM_Auto) || (fireMode == FM_Burst && burstCount < burstRounds) || burstCount == 0) {

		// Debugging.
		u.debug("FAFire:fireLoop: fire loop: burstCount: " $ burstCount $ " bFire/Alt: " $ Pawn(owner).bFire $ "/" $ Pawn(owner).bAltFire);

		if (needReload() || !ammoLeft())
			break;

		/* Recoil animation. Note that the recoil animations keep
		   going after the fire loop is done if we hold down the fire
		   button. FIX, eventually. Also the recoil movement causes
		   the recoil anim to temporarily stop. FIX, eventually.
		*/
		bRapidFire = (fireMode > FM_Single);
		Pawn(owner).playRecoil(firingSpeed);

		playFAFiring();

		if (role == ROLE_Authority) {
			if (level.netmode != NM_DedicatedServer)
				spawnMuzzleFlash();

			if (level.netmode != NM_Standalone)
				// For clients.
				flashCount++;

			traceFire(vsize(recoilv) * recoilData.accScale);

			// We already checked for ammo above.
			useAmmo(1);
		}

		// Recoil should be done *after* traceFire(), otherwise the
		// first shot will always be off.
		recoil();
		spawnBrass(brassClass);




		sleep(60 / rpm);
		burstCount++;
	}













	// Fin.
	//sleep(burstWait);
	//u.debug("FAFire:fireLoop: burst wait over");
	bClear = true;
	finishAnim();

	if (role == ROLE_Authority)
		finish();
	else
		gotoState('Idle');
}

*/
/** Rather than use the undocumented 3rd person flash from Inventory,
	we'll just use a simple sprite. I think it looks better, anyway.
*/
simulated function spawnMuzzleFlash() {
	local vector x, y, z, fo;

	if (owner != none) {
		// This seems to look adequate.
		fo = fireOffset * 2.0;

		getAxes(owner.rotation, x, y, z);
		spawn(Class'SLMuzzleFlash', owner,, owner.location + fo.x * x + fo.y * y * -hand() + fo.z * z);

		// Hmm, this might not be appropriate for reloading, etc. There is
		// no way to tell currently if the weapon is firing or not.
		if (slave != none) {
			slave.spawnMuzzleFlash();
		}
	}
}


/** Recoil alters the view rotation of the player. The delta is kept
	track of in recoilv.
*/
simulated function recoil() {
	local vector v;

	v = (vrand() - vrand());
	v.z += frand() * recoilData.kick;

	recoilv += v * recoilData.base;

	recoilv.x = fclamp(recoilv.x, -recoilData.limit, recoilData.limit);
	recoilv.y = fclamp(recoilv.y, -recoilData.limit, recoilData.limit);
	recoilv.z = fclamp(recoilv.z, -recoilData.limit, recoilData.limit);

	u.debug("recoil: " $ u.sv(recoilv));
}


/** Recoil is slowly brought under control at recoilRate.
*/
simulated function tick(float delta) {
	local Pawn p;
	local float x, y, z;
	local int dir;

	/*
	if (PlayerPawn(owner) != none) //&& level.netmode == NM_Client)
		u.debug("tick(): state: " $ getStateName() $ " seq: " $ animSequence $ " weap: " $ u.sname(PlayerPawn(owner).weapon) $ " bBringingUp: " $ bBringingUp $ " slave: " $ u.sname(slave) $ " weapup: " $ TournamentPlayer(owner).weaponUpdate);
	*/

	// Normally these are used for the flash mesh, but we're using sprites.
	if (role < ROLE_Authority && flashCount > oldFlashCount) {
		spawnMuzzleFlash();
		oldFlashCount++;
	}

	p = PlayerPawn(owner);
	if (p != none) {
		if (vsize(recoilv) > 1.0) {
			recoilv = normal(recoilv) * fmax(vsize(recoilv) - (recoilData.returnRate * delta), 0);
		}
	}
}


/** If you're wielding two weapons, your accuracy drops. Note the
	recoil is also doubled with slaves.
*/
function traceFire(float acc) {
	if (slave != none || bSlave) {
		acc *= slaveAcc;
	}
	super.traceFire(acc);
}


/** Find out where the bullet went and deal the damage.
*/
function processTraceHit(Actor who, vector hitloc, vector hitn, vector x, vector y, vector z) {
	if (who == level) {
		//if (bSlave || slave != none) Light wall hit? Nah.
		spawn(wallhitClass, who,, hitloc + hitn, rotator(hitn));
	} else if ((who != self) && (who != owner) && (who != none)) {
		/* WTF is this? FIX.
		if (frand() < 0.2)
			x *= 5;
		*/

		who.takeDamage(hitdam, Pawn(owner), hitloc, 3000.0 * x, myDamageType);

		if (!who.bIsPawn && !who.IsA('Carcass'))
			spawn(wallhitClass.default.puffClass, who,, hitloc + hitn, rotator(hitn));
		else
			who.playSound(Sound'ChunkHit',, 4.0,, 100);
	}
}


/** Server-spawned.
*/
function spawnBrass(Class<EjectedBrass> c, optional float ejectv) {
	local vector x, y, z;
	local EjectedBrass s;

	// Default is 1.0.
	if (ejectv == 0)
		ejectv = 1.0;

	if (level.netmode != NM_DedicatedServer) {
		getAxes(owner.rotation, x, y, z);
		s = spawn(c,,, owner.location + calcDrawOffset() + (0 * x) + (-6 * z)); // + (fireOffset.y * y * -hand()));
		if (s != none)
			s.eject(brassv(x, y, z) * ejectv);
	}
}


/** Override this to set the brass eject velocity.
*/
simulated function vector brassv(vector x, vector y, vector z) {
	return ((frand() * 0.3 - 0.15) * x + (frand() * 0.2 + 1.0) * y * -hand() + (frand() * 0.3 + 0.3) * z) * 120;
}


/** Finish a firing sequence.
*/
function finish() {
	local Pawn po;
	local bool bForce, bForceAlt;

	u.debug("finish()");

	bForce = bForceFire;
	bForceAlt = bForceAltFire;
	bForceFire = false;

	bForceAltFire = false;


	// Reset this.
	bAlt = false;

	if (bChangeWeapon) {
		gotoState('DownWeapon');
		return;
	}

	po = Pawn(owner);
	if (po == none)
		return;

	if (PlayerPawn(owner) == none) {
		// Pawns.
		if (!ammoLeft()) {
			po.stopFiring();
			gotoState('Idle');

			po.switchToBestWeapon();
			if (bChangeWeapon)
				gotoState('DownWeapon');

		} else if ((po.bFire != 0) && (frand() < refireRate)) {
			global.Fire(0);
		} else if ((po.bAltFire != 0) && (frand() < altrefireRate)) {
			global.AltFire(0);
		} else {
			po.stopFiring();
			gotoState('Idle');
		}

	} else {
		// Players.

		// Some of our animations don't zero. FIX.
		tweenToStill();
		gotoState('Idle');

		/* Can't hold down trigger. Make this an option? FIX.
		if (!ammoLeft() || (po.weapon != self)) {
			gotoState('Idle');
		} else if (po.bFire != 0 || bForce) {
			//global.fire(0);
		} else if (po.bAltFire != 0 || bForceAlt) {
			//global.altFire(0);
		} else {
			gotoState('Idle');
		}
		*/
	}
}


/** Throw the slave first, then us.
*/
function dropFrom(vector startLoc) {
	u.debug("dropFrom()");

	if (slave == none) {
		// We don't transfer clips with dropped weapons.
		if (ammo().bClipped) {
			// This keeps the super call from setting ammo.
			ammoType = none;

			// Keep the clip. Unset pickup ammo.
			pickupAmmoCount = 0;
		}

		// Unset the master.
		master = none;

		super.dropFrom(startLoc);
	} else {
		slave.dropFrom(startLoc);
	}
}


simulated function playFiring() {
	u.debug("playFiring()");

	viewFX();
	playAss(assFire);
}


simulated function playAltFiring() {
	u.debug("playAltFiring()");

	viewFX();
	playAss(assAltFire);
}


simulated function viewFX() {
	if ((PlayerPawn(owner) != none)  && ((level.netmode == NM_Standalone) || PlayerPawn(owner).player.isA('ViewPort'))) {
		if (instFlash != 0.0)
			PlayerPawn(owner).clientInstantFlash(instflash, instfog);
		PlayerPawn(owner).shakeView(shaketime, shakemag, shakevert);
	}
	if (affector != none)
		affector.fireEffect();

	if (bDrawMuzzleFlash)
		bMuzzleFlash++;
}





/** This handles fake firing on the client.

	OK, here's the deal. The player (TournamentPlayer), in
	replicateMove(), will call gotoState('') and then tweenToStill() on us
	if we're not currently animating, almost every tick. What that means
	is that you *must* start an animation here before going to another
	state. I used to just go to FAFire here, but due to this issue, I had
	to start playing the anim here. playFAFiring(true) skips the next
	anim so it doesn't play twice.
*/
simulated function bool clientFire(float v) {
	local bool bFired;

	u.debug("clientFire(" $ u.chopf(v) $ "): alt: " $ bAlt, DL_Normal);

	if (bCanClientFire) {
		if (!ammoLeft()) {
			playAss(assEmpty);

		} else if (needReload()) {
			// Server will send reload.
			//reload();
/*
		} else {
			if (bFirearm) {
				u.debug("clientFire(): going to FAFire");
				playFAFiring(true);
				gotoState('FAFire');
*/
			} else {
				// Do we need a role check here? FIX.
				if (bAlt) {
					playAltFiring();
					gotoState('ClientAltFiring');
				} else {
					playFiring();
					gotoState('ClientFiring');
				}
			//}

			bFired = true;
		}

		if (slave != none)
			// Did we fire? Then pause before slave fire.
			slave.slaveFire(bAlt, bFired);

	}

	return bFired;
}


simulated function bool clientAltFire(float value) {
	// Server will send new mode.
	if (bAltSwitchMode)
		return false;

	bAlt = true;
	return clientFire(value);
}


/** This is just like projectileFire() from Engine.Weapon, except the
	owner is set in the call to spawn(). Used for the Konglauncher.
*/
function Projectile projectileFire(Class<Projectile> projClass, float speed, bool warn) {
	local vector start, x, y, z;
	local Pawn po;

	u.debug("projectileFire(" $ projClass $ ")");

	// Clear it.
	lastProj = none;

	po = Pawn(owner);
	owner.makeNoise(po.soundDampening);
	getAxes(po.viewRotation, x, y, z);



	if (spawnProjOffset != vect(0, 0, 0)) {
		start = owner.location + spawnProjOffset;
	} else {
		start = owner.location + calcDrawOffset() + fireoffset.x * x + fireoffset.y * y + fireoffset.z * z;
	}

	adjustedAim = po.adjustAim(speed, start, aimError, true, warn);

	if (!bSetProjOwner)
		po = none;

	// Will setting the owner cause problems for other weapons?
	lastProj = spawn(projClass, po,, start, adjustedAim);

	if (lastProj == none)
		u.err("projectileFire(): Spawn failed!");

	return lastProj;
}


/** For akimbo weapons. The server says when to bring up the slave (us). Er...
*/
simulated function animEnd() {
	if (level.netmode == NM_Client && bBringingUp && mesh != pickupViewMesh) {
		u.debug("animEnd(): bringing up");
		bBringingUp = false;
		playSelect();
	} else {
		super.animEnd();
	}
}


/** FIX. We can clean up these states if we decide to definitely not
	go with refiring.
*/
state ClientFiring {

	simulated function animEnd() {
		if (Pawn(owner) == none || !ammoLeft()) {
			playIdleAnim();
			gotoState('');
		} else if (!bCanClientFire) {
			gotoState('');

		/* Don't refire.
		else if (Pawn(owner).bFire != 0)
			global.ClientFire(0);
		else if (Pawn(owner).bAltFire != 0)
			global.ClientAltFire(0);
		*/

		} else {
			playIdleAnim();
			gotoState('');
		}
	}
}


state ClientAltFiring {

	simulated function animEnd() {
		if (Pawn(owner) == none || !ammoLeft()) {
			playIdleAnim();
			gotoState('');
		} else if (!bCanClientFire) {
			gotoState('');

		/* Don't refire.
		else if (Pawn(owner).bFire != 0)
			global.ClientFire(0);
		else if (Pawn(owner).bAltFire != 0)
			global.ClientAltFire(0);
		*/

		} else {
			playIdleAnim();
			gotoState('');
		}
	}
}


simulated function playSelect() {
	u.debug("playSelect()");

	bForceFire = false;
	bForceAltFire = false;
	bCanClientFire = false;

	if (!isAnimating() || (animSequence != assSelect.aname))
		playAss(assSelect);
}


simulated function tweenDown() {

	u.debug("tweenDown()");

	if (isAnimating() && (animSequence != '') && (getAnimGroup(animSequence) == assSelect.aname))
		tweenAnim(animSequence, animFrame * 0.4);
	else
		playAss(assDown);
}


/* We'll replace this with a new gametype.
state Sleeping {
begin:
	sleep(respawnTime);
	playSound(respawnSound);
	spawn(class'RespawnEffect', self,, location);
	sleep(0.3);
	gotoState('Pickup');
}
*/


state DownWeapon {
	ignores fire, altFire, animEnd;

	function beginState() {
		super.beginState();
		if (slave != none)
			slave.gotoState('DownWeapon');
	}
}


/** This handles rendering the slave. What happens if we are viewing
	through a bot with akimbo weapons? ... FIX.
*/
simulated function renderOverlays(Canvas c) {
	local vector pvo;
	local PlayerPawn po;
	local float oldhand;

	// Let save us some effort here.
	if (bHideWeapon || owner == none)
		return;

	po = PlayerPawn(owner);

	// Store it for later.
	pvo = playerViewOffset;

	if (po != none) {
		pitchAdjust(po.rotation.pitch);
		playerViewOffset += (recoilv * recoilData.pvoScale);
	}

	// Pick a random flash.
	if (bDrawMuzzleFlash && arrayCount(MFVariations) > 0) {
		MFTexture = MFVariations[rand(arrayCount(MFVariations))];
	}

	if (po != none) {
		// This is a hack to get it to render in the right hand.
		oldhand = po.handedness;
		po.handedness = hand();
	}

	// Do it.
	super.renderOverlays(c);

	// Render the slave.
	if (slave != none) {
		// Is this not ever caught in animEnd()? FIX.
		if (slave.bBringingUp) {
			u.debug("renderOverlays(): bringing up slave: " $ u.sname(slave));
			slave.bBringingUp = false;
			slave.playSelect();
		}
		slave.renderOverlays(c);
	}

	if (po != none)
		// Restore the hand.
		po.handedness = oldhand;

	// Restore the true PVO.
	playerViewOffset = pvo;
}


/** While rotation is free (18000 up and 49752 down), viewRotation
	only goes from 3072 (up) to 62464 (down). Except underwater, so we'll
	lock it to the normal viewRotation pitch range.
*/
simulated function pitchAdjust(int pitch) {
	if (pitch >= 49752)
		pitch = max(62464, pitch);

	if (pitch < 18000)
		pitch = min(3072, pitch);

	if (pitch > 3072) {
		// Looking down.
		pitch -= 65535;
	}

	playerViewOffset.x = 100 * (default.playerViewOffset.x + paSlide * (pitch / 3072.0));

	if (bDrawMuzzleFlash) {
		flashY = default.flashY - paFlashY * (pitch / 3072.0);
		flashO = default.flashO - paFlashO * (pitch / 3072.0);
	}
}


/** Sometimes the slave needs to refer back to the master.
*/
simulated function SLWeapon mate() {
	if (bSlave)
		// Obey... your...
		return master;
	else
		return slave;
}


/** The handedness is Botpack.PlayerPawn is not always the value that
	we want to use for displaying and firing. Certain weapons may lack
	models for either left, right, or center; or may have a slave
	counterpart, which is used in the opposite hand. This function
	returns the correct value for this weapon instance.

	Sometimes during ClientActive the owner is not set. Default to
	right-handed.
*/
simulated function float hand() {
	local float h;

	if (owner != none && owner.isA('PlayerPawn'))
		h = PlayerPawn(owner).handedness;
	else
		// Default to right handed (bots).
		h = -1;

	// No center? Use right.
	if (bNoCenter && h == 0)
		h = -1;

	// Generally akimbo weapons are bNoCenter, but what the hay.
	if (bSlave && h != 0)
		h = -h;

	return h;
}



// end

defaultproperties
{
     recoilData=(Base=100.000000,limit=1000.000000,Kick=1.000000,returnRate=1000.000000,smoothRate=500.000000,pvoScale=0.100000,accScale=0.001000)
     assFire=(aname=Fire,arate=1.000000,Volume=1.000000,bSkipOwner=True)
     assAltFire=(aname=AltFire,arate=1.000000,Volume=1.000000,bSkipOwner=True)
     assSelect=(aname=Select,arate=1.000000,Volume=1.000000,Slot=SLOT_Misc)
     assDown=(aname=Down,arate=1.000000,tween=0.050000,Volume=1.000000,Slot=SLOT_Misc)
     assReload=(aname=Reload,arate=1.000000,Sound=Sound'SLV2Sounds.Weapon.Reload',Volume=2.000000,Slot=SLOT_Misc)
     assIdle=(aname=Idle,arate=1.000000,Volume=1.000000,Slot=SLOT_Misc)
     assEmpty=(aname=empty,Sound=Sound'SLV2Sounds.Weapon.empty',Volume=1.000000,Slot=SLOT_Misc)
     assMode=(aname=empty,Sound=Sound'SLV2Sounds.Weapon.empty',Volume=0.500000,Slot=SLOT_Misc)
     MFVariations(0)=Texture'SLV2Textures.muzf.mf0'
     MFVariations(1)=Texture'SLV2Textures.muzf.mf1'
     MFVariations(2)=Texture'SLV2Textures.muzf.mf2'
     MFVariations(3)=Texture'SLV2Textures.muzf.mf3'
     MFVariations(4)=Texture'SLV2Textures.muzf.mf4'
     MFVariations(5)=Texture'SLV2Textures.muzf.mf5'
     paSlide=2.000000
     PickupAmmoCount=1
     bOwnsCrosshair=True
     Physics=PHYS_Falling
     bNoSmooth=False
}
