///////////////////////////////////////////////////////////////////////////////
//	p_utils.c
//
//	misc utility functions for physics.dll
///////////////////////////////////////////////////////////////////////////////

#include "p_global.h"
#include "p_user.h"


///////////////////////////////////////////////////////////////////////////////
//	P_InitEdict
//
///////////////////////////////////////////////////////////////////////////////

void P_InitEdict (edict_t *e)
{
	e->inuse = true;
	e->className = "noclass";
	e->gravity = 1.0;
	e->s.render_scale [0] = e->s.render_scale [1] = e->s.render_scale [2] = 1.0;
	e->s.number = e - g_edicts;
}

///////////////////////////////////////////////////////////////////////////////
//	P_Spawn
//
//	Either finds a free edict, or allocates a new one.
//	Try to avoid reusing an entity that was recently freed, because it
//	can cause the client to think the entity morphed into something else
//	instead of being removed and recreated, which can cause interpolated
//	angles and bad trails.
///////////////////////////////////////////////////////////////////////////////

edict_t *P_Spawn (void)
{
	int			i;
	edict_t		*e;

	e = &g_edicts[(int)maxclients->value+1];
	for ( i=maxclients->value+1 ; i<globals.num_edicts ; i++, e++)
	{
		// the first couple seconds of server time can involve a lot of
		// freeing and allocating, so relax the replacement policy
		if (!e->inuse && ( e->freetime < 2 || level.time - e->freetime > 0.5 ) )
		{
			P_InitEdict (e);
			return e;
		}
	}
	
	if (i == game.maxentities)
		gi.error ("ED_Alloc: no free edicts");
		
	globals.num_edicts++;
	P_InitEdict (e);
	return e;
}

///////////////////////////////////////////////////////////////////////////////
//	P_EntPtr
//
//	returns a pointer to entity # entnum
///////////////////////////////////////////////////////////////////////////////

edict_t	*P_EntPtr (int entnum)
{
	edict_t *e;

	e = &g_edicts[entnum];

	return(e);
}

///////////////////////////////////////////////////////////////////////////////
//	P_EntNum
//
//	returns the corresponding number of entity ent
///////////////////////////////////////////////////////////////////////////////

int	P_EntNum (edict_t *ent)
{
	edict_t	*cur_ent;
	int		i;

	cur_ent = g_edicts;

	for (i = 0; i < globals.num_edicts; i++, cur_ent++)
	{
		if (cur_ent == ent)
			return	i;
	}

	return	globals.num_edicts + 1;
}

///////////////////////////////////////////////////////////////////////////////
//	P_FreeEdict
//
//	Marks the edict as free, saves the gclient_t pointer, initializes the 
//	edict to 0, restores the client pointer and sets a few other things
///////////////////////////////////////////////////////////////////////////////

void P_FreeEdict (edict_t *ent)
{
	gclient_t	*client;

	gi.unlinkentity (ent);		// unlink from world

	//	Nelno:	save the pointer to gclient_t so edicts ALWAYS have one
	client = ent->client;

	memset (ent, 0, sizeof(edict_t));

	ent->client = client;

	ent->className = "freed";
	ent->freetime = level.time;
	ent->inuse = false;
}

///////////////////////////////////////////////////////////////////////////////
//	P_FirstEntity
//
//	returns the first entity in the entity list
///////////////////////////////////////////////////////////////////////////////

userEntity_t *P_FirstEntity(void)
{
	return	(g_edicts);
}

///////////////////////////////////////////////////////////////////////////////
//	P_NextEntity
//
//	returns the entity after ent in the entity list
///////////////////////////////////////////////////////////////////////////////

userEntity_t *P_NextEntity (edict_t *ent)
{
	edict_t		*cur_ent;
	int			i;

	for (i = P_EntNum (ent) + 1; i < globals.num_edicts; i++, cur_ent++)
	{
		cur_ent = &g_edicts [i];
		if (!cur_ent->inuse)
			continue;

		return	(userEntity_t *) cur_ent;
	}

	return	NULL;
}

///////////////////////////////////////////////////////////////////////////////
//	P_TouchTriggers
//
//	Nelno:	forms a list of all the triggers with any part of their volume 
//			inside the area specified by ent->mins/ent->maxs.
//			For each entity in the list, calls its touch functions
///////////////////////////////////////////////////////////////////////////////

void	P_TouchTriggers (edict_t *ent)
{
	int			i, num;
	edict_t		*touch [MAX_EDICTS], *hit;

	// dead things don't activate triggers!
	if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0))
		return;

	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS);

	// be careful, it is possible to have an entity in this
	// list removed before we get to it (killtriggered)
	for (i=0 ; i<num ; i++)
	{
		hit = touch[i];
		if (!hit->inuse)
			continue;
		if (!hit->touch)
			continue;
		hit->touch (hit, ent, NULL, NULL);
	}
}


///////////////////////////////////////////////////////////////////////////////
//	P_TouchSolids
//
//	Call after linking a new trigger in during gameplay
//	to force all entities it covers to immediately touch it
///////////////////////////////////////////////////////////////////////////////

void	P_TouchSolids (edict_t *ent)
{
	int			i, num;
	edict_t		*touch[MAX_EDICTS], *hit;

	num = gi.BoxEdicts (ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_SOLID);

	// be careful, it is possible to have an entity in this
	// list removed before we get to it (killtriggered)
	for (i=0 ; i<num ; i++)
	{
		hit = touch[i];
		if (!hit->inuse)
			continue;
		if (ent->touch)
			ent->touch (hit, ent, NULL, NULL);
		if (!ent->inuse)
			break;
	}
}


///	Nelno: move to COMMON.DLL

///////////////////////////////////////////////////////////////////////////////
//	KillBox
//
//	Kills all entities that would touch the proposed new positioning
//	of ent.  Ent should be unlinked before calling this!
///////////////////////////////////////////////////////////////////////////////

qboolean KillBox (edict_t *ent)
{
	trace_t		tr;

	while (1)
	{
		tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, NULL, MASK_PLAYERSOLID);
		if (!tr.ent)
			break;

		// nail it
//		T_Damage (tr.ent, ent, ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 0, DAMAGE_NO_PROTECTION);

		// if we didn't kill it, fail
		if (tr.ent->solid)
			return false;
	}

	return true;		// all clear
}

