/*
  - Weapons.qc modified by Skarsnik. v. 1.2

 - Impulse 1 = Axe.
 - Impulse 2 = Shotgun/Double barrel shotgun.
 - Impulse 3 = Pipe bomb launcher/trigger pipebombs.
 - Impulse 4 = Nailgun.
 - Impulse 5 = Super-Nailgun.
 - Impulse 6 = Grenade/Nail bomb launcher.
 - Impulse 7 = Rocket/Homer launcher.
 - Impulse 8 = Lightning gun.
 - Impulse 9 = Laser.
 - Impulse 12 = Cheat. 
 - Impulse 13 = Fire a flare.
 - Impulse 20 = Throw backpack with some ammo.
 - Impulse 50 = Hologram (costs 10 power cells).
 - Impulse 200 = Change skin (forward).
 - Impulse 201 = Change skin (backwards).
 - Impulse 254 = Fiend cheat.
 - Impulse 255 = Quad cheat.

 More things added like:

  - Splat sound for axe.
  - Zombies on walls are now gibbable.
  - Lots more.. see skarmod*.txt for more info.

*/
void (entity targ, entity inflictor, entity attacker, float damage) T_Damage;
void () player_run;
void(entity bomb, entity attacker, float rad, entity ignore) T_RadiusDamage;
void(vector org, vector vel, float damage) SpawnBlood;
void() SuperDamageSound;

// called by worldspawn
void() W_Precache =
{

        precache_model ("shelcase.mdl"); // Shell casing.
        precache_sound ("shellhit.wav");  // Shell Casing.
        precache_model ("progs/pipebomb.mdl"); //Pipebomb
	precache_model ("progs/v_pipe.mdl"); //Pipebomb launcher!
        precache_model ("progs/g_laser.mdl"); //Laser Gun!
	precache_model ("progs/laser.mdl"); // Enforcer laser for flare
	precache_sound ("misc/power.wav");  // new rocket explosion
    	precache_model ("progs/quaddama.mdl");    //laser bolt
        precache_sound ("enforcer/enfire.wav");  // laser
        precache_sound ("enforcer/enfstop.wav"); // enforcer something
        precache_sound ("zombie/z_miss.wav");  // axe splat
        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
};

float() crandom =
{
	return 2*(random() - 0.5);
};
/*
================
W_FireAxe
================
*/
void() W_FireAxe =
{
	local	vector	source;
	local	vector	org;

	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)
	{
		trace_ent.axhitme = 1;
		SpawnBlood (org, '0 0 0', 20);
                sound (self, CHAN_WEAPON, "zombie/z_miss.wav", 1, ATTN_NORM);
		T_Damage (trace_ent, self, self, 20);
	}
	else
	{	// hit wall
		sound (self, CHAN_WEAPON, "player/axhit2.wav", 1, ATTN_NORM);
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		WriteByte (MSG_BROADCAST, TE_GUNSHOT);
		WriteCoord (MSG_BROADCAST, org_x);
		WriteCoord (MSG_BROADCAST, org_y);
		WriteCoord (MSG_BROADCAST, org_z);
	}
};


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


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, mpuff;
	local	vector	org;

	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, vector vel, float damage) SpawnBlood =
{
	particle (org, vel*0.1, 73, damage*2);
};

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

	vel = wall_velocity () * 0.2;
	SpawnBlood (self.origin + vel*0.01, vel, 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;

void() ClearMultiDamage =
{
	multi_ent = world;
	multi_damage = 0;
};

void() ApplyMultiDamage =
{
	if (!multi_ent)
		return;
	T_Damage (multi_ent, self, self, multi_damage);
};

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

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

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 - dir*4;

	if (trace_ent.takedamage)
	{
		SpawnBlood (org, vel*0.2, damage);
		AddMultiDamage (trace_ent, damage);
	}
	else
	{
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		WriteByte (MSG_BROADCAST, TE_GUNSHOT);
		WriteCoord (MSG_BROADCAST, org_x);
		WriteCoord (MSG_BROADCAST, org_y);
		WriteCoord (MSG_BROADCAST, org_z);
	}
};

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

Used by shotgun, super shotgun, 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;
	
	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*2048, FALSE, self);
		if (trace_fraction != 1.0)
			TraceAttack (4, direction);

		shotcount = shotcount - 1;
	}
	ApplyMultiDamage ();
};

/*
================
W_FireShotgun
================
*/

void() W_FireShotgun =
{
	local vector dir;

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

	self.punchangle_x = -2;
	
	self.currentammo = self.ammo_shells = self.ammo_shells - 1;
	dir = aim (self, 100000);

        eject_shell (self.origin + '0 0 16' + v_forward*3,dir); // ADDED FOR EJECT.QC

	FireBullets (6, dir, '0.04 0.04 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);	

	self.punchangle_x = -4;
	
	self.currentammo = self.ammo_shells = self.ammo_shells - 2;
	dir = aim (self, 100000);

	eject_shell (self.origin + '0 0 16' + v_forward*3,dir); // ADDED FOR EJECT.QC
        eject_shell (self.origin + '0 0 16' + v_forward*3,dir); // ADDED FOR EJECT.QC

	FireBullets (14, dir, '0.14 0.08 0');
};


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

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 =
{
	self.movetype = MOVETYPE_NONE;
	self.velocity = '0 0 0';
	self.touch = SUB_Null;
	setmodel (self, "progs/s_explod.spr");
	self.solid = SOLID_NOT;
	s_explode1 ();
};

void() T_MissileTouch =
{
	local float	damg;

	if (other == self.owner)
		return;		// don't explode on owner

	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		remove(self);
		return;
	}

	damg = 100 + random()*20;
	
	if (other.health)
	{
		if (other.classname == "monster_shambler")
			damg = damg * 0.5;	// mostly immune
		T_Damage (other, self, self.owner, damg );
	}

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

//	sound (self, CHAN_WEAPON, "weapons/r_exp3.wav", 1, ATTN_NORM);
	self.origin = self.origin - 8*normalize(self.velocity);

	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
	WriteByte (MSG_BROADCAST, TE_EXPLOSION);
	WriteCoord (MSG_BROADCAST, self.origin_x);
	WriteCoord (MSG_BROADCAST, self.origin_y);
	WriteCoord (MSG_BROADCAST, self.origin_z);

	BecomeExplosion ();
};

/*
================
W_FireRocket
================
*/
void() W_FireRocket =
{
	local	entity missile, mpuff;
	
	self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
	
	sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);

	self.punchangle_x = -2;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_FLYMISSILE;
	missile.solid = SOLID_BBOX;
		
// set missile speed	

	makevectors (self.v_angle);
	missile.velocity = aim(self, 1000);
	missile.velocity = missile.velocity * 1000;
	missile.angles = vectoangles(missile.velocity);
	
	missile.touch = T_MissileTouch;
	
// set missile duration
	missile.nextthink = time + 5;
	missile.think = SUB_Remove;

	setmodel (missile, "progs/missile.mdl");
	setsize (missile, '0 0 0', '0 0 0');		
	setorigin (missile, self.origin + v_forward*8 + '0 0 16');
};



/*
================
W_FireHomer
================
*/
void()   HomeThink;
entity() HomeFindTarget;
float(entity targ) visible;
float(entity targ) infront;

void() W_FireHomer =

{

// If player doesn't have 5 or more rockets, don't launch

	if (self.ammo_rockets < 5)

	{

	return;

	}



	local	entity missile, mpuff;

        if (self.currentammo < 5)
               self.currentammo = self.ammo_rockets = 0;
        else                
               self.currentammo = self.ammo_rockets = self.ammo_rockets - 5;
	
	sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);

	self.punchangle_x = -2;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_FLYMISSILE;
	missile.solid = SOLID_BBOX;
        missile.classname = "arocket";
		
// set missile speed	

	makevectors (self.v_angle);
	missile.velocity = aim(self, 1000);
	missile.velocity = missile.velocity * 300;
	missile.angles = vectoangles(missile.velocity);
	
	missile.touch = T_MissileTouch;
	
// set missile duration
//	missile.nextthink = time + 30;
//	missile.think = SUB_Remove;

	missile.nextthink = time + 0.2;
	missile.think = HomeThink;
	missile.enemy = world;

	setmodel (missile, "progs/missile.mdl");
	setsize (missile, '0 0 0', '0 0 0');		
	setorigin (missile, self.origin + v_forward*8 + '0 0 16');
};

entity() HomeFindTarget = 
{
	local entity head, selected;
	local float dist;
	dist = 100000;
	selected = world;
	head = findradius(self.origin, 100000);
	while(head)
	{
                if( (head.health > 1) && (head.classname != "misc_explobox") && (head != self) && (head != self.owner) && !(head.items & IT_INVISIBILITY) )
		{
			traceline(self.origin,head.origin,TRUE,self);
			if ( (trace_fraction >= 1) && (vlen(head.origin - self.origin) < dist) )
			{
				selected = head;
				dist = vlen(head.origin - self.origin);
			}
		}		
		head = head.chain;
	}
	if (selected != world)
	{
		sprint (self.owner,"Homing->");
		if (selected.classname == "player")
		{
			sprint (self.owner,selected.netname);
			sprint (selected,self.owner.netname);
			sprint (selected," has a HOMER on you!\n");
		}
		else
			sprint (self.owner,selected.classname);
		sprint (self.owner,"\n");
	}
	return selected;
};

void() HomeThink =
{
        local vector dir, olddir, vtemp;
        local float turnrate;

        turnrate= 0.2;
	if ( !(self.enemy) || (self.enemy == world) || (self.enemy.health < 1) )
		self.enemy = HomeFindTarget();

	if (self.enemy != world) // Arr.. don't be taken on da World!
	{
		vtemp = self.enemy.origin + '0 0 10';
                olddir = normalize(self.velocity);
		dir = normalize(vtemp - self.origin);
                //Limits the turnrate of the rockets
                if (olddir_x - dir_x > turnrate)
                        dir_x = olddir_x - turnrate;
                if (olddir_x - dir_x < -1 * turnrate)
                        dir_x = olddir_x + turnrate;
                if (olddir_y - dir_y > turnrate)
                        dir_y = olddir_y - turnrate;
                if (olddir_y - dir_y < -1 * turnrate)
                        dir_y = olddir_y + turnrate;
                if (olddir_z - dir_z > turnrate)
                        dir_z = olddir_z - turnrate;
                if (olddir_z - dir_z < -1 * turnrate)
                        dir_z = olddir_z + turnrate;
                self.velocity = dir * 230;
		self.angles = vectoangles(self.velocity);
	}

	self.nextthink = time + 0.2;
	self.think=HomeThink;
};
/*
===============================================================================

LIGHTNING

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

/*
=================
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 = world;

	traceline (p1, p2, FALSE, self);
	if (trace_ent.takedamage)
	{
		particle (trace_endpos, '0 0 100', 225, damage*4);
		T_Damage (trace_ent, from, from, damage);
		if (self.classname == "player")
		{
			if (other.classname == "player")
				trace_ent.velocity_z = trace_ent.velocity_z + 400;
		}
	}
	e1 = trace_ent;

	traceline (p1 + f, p2 + f, FALSE, self);
	if (trace_ent != e1 && trace_ent.takedamage)
	{
		particle (trace_endpos, '0 0 100', 225, damage*4);
		T_Damage (trace_ent, from, from, damage);
	}
	e2 = trace_ent;

	traceline (p1 - f, p2 - f, FALSE, self);
	if (trace_ent != e1 && trace_ent != e2 && trace_ent.takedamage)
	{
		particle (trace_endpos, '0 0 100', 225, damage*4);
		T_Damage (trace_ent, from, from, damage);
	}
};


void() W_FireLightning =
{
	local	vector		org;

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

// explode if under water
	if (self.waterlevel > 1)
	{
		T_RadiusDamage (self, self, 35*self.ammo_cells, world);
		self.ammo_cells = 0;
		W_SetCurrentAmmo ();
		return;
	}

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

	self.currentammo = self.ammo_cells = self.ammo_cells - 1;

	org = self.origin + '0 0 16';
	
	traceline (org, org + v_forward*600, TRUE, self);

	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
	WriteByte (MSG_BROADCAST, TE_LIGHTNING2);
	WriteEntity (MSG_BROADCAST, self);
	WriteCoord (MSG_BROADCAST, org_x);
	WriteCoord (MSG_BROADCAST, org_y);
	WriteCoord (MSG_BROADCAST, org_z);
	WriteCoord (MSG_BROADCAST, trace_endpos_x);
	WriteCoord (MSG_BROADCAST, trace_endpos_y);
	WriteCoord (MSG_BROADCAST, trace_endpos_z);

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


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


void() GrenadeExplode =
{
	T_RadiusDamage (self, self.owner, 120, world);

	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
	WriteByte (MSG_BROADCAST, TE_EXPLOSION);
	WriteCoord (MSG_BROADCAST, self.origin_x);
	WriteCoord (MSG_BROADCAST, self.origin_y);
	WriteCoord (MSG_BROADCAST, self.origin_z);

	BecomeExplosion ();
};

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 =
{
	local	entity missile, mpuff;

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

	self.punchangle_x = -2;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_BOUNCE;
	missile.solid = SOLID_BBOX;
	missile.classname = "grenade";
        missile.wait = time + 15 + 15*random();
		
// set missile speed	

	makevectors (self.v_angle);

	if (self.v_angle_x)
		missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
	else
	{
		missile.velocity = aim(self, 10000);
		missile.velocity = missile.velocity * 600;
		missile.velocity_z = 200;
	}

	missile.avelocity = '300 300 300';

	missile.angles = vectoangles(missile.velocity);
	
	missile.touch = GrenadeTouch;

        // If we have enough for a cluster, fire a cluster, otherwise
        // fire a bouncer.
        // Uncomment this block for CBP
/*        if (self.ammo_rockets > 4) {
                self.currentammo = self.ammo_rockets = self.ammo_rockets - 5;
                missile.nextthink = time + 2+(random()*3);
                missile.think = GrenadeDeploy;
        }
        else {*/
                self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
                missile.nextthink = time + 2.5;
                missile.think = GrenadeExplode;
                // Comment the above line and uncomment the next three below
                // to enable CBP Grenades.
                // missile.think = GrenadeThink;
                // missile.nextthink = time + 2+(random()*2);
//        }

        setmodel (missile, "progs/grenade.mdl");
	setsize (missile, '0 0 0', '0 0 0');		
	setorigin (missile, self.origin);
};


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


void() flare_touch;
void() flare_bright;
void() flare_dim;

void() spike_touch;
void() superspike_touch;



/*
=========================================================================
Flares Code Begins Here.
=========================================================================
*/
/*
================================
launch_flare

rework of id's launch_spike code
================================
*/
void(vector org, vector dir) launch_flare =
{
	local   entity  missile;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_FLYMISSILE;
	missile.solid = SOLID_BBOX;

	missile.angles = vectoangles(dir);

// go to flare_touch if the flare touches anything
	missile.touch = flare_touch;
	missile.classname = "spike";

// go to flare_bright when the flare's think time is up	
	missile.think = flare_bright;

// 3 seconds until flare goes bright
	missile.nextthink = time + 3;

// The LASER.MDL makes a decent flare
	setmodel (missile, "progs/laser.mdl");
	setsize (missile, VEC_ORIGIN, VEC_ORIGIN);		setorigin (missile, org);
	missile.velocity = dir * 1000;

// Make the flare dim. (.effects is an 8-bit register)
	missile.effects=8;

};
/*
============================
flare_touch
rework of id's spike_touch()
============================
*/
void() flare_touch =
{
local float rand;
	if (other == self.owner)	
		return;

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

	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		remove(self);
		return;
	}
	
// has the flare hit something that bleeds?
	if (other.takedamage)
	{
		// If so, spawn some blood
		spawn_touchblood (9);
		// also do one point of damage
		T_Damage (other, self, self.owner, 1);

/*
Don't remove the flare unless it is still flying. Otherwise, monsters orother players can come up and 'pull' your flare out of the wall
*/
	      if (self.velocity != '0 0 0')
			remove(self);
	}
	else
	{
        //Write information to the network
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);		WriteByte (MSG_BROADCAST, TE_SPIKE);
		WriteCoord (MSG_BROADCAST, self.origin_x);		WriteCoord (MSG_BROADCAST, self.origin_y);
		WriteCoord (MSG_BROADCAST, self.origin_z);
	}

//Stop the flare, but do not remove it.
	self.movetype = MOVETYPE_NONE;
	self.velocity = '0 0 0';
	self.touch = SUB_Null;

};
/*
==============================
flare_bright()
This function makes the flare
emit brighter light
==============================
*/
void() flare_bright =
{
	local vector    vel;
// Make the flare get BRIGHT by setting .effects bit
       	self.effects=4;
// Give it 10 seconds at maximum intensity
	self.nextthink = time + 10;
// After 10 seconds, call flare_dim
	self.think = flare_dim;
// Play a sound for flare ignition
	sound (self, CHAN_WEAPON, "misc/power.wav", 1, ATTN_NORM);

// Set up some red and yellow sparks
	vel = '0 0 150';
	particle (self.origin+vel*0.01,vel,111,150);
        vel = '0 0 120';
	particle (self.origin+vel*0.01,vel,73,200);
/*
==============================
flare_dim()
This function makes the flare
go dim again
==============================
*/
};
void() flare_dim =
{
// Make the flare get dim by setting .effects bit
        self.effects=8;
// Give it 15 seconds before burnout
	self.nextthink = time + 15;
// After 15 seconds remove the flare from the game
	self.think = SUB_Remove;
};


/*
===================================================================End of Flare Code  -    Steve Bond 8/1/96===================================================================
*/

/*
===============
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.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 * 1000;
};

void() W_FireSuperSpikes =
{
	local vector	dir;
	local entity	old;
	
	sound (self, CHAN_WEAPON, "weapons/spike2.wav", 1, ATTN_NORM);
	self.attack_finished = time + 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;
	setmodel (newmis, "progs/s_spike.mdl");
	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);		
	self.punchangle_x = -2;
};

void(float ox) W_FireFlare =
{
	local vector    dir;
	local entity    old;

	makevectors (self.v_angle);
		sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);
	self.attack_finished = time + 0.5;
	dir = aim (self, 1000);
	launch_flare (self.origin + '0 0 24' + v_right*ox, dir);
	self.punchangle_x = -2;	dprint ("Flare Away!                      v.9");
};


void(float ox) W_FireSpikes =
{
	local vector	dir;
	local entity	old;
	
	makevectors (self.v_angle);
	
	if (self.ammo_nails >= 2 && self.weapon == IT_SUPER_NAILGUN)
	{
		W_FireSuperSpikes ();
		return;
	}

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

	sound (self, CHAN_WEAPON, "weapons/rocket1i.wav", 1, ATTN_NORM);
	self.attack_finished = time + 0.2;
	self.currentammo = self.ammo_nails = self.ammo_nails - 1;
	dir = aim (self, 1000);
	launch_spike (self.origin + '0 0 16' + v_right*ox, dir);

	self.punchangle_x = -2;
};



.float hit_z;
void() spike_touch =
{
local float rand;
	if (other == self.owner)
		return;

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

	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		remove(self);
		return;
	}
	
// hit something that bleeds
	if (other.takedamage)
	{
		spawn_touchblood (9);
		T_Damage (other, self, self.owner, 9);
	}
	else
	{
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		
		if (self.classname == "wizspike")
			WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
		else if (self.classname == "knightspike")
			WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
		else
			WriteByte (MSG_BROADCAST, TE_SPIKE);
		WriteCoord (MSG_BROADCAST, self.origin_x);
		WriteCoord (MSG_BROADCAST, self.origin_y);
		WriteCoord (MSG_BROADCAST, self.origin_z);
	}

	remove(self);

};

void() superspike_touch =
{
local float rand;
	if (other == self.owner)
		return;

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

	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		remove(self);
		return;
	}
	
// hit something that bleeds
	if (other.takedamage)
	{
		spawn_touchblood (18);
		T_Damage (other, self, self.owner, 18);
	}
	else
	{
		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
		WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);
		WriteCoord (MSG_BROADCAST, self.origin_x);
		WriteCoord (MSG_BROADCAST, self.origin_y);
		WriteCoord (MSG_BROADCAST, self.origin_z);
	}

	remove(self);

};

/*
 ------------------------------------------
 Pipe Bombs
 ------------------------------------------
*/

/*
 * Blow up the toys.  There is a range of 1000 units (pixels?), so you can't
 * go wandering off.
 */
 
void() DetPipeBombs =
{
        local entity    head;

        head = findradius (self.origin, 1000);
        while(head)
        {
                if((head.classname == "pipebomb") && (head.owner == self))
                        head.nextthink = time;
                head = head.chain;
        }
};

/*
 * What happens if it touches something
 */
 
void() PipeBombTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner
	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

/*
 * Fires a pipe bomb.  Can be detonated at any time.  Doesn't need a special
 * weapon selected.
 */

void() W_FirePipeBomb =
{
	local	entity missile, mpuff;
	
	if(self.ammo_rockets < 1)	// have to have ammo
	  return;
	self.currentammo = self.ammo_rockets = self.ammo_rockets - 1;
	
//	sound (self, CHAN_WEAPON, "weapons/grenade.wav", 1, ATTN_NORM);

//	self.punchangle_x = -2;

	missile = spawn ();
	missile.owner = self;
	missile.movetype = MOVETYPE_BOUNCE;
	missile.solid = SOLID_BBOX;
	missile.classname = "pipebomb";
		
// set missile speed	

	makevectors (self.v_angle);

	if (self.v_angle_x)
		missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;
	else
	{
		missile.velocity = aim(self, 10000);
		missile.velocity = missile.velocity * 600;
		missile.velocity_z = 200;
	}

	missile.avelocity = '300 300 300';

	missile.angles = vectoangles(missile.velocity);
	
	missile.touch = PipeBombTouch;
	missile.think = GrenadeExplode;
	
        setmodel (missile, "progs/pipebomb.mdl");
	setsize (missile, '0 0 0', '0 0 0');		
	setorigin (missile, self.origin);
};

/*
=====================
LASER STUFF -- Shyft
=====================
*/

void() Laser_Touch; //Enforcer.qc Laser_touch() modified to change player dmg

void(vector vec) PLaser = 
{   sound (self, CHAN_WEAPON, "enforcer/enfire.wav", 1, ATTN_NORM);
   
	vec = normalize(vec);
	
	newmis = spawn();
	newmis.owner = self;
	newmis.movetype = MOVETYPE_FLY;
	newmis.solid = SOLID_BBOX;
	newmis.effects = EF_DIMLIGHT;

	setmodel (newmis, "progs/laser.mdl");
    setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);  
        
    setorigin (newmis, self.origin + v_forward*8 + '0 0 16');
    newmis.velocity = aim(self, 1000);
    newmis.velocity = newmis.velocity * 600;

    newmis.angles = vectoangles(newmis.velocity);

	newmis.nextthink = time + 5;
	newmis.think = SUB_Remove;
    newmis.touch = Laser_Touch;

};

void() W_FireLaser =
{
   	self.effects = self.effects | EF_MUZZLEFLASH;
    makevectors (self.v_angle);
    self.currentammo = self.ammo_cells = self.ammo_cells - 1;
    PLaser(self.enemy.origin - self.origin);
};




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

BOUNCING FRAGMENTATION GRENADE - Version .9

7/28/96 - Steve Bond  email:wedge@nuc.net

http://www.nuc.net/quake

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



//This code segment handles the impact of shrapnel

//this is merely id's superspike_touch code, reworked

void() shrapnel_touch =

{

local float rand;

// has the shrapnel hit a switch? 

	if (other.solid == SOLID_TRIGGER)

		return; // trigger field, do nothing



// has the shrapnel hit the sky?

	if (pointcontents(self.origin) == CONTENT_SKY)

	{

		remove(self);

		return;

	}

	

// has the shrapnel hit a living thing?

	if (other.takedamage)

	{

		spawn_touchblood (33);

		T_Damage (other, self, self.owner, 33);

	}

	else

	{

		WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);

		WriteByte (MSG_BROADCAST, TE_SUPERSPIKE);

		WriteCoord (MSG_BROADCAST, self.origin_x);

		WriteCoord (MSG_BROADCAST, self.origin_y);

		WriteCoord (MSG_BROADCAST, self.origin_z);

	}

	remove(self);

};



/*

Code to spawn ONE randomly directed piece of shrapnel

this is id's launch_spike code, reworked

Pass a vector to this function to determine the shrap's origin

*/

void (vector org, float spin) launch_shrapnel=

{

	local float xdir,ydir,zdir;

	

//Assign a random direction for the shrapnel to fly in

	xdir = 110 * random() - 55;

	ydir = 110 * random() - 55;

	zdir = 50 * random() - 25;



	newmis = spawn ();

	newmis.owner = self;

	newmis.movetype = MOVETYPE_BOUNCE;

	self.touch = SUB_Null;

	newmis.solid = SOLID_BBOX;



	newmis.touch = shrapnel_touch;

	newmis.classname = "spike";

	newmis.think = SUB_Remove;

	

// this is how many seconds(?) the nails can exist.        

	newmis.nextthink = time + 6;

	

// speed at which to move the shrapnel        

	newmis.velocity_x = xdir * 5;

	newmis.velocity_y = ydir * 5;

	newmis.velocity_z = zdir * 4;



/*

as best I can figure, AVELOCITY means "attitude velocity"        

or something thereabouts. Anyway, it makes shit spin on 

the x,y,z axes by the given velocity for each axis. In this 

case, it makes the shrapnel spin in flight. Good stuff.

this segment assigns one of five preset attitudes for 

each piece of shrapnel, based on the number passed to the

function.

*/        

	if (spin == 0)

	newmis.avelocity='250 300 400';

	if (spin == 1)

	newmis.avelocity='400 250 300';

	if (spin == 2)

	newmis.avelocity='300 400 250';

	if (spin == 3)

	newmis.avelocity='300 300 300';

	if (spin == 4) 

	newmis.avelocity='400 250 400';



	setmodel (newmis, "progs/s_spike.mdl");

	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);

	setorigin (newmis, org);

};



// This code segment detonates the 'second stage' of the grenade

// (After it has popped up)

void()  BouncerExplode =

{

	

// Do the damage

	T_RadiusDamage (self, self.owner, 120, world);

// Tell the network

	WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);

	WriteByte (MSG_BROADCAST, TE_EXPLOSION);

	WriteCoord (MSG_BROADCAST, self.origin_x);

	WriteCoord (MSG_BROADCAST, self.origin_y);

	WriteCoord (MSG_BROADCAST, self.origin_z);



// Let Quake handle the explosion and deallocation of the grenade        

	self.solid=SOLID_NOT;

	BecomeExplosion ();



// Launch a hail (20 pieces) of shrapnel

	launch_shrapnel (self.origin + '0 0 -1',0);

	launch_shrapnel (self.origin + '0 0 -1',1);

	launch_shrapnel (self.origin + '0 0 -1',2);

	launch_shrapnel (self.origin + '0 0 -1',3);

	launch_shrapnel (self.origin + '0 0 -1',4);

	launch_shrapnel (self.origin + '0 0 -1',0);

	launch_shrapnel (self.origin + '0 0 -1',1);

	launch_shrapnel (self.origin + '0 0 -1',2);

	launch_shrapnel (self.origin + '0 0 -1',3);

	launch_shrapnel (self.origin + '0 0 -1',4);

	launch_shrapnel (self.origin + '0 0 -1',0);

	launch_shrapnel (self.origin + '0 0 -1',1);

	launch_shrapnel (self.origin + '0 0 -1',2);

	launch_shrapnel (self.origin + '0 0 -1',3);

	launch_shrapnel (self.origin + '0 0 -1',4);

	launch_shrapnel (self.origin + '0 0 -1',0);

	launch_shrapnel (self.origin + '0 0 -1',1);

	launch_shrapnel (self.origin + '0 0 -1',2);

	launch_shrapnel (self.origin + '0 0 -1',3);

	launch_shrapnel (self.origin + '0 0 -1',4);

};



/*

This code segment makes the 'first stage' of the bouncer pop upward

after it's time has expired.

*/

void() BouncerPopUp=

{

	local entity missile, mpuff;



// Make the grenade stop

	self.movetype=MOVETYPE_NONE;

	self.velocity='0 0 0';

// Draw a tiny explosion (no particles)        

	setmodel (self, "progs/s_explod.spr");

	s_explode1 ();

// Make the :FOOMP: grenade launcher sound        

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

// Spawn and animate the 'second stage'

	missile = spawn ();

	missile.owner = self;

	missile.movetype = MOVETYPE_BOUNCE;

	missile.solid = SOLID_BBOX;

	missile.classname = "grenade";

// Set speed

	missile.velocity = '0 0 650';

	missile.angles = vectoangles(missile.velocity);

	missile.touch = BouncerExplode;

// Set Duration

	missile.nextthink = time + 1;

	missile.think = BouncerExplode;



	setmodel (missile, "progs/missile.mdl");

	setsize (missile, '0 0 0', '0 0 0');

	setorigin (missile, self.origin);

};



// This code segment handles collisions for the 'first stage'

// Of the grenade (after launch and before popup)



void() BouncerTouch =

{

//Did the grenade hit a 'living' thing?

	if (other.takedamage)

	{

// yes, so play the bounce sound

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

// now, exit the function without cause damage to the thing        

	return;

	}



// This controls what happens when the grenade hits walls, etz        

// It just plays the sound and bounces on

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

	if (self.velocity == '0 0 0')

		self.avelocity = '0 0 0';

};



/*

This code segment handles the launching of the Bouncing Fragmentation Grenade

this is a reworked copy of id's W_launchgrenade code

*/

void() W_LaunchBouncer =

{

// If player doesn't have 3 or more rockets, don't launch

	if (self.ammo_rockets < 3)

	{

	return;

	}



	local   entity missile, mpuff;

	

// Take 3 rockets from the player        

	self.currentammo = self.ammo_rockets = self.ammo_rockets - 3;

	

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

/*

self.punchangle_x (x, y, or z) defines how hard the weapon         

recoils (or 'punches' the player, making the screen shake)

*/        

	self.punchangle_x = -2;



// This spawns the grenade - it is all id's standard grenade code        

	missile = spawn ();

	missile.owner = self;

	missile.movetype = MOVETYPE_BOUNCE;

	missile.solid = SOLID_BBOX;

	missile.classname = "grenade";

		

// set missile speed    



	makevectors (self.v_angle);



	if (self.v_angle_x)

		missile.velocity = v_forward*600 + v_up * 200 + crandom()*v_right*10 + crandom()*v_up*10;

	else

	{

		missile.velocity = aim(self, 10000);

		missile.velocity = missile.velocity * 600;

		missile.velocity_z = 200;

	}



	missile.avelocity = '300 300 300';



	missile.angles = vectoangles(missile.velocity);

	

// if the grenade touches anything, BouncerTouch() is called        

	missile.touch = BouncerTouch;

	

// Grenade has a maximum lifespan of 1.5 (seconds?)

// set missile duration

	missile.nextthink = time + 1.5;

	

// when the grenade's lifespan has expired, BouncerPopUp() is called        

	missile.think = BouncerPopUp;



	setmodel (missile, "progs/grenade.mdl");

	setsize (missile, '0 0 0', '0 0 0');            

	setorigin (missile, self.origin);

};

/*

===============================================================================

End of Bouncing Fragmentation Grenade code.

===============================================================================

*/


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

PLAYER WEAPON USE

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

void() W_SetCurrentAmmo =
{
	player_run ();		// get out of any weapon firing states

	self.items = self.items - ( self.items & (IT_SHELLS | IT_NAILS | IT_ROCKETS | IT_CELLS) );


        if (self.invincible_time)       // Fiend stuff
        {
		self.currentammo = 0;
                self.weaponmodel = "";
		self.weaponframe = 0;
        }

	if (self.weapon == IT_AXE)
	{
		self.currentammo = 0;
		self.weaponmodel = "progs/v_axe.mdl";
		self.weaponframe = 0;
	}

	else if (self.weapon == IT_SHOTGUN)

	{
		self.currentammo = self.ammo_shells;
		self.weaponmodel = "progs/v_shot.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_SHELLS;
	}

	else if (self.weapon == IT_SUPER_SHOTGUN)
	{
		self.currentammo = self.ammo_shells;
		self.weaponmodel = "progs/v_shot2.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_SHELLS;
	}

	else if (self.weapon == IT_NAILGUN)
	{
		self.currentammo = self.ammo_nails;
		self.weaponmodel = "progs/v_nail.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_NAILS;
	}
	else if (self.weapon == IT_SUPER_NAILGUN)
	{
		self.currentammo = self.ammo_nails;
		self.weaponmodel = "progs/v_nail2.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_NAILS;
	}
	else if ((self.weapon == IT_GRENADE_LAUNCHER) || (self.weapon == IT_NAILBOMB))
	{
		self.currentammo = self.ammo_rockets;
		self.weaponmodel = "progs/v_rock.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_ROCKETS;
	}

	else if (self.weapon == IT_PIPEBOMB)
	{
		self.currentammo = self.ammo_rockets;
		self.weaponmodel = "progs/v_pipe.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_ROCKETS;
	}

	else if (self.weapon == IT_ROCKET_LAUNCHER || (self.weapon == IT_HOMER))
	{
		self.currentammo = self.ammo_rockets;
		self.weaponmodel = "progs/v_rock2.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_ROCKETS;
	}
	else if (self.weapon == IT_LIGHTNING)
	{
		self.currentammo = self.ammo_cells;
		self.weaponmodel = "progs/v_light.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_CELLS;
	}
    else if (self.weapon == IT_LASER)
	{
		self.currentammo = self.ammo_cells;
        self.weaponmodel = "progs/g_laser.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_CELLS;
    }
	else
	{
		self.currentammo = 0;
		self.weaponmodel = "";
		self.weaponframe = 0;
	}
};

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

	if(self.ammo_cells >= 1 && (it & IT_LIGHTNING) )
		return IT_LIGHTNING;
	else if(self.ammo_nails >= 2 && (it & IT_SUPER_NAILGUN) )
		return IT_SUPER_NAILGUN;
	else if(self.ammo_shells >= 2 && (it & IT_SUPER_SHOTGUN) )
		return IT_SUPER_SHOTGUN;
	else if(self.ammo_nails >= 1 && (it & IT_NAILGUN) )
		return IT_NAILGUN;
	else if(self.ammo_shells >= 1 && (it & IT_SHOTGUN) )
		return IT_SHOTGUN;
		
/*
	if(self.ammo_rockets >= 1 && (it & IT_ROCKET_LAUNCHER) )
		return IT_ROCKET_LAUNCHER;
	else if(self.ammo_rockets >= 1 && (it & IT_GRENADE_LAUNCHER) )
		return IT_GRENADE_LAUNCHER;

*/

	return IT_AXE;
};

float() W_CheckNoAmmo =
{
	if (self.currentammo > 0)
		return TRUE;

	if (self.invincible_time)
		return TRUE;

	if (self.weapon == IT_AXE)
		return TRUE;
	
	self.weapon = W_BestWeapon ();

	W_SetCurrentAmmo ();
	
// drop the weapon down
	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_shot1;
void()	player_nail1;
void()	player_light1;
void()	player_rocket1;
void()  	player_dattack;

void() W_Attack =
{
	local	float	r;

	if (!W_CheckNoAmmo ())
		return;

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

	if (self.invincible_time)	// Fiend stuff
        {
                self.attack_finished = time + 1;
                player_dattack();
        }

	else if (self.weapon == IT_AXE)
	{
		sound (self, CHAN_WEAPON, "weapons/ax1.wav", 1, ATTN_NORM);
		r = random();
		if (r < 0.25)
			player_axe1 ();
		else if (r<0.5)
			player_axeb1 ();
		else if (r<0.75)
			player_axec1 ();
		else
			player_axed1 ();
		self.attack_finished = time + 0.5;
	}
	else if (self.weapon == IT_SHOTGUN)
	{
		player_shot1 ();
		W_FireShotgun ();
		self.attack_finished = time + 0.5;
	}
	else if (self.weapon == IT_SUPER_SHOTGUN)
	{
		player_shot1 ();
		W_FireSuperShotgun ();
		self.attack_finished = time + 0.7;
	}
	else if (self.weapon == IT_NAILGUN)
	{
		player_nail1 ();
	}
	else if (self.weapon == IT_SUPER_NAILGUN)
	{
		player_nail1 ();
	}
	else if (self.weapon == IT_GRENADE_LAUNCHER)
	{
		player_rocket1();
		W_FireGrenade();
		self.attack_finished = time + 0.6;
	}
	else if (self.weapon == IT_ROCKET_LAUNCHER)
	{
		player_rocket1();
		W_FireRocket();
                self.attack_finished = time + 0.8;
	}
	else if (self.weapon == IT_LIGHTNING)
	{
		player_light1();
		self.attack_finished = time + 0.1;
		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
	}
   else if (self.weapon == IT_LASER)         //SHYFT ADD
	{
        player_shot1();
        W_FireLaser();
        self.attack_finished = time + 0.2;
	}
	else if (self.weapon == IT_NAILBOMB)
	{
		W_LaunchBouncer();
		self.attack_finished = time + 0.4;
	}
	else if (self.weapon == IT_HOMER)
	{
		W_FireHomer();
		self.attack_finished = time + 0.6;
	}	
	else if (self.weapon == IT_PIPEBOMB)
	{
                player_rocket1();
		W_FirePipeBomb();
                self.attack_finished = time + 0.4;
	}


};

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

============
*/
void() W_ChangeWeapon =
{
	local	float	it, am, fl;
	
	it = self.items;
	am = 0;
	
	if (self.impulse == 1)
	{
		fl = IT_AXE;
	}
	else if (self.impulse == 2)
	{
	if (self.weapon == IT_SHOTGUN)
		{


			fl = IT_SUPER_SHOTGUN;       // IT_SHOTGUN
                        if (!(self.items & fl))
                 {       // don't have the weapon or the ammo
                         sprint (self, "no weapon.\n");
                         return;
                  }
			self.weapon = IT_SUPER_SHOTGUN;
			centerprint(self,"Super Shotgun mode\n");
			return;
		}

		fl = IT_SHOTGUN;
		if (self.ammo_shells < 1)
			am = 1;
		if (!am) centerprint(self,"Shotgun Mode\n");
	}
	else if (self.impulse == 3)
	{
	if (self.weapon == IT_PIPEBOMB)
		{
			DetPipeBombs();
			centerprint(self,"Pipebomb triggered\n");
			return;
		}

		fl = IT_PIPEBOMB;
		if (self.ammo_rockets < 1)
			am = 1;
		if (!am) centerprint(self,"Pipebomb Mode\n");
	}


	else if (self.impulse == 4)
	{
		fl = IT_NAILGUN;
		if (self.ammo_nails < 1)
			am = 1;
	}
	else if (self.impulse == 5)
	{
		fl = IT_SUPER_NAILGUN;
		if (self.ammo_nails < 2)
			am = 1;
	}
	else if (self.impulse == 6)
	{
	if (self.weapon == IT_GRENADE_LAUNCHER)
		{ 
			self.weapon = IT_NAILBOMB;
			centerprint(self,"Nailbomb mode\n");
			return;
		} 

		fl = IT_GRENADE_LAUNCHER;
		if (self.ammo_rockets < 1)
			am = 1;
		if (!am) centerprint(self,"Grenade Launcher Mode\n");
	}
	else if (self.impulse == 7)
	{
		if (self.weapon == IT_ROCKET_LAUNCHER)
		{ 
			self.weapon = IT_HOMER;
			centerprint(self,"Homer mode\n");
			return;
		} 
	
		fl = IT_ROCKET_LAUNCHER;
		if (self.ammo_rockets < 1)
			am = 1;
		if (!am) centerprint(self,"Rocket Launcher Mode\n");
	}
	else if (self.impulse == 8)
	{
		fl = IT_LIGHTNING;
		if (self.ammo_cells < 1)
			am = 1;
	}
    else if (self.impulse == 9)       // SHYFT ADD
	{
        fl = IT_LASER;
		if (self.ammo_cells < 1)
			am = 1;
	}
	self.impulse = 0;
	
	if (!(self.items & fl))
	{	// don't have the weapon or the ammo
		sprint (self, "no weapon.\n");
		return;
	}
	
	if (am)
	{	// don't have the ammo
		sprint (self, "not enough ammo.\n");
		return;
	}

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

/*
============
CheatCommand
============
*/
void() CheatCommand =
{
	if (deathmatch || coop)
		return;

	self.ammo_rockets = 100;
	self.ammo_nails = 200;
	self.ammo_shells = 100;
	self.items = self.items | 
		IT_AXE |
		IT_SHOTGUN |
		IT_SUPER_SHOTGUN |
		IT_NAILGUN |
		IT_SUPER_NAILGUN |
		IT_GRENADE_LAUNCHER |
		IT_ROCKET_LAUNCHER |
        	IT_LASER |
		IT_PIPEBOMB |
		IT_KEY1 | IT_KEY2;

	self.ammo_cells = 200;
	self.items = self.items | IT_LIGHTNING;

	self.weapon = IT_ROCKET_LAUNCHER;
	self.impulse = 0;
	W_SetCurrentAmmo ();
};

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

Go to the next weapon with ammo
============
*/
void() CycleWeaponCommand =
{
	local	float	it, am;
	
	it = self.items;
	self.impulse = 0;
	
	while (1)
	{
		am = 0;

		if (self.weapon == IT_LIGHTNING)
		{
			self.weapon = IT_AXE;
		}
		else if (self.weapon == IT_AXE)
		{
			self.weapon = IT_SHOTGUN;
			if (self.ammo_shells < 1)
				am = 1;
		}
		else if ((self.weapon == IT_SHOTGUN) || (self.weapon == IT_SUPER_SHOTGUN))
		{
			self.weapon = IT_PIPEBOMB;
			if (self.ammo_shells < 2)
				am = 1;
		}		

		else if (self.weapon == IT_PIPEBOMB)
		{
			self.weapon = IT_NAILGUN;
			if (self.ammo_nails < 1)
				am = 1;
		}


		else if (self.weapon == IT_NAILGUN)
		{
			self.weapon = IT_SUPER_NAILGUN;
			if (self.ammo_nails < 2)
				am = 1;
		}
		else if (self.weapon == IT_SUPER_NAILGUN)
		{
			self.weapon = IT_GRENADE_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		}
		else if ((self.weapon == IT_GRENADE_LAUNCHER) || (self.weapon == IT_NAILBOMB))
		{
			self.weapon = IT_ROCKET_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		}
		else if ((self.weapon == IT_ROCKET_LAUNCHER) || (self.weapon == IT_HOMER))
		{
           self.weapon = IT_LASER;                   //SHYFT ADD
			if (self.ammo_cells < 1)
				am = 1;
		}
        else if (self.weapon == IT_LASER)
		{
			self.weapon = IT_LIGHTNING;
			if (self.ammo_cells < 1)
				am = 1;
		}
	
		if ( (self.items & self.weapon) && am == 0)
		{
			W_SetCurrentAmmo ();
			return;
		}
	}

};

/*
============
ServerflagsCommand

Just for development
============
*/
void() ServerflagsCommand =
{
	serverflags = serverflags * 2 + 1;
};

void() QuadCheat =
{
	if (deathmatch || coop)
		return;
	self.super_time = 1;
	self.super_damage_finished = time + 30;
	self.items = self.items | IT_QUAD;
	dprint ("quad cheat\n");
};

void() FiendCheat =
{
        // No Cheating during net games.
        if (deathmatch || coop)
                return;
        self.invincible_time = 1;
        self.invincible_finished = time + 120;
        self.weaponmodel = "";
        self.view_ofs = '0 0 4';
        self.items = self.items | IT_INVULNERABILITY;
        dprint ("You fiend!\n");
};

/*
=======================
ThrowBackpack by Vhold
=======================
*/
void() ThrowBackpack =
{
	local entity 	item;

	if ( (self.ammo_shells + self.ammo_nails + self.ammo_rockets + self.ammo_cells) == 0)
		return;

	item = spawn();

        if ( self.ammo_shells >= 20)
	{
		item.ammo_shells = 20;
		self.ammo_shells = self.ammo_shells - 20;
	}
	else
	{
		item.ammo_shells = self.ammo_shells;
		self.ammo_shells = 0;
	}
	
        if ( self.ammo_nails >= 20)
	{
		item.ammo_nails = 20;
                self.ammo_nails = self.ammo_nails - 20;
	}
	else
	{
		item.ammo_nails = self.ammo_nails;
		self.ammo_nails = 0;
	}

	if ( self.ammo_rockets >= 10)
	{
		item.ammo_rockets = 10;
		self.ammo_rockets = self.ammo_rockets - 10;
	}
	else
	{
		item.ammo_rockets = self.ammo_rockets;
                self.ammo_rockets = 0;
	}

	if (self.ammo_cells >= 20)
	{	
		item.ammo_cells = 20;
		self.ammo_cells = self.ammo_cells - 20;
	}
	else
	{
		item.ammo_cells = self.ammo_cells;
		self.ammo_cells = 0;
	}

	item.owner = self;
	makevectors(self.v_angle);
	setorigin(item, self.origin + '0 0 16');
	item.velocity = aim(self, 1000);
	item.velocity = item.velocity * 500;
	item.flags = FL_ITEM;
	item.solid = SOLID_TRIGGER;
	item.movetype = MOVETYPE_BOUNCE;

	setmodel (item, "progs/backpack.mdl");
	setsize(item, '-16 -16 0', '16 16 56');
	item.touch = BackpackTouch;
	item.nextthink = time + 120;	// remove after 2 minutes
	item.think = SUB_Remove;

	W_SetCurrentAmmo();
};
/*
============
ImpulseCommands

============
*/
void() ImpulseCommands =
{
	CheckHoloCommand ();

	if (self.impulse >= 1 && self.impulse <= 9)
		W_ChangeWeapon ();

	if (self.impulse == 10)
		CycleWeaponCommand ();

	if (self.impulse == 10)
		CycleWeaponCommand ();
	if (self.impulse == 11)
		ServerflagsCommand ();

	if (self.impulse == 12)
		CheatCommand ();


        // Stove Bond's flare
	if (self.impulse == 13)
		W_FireFlare ();

	// Vhold's Backpack thing
	if (self.impulse == 20)
		ThrowBackpack();

// *************************************************************************
// **								          **
// ** M U L T I S K I N  1.1  (start)                                     **
// **									  **
// *************************************************************************


	if ((self.impulse == 200) || (self.impulse == 201))
	{
		if (self.impulse == 200)
		{
		self.skin = self.skin + 1;
                if (self.skin == 48) self.skin = 0;
		} else
		if (self.impulse == 201)
		{
		self.skin = self.skin - 1;
                if (self.skin == -1) self.skin = 47;
		}
		if (self.skin == 0) centerprint(self, "SKIN: Quake himself (1)"); else
		if (self.skin == 1) centerprint(self, "SKIN: Duke Nukem 3d (2)"); else
		if (self.skin == 2) centerprint(self, "SKIN: Mr. Toad (3)"); else
		if (self.skin == 3) centerprint(self, "SKIN: the Stormtrooper (4)"); else
		if (self.skin == 4) centerprint(self, "SKIN: Max (5)"); else
		if (self.skin == 5) centerprint(self, "SKIN: the Terminator (6)"); else
		if (self.skin == 6) centerprint(self, "SKIN: Judge Dredd (7)"); else
		if (self.skin == 7) centerprint(self, "SKIN: Camouflaged soldier (8)"); else
		if (self.skin == 8) centerprint(self, "SKIN: Captain Picard (9)"); else
		if (self.skin == 9) centerprint(self, "SKIN: the Wizzard (10)"); else
		if (self.skin == 10) centerprint(self,"SKIN: the Predator (11)"); else
		if (self.skin == 11) centerprint(self,"SKIN: Skeleton 12)"); else
		if (self.skin == 12) centerprint(self,"SKIN: Wan-Fu (13)"); else
		if (self.skin == 13) centerprint(self,"SKIN: Henry Rollins (14)"); else
		if (self.skin == 14) centerprint(self,"SKIN: He-Man (15)"); else
		if (self.skin == 15) centerprint(self,"SKIN: Boba (16)"); else
		if (self.skin == 16) centerprint(self,"SKIN: Superman (17)"); else

		if (self.skin == 17) centerprint(self,"SKIN: NYPD Cop (18)"); else
		if (self.skin == 18) centerprint(self,"SKIN: Red/Yellow women dude (19)"); else

		if (self.skin == 19) centerprint(self,"SKIN: Zombie (20)"); else
		if (self.skin == 20) centerprint(self,"SKIN: Homer Simpson (21)"); else
		if (self.skin == 21) centerprint(self,"SKIN: Mario (22)"); else
		if (self.skin == 22) centerprint(self,"SKIN: 311 soldier (23)"); else
		if (self.skin == 23) centerprint(self,"SKIN: Ninja guy 1 (24)"); else
		if (self.skin == 24) centerprint(self,"SKIN: Deadpool (25)"); else
		if (self.skin == 25) centerprint(self,"SKIN: Bonehead (26)"); else
		if (self.skin == 26) centerprint(self,"SKIN: Black spiderman (27)"); else
		if (self.skin == 27) centerprint(self,"SKIN: Old cop (28)"); else
		if (self.skin == 28) centerprint(self,"SKIN: The Punisher (29)"); else
		if (self.skin == 29) centerprint(self,"SKIN: Stormtrooper 2 (30)"); else
		if (self.skin == 30) centerprint(self,"SKIN: Evil Quake (31)"); else
		if (self.skin == 31) centerprint(self,"SKIN: Hans Solo (32)"); else
		if (self.skin == 32) centerprint(self,"SKIN: Batman (33)"); else
		if (self.skin == 33) centerprint(self,"SKIN: Biosuit (34)"); else
		if (self.skin == 34) centerprint(self,"SKIN: Bosk (35)"); else
		if (self.skin == 35) centerprint(self,"SKIN: Dark Flash Gordon (36)"); else
		if (self.skin == 36) centerprint(self,"SKIN: Doom soldier (37)"); else
		if (self.skin == 37) centerprint(self,"SKIN: Enforcer (38)"); else
		if (self.skin == 38) centerprint(self,"SKIN: Evil Eye (39)"); else
		if (self.skin == 39) centerprint(self,"SKIN: Flash Gordon (40)"); else
		if (self.skin == 40) centerprint(self,"SKIN: Hell Knight (41)"); else
		if (self.skin == 41) centerprint(self,"SKIN: Jason (42)"); else
		if (self.skin == 42) centerprint(self,"SKIN: Knight (43)"); else
		if (self.skin == 43) centerprint(self,"SKIN: The Incredible MoleMan! (44)"); else
		if (self.skin == 44) centerprint(self,"SKIN: Ogre (45)"); else
		if (self.skin == 45) centerprint(self,"SKIN: Ninja 2 (46)"); else
		if (self.skin == 46) centerprint(self,"SKIN: Rage Against The Machine! (47)"); else
		if (self.skin == 47) centerprint(self,"SKIN: Quake Spawn (48)");
	
	}

// *************************************************************************
// **								          **
// ** M U L T I S K I N  1.1  (end)                                       **
// **									  **
// *************************************************************************

	if (self.impulse == 254)
		FiendCheat ();

	if (self.impulse == 255)
		QuadCheat ();
		
	self.impulse = 0;
};

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

Called every frame so impulse events can be handled as well as possible
============
*/
void() W_WeaponFrame =
{
	if (time < self.attack_finished)
		return;

	ImpulseCommands ();
	
// check for attack
	if (self.button0)
	{
		SuperDamageSound ();
		W_Attack ();
	}
};

/*
========
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);
		}
	}
	return;
};


