/*======================================================
	WEAPONS.QC			Custom TeamFortress v3.1

	(c) TeamFortress Software Pty Ltd 	29/2/97
	(c) William Kerney			5/21/00
========================================================
All the functions for firing all the weapons, holds
all new precache() functions, finding best weapons, 
choosing next weapon, and all impulse commands.
======================================================*/
#include "defs.qh"
#include "menu.qh"

void() SniperSight_Update2; //CH for RL
void() I_DID_CHEAT_ONE; //CH for speed.qc
void() I_DID_CHEAT_TWO;
void() I_DID_CHEAT_THREE;
void(string gibname, float dm) ThrowGib;	
void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
void (entity targ, entity inflictor, entity attacker, float damage, float T_flags, float T_AttackType) TF_T_Damage;
void () player_run;
void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
void() TeamFortress_DisplayDetectionItems;
vector(vector veca, vector vecb) crossproduct;
void(vector org, float damage) SpawnBlood;
void(entity rhook) Reset_Grapple;
void() SuperDamageSound;
float() W_BestWeapon;
void() ConcussionGrenadeTimer;
void() W_PrintWeaponMessage;
void() button_touch;
void() button_fire;
void() MauserRecoilThink;
float() ReturnWeaponVelocity;
vector() Grunty_LeadShot;

// TeamFortress Impulse Commands
void() TeamFortress_ChangeClass;
void() TeamFortress_DisplayLegalClasses;
void() TeamFortress_Inventory;
void() TeamFortress_SaveMe;
void(float inAuto) TeamFortress_ID;
void() TeamFortress_ShowTF;
void() TeamFortress_SniperWeapon;
void() TeamFortress_AssaultWeapon;
void() TeamFortress_IncendiaryCannon;
void() TeamFortress_FlameThrower;
void() TeamFortress_PrimeGrenade;
void() TeamFortress_ThrowGrenade;
void() TeamFortress_Discard;
void(entity p) TeamFortress_SetSpeed;
void() TeamFortress_DetonatePipebombs;
void() PipebombTouch;
void(float foo) TeamFortress_DetpackStop;
void(float type) SniperSight_Create;
void(float zoom_level) TF_zoom;
void() TeamFortress_ReloadCurrentWeapon;
void() TeamFortress_AutoZoomToggle;
void() TeamFortress_StatusQuery;
void() TeamFortress_SpyGoUndercover;
void(float type) TeamFortress_SpyFeignDeath;
void() TeamFortress_EngineerBuild;
void() DropKey;
void() UseSpecialSkill;
void() UseJobSkill; //WK Function for handling professions
void (entity targ, float pain) RevealThief;
void(vector startpos) GuerillaMineSweep;
void(entity foo,float bar) makeImmune;
float() CheckForReload;
void() SBBuildSensor;
void() SBFireInterface;
//void() SBInitiateInterface;
void() W_FireMauser;
void() W_FireDaedalus;

// TeamFortress Pre-Impulse Commands
void(float scanrange,float inAuto) TeamFortress_Scan;
void(float timer) TeamFortress_SetDetpack;

// Team Functions
float(float tno) TeamFortress_TeamSet;
void(float tno) TeamFortress_TeamShowScores;
void(entity Player) TeamFortress_TeamShowMemberClasses;

#ifdef DEMO_STUFF
// Camera Functions
void() CamLock;
void() CamDistLock;
void() CamVecLock; 
void() CamAngleLock;
void() CamRevAngleLock;
void() CamProjectileLock;
void() CamProjectileZoom;
void() CamProjectileLockOn;
void() CamProjectileLockOff;
void() CamOffset;
void() CamDrop;
void() fadetoblack;
void() fadefromblack;
void() fadetowhite;
void() fadefromwhite;
#endif

// Engineer Functions
void(entity disp) Engineer_UseDispenser;
void(entity cam) Engineer_UseSensor;
void(entity gun) Engineer_UseSentryGun;
void(entity gun) Engineer_UseTesla;
void(entity cam) Engineer_UseCamera;
void(entity tele) Engineer_UseTeleporter;
void(entity field) Engineer_UseFieldGen;
void() Engineer_AutoUse;

void(entity spy) Spy_RemoveDisguise;

// Help functions
void() TeamFortress_MOTD;
void() TeamFortress_HelpMap;
void(float res) StatusRes;

// BioInfection functions
void() BioInfection_Decay;
void() BioInfection_MonsterDecay;

// Attacking functions
void() W_FireFlame;
void() W_FireIncendiaryCannon;
void() W_FireTranq;
void() W_FireLaser;

// Timer Functions
void() HallucinationTimer;
void() TranquiliserTimer;

// CTF Support functions
void() TeamFortress_CTF_FlagInfo;

// PC_UNDEFINED viewing functions
void() TF_MovePlayer;

//WK CustomTF Functions
void() custom_demon_precache;
void() custom_lay;
//void() CameraSwitchView;

//CH dropitems
void() TeamFortress_DropItems;

//- OfN -
void(entity player) ActivateHolo;
void(vector org, vector dir) grunty_spike;
void () UpdateInfos;
void() launch_horn;
void() player_laser1;
void(entity field) PutFieldWork;
void(entity tfield, vector where, entity thing) FieldExplosion;

// called by worldspawn
void() W_Precache =
{
	precache_sound ("weapons/r_exp3.wav");	// new rocket explosion
	precache_sound ("weapons/rocket1i.wav");  // spike gun
	precache_sound ("weapons/sgun1.wav");
	precache_sound ("weapons/guncock.wav");	// player shotgun
	precache_sound ("weapons/ric1.wav");	// ricochet (used in c code)
	precache_sound ("weapons/ric2.wav");	// ricochet (used in c code)
	precache_sound ("weapons/ric3.wav");	// ricochet (used in c code)
	precache_sound ("weapons/spike2.wav");	// super spikes
	precache_sound ("weapons/tink1.wav");	// spikes tink (used in c code)
	precache_sound ("weapons/grenade.wav");	// grenade launcher
	precache_sound ("weapons/bounce.wav");	// grenade bounce
	precache_sound ("weapons/shotgn2.wav");	// super shotgun
	precache_sound ("wizard/wattack.wav");    // sniper rifle
	precache_sound ("items/r_item1.wav");	// Medikit
	precache_sound ("items/r_item2.wav");	// Medikit
	precache_model ("progs/flame2.mdl");  	// Flamethrower
	precache_sound ("ambience/fire1.wav");
	precache_sound2("blob/land1.wav");        // Hook
	precache_model2("progs/v_spike.mdl");	// Hook
	precache_sound ("hknight/hit.wav");		// Hook
// NEW FILES
	precache_sound ("weapons/turrset.wav");	// Sentry Gun Setup
	precache_sound ("weapons/turrspot.wav");	// Sentry Gun Spot 
	precache_sound ("weapons/turridle.wav");	// Sentry Gun Idle
	precache_sound ("weapons/sniper.wav");	// sniper rifle
	precache_sound ("weapons/flmfire2.wav");	// flamethrower
	precache_sound ("weapons/flmgrexp.wav");	// flamethrower
	precache_sound ("misc/vapeur2.wav");	// flamethrower
	precache_sound ("weapons/asscan1.wav");	// Assault Cannon Powerup
	precache_sound ("weapons/asscan2.wav");	// Assault Cannon Churning
	precache_sound ("weapons/asscan3.wav");	// Assault Cannon Powerdown
	precache_sound ("weapons/railgun.wav");	// Railgun
	precache_sound ("weapons/dartgun.wav");	// Spy's dart gun
	precache_sound ("ambience/thunder1.wav");	// Connect sound
	
	//WK
//	precache_model ("progs/v_merc.mdl");		//Carbine Model
//	precache_sound ("weapons/carbfire.wav");		// Carbine shooting
//	precache_sound ("weapons/carbreld.wav");		// Carbine shooting
//	precache_sound ("weapons/carbrock.wav");		// Carbine shooting
//	precache_sound ("weapons/nishi.wav");		// Nishi shooting
	precache_model ("progs/telepad.mdl");		//Teleporter pad
	precache_model ("progs/camera.mdl");		// Security Camera
	precache_sound ("ambience/orff.wav");		// Chaplan sound
	precache_sound ("weapons/guerilla_blip.wav");	// Landmine beep
	precache_sound ("weapons/guerilla_set.wav");	// Landmine set
	precache_sound ("weapons/camera_beep.wav");	// CH camera beep
	precache_sound ("misc/enemy.wav"); // sensor alert
	precache_sound ("weapons/fith.wav");	// WK Fire in the hole
//	precache_model2("progs/guerilla_mine.mdl");	// The Landmine
//	precache_model ("progs/tesla.mdl");	  	  	  // The Tesla (by --Warrior--)
	precache_model ("progs/minimissile.mdl");	  	  // Swarm missile (BLOG)
//	precache_model ("progs/newtesla.mdl");	  	  // The Tesla (by --Warrior-- & BLOG)
	precache_model ("progs/coil.mdl");	  	  // The Tesla (by --Warrior-- & BLOG)
//	precache_model ("progs/tscloak.mdl");
	precache_model ("progs/tesgib1.mdl");		  // Tesla Gib
	precache_model ("progs/tesgib2.mdl");		  // Tesla Gib
	precache_model ("progs/tesgib3.mdl");		  // Tesla Gib
	precache_sound ("doors/medtry.wav");		  //CH Dropping detpack sound
	precache_sound ("doors/baseuse.wav");		  //CH Detpack warning sound
	precache_sound ("enforcer/sight1.wav");   // WK Taunt
	precache_sound ("enforcer/sight2.wav");   // WK Taunt
	precache_sound ("enforcer/sight3.wav");   // WK Taunt
	precache_sound ("enforcer/sight4.wav");   // WK Taunt

	custom_demon_precache();
};

float() crandom =
{
	return 2*(random() - 0.5);
};

//======================================================================
// Calculate the attack_finished time
void(float att_delay) Attack_Finished =
{
	if (self.tfstate & TFSTATE_TRANQUILISED)
		self.attack_finished = time + (att_delay * 1.5);
	else if (self.aura == AURA_HASTE)
		self.attack_finished = time + (att_delay * 0.5);
	else 
		self.attack_finished = time + att_delay;
};

void (entity atk, boolean do_cc, float dist) find_melee = 
{
	local vector dir;

	if (self.classname == "player") {
		makevectors (atk.v_angle);
		dir = v_forward;
	} else {
		dir = normalize (atk.enemy.origin - atk.origin);
	}

	local vector source = atk.origin + '0 0 16';

	traceline (source, source + dir*dist, FALSE, atk);

	if (trace_fraction != 1.0)
		return;

	if (do_cc && (atk.cutf_items & CUTF_CLOSECOMBAT)) {
		local entity te = findradius (source, dist);
		local float tdist = -0.6;

		do {
			local vector diff = source - (te.origin + '0 0 16');
			diff_z *= 0.75; //hack

			local float l;

			l = (normalize (diff) * dir);

			if (l < tdist && te.takedamage == DAMAGE_AIM) {
				tdist = l;
				trace_ent = te;
				trace_fraction = 0.5;
			}
		} while ((te = te.chain));
	}
};

/*
================
W_FireAxe
================
*/
void() W_FireAxe =
{
	local	vector	org;
	
	find_melee (self, TRUE, 64);

	if (trace_fraction == 1.0)
		return;

	org = trace_endpos - v_forward*4;

	if (trace_ent.classname == "force_field") {
		FieldExplosion(trace_ent,trace_endpos,trace_ent);
		PutFieldWork(trace_ent);

		return;
	}

	if (trace_ent.takedamage) {
		trace_ent.axhitme = 1;

		SpawnBlood (org, 20);

		deathmsg = DMSG_AXE;

		if (!(self.cutf_items & CUTF_KNIFE)) {
			TF_T_Damage (trace_ent, self, self, 30, TF_TD_NOTTEAM, TF_TD_MELEE);
		} else {
			//WK Only give blood if you hit an enemy when being a warlock
			if ((!Teammate(trace_ent.team_no, self.team_no) || !(self.job & JOB_WARLOCK)) && prematch < time) {
				self.job = self.job | JOB_BLOODY_KNIFE;
				self.weaponmode = 1; // Put blood on the knife
  				self.weaponmodel = "progs/v_knife2.mdl";
			} else if (self.job & JOB_WARLOCK) {
				sprint(self,PRINT_HIGH,"You may only draw blood from enemies\n");
			}

			TF_T_Damage (trace_ent, self, self, 50, TF_TD_NOTTEAM, TF_TD_MELEE);
		}
	} else {	// hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PVS);
	}
};

boolean (boolean strict) is_backstab =
{
	local	float	d;
	local	vector	dir;

	makevectors (trace_ent.angles);

	dir = trace_ent.origin - self.origin;

	dir_z *= 0.75; // hack

	d = normalize (dir) * v_forward;

	if (d < 0.3)
		return FALSE;

	if (!strict)
		return TRUE;

	if (d < 0.7)
		return FALSE;

	d = normalize (trace_ent.origin - trace_endpos) * v_forward;

	if (d < 0.8)
		return FALSE;

	return TRUE;
};

/*
================
W_FireBackstab
================
*/

void() W_FireBackstab =
{
	local	vector	org;

	if (!(self.cutf_items & CUTF_KNIFE)) {
		W_FireAxe ();
		return;
	}
	
	find_melee (self, FALSE, 64);

	if (trace_fraction == 1.0)
		return;

	org = trace_endpos - v_forward*4;

	if (trace_ent.classname == "force_field") {
		FieldExplosion(trace_ent,trace_endpos,trace_ent);
		PutFieldWork(trace_ent);

		return;
	}

	local boolean	living = FALSE;

	if (trace_ent.classname == "player" || IsMonster (trace_ent))
		living = TRUE;

	if (trace_ent.takedamage) {
		trace_ent.axhitme = 1;

		deathmsg = DMSG_BACKSTAB;

		if (living) {
			if (trace_ent.classname != "player" && trace_ent.real_owner)
				trace_ent.team_no = trace_ent.real_owner.team_no;

			//WK Only give blood if you hit an enemy when being a warlock
			if ((!Teammate(trace_ent.team_no, self.team_no) || !(self.job & JOB_WARLOCK)) && prematch < time) {
				self.job = self.job | JOB_BLOODY_KNIFE;
				self.weaponmode = 1;
				self.weaponmodel = "progs/v_knife2.mdl";
			} else if (self.job & JOB_WARLOCK) {
				sprint(self,PRINT_HIGH,"You may only draw blood from enemies\n");
			}
		}

		if (is_backstab (TRUE) && living) {

			SpawnBlood (org, 50);

			local entity oself = self;
			self = trace_ent;

			ThrowGib ("progs/gib1.mdl", -50);
			ThrowGib ("progs/gib2.mdl", 10);
			ThrowGib ("progs/gib3.mdl", 50);
			ThrowGib ("progs/gib2.mdl", 25);

			self = oself;

			if (trace_ent.classname == "player")
				stuffcmd (trace_ent, "bf; bf\n");

			if (!(trace_ent.armorclass & AT_SAVEMELEE))
				TF_T_Damage (trace_ent, self, self, 100, TF_TD_NOTTEAM | TF_TD_IGNOREARMOUR,
					TF_TD_MELEE);
			else
				TF_T_Damage (trace_ent, self, self, 100, TF_TD_NOTTEAM, TF_TD_MELEE);
		} else {
			deathmsg = DMSG_AXE;

			SpawnBlood (org, 10);

			TF_T_Damage (trace_ent, self, self, 30, TF_TD_NOTTEAM, TF_TD_MELEE);
		}

	} else {	// hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PVS);
	}
}
/*
================
W_FireSpanner
================
*/
void() W_FireSpanner =
{
	local vector org;
	local float healam;
	local entity te;

	find_melee (self, TRUE, 64);

	if (trace_fraction == 1.0)
		return;
	
	org = trace_endpos - v_forward*4;

    if (trace_ent.classname == "force_field") {
        FieldExplosion(trace_ent,trace_endpos,trace_ent);
        PutFieldWork(trace_ent);

        deathmsg = DMSG_SPANNERFIELD;
        TF_T_Damage(self, self, self, self.health + 50, TF_TD_IGNOREARMOUR, TF_TD_OTHER);
        sound (self, CHAN_MISC, "effects/crunch.wav", 1, ATTN_NONE);

        return;
    }

	// It may be a trigger that can be activated by the engineer's spanner
	if (trace_ent.goal_activation & TFGA_SPANNER) {
		// Does the AP match the AP Criteria?
		if (Activated(trace_ent,self)) {
			DoResults(trace_ent, self, TRUE);

			if (trace_ent.classname == "func_button") {
				trace_ent.enemy = self;
				other = self;
				self = trace_ent;
				self.dont_do_triggerwork = TRUE;	// Already done in DoResults
				button_fire();
				self = other;
			}
		} else {
			// If an else goal should be activated, activate it
			if (trace_ent.else_goal != 0) {
				te = Findgoal(trace_ent.else_goal);
				if (te)
					DoResults(te, self, (trace_ent.goal_result & TFGR_ADD_BONUSES));
			} else {
				sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
				WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
				WriteByte (MSG_MULTICAST, TE_GUNSHOT);
				WriteByte (MSG_MULTICAST, 3);
				WriteCoord (MSG_MULTICAST, org_x);
				WriteCoord (MSG_MULTICAST, org_y);
				WriteCoord (MSG_MULTICAST, org_z);
				multicast (org, MULTICAST_PVS);
			}
		}

		return;
	}

	if (trace_ent.takedamage) {
		// auto-repair/dismantle if hit twice
		if (trace_ent == self.building) {
			Engineer_AutoUse();
		}

		if (trace_ent.classname == "building_dispenser") {
			Engineer_UseDispenser(trace_ent);
			return;
		} else if (trace_ent.classname == "building_sentrygun") {
			Engineer_UseSentryGun(trace_ent);
			return;
		} else if (trace_ent.classname == "building_sentrygun_base") {
			if (trace_ent.oldenemy)
				Engineer_UseSentryGun(trace_ent.oldenemy);
			return;
		} else if (trace_ent.classname == "building_tesla") {
			Engineer_UseTesla(trace_ent);
			return;
		} else if (trace_ent.classname == "building_camera") {
			Engineer_UseCamera(trace_ent);
			return;
		} else if (trace_ent.classname == "building_sensor") {
			Engineer_UseSensor(trace_ent);
			return;
		} else if (trace_ent.classname == "building_teleporter") {
			Engineer_UseTeleporter(trace_ent);
			return;
		} else if (trace_ent.classname == "building_fieldgen") {
			Engineer_UseFieldGen(trace_ent);
			return;
		} else {
			if (trace_ent.classname == "player") {
				if (Teammate(trace_ent.team_no, self.team_no) && (teamplay) || (coop)) {
					healam = WEAP_SPANNER_REPAIR;
					if (self.ammo_cells < healam)
						healam = self.ammo_cells;

					// Only fix armor if they've got some
					if (trace_ent.armor_allowed == 0) //WK
						return;
						
					if (trace_ent.armorvalue <= 0) // SB
						return;
					
					if (trace_ent.maxarmor - trace_ent.armorvalue < (healam * 4))
						healam = ceil((trace_ent.maxarmor - trace_ent.armorvalue) / 4);
						
					if (healam > 0) {
						trace_ent.armorvalue = trace_ent.armorvalue + (healam * 4);
						if (trace_ent.armorvalue > trace_ent.maxarmor)
							trace_ent.armorvalue = trace_ent.maxarmor;

						//WK Give them full armor color
						trace_ent.armortype = trace_ent.armor_allowed;

						self.ammo_cells = self.ammo_cells - healam;

						sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM);
						WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
						WriteByte (MSG_MULTICAST, TE_GUNSHOT);
						WriteByte (MSG_MULTICAST, 3);
						WriteCoord (MSG_MULTICAST, org_x);
						WriteCoord (MSG_MULTICAST, org_y);
						WriteCoord (MSG_MULTICAST, org_z);
						multicast (org, MULTICAST_PVS);

						W_SetCurrentAmmo ();
					}
					return;
				}
			}

			trace_ent.axhitme = 1;
			SpawnBlood (org, 20);

			deathmsg = DMSG_SPANNER;
//WK 20
			TF_T_Damage (trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_MELEE);
		}
	} else { // hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PVS);
	}
};

/*
================
W_FireMedikit  
================
*/

void(entity ignore, entity ignore2, string st, string st2, string st3, string st4, string st5, string st6) teamsprintbi;
void(float tno, entity ignore, entity ignore2) teamprefixsprintbi;

void(float inAuto) W_FireMedikit =
{
	local	vector	org;
	local	float healam;	
	local 	entity te, BioInfection;

	find_melee (self, TRUE, 64);

	if (trace_fraction == 1.0)
		return;
	
	org = trace_endpos - v_forward*4;

	if (trace_ent.takedamage) {
		if (trace_ent.classname == "player") {
			if (Teammate(trace_ent.team_no, self.team_no) || (coop)) {
				healam = WEAP_MEDIKIT_HEAL;

				// remove concussion from player
				// Try to find a concusstimer entity for this player
				te = find(NIL, classname, "timer");
				while (((te.owner != trace_ent) || (te.think != ConcussionGrenadeTimer)) && (te)) {
					te = find(te, classname, "timer");
				}

				if (te) {
					stuffcmd(trace_ent ,"v_idlescale 0\n");
					trace_ent.mangle = '0 0 0';
					SpawnBlood(org, 20);
					sprint(trace_ent, PRINT_HIGH, "you have been healed of your concussion\n");
					trace_ent.tfstate &= ~TFSTATE_CONCUSSIONED;

					// Give the medic a frag for doing it, only if it was caused by an enemy
					if (!Teammate(self.team_no,te.team_no)) {
						self.real_frags = self.real_frags + 1;
			 			if (!(toggleflags & TFLAG_TEAMFRAGS))
							self.frags = self.real_frags;
					}

					dremove(te);
				}

				// remove hallucination from player
				// Try to find a hallucination timer entity for this player
				if (trace_ent.tfstate & TFSTATE_HALLUCINATING) {
					te = find(NIL, classname, "timer");
					while (((te.owner != trace_ent)
							|| (te.think != HallucinationTimer)) && (te)) {
						te = find(te, classname, "timer");
					}

					if (te) {
						trace_ent.tfstate = trace_ent.tfstate - (trace_ent.tfstate & TFSTATE_HALLUCINATING);

						SpawnBlood(org, 20);
						sprint(trace_ent, PRINT_HIGH, "you have been healed of your hallucinations\n");

						// Give the medic a frag for doing it, only if it was caused by an enemy
						if (!Teammate(self.team_no,te.team_no)) {
							self.real_frags = self.real_frags + 1;
				 			if (!(toggleflags & TFLAG_TEAMFRAGS))
								self.frags = self.real_frags;
						}

						dremove(te);
					} else {
						RPrint("Warning: Error in Hallucination Timer logic.\n");
					}
				}

				// remove tranquilisation from player
				// Try to find a tranquilisation timer entity for this player
				if (trace_ent.tfstate & TFSTATE_TRANQUILISED) {
					te = find(NIL, classname, "timer");
					while (((te.owner != trace_ent) || (te.think != TranquiliserTimer)) && (te)) {
						te = find(te, classname, "timer");
					}

					if (te) {
						trace_ent.tfstate = trace_ent.tfstate - (trace_ent.tfstate & TFSTATE_TRANQUILISED);
						TeamFortress_SetSpeed(trace_ent);

						SpawnBlood(org, 20);
						sprint(trace_ent, PRINT_HIGH, "you have been healed of your tranquilisation\n");

						// Give the medic a frag for doing it, only if it was caused by an enemy
						if (!Teammate(self.team_no,te.team_no)) {
							self.real_frags = self.real_frags + 1;
				 			if (!(toggleflags & TFLAG_TEAMFRAGS))
								self.frags = self.real_frags;
						}

						dremove(te);
					} else {
						RPrint("Warning: Error in Tranquilisation Timer logic.\n");
					}
				}

				// check if the healed player is blinded
				if (trace_ent.FlashTime > 0) {
					te = find(NIL, netname, "flashtimer");
					while ((te.owner != trace_ent || te.classname != "timer") && (te))
						te = find(te, netname, "flashtimer");

					if (te) {
						trace_ent.FlashTime = 0;
						SpawnBlood(org, 20);

						// Give the medic a frag for doing it, only if it was caused by an enemy
						stuffcmd(trace_ent, "v_cshift 0\n"); //WK -- /CH te -> trace_ent
						stuffcmd(trace_ent, "r_norefresh 0;wait;echo;wait;echo;wait;echo;wait;echo\n"); //WK -- /CH te -> trace_ent

						if (!Teammate(self.team_no,te.team_no)) {
							self.real_frags = self.real_frags + 1;
				 			if (!(toggleflags & TFLAG_TEAMFRAGS))
								self.frags = self.real_frags;
						}

						dremove(te);
					} else {
						RPrint("Warning: Error in Flash Timer logic.\n");
						trace_ent.FlashTime = 0;
					}
				}

				// check if the healed player is infected
				if (trace_ent.tfstate & TFSTATE_INFECTED) {
					healam = rint(trace_ent.health / 2);

					// remove the infection
					trace_ent.tfstate = trace_ent.tfstate - (trace_ent.tfstate & TFSTATE_INFECTED);

					// some damage is caused (because of the use of leeches!)
					// remove half their remaining health
					deathmsg = DMSG_MEDIKIT;
					T_Damage(trace_ent, self, self, healam);

					SpawnBlood(org, 30);
					sprint(trace_ent, PRINT_HIGH,self.netname);
         			sprint(trace_ent, PRINT_HIGH, " cures your infection!\n");

					if (self.classname == "player") {
						sprint(self, PRINT_HIGH, "You have healed ");
						sprint(self, PRINT_HIGH, trace_ent.netname);
						sprint(self, PRINT_HIGH, " of the infection.\n");

						teamprefixsprintbi(self.team_no, self, trace_ent);
						teamsprintbi(self, trace_ent, trace_ent.netname,
									 " infection has been cured by ",
									 self.netname, "\n", "", "");

						// Give the medic a frag for doing it, only if it was caused by an enemy
						if (!Teammate(trace_ent.infection_team_no, self.team_no)) {
							self.real_frags = self.real_frags + 1;
				 			if (!(toggleflags & TFLAG_TEAMFRAGS))
								self.frags = self.real_frags;
						}
					}

					return;
				}

				// put out the fire if they are burning
				if (trace_ent.numflames > 0) {
					sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM);
					trace_ent.numflames = 0;

					sprint(trace_ent, PRINT_HIGH, "The flames have been doused!\n");

					if (self.classname == "player") {		
						sprint(self, PRINT_MEDIUM, "You have put out ");
						sprint(self, PRINT_MEDIUM, trace_ent.netname);
						sprint(self, PRINT_MEDIUM, "'s fire.\n");	
					}
					
					return;
				}

				if (healam > 0 && trace_ent.health < trace_ent.max_health) {
					sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM);
					trace_ent.axhitme = 1;
					SpawnBlood (org, 20);

					T_Heal(trace_ent, healam, 0);
				} else if (trace_ent.health >= trace_ent.max_health && trace_ent.health < (trace_ent.max_health + WEAP_MEDIKIT_OVERHEAL)) {
					healam = 10;
					if (healam > (self.ammo_medikit * 10))
						healam = (self.ammo_medikit * 10);
					if (healam > 0) {
						sound(trace_ent, CHAN_ITEM, "items/r_item2.wav", 1, ATTN_NORM);
						T_Heal(trace_ent, healam, 1);
						self.ammo_medikit = self.ammo_medikit - rint(healam / 10);
						if (!(trace_ent.items & IT_SUPERHEALTH)) {
							trace_ent.items = trace_ent.items | IT_SUPERHEALTH;
							newmis = spawn();
							newmis.classname = "medikit_rot";
							newmis.nextthink = time + 20;
							newmis.think = item_megahealth_rot;
							newmis.owner = trace_ent;
						}
					}
				}
			}

#ifdef MEDIKIT_IS_BIOWEAPON
			//WK Don't infect if they're invincible or observing
			else if (!(trace_ent.invincible_finished) && !(trace_ent.playerclass == PC_UNDEFINED)) {
				if (inAuto)
					return;
				trace_ent.axhitme = 1;
				SpawnBlood (org, 20);

				deathmsg = DMSG_BIOWEAPON_ATT;
				if (!(self.cutf_items & CUTF_CLOSECOMBAT))
					T_Damage (trace_ent, self, self, 10);
				else
					T_Damage (trace_ent, self, self, 20);
					
				if (trace_ent.weapons_carried & WEAP_MEDIKIT) //WK
					return;

				//Melee armor stops infection 75% of the time
				if (trace_ent.tf_items & NIT_GEL && random() < 0.75)
					return;

				trace_ent.tfstate = trace_ent.tfstate | TFSTATE_INFECTED;

				BioInfection = spawn ();
				BioInfection.classname = "timer";
				BioInfection.netname = "biotimer";
				BioInfection.owner = trace_ent;
				BioInfection.nextthink = time + 2;
				BioInfection.think = BioInfection_Decay;
				BioInfection.enemy = self;

				trace_ent.infection_team_no = self.team_no;
			}
#endif

  		} else if (IsMonster(trace_ent)) { //- OfN - //|| trace_ent.classname == "monster_fish")
  			if (Teammate(trace_ent.real_owner.team_no, self.team_no)) {
				if (trace_ent.health < trace_ent.max_health) {
					if (trace_ent.max_health - trace_ent.health < 50)
						healam = trace_ent.max_health - trace_ent.health;
					else
						healam = 50;
					if (healam > self.ammo_medikit)
						healam = self.ammo_medikit;
						
					if (healam == 0)
						return;
					sound(trace_ent, CHAN_WEAPON, "items/r_item1.wav", 1, ATTN_NORM);
					trace_ent.axhitme = 1;
					SpawnBlood (org, 20);

					T_Heal(trace_ent, healam, 0);
					self.ammo_medikit = self.ammo_medikit - healam;
					if (trace_ent.health > trace_ent.max_health)
						trace_ent.health = trace_ent.max_health;
				}
			}
		} else {
			trace_ent.axhitme = 1;
			SpawnBlood (org, 30);
			T_Damage (trace_ent, self, self, 10);
		}
	} else {
		if (inAuto) return; //Don't click for automedic
		// hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PVS);
	}
};

/*
================
W_FireBioweapon
================
*/
void() W_FireBioweapon =
{
	local	vector	source;
	local	vector	org;

	local 	entity BioInfection;

	source = self.origin + '0 0 16';
	traceline (source, source + v_forward*64, FALSE, self);
	if (trace_fraction == 1.0)
		return;
	
	org = trace_endpos - v_forward*4;

	if (trace_ent.takedamage) {
		if (trace_ent.classname == "player") {
			if ((!Teammate(trace_ent.team_no, self.team_no) && teamplay) || teamplay == 0) {
				trace_ent.axhitme = 1;
				SpawnBlood (org, 20);
		
				deathmsg = DMSG_BIOWEAPON_ATT;
				if (!(self.cutf_items & CUTF_CLOSECOMBAT))
					T_Damage (trace_ent, self, self, 10);
				else
					T_Damage (trace_ent, self, self, 20);

				if (trace_ent.weapons_carried & WEAP_MEDIKIT) //WK
					return;

				trace_ent.tfstate = trace_ent.tfstate | TFSTATE_INFECTED;

				BioInfection = spawn ();
				BioInfection.classname = "timer";
				BioInfection.netname = "biotimer";
				BioInfection.owner = trace_ent;
				BioInfection.nextthink = time + 2;
				BioInfection.think = BioInfection_Decay;
				BioInfection.enemy = self;

				trace_ent.infection_team_no = self.team_no;
			}
		} else if (trace_ent.flags & FL_MONSTER) {
			if (trace_ent.classname == "monster_zombie") {
				// zombie slayer!
				T_Damage (trace_ent, self, self, 200);
			}

			trace_ent.axhitme = 1;
			SpawnBlood(org, 20);
			if (!(self.cutf_items & CUTF_CLOSECOMBAT))
				T_Damage (trace_ent, self, self, 10);
			else
				T_Damage (trace_ent, self, self, 20);

			BioInfection = spawn ();
			BioInfection.classname = "timer";
			BioInfection.classname = "biotimer";
			BioInfection.nextthink = time + 2;
			BioInfection.think = BioInfection_MonsterDecay;
			BioInfection.owner = self;
			BioInfection.enemy = trace_ent;
		} else { // must be a switch
			trace_ent.axhitme = 1;
			SpawnBlood (org, 30);

			T_Damage(trace_ent, self, self, 40);
		}
	} else {	// hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PVS);
	}
};

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

vector() wall_velocity =
{
	local vector	vel;
	
	vel = normalize (self.velocity);
	vel = normalize(vel + v_up*(random()- 0.5) + v_right*(random()- 0.5));
	vel = vel + 2*trace_plane_normal;
	vel = vel * 200;
	
	return vel;
};

/*
================
SpawnMeatSpray
================
*/
void(vector org, vector vel) SpawnMeatSpray =
{
	local	entity missile;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_BOUNCE;
	missile.solid = SOLID_NOT;

	makevectors (self.angles);

	missile.velocity = vel;
	missile.velocity_z = missile.velocity_z + 250 + 50*random();

	missile.avelocity = '3000 1000 2000';

	// set missile duration
	missile.nextthink = time + 1;
	missile.think = SUB_Remove;

	setmodel (missile, "progs/zom_gib.mdl");
	setsize (missile, '0 0 0', '0 0 0');		
	setorigin (missile, org);
};

/*
================
SpawnBlood
================
*/
void(vector org, float damage) SpawnBlood =
{
	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_BLOOD);
	WriteByte (MSG_MULTICAST, 1);
	WriteCoord (MSG_MULTICAST, org_x);
	WriteCoord (MSG_MULTICAST, org_y);
	WriteCoord (MSG_MULTICAST, org_z);
	multicast (org, MULTICAST_PVS);
};

/*
================
spawn_touchblood
================
*/
void(float damage) spawn_touchblood =
{
	local vector	vel;

	vel = wall_velocity () * 0.2;
	SpawnBlood (self.origin + vel*0.01, damage);
};

/*
================
SpawnChunk
================
*/
void(vector org, vector vel) SpawnChunk =
{
//	particle (org, vel*0.02, 0, 10);
};

/*
==============================================================================

MULTI-DAMAGE

Collects multiple small damages into a single damage

==============================================================================
*/

entity	multi_ent;
float	multi_damage;

vector  blood_org;
float   blood_count;

vector  puff_org;
float   puff_count;

void() ClearMultiDamage =
{
	multi_ent = NIL;
	multi_damage = 0;
	blood_count = 0;
	puff_count = 0;
};

void() ApplyMultiDamage =
{
	if (!multi_ent)
		return;
	// don't set deathmsg here, since it'll be set by the weapon that fired
	if (self.current_weapon & WEAP_LIGHT_ASSAULT)
		TF_T_Damage (multi_ent, self, self, multi_damage, TF_TD_NOTTEAM, TF_TD_NAIL);
	else
		TF_T_Damage (multi_ent, self, self, multi_damage, TF_TD_NOTTEAM, TF_TD_SHOT);
};

void(entity hit, float damage) AddMultiDamage =
{
	if (!hit)
		return;
	
	if (hit != multi_ent) {
		ApplyMultiDamage ();
		multi_damage = damage;
		multi_ent = hit;
	} else
		multi_damage = multi_damage + damage;
};

void (integer big) Multi_Finish =
{
	if (puff_count) {
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, big ? puff_count * 2 : puff_count);
		WriteCoord (MSG_MULTICAST, puff_org_x);
		WriteCoord (MSG_MULTICAST, puff_org_y);
		WriteCoord (MSG_MULTICAST, puff_org_z);
		multicast (puff_org, MULTICAST_PVS);
	}
	
	if (blood_count) {
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_BLOOD);
		WriteByte (MSG_MULTICAST, big ? blood_count * 2 : puff_count);
		WriteCoord (MSG_MULTICAST, blood_org_x);
		WriteCoord (MSG_MULTICAST, blood_org_y);
		WriteCoord (MSG_MULTICAST, blood_org_z);
		multicast (puff_org, MULTICAST_PVS);
	}
};

/*
==============================================================================

BULLETS

==============================================================================
*/

/*
================
TraceAttack
================
*/
void (float damage, vector dir) TraceAttack =
{
	local vector vel, org;
	
	vel = normalize (dir + v_up * crandom() + v_right * crandom());
	vel = vel + 2 * trace_plane_normal;
	vel = vel * 200;

	org = trace_endpos - v_forward * 4;

	//WK Sweep mines at the end of the attack
	GuerillaMineSweep (trace_endpos);

	if (damage && trace_ent.takedamage) {
		blood_org = org;
		blood_count++;

		AddMultiDamage (trace_ent, damage);
	} else {
		puff_org = org;
		puff_count++;
	if (trace_ent.classname == "force_field") { //- OfN - Makes field explosion b4 removing it
		FieldExplosion(trace_ent,trace_endpos,trace_ent);
		PutFieldWork(trace_ent);
		}
	}
};

/*
================
FireBullets

Used by shotgun, super shotgun, assault cannon, and enemy soldier firing
Go to the trouble of combining multiple pellets into a single damage call.
================
*/
void(float shotcount, vector dir, vector spread) FireBullets =
{
	local vector direction;
	local vector src;
	local string st = infokey (NIL, "numpuffs");
	local float numpuffs = 0;
	local integer puffdiv;

	if (st)
		numpuffs = stof (st) - 1;

	if (numpuffs <= 0)
		puffdiv = 0;
	else
		puffdiv = (shotcount / numpuffs) + 1;

	makevectors (self.v_angle);

	src = self.origin + v_forward * 10;
	src_z = self.absmin_z + self.size_z * 0.7;

	ClearMultiDamage ();
	while (shotcount > 0) {
		
		direction = dir + crandom() * spread_x * v_right + crandom() * spread_y * v_up;

		traceline (src, src + direction * 4096, FALSE, self);
										
		if (trace_fraction == 1.0)
			TraceAttack (0, direction);
		else
			TraceAttack (6, direction); //WK 4

		if (puffdiv) {
			if (shotcount % puffdiv == 0)
				Multi_Finish (TRUE);
		}

		shotcount--;
  	}
	ApplyMultiDamage ();
	Multi_Finish (TRUE);
};

/*
================
W_FireShotgun
================
*/
void() W_FireShotgun =
{
	local vector dir;

	sound (self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);	

	if (self.classname == "player")
		KickPlayer(-2, self);
				 
	self.currentammo = self.ammo_shells = self.ammo_shells - 1;
	if (self.classname == "player")
		dir = aim (self, 100000);
	else {
		dir = self.enemy.origin - self.enemy.velocity * (0.08 / self.has_sensor);
		dir = normalize (dir - self.origin);
	}

	deathmsg = DMSG_SHOTGUN;
	FireBullets (6, dir, '0.03 0.03 0');
};


/*
================
W_FireSuperShotgun
================
*/
void() W_FireSuperShotgun =
{
	local vector dir;

	if (self.currentammo == 1) {
		W_FireShotgun ();
		return;
	}
		
	sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);	

	if (self.classname == "player")
		KickPlayer(-4, self);

	self.currentammo = self.ammo_shells = self.ammo_shells - 2;
	if (self.classname == "player")
		dir = aim (self, 100000);
	else {
		dir = self.enemy.origin - self.enemy.velocity * (0.08 / self.has_sensor);
		dir = normalize (dir - self.origin);
	}
	deathmsg = DMSG_SSHOTGUN;
	FireBullets (6, dir, '0.11 0.06 0'); //WK 14, 0.14, 0.08
	FireBullets (6, dir, '0.11 0.06 0');
};

/*
================
FireSniperBullet
Used by sniper rifle firing (W_FireSniperRifle)
================
*/
void(vector direction, float damage) FireSniperBullet =
{
	local	vector	src;

	makevectors (self.v_angle);

	src = self.origin + v_forward * 10;
	src_z = self.absmin_z + self.size_z * 0.7;

	ClearMultiDamage ();

	traceline (src, src + direction * 4096, FALSE, self);

	if (trace_fraction == 1.0)
		TraceAttack (0, direction);
	else
   		TraceAttack (damage, direction);

	ApplyMultiDamage ();
	Multi_Finish (FALSE);
};

/*
=================================
TeamFortress : W_FireSniperRifle
=================================
*/
void() W_FireSniperRifle =
{
	local vector dir, src;
	local float dam_mult, zdif, use_this, ign_mult = 0;
	local vector angle;

	sound (self ,CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM);
	KickPlayer(-2, self);

	angle = self.v_angle;

	if (self.heat < vlen(self.velocity) * 0.1)
	    self.heat = vlen(self.velocity) * 0.1;
	
	if (!(self.flags & FL_ONGROUND) && self.heat < 100) 
	    self.heat = 100;

	if (self.heat > 0) {
	    angle_x += (random() * 0.08 * self.heat) - (0.04 * self.heat);
	    angle_y += (random() * 0.08 * self.heat) - (0.04 * self.heat);
	}

	makevectors(angle);
	src = self.origin + v_forward * 10;
	src_z = self.absmin_z + self.size_z * 0.7;

	dir = v_forward; //XXX is this correct?

	use_this = FALSE;
	traceline (src, src + dir*8092, FALSE, self);
	if (trace_fraction != 1.0) {
		if (trace_ent) {
			if (trace_ent.classname == "player") {
				use_this = TRUE;
			}
		}
	}

	KickPlayer(-4, self);

	if (!use_this) {
		// aim, 'cause no entity in sights
		dir = aim (self, 10000);	// this corrects the aiming slightly, for bad players
	    traceline (src, src + dir*3072, FALSE, self);
	}

	deathmsg = DMSG_SNIPERRIFLE;

	dam_mult = 0;

	local string st = infokey (NIL, "sniper_dmg");
	if (st)
	   dam_mult = stof (st);
	if (!dam_mult)
	   dam_mult = SNIPER_DMG;	

#if 0	// otr out
	if (self.cutf_items & CUTF_OTR)
	{
		ign_mult=dam_mult*OTR_IGNFACTOR;
		dam_mult=dam_mult*OTR_DMGFACTOR;
	}
#endif

	self.ammo_shells -= 5;
	W_SetCurrentAmmo();
	

	if (trace_ent) {
		if (trace_ent.classname == "player") {
			local float x;
			local vector f, g, h;

			f = trace_endpos - src;

			g_x = trace_endpos_x;
			g_y = trace_endpos_y;
			g_z = 0;

			h_x = trace_ent.origin_x;
			h_y = trace_ent.origin_y;
			h_z = 0;

			x = vlen(g - h);

			f = (normalize(f) * x) + trace_endpos;

			zdif = f_z - trace_ent.origin_z;
  			deathmsg = DMSG_SNIPERRIFLE;

			trace_ent.head_shot_vector = '0 0 0';
			if (zdif < 0) {
				// leg shot doesn't hurt very much
				dam_mult *= 0.40;

				if (dam_mult > SNIPER_MAXLEG)
				{
					dam_mult = SNIPER_MAXLEG;
				}

				if (trace_ent.armorvalue < 0.8)
					trace_ent.leg_damage++;

				if (trace_ent.leg_damage > 5)
					trace_ent.leg_damage = 5;

#if 0	// OTR out
                //- OfN - OTR bullets do twice damage ----------//
				if (self.cutf_items & CUTF_OTR) {
					trace_ent.leg_damage++;
				}
#endif
                
				TeamFortress_SetSpeed(trace_ent); 
				deathmsg = DMSG_SNIPERLEGSHOT;
				//WK Kevlar ignored for snipers again.
				//GR red armor has leg protection

				if (trace_ent.armortype >= 0.7 && trace_ent.armorvalue > 0) {
				    TF_T_Damage (trace_ent, self, self, dam_mult, 0, TF_TD_SHOT);
				} else {
				    TF_T_Damage (trace_ent, self, self, dam_mult, TF_TD_IGNOREARMOUR,0);
				} 

				if (trace_ent.health > 0) {
#if 0 // OTR out
					if (self.cutf_items & CUTF_OTR) {
						sprint(trace_ent, PRINT_MEDIUM, "Leg injury! That was OTR stuff!\n");
						sprint(self, PRINT_MEDIUM, "OTR Leg shot - that'll slow him down!\n");
					} else 
#endif
					{ //- not OTR..
						sprint(trace_ent, PRINT_MEDIUM, "Leg injury!\n");
						sprint(self, PRINT_MEDIUM, "Leg shot - that'll slow him down!\n");
					}
				}

				return;
			} else if (zdif > 20) {
				// head shot
				dam_mult *= 2;

				stuffcmd(trace_ent, "bf\n");

				trace_ent.head_shot_vector = trace_ent.origin - self.origin;
				deathmsg = DMSG_SNIPERHEADSHOT;
				if (trace_ent.armortype > 0.5 && trace_ent.armorvalue > 0)
				{
				    TF_T_Damage (trace_ent, self, self, dam_mult, 0, TF_TD_SHOT);
				} else {
				    TF_T_Damage (trace_ent, self, self, dam_mult, TF_TD_IGNOREARMOUR, 0);
				}

				if (trace_ent.health > 0) {
#if 0 // otr out
					if (self.cutf_items & CUTF_OTR) {
						sprint(trace_ent, PRINT_MEDIUM, "Head injury! That was OTR stuff!\n");
						sprint(self, PRINT_MEDIUM, "OTR Head shot - that's gotta hurt!\n");
					} else 
#endif
					{
						sprint(trace_ent, PRINT_MEDIUM, "Head injury!\n");
						sprint(self, PRINT_MEDIUM, "Head shot - that's gotta hurt!\n");
					}
				}

				return;
			}
		}
	}

	ClearMultiDamage ();

	if (trace_fraction == 1.0)
		TraceAttack (0, dir);
	else // if it hit something
   		TraceAttack (SNIPER_DMG * dam_mult, dir);

	ApplyMultiDamage ();
	Multi_Finish (FALSE);
};

#ifndef NO_AUTORIFLE
/*
===================================
TeamFortress : W_FireAutoRifle
===================================
*/
// same as sniper rifle
void() W_FireAutoRifle =
{
	local vector dir;

	sound (self ,CHAN_WEAPON, "weapons/sniper.wav", 1, ATTN_NORM);

	KickPlayer(-1, self);

	self.currentammo = self.ammo_shells = self.ammo_shells - 1;

	makevectors(self.v_angle);
	dir = v_forward;
	deathmsg = DMSG_AUTORIFLE;
	FireSniperBullet (dir, 8);
};

#endif

/*
================
TeamFortress : W_FireAssaultCannon
================
*/
void(float num) W_FireAssaultCannon =
{
	local vector dir;

	KickPlayer(-4, self);

	self.currentammo = self.ammo_shells = self.ammo_shells - 1;
	dir = aim (self, 100000);
	deathmsg = DMSG_ASSAULTCANNON;
	FireBullets (num, dir, '0.013 0.013 0' * num);

	if (!(self.flags & FL_ONGROUND)) {
		if (!self.waterlevel || (self.tf_items & NIT_SCUBA))
			self.velocity -= 5 * num * dir;
		else
			self.velocity -= 10 * num * dir;
	}
};

/*
=========================================
Custom TeamFortress : W_FireLightAssault
=========================================
*/
void() W_FireLightAssault =
{
	local vector dir;

	if (self.ammo_nails < 1) {
		self.current_weapon = W_BestWeapon ();
		W_SetCurrentAmmo ();
		W_PrintWeaponMessage();
		return;
	}

	sound (self, CHAN_WEAPON, "weapons/guncock.wav", 0.6, ATTN_NORM);	

	KickPlayer(-4, self);

	makevectors(self.v_angle);

	dir = v_forward;
	deathmsg = DMSG_LIGHT_ASSAULT;
	self.currentammo = self.ammo_nails = self.ammo_nails - 1;
	self.reload_light_assault = self.reload_light_assault + 1;

	if (CheckForReload() == TRUE)
		return;
	FireBullets (5, dir, '0.1 0.1 0');
	Attack_Finished(0.2);
};

/*
==============================================================================

ROCKETS

==============================================================================
*/

void()	s_explode1	=	[0,		s_explode2] {};
void()	s_explode2	=	[1,		s_explode3] {};
void()	s_explode3	=	[2,		s_explode4] {};
void()	s_explode4	=	[3,		s_explode5] {};
void()	s_explode5	=	[4,		s_explode6] {};
void()	s_explode6	=	[5,		SUB_Remove] {};

void() BecomeExplosion =
{
	dremove(self);
};

void() T_MissileTouch =
{
	local float	damg;
	local float	bonus;

	if (other.classname == "player" && other.playerclass == PC_UNDEFINED)
		return;

	if (pointcontents(self.origin) == CONTENTS_SKY) {
		dremove(self);
		return;
	}

	// Lowered from 120
	damg = 100;
	
    if (self.owner.classname == "trap_shooter" || self.owner.classname == "trap_spikeshooter" || self.owner.classname == "trap_tf_spikeshooter" || self.owner.classname == "trap_tf_shooter")
		if (self.owner.dmg != 0)
			damg = self.owner.dmg;

	if (self.has_tesla) //Cluster rockets do less
		damg = damg - 25;

	deathmsg = self.weapon;
	if (other.health) {
		bonus = 10 + random()*20;
		if (self.has_tesla)
			bonus = 0;
		TF_T_Damage (other, self, self.owner, damg+bonus, 0, TF_TD_EXPLOSION);
	}

	// don't do radius damage to the other, because all the damage
	// was done in the impact
	// Lowered from 120
	T_RadiusDamage (self, self.owner, damg, other);

	self.origin = self.origin - 8*normalize(self.velocity);

#ifdef DEMO_STUFF
	// Remove any camera's locks on this missile
	if (self.enemy)
		CamProjectileLockOff();
#endif

	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_EXPLOSION);
	WriteCoord (MSG_MULTICAST, self.origin_x);
	WriteCoord (MSG_MULTICAST, self.origin_y);
	WriteCoord (MSG_MULTICAST, self.origin_z);
	multicast (self.origin, MULTICAST_PHS);

	if (other.classname == "force_field") //- OfN - Makes field explosion b4 removing it
		FieldExplosion(other,self.origin,self);

	dremove(self);
};

//CH rocket tracker (taken from shalrath.qc)
void() Rocket_Track_Dot =
{
	if (time > self.has_sentry) {
		self.think = SUB_Remove;
	} else {
		local vector	dir, vtemp;
		local entity tg, sight;

		sight = NIL;
		tg = find (NIL, classname, "timer");
		while (tg) {
			if (tg.owner == self.owner && tg.think == SniperSight_Update2)
				sight = tg;
			tg = find(tg, classname, "timer");
		}
		if (sight) { //Found a sight
			vtemp = sight.origin;
			dir = normalize(vtemp - self.origin);
//			if (self.owner.cluster_mode && !(self.has_tesla)) //Slow down main rocket
//				self.velocity = dir * 500;
//			else
			if (self.owner.cluster_mode)
				self.velocity = dir * 600;
			else
				self.velocity = dir * 900;
			self.angles = vectoangles(self.velocity);
			self.think = Rocket_Track_Dot;
			//WK Add in cluster munitions support
			if (self.has_tesla) { //We're a cluster, so act crazy	
				makevectors(self.angles);
				self.v_angle = sight.origin; //Save last direction for losing sight
				self.velocity = self.velocity + 300 * v_right * (random() - 0.5);
				self.velocity = self.velocity + 300 * v_up * (random() - 0.5);
			}
		} else { //Lost sight of sight
			if (self.has_tesla && self.v_angle != '0 0 0') {
				vtemp = self.v_angle;
				dir = normalize(vtemp - self.origin);
				if (self.owner.cluster_mode && !(self.has_tesla)) //Slow down main rocket
					self.velocity = dir * 900;
				else
					self.velocity = dir * 1000;
				self.angles = vectoangles(self.velocity);
				self.think = Rocket_Track_Dot;
				makevectors(self.angles);
				self.velocity = self.velocity + 300 * v_right * (random() - 0.5);
				self.velocity = self.velocity + 300 * v_up * (random() - 0.5);
			}
			//	self.velocity = 1000 * normalize(self.v_angle);
		}
	}

	self.nextthink = time + 0.25;
};
/*
================
W_FireRocket
================
*/
void() W_FireRocket =
{
	local float loops;
	local vector olorigin, dir = NIL;	//XXX false +ve for dir
	loops = 0;
	if (self.tf_items & NIT_CLUSTER_ROCKETS && self.cluster_mode == TRUE)
		loops = 5;
	while (loops >= 0) {
	self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
	if (self.ammo_rockets < 0) {
		self.currentammo = self.ammo_rockets = 0;
		return;
	}
	if (loops == 0) {
		sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);
		if (self.classname == "player")
			KickPlayer(-2, self);
	}
	newmis = spawn ();
	newmis.owner = self;
	newmis.movetype = MOVETYPE_FLYMISSILE;
	newmis.solid = SOLID_BBOX;
    
    newmis.classname = "rocket"; //- OfN - Checked on airfist

	// set newmis speed	
	if (self.classname == "player") {
		makevectors (self.v_angle);
		dir = v_forward;
	} else if (self.classname == "monster_army")
		dir = Grunty_LeadShot();

	newmis.velocity = dir;	
	if (!loops) { //WK Not a cluster Rocket
		if (self.tf_items & NIT_CLUSTER_ROCKETS && self.cluster_mode == TRUE)
		{ //Make lead rocket start slower too
			if (self.tf_items & NIT_RL_LASER_SIGHT) //Cluster and sight to start
				newmis.velocity = newmis.velocity * 400;
			else
				newmis.velocity = newmis.velocity * 600; //Cluster and no sight
		} else
			newmis.velocity = newmis.velocity * 900;
	} else if (self.tf_items & NIT_RL_LASER_SIGHT) //Cluster and sight to start
		newmis.velocity = newmis.velocity * 400;
	else
		newmis.velocity = newmis.velocity * 600; //Cluster and no sight
	newmis.angles = vectoangles(newmis.velocity);

	newmis.touch = T_MissileTouch;

	// set newmis duration
	if (self.tf_items & NIT_RL_LASER_SIGHT) {
		newmis.nextthink = time + 0.1; //Because tracks a sight
		if (loops)
			newmis.nextthink = time + 0.5; //Delay one second to spread out
		newmis.think = Rocket_Track_Dot;
		newmis.has_sentry = time + 6;
	} else {
		newmis.nextthink = time + 4;
		newmis.think = SUB_Remove;
	}

	newmis.weapon = DMSG_ROCKETL;
	if (!loops)
		setmodel (newmis, "progs/missile.mdl");
	else
		setmodel (newmis, "progs/minimissile.mdl"); //Diff model for swarm rockets
	setsize (newmis, '0 0 0', '0 0 0');		
	setorigin (newmis, self.origin + dir*8 + '0 0 16');
	if (loops) { //WK Vary the starting point of the cluster
		traceline (self.origin, self.origin + v_forward*9192, FALSE, self); //Make this TRUE
		newmis.v_angle = trace_endpos;
		newmis.has_tesla = loops; //Tell the rocket it is a cluster
       	newmis.weapon = DMSG_CLUSTER_ROCKET;
		olorigin = newmis.origin;
		newmis.origin = newmis.origin + v_right * (random() * 120 - 60);
		newmis.origin = newmis.origin + v_forward * (random() * 40);
		newmis.origin = newmis.origin + v_up * (random() * 50 - 20);
		olorigin = olorigin - newmis.origin; //Get vector to new point
		olorigin = 200 * normalize(olorigin);
		if (self.tf_items & NIT_RL_LASER_SIGHT) //Dont spread without sight
			newmis.velocity = newmis.velocity + olorigin;			
	}
	loops = loops - 1;
	} //End while loops
#ifdef DEMO_STUFF
	// Have we got a live camera in projectile mode?
	if (live_camera)
		CamProjectileLockOn();
#endif
};

/*
===============================================================================

LIGHTNING

===============================================================================
*/

void(entity from, float damage) LightningHit =
{
	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_LIGHTNINGBLOOD);
	WriteCoord (MSG_MULTICAST, trace_endpos_x);
	WriteCoord (MSG_MULTICAST, trace_endpos_y);
	WriteCoord (MSG_MULTICAST, trace_endpos_z);
	multicast (trace_endpos, MULTICAST_PVS);

	TF_T_Damage (trace_ent, from, from, damage, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
};

/*
=================
LightningDamage
=================
*/
void(vector p1, vector p2, entity from, float damage) LightningDamage =
{
	local entity		e1, e2;
	local vector		f;
	
	f = p2 - p1;
	normalize (f);
	f_x = 0 - f_y;
	f_y = f_x;
	f_z = 0;
	f = f*16;

	e1 = e2 = NIL;

	traceline (p1, p2, FALSE, self);

	//WK Sweep mines at point of impact
	GuerillaMineSweep(trace_endpos);

	deathmsg = DMSG_LIGHTNING;
	if (trace_ent.takedamage)
		LightningHit (from, damage);
	e1 = trace_ent;

	traceline (p1 + f, p2 + f, FALSE, self);
	if (trace_ent != e1 && trace_ent.takedamage)
		LightningHit (from, damage);
	e2 = trace_ent;

	traceline (p1 - f, p2 - f, FALSE, self);
	if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
		LightningHit (from, damage);
};


void() W_FireLightning =
{
	local	vector	org;
	local	float	cells, damage;

	if (self.ammo_cells < 1) {
		self.current_weapon = W_BestWeapon ();
		W_SetCurrentAmmo ();
		W_PrintWeaponMessage();
		return;
	}

	makevectors (self.v_angle);

// explode if under water
	if (self.waterlevel > 1) {
		cells = self.ammo_cells;
		if (cells > 10)
			cells = 10; //WK Don't allow detpacks on the fly!
		self.ammo_cells = self.ammo_cells - cells;
		W_SetCurrentAmmo ();
		deathmsg = DMSG_LIGHTNING;
//WK	T_RadiusDamage (self, self, 35*cells, NIL);
		T_RadiusDamage (self, self, 20*cells, NIL);
		Attack_Finished(5);
		return;
	}

	if (self.t_width < time) {
		sound (self, CHAN_WEAPON, "weapons/lhit.wav", 1, ATTN_NORM);
		self.t_width = time + 0.6;
	}

	KickPlayer(-2, self);

	if (self.ammo_cells > 300) {
		damage = 25;
		self.ammo_cells -= 15;
	} else if (self.ammo_cells > 200) {
		damage = 20;
		self.ammo_cells -= 10;
	} else if (self.ammo_cells > 100) {
		damage = 17;
		self.ammo_cells -= 4;
	} else {
		damage = 12;
		self.ammo_cells -= 1.2;
	}

	self.currentammo = self.ammo_cells;

	org = self.origin + '0 0 16';

	// OfN - Check for force field
	traceline (org, org + v_forward*600, FALSE, self);

	if (trace_ent.classname == "force_field") {
		FieldExplosion(trace_ent,trace_endpos,trace_ent);
		PutFieldWork(trace_ent);

		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_LIGHTNING2);
		WriteEntity (MSG_MULTICAST, self);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		WriteCoord (MSG_MULTICAST, trace_endpos_x);
		WriteCoord (MSG_MULTICAST, trace_endpos_y);
		WriteCoord (MSG_MULTICAST, trace_endpos_z);
		multicast (org, MULTICAST_PHS);

		return;
	}
	//_------------------------------------_//

	traceline (org, org + v_forward*600, TRUE, self);

	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_LIGHTNING2);
	WriteEntity (MSG_MULTICAST, self);
	WriteCoord (MSG_MULTICAST, org_x);
	WriteCoord (MSG_MULTICAST, org_y);
	WriteCoord (MSG_MULTICAST, org_z);
	WriteCoord (MSG_MULTICAST, trace_endpos_x);
	WriteCoord (MSG_MULTICAST, trace_endpos_y);
	WriteCoord (MSG_MULTICAST, trace_endpos_z);
	multicast (org, MULTICAST_PHS);

	LightningDamage (self.origin, trace_endpos + v_forward*4, self, damage);
};

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

float (float tno) num_team_pipebombs =
{
	if (tno == 1)
		return num_team_pipebombs_1;
	if (tno == 2)
		return num_team_pipebombs_2;
	if (tno == 3)
		return num_team_pipebombs_3;
	if (tno == 4)
		return num_team_pipebombs_4;

	return 0;
};

void(float tno) ExplodeOldPipebomb =
{
	local entity old;
	local float index;

	if (tno != 0) {
		index = num_team_pipebombs(tno);
		index = index - (MAX_WORLD_PIPEBOMBS / number_of_teams);
	} else {
		index = num_world_pipebombs - MAX_WORLD_PIPEBOMBS;
	}

	old = find(NIL, classname, "pipebomb");
	while (index > 0) {
		if (!old) {
			RPrint("*** ERROR: ExplodeOldPipebomb. ***\n");
			RPrint("*** Please report this.        ***\n");
			num_world_pipebombs = 0;
			num_team_pipebombs_1 = 0;
			num_team_pipebombs_2 = 0;
			num_team_pipebombs_3 = 0;
			num_team_pipebombs_4 = 0;
			return;
		}

		if (old.owner.team_no == tno || tno == 0) {
			old.nextthink = time + 0.5;
			index = index - 1;
		}

		old = find(old, classname, "pipebomb");
	}
};

void(float tno) increment_team_pipebombs =
{
	if (tno == 1)
		num_team_pipebombs_1 = num_team_pipebombs_1 + 1;
	else if (tno == 2)
		num_team_pipebombs_2 = num_team_pipebombs_2 + 1;
	else if (tno == 3)
		num_team_pipebombs_3 = num_team_pipebombs_3 + 1;
	else if (tno == 4)
		num_team_pipebombs_4 = num_team_pipebombs_4 + 1;
};

void(float tno) decrement_team_pipebombs =
{
	if (tno == 1)
		num_team_pipebombs_1 = num_team_pipebombs_1 - 1;
	else if (tno == 2)
		num_team_pipebombs_2 = num_team_pipebombs_2 - 1;
	else if (tno == 3)
		num_team_pipebombs_3 = num_team_pipebombs_3 - 1;
	else if (tno == 4)
		num_team_pipebombs_4 = num_team_pipebombs_4 - 1;
};

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


void() GrenadeExplode =
{
	if (self.classname == "pipebomb") {
		num_world_pipebombs = num_world_pipebombs - 1;
		decrement_team_pipebombs(self.owner.team_no);
	}

	deathmsg = self.weapon;
	T_RadiusDamage (self, self.owner, 120, NIL);

#ifdef DEMO_STUFF
	// Remove any camera's locks on this missile
	if (self.enemy)
		CamProjectileLockOff();
#endif

	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_EXPLOSION);
	WriteCoord (MSG_MULTICAST, self.origin_x);
	WriteCoord (MSG_MULTICAST, self.origin_y);
	WriteCoord (MSG_MULTICAST, self.origin_z);
	multicast (self.origin, MULTICAST_PHS);
	dremove(self);
};

void() GrenadeTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner
	if (other.takedamage == DAMAGE_AIM) {
		GrenadeExplode();
		return;
	}
	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

/*
================
W_FireGrenade
================
*/
void() W_FireGrenade =
{
	self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
	sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
	KickPlayer(-2, self);
	newmis = spawn ();
	newmis.owner = self;
	newmis.movetype = MOVETYPE_BOUNCE;
	newmis.solid = SOLID_BBOX;

	// Set grenade type based on firing mode
	if (self.weaponmode == GL_NORMAL) {
		newmis.weapon = DMSG_GRENADEL;
		newmis.classname = "grenade";
		newmis.skin = 1;
		newmis.touch = GrenadeTouch;
		newmis.nextthink = time + 2.5;
	} else {		// if (self.weaponmode == GL_PIPEBOMB)
		if (self.team_no != 0) {
			increment_team_pipebombs(self.team_no);
			if (num_team_pipebombs(self.team_no) > (MAX_WORLD_PIPEBOMBS / number_of_teams))
				ExplodeOldPipebomb(self.team_no);
		} else {
			num_world_pipebombs = num_world_pipebombs + 1;
			if (num_world_pipebombs > MAX_WORLD_PIPEBOMBS)
				ExplodeOldPipebomb(0);
		}

		newmis.classname = "pipebomb";
		newmis.skin = 2;
		newmis.touch = PipebombTouch;
		newmis.nextthink = time + 120;		// Remove pipebombs older than 2 minutes
		newmis.weapon = DMSG_GREN_PIPE;
	}
		
	// set newmis speed	
	makevectors (self.v_angle);
	if (self.v_angle_x)
		newmis.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
	else {
		newmis.velocity = aim(self, 10000);
		newmis.velocity = newmis.velocity * 600;
		newmis.velocity_z = 200;
	}
	newmis.avelocity = '300 300 300';
	newmis.angles = vectoangles(newmis.velocity);

	newmis.think = GrenadeExplode;
	setmodel (newmis, "progs/grenade2.mdl");
	setsize (newmis, '0 0 0', '0 0 0');		
	setorigin (newmis, self.origin);

#ifdef DEMO_STUFF
	// Have we got a live camera in projectile mode?
	if (live_camera)
		CamProjectileLockOn();
#endif
};

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

void() spike_touch;


/*
===============
launch_spike

Used for both the player and the ogre
===============
*/
void(vector org, vector dir) launch_spike =
{
	newmis = spawn ();
	newmis.owner = self;
	newmis.movetype = MOVETYPE_FLYMISSILE;
	newmis.solid = SOLID_BBOX;

	newmis.angles = vectoangles(dir);

	newmis.touch = spike_touch;
	newmis.weapon = DMSG_NAILGUN;
	newmis.classname = "spike";
	newmis.think = SUB_Remove;
	newmis.nextthink = time + 6;
	setmodel (newmis, "progs/spike.mdl");
	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);		
	setorigin (newmis, org);

	newmis.velocity = dir * 1600; // was 1000

#ifdef DEMO_STUFF
	// Have we got a live camera in projectile mode?
	if (live_camera)
		CamProjectileLockOn();
#endif
};

void() superspike_touch =
{
	local float ndmg;

	if (other == self.owner)
		return;

	if (other.solid == SOLID_TRIGGER)
		return;	// trigger field, do nothing

	if (pointcontents(self.origin) == CONTENTS_SKY)
	{
		dremove(self);
		return;
	}
	
// hit something that bleeds
	if (other.takedamage) {
		spawn_touchblood (18);
		deathmsg = self.weapon;

/*
		// In QW, nail grens only launch 1 nail, and it does more damage.
		if (deathmsg == DMSG_GREN_NAIL)
			ndmg = 40;
		else
*/

		ndmg = 13;

		if (self.owner.classname == "grenade")
			TF_T_Damage (other, self, self.owner.owner, ndmg, TF_TD_NOTTEAM, TF_TD_NAIL);
		else
			TF_T_Damage (other, self, self.owner, ndmg, TF_TD_NOTTEAM, TF_TD_NAIL);
	} else {
		if (other.classname == "force_field") //- OfN - Makes field explosion b4 removing it
			FieldExplosion(other,self.origin,self);
		else {
			WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
			WriteByte (MSG_MULTICAST, TE_SUPERSPIKE);
			WriteCoord (MSG_MULTICAST, self.origin_x);
			WriteCoord (MSG_MULTICAST, self.origin_y);
			WriteCoord (MSG_MULTICAST, self.origin_z);
			multicast (self.origin, MULTICAST_PHS);
		}
	}

	dremove(self);
};


void() W_FireSuperSpikes =
{
	local vector	dir;

	sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
	Attack_Finished(0.2);
	self.currentammo = self.ammo_nails = self.ammo_nails - 2;
	dir = aim (self, 1000);
	launch_spike (self.origin + '0 0 16', dir);
	newmis.touch = superspike_touch;
	newmis.weapon = DMSG_SNG;
	setmodel (newmis, "progs/s_spike.mdl");
	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);		

	KickPlayer(-2, self);
};


void(float ox) W_FireSpikes =
{
	if (self.ammo_nails >= 2 && self.current_weapon == WEAP_SNG) {
		W_FireSuperSpikes ();
		return;
	}
    
    local vector	dir;

	if (self.classname == "player")
		makevectors (self.v_angle);
	else
		makevectors (self.angles);
	
	if (self.ammo_nails < 1)
		if (self.classname == "player") {
			self.current_weapon = W_BestWeapon ();
			W_SetCurrentAmmo ();
			W_PrintWeaponMessage();
			return;
		}

	sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
	Attack_Finished(0.2);
	self.currentammo = self.ammo_nails = self.ammo_nails - 1;
	if (self.classname == "player") {
        dir = aim (self, 1000);
        launch_spike (self.origin + '0 0 16' + v_right*ox, dir);
        KickPlayer(-2, self);
    } else if (self.classname == "monster_army") {		//- OfN -
        dir = Grunty_LeadShot();
        grunty_spike(self.origin + '0 0 16' + v_right*ox, dir);
	}		
};

//.float hit_z;
void() spike_touch =
{
	if (other.solid == SOLID_TRIGGER)
		return;	// trigger field, do nothing

	if (pointcontents(self.origin) == CONTENTS_SKY) {
		dremove(self);
		return;
	}
	
	//WK Sweep mines at point of impact
	GuerillaMineSweep(self.origin);

	// hit something that bleeds
	if (other.takedamage) {
		spawn_touchblood (9);
		deathmsg = self.weapon;

        //- OfN - Wizard projectiles do SCRAG_DMG damage
        if (self.classname == "wizspike") {
           local float wizdmg;
           wizdmg = SCRAG_DMG;
    
           if (other.classname == "player") {
              if (other.cutf_items & CUTF_DEMONLORE) // if we have demon lore, it does less damage to us
                 wizdmg = wizdmg * 0.8;
           }

           TF_T_Damage (other, self, self.owner, wizdmg, TF_TD_NOTTEAM, 0);
           sound (self, CHAN_MISC, "effects/crunch.wav", 0.4, ATTN_NORM); // any better sound?
        } else if (self.owner.classname == "grenade")		// - OfN -
			TF_T_Damage (other, self, self.owner.owner, 12, TF_TD_NOTTEAM, TF_TD_NAIL);
		else
			TF_T_Damage (other, self, self.owner, 12, TF_TD_NOTTEAM, TF_TD_NAIL);
	} else {
        if (other.classname == "force_field") //- OfN - Makes field explosion b4 removing it
			FieldExplosion(other,self.origin,self);
		else {
			WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
			if (self.classname == "wizspike")
				WriteByte (MSG_MULTICAST, TE_WIZSPIKE);
			else if (self.classname == "knightspike")
				WriteByte (MSG_MULTICAST, TE_KNIGHTSPIKE);
			else
				WriteByte (MSG_MULTICAST, TE_SPIKE);
			WriteCoord (MSG_MULTICAST, self.origin_x);
			WriteCoord (MSG_MULTICAST, self.origin_y);
			WriteCoord (MSG_MULTICAST, self.origin_z);
			multicast (self.origin, MULTICAST_PHS);
		}
	}

#ifdef DEMO_STUFF
	// Remove any camera's locks on this missile
	if (self.enemy)
		CamProjectileLockOff();
#endif

	dremove(self);
};

/*
===============================================================================

PLAYER WEAPON USE

===============================================================================
*/

void() W_SetCurrentAmmo =
{
	if (self.health <= 0 || self.current_weapon == 0)
		return;		// get out of any weapon firing states

	player_run();

	self.items = self.items & ~(IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS);
	self.weapon = 0;

	//WK Set armor here... update armor picture
	self.items = self.items & ~(IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3);
	if (self.armortype >= 0.8)
		self.items = self.items | IT_ARMOR3;
	else if (self.armortype >= 0.6)
		self.items = self.items | IT_ARMOR2;
	else if (self.armortype >= 0.3)
		self.items = self.items | IT_ARMOR1;

	//WK Show nothing for custom playerclass while building
	if ( self.playerclass == PC_CUSTOM
		 && (self.done_custom & CUSTOM_BUILDING)) {
		//We are building a class
		self.currentammo = 0;
		self.weaponmodel = "";
		return;
	}
	if (self.current_weapon == WEAP_AXE) {
		self.currentammo = 0;

		if (self.cutf_items & CUTF_KNIFE) {			//WK
			if (self.job & JOB_BLOODY_KNIFE)
				self.weaponmode = 1;
			else
				self.weaponmode = 0; //CH maybe fix bug that knife is bloody when not?
			if (self.weaponmode == 0)
				self.weaponmodel = "progs/v_knife.mdl"; //Nonbloody
			else
				self.weaponmodel = "progs/v_knife2.mdl"; //Bloody
		} else
			self.weaponmodel = "progs/v_axe.mdl";

		self.weaponframe = 0;
	} else if (self.current_weapon == WEAP_HOOK) {
		self.currentammo = 0;
		self.weaponmodel = "progs/v_grap.mdl";
		self.weaponframe = 0;
	} else if (self.current_weapon == WEAP_SPANNER) {
		self.currentammo = self.ammo_cells;
		self.weaponmodel = "progs/v_span.mdl";
		self.weaponframe = 0;
	} else if (self.current_weapon == WEAP_SHOTGUN) {
		self.currentammo = self.ammo_shells;
		self.items = self.items | IT_CELLS;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_shot.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_SHELLS;
		self.weapon = IT_SHOTGUN;
	} else if (self.current_weapon == WEAP_SUPER_SHOTGUN) {
		self.currentammo = self.ammo_shells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_shot2.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_SHELLS;
		self.weapon = IT_SUPER_SHOTGUN;
	} else if (self.current_weapon == WEAP_NAILGUN) {
		self.currentammo = self.ammo_nails;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_nail.mdl";
			self.weaponframe = 0;
		}

		self.items = self.items | IT_NAILS;
		self.weapon = IT_NAILGUN;
	} else if (self.current_weapon == WEAP_LIGHT_ASSAULT) {
		self.currentammo = self.ammo_nails;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_nail2.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_NAILS;
		self.weapon = IT_LIGHT_ASSAULT;
	} else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) {
		self.currentammo = self.ammo_rockets;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_rock.mdl";
			self.weaponframe = 0;
		}

		self.weapon = IT_GRENADE_LAUNCHER;
		self.items = self.items | IT_ROCKETS;
	} else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) {
		self.currentammo = self.ammo_rockets;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_rock2.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_ROCKETS;
		self.weapon = IT_ROCKET_LAUNCHER;
	} else if (self.current_weapon == WEAP_LIGHTNING) {
		self.currentammo = self.ammo_cells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_light.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_CELLS;
		self.weapon = IT_LIGHTNING;
	} else if (self.current_weapon == WEAP_SNIPER_RIFLE) {
	    	self.currentammo = self.ammo_shells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_srifle.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_SHELLS;
		self.weapon = IT_SHOTGUN;
#ifndef NO_AUTORIFLE
	} else if (self.current_weapon == WEAP_AUTO_RIFLE) {
  		self.currentammo = self.ammo_shells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
		    	self.weaponmodel = "progs/v_srifle.mdl";
		    	self.weaponframe = 0;
		}
		self.items = self.items | IT_SHELLS;
		self.weapon = IT_SUPER_SHOTGUN;
#endif
	} else if (self.current_weapon == WEAP_ASSAULT_CANNON) {
  		self.currentammo = self.ammo_shells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_asscan.mdl";
		    	self.weaponframe = 0;
		}
		self.items = self.items | IT_SHELLS;
		self.weapon = IT_ROCKET_LAUNCHER;
	} else if (self.current_weapon == WEAP_FLAMETHROWER) {
  		self.currentammo = self.ammo_cells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
	    	self.weaponmodel = "progs/v_rock.mdl";
	    	self.weaponframe = 0;
		}
		self.items = self.items | IT_CELLS;
		self.weapon = IT_GRENADE_LAUNCHER;
	} else if (self.current_weapon == WEAP_INCENDIARY) {
  		self.currentammo = self.ammo_rockets;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
	    	self.weaponmodel = "progs/v_rock2.mdl";
	    	self.weaponframe = 0;
		}
		self.items = self.items | IT_ROCKETS;
		self.weapon = IT_ROCKET_LAUNCHER;
	} else if (self.current_weapon == WEAP_MEDIKIT) {
		self.currentammo = 0;
		self.weaponmodel = "progs/v_medi.mdl";
		self.weaponframe = 0;
   	} else if (self.current_weapon == WEAP_TRANQ) {
		self.currentammo = self.ammo_nails;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_shot.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_NAILS;
		self.weapon = IT_SHOTGUN;
	} else if (self.current_weapon == WEAP_LASER) {
		self.currentammo = self.ammo_nails;

		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_rail.mdl";
			self.weaponframe = 0;
		}

		self.items = self.items | IT_NAILS;
		self.weapon = IT_SHOTGUN;
	} else if (self.current_weapon == WEAP_DAEDALUS) {
		self.currentammo = self.ammo_cells;

		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_rock.mdl";
			self.weaponframe = 0;
		}

		self.items = self.items | IT_CELLS;
		self.weapon = IT_LIGHTNING;
	} else if (self.current_weapon == WEAP_MAUSER) {
		self.currentammo = self.ammo_nails;

		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_rail.mdl";
			self.weaponframe = 0;
		}

		self.items = self.items | IT_NAILS;
		self.weapon = IT_LIGHT_ASSAULT;
	} else if (self.current_weapon == WEAP_AIRF) {
  		self.currentammo = 0;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_airgun.mdl";
	    		self.weaponframe = 0;
		}
	} else if (self.current_weapon == WEAP_SNG) {
		self.currentammo = self.ammo_nails;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_nail2.mdl";
			self.weaponframe = 0;
		}
		self.items = self.items | IT_NAILS;
		self.weapon = IT_LIGHT_ASSAULT;//IT_SUPER_NAILGUN;
	} else if (self.current_weapon == WEAP_LASERCANNON) {
    	self.currentammo = self.ammo_cells;
		if (!(self.tfstate & TFSTATE_RELOADING)) {
			self.weaponmodel = "progs/v_laserg.mdl";
	    		self.weaponframe = 0;
		}

   		self.items = self.items | IT_CELLS;
		self.weapon = WEAP_LASERCANNON;
	} else {
		self.currentammo = 0;
		self.weaponmodel = "";
		self.weaponframe = 0;
	}
};

float() W_BestWeapon =
{
	local	float	it;
	
	it = self.weapons_carried;

	if (self.ammo_cells >= 1 && (it & WEAP_LIGHTNING) && self.waterlevel <= 1)
		return WEAP_LIGHTNING;
	if(self.ammo_shells >= 1 && (it & WEAP_SNIPER_RIFLE) )
		return WEAP_SNIPER_RIFLE;
	if(self.ammo_rockets >= 1 && (it & WEAP_ROCKET_LAUNCHER) )
		return WEAP_ROCKET_LAUNCHER;
	if (self.ammo_cells >= 5 && (it & WEAP_DAEDALUS) )
		return WEAP_DAEDALUS;
	if (self.ammo_cells >= 6 && (self.ammo_shells >= 1) && (it & WEAP_ASSAULT_CANNON))
		return WEAP_ASSAULT_CANNON;
	if(self.ammo_nails >= 10 && (it & WEAP_LIGHT_ASSAULT) )
		return WEAP_LIGHT_ASSAULT;
	if(self.ammo_rockets >= 3 && (it & WEAP_INCENDIARY) )
		return WEAP_INCENDIARY;
	if(self.ammo_rockets >= 1 && (it & WEAP_GRENADE_LAUNCHER) )
		return WEAP_GRENADE_LAUNCHER;
    if (self.ammo_cells >= 1 && (it & WEAP_LASERCANNON))
		return WEAP_LASERCANNON;
   	if(self.ammo_nails >= 2 && (it & WEAP_SNG))
		return WEAP_SNG;
    if (self.ammo_cells >= 1 && (it & WEAP_FLAMETHROWER))
		return WEAP_FLAMETHROWER;
    if(self.ammo_shells >= 2 && (it & WEAP_SUPER_SHOTGUN) )
		return WEAP_SUPER_SHOTGUN;
	if (self.ammo_nails >= 1 && (it & WEAP_LASER) )
		return WEAP_LASER;
	if(self.ammo_nails >= 1 && (it & WEAP_NAILGUN) )
		return WEAP_NAILGUN;
	if(self.ammo_shells >= 1 && (it & WEAP_SHOTGUN) )
		return WEAP_SHOTGUN;
	if (self.ammo_nails >= 1 && (it & WEAP_MAUSER) )
		return WEAP_MAUSER;
	if (self.ammo_nails >= 1 && (it & WEAP_TRANQ) )
		return WEAP_TRANQ;

	if (it & WEAP_MEDIKIT)
		return WEAP_MEDIKIT;

	if (it & WEAP_AIRF)
		return WEAP_AIRF;

	if (it & WEAP_SPANNER)
		return WEAP_SPANNER;
	if (it & WEAP_AXE)
		return WEAP_AXE;

	return 0;
};

float() W_CheckNoAmmo =
{
	if (self.current_weapon == WEAP_MEDIKIT)
		return TRUE;
	if (self.current_weapon == WEAP_AIRF)
		return TRUE;
	if (self.current_weapon == WEAP_AXE || self.current_weapon == WEAP_HOOK || self.current_weapon == WEAP_SPANNER)
		return TRUE;
	if (self.current_weapon == WEAP_INCENDIARY) {
		if (self.currentammo >= 3)
			return TRUE;
	} else if (self.current_weapon == WEAP_DAEDALUS) {
		if (self.currentammo >= 5)
			return TRUE;
	} else if (self.current_weapon == WEAP_SNIPER_RIFLE) {
		if (self.currentammo >= 5)
			return TRUE;
	} else if (self.currentammo > 0)
		return TRUE;

	self.current_weapon = W_BestWeapon ();
	W_SetCurrentAmmo ();
	W_PrintWeaponMessage();
	
// drop the weapon down
	return FALSE;
};

/*====================
W_Reload
Is called when weapon has finished reloading
====================*/
void() W_Reload_shotgun =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_shot.mdl";
	sprint(self.owner, PRINT_LOW, "finished reloading\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

void() W_Reload_light_assault =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_nail2.mdl";
	sprint(self.owner, PRINT_LOW, "finished reloading\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

void() W_Reload_super_shotgun =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_shot2.mdl";
	sprint(self.owner, PRINT_LOW, "finished reloading\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

void() W_Reload_grenade_launcher =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_rock.mdl";
	sprint(self.owner, PRINT_LOW, "finished reloading\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

void() W_Reload_rocket_launcher =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_rock2.mdl";
	sprint(self.owner, PRINT_LOW, "finished reloading\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

void() W_Reload_laser_cannon =
{
	self.owner.tfstate = self.owner.tfstate - (self.owner.tfstate & TFSTATE_RELOADING);
	self.owner.weaponmodel = "progs/v_laserg.mdl";
	sprint(self.owner, PRINT_LOW, "Laser Cannon charged\n");
	self.owner.StatusRefreshTime = time + 0.1;

	dremove(self);
};

float() CheckForReload =
{
	local entity tWeapon;

	if (self.current_weapon == WEAP_SHOTGUN) {
        if (self.reload_shotgun >= RE_SHOTGUN && self.ammo_shells > 0) {
			self.reload_shotgun = 0;
			if (self.ammo_shells < RE_SHOTGUN)
				self.reload_shotgun = RE_SHOTGUN - self.ammo_shells;

			sprint (self, PRINT_HIGH, "reloading...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			tWeapon.nextthink = time + RE_SHOTGUN_TIME;
			tWeapon.think = W_Reload_shotgun;

			self.weaponmodel = "";
			self.weaponframe = 0;

			return TRUE;
        }
	} else if (self.current_weapon == WEAP_SUPER_SHOTGUN) {
		if (self.reload_super_shotgun > RE_SUPER_SHOTGUN)
			self.reload_super_shotgun = RE_SUPER_SHOTGUN;
        if ( self.reload_super_shotgun >= RE_SUPER_SHOTGUN
			 && self.ammo_shells > 0) {
			self.reload_super_shotgun = 0;
			if (self.ammo_shells < RE_SUPER_SHOTGUN)
				self.reload_super_shotgun =
					RE_SUPER_SHOTGUN - self.ammo_shells;

			sprint (self, PRINT_HIGH, "reloading...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			tWeapon.nextthink = time + RE_SUPER_SHOTGUN_TIME;
			tWeapon.think = W_Reload_super_shotgun;

         	self.weaponmodel = "";
         	self.weaponframe = 0;

			return TRUE;
	  	}
	} else if (self.current_weapon == WEAP_LIGHT_ASSAULT) {
        if ( self.reload_light_assault >= RE_LIGHT_ASSAULT
			 && self.ammo_nails > 0) {
			self.reload_light_assault = 0;
			if (self.ammo_nails < RE_LIGHT_ASSAULT)
				self.reload_light_assault = RE_LIGHT_ASSAULT - self.ammo_nails;

			sprint (self, PRINT_HIGH, "reloading...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			tWeapon.nextthink = time + RE_LIGHT_ASSAULT_TIME;
			tWeapon.think = W_Reload_light_assault;

			self.weaponmodel = "";
			self.weaponframe = 0;

			return TRUE;
        }
	} else if (self.current_weapon == WEAP_LASERCANNON) {
        if ( self.reload_laser_cannon >= RE_LASER_CANNON
			 && self.ammo_cells > 0) {
			self.reload_laser_cannon = 0;
			if (self.ammo_cells < RE_LASER_CANNON)
				self.reload_laser_cannon = RE_LASER_CANNON - self.ammo_cells;

			sprint (self, PRINT_HIGH, "Charging cannon...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			tWeapon.nextthink = time + RE_LASER_CANNON_TIME;
			tWeapon.think = W_Reload_laser_cannon;

			self.weaponmodel = "";
			self.weaponframe = 0;

			return TRUE;
		}
	} else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) {
		if ( self.reload_grenade_launcher >= RE_GRENADE_LAUNCHER
			 && self.ammo_rockets > 0) {
			self.reload_grenade_launcher = 0;
			if (self.ammo_rockets < RE_GRENADE_LAUNCHER)
				self.reload_grenade_launcher =
					RE_GRENADE_LAUNCHER - self.ammo_rockets;

			sprint (self, PRINT_HIGH, "reloading...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			tWeapon.nextthink = time + RE_GRENADE_LAUNCHER_TIME;
			tWeapon.think = W_Reload_grenade_launcher;

			self.weaponmodel = "";
			self.weaponframe = 0;

			return TRUE;
		}
	} else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) {
		if ( self.reload_rocket_launcher >= RE_ROCKET_LAUNCHER
			 && self.ammo_rockets > 0) {
			self.reload_rocket_launcher = 0;
			if (self.ammo_rockets < RE_ROCKET_LAUNCHER)
			self.reload_rocket_launcher = RE_ROCKET_LAUNCHER
				- self.ammo_rockets;

			sprint (self, PRINT_HIGH, "reloading...\n");
			self.tfstate = (self.tfstate | TFSTATE_RELOADING);
			tWeapon = spawn();
			tWeapon.owner = self;
			tWeapon.classname = "timer";
			if (self.tf_items & NIT_CLUSTER_ROCKETS)
				tWeapon.nextthink = time + RE_ROCKET_LAUNCHER_TIME - 1;
			else
       			tWeapon.nextthink = time + RE_ROCKET_LAUNCHER_TIME;
			tWeapon.think = W_Reload_rocket_launcher;

			self.weaponmodel = "";
			self.weaponframe = 0;

			return TRUE;
		}
	}

	return FALSE;
};

/*
============
W_Attack

An attack impulse can be triggered now
============
*/
void()	player_axe1;
void()	player_axeb1;
void()	player_axec1;
void()	player_axed1;

void()	player_axe2;
void()	player_axeb2;
void()	player_axec2;
void()	player_axed2;

void()	player_shot1;
void()	player_nail1;

void()	player_snail1; // ofn SNG

void()	player_light1;
void()	player_light_assault1;
void()	player_rocket1;

#ifndef NO_AUTORIFLE
void()	player_autorifle1;
#endif
void()  player_assaultcannon1;
void()  player_assaultcannonup1;
void()  player_assaultcannondown1;
void()	player_medikit1;
void()	player_medikitb1;
void()	player_medikitc1;
void()	player_medikitd1;
void()	player_bioweapon1;
void()	player_bioweaponb1;
void()	player_bioweaponc1;
void()	player_bioweapond1;
void()  player_chain1;
void()  player_chain2;
void()  player_chain3;
void()  player_chain4;
void()  player_chain5;


void() W_Attack =
{
	local float	 r;

	if (!W_CheckNoAmmo ())
		return;

	if (self.playerclass == PC_CUSTOM && (self.done_custom & CUSTOM_BUILDING))
		return;

	if (self.tfstate & TFSTATE_RELOADING)
		return;

	if (self.penance_time > time)
		return;

	//WK Tranq does not remove disguise
	//GR Spy can fire and keep their skin if not color-disguised.
	if (self.undercover_team && (self.current_weapon != WEAP_TRANQ && self.current_weapon != WEAP_MAUSER))
		Spy_RemoveDisguise(self);

	if (self.job & JOB_THIEF && (self.job & JOB_ACTIVE || self.job & JOB_FULL_HIDE))
		RevealThief(self,FALSE);

	//WK When conced you randomly don't fire
	if (self.tfstate & TFSTATE_CONCUSSIONED)
		if (random() <= 0.3)
			return;

	makevectors	(self.v_angle);			// calculate forward angle for velocity
	self.show_hostile = time + 1;	// wake monsters up

	if (self.current_weapon == WEAP_AXE) {
		local float af = 0.5;
		
        sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
		r = random();

		if (self.cutf_items & CUTF_KNIFE) {
			find_melee (self, TRUE, 72);

			if (!is_backstab (FALSE) || !trace_ent.takedamage ||
				(trace_ent.classname != "player" && !IsMonster (trace_ent))) {
				af -= 0.1;

				if (r < 0.5)
					player_axe2 ();
				else
					player_axec2 ();
			} else {
				af += 0.3;

				if (r < 0.5)
					player_axeb1 ();
				else
					player_axed1 ();
			}
		} else {
			if (r < 0.25)
				player_axe1 ();
			else if (r<0.5)
				player_axeb1 ();
			else if (r<0.75)
				player_axec1 ();
			else
				player_axed1 ();
		}

		if (self.cutf_items & CUTF_CLOSECOMBAT)
			af -= 0.1;

		Attack_Finished (af);

	} else if (self.current_weapon == WEAP_SPANNER) {
		Attack_Finished(0.35); //WK Berserk with spanner
		sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
		player_axe1 ();
	} else if (self.current_weapon == WEAP_HOOK) {
		if (!self.hook_out)
	    	player_chain1 ();

		Attack_Finished(1); //WK
	} else if (self.current_weapon == WEAP_SHOTGUN) {
		if (CheckForReload() == TRUE)
			return;

		player_shot1 ();
		W_FireShotgun ();

   	    self.reload_shotgun = self.reload_shotgun + 1;
		self.StatusRefreshTime = time + 0.1;

		CheckForReload();
		Attack_Finished(0.5);
	} else if (self.current_weapon == WEAP_SUPER_SHOTGUN) {
		if (CheckForReload() == TRUE)
			return;

		player_shot1 ();
		W_FireSuperShotgun ();
 
       	self.reload_super_shotgun = self.reload_super_shotgun + 2;
			
		self.StatusRefreshTime = time + 0.1;

		CheckForReload();
		Attack_Finished(0.7);
	} else if (self.current_weapon == WEAP_SNG) {
		player_snail1 ();
	} else if (self.current_weapon == WEAP_NAILGUN) {
		player_nail1 ();
	} else if (self.current_weapon == WEAP_LIGHT_ASSAULT) {
		if (CheckForReload() == TRUE)
			return;

		player_light_assault1();
		CheckForReload();
	} else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) {
		if (CheckForReload() == TRUE)
			return;

		player_rocket1();
		W_FireGrenade();

		self.reload_grenade_launcher = self.reload_grenade_launcher + 1;
		self.StatusRefreshTime = time + 0.1;

		CheckForReload();
		Attack_Finished(0.6);
	} else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) {
		if (CheckForReload() == TRUE)
			return;

		player_rocket1();
		W_FireRocket();

		if (self.tf_items & NIT_CLUSTER_ROCKETS && self.cluster_mode == TRUE) //WK Clusters are multiple shots
	       	self.reload_rocket_launcher = self.reload_rocket_launcher + 8;
		else
	       	self.reload_rocket_launcher = self.reload_rocket_launcher + 1;
		self.StatusRefreshTime = time + 0.1;

		CheckForReload();
//CH so that the dot can be removed quicker (reset after dot gone)
		if (self.tf_items & NIT_RL_LASER_SIGHT)
			Attack_Finished(0.1);
		else
			Attack_Finished(0.8);
	} else if (self.current_weapon == WEAP_LIGHTNING) {
		player_light1();
		Attack_Finished(0.1);
		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
	} else if (self.current_weapon == WEAP_DAEDALUS) {		//CHANGEME
		player_rocket1();
		W_FireDaedalus();
		Attack_Finished(0.8);
		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
	} else if (self.current_weapon == WEAP_SNIPER_RIFLE) {
		// Can't fire while jumping
		// WK You can if you are a scuba commando!
		if ( (self.flags & FL_ONGROUND) || (self.hook_out)
			 || ((self.tf_items & NIT_SCUBA) && self.waterlevel) ) {
			player_shot1();
			W_FireSniperRifle();
			Attack_Finished(SNIPER_RIFLE_RELOAD_TIME);
		}
#ifndef NO_AUTORIFLE
	} else if (self.current_weapon == WEAP_AUTO_RIFLE) {
		player_autorifle1();
	     	W_FireAutoRifle();
	     	Attack_Finished(0.1);
#endif
	} else if (self.current_weapon == WEAP_ASSAULT_CANNON) {
		// Need 4 cells to power up the Assault Cannon
		if (self.ammo_cells < 4) {
			sprint (self, PRINT_MEDIUM, "Insufficient cells to power up the Assault Cannon.\n");
			stuffcmd (self, "-attack;\n"); // to avoid flooding
		} else {
			self.ammo_cells = self.ammo_cells - 4;

			// Can't move while firing the Assault Cannon :)
			self.heat = 1;
			makeImmune(self,time+2);
//			self.immune_to_check = time + 2;
			self.tfstate = self.tfstate | TFSTATE_ASSAULTCANNON;
			TeamFortress_SetSpeed(self);
			player_assaultcannonup1();
		}
	} else if (self.current_weapon == WEAP_FLAMETHROWER) {
		player_shot1();
		W_FireFlame();
		if (self.waterlevel > 2)
			Attack_Finished(1);
        else
			Attack_Finished(0.15);
	} else if (self.current_weapon == WEAP_INCENDIARY) {
		player_rocket1();
		W_FireIncendiaryCannon();
		Attack_Finished(1.2);
	} else if (self.current_weapon == WEAP_MEDIKIT) {
		sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
		r = random();
		if (r < 0.25)
			player_medikit1 ();
		else if (r < 0.5)
			player_medikitb1 ();
		else if (r < 0.75)
			player_medikitc1 ();
		else
			player_medikitd1 ();
		Attack_Finished(0.5);
	} else if (self.current_weapon == WEAP_TRANQ) {
		sound (self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM);
		player_shot1 ();
		W_FireTranq ();
		Attack_Finished(1.5);
	} else if (self.current_weapon == WEAP_LASER) {
		sound (self, CHAN_WEAPON, "weapons/railgun.wav", 1, ATTN_NORM);
		player_shot1();
		W_FireLaser();
		Attack_Finished(0.4);
	} else if (self.current_weapon == WEAP_MAUSER) {
		sound (self, CHAN_WEAPON, "weapons/dartgun.wav", 1, ATTN_NORM);
//		player_shot1();
		W_FireMauser();
		Attack_Finished(2.0);
	} else if (self.current_weapon == WEAP_AIRF) {
		launch_horn();
	}
	if (self.current_weapon == WEAP_LASERCANNON) {
		if (CheckForReload() == TRUE)
			return;

		player_laser1();
		CheckForReload();
	}
};

/*=========================
	W_PrintWeaponMessage

Prints a message indicating
the current selected weapon,
if needed.
=========================*/
void() W_PrintWeaponMessage =
{
	//WK Custom class friendly
	if (self.current_weapon == WEAP_AXE) { // && (self.weapons_carried & WEAP_HOOK))
		if (!(self.cutf_items & CUTF_KNIFE))
			sprint(self, PRINT_MEDIUM, "Axe selected\n");
		else {
			if (self.weaponmode == 0)
				sprint(self, PRINT_MEDIUM, "Knife selected\n"); //Nonbloody
			else
				sprint(self, PRINT_MEDIUM, "Bloody Knife selected\n"); //Bloody
		}
	} else if (self.current_weapon == WEAP_HOOK)
		sprint(self, PRINT_MEDIUM, "Grappling Hook selected\n");
//CH because they use the same mdl, say what they are.
	else if (self.current_weapon == WEAP_FLAMETHROWER)
		sprint(self, PRINT_MEDIUM, "Flamethrower selected\n");
	else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) {
		sprint(self, PRINT_MEDIUM, "Rocket Launcher selected");

		if (self.cluster_mode == TRUE && self.tf_items & NIT_CLUSTER_ROCKETS) //set to fire cluster rockets
			sprint(self, PRINT_MEDIUM, "  Cluster Mode");
		else if (self.tf_items & NIT_CLUSTER_ROCKETS)
			sprint(self, PRINT_MEDIUM, "  Normal Mode");

		sprint(self, PRINT_MEDIUM, "\n");
	} else if (self.current_weapon == WEAP_INCENDIARY)
		sprint(self, PRINT_MEDIUM, "Incendiary cannon selected\n");
	else if (self.current_weapon == WEAP_LIGHTNING)
			sprint(self, PRINT_MEDIUM, "Lightning Gun selected\n");
	else if (self.current_weapon == WEAP_SPANNER)
			sprint(self, PRINT_MEDIUM, "Spanner readied\n");

	else if (self.current_weapon == WEAP_GRENADE_LAUNCHER) {
		if (self.weaponmode == GL_NORMAL)
			sprint(self, PRINT_MEDIUM, "Normal grenade mode\n");
		else if (self.weaponmode == GL_PIPEBOMB)
			sprint(self, PRINT_MEDIUM, "Pipebomb mode\n");
	} else if (self.current_weapon == WEAP_SNIPER_RIFLE)
		sprint(self, PRINT_MEDIUM, "Sniper Rifle ready\n");
#ifndef NO_AUTORIFLE
	else if (self.current_weapon == WEAP_AUTO_RIFLE)
		sprint(self, PRINT_MEDIUM, "Rifle on fully auto\n");
#endif
	else if (self.current_weapon == WEAP_TRANQ)
		sprint(self, PRINT_MEDIUM, "Tranquiliser gun selected\n");
	else if (self.current_weapon == WEAP_MEDIKIT)
		sprint(self, PRINT_MEDIUM, "Medikit/Bioweapon readied\n");
	else if (self.current_weapon == WEAP_MAUSER)
		sprint(self, PRINT_MEDIUM, "Mauser WK-77 Assassin's Gun readied\n");
	else if (self.current_weapon == WEAP_DAEDALUS)
		sprint(self, PRINT_MEDIUM, "Daedalus Impulse Rifle readied\n");
    else if (self.current_weapon == WEAP_LIGHTNING)
		sprint(self, PRINT_MEDIUM, "Lighting gun selected\n");
    else if (self.current_weapon == WEAP_AIRF)
        sprint(self, PRINT_MEDIUM, "Airfist prepared\n");
    else if (self.current_weapon == WEAP_LASERCANNON)
        sprint(self, PRINT_MEDIUM, "Laser Cannon selected\n");
    else if (self.current_weapon == WEAP_SNG)
        sprint(self, PRINT_MEDIUM, "Super Nailgun selected\n");
    else if (self.current_weapon == WEAP_NAILGUN)
        sprint(self, PRINT_MEDIUM, "Nailgun selected\n");
    else if (self.current_weapon == WEAP_LIGHT_ASSAULT)
        sprint(self, PRINT_MEDIUM, "Light Assualt cannon selected\n");
};

/*
============
W_ChangeWeapon

============
*/
void() W_ChangeWeapon =
{
	local	float	it, am, fl, loopck;
	local 	float 	have_weapon, usable;
	
	if (self.tfstate & TFSTATE_RELOADING)
  		return;

	if (self.tfstate & TFSTATE_CANT_MOVE)
		return; 

	it = self.weapons_carried;
	fl = self.current_weapon;
	am = 0;
	usable = 0;
	have_weapon = TRUE;

	if (self.impulse == 1) {
		if (!(it & (WEAP_HOOK | WEAP_MEDIKIT | WEAP_AXE | WEAP_SPANNER)))
			have_weapon = FALSE;			

		while (!usable && have_weapon) {
			if (fl == WEAP_SPANNER) {
				fl = WEAP_MEDIKIT;

				if (it & WEAP_MEDIKIT)
					usable = 1;
			} else if (fl == WEAP_MEDIKIT) {
				fl = WEAP_HOOK;

				if ((self.weapons_carried & WEAP_HOOK) && (fl & WEAP_HOOK))
					usable = 1;

                if (self.hook_out)
                	Reset_Grapple(self.hook);
			} else if (fl == WEAP_HOOK) {
				fl = WEAP_AXE;

				if (it & WEAP_AXE)
					usable = 1;
			} else {
				fl = WEAP_SPANNER;

				if (it & WEAP_SPANNER)
					usable = 1;
			}
		}
	} else if ((self.weapons_carried & WEAP_HOOK) && (self.impulse == HOOK_IMP1 || self.impulse == HOOK_IMP2)) {
		fl = WEAP_HOOK;		
	} else if (self.impulse == AXE_IMP) {
		if (!(it & (WEAP_MEDIKIT | WEAP_AXE | WEAP_SPANNER)))
			have_weapon = FALSE;			

		while (!usable && have_weapon) {
			if (fl == WEAP_SPANNER) {
				fl = WEAP_MEDIKIT;

				if (it & WEAP_MEDIKIT)
					usable = 1;
			} else if (fl == WEAP_MEDIKIT) {
				fl = WEAP_AXE;

				if (it & WEAP_AXE)
					usable = 1;
			} else {
				fl = WEAP_SPANNER;

				if (it & WEAP_SPANNER)
					usable = 1;
			}
		}
	} else if (self.impulse == 2) {
		if (!(((it & WEAP_SNIPER_RIFLE || it & WEAP_SHOTGUN || it & WEAP_TRANQ) && self.ammo_shells > 0) || (it & WEAP_LASER && self.ammo_nails > 0)|| (it & WEAP_DAEDALUS && self.ammo_cells > 0)))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_SNIPER_RIFLE) {
				fl = WEAP_SHOTGUN;
				if (it & WEAP_SHOTGUN && self.ammo_shells > 0)
					usable = 1;
			} else if (fl == WEAP_SHOTGUN) {
				fl = WEAP_TRANQ;
				if (it & WEAP_TRANQ && self.ammo_nails > 0)
					usable = 1;
			} else if (fl == WEAP_TRANQ) {
				fl = WEAP_LASER;
				if (it & WEAP_LASER && self.ammo_nails > 0)
					usable = 1;
			} else {
				fl = WEAP_SNIPER_RIFLE;
				if (it & WEAP_SNIPER_RIFLE && self.ammo_shells > 0)
					usable = 1;
			}
		}

		if (fl == WEAP_LASER) {
			if (self.ammo_nails < 1)
				am = 1;
		} else {
			if (self.ammo_shells < 1)
				am = 1;
		}
	} else if (self.impulse == 3) {
		if (!(
#ifndef NO_AUTORIFLE
			(it & WEAP_AUTO_RIFLE && self.ammo_shells > 0) || 
#endif
			(it & WEAP_SUPER_SHOTGUN && self.ammo_shells >1)))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
#ifndef NO_AUTORIFLE
			if (fl == WEAP_AUTO_RIFLE) {
				fl = WEAP_SUPER_SHOTGUN;
				if (it & WEAP_SUPER_SHOTGUN && self.ammo_shells > 1)
					usable = 1;
			} else {
				fl = WEAP_AUTO_RIFLE;
				if (it & WEAP_AUTO_RIFLE && self.ammo_shells > 0)
					usable = 1;
			}
#else
			fl = WEAP_SUPER_SHOTGUN;
			if (it & WEAP_SUPER_SHOTGUN && self.ammo_cells > 1)
				usable = 1;
			else
				have_weapon = FALSE;
#endif
		}

		if (fl == WEAP_SUPER_SHOTGUN) {
			if (self.ammo_shells < 2)
				am = 1;
		} else {
			if (self.ammo_shells < 1)
				am = 1;
		}
	} else if (self.impulse == 4) {
/*
		fl = WEAP_NAILGUN;
		if (self.ammo_nails < 1)
			am = 1;
*/

		if (!(it & WEAP_LASERCANNON || it & WEAP_NAILGUN))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_LASERCANNON) {
				fl = WEAP_NAILGUN;
				if (it & WEAP_NAILGUN)
					usable = 1;
			} else {
				fl = WEAP_LASERCANNON;
				if (it & WEAP_LASERCANNON)
					usable = 1;
			}
		}
		if (fl == WEAP_NAILGUN) {
			if (self.ammo_nails < 1)
				am = 1;
		} else if (fl == WEAP_LASERCANNON) {
			if (self.ammo_cells < 1)
				am = 1;
		}
	} else if (self.impulse == 5) {
		if (!(it & WEAP_LIGHT_ASSAULT || it & WEAP_MAUSER || it & WEAP_SNG))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_LIGHT_ASSAULT) {
				fl = WEAP_MAUSER;
				if (it & WEAP_MAUSER)
					usable = 1;
			//-
			} else if (fl == WEAP_MAUSER) {
				fl = WEAP_SNG;
				if (it & WEAP_SNG)
					usable = 1;
			//-
			} else {
				fl = WEAP_LIGHT_ASSAULT;
				if (it & WEAP_LIGHT_ASSAULT)
					usable = 1;
			}
		}
		if (fl == WEAP_MAUSER) {
			if (self.ammo_nails < 1)
				am = 1;
		} else if (fl == WEAP_LIGHT_ASSAULT) {
			if (self.ammo_nails < 1)
				am = 1;
		} else if (fl == WEAP_SNG) {
			if (self.ammo_nails < 2)
				am = 1;
		}
	} else if (self.impulse == 6) {
		if (!((it & WEAP_FLAMETHROWER && self.ammo_cells > 0) || (it & WEAP_GRENADE_LAUNCHER && self.ammo_rockets > 0)))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_FLAMETHROWER) {
				fl = WEAP_GRENADE_LAUNCHER;
				self.weaponmode = GL_NORMAL;
				if (it & WEAP_GRENADE_LAUNCHER && self.ammo_rockets > 0)
					usable = 1;
			} else {
				fl = WEAP_FLAMETHROWER;
				if (it & WEAP_FLAMETHROWER && self.ammo_cells > 0)
					usable = 1;
			}
		}
		if (fl == WEAP_FLAMETHROWER) {
			if (self.ammo_cells < 1)
				am = 1;
		} else {
			if (self.ammo_rockets < 1)
				am = 1;
		}
	} else if (self.impulse == 7) {
		if (!((it & WEAP_INCENDIARY && self.ammo_rockets > 2) || ((it & WEAP_ROCKET_LAUNCHER || it & WEAP_GRENADE_LAUNCHER) && self.ammo_rockets > 0) || (it & WEAP_ASSAULT_CANNON && self.ammo_shells > 0 && self.ammo_cells > 3)))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_INCENDIARY) {
				fl = WEAP_ROCKET_LAUNCHER;
				if (it & WEAP_ROCKET_LAUNCHER && self.ammo_rockets > 0)
					usable = 1;
			} else if (fl == WEAP_ROCKET_LAUNCHER) {
				if (self.tf_items & NIT_CLUSTER_ROCKETS) {
					if (self.cluster_mode == TRUE) {
//						bprint(PRINT_HIGH, "cluster mode FALSE\n");
						self.cluster_mode = FALSE;
						fl = WEAP_ASSAULT_CANNON;
						if ( it & WEAP_ASSAULT_CANNON && self.ammo_shells > 0
							 && self.ammo_cells > 3)
							usable = 1;
					} else {
//						bprint(PRINT_HIGH, "cluster mode TRUE\n");
						self.cluster_mode = TRUE;
						fl = WEAP_ROCKET_LAUNCHER;
						if (it & WEAP_ROCKET_LAUNCHER && self.ammo_rockets > 0)
							usable = 1;
					}
				} else {
					fl = WEAP_ASSAULT_CANNON;
					if ( it & WEAP_ASSAULT_CANNON && self.ammo_shells > 0
						 && self.ammo_cells > 3)
						usable = 1;
				}
			} else if (fl == WEAP_ASSAULT_CANNON) {
				fl = WEAP_GRENADE_LAUNCHER;
				self.weaponmode = GL_PIPEBOMB;
				if (it & WEAP_GRENADE_LAUNCHER && self.ammo_rockets > 0)
					usable = 1;
			} else {
				fl = WEAP_INCENDIARY;
				if (it & WEAP_INCENDIARY && self.ammo_rockets > 2)
					usable = 1;
			}
		}
		if (fl == WEAP_ASSAULT_CANNON) {
			if (self.ammo_cells < 4 || self.ammo_shells < 1)
				am = 1;
		} else if (fl == WEAP_INCENDIARY) {
			if (self.ammo_rockets < 3)
				am = 1;
		} else {
			if (self.ammo_rockets < 1)
				am = 1;
		}
	} else if (self.impulse == 8) {
		if (!(it & WEAP_LIGHTNING || it & WEAP_DAEDALUS || it & WEAP_AIRF))
			have_weapon = FALSE;
		loopck = 0;
		while (!usable && have_weapon) {
			loopck = (loopck + 1);
			if (loopck >= 10)
				have_weapon = FALSE;
			if (fl == WEAP_DAEDALUS) {
				fl = WEAP_LIGHTNING;
				if (it & WEAP_LIGHTNING) //WEAP_DAEDALUS
					usable = 1;
			} else if (fl == WEAP_LIGHTNING) {
				fl = WEAP_AIRF;
				if (it & WEAP_AIRF) //WEAP_DAEDALUS
					usable = 1;
			} else {
				fl = WEAP_DAEDALUS;
				if (it & WEAP_DAEDALUS)
					usable = 1;
			}
		} if (fl == WEAP_DAEDALUS) {
			if (self.ammo_cells < 5)
			{
			   if (it & WEAP_LIGHTNING)
			     fl = WEAP_LIGHTNING;
			   else am = 1;
			} 
		} if (fl == WEAP_LIGHTNING) {
			if (self.ammo_cells < 1)
			   am = 1;
		} if (it & WEAP_AIRF && am) {
			fl = WEAP_AIRF;
			am = 0;
		}
	} else if (self.impulse == TF_MEDIKIT) {
		fl = WEAP_MEDIKIT;

		if (it & WEAP_MEDIKIT)
			usable = 1;
	}

	self.impulse = 0;
	
	// don't have the weapon
	if (!have_weapon || (!(it & fl))) {	
		sprint (self, PRINT_HIGH, "no weapon.\n");
		return;
	}
	
	// don't have the ammo
	if (am == 1) {
		sprint(self, PRINT_HIGH, "not enough ammo.\n");
		return;
	}

	// don't have the cells for the cannon
	if (am == 2) {
		sprint(self, PRINT_HIGH, "not enough cells to power assault cannon.\n");
		return;
	}

	// set weapon, set ammo
	self.current_weapon = fl;
	W_SetCurrentAmmo ();
	W_PrintWeaponMessage();

	self.StatusRefreshTime = time + 0.1;
};

/*
============
CycleWeaponCommand

Go to the next weapon with ammo
============
*/
void() CycleWeaponCommand =
{
//CH reorder so that they please me
	local	float	it, am, cont, loopcount;
	
	// Some safety code
	if (!self.weaponmodel || self.current_weapon == 0)
		return;

	if (self.tfstate & TFSTATE_RELOADING)
		return;

	if (self.tfstate & TFSTATE_CANT_MOVE)
		return; 

	it = self.weapons_carried;
	self.impulse = 0;
	loopcount = 0;
	
	while (1) {
		am = 0;
		cont = FALSE;

		if (self.current_weapon == WEAP_AXE) {
			self.current_weapon = WEAP_SPANNER;
		} else if (self.current_weapon == WEAP_SPANNER) {
			self.current_weapon = WEAP_SHOTGUN;
			if (self.ammo_shells < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_SHOTGUN) {
			self.current_weapon = WEAP_LASER;
			if (self.ammo_nails < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_LASER) {
			self.current_weapon = WEAP_TRANQ;
			if (self.ammo_nails < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_TRANQ) {
			self.current_weapon = WEAP_SNIPER_RIFLE;
			if (self.ammo_shells < 5)
				am = 1;
		} else if (self.current_weapon == WEAP_SNIPER_RIFLE) {
#ifndef NO_AUTORIFLE
			self.current_weapon = WEAP_AUTO_RIFLE;
			if (self.ammo_shells < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_AUTO_RIFLE) {
#endif
			self.current_weapon = WEAP_MAUSER;
			if (self.ammo_nails < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_MAUSER) {
			self.current_weapon = WEAP_SUPER_SHOTGUN;
			if (self.ammo_shells < 2)
				am = 1;
		} else if (self.current_weapon == WEAP_SUPER_SHOTGUN) {
			self.current_weapon = WEAP_NAILGUN;
			if (self.ammo_nails < 1)
				am = 1;
		//-
		} else if (self.current_weapon == WEAP_NAILGUN) {
			self.current_weapon = WEAP_SNG;
			if (self.ammo_nails < 2)
				am = 1;
		//-
		} else if (self.current_weapon == WEAP_SNG) {
			self.current_weapon = WEAP_LASERCANNON;
			if (self.ammo_cells < 1)
				am = 1;
		//-
		} else if (self.current_weapon == WEAP_LASERCANNON) { // was WEAP_NAILGUN
			self.current_weapon = WEAP_LIGHT_ASSAULT;
			if (self.ammo_nails < 2)
				am = 1;
		} else if (self.current_weapon == WEAP_LIGHT_ASSAULT) {
			self.current_weapon = WEAP_FLAMETHROWER;
			if (self.ammo_cells < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_FLAMETHROWER) {
			self.current_weapon = WEAP_GRENADE_LAUNCHER;
			self.weaponmode = GL_NORMAL;
			if (self.ammo_rockets < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_GRENADE_LAUNCHER && self.weaponmode == GL_NORMAL) {
			self.current_weapon = WEAP_GRENADE_LAUNCHER;
			self.weaponmode = GL_PIPEBOMB;
			if (self.ammo_rockets < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_GRENADE_LAUNCHER && self.weaponmode == GL_PIPEBOMB) {
			self.current_weapon = WEAP_INCENDIARY;
			if (self.ammo_rockets < 3)
				am = 1;
		} else if (self.current_weapon == WEAP_INCENDIARY) {
			self.current_weapon = WEAP_DAEDALUS;
			if (self.ammo_cells < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_DAEDALUS) {
			self.current_weapon = WEAP_ROCKET_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		} else if (self.current_weapon == WEAP_ROCKET_LAUNCHER) {
			if (self.tf_items & NIT_CLUSTER_ROCKETS) {
				if (self.cluster_mode == TRUE) {
//					bprint(PRINT_HIGH, "cluster mode FALSE\n");
					self.cluster_mode = FALSE;
					self.current_weapon = WEAP_ASSAULT_CANNON;
					if (self.ammo_cells < 4)
						am = 1;
       				if (self.ammo_shells < 1)
		        		am = 1;
				} else {
//					bprint(PRINT_HIGH, "cluster mode TRUE\n");
					self.cluster_mode = TRUE;
					self.current_weapon = WEAP_ROCKET_LAUNCHER;
					if (self.ammo_rockets < 1)
						am = 1;
				}
			} else {
				self.current_weapon = WEAP_ASSAULT_CANNON;
				if (self.ammo_cells < 4)
					am = 1;
      	  		if (self.ammo_shells < 1)
	        		am = 1;
			}
		} else if (self.current_weapon == WEAP_ASSAULT_CANNON) {
         		self.current_weapon = WEAP_LIGHTNING;
         		if (self.ammo_cells < 1)
         			am = 1;
      	} else if (self.current_weapon == WEAP_LIGHTNING) {
			self.current_weapon = WEAP_AIRF;

			if (!(self.weapons_carried & WEAP_AIRF))
				am = 1;
     	} else if (self.current_weapon == WEAP_AIRF) {
			self.current_weapon = WEAP_HOOK;

			if (!(self.weapons_carried & WEAP_HOOK))
				am = 1;
     	} else if (self.current_weapon == WEAP_HOOK) {
			self.current_weapon = WEAP_MEDIKIT;
		} else if (self.current_weapon == WEAP_MEDIKIT) {
			self.current_weapon = WEAP_AXE;
		}

		// Safety precaution
		if (loopcount > 30)
			return;

		loopcount = loopcount + 1;

	    // check if player actually has the weapon
	   	// if not, loop again
		if ((self.weapons_carried & self.current_weapon) && (am == 0)) {
			if (self.current_weapon != WEAP_GRENADE_LAUNCHER)
				self.weaponmode = GL_NORMAL;	// reset the pipebombs

			W_SetCurrentAmmo ();
			W_PrintWeaponMessage();

			self.StatusRefreshTime = time + 0.1;
			return;
		}
	}
};

/*
============
ImpulseCommands

============
*/
void() DeadImpulses;

float(float inp) BuildingImpulses =
{
	if (inp < 10) return TRUE;
	if (inp > TF_CHANGEPC && inp <= TF_CHANGEPC + PC_LASTCLASS) return TRUE;
	if (inp == TF_CHANGECLASS) return TRUE;
	if (inp == TF_HELP_MAP) return TRUE;
	if (inp == TF_SHOWTF) return TRUE;
	if (inp == TF_TEAM_CLASSES) return TRUE;
	if (inp == TF_TEAM_SCORES) return TRUE;
	if (inp == TF_TEAM_LIST) return TRUE;
	if (inp == TF_TEAM_ENUM) return TRUE;
	if (inp == TF_ID) return TRUE;
	if (inp == TF_SELL) return TRUE;
	if (inp == I_CHEAT_ONE) return TRUE;
	if (inp == I_CHEAT_TWO) return TRUE;
	if (inp == I_CHEAT_THREE) return TRUE;
	return FALSE;
};

void() Alias_BitImpulse;

void() ImpulseCommands =
{
	if (self.impulse >= TF_BITSTART && self.impulse <= TF_BITNONE) {
		Alias_BitImpulse ();
		self.impulse = 0;
		return;
	}

	if (self.impulse == TF_ALIASNEXT) {
		self.impulse = 0;
		self.got_aliases_time = time;
		return;
	}

	if ((self.impulse== TF_CHANGEPC + PC_CUSTOM || self.impulse==TF_SELL) && custom_mode==2) {
        self.impulse=0;
        sprint(self,PRINT_MEDIUM,"Custom player classes are disabled\n");
        return;
    }

    if (self.impulse <= TF_CHANGEPC + PC_RANDOM && self.impulse >= TF_CHANGEPC + PC_SCOUT && stock_mode==2) {
        self.impulse=0;
        sprint(self,PRINT_MEDIUM,"Stock player classes are disabled\n");
        return;
    }

//	local entity te; //- OfN - Unused!
    
	//WK Don't allow any commands except menu ones when building a class
	if ( self.playerclass == PC_CUSTOM
		 && (self.done_custom & CUSTOM_BUILDING)) {
		if (!BuildingImpulses(self.impulse)) {
			self.impulse = 0;
			return;
		}
	}

	//WK Don't allow bastards to do any commands
	if (self.penance_time > time)
		return;
		
	if (prematch >= time)
		if (self.impulse > 10 || self.impulse < 1) {
			self.impulse = 0;
			return;
		}

	/*=====================
	These Impulse commands rely on the use of self.last_impulse. Since they use 
	self.impulse for their own purposes, they _must_ be placed before the other 
	self.impulse tests, and they _must_ set self.impulse = 0 when they're done. 
	=====================*/

	// TeamFortress Detpack
	if (self.last_impulse == TF_DETPACK && self.impulse)
		TeamFortress_SetDetpack(self.impulse);
	// TeamFortress Scan
	else if (self.last_impulse == TF_SCAN && self.impulse)
		TeamFortress_Scan(self.impulse,FALSE);

	/*=====================
    The rest of these Impulse Commands don't use self.last_impulse. They _must_
	be placed _after_ the Impulse Commands that do require self.last_impulse 
	=====================*/

	// Catch the 8 key to reprint the classhelp.
	// Remove this when we return the lightning gun
	//CH was on impulse 8, but thats lgun
	if (self.impulse == 9 && self.current_menu != MENU_CLASSHELP && (self.playerclass > 0 && self.playerclass < 11)) {
		self.current_menu = MENU_CLASSHELP;
		self.menu_count = MENU_REFRESH_RATE;
		self.menu_displaytime = 0;
	}

	// uses the special skill of the player's class
	if (self.impulse == TF_SPECIAL_SKILL)
		UseSpecialSkill();

	// uses the special skill of the player's class
	if (self.impulse == TF_SKILL)
		UseJobSkill();

	// No weapon related impulses can be done when setting detpacks or building WK or chaplaning
	if (!self.is_building && !self.is_detpacking && !self.is_feigning && !(self.job & JOB_CHAPLAN && self.job & JOB_ACTIVE)) {
		if ((self.impulse >= 1 && self.impulse < 9) || (self.impulse == TF_MEDIKIT))
			W_ChangeWeapon ();

		// Grappling Hook
		else if ((self.weapons_carried & WEAP_HOOK) && (self.impulse == HOOK_IMP1 || self.impulse == HOOK_IMP2))
			W_ChangeWeapon ();

		// Axe 
		else if (self.impulse == AXE_IMP)
			W_ChangeWeapon ();

		// cycle weapon reverse and cycle weapon do the same thing
		// TBD: make CycleWeaponReverseCommand()
		else if (self.impulse == 10 || self.impulse == 12)
			CycleWeaponCommand ();

		// TeamFortress Reload current weapon
		else if (self.impulse == TF_RELOAD)
			TeamFortress_ReloadCurrentWeapon();

		// Scanning impulses
		else if (self.impulse == TF_SCAN_10)
			TeamFortress_Scan(10,FALSE);
		else if (self.impulse == TF_SCAN_30)
			TeamFortress_Scan(30,FALSE);
		else if (self.impulse == TF_SCAN_100)
			TeamFortress_Scan(100,FALSE);
		else if (self.impulse == TF_SCAN_ENEMY) //CH
			TeamFortress_Scan(TF_SCAN_ENEMY,FALSE);
		else if (self.impulse == TF_SCAN_FRIENDLY)
			TeamFortress_Scan(TF_SCAN_FRIENDLY,FALSE);

		// TeamFortress Set Detpack Impulses
		else if (self.impulse == TF_DETPACK_5)
			TeamFortress_SetDetpack(5);
		else if (self.impulse == TF_DETPACK_20)
			TeamFortress_SetDetpack(20);
		else if (self.impulse == TF_DETPACK_50)
			TeamFortress_SetDetpack(50);
		else if (self.impulse == TF_DROP_AMMO) {
			self.current_menu = MENU_DROP;
			self.menu_count = MENU_REFRESH_RATE - 5;
		} else if (self.impulse == TF_DISCARD)
			TeamFortress_Discard();
//CH
		else if (self.impulse == TF_DROPITEMS)
			TeamFortress_DropItems();
#ifdef COOP_MODE
		else if (self.impulse == TF_DROPKEY && coop)
			DropKey();
#endif
	}
	//WK We can toss grens while chaplaining. Readme says so. :p
	if (!self.is_building && !self.is_detpacking && !self.is_feigning) {
		// TeamFortress Prime Grenade Type 1
		if (self.impulse == TF_GRENADE_1)
			TeamFortress_PrimeGrenade();
		// TeamFortress Prime Grenade Type 2
		else if (self.impulse == TF_GRENADE_2)
			TeamFortress_PrimeGrenade();
	}

	// TeamFortress Inventory
	if (self.impulse == TF_INVENTORY)
		TeamFortress_Inventory();

	else if (self.impulse == TF_MEDIC_HELPME)
		TeamFortress_SaveMe();
	else if (self.impulse == TF_TAUNT) {
		if (self.last_saveme_sound < time) {
			sound(self, CHAN_WEAPON, "enforcer/sight1.wav", 1, ATTN_NORM);
			self.last_saveme_sound = time + 4;
		}
	} else if (self.impulse == TF_TAUNT2) {
		if (self.last_saveme_sound < time) {
			sound(self, CHAN_WEAPON, "enforcer/sight2.wav", 1, ATTN_NORM);
			self.last_saveme_sound = time + 4;
		}
	} else if (self.impulse == TF_TAUNT3) {
		if (self.last_saveme_sound < time) {
			sound(self, CHAN_WEAPON, "enforcer/sight3.wav", 1, ATTN_NORM);
			self.last_saveme_sound = time + 4;
		}
	} else if (self.impulse == TF_TAUNT4) {
		if (self.last_saveme_sound < time) {
			sound(self, CHAN_WEAPON, "enforcer/sight4.wav", 1, ATTN_NORM);
			self.last_saveme_sound = time + 4;
		}
	} else if (self.impulse == TF_TAUNT5) {
		if (self.last_saveme_sound < time) {
			sound(self, CHAN_WEAPON, "weapons/fith.wav", 1, ATTN_NORM);
			self.last_saveme_sound = time + 4;
		}
	}

	// TeamFortress Throw Grenade 
	else if (self.impulse == TF_GRENADE_T)
		TeamFortress_ThrowGrenade();
		
	//else if (self.impulse == BUILD_SENSOR && self.cutf_items & CUTF_SENSOR) // SB build sensor (not enough room on menu...)
	//	SBBuildSensor();
		
	else if (self.impulse == THROW_DETPACK)
		PrimeC4Det();

	/*else if (self.impulse == IMPULSE_INTERFACE)
		SBInitiateInterface();*/

    else if (self.impulse == IMPULSE_HOLO)
		ActivateHolo(self);

	else if (self.impulse == TF_ID)
		TeamFortress_ID(FALSE);

	// TeamFortress Detonate Pipebombs  (yep, can be done while setting a detpack :)
	else if (self.impulse == TF_PB_DETONATE)
		TeamFortress_DetonatePipebombs();

	// TeamFortress Stop Setting Detpack
	else if (self.impulse == TF_DETPACK_STOP)
		TeamFortress_DetpackStop(FALSE);

	// TeamFortress Class Impulses
	//WK - Custom class friendly
	else if (self.impulse == TF_SPY_SPY && (self.cutf_items & CUTF_SPY_KIT))
		TeamFortress_SpyGoUndercover();
	else if (self.impulse == TF_SPY_DIE && (self.cutf_items & CUTF_SPY_KIT))
		TeamFortress_SpyFeignDeath(1); //CH normal feign
	else if (self.impulse == TF_SPY_DIE2 && (self.cutf_items & CUTF_SPY_KIT))
		TeamFortress_SpyFeignDeath(2); //CH special sfeign
	else if (self.impulse == TF_ENGINEER_BUILD &&
              ((self.cutf_items & CUTF_SENSOR) || (self.cutf_items & CUTF_SENTRYGUN) || self.tf_items & NIT_TESLA || self.tf_items & NIT_SECURITY_CAMERA || self.tf_items & NIT_TELEPORTER || self.cutf_items & CUTF_FIELDGEN || self.cutf_items & CUTF_DISPENSER)) 
		TeamFortress_EngineerBuild();

	// CTF Support Impulses
	else if (self.impulse == FLAG_INFO) {
		if (CTF_Map == TRUE)	
			TeamFortress_CTF_FlagInfo();
		else
			TeamFortress_DisplayDetectionItems();
	}

#ifdef DEMO_STUFF
	// Camera Impulses
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_TARGET)
		CamLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_ZOOM)
		CamDistLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_VEC)
		CamVecLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_ANGLE)
		CamAngleLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_REVANGLE)
		CamRevAngleLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_PROJECTILE)
		CamProjectileLock();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_PROJECTILE_Z)
		CamProjectileZoom();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_OFFSET)
		CamOffset();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_DROP)
		CamDrop();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_FADETOBLACK)
		fadetoblack();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_FADEFROMBLACK)
		fadefromblack();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_FADETOWHITE)
		fadetowhite();
	else if (self.playerclass == PC_UNDEFINED && self.impulse == TF_CAM_FADEFROMWHITE)
		fadefromwhite();
#endif

	else
		DeadImpulses();

	/*=====================
	TeamFortress Pre-Impulse Commands
	=====================*/
	if (self.impulse == TF_DETPACK)
		self.last_impulse = self.impulse;
	if (self.impulse == TF_SCAN)
		self.last_impulse = self.impulse;
		
	self.impulse = 0;
};

/*====================
	DeadImpulses

Impulse commands that
are allowable if the
player is dead
====================*/
void() DeadImpulses =
{
	if ((self.impulse== TF_CHANGEPC + PC_CUSTOM || self.impulse==TF_SELL) && custom_mode==2) {
        self.impulse=0;
        sprint(self,PRINT_MEDIUM,"Custom player classes are disabled\n");
        return;
    }

    if (self.impulse <= TF_CHANGEPC + PC_RANDOM && self.impulse >= TF_CHANGEPC + PC_SCOUT && stock_mode==2) {
        self.impulse=0;
        sprint(self,PRINT_MEDIUM,"Stock player classes are disabled\n");
        return;
    }
#ifdef DEBUG
    if (self.impulse == 69 && infokey(NIL, "allow_debug") == "yes")
    {
        self.demon_blood = MAX_KNIFE_BLOOD;
	self.job = self.job | JOB_BLOODY_KNIFE;
        self.impulse=0;
        return;
    }

	if (self.impulse == 18 && infokey(NIL, "allow_debug") == "yes")
	{
		sprint(self, PRINT_HIGH, "Your origin is: '", ftos(self.origin_x), " ", ftos(self.origin_y));
		sprint(self, PRINT_HIGH, " ", ftos(self.origin_z), "'\n");
		self.impulse=0;
		return;
	}

	if (self.impulse == 195 && !debug_target && infokey(NIL, "allow_debug") == "yes")
		debug_target = self;
#endif

//<CH>
	if (self.impulse == I_CHEAT_ONE) {
		I_DID_CHEAT_ONE();
	}
	if (self.impulse == I_CHEAT_TWO) {
		I_DID_CHEAT_TWO();
	}
	if (self.impulse == I_CHEAT_THREE) {
		I_DID_CHEAT_THREE();
	}
//</CH>
	//WK - Add in TF2.6 support for changeclass
	if (self.impulse == TF_CHANGECLASS) {
        self.current_menu = MENU_CLASS;
        Menu_Class();
	}

	//WK Have a normal "custom" command reset the "sell" flag
	//Have to do this here, since "upgrade" corrupts self.impulse
	if (self.impulse == TF_CHANGEPC + PC_CUSTOM) //
		self.done_custom = self.done_custom - (self.done_custom & CUSTOM_SELLING);

	//WK - CustomTF1.6 ability to sell frags
	//Sets a flag saying that we wish to sell
	//And then issues a command to rebuild our class.
	if (self.impulse == TF_SELL) {
		if (bounty) {
			self.done_custom = self.done_custom | CUSTOM_SELLING;
			self.impulse = TF_CHANGEPC + PC_CUSTOM;
		} else {
			sprint (self, PRINT_HIGH, "Sorry, the admin has bounty disabled\n");
			self.impulse = 0;
			return;
		}
	}

	// TeamFortress Show Toggleflag State
	if (self.impulse == TF_SHOWTF)
		TeamFortress_ShowTF();
	// TeamFortress Show Legal PlayerClasses 
	// Toggle autozoom on/off
	else if (self.impulse == TF_AUTOZOOM)
		TeamFortress_AutoZoomToggle();
	else if (self.impulse == TF_SHOWLEGALCLASSES)
		TeamFortress_DisplayLegalClasses();

	// TeamFortress Change PlayerClass
	else if (self.impulse > TF_CHANGEPC && self.impulse <= (TF_CHANGEPC + PC_CUSTOM) ) {
		//WK Hackish bug-fix for "Custom Custom" teleporting
		if (self.impulse == TF_CHANGEPC + PC_CUSTOM) {
			if ((self.done_custom & (CUSTOM_FINISHED | CUSTOM_BUILDING) && !(self.done_custom & CUSTOM_ON_SPAWN)) || self.playerclass != PC_CUSTOM)
		    		TeamFortress_ChangeClass();
		} else
	    	TeamFortress_ChangeClass();

	} else if (self.impulse == TF_UNCUSTOM && self.done_custom & CUSTOM_ON_SPAWN) {
		self.done_custom = self.done_custom - (self.done_custom & CUSTOM_ON_SPAWN);
		sprint(self, PRINT_HIGH, "You will no longer spawn as a new playerclass.\n");	
	}
	// TeamFortress Help Impulses
	else if (self.impulse == TF_LAY)
		custom_lay();
	else if (self.impulse == TF_HELP_MAP)
		TeamFortress_HelpMap();
	else if (self.impulse == TF_STATUS_QUERY)
		TeamFortress_StatusQuery();
	// TeamFortress Team Impulse
	else if (self.impulse == TF_TEAM_1)
		TeamFortress_TeamSet(1);
	else if (self.impulse == TF_TEAM_2)
		TeamFortress_TeamSet(2);
	else if (self.impulse == TF_TEAM_3)
		TeamFortress_TeamSet(3);
	else if (self.impulse == TF_TEAM_4)
		TeamFortress_TeamSet(4);
	else if (self.impulse == TF_TEAM_SCORES)
		TeamFortress_TeamShowScores(0);
	else if (self.impulse == TF_TEAM_CLASSES)
		TeamFortress_TeamShowMemberClasses(self);
	else if (self.impulse == TF_STATUSBAR_ON) {
		self.StatusRefreshTime = time + 0.2;
		self.StatusBarSize = self.StatusBarSize + 1;
		if (self.StatusBarSize > 2)
			self.StatusBarSize = 1;
	} else if (self.impulse == TF_STATUSBAR_OFF) {
		self.StatusRefreshTime = time + 60;
		self.StatusBarSize = 0;
	} else if (self.impulse >= TF_STATUSBAR_RES_START && self.impulse <= TF_STATUSBAR_RES_END) {
		StatusRes(self.impulse - 71);
	}
	// TeamFortress Alias checking
	else if (self.impulse == TF_ALIAS_CHECK) {
		sprint (self, PRINT_HIGH, "Aliases checked.\n");
		self.got_aliases = TRUE;
		self.impulse = 0;
	}
};

/*
============
W_WeaponFrame

Called every frame so impulse events can be handled as well as possible
============
*/
void() W_WeaponFrame =
{
	local vector tv;

	if (!(self.tfstate & TFSTATE_AIMING)) {
		if (self.height > 29 && self.height < 90) {
			self.height = self.height + 80 * frametime;
			if (self.height > 90)
				self.height = 90;

			TF_zoom(self.height);
		}
	}

	if (self.current_menu > 0) {
		Player_Menu();		

		if (self.impulse > 0 && self.impulse < 11) {
  			Menu_Input(self.impulse);

			if (self.impulse != 0) {
				if (self.team_no == 0 && teamplay && (self.lives != 0)) {
					Menu_Team_Input(self.impulse);
				}
/* WK Disable picking normal class menu
				else if (self.playerclass == PC_UNDEFINED && (self.lives != 0))
				{
					Menu_Class_Input(self.impulse);
				}
*/
			}
		}
	}

	if (time < self.attack_finished)
		return;

	// Stop calling this function so much
	if (self.impulse != 0)
		ImpulseCommands ();

	// Can't fire while setting a detpack or building something
	if ((self.is_building != 0) || (self.is_detpacking != 0) || (self.is_feigning != 0) || (self.is_haxxxoring != 0) || (self.is_toffingadet != 0))
		return;

	//WK ...or Chaplaning
	if (self.job & JOB_CHAPLAN && self.job & JOB_ACTIVE)
		return;

	// Check for release
	if (!self.button0 && self.fire_held_down && self.current_weapon == WEAP_ASSAULT_CANNON) {
	    self.fire_held_down = FALSE;

		// Let him/her walk again
		self.tfstate &= ~TFSTATE_ASSAULTCANNON;
		TeamFortress_SetSpeed(self);

		player_run ();
	}

	// check for attack
    if (self.button0 && !(self.fire_held_down)) {
		if ((self.current_menu == MENU_CLASSHELP) || (self.current_menu == MENU_CLASSHELP2)) {
			self.current_menu = MENU_REPEATHELP;
			self.menu_count = MENU_REFRESH_RATE;
			Attack_Finished(0.2);
		} else if (self.current_weapon == WEAP_SNIPER_RIFLE) {
			if (self.tfstate & TFSTATE_AIMING) {
				if (!W_CheckNoAmmo())
					self.tfstate &= ~TFSTATE_AIMING;
				else if (self.height > 30) {
					self.height = self.height - 5;
					TF_zoom(self.height);
				}
			} else {
				tv = self.velocity;
				tv_z = 0;

				if (vlen(tv) <= WEAP_SNIPER_RIFLE_MAX_MOVE && W_CheckNoAmmo()) {
					// create the laser sight
					SniperSight_Create(0);
					self.heat = 30; // damage done 
							 // GR no, charging sniper rifle makes no sense, idiot
					#ifdef WEINER_SNIPER
						self.heat = 80;
					#endif
					
					self.height = 90;
					self.tfstate = self.tfstate | TFSTATE_AIMING;
	
					TeamFortress_SetSpeed(self);
				}
			}
		} else if (self.current_weapon == WEAP_ROCKET_LAUNCHER && self.tf_items & NIT_RL_LASER_SIGHT) {
			if (!(self.tfstate & TFSTATE_RL_LASER)) {
				// create the laser sight
				SniperSight_Create(1);
				self.tfstate = self.tfstate | TFSTATE_RL_LASER;

				SuperDamageSound ();
				W_Attack ();

				TeamFortress_SetSpeed(self);
			}
		} else {
			SuperDamageSound ();
			W_Attack ();
		}
	} else if (self.playerclass == PC_UNDEFINED) {
		self.weaponmode = 0;
	} else if (self.tfstate & TFSTATE_AIMING) {
		W_Attack();
		self.tfstate = self.tfstate - TFSTATE_AIMING;
		TeamFortress_SetSpeed(self);
		self.heat = 0;
	} else if (self.tfstate & TFSTATE_RL_LASER) {
		//CH the dot should remove itself
		Attack_Finished(0.5); //Finish it up
		self.tfstate = self.tfstate - TFSTATE_RL_LASER;
		TeamFortress_SetSpeed(self);

		player_run ();
	}
};

/*
================
T_DaedalusTouch
Combination conc, krac and RL
================
*/
#define BOUNCE 120
void() T_DaedalusTouch =
{
	local float points = 0; //XXX false +ve
	local vector org;
	local entity head;

	head = findradius(self.origin, BOUNCE);	
	while (head) {
		//Conc
		if (head.takedamage && !IsBuilding(head)) {
			org = head.origin + (head.mins + head.maxs)*0.5;
			points = 0.5*vlen (org - self.origin);
			if (points < 0) points = 0;
				points = BOUNCE - points;
			if (points > 0) {
				head.velocity = org - self.origin;
				head.velocity = head.velocity * (points / 20);
				if (head.cutf_items & CUTF_GYMNAST)
					head.velocity = head.velocity * (points / 20);
				if (head.classname != "player" && head.flags & FL_ONGROUND)
					head.flags = head.flags - FL_ONGROUND;
			}
		}
		if (head.takedamage) {
			//Krac
			if (IsBuilding(head))
				TF_T_Damage (head, self, self.owner, 100, TF_TD_NOTTEAM, TF_TD_FIRE);
			//Rocket Launcher (w/ armor stripping)
			else {
				if (head.armorvalue > 35) head.armorvalue = head.armorvalue - 35;				
				else head.armorvalue = 0;
				deathmsg = DMSG_DAEDALUS;
				TF_T_Damage (head, self, self.owner, points / 8, TF_TD_NOTTEAM, TF_TD_FIRE);
			}
		}
		head = head.chain;
	}

	WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
	WriteByte (MSG_MULTICAST, TE_EXPLOSION);
	WriteCoord (MSG_MULTICAST, self.origin_x);
	WriteCoord (MSG_MULTICAST, self.origin_y);
	WriteCoord (MSG_MULTICAST, self.origin_z);
	multicast (self.origin, MULTICAST_PHS);

    if (other.classname == "force_field") //- OfN - Makes field explosion b4 removing it
        FieldExplosion(other,self.origin,self);

	dremove(self);
};

/*
================
W_FireDaedalus (WK)
================
*/
void() W_FireDaedalus =
{
	sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
	KickPlayer(-2, self);

	self.currentammo = self.ammo_cells = self.ammo_cells - 5;
	if (self.ammo_cells < 0) {
		self.ammo_cells = 0;
		return;
	}
	
	SuperDamageSound();
	
	newmis = spawn ();
	newmis.owner = self;
	newmis.movetype = MOVETYPE_FLYMISSILE;
    newmis.classname = "rocket"; // OfN - for airfist pushing
	newmis.solid = SOLID_BBOX;
		
	makevectors (self.v_angle);
	newmis.velocity = v_forward;	
	newmis.velocity = newmis.velocity * 500;
	newmis.avelocity = '600 600 0';
	newmis.angles = vectoangles(newmis.velocity);
	newmis.skin = 1;
	//CHANGEME Replace this with s_explode sprite. :)
	setmodel (newmis, "progs/flare.mdl");
	setsize (newmis, '0 0 0', '0 0 0');		
	setorigin (newmis, self.origin + v_forward*8 + '0 0 16');

	newmis.touch = T_DaedalusTouch;
	newmis.nextthink = time + 4;
	newmis.think = SUB_Remove;
};

/* Sponsored by SB-1 Tech
**
** W_FireMauser!
** Fires the mauser spy thing which is likely to have a name change
** so nyeh
*/

void() W_FireMauser =
{
	local vector org;
	local vector source;

	self.currentammo = self.ammo_nails = self.ammo_nails - 1;

	if (self.ammo_nails < 0) {
		self.ammo_nails = 0;
		return;
	}
	
	KickPlayer(-2, self);

	makevectors(self.v_angle);
	source = self.origin + '0 0 16';
	
	traceline (source, source + v_forward*100, FALSE, self);
	
	if (trace_fraction == 1.0)
		return;
	
	org = trace_endpos - v_forward*4;

	if (trace_ent.takedamage) {
		trace_ent.axhitme = 1;
		
		SpawnBlood (org, 20);
		deathmsg = DMSG_MAUSER;
		SuperDamageSound();
		TF_T_Damage(trace_ent, self, self, 20, TF_TD_NOTTEAM, TF_TD_SHOT);
		if (trace_ent.classname == "player")
		{
			TF_T_Damage(trace_ent, self, self, 50+200*random(), TF_TD_NOTTEAM + TF_TD_IGNOREARMOUR, TF_TD_OTHER);
			sprint(trace_ent, PRINT_HIGH, "Your nerves scream as poison floods your veins...\n");
		}
	} else {
       if (trace_ent.classname == "force_field") { //- OfN - Makes field explosion
            FieldExplosion(trace_ent,trace_endpos,trace_ent);
            PutFieldWork(trace_ent);
       }
    }
	
	newmis = spawn();
	newmis.owner = self;
	newmis.heat = 0;
	newmis.think = MauserRecoilThink;
	newmis.nextthink = time + 0.1;
};

void () MauserRecoilThink =
{

	self.owner.weaponframe = self.heat = self.heat + 1;
	
	if (self.heat >= 6) {
		self.owner.weaponframe = 0;
		dremove(self);
		return;
	}

	self.nextthink = time + 0.1;

};

/*
========
SuperDamageSound

Plays sound if needed
========
*/
void() SuperDamageSound =
{
	if (self.super_damage_finished > time) {
		if (self.super_sound < time) {
			self.super_sound = time + 1;
			sound (self, CHAN_BODY, "items/damage3.wav", 1, ATTN_NORM);
		}
	} else if (self.aura == AURA_POWER) {
		if (self.super_sound < time)
		{
			self.super_sound = time + 1;
			sound (self, CHAN_BODY, "auras/aura2.wav", 1, ATTN_NORM);
		}
	} else if (self.aura == AURA_HASTE) {
		if (self.super_sound < time) {
			self.super_sound = time + 1;
			sound (self, CHAN_BODY, "auras/aura4.wav", 1, ATTN_NORM);
		}
	}
	return;
};

/*===========================================================
// laser cannon stuff (from hipnotic)
//==========================================================
*/
void() HIP_LaserTouch =
{
	local vector org;
	local vector spot1,spot2;
	local vector oldvel;
//	local float r;

	self.owner = NIL;
	self.cnt = self.cnt + 1;
	if (pointcontents(self.origin) == CONTENTS_SKY) {
		remove(self);
		return;
	}
	oldvel = normalize(self.neworigin);
	spot1 = self.origin - (16*oldvel);
	spot2 = self.origin + (16*oldvel);
	traceline (spot1, spot2, FALSE, self);  // see through other monsters
	self.origin = trace_endpos;

	org = self.origin;

	if (other.health) {
//		other.deathtype = "hiplaser";
		if (self.owner == other)
			self.dmg = self.dmg / 2;
   
		spawn_touchblood (self.dmg);

		//- OfN laser hurts monsters a lot
		if (IsMonsterNonArmy(other))
			self.dmg = self.dmg * 2;

		//- scrags get rapped by the laser
		if (other.classname == "monster_wizard")
			self.dmg = self.dmg * 2; // this is *4

		deathmsg = DMSG_LASERCANNON;
		TF_T_Damage (other, self, self.demon_one, self.dmg, TF_TD_NOTTEAM, TF_TD_ELECTRICITY);
	} else if ((self.cnt >= 3) || (random() < 0.15)) {
		WriteByte (MSG_MULTICAST, SVC_TEMPENTITY);
		WriteByte (MSG_MULTICAST, TE_GUNSHOT);
		WriteByte (MSG_MULTICAST, 3);
		WriteCoord (MSG_MULTICAST, org_x);
		WriteCoord (MSG_MULTICAST, org_y);
		WriteCoord (MSG_MULTICAST, org_z);
		multicast (org, MULTICAST_PHS);
	} else {
//		self.dmg = 0.66 * self.dmg;
		self.dmg = 0.9 * self.dmg;
//		self.speed = 0.95 * self.speed;
		self.velocity = oldvel+(2*trace_plane_normal);
		self.velocity = normalize(self.velocity);
		self.velocity = self.speed * self.velocity;
		self.neworigin = self.velocity;
		if (self.flags & FL_ONGROUND)
			self.flags = self.flags - FL_ONGROUND;
//		r = random();
//		self.attack_finished = time + 7; //ofn - restart its life of 7 seconds

		if (other.classname == "force_field") //- OfN - Makes field explosion
			FieldExplosion(other,self.origin,self);
		sound (self, CHAN_WEAPON, "weapons/laserric.wav", 1, ATTN_STATIC);
		return;
	}

	if (other.classname == "force_field") //- OfN - Makes field explosion b4 removing it
		FieldExplosion(other,self.origin,self);

	sound (self, CHAN_WEAPON, "enforcer/enfstop.wav", 1, ATTN_STATIC);
	dremove(self);
};

void() HIP_LaserThink =
{
//	local float delta; //unused?

	if (time>self.attack_finished) {
		remove(self);
		return;
	}
	if (self.flags & FL_ONGROUND)
		self.flags = self.flags - FL_ONGROUND;
	self.velocity = self.neworigin;
	self.angles = vectoangles(self.velocity);
	self.nextthink = time+0.15;
};

void(vector org, vector vec, float light) HIP_LaunchLaser =
{
//	sound (self ,CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
	sound (self ,CHAN_WEAPON, "weapons/laserg.wav", 1, ATTN_NORM);

	vec = normalize(vec);

	newmis = spawn();
	newmis.owner = self;
	newmis.classname = "hiplaser";
	newmis.demon_one = self; // was "lastvictim" field of hipnotic // OfN needed because .owner is removed later 
	newmis.movetype = MOVETYPE_FLYMISSILE;
	newmis.solid = SOLID_BBOX;
//	if (light)
//		newmis.effects = EF_DIMLIGHT;

	setmodel (newmis, "progs/lasrspik.mdl");
	setsize (newmis, '0 0 0', '0 0 0');

	setorigin (newmis, org);

	newmis.speed = 1000;
	newmis.dmg = LASER_CANNON_DMG;
	newmis.velocity = vec * newmis.speed;
	newmis.neworigin = newmis.velocity; // was last_velocity field on hypnotic source code
	newmis.angles = vectoangles(newmis.velocity);
	newmis.avelocity = '0 0 400';

	newmis.nextthink = time;
	newmis.attack_finished = time + 3.5; //was 3.5//OfN- they last for 7 seconds now
	newmis.think = HIP_LaserThink;
	newmis.touch = HIP_LaserTouch;
	newmis.count = 0;
};

/*
=================
HIP_FireLaser
=================
*/
void(float stat) HIP_FireLaser =
{
	local vector org;
	local vector dir;
	local vector out;
	local float ofs;
	local float aofs;

	if (!self.button0) {
		player_run ();
		return;
	}
	if (self.ammo_cells < 1) {
		self.weapon = W_BestWeapon ();
		W_SetCurrentAmmo ();
		return;
	}

	SuperDamageSound();
	muzzleflash();
	makevectors (self.v_angle);

	ofs = 6;
	out = v_forward;
	out_z = 0;
	out = normalize(out);
	org = self.origin + ((12-ofs) * v_up) + (12*out);
//	org = self.origin + (1*v_forward);
	dir = aim (self, 1000);
	aofs = ofs * 0.707;
	if (stat == 0) {
		self.currentammo = self.ammo_cells = self.ammo_cells - 1;
//		org = org + (aofs*v_right);
		org = org - (aofs*v_up);
		HIP_LaunchLaser(org, dir, 0);
//		org = org - (2*aofs*v_right);
//		HIP_LaunchLaser(org, dir, 0);
	} else if (stat == 1) {
		self.currentammo = self.ammo_cells = self.ammo_cells - 1;
		org = org + (ofs*v_up);
//		if (random()<0.1) {
//			HIP_LaunchLaser(org, dir, 1);
//			newmis.dmg = 25;
//		} else
		HIP_LaunchLaser(org, dir, 0);
	}
	msg_entity = self;
	WriteByte (MSG_ONE, SVC_SMALLKICK);

	self.reload_laser_cannon = self.reload_laser_cannon + 1;

	if (CheckForReload() == TRUE)
		return;
};