/*
	TeamFortress 1.0	-	10/8/96

	Robin Walker, John Cook, Ian Caughley.

	Functions specific to the TeamFortress QuakeC patch.
*/

// Function declarations
void() GrenadeExplode;
void() spike_touch;

// Impulse Functions
void() TeamFortress_ChangeClass;
void() TeamFortress_Help;
void() TeamFortress_Inventory;
void() TeamFortress_PrimeGrenade;
void() TeamFortress_ThrowGrenade;
void() TeamFortress_DetonatePipebombs;

// Player Class Handling Functions
void() TeamFortress_SetHealth;
void() TeamFortress_SetEquipment;
void() TeamFortress_SetSpeed;
float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo;
float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon;
float(entity Retriever, entity Armor) TeamFortress_CanGetArmor;
float(entity Retriever, entity Items) TeamFortress_AddBackpackItems;

// Weapon Handling Functions
void() TeamFortress_SniperWeapon;
void() TeamFortress_ExplodePerson;
void() NormalGrenadeTouch;
void() NormalGrenadeExplode;
void() ConcussionGrenadeTouch;
void() ConcussionGrenadeExplode;
void() ConcussionGrenadeTimer;
void() NailGrenadeTouch;
void() NailGrenadeExplode;
void() NailGrenadeNailEm;
void() NailGrenadeLaunchNail;
void() MirvGrenadeTouch;
void() MirvGrenadeExplode;
void(vector org, entity shooter) MirvGrenadeLaunch;
void() PipebombTouch;

// Item Handling Functions
void(float scanrange) TeamFortress_Scan;
void(float timer) TeamFortress_SetDetpack;
void() TeamFortress_DetpackSet;
void() TeamFortress_DetpackExplode;
void() TeamFortress_DetpackTouch;

// Utility Functions
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce;
entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan;

// Cyclic Event Functions
void() TeamFortress_Regenerate;
void() TeamFortress_CheckforCheats;

//=========================================================================
// IMPULSE FUNCTIONS
//=========================================================================
//=========================================================================
// Player change class function
void() TeamFortress_ChangeClass =
{
	cvar_set("sv_maxspeed", "600");
	// Only change playerclass once
	if ( self.playerclass != PC_UNDEFINED )
		return;

	self.playerclass = self.impulse - TF_CHANGEPC;

	// Display chosen class, and Tell rest of the team
	if ( self.playerclass == PC_SCOUT )
	{
		sprint(self, "SCOUT.\n");
	}
	else if ( self.playerclass == PC_SNIPER )
	{
		sprint(self, "SNIPER.\n");
	}
	else if ( self.playerclass == PC_SOLDIER )
	{
		sprint(self, "SOLDIER.\n");
	}
	else if ( self.playerclass == PC_DEMOMAN )
	{
		sprint(self, "DEMOLITIONS MAN.\n");
	}
	else if ( self.playerclass == PC_MEDIC )
	{
		sprint(self, "COMBAT MEDIC.\n");
	}

	TeamFortress_SetEquipment();
	TeamFortress_SetHealth();
	TeamFortress_SetSpeed();
};

//=========================================================================
// Help for the Impulse commands in TeamFortress
void() TeamFortress_Help =
{
	local string imp;

	sprint(self, "Welcome to TeamFortress! v1.0\n");
	sprint(self, "Robin Walker, John Cook, Ian Cawley.");
	sprint(self, "====================================");
	sprint(self, "Impulse Commands are as follows:\n");
	sprint(self, "Inventory       :   ");
	imp = ftos(TF_INVENTORY);
	sprint(self, imp);
	sprint(self, "\nPrime Grenade 1 :   ");
	imp = ftos(TF_GRENADE_1);
	sprint(self, imp);
	sprint(self, "\nPrime Grenade 2 :   ");
	imp = ftos(TF_GRENADE_2);
	sprint(self, imp);
	sprint(self, "\nThrow Grenade   :   ");
	imp = ftos(TF_GRENADE_T);
	sprint(self, imp);
	sprint(self, "\nScanner Pre-Imp :   ");
	imp = ftos(TF_SCAN);
	sprint(self, imp);
	sprint(self, "\nToggle Friends  :   ");
	imp = ftos(TF_SCAN_FRIENDLY);
	sprint(self, imp);
	sprint(self, "\nToggle Enemies  :   ");
	imp = ftos(TF_SCAN_ENEMY);
	sprint(self, imp);
	sprint(self, "\nDetpack Pre-Imp :   ");
	imp = ftos(TF_DETPACK);
	sprint(self, imp);
	sprint(self, "\nDet. Pipebombs  :   ");
	imp = ftos(TF_PB_DETONATE);
	sprint(self, imp);
	sprint(self, "\nScout           :   ");
	imp = ftos(TF_CHANGEPC + PC_SCOUT);
	sprint(self, imp);
	sprint(self, "\nSniper          :   ");
	imp = ftos(TF_CHANGEPC + PC_SNIPER);
	sprint(self, imp);
	sprint(self, "\nSoldier         :   ");
	imp = ftos(TF_CHANGEPC + PC_SOLDIER);
	sprint(self, imp);
	sprint(self, "\nDemolitions Man :   ");
	imp = ftos(TF_CHANGEPC + PC_DEMOMAN);
	sprint(self, imp);
	sprint(self, "\nCombat Medic    :   ");
	imp = ftos(TF_CHANGEPC + PC_MEDIC);
	sprint(self, imp);
	sprint(self, "\nComments : walker@netspace.net.au\n");
	sprint(self, "Full command descriptions in Readme.txt\n");
	sprint(self, "Use pageup in the console to see all the impulses above :)\n");
};

//=========================================================================
// Displays the player's inventory
void() TeamFortress_Inventory =
{
	local string ac;

	// Display Number of Grenades of each type
	if (self.no_grenades_1 > 0)
	{
		ac = ftos(self.no_grenades_1);
		sprint(self, ac);
		if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
			sprint(self, " concussion");
		if (self.tp_grenades_1 == GR_TYPE_NAIL)
			sprint(self, " nail");
		if (self.tp_grenades_1 == GR_TYPE_MIRV)
			sprint(self, " Mirv");

		sprint(self, " grenades. ");
	}
	if (self.no_grenades_2 > 0)
	{
		ac = ftos(self.no_grenades_2);
		sprint(self, ac);
		if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
			sprint(self, " concussion");
		if (self.tp_grenades_2 == GR_TYPE_NAIL)
			sprint(self, " nail");
		if (self.tp_grenades_2 == GR_TYPE_MIRV)
			sprint(self, " Mirv");

		sprint(self, " grenades. ");
	}

	if (self.tf_items & NIT_SCANNER)
		sprint(self, "Scanner. ");

	if (self.secondary_items & NIT_MEDIKIT)
	{
		sprint(self, "Medikit (");
		ac = ftos(self.ammo_medikit);
		sprint(self, ac);
		sprint(self,") ");
	}
		
	sprint(self, "\n");
};

//=========================================================================
// Primes a grenade of the type corresponding to the player's impulse
void() TeamFortress_PrimeGrenade =
{
	local float gtype;
	local string gs, ptime;

	// If you've already primed a grenade, return
	if (self.grenadeprimed)
		return;

	if (self.impulse == TF_GRENADE_1)
	{
		gtype = self.tp_grenades_1;
		if (self.tp_grenades_1 == GR_TYPE_CONCUSSION)
			gs = "Concussion grenade";
		else if (self.tp_grenades_1 == GR_TYPE_NAIL)
			gs = "Nail grenade";
		else if (self.tp_grenades_1 == GR_TYPE_MIRV)
			gs = "Mirv grenade";
		else
			gs = "Grenade";

		if (self.no_grenades_1 > 0)
		{
			ptime = ftos( GR_PRIMETIME );
			sprint(self, gs);
			sprint(self, " primed, ");
			sprint(self, ptime);
			sprint(self, " seconds...\n");
			self.no_grenades_1 = self.no_grenades_1 - 1;
		}
		else
		{
			sprint(self, "No ");
			sprint(self, gs);
			sprint(self, "s left.\n");
			return;
		}
	}
	if (self.impulse == TF_GRENADE_2)
	{
		gtype = self.tp_grenades_2;
		if (self.tp_grenades_2 == GR_TYPE_CONCUSSION)
			gs = "Concussion grenade";
		else if (self.tp_grenades_2 == GR_TYPE_NAIL)
			gs = "Nail grenade";
		else if (self.tp_grenades_2 == GR_TYPE_MIRV)
			gs = "Mirv grenade";
		else
			gs = "Grenade";

		if (self.no_grenades_2 > 0)
		{
			ptime = ftos( GR_PRIMETIME );
			sprint(self, gs);
			sprint(self, " primed, ");
			sprint(self, ptime);
			sprint(self, " seconds...\n");
			self.no_grenades_2 = self.no_grenades_2 - 1;
		}
		else
		{
			sprint(self, "No ");
			sprint(self, gs);
			sprint(self, "s left.\n");
			return;
		}
	}

	self.grenadeprimed = 1;
	self.Grenade = spawn();
	self.Grenade.owner = self;
	self.Grenade.weapon = gtype;
	self.Grenade.nextthink = time + GR_PRIMETIME;
	self.Grenade.think = TeamFortress_ExplodePerson;
};

//=========================================================================
// Throws a currently primed grenade
void() TeamFortress_ThrowGrenade =
{
	local	entity missile;

	// If no grenade is primed, return
	if (self.grenadeprimed == 0)
		return;

	self.grenadeprimed = 0;

	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 grenade 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);

	// set the grenade's alternative kill flag
	missile.altkill = 1;
	
	// set the grenade's thinktime to when the PRIMETIME runs out
	missile.nextthink = self.Grenade.nextthink;

	// set the think and touches to the appropriate grenade type
	if (self.Grenade.weapon == GR_TYPE_NORMAL)
	{
		missile.touch = NormalGrenadeTouch;
		missile.think = NormalGrenadeExplode;
		missile.altkillweapon = AK_GRENADE;
	}
	if (self.Grenade.weapon == GR_TYPE_CONCUSSION)
	{
		missile.touch = ConcussionGrenadeTouch;
		missile.think = ConcussionGrenadeExplode;
	}
	if (self.Grenade.weapon == GR_TYPE_NAIL)
	{
		missile.touch = NailGrenadeTouch;
		missile.think = NailGrenadeExplode;
		missile.altkillweapon = AK_GRENADE_NAIL;
	}
	if (self.Grenade.weapon == GR_TYPE_MIRV)
	{
		missile.touch = MirvGrenadeTouch;
		missile.think = MirvGrenadeExplode;
		missile.altkillweapon = AK_GRENADE_MIRV;
	}

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

// Remove primed grenade object	
	remove(self.Grenade);
};

//=========================================================================
// PLAYER CLASS HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Alter the player's Movement based on class
void() TeamFortress_SetSpeed =
{
	local string sp;
	local float tf;

	stuffcmd(self,"v_idlescale 0\n");
	stuffcmd(self,"cl_movespeedkey 1\n");

	if ( self.playerclass == PC_SCOUT )
	{
		self.maxfbspeed = PC_SCOUT_MAXSPEED;
		self.maxstrafespeed = PC_SCOUT_MAXSTRAFESPEED;
	}
	else if ( self.playerclass == PC_SNIPER )
	{
		self.maxfbspeed = PC_SNIPER_MAXSPEED;
		self.maxstrafespeed = PC_SNIPER_MAXSTRAFESPEED;
	}
	else if ( self.playerclass == PC_SOLDIER )
	{
		self.maxfbspeed = PC_SOLDIER_MAXSPEED;
		self.maxstrafespeed = PC_SOLDIER_MAXSTRAFESPEED;
	}
	else if ( self.playerclass == PC_DEMOMAN )
	{
		self.maxfbspeed = PC_DEMOMAN_MAXSPEED;
		self.maxstrafespeed = PC_DEMOMAN_MAXSTRAFESPEED;
	}
	else if ( self.playerclass == PC_MEDIC )
	{
		self.maxfbspeed = PC_MEDIC_MAXSPEED;
		self.maxstrafespeed = PC_MEDIC_MAXSTRAFESPEED;
	}
	else if ( self.playerclass == PC_UNDEFINED )
	{
		self.maxfbspeed = 0;
		self.maxstrafespeed = 0;
	}

	sp = ftos(self.maxfbspeed);
	stuffcmd(self,"cl_backspeed ");
	stuffcmd(self,sp);
	stuffcmd(self,"\n");
	stuffcmd(self,"cl_forwardspeed ");
	stuffcmd(self,sp);
	stuffcmd(self,"\n");
	sp = ftos(self.maxstrafespeed);
	stuffcmd(self,"cl_sidespeed ");
	stuffcmd(self,sp);
	stuffcmd(self,"\n");
};

//=========================================================================
// Set the max_health of a player based on his/her class
void() TeamFortress_SetHealth = 
{
	if (self.classname != "player")
		return;

	if ( self.playerclass == PC_SCOUT )
	{
		self.max_health = PC_SCOUT_MAXHEALTH;
	}
	else if ( self.playerclass == PC_SNIPER )
	{
		self.max_health = PC_SNIPER_MAXHEALTH;
	}
	else if ( self.playerclass == PC_SOLDIER )
	{
		self.max_health = PC_SOLDIER_MAXHEALTH;
	}
	else if ( self.playerclass == PC_DEMOMAN )
	{
		self.max_health = PC_DEMOMAN_MAXHEALTH;
	}
	else if ( self.playerclass == PC_MEDIC )
	{
		self.max_health = PC_MEDIC_MAXHEALTH;
	}
	else if ( self.playerclass == PC_UNDEFINED )
	{
		self.max_health = 1;
	}

	self.health = self.max_health;
};

//=========================================================================
// Set the max_health of a player based on his/her class
void() TeamFortress_SetEquipment =
{
	if (self.classname != "player")
		return;

	self.items = 0;
	self.secondary_weapon = 0;
	self.secondary_items = 0;
	self.tf_items = 0;
	self.tf_items_flags = 0;
	self.armorclass = 0;
	self.grenadeprimed = 0;
	self.impulse = 0;

	self.ammo_medikit = 0;
	self.maxammo_medikit = 0;
	self.ammo_detpack = 0;
	self.maxammo_detpack = 0;
	self.items_allowed = 0;
	self.secondary_items_allowed = 0;
   	self.armor_allowed = 0;
   	self.maxarmor = 0;
	self.weaponmode = 0;
	self.altkill = 0;
	self.altkillweapon = 0;

	// Start the Cheat-Checking Cyclic Event
	self.cheattimer = spawn();
	self.cheattimer.nextthink = time + 20;
	self.cheattimer.think = TeamFortress_CheckforCheats;
	self.cheattimer.owner = self;

	if ( self.playerclass == PC_SCOUT )
	{
		self.items = self.items | PC_SCOUT_WEAPONS;
		self.ammo_rockets = PC_SCOUT_INITAMMO_ROCKET;
		self.ammo_nails = PC_SCOUT_INITAMMO_NAIL;
		self.ammo_shells = PC_SCOUT_INITAMMO_SHOT;
		self.ammo_cells = PC_SCOUT_INITAMMO_CELL;
		self.maxammo_rockets = PC_SCOUT_MAXAMMO_ROCKET;
		self.maxammo_nails = PC_SCOUT_MAXAMMO_NAIL;
		self.maxammo_shells = PC_SCOUT_MAXAMMO_SHOT;
		self.maxammo_cells = PC_SCOUT_MAXAMMO_CELL;

		self.no_grenades_1 = PC_SCOUT_GRENADE_INIT_1;
		self.no_grenades_2 = PC_SCOUT_GRENADE_INIT_2;
		self.tp_grenades_1 = PC_SCOUT_GRENADE_TYPE_1;
		self.tp_grenades_2 = PC_SCOUT_GRENADE_TYPE_2;
		self.tf_items = PC_SCOUT_TF_ITEMS;

		self.armorclass = self.armorclass | PC_SCOUT_INITARMORCLASS;
		self.armortype = PC_SCOUT_INITARMORTYPE;
		self.armorvalue = PC_SCOUT_INITARMOR;
	   	self.armor_allowed = PC_SCOUT_MAXARMORTYPE;
	   	self.maxarmor = PC_SCOUT_MAXARMOR;
		self.weapon = IT_NAILGUN;

		self.items_allowed = PC_SCOUT_WEAPONS;
	}
	else if ( self.playerclass == PC_SNIPER )
	{
		self.items = self.items | PC_SNIPER_WEAPONS;
		self.ammo_rockets = PC_SNIPER_INITAMMO_ROCKET;
		self.ammo_nails = PC_SNIPER_INITAMMO_NAIL;
		self.ammo_shells = PC_SNIPER_INITAMMO_SHOT;
		self.ammo_cells = PC_SNIPER_INITAMMO_CELL;
		self.maxammo_rockets = PC_SNIPER_MAXAMMO_ROCKET;
		self.maxammo_nails = PC_SNIPER_MAXAMMO_NAIL;
		self.maxammo_shells = PC_SNIPER_MAXAMMO_SHOT;
		self.maxammo_cells = PC_SNIPER_MAXAMMO_CELL;
	
		self.no_grenades_1 = PC_SNIPER_GRENADE_INIT_1;
		self.no_grenades_2 = PC_SNIPER_GRENADE_INIT_2;
		self.tp_grenades_1 = PC_SNIPER_GRENADE_TYPE_1;
		self.tp_grenades_2 = PC_SNIPER_GRENADE_TYPE_2;
		self.tf_items = PC_SNIPER_TF_ITEMS;

		// Get the sniper's weapon
		self.secondary_items = self.secondary_items | NIT_SNIPER_RIFLE | NIT_AUTO_RIFLE;

		self.armorclass = self.armorclass | PC_SNIPER_INITARMORCLASS;
		self.armortype = PC_SNIPER_INITARMORTYPE;
		self.armorvalue = PC_SNIPER_INITARMOR;
	   	self.armor_allowed = PC_SNIPER_MAXARMORTYPE;
	   	self.maxarmor = PC_SNIPER_MAXARMOR;
		self.weapon = IT_EXTRA_WEAPON;
		self.secondary_weapon = NIT_SNIPER_RIFLE;

		self.items_allowed = PC_SNIPER_WEAPONS;
	}
	else if ( self.playerclass == PC_SOLDIER )
	{
		self.items = self.items | PC_SOLDIER_WEAPONS;
		self.ammo_rockets = PC_SOLDIER_INITAMMO_ROCKET;
		self.ammo_nails = PC_SOLDIER_INITAMMO_NAIL;
		self.ammo_shells = PC_SOLDIER_INITAMMO_SHOT;
		self.ammo_cells = PC_SOLDIER_INITAMMO_CELL;
		self.maxammo_rockets = PC_SOLDIER_MAXAMMO_ROCKET;
		self.maxammo_nails = PC_SOLDIER_MAXAMMO_NAIL;
		self.maxammo_shells = PC_SOLDIER_MAXAMMO_SHOT;
		self.maxammo_cells = PC_SOLDIER_MAXAMMO_CELL;
	
		self.no_grenades_1 = PC_SOLDIER_GRENADE_INIT_1;
		self.no_grenades_2 = PC_SOLDIER_GRENADE_INIT_2;
		self.tp_grenades_1 = PC_SOLDIER_GRENADE_TYPE_1;
		self.tp_grenades_2 = PC_SOLDIER_GRENADE_TYPE_2;
		self.tf_items = PC_SOLDIER_TF_ITEMS;

		self.armorclass = self.armorclass | PC_SOLDIER_INITARMORCLASS;
		self.armortype = PC_SOLDIER_INITARMORTYPE;
		self.armorvalue = PC_SOLDIER_INITARMOR;
	   	self.armor_allowed = PC_SOLDIER_MAXARMORTYPE;
	   	self.maxarmor = PC_SOLDIER_MAXARMOR;
		self.weapon = IT_ROCKET_LAUNCHER;

		self.items_allowed = PC_SOLDIER_WEAPONS;
	}
	else if ( self.playerclass == PC_DEMOMAN )
	{
		self.items = self.items | PC_DEMOMAN_WEAPONS;
		self.ammo_rockets = PC_DEMOMAN_INITAMMO_ROCKET;
		self.ammo_nails = PC_DEMOMAN_INITAMMO_NAIL;
		self.ammo_shells = PC_DEMOMAN_INITAMMO_SHOT;
		self.ammo_cells = PC_DEMOMAN_INITAMMO_CELL;
		self.maxammo_rockets = PC_DEMOMAN_MAXAMMO_ROCKET;
		self.maxammo_nails = PC_DEMOMAN_MAXAMMO_NAIL;
		self.maxammo_shells = PC_DEMOMAN_MAXAMMO_SHOT;
		self.maxammo_cells = PC_DEMOMAN_MAXAMMO_CELL;
	
		self.no_grenades_1 = PC_DEMOMAN_GRENADE_INIT_1;
		self.no_grenades_2 = PC_DEMOMAN_GRENADE_INIT_2;
		self.tp_grenades_1 = PC_DEMOMAN_GRENADE_TYPE_1;
		self.tp_grenades_2 = PC_DEMOMAN_GRENADE_TYPE_2;
		self.tf_items = PC_DEMOMAN_TF_ITEMS;

		// Detpacks
		self.secondary_items = self.secondary_items | NIT_DETPACK;
		self.ammo_detpack = PC_DEMOMAN_INITAMMO_DETPACK;
		self.maxammo_detpack = PC_DEMOMAN_MAXAMMO_DETPACK;

		self.armorclass = self.armorclass | PC_DEMOMAN_INITARMORCLASS;
		self.armortype = PC_DEMOMAN_INITARMORTYPE;
		self.armorvalue = PC_DEMOMAN_INITARMOR;
	   	self.armor_allowed = PC_DEMOMAN_MAXARMORTYPE;
	   	self.maxarmor = PC_DEMOMAN_MAXARMOR;
		self.weapon = IT_GRENADE_LAUNCHER;

		self.items_allowed = PC_DEMOMAN_WEAPONS;
	}
	else if ( self.playerclass == PC_MEDIC )
	{
		self.items = self.items | PC_MEDIC_WEAPONS;
		self.ammo_rockets = PC_MEDIC_INITAMMO_ROCKET;
		self.ammo_nails = PC_MEDIC_INITAMMO_NAIL;
		self.ammo_shells = PC_MEDIC_INITAMMO_SHOT;
		self.ammo_cells = PC_MEDIC_INITAMMO_CELL;
		self.maxammo_rockets = PC_MEDIC_MAXAMMO_ROCKET;
		self.maxammo_nails = PC_MEDIC_MAXAMMO_NAIL;
		self.maxammo_shells = PC_MEDIC_MAXAMMO_SHOT;
		self.maxammo_cells = PC_MEDIC_MAXAMMO_CELL;
	
		self.no_grenades_1 = PC_MEDIC_GRENADE_INIT_1;
		self.no_grenades_2 = PC_MEDIC_GRENADE_INIT_2;
		self.tp_grenades_1 = PC_MEDIC_GRENADE_TYPE_1;
		self.tp_grenades_2 = PC_MEDIC_GRENADE_TYPE_2;
		self.tf_items = PC_MEDIC_TF_ITEMS;

		self.armorclass = self.armorclass | PC_MEDIC_INITARMORCLASS;
		self.armortype = PC_MEDIC_INITARMORTYPE;
		self.armorvalue = PC_MEDIC_INITARMOR;
	   	self.armor_allowed = PC_MEDIC_MAXARMORTYPE;
	   	self.maxarmor = PC_MEDIC_MAXARMOR;
		self.weapon = IT_SUPER_NAILGUN;

		// Medikit
		self.secondary_items = self.secondary_items | NIT_MEDIKIT;
		self.ammo_medikit = PC_MEDIC_INITAMMO_MEDIKIT;
		self.maxammo_medikit = PC_MEDIC_MAXAMMO_MEDIKIT;

		// Start the Regeneration Cyclic Event
		self.cyclictimer = spawn();
		self.cyclictimer.nextthink = time + PC_MEDIC_REGEN_TIME;
		self.cyclictimer.think = TeamFortress_Regenerate;
		self.cyclictimer.owner = self;

		self.items_allowed = PC_MEDIC_WEAPONS;
	}
	else if ( self.playerclass == PC_UNDEFINED )
	{
		self.items = self.items | IT_AXE;
		self.ammo_rockets = 0;
		self.ammo_nails = 0;
		self.ammo_shells = 0;
		self.ammo_cells = 0;

		self.no_grenades_1 = 0;
		self.no_grenades_2 = 0;
		self.tp_grenades_1 = 0;
		self.tp_grenades_2 = 0;
	
		self.armorclass = 0;
		self.armortype = 0;
		self.armorvalue = 0;
		self.weapon = IT_AXE;
	}

	W_SetCurrentAmmo ();
};

//=========================================================================
// Return the max amount of ammo the Retriever can carry, based on his class
float(entity Retriever, float AmmoType) TeamFortress_GetMaxAmmo =
{
	if (AmmoType == IT_SHELLS)
	{
		return Retriever.maxammo_shells;
	}
	else if (AmmoType == IT_NAILS)
	{
		return Retriever.maxammo_nails;
	}
	else if (AmmoType == IT_CELLS)
	{
		return Retriever.maxammo_cells;
	}
	else if (AmmoType == IT_ROCKETS)
	{
		return Retriever.maxammo_rockets;
	}

	dprint("Error in TeamFortress_GetMaxAmmo()\n");
	dprint("Invalid ammo type passed.\n");
	return 0;
};

//=========================================================================
// Return 1 if the Retriever is allowed to pick up the Weapon
float(entity Retriever, float WeaponType) TeamFortress_CanGetWeapon =
{
	if ( Retriever.items_allowed & WeaponType )
		return 1;

	return 0;
};

//=========================================================================
// Return 1 if the Retriever is allowed to pick up the Armor
float(entity Retriever, entity Armor) TeamFortress_CanGetArmor =
{
	local float	type;
	local float af;
	local string at;

	if (Armor.classname == "item_armor1")
	{
		type = 0.3;
	}
	else if (Armor.classname == "item_armor2")
	{
		type = 0.6;
	}
	else if (Armor.classname == "item_armorInv")
	{
		type = 0.8;
	}
	else
	{
		dprint("Error in TeamFortress_CanGetArmor()\n");
		dprint("Invalid armor type passed.\n");
		return 0;
	}

	af = Armor.spawnflags - (Armor.spawnflags & AT_NORMAL);

	if ( type > Retriever.armor_allowed )
		return 0;

	return 1;

	if (!af)
		return 1;
	if (PC_SCOUT_ARMORCLASSES & af)
		return 1;

	return 0;
};


//=========================================================================
// Controls the equipment a class receives from backpacks
float(entity Retriever, entity Items) TeamFortress_AddBackpackItems =
{
	// If you want the classes to _not_ start off with all their legal
	// weapons, then you may want them to be able to pick up weapons
	// from backpacks. If so, this is where to do it.
	// For now, return. 
	return;
};

//=========================================================================
// WEAPON HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Sniper's Weapon choice function
void() TeamFortress_SniperWeapon =
{
	local	float	it;
	
    if (self.reloading)
   		return;

	if (!((self.secondary_items & NIT_SNIPER_RIFLE) && (self.secondary_items & NIT_AUTO_RIFLE)))
		return;

	self.impulse = 0;

	if (self.playerclass != PC_SNIPER)
		return;

	if (self.ammo_shells < 1)
	{	// don't have the ammo
		sprint (self, "not enough ammo.\n");
		return;
	}

	if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_SNIPER_RIFLE)
	{
		self.secondary_weapon = NIT_AUTO_RIFLE;
	}
	else if (self.weapon == IT_EXTRA_WEAPON && self.secondary_weapon == NIT_AUTO_RIFLE)
	{
		self.secondary_weapon = NIT_SNIPER_RIFLE;
	}
	else
	{
		self.secondary_weapon = NIT_SNIPER_RIFLE;
		self.weapon = IT_EXTRA_WEAPON;
	}

	W_SetCurrentAmmo ();
};

//=========================================================================
// If this gets called, the players holding onto an exploding grenade :)
void() TeamFortress_ExplodePerson =
{
	local	entity missile;

	// Removes the owners grenade
	self.owner.grenadeprimed = 0;

	self.owner.punchangle_x = -2;

	missile = spawn ();
	missile.movetype = MOVETYPE_BOUNCE;
	missile.solid = SOLID_BBOX;
	missile.classname = "grenade";
		
	// Don't bother calculating a velocity
	missile.velocity = '0 0 0';
	missile.avelocity = '300 300 300';

	missile.angles = vectoangles(missile.velocity);
	
	// set the grenade's alternative kill flag
	missile.altkill = 1;

	// set the grenades thinktime to now
	missile.nextthink = time + 0.1;

	// set the think and touches to the appropriate grenade type
	if (self.weapon == GR_TYPE_NORMAL)
	{
		missile.touch = NormalGrenadeTouch;
		missile.think = NormalGrenadeExplode;
		missile.altkillweapon = AK_GRENADE;
	}
	if (self.weapon == GR_TYPE_CONCUSSION)
	{
		missile.touch = ConcussionGrenadeTouch;
		missile.think = ConcussionGrenadeExplode;
	}
	if (self.weapon == GR_TYPE_NAIL)
	{
		missile.touch = NailGrenadeTouch;
		missile.think = NailGrenadeExplode;
		missile.altkillweapon = AK_GRENADE_NAIL;
	}
	if (self.weapon == GR_TYPE_MIRV)
	{
		missile.touch = MirvGrenadeTouch;
		missile.think = MirvGrenadeExplode;
		missile.altkillweapon = AK_GRENADE_MIRV;
	}

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

	bprint("No ");
	bprint(self.owner.netname);
	bprint(", throw the grenade, not the pin!\n");

// Remove primed grenade object	
	remove(self);
};

//=========================================================================
// Touch function for a concussion grenade
void() ConcussionGrenadeTouch =
{
	local entity timer;

	if (other.takedamage == DAMAGE_AIM)
	{
		// A person hit by a concussion grenade doesn't move much,
		// since their origin is pretty much right on the grenade's
		// explosion point, so we'll give him a kick.
		other.velocity_x = self.velocity_x - 300;
		other.velocity_y = self.velocity_y - 300;
		other.velocity_z = 300;

		if (other.classname != "player")
		{
			if(other.flags & FL_ONGROUND)
				other.flags = other.flags - FL_ONGROUND;
		}
		else
		{
			// Concuss 'em!!
			stuffcmd(other,"v_idlescale 100\n");
			// Create a timer entity
			timer = spawn();
			timer.nextthink = time + GR_CONCUSS_TIME;
			timer.think = ConcussionGrenadeTimer;
			timer.owner = other;
			timer.health = 100;
		}

		ConcussionGrenadeExplode();
		return;
	}

	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

//=========================================================================
// Concussion grenade explosion function
void() ConcussionGrenadeExplode =
{
	T_RadiusBounce (self, self.owner, 240, 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 ();
};

//=========================================================================
// Concussion grenade timer to remove idlescale
void() ConcussionGrenadeTimer =
{
	local string st;

	if (self.health <= 0)
	{
		remove(self);
		return;
	}

	self.health = self.health - GR_CONCUSS_DEC;
	self.nextthink = time + GR_CONCUSS_TIME;

	st = ftos(self.health);
	stuffcmd(self.owner, "v_idlescale ");
	stuffcmd(self.owner, st);
	stuffcmd(self.owner, "\n");
};

//=========================================================================
// Touch Function for Nail Grenade
void() NailGrenadeTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner

	// If the Nail Grenade hits a player, it just bounces off

	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

//=========================================================================
// Explode Function for Nail Grenade
void() NailGrenadeExplode =
{
	// Raise into the air
	self.movetype = MOVETYPE_NOCLIP;
	self.velocity = '0 0 100';
	self.avelocity = '0 500 0';
	self.nextthink = time + 0.5;
	self.think = NailGrenadeNailEm;
};

//=========================================================================
// Nail function for Nail Grenade
void() NailGrenadeNailEm =
{
	// Rotate and spew Nails
	self.velocity = '0 0 0';

	self.nextthink = time + 0.1;
	self.think = NailGrenadeLaunchNail;
	self.playerclass = 0;
};

//=========================================================================
// Nail function for Nail Grenade
void() NailGrenadeLaunchNail =
{
	local float i,j;

	i = 0;
	while (i < 3)
	{
		j = (random() + 2) * 2;
		current_yaw = anglemod( self.angles_y );
		current_yaw = anglemod(current_yaw + j);
		self.angles_y = current_yaw;
		self.angles_x = 0;
		self.angles_z = 0;
		makevectors(self.angles);

		launch_spike(self.origin, v_forward, 1, AK_GRENADE_NAIL);

		i = i + 1;
	}

	self.playerclass = self.playerclass + 1;
	self.nextthink = time + 0.1;

	// Explode 
	if (self.playerclass > 50)
		self.think = GrenadeExplode;
};

//=========================================================================
// Touch Function for Mirv Grenade
// Mirv Grenade heavily influenced by the Firewall Grenade by Steve Bond (wedge@nuc.net)
void() MirvGrenadeTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner

	// If the Mirv Grenade hits a player, it just bounces off

	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

//=========================================================================
// Mirv Grenade explode function, for when the PRIMETIME runs out
void() MirvGrenadeExplode =
{
	local float i;

	T_RadiusDamage (self, self.owner, 250, 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);

	self.solid=SOLID_NOT;
	BecomeExplosion ();

	// Launch mirvs
	i = 0;
	while (i < GR_TYPE_MIRV_NO)
	{
		MirvGrenadeLaunch (self.origin + '0 0 -1',self.owner);
		i = i + 1;
	}
};

//=========================================================================
// Launch a Mirv
void (vector org, entity shooter) MirvGrenadeLaunch =
{
	local float xdir,ydir,zdir, spin;
	
	xdir = 150 * random() - 75;
	ydir = 150 * random() - 75;
	zdir = 40 * random();

	newmis = spawn ();
	newmis.owner = shooter;
	newmis.movetype = MOVETYPE_BOUNCE;
	self.touch = SUB_Null;
	newmis.solid = SOLID_BBOX;

	newmis.classname = "grenade";
	newmis.touch = GrenadeTouch;
	newmis.think = 	GrenadeExplode;
	newmis.nextthink = time + 2;
	
	newmis.velocity_x = xdir * 2;
	newmis.velocity_y = ydir * 2;
	newmis.velocity_z = zdir * 15;

	spin = (random() * 10) / 2;
	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/grenade.mdl");
	setsize (newmis, VEC_ORIGIN, VEC_ORIGIN);
	setorigin (newmis, org);
};

//=========================================================================
// Thrown Grenade touch function.
void() NormalGrenadeTouch =
{
	if (other == self.owner)
		return;		// don't explode on owner

	// Thrown grenades don't detonate when hitting an enemy

	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

//=========================================================================
// Thrown grenade explosion. Twice as powerful as grenade launcher grenades.
void() NormalGrenadeExplode =
{
	T_RadiusDamage (self, self.owner, 240, 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 ();
};

//=========================================================================
// Detonate all thrown pipebombs
void() TeamFortress_DetonatePipebombs =
{
	local entity e;

// Find all this players pipebombs
	e = find(world, classname, "pipebomb");
	while (e)
	{
    	if(e.owner == self)
			e.nextthink = time;
		
		e = find(e, classname, "pipebomb");
	}
};

//=========================================================================
// Pipebomb touch function
void() PipebombTouch =
{
	sound (self, CHAN_WEAPON, "weapons/bounce.wav", 1, ATTN_NORM);	// bounce sound
	if (self.velocity == '0 0 0')
		self.avelocity = '0 0 0';
};

//=========================================================================
// ITEM HANDLING FUNCTIONS
//=========================================================================
//=========================================================================
// Handles the scanner function for scouts, and Base Defences
void(float scanrange) TeamFortress_Scan = 
{
	local string power;
	local entity list;
	local float scen, scfr;

	// prevent scan impulse from triggering anything else
	self.impulse = 0;
	self.last_impulse = 0;

	if (self.classname == "player")
	{
		if (!(self.tf_items & NIT_SCANNER))
			return;

		// If Impulse is TF_SCAN_ENEMY, toggle Scanning for Enemies
		if (scanrange == TF_SCAN_ENEMY)
		{
			if (self.tf_items_flags & NIT_SCANNER_ENEMY)
			{
				sprint(self, "Enemy Scanning disabled.\n");
				self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_ENEMY;
				return;
			}
			sprint(self, "Enemy Scanning enabled.\n");
			self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_ENEMY;
			return;
		}

		// If Impulse is TF_SCAN_FRIENDLY, toggle Scanning for Friendlies
		if (scanrange == TF_SCAN_FRIENDLY)
		{
			if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
			{
				sprint(self, "Friendly Scanning disabled.\n");
				self.tf_items_flags = self.tf_items_flags - NIT_SCANNER_FRIENDLY;
				return;
			}
			sprint(self, "Friendly Scanning enabled.\n");
			self.tf_items_flags = self.tf_items_flags | NIT_SCANNER_FRIENDLY;
			return;
		}

		// If the user doesn't have as many cells as he/she specified, just
		// use as many as they've got.
		if (scanrange > self.ammo_cells)
			scanrange = self.ammo_cells;

		if (scanrange <= 0)
		{
			sprint(self,"No cells.\n");
			return;
		}

		if (scanrange > NIT_SCANNER_MAXCELL)
			scanrange = NIT_SCANNER_MAXCELL;

		scen = 0;
		scfr = 0;
		// Set the Scanner flags
		if (self.tf_items_flags & NIT_SCANNER_ENEMY)
			scen = 1;
		if (self.tf_items_flags & NIT_SCANNER_FRIENDLY)
			scfr = 1;

		// If no entity type is enabled, don't scan
		if ((scen == 0) && (scfr == 0))
		{
			sprint(self,"All scanner functions are disabled.\n");
			return;
		}

		sprint(self, "Power Usage: ");
		power = ftos(scanrange);
		sprint(self, power);
		sprint(self, ". Scanning...\n");

		// Use up cells to power the scanner
		self.ammo_cells = self.ammo_cells - scanrange;
		scanrange = scanrange * NIT_SCANNER_POWER;

		// Get the list of entities the scanner finds
		list = T_RadiusScan(self, scanrange, scen, scfr);
	}
	// Base Defence scanning code here

	// Reset the entity counts
	scen = 0;
	scfr = 0;

	// Walk the list
	// For now, just count the entities.
	// In the future, we'll display bearings :)
	while (list)
	{
		// If this scanner is a motion detector, don't record
		// object that don't have the required velocity to be detected.
		if (self.tf_items_flags & NIT_SCANNER_MOVEMENT)
		{
			if (vlen(list.velocity) > NIT_SCANNER_MIN_MOVEMENT)
			{
				if ((list.team > 0) && (self.team > 0) && (list.team == self.team)) 
					scfr = scfr + 1;
				else
					scen = scen + 1;
			}
		}
		else
		{
			if ((list.team > 0) && (self.team > 0) && (list.team == self.team))
				scfr = scfr + 1;
			else
				scen = scen + 1;
		}

		list = list.linked_list;
	}

	// Display the counts
	// For Base Defences, it will display the counts to all team members
	if ((scen == 0) && (scfr == 0))
	{
		sprint(self, "No blips.\n");
		return;
	}

	if (scen > 0)
	{
		power = ftos(scen);
		sprint(self, power);
		if (scen > 1)
			sprint(self, " enemies. ");
		else
			sprint(self, " enemy. ");
	}
	if (scfr > 0)
	{
		power = ftos(scfr);
		sprint(self, power);
		if (scfr > 1)
			sprint(self, " friendlies. ");
		else
			sprint(self, " friendly. ");
	}
	sprint(self, "\n");

	// Update ammo levels
	W_SetCurrentAmmo ();

	return;
};

//=========================================================================
// Handles the Setting of Detpacks
void(float timer) TeamFortress_SetDetpack =
{
	// prevent detpack impulse from triggering anything else
	self.impulse = 0;
	self.last_impulse = 0;

	if (!(self.secondary_items & NIT_DETPACK))
		return;

	if (self.ammo_detpack <= 0)
		return;

	self.ammo_detpack = self.ammo_detpack - 1;
	stuffcmd(self, "cl_forwardspeed 0\n");
	stuffcmd(self, "cl_backspeed 0\n");
	stuffcmd(self, "cl_sidespeed 0\n");

	self.detpack = spawn();
	self.detpack.owner = self;
	self.detpack.nextthink = time + NIT_DETPACK_SETTIME;
	self.detpack.think = TeamFortress_DetpackSet;
	self.detpack.health = timer;
};

//=========================================================================
// The detpack is set, let the player go and start timer
void() TeamFortress_DetpackSet =
{
	local entity tmp;

	self.nextthink = time + self.health; 
	self.think = TeamFortress_DetpackExplode;

	tmp = self;
	self = self.owner;
	TeamFortress_SetSpeed();
	self = tmp;

	self.owner.detpack = spawn ();
	self.owner.detpack.owner = self.owner;
    self.owner.detpack.origin = self.owner.origin - '0 0 23';
	self.owner.detpack.movetype = MOVETYPE_BOUNCE;
	self.owner.detpack.solid = SOLID_TRIGGER;
	self.owner.detpack.classname = "detpack";
    self.owner.detpack.flags = FL_ITEM;
		
	self.owner.detpack.velocity = '0 0 0';
	self.owner.detpack.avelocity = '0 0 0';
	self.owner.detpack.angles = vectoangles(self.owner.detpack.velocity);

	// Set the Detpack alternative kill flag
	self.owner.detpack.altkill = 1;
	self.owner.detpack.altkillweapon = AK_DETPACK;
	
	self.owner.detpack.nextthink = time + self.health;
	self.owner.detpack.think = TeamFortress_DetpackExplode;

   	self.owner.detpack.touch = TeamFortress_DetpackTouch;

	setmodel (self.owner.detpack, "progs/backpack.mdl");
	setsize (self.owner.detpack, '-16 -16 0', '16 16 56');		
	setorigin (self.owner.detpack, self.owner.origin);
};

//=========================================================================
// The detpack goes BOOM!
void() TeamFortress_DetpackExplode = 
{
	T_RadiusDamage (self, self.owner, NIT_DETPACK_SIZE, 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 ();
};

//=========================================================================
// The detpack touch function. Scouts can disarm it
void() TeamFortress_DetpackTouch = 
{
	if (other.classname != "player")
		return;

	if (other.playerclass != PC_SCOUT)
		return;

	bprint(other.netname);
	bprint(" snuffs ");
	bprint(self.owner.netname);
	bprint("'s fuse!\n");

	remove(self);
};

//=========================================================================
// UTILITY FUNCTIONS
//=========================================================================
//=========================================================================
// Acts just like T_RadiusDamage, but doesn't damage things, just pushes them away
// from the explosion at a speed relative to the distance from the explosion's origin.
void(entity inflictor, entity attacker, float bounce, entity ignore) T_RadiusBounce =
{
	local	float 	points;
	local	entity	head, timer;
	local	vector	org;
	local	string	st;

	head = findradius(inflictor.origin, bounce+40);
	
	while (head)
	{
		if (head != ignore)
		{
			if (head.takedamage)
			{
				org = head.origin + (head.mins + head.maxs)*0.5;
				points = 0.5*vlen (org - inflictor.origin);
				if (points < 0)
					points = 0;
				points = bounce - points;
				if (points > 0)
				{
					// Bounce!!
					head.velocity = org - inflictor.origin;
					head.velocity = head.velocity * (points / 10);

					if (head.classname != "player")
					{
						if(head.flags & FL_ONGROUND)
							head.flags = head.flags - FL_ONGROUND;
					}
					else
					{
						// Concuss 'em!!
						stuffcmd(head,"v_idlescale 100\n");
						// Create a timer entity
						timer = spawn();
						timer.nextthink = time + GR_CONCUSS_TIME;
						timer.think = ConcussionGrenadeTimer;
						timer.owner = head;
						timer.health = 100;
					}
				}
			}
		}
		head = head.chain;
	}
};

//=========================================================================
// Returns a list of players within a radius around the origin, like findradius,
// except that some parsing of the list can be done based on the parameters passed in.
// Make sure you check that the return value is not NULL b4 using it.
entity(entity scanner, float scanrange, float enemies, float friends) T_RadiusScan =
{
	local entity head;
	local entity list_head;
	local entity list;
	local float gotatarget;

	head = findradius(scanner.origin, scanrange+40);

	while (head)
	{
		gotatarget = 0;
		if (head != scanner)			// Don't pick up the entity that's scanning
		{
			if (head.takedamage)
			{
				if ((head.classname == "player") && (friends || enemies))
				{
					if (teamplay == 1)
					{
						if ( friends && (head.team > 0) && (scanner.team > 0) && (head.team == scanner.team) )
							gotatarget = 1;
						if ( enemies && (head.team > 0) && (scanner.team > 0) && (head.team != scanner.team) )
							gotatarget = 1;
					}
					else
						gotatarget = 1;
				}
			}
		}

		// Add this entity to the linked list if it matches the target criteria
		if (gotatarget)
		{
			if (list)
			{
				list.linked_list = head;
				list = list.linked_list;
			}
			else
			{
				list_head = head;
				list = head;
			}
		}

		head = head.chain;
	}

	return list_head;
};

//=========================================================================
// CYCLIC EVENT FUNCTIONS
//=========================================================================
//=========================================================================
// Regenerates the entity which owns this cyclictimer
void() TeamFortress_Regenerate =
{
	if (self.owner.playerclass == PC_MEDIC)
	{
		self.nextthink = time + PC_MEDIC_REGEN_TIME;

		if (self.owner.health >= self.owner.max_health)
			return;

		self.owner.health = self.owner.health + PC_MEDIC_REGEN_AMOUNT;
		if (self.owner.health > self.owner.max_health)
			self.owner.health = self.owner.max_health;
		return;
	}

	return;
};

//=========================================================================
// Check for cheats :) Mainly for internet play
// This is _far_ from a good solution. It will catch non-scouts that
// set their speeds to maxspeed, but not much else.
// It will occasionally catch someone who only sets their speed up 
// by a little bit.
// Still, in my opinion it was better than noth checking at all.
// If you trust people, or play only with friends, remove the creation
// of the cheattimer ( See TeamFortress_SetEquipment() above )
// If anyone knows of a better way to do this, or knows how to
// get the value of a _client_ cvar, please mail me.
void() TeamFortress_CheckforCheats =
{
	local float tf;
	local string st;

	tf = random() * 50;
	self.nextthink = time + 10 + tf;

	tf = vlen(self.owner.velocity);

	// Since players still exceed their maxfbspeed when strafing
	// as well as moving forward or backward, I played around a
	// while until I decided on 200. I've never broken this.
	// If you do exceed this when not cheating, please mail me.
	if (tf > (self.owner.maxfbspeed + 200))
	{
		// Make sure they're on the ground
		if ((self.owner.flags & FL_ONGROUND) && (self.velocity_z == 0))
		{
			bprint(self.owner.netname);
			bprint(" has been fined 5 frags for cheating!\n");
			self.owner.frags = self.owner.frags - 5;
			T_Damage(self.owner, world, world, 400);
	
			// Make sure they don't get fined again before they respawn
			self.owner.maxfbspeed = 1000;
		}
 	}
 };

