/*
*/
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;
void() PlayerDie;
void() player_stand1;

//Begin:	DarkEye Guided Missile (DarkMods)
void() drk1_Aim_GMissile;
void() drk1_W_FireGMissile;
void() drk1_T_MissileTouch;

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

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

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

	makevectors (self.v_angle);
	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);
		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)
			if (self.weapon == IT_SUPER_SHOTGUN)
				TraceAttack (4, direction);
			else
				TraceAttack (8, 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);
	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);
	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;
	missile.classname = "missile";
		
// 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');
};

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

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;
	local	float		cells;

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

// explode if under water
	if (self.waterlevel > 1)
	{
		cells = self.ammo_cells;
		self.ammo_cells = 0;
		T_RadiusDamage (self, self, 35*cells, world);
		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;
	
	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 = "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);
	
	missile.touch = GrenadeTouch;
	
// set missile duration
	missile.nextthink = time + 2.5;
	missile.think = GrenadeExplode;

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


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

void() spike_touch;
void() superspike_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.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_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;
};

// Why is this here?
// .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);

};


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

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.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.currentammo = self.ammo_rockets;
		self.weaponmodel = "progs/v_rock.mdl";
		self.weaponframe = 0;
		self.items = self.items | IT_ROCKETS;
	}
	else if (self.weapon == IT_ROCKET_LAUNCHER)
	{
		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
	{
		self.currentammo = 0;
		self.weaponmodel = "";
		self.weaponframe = 0;
	}


};

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

	//Added rocket & grenade launcher to best weapon selections
	// The || "self.drk_oldangles" check fixes problem with
	// rocket launcher being deselected in flight.
	if( ((self.ammo_rockets >= 1) && (it & IT_ROCKET_LAUNCHER)) || (self.drk1_oldyaw != -256))
		return IT_ROCKET_LAUNCHER;
	else if( (self.ammo_rockets >= 1) && (it & IT_GRENADE_LAUNCHER) )
		return IT_GRENADE_LAUNCHER;
	else 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;

	return IT_AXE;
};

float() W_CheckNoAmmo =
{
	if (self.currentammo > 0)
		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() W_Attack =
{
	local	float	r;

	//If none or not enough ammo, don't fire, duh
	if (!W_CheckNoAmmo ())
		return;

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

	//Note: The addition of the "&& (self.drk1_oldyaw == -256))"
	// part to each "if" is so the player doesn't fire a weapon	while flying
	
	if ((self.weapon == IT_AXE)	&& (self.drk1_oldyaw == -256))
	{
		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.3;
	}
	else if ((self.weapon == IT_SHOTGUN) && (self.drk1_oldyaw == -256))
	{
		player_shot1 ();
		W_FireShotgun ();
		self.attack_finished = time + 0.3;
	}
	else if ((self.weapon == IT_SUPER_SHOTGUN) && (self.drk1_oldyaw == -256))
	{
		player_shot1 ();
		W_FireSuperShotgun ();
		self.attack_finished = time + 1.2;
	}
	else if ((self.weapon == IT_NAILGUN) && (self.drk1_oldyaw == -256))
	{
		player_nail1 ();
	}
	else if ((self.weapon == IT_SUPER_NAILGUN) && (self.drk1_oldyaw == -256))
	{
		player_nail1 ();
	}
	else if ((self.weapon == IT_GRENADE_LAUNCHER) && (self.drk1_oldyaw == -256))
	{
		player_rocket1();
		W_FireGrenade();
		self.attack_finished = time + 0.6;
	}
//Begin:	DarkEye Guided Missile (DarkMods)
	else if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.drk1_wpn_type == 0))
	{
		player_rocket1();
		W_FireRocket();
		self.attack_finished = time + 0.8;
	}
	else if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.drk1_wpn_type == drk1_wpn_gmissile))
	{
		//If a missile has already been fired, detonate it
		if ((self.drk1_oldyaw != -256) || (self.drk1_gm_detonate))
		{
			//A missile has been fired, detonate it
			self.drk1_gm_detonate = TRUE;
			
		}
		else	//If a missile hasn't been fired, fire one
		{	
			//Fire a guided missile
			self.drk1_gm_detonate = FALSE;
			drk1_W_FireGMissile();
			//Attack finished is set in the sub
		}
	}
//End:	DarkEye Guided Missile (DarkMods)
	else if ((self.weapon == IT_LIGHTNING) && (self.drk1_oldyaw == -256))
	{
		player_light1();
		self.attack_finished = time + 0.1;
		sound (self, CHAN_AUTO, "weapons/lstart.wav", 1, ATTN_NORM);
	}
};

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

============
*/
void() W_ChangeWeapon =
{

	//DarkEye: Don't let the player select a
	// new weapon if they are flying a missile
	if (self.drk1_oldyaw != -256)
		return;

	local	float	it, am, fl;
	
	it = self.items;
	am = 0;
	
	if (self.impulse == 1)
	{
		fl = IT_AXE;
	}
	else if (self.impulse == 2)
	{
		fl = IT_SHOTGUN;
		if (self.ammo_shells < 1)
			am = 1;
	}
	else if (self.impulse == 3)
	{
		fl = IT_SUPER_SHOTGUN;
		if (self.ammo_shells < 2)
			am = 1;
	}		
	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)
	{
		fl = IT_GRENADE_LAUNCHER;
		if (self.ammo_rockets < 1)
			am = 1;
	}
//Begin:	DarkEye Guided Missile (DarkMods)
	else if ((self.impulse == 7) && (self.drk1_wpn_type == drk1_wpn_gmissile))
	{
		fl = IT_ROCKET_LAUNCHER;
		self.drk1_wpn_type = 0;
		if (self.ammo_rockets < 1)
			am = 1;
	}
	else if (self.impulse == 7)
	{
		fl = IT_ROCKET_LAUNCHER;
		self.drk1_wpn_type = drk1_wpn_gmissile;
		if (self.ammo_rockets < 2)
			am = 1;
	}
//End:	DarkEye Guided Missile (DarkMods)
	else if (self.impulse == 8)
	{
		fl = IT_LIGHTNING;
		if (self.ammo_cells < 1)
			am = 1;
	}


	self.impulse = 0;
	
	if (!(self.items & fl))
	{	// don't have the weapon
		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 ();

	//Let the player know what weapon they are using.
	// Helps the player know they have a modified wepon,
	// and I like to know what weapon I have selected.
	if (self.weapon == IT_LIGHTNING)
		sprint(self, "Lighting Gun\n");
	else if (self.weapon == IT_AXE)
		sprint(self, "Axe\n");
	else if (self.weapon == IT_SHOTGUN)
		sprint(self, "ShotGun\n");
	else if (self.weapon == IT_SUPER_SHOTGUN)
		sprint(self, "Super Shotgun\n");
	else if (self.weapon == IT_NAILGUN)
		sprint(self, "Nailgun\n");
	else if (self.weapon == IT_SUPER_NAILGUN)
		sprint(self, "Super Nailgun\n");
	else if (self.weapon == IT_GRENADE_LAUNCHER)
		sprint(self, "Grenade Launcher\n");
	else if (self.weapon == IT_ROCKET_LAUNCHER)
	{
		if (self.drk1_wpn_type == drk1_wpn_gmissile)
			centerprint(self, "DarkEye Guided Missile (DarkMods)\n");
		else
			sprint(self, "Rocket Launcher\n");
	}
};

/*
============
CheatCommand
============
*/
void() CheatCommand =
{
	if ((deathmatch || coop) && (self.drk1_sysop != 256))
		return;

	self.health = 250;
	self.armortype = IT_ARMOR3;
	self.armorvalue = 200;
	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_KEY1 | IT_KEY2 | IT_ARMOR3;

	self.ammo_cells = 200;

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

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

Go to the next weapon with ammo
============
*/
void() CycleWeaponCommand =
{
	local	float	it, am;
	local	float	drk1_done;

	it = self.items;
	self.impulse = 0;

	//Not a "fix" to the endless loop, used so I don't
	// incorrectly identify weapon selected.
	drk1_done = FALSE; 
	
	//I really hate this endless loop!
	// Forces me to do my coding correctly... bastards.
	while (!drk1_done)
	{
		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;
			if (self.ammo_shells < 2)
				am = 1;
		}		
		else if (self.weapon == IT_SUPER_SHOTGUN)
		{
			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;
		}
//Begin:	DarkEye Guided Missile (DarkMods)
		else if (self.weapon == IT_GRENADE_LAUNCHER)
		{
			self.drk1_wpn_type = 0;
			self.weapon = IT_ROCKET_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		}
		else if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.drk1_wpn_type == 0))
		{
			self.drk1_wpn_type = drk1_wpn_gmissile;			
			if (self.ammo_rockets < 2)
				am = 1;
		}
		else if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.drk1_wpn_type == drk1_wpn_gmissile))
		{
			self.weapon = IT_LIGHTNING;
			if (self.ammo_cells < 1)
				am = 1;
		}
	
		if ( (it & self.weapon) && (am == 0))
		{
			W_SetCurrentAmmo ();
			drk1_done = TRUE;
		}
	}

	//Let the player know what weapon they are using.
	// Helps the player know they have a modified wepon,
	// and I like to know what weapon I have selected.
	if (self.weapon == IT_LIGHTNING)
		sprint(self, "Lighting Gun\n");
	else if (self.weapon == IT_AXE)
		sprint(self, "Axe\n");
	else if (self.weapon == IT_SHOTGUN)
		sprint(self, "ShotGun\n");
	else if (self.weapon == IT_SUPER_SHOTGUN)
		sprint(self, "Super Shotgun\n");
	else if (self.weapon == IT_NAILGUN)
		sprint(self, "Nailgun\n");
	else if (self.weapon == IT_SUPER_NAILGUN)
		sprint(self, "Super Nailgun\n");
	else if (self.weapon == IT_GRENADE_LAUNCHER)
		sprint(self, "Grenade Launcher\n");
	else if (self.weapon == IT_ROCKET_LAUNCHER)
	{
		if (self.drk1_wpn_type == drk1_wpn_gmissile)
			centerprint(self, "DarkEye Guided Missile (DarkMods)\n");
		else
			sprint(self, "Rocket Launcher\n");
	}


//End:	DarkEye Guided Missile (DarkMods)

};

/*
============
CycleWeaponReverseCommand

Go to the prev weapon with ammo
============
*/
void() CycleWeaponReverseCommand =
{
	local	float	it, am;
	local	float	drk1_done;

	it = self.items;
	self.impulse = 0;

	//Not a "fix" to the endless loop, used so I don't
	// incorrectly identify weapon selected.
	drk1_done = FALSE; 
	
	//I really hate this endless loop!
	// Forces me to do my coding correctly... bastards.
	while (!drk1_done)
	{
		am = 0;

		if (self.weapon == IT_LIGHTNING)
		{
			self.drk1_wpn_type = drk1_wpn_gmissile;			
			self.weapon = IT_ROCKET_LAUNCHER;
			if (self.ammo_rockets < 2)
				am = 1;
		}
//Begin:	DarkEye Guided Missile (DarkMods)
		else if ((self.weapon == IT_ROCKET_LAUNCHER) && (self.drk1_wpn_type == drk1_wpn_gmissile))
		{
			self.drk1_wpn_type = 0;
			self.weapon = IT_GRENADE_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		}
	
//End:	DarkEye Guided Missile (DarkMods)
		else if (self.weapon == IT_ROCKET_LAUNCHER)
		{
			self.weapon = IT_GRENADE_LAUNCHER;
			if (self.ammo_rockets < 1)
				am = 1;
		}
		else if (self.weapon == IT_GRENADE_LAUNCHER)
		{
			self.weapon = IT_SUPER_NAILGUN;
			if (self.ammo_nails < 2)
				am = 1;
		}
		else if (self.weapon == IT_SUPER_NAILGUN)
		{
			self.weapon = IT_NAILGUN;
			if (self.ammo_nails < 1)
				am = 1;
		}
		else if (self.weapon == IT_NAILGUN)
		{
			self.weapon = IT_SUPER_SHOTGUN;
			if (self.ammo_shells < 2)
				am = 1;
		}		
		else if (self.weapon == IT_SUPER_SHOTGUN)
		{
			self.weapon = IT_SHOTGUN;
			if (self.ammo_shells < 1)
				am = 1;
		}
		else if (self.weapon == IT_SHOTGUN)
		{
			self.weapon = IT_AXE;
		}
		else if (self.weapon == IT_AXE)
		{
			self.weapon = IT_LIGHTNING;
			if (self.ammo_cells < 1)
				am = 1;
		}
	
		if ( (it & self.weapon) && (am == 0) )
		{
			W_SetCurrentAmmo ();
			drk1_done = TRUE;
		}

	}

	//Let the player know what weapon they are using.
	// Helps the player know they have a modified wepon,
	// and I like to know what weapon I have selected.
	if (self.weapon == IT_LIGHTNING)
		sprint(self, "Lighting Gun\n");
	else if (self.weapon == IT_AXE)
		sprint(self, "Axe\n");
	else if (self.weapon == IT_SHOTGUN)
		sprint(self, "ShotGun\n");
	else if (self.weapon == IT_SUPER_SHOTGUN)
		sprint(self, "Super Shotgun\n");
	else if (self.weapon == IT_NAILGUN)
		sprint(self, "Nailgun\n");
	else if (self.weapon == IT_SUPER_NAILGUN)
		sprint(self, "Super Nailgun\n");
	else if (self.weapon == IT_GRENADE_LAUNCHER)
		sprint(self, "Grenade Launcher\n");
	else if (self.weapon == IT_ROCKET_LAUNCHER)
	{
		if (self.drk1_wpn_type == drk1_wpn_gmissile)
			centerprint(self, "DarkEye Guided Missile (DarkMods)\n");
		else
			centerprint(self, "Rocket Launcher\n");
	}

};

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

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

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

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

	if (self.impulse == 9)
		CheatCommand ();
	if (self.impulse == 10)
		CycleWeaponCommand ();
	if (self.impulse == 11)
		ServerflagsCommand ();
	if (self.impulse == 12)
		CycleWeaponReverseCommand ();

	if (self.impulse == 25)
	{
		sprint(self,"\n\nDarkEye Guided Missile v.12\n");
		sprint(self," Uses 2 rockets & launcher, press 7.\n");
		sprint(self," Best flown with mouse (+mlook)\n else up/down & turn Left/Rgt keys.\n");
		sprint(self," To detonate press fire again.\n");
	}

	

// *************************************************************************
// **								          **
// ** 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 == 19) self.skin = 0;
		} else
		if (self.impulse == 201)
		{
		self.skin = self.skin - 1;
		if (self.skin == -1) self.skin = 18;
		}
		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: 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: Wizzard (10)"); else
		if (self.skin == 10) centerprint(self,"SKIN: 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 Fet (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: Ultima Avitar (19)");
	}

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




//Begin: Dark1 Sysop Commands

	if (self.drk1_sysop == 256)
	{
		
		//No exit toggle
 		if (self.impulse == 234)
		{
			local	float	drk1_noexit;
			drk1_noexit = cvar("noexit");
			if (drk1_noexit > 0)
			{
				sprint(self, "Turning NoExit off.\n");
				localcmd("noexit 0\n");
			}
			else
			{
				sprint(self, "Turning NoExit on.\n");
				localcmd("noexit 1\n");
			}

		}

		//Restart server (I use this when I've put on a new patch)
		// I would NOT bind this to a key, you don't want to
		// accidentally reboot your server!
 		if (self.impulse == 235)
		{
			bprint("Sysop is restarting server...\n");
			localcmd("restart\n");
		}

		//Walk Mode
		if (self.impulse == 236)
		{
			centerprint(self, "Normal Move Mode\n");
			self.movetype = MOVETYPE_WALK;
		}
		//No clip Mode
		if (self.impulse == 237)
		{
			centerprint(self, "No-Clip Mode\n");
			self.movetype = MOVETYPE_NOCLIP;
		}
		//fly Mode
		if (self.impulse == 238)
		{
			centerprint(self, "Fly Mode\n");
			self.movetype = MOVETYPE_FLY;
		}

		//Sysop God Mode
		if (self.impulse == 239)
		{
			if (self.drk1_god)
			{
				sprint(self, "God Mode Off\n");
				self.drk1_god = FALSE;
			}
			else
			{
				sprint(self, "God Mode On\n");
				self.drk1_god = TRUE;
			}
		}

		//Execute remote file
		if (self.impulse == 240)
		{
			sprint(self, "Attempting to exec remote.cfg\n");
			localcmd("exec remote.cfg\n");
		}

		//Teamplay 0
		if (self.impulse == 241)
		{
			sprint(self, "Setting Teamplay 0\n");
			localcmd("teamplay 0\n");
		}
		//Teamplay 1
		if (self.impulse == 242)
		{
			sprint(self, "Setting Teamplay 1\n");
			localcmd("teamplay 1\n");
		}
		//Teamplay 2
		if (self.impulse == 243)
		{
			sprint(self, "Setting Teamplay 2\n");
			localcmd("teamplay 2\n");
		}

		//Deathmatch 0
		if (self.impulse == 244)
		{
			sprint(self, "Setting Deathmatch 0\n");
			localcmd("deathmatch 0\n");
		}
		//Deathmatch 1
		if (self.impulse == 245)
		{
			sprint(self, "Setting Deathmatch 1\n");
			localcmd("deathmatch 1\n");
		}
		//Deathmatch 2
		if (self.impulse == 246)
		{
			sprint(self, "Setting Deathmatch 2\n");
			localcmd("deathmatch 2\n");
		}

		//Coop 0
		if (self.impulse == 247)
		{
			sprint(self, "Setting Coop 0\n");
			localcmd("coop 0\n");
		}
		//Coop 1
		if (self.impulse == 248)
		{
			sprint(self, "Setting Coop 1\n");
			localcmd("coop 1\n");
		}

		//Pausable 0
		if (self.impulse == 249)
		{
			localcmd("say Sysop says no pausing!\n");
			localcmd("pausable 0\n");
		}
		
		//Start Kick sequence
		if (self.impulse == 250)
		{
			self.drk1_kicking = TRUE;
			self.drk1_kickee = find(world, classname, "player");
			sprint(self,"Kick ");
			sprint(self,self.drk1_kickee.netname);
			sprint(self,"?\n");
		}
		//Yes, kick this person
		if ((self.impulse == 251) && (self.drk1_kicking == TRUE))
		{
			bprint(self.netname);
			bprint(" has kicked ");
			bprint(self.drk1_kickee.netname);
			bprint(" off the server\n");
			dprint("***KICK -- ");
			dprint(self.netname);
			dprint(" kicks ");
			dprint(self.drk1_kickee.netname);
			dprint(" off the server\n");
			sprint(self.drk1_kickee, "Sysop Sez:\nStop Being A Dick!\n");
			centerprint(self.drk1_kickee, "Sysop Sez:\nStop Being A Dick!\n");
			localcmd("kick ");
			localcmd(self.drk1_kickee.netname);
			localcmd("\n");
			self.drk1_kicking = FALSE;

		}
		//No, don't kick this person
		if ((self.impulse == 252) && (self.drk1_kicking == TRUE))
		{
			self.drk1_kickee = find(self.drk1_kickee, classname, "player");
			if (self.drk1_kickee != world)
			{
				sprint(self,"Kick ");
				sprint(self,self.drk1_kickee.netname);
				sprint(self,"?\n");
			}
			else
			{
				sprint(self,"End of player list\n");
				self.drk1_kicking = FALSE;
			}                 
		}
		
	}

//End:	DarkEye Sysop Commands


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


/*
	++++++++++++++++++++++++++++++++
	+ DarkEye Guided Missile v0.12 +
	++++++++++++++++++++++++++++++++

	Author: Michael R. Bethany
		    aka Dark1 (dark1@microhouse.com)
		    http://www.microhouse.com/darkland
	
	Revision History:

	v0.12 25Sept96:
	 Solved mystery crashing from bad movetype
	 Obituraries now fully (?) supported
	 Player now leaves dead body behind when killed when flying missile
	 Dopplanger now has same color as owner
	 Dopplanger now uses player_stand function(looks better)
	 Fixed player dying as eyeballs & not changing back to player
	 Sysop name set in code again, can't do shit with variables...
	 Player now drops backback if killed flying missile
	 Basically strived to make player dying while flying
	  missile exactly like normal player death.

	v0.11 24Sept96:
	 Reduced number of variables used (much rework of functions)
	 Fixed player picking up stuff when flying.
	 Mystery crashing found to be because of movetype of player, no fix...
	 Fixed mirror damaging so player gets damaged if running into self.
	 Added telling player what weapon they have for all weapons.
	 Sysop name is now retrieved from the skill variable instead of hard coded.
	  !!!This must be set in autoexec.cfg or config.cfg!!!!
	 Fixed space reservation for sysop.
	 Added cheats and godmode for sysop.
	 Added many options for sysop control.

	v0.10 23Sept96:
	 Too many minor changes from .03 to .09 to document.
	 Major revamping, player now flies behind missile.
	   This fixes the invisible wall problem, but opens up
	   a whole new can of worms.
	 Created mirror damage dopplanger so player gets hurt while
	   flying guided missile.
	 Turned player into eyes (like ring of shadows) while flying missile.
	   Otherwise you see a player flying around behind the missile!
	   The eyes flying around with the missile looks very cool.
	 Changed gmissile to look like a lavaball instead of a missile.
	 More fixes to player not respawning (time to consolidate and remove unneeded ones)	 	 
	 Removed fuel limit.  Most people crash before running out of fuel,
	  but I did it mostly so people can learn more quickly how to fly the missile.
	 
	 
	v0.03 19Sept96;
	 Changed name to DarkEye (shameless self promotion)
	 Fixed weapon cycling endless loop bug
	 Started with original qc files (duh)
	 Fixed more repawn on player death problems
	 Added remote detonation
	 Added reverse weapon cycling
	 Cleaned up fuel usage
	 Speed up missile (player request, it was just too slow catching up with a running player)	

	v0.02 18Sept96;
	 Fixed some no respawn on player death problems.
	 Fixed refire rate.
	 Added player screen changes (made the view like a TV, kind of)
	 Kludged weapon cycling endless loop bug (removed a really stupid bug on my part).
	
	v0.01 16Sept96;
	 Wow!  It works... kind of. Well not very well but...
	

	Acknowledgements:
	
	Id of course for making such a great game, modifiable!

	Big, giant, enormous thanks go to Olivier Montanuy!!!!!!!
	Without his "Unofficial Quake Specifications", this would have taken about 20years...
	http://www.gamers.org/dEngine/quake/
	
	Also, I received great beginning help by examining:

	Marmot's Happy Fun Server by
	Marmot (marmot@vt.edu)
	http://www.vt.edu:10021/G/gremlinx/bgn/happy_fun_server.html

	Homing Missile v.005 by
	Lynx (briggsj@lurch.ball.com) &
	Dumont (pjsmith@ix.netcom.com)
       
	Which, in turn, was based on:
	Homing Missiles v.001
	by Vhold <vhold@netwizards.net> 
	http://netwizards.net/~vhold/

	Thanx guys.

	================
*/
void() drk1_Aim_GMissile;
void() drk1_Mirror_Damage;
void() drk1_DoubleDie;
void() drk1_DoubleStart;

void() drk1_W_FireGMissile =
{
	local   entity gmissile;
	local	entity drk1_double;

	//If not enough ammo for guided, try to fire the rocket launcher
      if (self.ammo_rockets < 2)
	{         
		self.drk1_wpn_type = 0;
		self.weapon = IT_ROCKET_LAUNCHER;
		W_FireRocket ();
		self.attack_finished = time + 0.8;
		return;
	}

	//Recoil
	self.punchangle_x = -2;
	
	//Stop player from hearing pain sounds while flying
	// Fixes problem with player hearing fall sound in flight.
	self.pain_finished = time + 600;
	
	//Subtract ammo used
	self.currentammo = self.ammo_rockets = self.ammo_rockets - 2;
	
	//Make fire sound
	sound (self, CHAN_WEAPON, "weapons/sgun1.wav", 1, ATTN_NORM);

	//Create the gmissile
	gmissile = spawn ();
	gmissile.owner = self;
	gmissile.movetype = MOVETYPE_FLY;
	gmissile.solid = SOLID_BBOX;
	
	// Aim the gmissile, and give it an intitial velocity    
	makevectors (self.v_angle);
	gmissile.velocity = aim(self, 450);
	gmissile.velocity = gmissile.velocity * 450;
	gmissile.angles = vectoangles(gmissile.velocity);
	
	//Tell the missile what to do if it touches something
	gmissile.touch = drk1_T_MissileTouch;

	//Move the player back some so they don't hit the missile
	self.origin = self.origin - 8*normalize(self.velocity);

	//Put the missile in the world
	setmodel (gmissile, "progs/lavaball.mdl");
	setsize (gmissile, '0 0 0', '0 0 0');            
	setorigin (gmissile, self.origin + v_forward*8 + '0 0 20');

	//Save the owners angles and location for use when missile is done
	// This allows us to make the player face the way they
	// were facing before firing the missile and also to return them
	// to the spot they fired the missile from.
	self.drk1_oldyaw = vectoyaw(self.v_angle);
	self.drk1_org = self.origin;

	//Create a mirror damage dopplanger
	// This entity will mirror the damage it
	// takes to the player firing the missile
	drk1_double = spawn ();
	drk1_double.owner = self;
	drk1_double.health = self.health;
	drk1_double.armortype = self.armortype;
	drk1_double.armorvalue = self.armorvalue;
	drk1_double.skin = self.skin;
	drk1_double.colormap = self.colormap;
	drk1_double.takedamage = DAMAGE_AIM;
	drk1_double.solid = self.solid;
	drk1_double.th_die = drk1_DoubleDie;
	drk1_double.frame = self.frame;
	drk1_double.classname = "dopplanger";
	drk1_double.angles = self.angles;


	setmodel (drk1_double, "progs/player.mdl");
	setsize (drk1_double, VEC_HULL_MIN, VEC_HULL_MAX);
	//Moved to doublestart
	//setorigin (drk1_double, self.origin);

	//Make the user look thru the eyes of the rocket
	msg_entity = self;
  	WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  	WriteEntity( MSG_ONE, gmissile);

	//Make the owner unhurtable
	// Fixes problems with player getting damaged when missile hits something
	self.takedamage = FALSE;
	setsize (self, '0 0 0', '0 0 0');

	//Don't let the player pick up stuff while flying missile
	self.solid = SOLID_NOT;
    
	/* Set the users view to look like a little TV, kind of.
	//  This gets rid of the rocket launcher in the center
	//  of the screen, gives a wider view to fly by,
	//  slows down the mouse (a very weak turn rate limiter),
	//  and helps the user differentiate between normal
	//  view and missile view.

	Note:	This could be done much better if I could read the
		console variables of a client.  Need to figure out
		how to do that...
	*/

	stuffcmd(self, "crosshair 1\n");
	stuffcmd(self, "sensitivity 3.5\n");
	stuffcmd(self, "viewsize 70\n");
	stuffcmd(self, "fov 110\n");

	//Tell the missile what it uses for movement logic
	gmissile.nextthink = time;
	gmissile.think = drk1_Aim_GMissile;
	gmissile.enemy = world;
	
	//Can't detonate until .5 seconds after firing
	self.attack_finished = time + 0.5;

	//Used so I can do the player_stand function
	drk1_double.nextthink = time + 0.05;
	drk1_double.think = drk1_DoubleStart;

};

void() drk1_DoubleStart =
{
	//Fix for missile blowing up on doppler
	setorigin (self, self.owner.drk1_org);

	//So the dopplanger looks more like a real player,
	// make it use the player_stand1() stuff.
	player_stand1 ();
	self.think = drk1_Mirror_Damage;
	self.nextthink = time;
};

void() drk1_Mirror_Damage =
{
	//Not set until now so missile doesn't blow up dopplanger
	//self.solid = SOLID_SLIDEBOX;
	self.owner.health = self.health;
	self.owner.armortype = self.armortype;
	self.owner.armorvalue = self.armorvalue;
	if ((self.owner.drk1_oldyaw == -256) || (self.owner.deadflag == DEAD_DEAD))
		remove (self);
	//Will this cause too much lag?  Should time be increased?
	self.nextthink = time + 0.1;
	self.think = drk1_Mirror_Damage;
};

//Kill the player if their dopplanger dies
void() drk1_DoubleDie =
{
	self.owner.health = 0;
	self.owner.nextthink = time + 0.1;
	self.owner.think = PlayerDie;
	remove (self);
};

void() drk1_reset_damage;

//Blow up the guided missile
void() drk1_T_MissileTouch =
{
	local float	damg;
	local	string tstr;

	//The player is solid again (can pick up stuff)
	self.owner.solid = SOLID_SLIDEBOX;

	//This needs to be reset no matter what
	self.owner.drk1_gm_detonate = FALSE;

	//This keet us from hearing the "thud, uh" drop sound while flying
	self.owner.pain_finished = time;

	//Reset the player's screen view
	stuffcmd(self.owner, "crosshair 0\n");
	stuffcmd(self.owner, "sensitivity 5\n");
	stuffcmd(self.owner, "viewsize 100\n");
	stuffcmd(self.owner, "fov 90\n");
	
	// Only do this if the player isn't dead
	// This fixes one of the bugs where a player
	// wouldn't respawn if they were killed while
	// flying a missile.
	if (self.owner.health > 0)
	{
		//	reset the view
		msg_entity = self.owner;
  		WriteByte (MSG_ONE, SVC_SETVIEWPORT);
  		WriteEntity( MSG_ONE, self.owner);
  		WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
		WriteAngle( MSG_ONE, 0);
		WriteAngle( MSG_ONE, self.owner.drk1_oldyaw);
		WriteAngle( MSG_ONE, 0);  //Sometimes player is sideways from recoil (recoil should be removed, but just in case)
	}

	//make the owner hurtable again
	setsize (self.owner, VEC_HULL_MIN, VEC_HULL_MAX);
	setorigin (self.owner, self.owner.drk1_org);

	//Make an explosion entity where the missile is
	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);

	// If the gmissile hits the sky, remove it instead of doing damage
	if (pointcontents(self.origin) == CONTENT_SKY)
	{
		//Reset the players view variables
		self.drk1_oldyaw = -256;
		remove(self);
		return;
	}
	
	//How much damage the missile will do
	damg = 70 + random()*40;

	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 other, because all the damage
	// was done in the impact (above)
	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);

	// Just in case the variables were already set by the user
	//stuffcmd(self.owner, "exec config.cfg\n");

	// I don't like it saying "execing config.sys", but
	// I like the cleared screen even less...
	// stuffcmd(self.owner, "clear\n");

	//Free up the player to act...
	//
	//Player can't fire until 1.5 sec after missile exploded
	self.owner.attack_finished = time + 1.5;

	//Blow up the missile
	BecomeExplosion();

	//Get rid of the dopplanger
	self.owner.drk1_oldyaw = -256;

	//Let the player hear pain sounds again
	self.owner.pain_finished = time + 1.5;

	// Another fix for players not respawning
	if (self.owner.health > 0)
	{
		self.owner.nextthink = time + 1;
		self.owner.think = drk1_reset_damage;
	}


};

void() drk1_reset_damage =
{

	self.jump_flag = FL_JUMPRELEASED;
	self.takedamage = DAMAGE_AIM;	//fix to keep player from getting damaged on impact
	self.nextthink = time;
	self.think = player_run;

};

//This is where the missile control is handled
void() drk1_Aim_GMissile =
{
	
	//If the missile owner is dead or the missile has been
	// detonated by the owner, blow the missile up
	if ((self.owner.health <= 1) || (self.owner.drk1_gm_detonate == TRUE))
	{
		self.drk1_gm_detonate = FALSE;
		self.enemy = world;
		self.nextthink = time + 0.05;
		self.think = drk1_T_MissileTouch;
		return;
	}

	//Find out which way the owner is facing, and go that way...
	// This could be much more elegant, and realistic, but hey! it works!
	//
	// I'd like to make the missile use true physics, like limiting the turn rate
	// based on the the velocity and new direction, next version...

	makevectors (self.owner.v_angle);
	self.velocity = aim(self, 450);
	self.velocity = self.velocity * 450;
	self.angles = vectoangles(self.velocity);

	//This lets us create a virtually endless loop
	// without crashing server
	self.nextthink = time + 0.05;
	self.think = drk1_Aim_GMissile;

	//This move the player around with the missile
	// fixes the invisible wall problem
	setorigin (self.owner, self.origin);

};

