#include "g_local.h"
int bonus[] = { 1, 1, 2, 1, 1, 4, 2, 3, 10 };
int TeamBase = 1;

#define DAMAGE_HIGH 60
#define DAMAGE_MEDIUM 40
#define DAMAGE_LOW 20

int NumClients()
{
	int total = 0, i;
	
	for (i = 0; i < maxclients->value; i++) 
	{
		if (!(g_edicts[i+1].inuse))
			continue;
		if (game.clients[i].pers.team == NOTEAM)
			continue;
		total++;
	}
	return total;

}

/*QUAKED func_explosive (0 .5 .8) ? Trigger_Spawn ANIMATED ANIMATED_FAST ENTRANCE
Any brush that you want to explode or break apart.  If you want an
explosion, set dmg and it will do a radius explosion of that amount
at the center of the bursh.

If targeted it will not be shootable.

Health defaults to 100.

Mass defaults to 75.  This determines how much debris is emitted when
it explodes.  You get one large chunk per 100 of mass (up to 8) and
one small chunk per 25 of mass (up to 16).  So 800 gives the most.

ENTRANCE will make it the main wall for base defence.

Style determines the animation that the wall does on exploding.
1)		Glass/thin wall.  Regular Quake 2 explosion.
2)		Metal/thick wall.
3)		Stone.
4)		Wood.
5)		Feild.
*/

void func_explosive_explode (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	vec3_t	origin;
	vec3_t	chunkorigin;
	vec3_t	size;
	int		count;
	int		mass;
	int i;
	edict_t *ent, *extraexplo;
	vec3_t	neworigin, oldorigin, oldvelocity, oldsize;



	VectorCopy (self->s.origin, oldorigin);
	VectorCopy (self->velocity, oldvelocity);
	VectorCopy (self->size, oldsize);

	// bmodel origins are (0 0 0), we need to adjust that here
	VectorScale (self->size, 0.5, size);
	VectorAdd (self->absmin, size, origin);
	VectorCopy (origin, self->s.origin);
	VectorCopy (origin, neworigin);

	self->takedamage = DAMAGE_NO;

	ent = G_Spawn ();
	VectorCopy (self->s.origin, ent->s.origin);
	gi.linkentity (ent);



	/*
	if (self->spawnflags & 8)
		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_ENTRANCE);
	else
		T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
	*/



	VectorSubtract (self->s.origin, inflictor->s.origin, self->velocity);
	VectorNormalize (self->velocity);
	VectorScale (self->velocity, 150, self->velocity);

	// start chunks towards the center
	VectorScale (size, 0.5, size);

	mass = self->mass;
	if (!mass)
		mass = 75;

	switch (self->style)
	{
		case 1:
		default:
			// big chunks
			if (mass >= 100)
			{
				count = mass / 100;
				if (count > 8)
					count = 8;
				while(count--)
				{
					chunkorigin[0] = origin[0] + crandom() * size[0];
					chunkorigin[1] = origin[1] + crandom() * size[1];
					chunkorigin[2] = origin[2] + crandom() * size[2];
					ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
				}
			}

			// small chunks
			count = mass / 25;
			if (count > 16)
				count = 16;
			while(count--)
			{
				chunkorigin[0] = origin[0] + crandom() * size[0];
				chunkorigin[1] = origin[1] + crandom() * size[1];
				chunkorigin[2] = origin[2] + crandom() * size[2];
				ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
			}

			//no explosion 
			self->dmg = 0;
			break;
		case 2:
			// more big chunks, extra explosions
			if (mass >= 50)
			{
				count = mass / 50;
				if (count > 12)
					count = 12;
				while(count--)
				{
					chunkorigin[0] = origin[0] + crandom() * size[0];
					chunkorigin[1] = origin[1] + crandom() * size[1];
					chunkorigin[2] = origin[2] + crandom() * size[2];
					ThrowDebris (self, "models/objects/debris3/tris.md2", 4, chunkorigin);
					
				}
				count = 2 + random() * 4;
				while(count--)
				{
					chunkorigin[0] = origin[0] + crandom() * size[0];
					chunkorigin[1] = origin[1] + crandom() * size[1];
					chunkorigin[2] = origin[2] + crandom() * size[2];
					extraexplo = G_Spawn ();
					VectorCopy (chunkorigin, extraexplo->s.origin);
					extraexplo->think = BecomeExplosion1;
					extraexplo->nextthink = level.time + FRAMETIME * (random() * 25);
					gi.linkentity (extraexplo);
				}
			}

			// no small chunks
			break;
		case 3:
		// big chunks
			if (mass >= 60)
			{
				count = mass / 60;
				if (count > 12)
					count = 12;
				while(count--)
				{
					chunkorigin[0] = origin[0] + crandom() * size[0];
					chunkorigin[1] = origin[1] + crandom() * size[1];
					chunkorigin[2] = origin[2] + crandom() * size[2];
					ThrowDebris (self, "models/objects/debris1/tris.md2", 1, chunkorigin);
				}
			}

			// small chunks
			count = mass / 20;
			if (count > 20)
				count = 20;
			while(count--)
			{
				chunkorigin[0] = origin[0] + crandom() * size[0];
				chunkorigin[1] = origin[1] + crandom() * size[1];
				chunkorigin[2] = origin[2] + crandom() * size[2];
				ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
			}
			//no explosion 
			self->dmg = 0;
			break;
		case 4:
			// small chunks only
			count = mass / 25;
			if (count > 20)
				count = 20;
			while(count--)
			{
				chunkorigin[0] = origin[0] + crandom() * size[0];
				chunkorigin[1] = origin[1] + crandom() * size[1];
				chunkorigin[2] = origin[2] + crandom() * size[2];
				ThrowDebris (self, "models/objects/debris2/tris.md2", 2, chunkorigin);
			}

			//no explosion 
			self->dmg = 0;
			break;
		case 5:
			gi.sound(ent, CHAN_ITEM, gi.soundindex("misc/power3.wav"), 1, ATTN_NORM, 0);

			//no explosion 
			self->dmg = 0;
			break;
	}

	if (self->dmg)
	{
		if (self->spawnflags & 8)
			T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_ENTRANCE);
		else
			T_RadiusDamage (self, attacker, self->dmg, NULL, self->dmg+40, MOD_EXPLOSIVE);
		BecomeExplosion1 (ent);
	}
	else
		G_FreeEdict (ent);

	
	if (self->spawnflags & 8)
	{
		WallStatus = 0;
		if (attacker->client) 
		{
			if (attacker->client->pers.team == TeamBase)
			{
				i = rand() % 3;
				switch (i) {
				case 0:
					gi.bprintf (PRINT_MEDIUM,"%s dislikes being on the %s team\n", attacker->client->pers.netname, teams[attacker->client->pers.team]->name);
					break;
				case 1:
					gi.bprintf (PRINT_MEDIUM,"%s lets the other team in\n", attacker->client->pers.netname);
					break;
				case 2:
				default:
					gi.bprintf (PRINT_MEDIUM,"%s blames defection on lag\n", attacker->client->pers.netname);
					break;
				}
				attacker->client->resp.score -= bonus[BD_WALL_BONUS];
				if (teams[attacker->client->pers.team]) 
					teams[attacker->client->pers.team]->total_score -= bonus[BD_WALL_BONUS];
			}
			else
			{
				gi.bprintf (PRINT_MEDIUM,"%s takes out %s team's defences\n", attacker->client->pers.netname, teams[TeamBase]->name);
				attacker->client->resp.score += bonus[BD_WALL_BONUS];
				if (teams[attacker->client->pers.team]) 
					teams[attacker->client->pers.team]->total_score += bonus[BD_WALL_BONUS];
			}
		}
	}


	G_UseTargets (self, attacker);

	VectorCopy (oldorigin, self->s.origin);
	VectorCopy (oldvelocity, self->velocity);
	VectorCopy (oldsize, self->size);
	self->solid = SOLID_NOT;
	self->svflags |= SVF_NOCLIENT;
	KillBox (self);
	gi.linkentity (self);
}


void func_explosive_use(edict_t *self, edict_t *other, edict_t *activator)
{
	func_explosive_explode (self, self, other, self->health, vec3_origin);
}

void func_explosive_respawn (edict_t *self)
{
	int Players;

	self->solid = SOLID_BSP;
	self->svflags &= ~SVF_NOCLIENT;
	self->takedamage = DAMAGE_YES;

	//give it some health
	Players = NumClients();
	if (!Players)
		Players = 1;
	self->max_health = self->gib_health * Players;
	self->health = self->max_health;

	//check for entrance
	if (self->spawnflags & 8)
		WallStatus = 8;

	gi.linkentity (self);
}
	
void func_explosive_spawn (edict_t *self, edict_t *other, edict_t *activator)
{
	self->solid = SOLID_BSP;
	self->svflags &= ~SVF_NOCLIENT;
	self->use = NULL;
	KillBox (self);
	gi.linkentity (self);
}

void func_explosive_heal (edict_t *self, edict_t *other, int amount)
{

	if (other->client)
	{
		other->client->base_flag |= BD_WALL_HEAL;
		other->client->base_flag_time = level.time;
	}

	self->health += amount;
	if (self->health > self->max_health)
		self->health = self->max_health;

	if (self->health > (self->max_health * 0.875))
	{
		WallStatus = 8;
		return;
	}
	else if (self->health > (self->max_health * 0.75))
	{
		WallStatus = 7;
		return;
	}
	else if (self->health > (self->max_health * 0.625))
	{
		WallStatus = 6;
		return;
	}
	else if (self->health > (self->max_health * 0.5))
	{
		WallStatus = 5;
		return;
	}
	else if (self->health > (self->max_health * 0.375))
	{
		WallStatus = 4;
		return;
	}
	else if (self->health > (self->max_health * 0.25))
	{
		WallStatus = 3;
		return;
	}
	else if (self->health > (self->max_health * 0.125))
	{
		WallStatus = 2;
		return;
	}
	else if (self->health > 0)
	{
		WallStatus = 1;
		return;
	}

	WallStatus = 0;
	//Dunno why this aint working
	//WallStatus = (self->health / self->max_health) * 8;

	return;
}


void func_explosive_pain (edict_t *self, edict_t *other, float kick, int damage)
{
	vec3_t	point;
	int count;

	switch (self->style)
	{
		case 1:
		default:
			if (damage > DAMAGE_MEDIUM) 
			{
				count = 2 + random() * 4;
				while(count--)
				{
					point[0] = self->absmin[0] + random() * self->size[0];
					point[1] = self->absmin[1] + random() * self->size[1];
					point[2] = self->absmin[2] + random() * self->size[2];
					ThrowDebris (self, "models/objects/debris2/tris.md2", 2, point);
				}
			}
			break;
		case 2:
			if (damage > DAMAGE_HIGH) 
			{
				count = random() * 3;
				while(count--)
				{
					point[0] = self->absmin[0] + random() * self->size[0];
					point[1] = self->absmin[1] + random() * self->size[1];
					point[2] = self->absmin[2] + random() * self->size[2];

					
					gi.WriteByte (svc_temp_entity);
					gi.WriteByte (TE_PLASMATRAIL);
					gi.WritePosition (point);
					gi.WriteDir (vec3_origin);
					gi.multicast (point, MULTICAST_PVS);
				}
			}
			break;
		case 3:
			if (damage > DAMAGE_HIGH) 
			{
				count = random() * 3;
				while(count--)
				{
					point[0] = self->absmin[0] + random() * self->size[0];
					point[1] = self->absmin[1] + random() * self->size[1];
					point[2] = self->absmin[2] + random() * self->size[2];
					ThrowDebris (self, "models/objects/debris3/tris.md2", 4, point);
				}
			}
		case 4:
			//FIXME add burning effect for wood
			if (damage > DAMAGE_HIGH) 
			{
				//FIXME spawn flame
			}
			break;
		case 5:
			if (damage > DAMAGE_HIGH) 
			{
				point[0] = self->absmin[0] + random() * self->size[0];
				point[1] = self->absmin[1] + random() * self->size[1];
				point[2] = self->absmin[2] + random() * self->size[2];


				gi.WriteByte (svc_temp_entity);
				gi.WriteByte (TE_SCREEN_SPARKS);
				gi.WritePosition (point);
				gi.WriteDir (vec3_origin);
				gi.multicast (point, MULTICAST_PVS);
			}
			break;
	}

	if (!(self->spawnflags & 8))
		return;
	
	if (other->client)
	{
		other->client->base_flag |= BD_WALL_HURT;
		other->client->base_flag_time = level.time;
	}

	if (self->health > (self->max_health * 0.875))
	{
		WallStatus = 8;
		return;
	}
	else if (self->health > (self->max_health * 0.75))
	{
		WallStatus = 7;
		return;
	}
	else if (self->health > (self->max_health * 0.625))
	{
		WallStatus = 6;
		return;
	}
	else if (self->health > (self->max_health * 0.5))
	{
		WallStatus = 5;
		return;
	}
	else if (self->health > (self->max_health * 0.375))
	{
		WallStatus = 4;
		return;
	}
	else if (self->health > (self->max_health * 0.25))
	{
		WallStatus = 3;
		return;
	}
	else if (self->health > (self->max_health * 0.125))
	{
		WallStatus = 2;
		return;
	}
	else if (self->health > 0)
	{
		WallStatus = 1;
		return;
	}

	WallStatus = 0;
	//Dunno why this aint working
	//WallStatus = (self->health / self->max_health) * 8;

	//Note to self: dont put code here, the function does not get this far ever
	//This isn't a piss take, I've tryed to make things work here for hours, 
	//on more than one occasion.

	return;
}

void SP_func_explosive (edict_t *self)
{
	int Players;

	self->movetype = MOVETYPE_PUSH;

	gi.modelindex ("models/objects/debris1/tris.md2");
	gi.modelindex ("models/objects/debris2/tris.md2");

	gi.setmodel (self, self->model);

	if (self->spawnflags & 1)
	{
		self->svflags |= SVF_NOCLIENT;
		self->solid = SOLID_NOT;
		self->use = func_explosive_spawn;
	}
	else
	{
		self->solid = SOLID_BSP;
		if (self->targetname)
			self->use = func_explosive_use;
	}

	if (self->spawnflags & 2)
		self->s.effects |= EF_ANIM_ALL;
	if (self->spawnflags & 4)
		self->s.effects |= EF_ANIM_ALLFAST;

	if (!self->mass)
		self->mass = 75;
	if (!self->style)
		self->style = 2;

	if (self->use != func_explosive_use)
	{
		if (!self->health)
			self->health = 1000;
		self->gib_health = self->health;
		//Store health from map in gib_health

		Players = NumClients();
		if (!Players)
			Players = 1;
		self->max_health = self->gib_health * Players;
		self->health = self->max_health;

		self->die = func_explosive_explode;

		if (self->spawnflags & 8)
		{
			WallStatus = 8;
		}
		self->pain = func_explosive_pain;
		self->takedamage = DAMAGE_YES;
	}

	gi.linkentity (self);
}
