#include "client.h"
#include "localent.h"

/*
==================
ClipVelocity

Slide off of the impacting object
returns the blocked flags (1 = floor, 2 = step / wall)
==================
*/
#define	STOP_EPSILON	0.1

int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
{
	float	backoff;
	float	change;
	int		i, blocked;
	
	blocked = 0;
	
	if (FLOAT_GT_ZERO(normal[2]))
		blocked |= 1;		// floor

	if (!normal[2])
		blocked |= 2;		// step
	
	backoff = DotProduct (in, normal) * overbounce;

	for (i=0 ; i<3 ; i++)
	{
		change = normal[i]*backoff;
		out[i] = in[i] - change;
		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
			out[i] = 0;
	}
	
	return blocked;
}

void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, trace_t *tr );
void LE_Physics_Toss (localent_t *ent)
{
	trace_t tr;
	vec3_t	vel;

	//copy old origin
	FastVectorCopy (ent->ent.origin, ent->ent.oldorigin);

	//FIXME: properly scale this to client FPS.
	ent->velocity[2] -= 1;

	//scale velocity based on something stupid
	FastVectorCopy (ent->velocity, vel);
	VectorScale (vel, cl.lerpfrac, vel);

	//add velocity to origin
	VectorAdd (ent->ent.origin, vel, ent->ent.origin);

	//check we didn't hit the world
	tr = CM_BoxTrace (ent->ent.oldorigin, ent->ent.origin, ent->mins, ent->maxs, 0, MASK_SOLID);
	if (tr.fraction != 1.0f)
	{
		//vec3_t down;
		//if we did, back off.
		FastVectorCopy (tr.endpos, ent->ent.origin);
		if (ent->touch)
			ent->touch (ent, &tr.plane, tr.surface);

		//check for stop
		ClipVelocity (ent->velocity, tr.plane.normal, ent->velocity, ent->movetype == MOVETYPE_BOUNCE ? 1.7f : 1.0f);

		if ((tr.plane.normal[2] > 0.7f && ent->movetype == MOVETYPE_TOSS) || ((ent->velocity[2] < 0.01f && ent->velocity[2] > -0.01f) && ent->movetype == MOVETYPE_BOUNCE))
			ent->movetype = MOVETYPE_NONE;
	}

	//note!! this only clips to entities that we currently know about (as the client).
	//this means if a localent is outside the PVS of a client, it will only clip to
	//the world.

	//fixme: do we want this?
	/*CL_ClipMoveToEntities (ent->ent.oldorigin, ent->mins, ent->maxs, ent->ent.origin, &tr);
	if (tr.ent) {
		if (ent->touch)
			ent->touch (ent, &tr.plane, tr.surface);
		
		VectorCopy (tr.endpos, ent->ent.origin);

		//check for stop
		ClipVelocity (ent->velocity, tr.plane.normal, ent->velocity, ent->movetype == MOVETYPE_BOUNCE ? 1.7 : 1);

		if (tr.plane.normal[2] > 0.7f && ent->movetype == MOVETYPE_TOSS || ((ent->velocity[2] < 0.01f && ent->velocity[2] > -0.01f) && ent->movetype == MOVETYPE_BOUNCE))
			ent->movetype = MOVETYPE_NONE;

	}*/
}

/*void LE_Physics_Fly (localent_t *ent)
{

}*/

void LE_RunEntity (localent_t *ent)
{
	switch (ent->movetype)
	{
		case MOVETYPE_NONE:
			break;
		case MOVETYPE_TOSS:
		case MOVETYPE_BOUNCE:
			LE_Physics_Toss (ent);
			break;
		case MOVETYPE_FLYMISSILE:
			//LE_Physics_Fly (ent);
			break;
		default:
			Com_Printf ("LE_RunEntity: bad movetype %i", LOG_CLIENT, ent->movetype);
	}

	if (ent->think && cl.time >= ent->nextthink )
		ent->think (ent);

	//if (ent->ent.flags & EF_GIB)
	//	CL_DiminishingTrail (ent->ent.oldorigin, ent->ent.origin, ent->ent, ent->ent.flags);
}
