/*
+-------+
|Damage |
+-------+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=+
| Scratch                                      Http://www.admdev.com/scratch |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
| Damage related functions and stuff that generally involves hurting         |
| Corporal.			                       			                 |
+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
*/

void(entity targ, entity attacker) ClientObituary;

/*
============
Killed
============
*/
void(entity targ, entity attacker) Killed =
{
	local entity oself;

	oself = self;
	self = targ;
	
	if (self.health < -99) self.health = -99;

	if (self.movetype == MOVETYPE_PUSH || self.movetype == MOVETYPE_NONE)
	{	// doors, triggers, etc
		self.th_die ();
		self = oself;
		return;
	}

	self.enemy = attacker;

	ClientObituary(self, attacker);
	
	self.takedamage = DAMAGE_NO;
	self.touch = SUB_Null;
	self.th_die ();
	self = oself;
};

/*
============
CanDamage

Returns true if the inflictor can directly damage the target.  Used for
explosions.
============
*/

float(entity targ, entity inflictor) CanDamage =
{
	// bmodels need special checking because their origin is 0,0,0
	if (targ.movetype == MOVETYPE_PUSH)
	{
		traceline(inflictor.origin, 0.5 * (targ.absmin + targ.absmax), TRUE, self);
		if (trace_fraction == 1)
			return TRUE;
		if (trace_ent == targ)
			return TRUE;
		return FALSE;
	}
	
	traceline(inflictor.origin, targ.origin, TRUE, self);
	if (trace_fraction == 1)
		return TRUE;
	traceline(inflictor.origin, targ.origin + '15 15 0', TRUE, self);
	if (trace_fraction == 1)
		return TRUE;
	traceline(inflictor.origin, targ.origin + '-15 -15 0', TRUE, self);
	if (trace_fraction == 1)
		return TRUE;
	traceline(inflictor.origin, targ.origin + '-15 15 0', TRUE, self);
	if (trace_fraction == 1)
		return TRUE;
	traceline(inflictor.origin, targ.origin + '15 -15 0', TRUE, self);
	if (trace_fraction == 1)
		return TRUE;

	return FALSE;
};

/*
============
T_RadiusDamage
============
*/
void(entity inflictor, entity attacker, float damage, entity ignore) T_RadiusDamage =
{
	local	float 	points;
	local	entity	head;
	local	vector	org, dir, view;
	local float addition;

	head = findradius(inflictor.origin, damage+40);
	
	while (head)
	{
		if (head != ignore)
		{
			if (head.takedamage)
			{
				org = head.origin + (head.mins + head.maxs)*0.5;
				points = 0.5*vlen (inflictor.origin - org);
				if (points < 0)
					points = 0;
				points = damage - points;
				if (head == attacker)
					points = points * 0.5;
				if (points > 0)
				{
					if (CanDamage (head, inflictor))
					{
						addition = head.health + head.armorvalue;
						if (addition <= points)
							head.exploded = TRUE; // tells the player they were blown up by a grenade..
										    // used for setting up the grenade death

						// if a death message for the weapon you're carrying displays
						// while they were blown up by a grenade, then the 'addition' math is wrong!

						T_Damage (head, inflictor, attacker, points);
						// grenade figure momentum add
						if ((inflictor != world) && (head.movetype == MOVETYPE_WALK))
						{
							dir = head.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
							dir = normalize(dir);
							self.flags = self.flags - (self.flags & FL_ONGROUND);
							head.velocity = head.velocity + dir*damage*2;
							head.velocity_z = head.velocity_z + damage*1.2;
						}
					}
				}
			}
		}
		head = head.chain;
	}
};

/*
============
T_Damage
============
*/

void(entity targ, entity inflictor, entity attacker, float damage) T_Damage =
{
	local	vector	dir;
	local	entity	oldself;
	local	float	save;
	local	float	take;

	targ.opponent = attacker;

	if (!targ.takedamage) return;

	save = damage;

	if (save >= targ.armorvalue)
	{
		save = targ.armorvalue;
		targ.armortype = 0;	// lost all armor
		targ.items = targ.items - (targ.items & (IT_SHIELD));
	}
	
	targ.armorvalue = targ.armorvalue - save;
	take = ceil(damage-save);

	if (targ.flags & FL_CLIENT)
	{
		targ.dmg_take = targ.dmg_take + take;
		targ.dmg_save = targ.dmg_save + save;
		targ.dmg_inflictor = inflictor;
	}

	if (!targ.ishuman)
	{
		// Add skill based checks
		targ.enemy = attacker;
	}

	// team play damage avoidance
	if ((teamplay == 1) && (targ.team > 0)&&(targ.team == attacker.team)) return;
		
	// do the damage
	if (targ.armorvalue <= 0) // Shield absorbes all damage
	{
		targ.health = targ.health - damage;
		targ.punchangle_x = -2;
	}

	if (targ.health < 1)
	{
		Killed (targ, attacker);
		targ.health = 0;
		return;
	}

	// react to the damage
	oldself = self;
	self = targ;

	if (self.th_pain)	self.th_pain (attacker, damage);

	self = oldself;
};

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

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

/*
================
SpawnShieldParticle
================
*/
void(vector org, vector vel, float damage) SpawnShieldParticle =
{
	particle (org, vel*0.1, 111, damage*2);
};

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

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

//=======
// blood
//
// pool of blood drops underneath during death
//=======

void() blood_think =
{
	if (self.cnt == FALSE)
	{
		if (self.frame < 8)
		{
			self.frame = self.frame + 1;
			self.nextthink = time + 0.5; //animate speed
		}
		else
		{
			self.cnt = TRUE;
			self.nextthink = time + 8;
		}
	}
	else
	{
		if (self.frame > 0)
			self.frame = self.frame - 1;
		else
		{
			remove(self);
			return;
		}
		self.nextthink = time + 0.2;
	}
	if (self.owner.flags & FL_ONGROUND)
		droptofloor(0,0);
	tilt();
};

void() blood =
{
	local entity pool;

	makevectors (self.angles);

	pool = spawn ();
	pool.owner = self;
	pool.movetype = MOVETYPE_TOSS;
	pool.solid = SOLID_BBOX;
	pool.classname = "bloodpool";
	setmodel (pool, "progs/bloodp.mdl");
	setsize (pool, '0 0 0', '0 0 0');
	setorigin (pool, self.origin); // match up with the dead corporal body
	pool.angles_y = random() * 360;
	pool.think = blood_think;
	pool.nextthink = time + 0.1;
};