/*
========================================================
File:				Weapon_Mine

Written by: iD Software, adapted by Ch0wW
Latest update: 30/12/13
========================================================
*/

#include "../g_local.h"

#define MINE_ACTIVATION_TIME	2500
#define MINE_DETONATION_TIME	500

#define DAMAGE_DIRECT			0		// If you want to kill someone by touching
#define DAMAGE_RADIUS			60
#define DISTANCE_RADIUS			175

/*
================
ProximityMine_Explode
================
*/
static void ProximityMine_Explode( gentity_t *mine ) {
	G_ExplodeMissile( mine );
	// if the prox mine has a trigger free it
	if (mine->activator) {
		G_FreeEntity(mine->activator);
		mine->activator = NULL;
	}
}

/*
================
ProximityMine_Die
================
*/
static void ProximityMine_Die( gentity_t *ent, gentity_t *inflictor, gentity_t *attacker, int damage, int mod ) {
	ent->think = ProximityMine_Explode;
	ent->nextthink = level.time + 1;
}

/*
================
AntiPersMine_Trigger
Used for verification BEFORE exploding the mine
================
*/
void AntiPersMine_Trigger( gentity_t *trigger, gentity_t *other, trace_t *trace ) {
	vec3_t		v;
	gentity_t	*mine;

	if( !other->r.client )
		return;

	// trigger is a cube, do a distance test now to act as if it's a sphere
	VectorSubtract( trigger->s.pos.trBase, other->s.pos.trBase, v );
	if( VectorLength( v ) > trigger->parent->splashRadius ) {
		return;
	}

	// don't trigger same team mines or self mines in DM
	if ( GAMEMODE_GetMode() < GT_TEAM && trigger->parent->s.clientNum == other->r.client->ps.clientNum)
		return;
	if ( GAMEMODE_GetMode() >= GT_TEAM && trigger->parent->s.generic1 == other->r.client->sess.sessionTeam)
		return;

	// Check for ability to damage so we don't get triggered thru walls, closed doors, etc...
	if( !CanDamage( other, trigger->s.pos.trBase ) ) 
		return;

	// trigger the mine!
	mine = trigger->parent;
	mine->s.loopSound = 0;
	mine->nextthink = level.time + MINE_DETONATION_TIME;
	G_AddEvent( mine, EV_PROXIMITY_MINE_TRIGGER, 0 );

	G_FreeEntity( trigger );
}

/*
================
ProximityMine_Activate
================
*/
static void ProximityMine_Activate( gentity_t *ent ) {
	gentity_t	*trigger;
	float		r;

	ent->think = ProximityMine_Explode;

	ent->takedamage = true;
	ent->health = 1;
	ent->die = ProximityMine_Die;

	ent->s.loopSound = G_SoundIndex( "sound/weapons/proxmine/wstbtick.wav" );

	// build the proximity trigger
	trigger = G_Spawn ();

	trigger->classname = "proxmine_trigger";

	r = ent->splashRadius;
	VectorSet( trigger->r.mins, -r, -r, -r );
	VectorSet( trigger->r.maxs, r, r, r );

	G_SetOrigin( trigger, ent->s.pos.trBase );

	trigger->parent =			ent;
	trigger->r.contents =		CONTENTS_TRIGGER;
	trigger->touch =			AntiPersMine_Trigger;

	trap_LinkEntity				(trigger);

	// set pointer to trigger so the entity can be freed when the mine explodes
	ent->activator =			trigger;
}

/*
================
ProximityMine_ExplodeOnPlayer
================
*/
static void ProximityMine_ExplodeOnPlayer( gentity_t *mine ) {
	gentity_t	*player;

	player = mine->enemy;
	player->r.client->ps.eFlags &= ~EF_TICKING;

	G_SetOrigin( mine, player->s.pos.trBase );
	// make sure the explosion gets to the client
	mine->r.svFlags &= ~SVF_NOCLIENT;
	mine->splashMethodOfDeath = MOD_PROXIMITY_MINE;
	G_ExplodeMissile( mine );

}

/*
================
AntiPersMine_Activation
================
*/
void AntiPersMine_Activation ( gentity_t *ent, gentity_t *other, trace_t *trace ) {

	if( ent->s.pos.trType != TR_GRAVITY )
		return;

	// if it's a player, stick it on to them (flag them and remove this entity)
	if( other->s.eType == ET_PLAYER && other->health > 0 ) {
		G_BounceMissile( ent, trace );
		return;
	}
	
	SnapVectorTowards( trace->endpos, ent->s.pos.trBase );
	G_SetOrigin( ent, trace->endpos );
	ent->s.pos.trType = TR_STATIONARY;
	VectorClear( ent->s.pos.trDelta );

	G_AddEvent( ent, EV_PROXIMITY_MINE_STICK, trace->surfaceFlags );

	ent->think = ProximityMine_Activate;
	ent->nextthink = level.time + MINE_ACTIVATION_TIME;					// REPERE : Grenade stick, initialisation

	vectoangles( trace->plane.normal, ent->s.angles );
	ent->s.angles[0] += 90;

	// link the prox mine to the other entity
	ent->enemy = other;
	ent->die = ProximityMine_Die;
	VectorCopy(trace->plane.normal, ent->movedir);
	VectorSet(ent->r.mins, -4, -4, -4);
	VectorSet(ent->r.maxs, 4, 4, 4);
	trap_LinkEntity(ent);
}

/*
=================
fire_prox
=================
*/
gentity_t *fire_prox( gentity_t *self, vec3_t start, vec3_t dir, int clientnum ) {
	gentity_t	*bolt;

	VectorNormalize (dir);

	bolt = G_Spawn();
	bolt->classname =			"proxmine";
	bolt->nextthink =			level.time + 5000;
	bolt->think =				G_ExplodeMissile;

	bolt->s.eType =				ET_MISSILE;
	bolt->r.svFlags =			SVF_USE_CURRENT_ORIGIN;
	bolt->s.weapon =			WP_EQUIP_APMINE;
	bolt->s.eFlags =			0;
	bolt->r.ownerNum =			clientnum;
	bolt->parent =				self;
	
	bolt->damage =				DAMAGE_DIRECT;
	bolt->splashDamage =		DAMAGE_RADIUS;
	bolt->splashRadius =		DISTANCE_RADIUS;
	bolt->methodOfDeath =		MOD_MACHINEGUN;
	bolt->splashMethodOfDeath = MOD_MACHINEGUN;
	
	bolt->clipmask =			MASK_SHOT;
	bolt->target_ent =			NULL;
	// count is used to check if the prox mine left the player bbox
	// if count == 1 then the prox mine left the player bbox and can attack to it
	bolt->count = 0;

	//FIXME: we prolly wanna abuse another field
	bolt->s.generic1 = self->r.client->sess.sessionTeam;

	bolt->s.pos.trType = TR_GRAVITY;
	bolt->s.pos.trTime = level.time - 50;		// move a bit on the very first frame
	VectorCopy( start, bolt->s.pos.trBase );
	VectorScale( dir, 700, bolt->s.pos.trDelta );
	SnapVector( bolt->s.pos.trDelta );			// save net bandwidth

	VectorCopy (start, bolt->r.currentOrigin);

	return bolt;
}

/*
==============
WPN_AntiPersMine_Fire
Used for weapon usage
==============
*/
void WPN_AntiPersMine_Fire (gentity_t *ent, vec3_t forward, vec3_t muzzle ) {
	gentity_t	*m;

	// extra vertical velocity
	forward[2] += 0.2f;
	VectorNormalize( forward );

	m = fire_prox (ent, muzzle, forward, ent->r.client->ps.clientNum);

	VectorAdd( m->s.pos.trDelta, ent->r.client->ps.velocity, m->s.pos.trDelta );	// "real" physics
}