/*
Copyright (C) 1997-2001 Id Software, Inc.
Copyright (C) 2000-2002 Mr. Hyde and Mad Dog

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "g_local.h"
//
// mappack stuff by mr. ed, modified extensively for Tremor by dwh
//

//Spawns a user defined model, you can specify whether its solid, if so how big the box is, and apply nearly
//any effect to the entity.
//
//	PLAYER		set this if you want to use a player model
//
//	Note : These flags override any frame settings you may have enterered
//	ANIM01		cycle between frames 0 and 1 at 2 hz
//	ANIM23		cycle between frames 2 and 3 at 2 hz
//	ANIM_ALL		cycle through all frames at 2hz
//	ANIM_ALLFAST	cycle through all frames at 10hz
//
//	START_OFF		Start inactive, when triggered display the model
//	TOGGLE		Start active, when triggered become inactive
//	NO_MODEL		Don't use a model. Usefull for placeing particle effects and
//				dynamic lights on their own
//
//	"usermodel" = The model to load (models/ is already coded)
//	"startframe" = The starting frame : default 0
//	"userframes" = The number of frames you want to display after startframe
//	"solidstate" = 1 : SOLID_NOT - not solid at all
//			       2 : SOLID_BBOX - solid and affected by gravity
//			       3 : NO DROP - solid but not affected by gravity
//                 4 : SOLID_NOT, but affect by gravity
//
//	NOTE : if you want the model to be solid then you must enter vector values into the following fields :
//	"bleft" = the point that is at the bottom left of the models bounding box in a model editor
//	"tright" = the point that is at the top left of the models bounding box in a model editor
//

#define	TOGGLE		    2
#define	PLAYER_MODEL	8
#define	NO_MODEL		16
#define ANIM_ONCE		32

void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator);
void modelspawn_think (edict_t *self)
{
	self->s.frame++;
	if (self->s.frame >= self->framenumbers)
	{
		self->s.frame = self->startframe;
		if(self->spawnflags & ANIM_ONCE)
		{
			model_spawn_use(self,world,world);
			return;
		}
	}
	self->nextthink = level.time + FRAMETIME;
	gi.linkentity(self);
}

void model_spawn_use (edict_t *self, edict_t *other, edict_t *activator)
{
	if (self->delay) //we started off
	{
		self->svflags &= ~SVF_NOCLIENT;
		self->delay = 0;
		if(self->framenumbers > 1)
		{
			self->think = modelspawn_think;
			self->nextthink = level.time + FRAMETIME;
		}
		self->s.sound = self->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
		self->s.attenuation = self->attenuation;
#endif
	}
	else             //we started active
	{
		self->svflags |= SVF_NOCLIENT;
		self->delay = 1;
		self->use = model_spawn_use;
		self->think = NULL;
		self->nextthink = 0;
		self->s.sound = 0;
	}
}

void model_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
	edict_t	*e, *next;

	e = self->movewith_next;
	while(e) {
		next = e->movewith_next;
		if(e->solid == SOLID_NOT) {
			e->nextthink = 0;
			G_FreeEdict(e);
		} else
			BecomeExplosion1 (e);
		e = next;
	}

	BecomeExplosion1(self);
}

#define ANIM_MASK (EF_ANIM01|EF_ANIM23|EF_ANIM_ALL|EF_ANIM_ALLFAST)

void SP_model_spawn (edict_t *ent)
{
	char	modelname[256];

	//paranoia checks
	if ((!ent->usermodel) && !(ent->spawnflags & NO_MODEL) && !(ent->spawnflags & PLAYER_MODEL))
	{
		gi.dprintf("%s without a model at %s\n", ent->classname, vtos(ent->s.origin));
		G_FreeEdict(ent);
		return;
	}

	switch (ent->solidstate)
	{
		case 1 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
		case 2 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_TOSS; break;
		case 3 : ent->solid = SOLID_BBOX; ent->movetype = MOVETYPE_NONE; break;
		case 4 : ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_TOSS; break;
		default: ent->solid = SOLID_NOT; ent->movetype = MOVETYPE_NONE; break;
	}
	if (ent->solid != SOLID_NOT ) {
		if (ent->health > 0) {
			ent->die = model_die;
			ent->takedamage = DAMAGE_YES;
		}
	}

	switch (ent->style)
	{
		case 1 : ent->s.effects |= EF_ANIM01; break;
		case 2 : ent->s.effects |= EF_ANIM23; break;
		case 3 : ent->s.effects |= EF_ANIM_ALL; break;
		case 4 : ent->s.effects |= EF_ANIM_ALLFAST; break;
	}

	// DWH: Rather than use one value (renderfx) we use the
	//      actual values for effects and renderfx. All may
	//      be combined.
	ent->s.effects  |= ent->effects;
	ent->s.renderfx |= ent->renderfx;

	if (ent->startframe < 0)
		ent->startframe = 0;
	if (!ent->framenumbers)
		ent->framenumbers = 1;
	// Change framenumbers to last frame to play
	ent->framenumbers += ent->startframe;

	if (ent->bleft)
	{
		VectorCopy (ent->bleft, ent->mins);
	}
	else
	{
		if (ent->solid != SOLID_NOT)
		{
			gi.dprintf("%s solid with no bleft vector at %s\n", ent->classname, vtos(ent->s.origin));
			ent->solid = SOLID_NOT;
		}
	}

	if (ent->tright)
	{
		VectorCopy (ent->tright, ent->maxs);
	}
	else
	{
		if (ent->solid != SOLID_NOT)
		{
			gi.dprintf("%s solid with no tright vector at %s\n", ent->classname, vtos(ent->s.origin));
			ent->solid = SOLID_NOT;
		}
	}

//	if(ent->movewith && (ent->solid == SOLID_BBOX))
	if(ent->movewith)
		ent->movetype = MOVETYPE_PUSH;

	if (ent->solid != SOLID_NOT)
		ent->clipmask = CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER;

	if (ent->spawnflags & NO_MODEL)
	{	// For rendering effects to work, we MUST use a model
		ent->s.modelindex = gi.modelindex ("sprites/point.sp2");
		ent->movetype = MOVETYPE_NOCLIP;
	}
	else
	{
		if (ent->spawnflags & PLAYER_MODEL) {
			if(!ent->usermodel || !strlen(ent->usermodel))
				ent->s.modelindex = MAX_MODELS-1;
			else
			{
				if (strstr(ent->usermodel,"tris.md2"))
					Com_sprintf(modelname, sizeof(modelname), "players/%s", ent->usermodel);
				else
					Com_sprintf(modelname, sizeof(modelname), "players/%s/tris.md2", ent->usermodel);
				ent->s.modelindex = gi.modelindex(modelname);
			}
		}
		else
		{
			if (strstr(ent->usermodel,".sp2")) {
				// Knightmare- check for "sprites/" already in path
				if ( !strncmp(ent->usermodel, "sprites/", 8) )
					Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
				else
					Com_sprintf(modelname, sizeof(modelname), "sprites/%s", ent->usermodel);
			}
			else {
				// Knightmare- check for "models/" already in path
				if ( !strncmp(ent->usermodel, "models/", 7) )
					Com_sprintf(modelname, sizeof(modelname), "%s", ent->usermodel);
				else
					Com_sprintf(modelname, sizeof(modelname), "models/%s", ent->usermodel);
			}
			ent->s.modelindex = gi.modelindex (modelname);
		}
		ent->s.frame = ent->startframe;
	}

	if (st.noise)
		ent->noise_index = gi.soundindex  (st.noise);
	ent->s.sound = ent->noise_index;
#ifdef LOOP_SOUND_ATTENUATION
	ent->s.attenuation = ent->attenuation;
#endif

//	if (ent->skinnum) // Knightmare- selectable skin
//		ent->s.skinnum = ent->skinnum;

	if (ent->spawnflags & ANIM_ONCE)
		ent->spawnflags |= TOGGLE;

	if (ent->spawnflags & TOGGLE)
	{
		ent->delay = 0;
		ent->use = model_spawn_use;
	}

	if(!(ent->s.effects & ANIM_MASK) && (ent->framenumbers > 1))
	{
		ent->think = modelspawn_think;
		ent->nextthink = level.time + 2*FRAMETIME;
	}
	gi.linkentity (ent);
}
