// ************************************************************************
//
//		w_equip.cpp
//
// This is for all selectable items.
// While some of these items (like the C4) can still be considered "weapons", 
// they don't use the "weapon" code, and so it is useful (and less of a load 
// on the overburdened w_fire.cpp module) to separate "equipment" out.
// ************************************************************************

#include "g_local.h"
#include "w_weapons.h"
#include "ai_private.h"	// so we know what a bodyhuman_c is
#include "../strings/items.h"

const unsigned short	MEDKIT_HEAL_DEFAULT	 = 25;
const float				REALISTIC_MOVESCALE	 = 0.5625;


extern edict_t	*SV_TestEntityPosition (edict_t *ent);

extern void SetProjVel(edict_t &self, edict_t &newEnt, float fwd, float right, float up);
extern void SetProjPhysics(edict_t &self, float friction, float gravity, float airresistance, float bouyancy, float elasticity);

// need to know about leaning when we toss c4
extern edict_t *GetLeanBuddy(edict_t *owner);

//yurg - don't wanna make it like this but the player .dll nonsense is just too annoying to deal with
void cacheForItem(equipment_t curEquip)
{
	switch(curEquip)
	{
	case SFE_FLASHPACK:
		game_ghoul.FindObject("Items/Projectiles", "flashpak")->RegistrationLock();
		gi.soundindex("Weapons/gren/bounce.wav");
		break;
//	case SFE_NEURAL_GRENADE:
//		gi.effectindex("weapons/world/neural");
		break;
	case SFE_C4:
		game_ghoul.FindObject("Items/Projectiles", "C4")->RegistrationLock();
		gi.soundindex("Weapons/C4/c4attch.wav");
		gi.soundindex("Weapons/C4/Beep.wav");
		break;
	case SFE_LIGHT_GOGGLES:
		gi.soundindex("Weapons/Goggles/on.wav");
		gi.soundindex("Weapons/Goggles/off.wav");
		break;
	case SFE_CLAYMORE:
		game_ghoul.FindObject("Items/Projectiles", "claymore")->RegistrationLock();
		gi.effectindex("weapons/world/claymore");
		gi.soundindex("Weapons/C4/c4attch.wav");
		gi.soundindex("Weapons/Claymore/Beep.wav");
		break;
	case SFE_MEDKIT:
		break;
	case SFE_GRENADE:
		game_ghoul.FindObject("Items/Projectiles", "grenade")->RegistrationLock();
		gi.effectindex("weapons/world/grenadeexplode");
		gi.soundindex("Weapons/gren/bounce.wav");
		break;
	default:
		break;
	}
}



//------------------------------------MEDKIT-------------------------------------------
qboolean tryToHeal(edict_t *ent,int amountToHeal);

bool medkitUse(edict_t &ent, itemSlot_c &slot)
{
	if (dm->dmRule_REALISTIC_DAMAGE())
	{
		// heal leg and arm damage, but not health!
		bodyhuman_c	*body = NULL;

		if (body = (bodyhuman_c*)ent.client->body)
		{
			body->RemoveLimbDamage();
			resetMovescale(&ent, 0);
		}
		gi.sound(&ent, CHAN_ITEM, gi.soundindex("dm/healthpu.wav"), 1.0, ATTN_IDLE, 0);
		return true;
	}

	bool didWeHeal = !!tryToHeal(&ent, MEDKIT_HEAL_DEFAULT);
	
	if (!didWeHeal)
	{		
		// print the "We're at full health, we don't need this, Bozo!" message
		gi.SP_Print(&ent, ITEMS_FULL_HEALTH);
	}
	return didWeHeal;
}

//------------------------------------GOGGLES-------------------------------------------

bool goggleUse(edict_t &ent, itemSlot_c &slot)
{
	if (!ent.client)
		return true;

	if (slot.getSlotStatus())
	{	// Goggles are on!
		ent.client->goggles_on = true;
		gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/Goggles/on.wav"), .6, ATTN_IDLE, 0);//fixme
	}
	else
	{
		ent.client->goggles_on = false;
		if (!game.cinematicfreeze)
		{
			gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/Goggles/off.wav"), .6, ATTN_IDLE, 0);//fixme
		}
	}
	return true;
}


//------------------------------------GRENADE-------------------------------------------

// Grenades are weapons, used by opponents as well.  For this reason, most of the functionality resides in w_fire.
extern void createGrenade(edict_t *owner, vec3_t loc, vec3_t vel, qboolean enemy);

bool grenadeUse(edict_t &ent, itemSlot_c &slot)
{
	vec3_t fwdV, rightV, upV;
	vec3_t vel, pos;
	edict_t *leanBuddy = GetLeanBuddy(&ent);

	// Decide on velocity.  Start by getting directional vectors.
	if(ent.client)
	{
		AngleVectors(ent.client->ps.viewangles, fwdV, rightV, upV);
	}
	else
	{
		AngleVectors(ent.s.angles, fwdV, rightV, upV);
	}

	VectorMA(ent.velocity,	475.0,				fwdV,	vel);
	VectorMA(vel,			gi.flrand(-15,15),	rightV, vel);
	VectorMA(vel,			gi.flrand(300,350),	upV,	vel);
	
	// kef -- take into account player leaning
	if (leanBuddy)
	{
		VectorCopy(leanBuddy->s.origin, pos);
		pos[2] = ent.s.origin[2] + ent.viewheight-20.0;
	}
	else
	{
		VectorCopy(ent.s.origin, pos);
		pos[2] += ent.viewheight-20.0;
	}

	createGrenade(&ent, pos, vel, false);
	return true;
}

//------------------------------------FLASHPACK-------------------------------------------

void flashTouch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
	if(game.cinematicfreeze)
	{	// We are in a cinematic, remove all volatile objects.
		G_FreeEdict(self);
		return;
	}

	if(plane && VectorLengthSquared(self->velocity) > 100)
	{
		gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/gren/bounce.wav"), .6, 2, 0);//fixme - bounce
	}
}

void flashpackExplode(edict_t *ent)
{
	vec3_t	pos;

	// if this thing is trying to explode during a cinematic, just get rid of it
	if (!game.cinematicfreeze)
	{
		VectorCopy(ent->s.origin, pos);
		pos[2] += 15;

		ent->solid = SOLID_NOT;

		BlindingLight(pos, 10000, 0.99, 0.15);

		FX_Flashpack(pos);
		T_RadiusDamage (ent, ent->owner, 20, ent, 100, MOD_FIRE, 0);
	}
	G_FreeEdict(ent);

	//this should probably affect enemies as well...
}

void flashpackFunc(edict_t &ent)
{
	edict_t *flashpack;
	edict_t *leanBuddy = GetLeanBuddy(&ent);

	flashpack = G_Spawn();
	SetProjVel(ent, *flashpack, 400, 0, gi.flrand(200, 400));
	SetProjPhysics(*flashpack, .7, 1.0, 0, 0, .7);
	// kef -- take into account player leaning
	if (leanBuddy)
	{
		VectorCopy(leanBuddy->s.origin, flashpack->s.origin);
		flashpack->s.origin[2] = ent.s.origin[2] + ent.viewheight;
	}
	else
	{
		VectorCopy(ent.s.origin, flashpack->s.origin);
		flashpack->s.origin[2] += ent.viewheight;
	}

	VectorSet (flashpack->mins, -2, -2, -3);
	VectorSet (flashpack->maxs, 2, 2, 3);
	flashpack->health = 100;
	flashpack->think = flashpackExplode;
	flashpack->nextthink = level.time + 1.5;
	VectorSet(flashpack->avelocity, gi.irand(-300, 300), gi.irand(-300, 300), gi.irand(-300, 300));
	//gi.setmodel(flashpack,"models/objects/generic/chunks_wall/tris.fm");
	game_ghoul.SetSimpleGhoulModel(flashpack, "Items/Projectiles", "flashpak");
	gi.linkentity(flashpack);
	flashpack->owner = &ent;
	flashpack->touch = flashTouch;
	flashpack->flags = FL_THROWN_WPN;

	// Play grenade throwing sound
	gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/gren/throw.wav"), .6, 1, 0);//fixme - bounce

	if(SV_TestEntityPosition(flashpack))
	{
		flashpack->touch(flashpack, g_edicts, 0, 0);
	}

}

bool flashpackUse(edict_t &ent, itemSlot_c &slot)
{
	flashpackFunc(ent);
	return true;
}

//--------------------------------NEURAL GRENADE----------------------------------------

bool neuralGrenadeUse(edict_t &ent, itemSlot_c &slot)
{
#ifndef _OEM_
	T_RadiusDamage (&ent, &ent, 400, &ent, 256, MOD_NEURAL_GRENADE, DT_NEURAL|DT_SHOCK|DAMAGE_NO_KNOCKBACK);
	gmonster.RadiusDeafen(&ent, 400, 300);
	fxRunner.setPos2(ent.s.origin);
	fxRunner.exec("weapons/world/emitter", ent.s.origin);
#endif
	return true;
}


//---------------------------------C4/PLASTIQUE------------------------------------------

void c4Explode(edict_t *self)
{
	if(self->health < 104)
	{
		gmonster.SpookEnemies(self->s.origin, 160, SPOOK_EXPLOSIVE);//hahaha
		gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/Beep.wav"), .6, ATTN_NORM, 0);
		self->health++;
		self->nextthink = level.time + .4;
	}
	else
	{
		if (!game.cinematicfreeze)
		{	// if we're in a cinematic don't do any of this...just free the edict.
			vec3_t fwd, pos;

			AngleVectors(self->s.angles, fwd, NULL, NULL);
			VectorMA(self->s.origin, 10, fwd, pos);

			T_RadiusDamage2(self, self->owner, pos, 250, 32, 200, NULL, MOD_C4, DT_MANGLE|DT_DIRECTIONALGORE);

			BlindingLight(self->s.origin, 2500, 0.8, 0.5);
			gmonster.RadiusDeafen(self, 300, 300);

			fxRunner.setDir(fwd);
			fxRunner.exec("weapons/world/c4explode", self->s.origin);
			IncreaseSpawnIntensity(.6);
		}
		G_FreeEdict(self);
	}
}

void c4Touch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
	if(game.cinematicfreeze)
	{	// We are in a cinematic, remove all volatile objects.
		G_FreeEdict(self);
		return;
	}

	if(plane)
	{
		if(plane->normal)
		{
			if(other == g_edicts)
			{
				if(self->gravity)
				{
					gmonster.SpookEnemies(self->s.origin, 160, SPOOK_EXPLOSIVE);
					gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/c4attch.wav"), .6, ATTN_NORM, 0);
					self->gravity = 0;
					VectorClear(self->velocity);
					VectorClear(self->avelocity);
					if(plane)
					{
						vectoangles(plane->normal, self->s.angles);
					}
				}
			}
		}
	}
}

bool c4use(edict_t &ent, itemSlot_c &slot)
{
	edict_t *c4;
	edict_t *leanBuddy = GetLeanBuddy(&ent);

	c4 = G_Spawn();
	game_ghoul.SetSimpleGhoulModel(c4, "Items/Projectiles", "C4");
	SetProjVel(ent, *c4, 410.0, gi.flrand(-30, 30), gi.flrand(150, 180));
	SetProjPhysics(*c4, 1.0, 1.0, 0, 0, 0.0);

	// kef -- take into account player leaning
	if (leanBuddy)
	{
		VectorCopy(leanBuddy->s.origin, c4->s.origin);
		c4->s.origin[2] = ent.s.origin[2] + ent.viewheight;
	}
	else
	{
		VectorCopy(ent.s.origin, c4->s.origin);
		c4->s.origin[2] += ent.viewheight;
	}

	VectorSet (c4->mins, -2, -2, -2);
	VectorSet (c4->maxs, 2, 2, 2);
	c4->health = 100;
	c4->think = c4Explode;
	c4->nextthink = level.time + .5;
	gi.linkentity(c4);
	c4->owner = &ent;
	c4->touch = c4Touch;
	c4->flags = FL_THROWN_WPN;
	VectorSet(c4->avelocity, gi.irand(-300, 300), gi.irand(-300, 300), gi.irand(-300, 300));

	// Play grenade throwing sound
	gi.sound(&ent, CHAN_VOICE, gi.soundindex("Weapons/gren/throw.wav"), .6, 1, 0);//fixme - bounce

	//c4->physicsFlags |= PHYS_ATTACHED|PHYS_ATTACH_COPYANG;

	if(SV_TestEntityPosition(c4))
	{
		c4->touch(c4, g_edicts, 0, 0);
	}
	return true;
}

//-----------------------------CLAYMORE-----------------------------------

void claymoreThink(edict_t *self)
{
	if(game.cinematicfreeze)
	{	// We are in a cinematic, remove all volatile objects.
		G_FreeEdict(self);
		return;
	}

	self->owner = g_edicts;
	CRadiusContent rad(self->s.origin, 128);

	if(self->health < 3)
	{	// play activate sound
		gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/Claymore/Beep.wav"), .6, ATTN_NORM, 0);//fixme
		self->health = 3;
	}

	for(int i = 0; i < rad.getNumFound(); i++)
	{
		edict_t *search = rad.foundEdict(i);

		if(search->client || search->ai || (self->gib_health < 1))
		{
			if((search->health > 0)||(self->gib_health < 1))
			{
				vec3_t	pos;

				self->owner = self->targetEnt;

				VectorCopy(self->s.origin, pos);
				pos[2] += 10;

				T_RadiusDamage2(self, self->owner, self->s.origin, 300, 150, 100, NULL, MOD_CLAYMORE, DT_MANGLE|DT_DIRECTIONALGORE);
				gmonster.RadiusDeafen(self, 300, 300);

//				fxRunner.exec("weapons/world/airexplode", self->s.origin);
//				FX_C4Explosion(self);

//				BlindingLight(pos, 5000, 0.8, 0.5);
//				ShakeCameras (self->s.origin, 500, 300, 25);
				IncreaseSpawnIntensity(.4);
				fxRunner.exec("weapons/world/claymore", self->s.origin);
				G_FreeEdict(self);

				return;
			}
		}
	}

	self->gib_health--;
	self->nextthink += .2;
}

void claymore_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	if(!self->gib_health)
	{	//already killed myself.
		return;
	}

	self->gib_health = 0;

	self->think = claymoreThink;
	self->nextthink = level.time + 0.2;
}

void claymoreTouch(edict_t *self, edict_t *other, cplane_t *plane, mtexinfo_t *surf)
{
	if(self->health < 2)
	{
		gi.sound(self, CHAN_VOICE, gi.soundindex("Weapons/C4/c4attch.wav"), .6, ATTN_NORM, 0);
		self->health = 2;
	}
}


bool claymoreUse(edict_t &ent, itemSlot_c &slot)
{
#ifndef _OEM_
	edict_t *claymore;

	claymore = G_Spawn();
	game_ghoul.SetSimpleGhoulModel(claymore, "Items/Projectiles", "claymore");
	SetProjVel(ent, *claymore, 0.0, 0.0, 0.0);
	SetProjPhysics(*claymore, 1.0, 1.0, 0, 0, 0.0);
	VectorCopy(ent.s.origin, claymore->s.origin);
	claymore->s.origin[2] += 24;
	claymore->gib_health = 200;//timer
	claymore->health = 10;
	claymore->think = claymoreThink;
	claymore->nextthink = level.time + 3.0;
	claymore->owner = &ent;
	claymore->targetEnt = &ent;
	claymore->takedamage = 1;
	claymore->die = claymore_die;
	VectorSet(claymore->s.angles, 270, 90, 90);
	claymore->clipmask = CONTENTS_SOLID|CONTENTS_MONSTER|CONTENTS_SHOT;
	VectorSet (claymore->mins, -4, -4, 0);
	VectorSet (claymore->maxs, 4, 4, 6);
	gi.linkentity(claymore);
	claymore->touch = claymoreTouch;
	claymore->flags = FL_THROWN_WPN;
	claymore->health = 1;
#endif
	return true;
}


bool DoWeHaveTheFlag(edict_t *ent)
{
	if (ent->ctf_flags)
		return true;
	return false;
}

