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



/////////////////////////////////////////////////////////////////////////
/// Init Server State
/////////////////////////////////////////////////////////////////////////

static void LightStyle (int style, char *val)
{
	//	gi.dprintf("Lightstyles were purged\n");
}

///////////////////////////////////////////////////////////////////////////////
//	SetOrigin
//
///////////////////////////////////////////////////////////////////////////////

static void SetOrigin (userEntity_t *ent, float x, float y, float z)
{
	ent->s.origin [0] = x;
	ent->s.origin [1] = y;
	ent->s.origin [2] = z;

	gi.linkentity (ent);
//	gi.dprintf("SetOrigin and call linkentity\n");
}

///////////////////////////////////////////////////////////////////////////////
//	SetOrigin2
//
///////////////////////////////////////////////////////////////////////////////

static void SetOrigin2 (userEntity_t *ent, vec3_t pos)
{
	ent->s.origin [0] = pos [0];
	ent->s.origin [1] = pos [1];
	ent->s.origin [2] = pos [2];

	gi.linkentity (ent);
//	gi.dprintf("SetOrigin and call linkentuty\n");
}

///////////////////////////////////////////////////////////////////////////////
//	TraceLine
//
///////////////////////////////////////////////////////////////////////////////

#define	MASK_NOMONSTERS (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW)
#define	MASK_MONSTERS (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_WINDOW|CONTENTS_MONSTER)

static void TraceLine (vec3_t start, vec3_t end, int nomonsters, userEntity_t *passent, userTrace_t *trace)
{
	trace_t		t;

	if (nomonsters)
		t = gi.trace (start, vec3_origin, vec3_origin, end, passent, MASK_NOMONSTERS);
	else
		t = gi.trace (start, vec3_origin, vec3_origin, end, passent, MASK_MONSTERS);

	trace->allsolid = t.allsolid;
	trace->startsolid = t.startsolid;
	trace->fraction = t.fraction;

	trace->endpos [0] = t.endpos [0];
	trace->endpos [1] = t.endpos [1];
	trace->endpos [2] = t.endpos [2];

	trace->ent = t.ent;

	trace->planeNormal [0] = t.plane.normal [0];
	trace->planeNormal [1] = t.plane.normal [1];
	trace->planeNormal [2] = t.plane.normal [2];

	trace->inwater = 0;
	trace->inopen = 0;

	//gi.dprintf("TraceLine, use trace\n");
}

///////////////////////////////////////////////////////////////////////////////
//	SetSize
//
///////////////////////////////////////////////////////////////////////////////

static void SetSize(userEntity_t *self, float minx, float miny, float minz, float maxx, float maxy, float maxz)
{
	self->mins [0] = minx;
	self->mins [1] = miny;
	self->mins [2] = minz;

	self->maxs [0] = maxx;
	self->maxs [1] = maxy;
	self->maxs [2] = maxz;

//	serverState.LinkEntity (self);
//	gi.dprintf("SetSize, user linkentuty\n");
}

///////////////////////////////////////////////////////////////////////////////
//	HunkAlloc
//
///////////////////////////////////////////////////////////////////////////////

static void *Hunk_Alloc(int size)
{
	gi.error ("Hunk_Alloc, OBSOLETE!!!  Use com->malloc instead!!\n");

	return(NULL);
}

///////////////////////////////////////////////////////////////////////////////
//	GetCvar
//	
///////////////////////////////////////////////////////////////////////////////

static	float	GetCvar (char *varName)
{
	cvar_t	*cv;

	cv = gi.cvar (varName, "", 0);
	return	atof (cv->string);
}

///////////////////////////////////////////////////////////////////////////////
//	SetCvar
//	
///////////////////////////////////////////////////////////////////////////////

static	void	SetCvar (char *varName, char *value)
{
	gi.cvar_forceset (varName, value);
}


///////////////////////////////////////////////////////////////////////////////
//	bprint
//
//	sends a text message to all clients
///////////////////////////////////////////////////////////////////////////////

static void bprint (char *fmt, ...)
{
	char	szBuf	[1024];
	va_list	ap;

	va_start (ap, fmt);
	vsprintf (szBuf, fmt, ap);
	va_end (ap);

	gi.bprintf (PRINT_HIGH, "%s", szBuf);
}

///////////////////////////////////////////////////////////////////////////////
//	sprint
//
//	sends a text message to a single client
///////////////////////////////////////////////////////////////////////////////

static void sprint (edict_t *ent, char *fmt, ...)
{
	char	szBuf	[1024];
	va_list	ap;

	va_start (ap, fmt);
	vsprintf (szBuf, fmt, ap);
	va_end (ap);

	gi.cprintf (ent, PRINT_HIGH, "%s", szBuf);
}

///////////////////////////////////////////////////////////////////////////////
//	particle
//
///////////////////////////////////////////////////////////////////////////////

static void particle (vec3_t org, vec3_t dir, int color, int count)
{
	gi.dprintf("particle:  damn good question\n");
}

///////////////////////////////////////////////////////////////////////////////
//	centerprint
//
///////////////////////////////////////////////////////////////////////////////

static void centerprint(edict_t *ent, float secs, char *fmt, ...)
{
	gi.dprintf("centerprint: translate seconds\n");
}

///////////////////////////////////////////////////////////////////////////////
//	
//
///////////////////////////////////////////////////////////////////////////////

void sound (userEntity_t *ent, int channel, char *sample, int volume, float attenuation)
{
	int		index;

	index = gi.soundindex (sample);
	
	gi.sound (ent, channel, index, volume, attenuation, 0);
}

#ifdef	QUAKE1_NETWORK_CODE

///////////////////////////////////////////////////////////////////////////////
//	WriteFloat
//
//	sends a float to one or all clients
///////////////////////////////////////////////////////////////////////////////

#define	RELIABLE	TRUE
#define	UNRELIABLE	FALSE

static void WriteFloat (userEntity_t *ent, int dest, float c) 
{
	if (dest == MSG_ONE)
		//	send to one client
		gi.unicast (ent, RELIABLE);
	else
		//	send to all clients
		gi.multicast (vec3_origin, MULTICAST_ALL);

	gi.WriteFloat (c);
}

///////////////////////////////////////////////////////////////////////////////
//	WriteByte
//
//	sends a byte to one or all clients
///////////////////////////////////////////////////////////////////////////////

static void WriteByte(userEntity_t *ent, int dest, int c) 
{
	Void
}

static void WriteChar(userEntity_t *ent, int dest, int c) {}
static void WriteShort(userEntity_t *ent, int dest, int c) {}
static void WriteLong(userEntity_t *ent, int dest, int c) {}
static void WriteAngle(userEntity_t *ent, int dest, float angle) {}
static void WriteCoord(userEntity_t *ent, int dest, float coord) {}
static void WriteString(userEntity_t *ent, int dest, char *str) {}
static void WriteEntity(userEntity_t *destEnt, int dest, userEntity_t *ent) {}
#endif

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

static void ClientCmd(userEntity_t *ent, char *cmd)
{
	gi.dprintf("ClientCmd : WTF\n");
}


///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////
	
// inventory create/delete methods
static invHandle_t *InventoryNew(void)
{
	gi.dprintf("inventorynew called\n");
	return(NULL);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void InventoryFree(invHandle_t *ptr) 
{
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

struct userInventory_s *InventoryFindItem(invHandle_t *ptr, char *name) 
{ 
	return(NULL); 
}
///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

struct userInventory_s *InventoryFirstItem(invHandle_t *ptr) 
{ 
	return(NULL); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

struct userInventory_s *InventoryNextItem(invHandle_t *ptr) 
{ 
	return(NULL); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int   InventoryAddItem(invHandle_t *ptr, struct userInventory_s *item) 
{ 
	return(0); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void  InventoryDeleteItem(invHandle_t *ptr, struct userInventory_s *item) 
{
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void  InventoryPrecache(char *className, char *iconName, char *modelName) 
{
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int ModelInfo(int modelIndex, userModelInfo_t *modelInfo) 
{ 
	gi.dprintf ("ModelInfo: not implemented.\n");

	return(0); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int FrameInfo(int modelIndex, int frameIndex, userFrameInfo_t *frameInfo) 
{ 
	gi.dprintf ("FrameInfo function no longer supported.\nUse dk_GetFrameName.\n");
	return(0); 
}

///////////////////////////////////////////////////////////////////////////////
//	AmbientSound
//
//	starts a sound at a specified location
//	Channel is auto-selected
//
//	Q2FIXME:	rework this function for ambient sounds that can be toggled
//	Q2FIXME:	implement fade rate for ambient sounds (attenuation modifier)
///////////////////////////////////////////////////////////////////////////////

void AmbientSound(vec3_t pos, char *samp, int vol, int attenuation, float fade) 
{
	int		index;

	index = gi.soundindex (samp);

	gi.positioned_sound (pos, NULL, 0, index, vol, attenuation, 0);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void MakeStatic(userEntity_t *ent) 
{
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

char *GetArgv(int arg) 
{ 
	return(NULL); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int   GetArgc(void) 
{ 
	return(0); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void  SetFunction(char *funcName, void *func, char *funcDesc) 
{
	gi.error ("SetFunction not supported in Q2 base, ass!\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void *GetFunction(char *funcName) 
{ 
	gi.error ("GetFunction not supported in Q2 base, ass!\n");
	return(NULL); 
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void  ListFunction(char *funcName) 
{
	gi.error ("ListFunction not supported in Q2 base, ass!\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void  TraceBox (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs,
		int nomonsters, userEntity_t *passent, userTrace_t *trace)
{
	gi.error ("TraceBox: use trace_q2, ass.\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int VertInfo (userEntity_t *self, int surfaceIndex, int frameIndex, int vertIndex, vec3_t vert)
{
	gi.dprintf ("VertInfo: not implemented\n");
	return(0);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

int	SurfInfo (int modelIndex, char *surfName)
{
	gi.dprintf ("SurfInfo: not implemented\n");
	return(0);
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void SetClientViewEntity (userEntity_t *client, userEntity_t *viewEntity)
{
	gi.dprintf("SetClientViewEntity not implemented.\n");
	client->view_entity = viewEntity;
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void SetClientInputEntity (userEntity_t *client, userEntity_t *inputEntity)
{
	gi.dprintf("SetClientInputEntity not implemented.\n");
	client->input_entity = inputEntity;
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void StickyInit (userEntity_t *parent, userEntity_t *child, unsigned long int flags)
{
	gi.dprintf ("StickyInit: not implemented\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void StickyRemove (userEntity_t *parent, userEntity_t *child)
{
	gi.dprintf("SkickyRemove: not implemented.\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void StickySetFlags (userEntity_t *parent, userEntity_t *child, unsigned long int flags)
{
	gi.dprintf ("SkickySetFlags: not implemented.\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void StickyRemoveChildren (userEntity_t *parent)
{
	gi.dprintf ("StickyRemoveChildren: not implemented.\n");
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void StickySurfaceInit (userEntity_t *parent, userEntity_t *child, unsigned long int flags, char *f_surf, int f_vIndex, char *r_surf, int r_vIndex, vec3_t offset)
{
	gi.dprintf ("StickySurfaceInit: not implemented.\n");
}

///////////////////////////////////////////////////////////////////////////////
//	SetModel
//
///////////////////////////////////////////////////////////////////////////////

void	SetModel (userEntity_t *self, char *modelName)
{
	//	Q2FIXME:	for testing until LWO code is in

	if (self->movetype != MOVETYPE_PUSH && self->solid != SOLID_NOT && self->solid != SOLID_TRIGGER)
	{
		gi.setmodel (self, "models/kingg/kingg.md2");
		self->modelName = "models/kingg/kingg.md2";

		gi.linkentity (self);

		return;
	}

	gi.setmodel (self, modelName);

	gi.linkentity (self);

	self->modelName = modelName;
}

///////////////////////////////////////////////////////////////////////////////
//
///////////////////////////////////////////////////////////////////////////////

void	dk_ClientCmd (userEntity_t *ent, char *cmd)
{
	gi.error ("ClientCmd no longer supported.  See Nelson.\n");
}

///////////////////////////////////////////////////////////////////////////////
//	InitiServerState
//
///////////////////////////////////////////////////////////////////////////////

void	InitServerState (game_import_t *import)
{
	memset (&serverState, 0x00, sizeof (serverState_t));

	serverState.Con_Printf     = import->conprintf;
	serverState.Con_Dprintf    = import->dprintf;
	serverState.Precache_Model = import->modelindex;
	serverState.Precache_Sound = import->soundindex;

	serverState.SetOrigin     = SetOrigin;
	serverState.SetOrigin2    = SetOrigin2;
	serverState.SetModel      = SetModel;
	serverState.TraceLine     = TraceLine;
	serverState.PointContents = import->pointcontents;
	serverState.RemoveEntity  = P_FreeEdict;
	serverState.SetSize       = SetSize;

	serverState.SpawnEntity   = P_Spawn;
	serverState.FirstEntity   = P_FirstEntity;
	serverState.NextEntity    = P_NextEntity;	//	Nelno: implemented this

	serverState.Hunk_Alloc = Hunk_Alloc;

	serverState.bprint      = bprint;
	serverState.sprint      = sprint;
	serverState.particle    = particle;
	serverState.centerprint = centerprint;
	serverState.sound       = sound;

#ifdef	QUAKE1_NETWORK_CODE
	serverState.WriteFloat  = WriteFloat;
	serverState.WriteByte   = WriteByte;
	serverState.WriteChar   = WriteByte;
	serverState.WriteShort  = WriteShort;
	serverState.WriteLong   = WriteLong;
	serverState.WriteAngle  = WriteAngle;
	serverState.WriteCoord  = WriteCoord;
	serverState.WriteString = WriteString;
	serverState.WriteEntity = WriteEntity;
#endif

	serverState.ServerCmd = import->AddCommandString;
	serverState.ClientCmd = ClientCmd;

	serverState.GetCvar = GetCvar;
	serverState.SetCvar = SetCvar;

	serverState.printxy = import->printxy;
	serverState.clearxy = import->clearxy;

	serverState.InventoryNew       = import->InventoryNew;
	serverState.InventoryFree      = import->InventoryFree;
	serverState.InventoryFindItem  = import->InventoryFindItem;
	serverState.InventoryFirstItem = import->InventoryFirstItem;
	serverState.InventoryNextItem  = import->InventoryNextItem;

	serverState.InventoryAddItem    = import->InventoryAddItem;
	serverState.InventoryDeleteItem = import->InventoryDeleteItem;
	serverState.InventoryPrecache   = import->InventoryPrecache;

	serverState.ModelInfo = ModelInfo;
	serverState.FrameInfo = FrameInfo;
	serverState.GetFrameName = import->dk_GetFrameName;
	serverState.ForceModelLoad = import->dk_ForceModelLoad;

	serverState.AmbientSound = AmbientSound;
	serverState.MakeStatic   = MakeStatic;

	serverState.GetArgv = import->argv;
	serverState.GetArgc = import->argc;

	serverState.Error = import->error;

	serverState.SetFunction = SetFunction;
	serverState.GetFunction = GetFunction;
	serverState.ListFunction = ListFunction;

	serverState.VertInfo = VertInfo;
	serverState.SurfInfo = SurfInfo;

	serverState.SetClientViewEntity  = SetClientViewEntity;
	serverState.SetClientInputEntity = SetClientInputEntity;

	serverState.StickyInit           = StickyInit;
	serverState.StickyRemove         = StickyRemove;
	serverState.StickySetFlags       = StickySetFlags;
	serverState.StickyRemoveChildren = StickyRemoveChildren;
	serverState.StickySurfaceInit    = StickySurfaceInit;

	//	Nelno's additions
	serverState.AddCommand	= import->AddCommand;
	serverState.LightStyle	= LightStyle;

	//	New for Q2
	serverState.trace_q2			= import->trace;
	serverState.inPVS				= import->inPVS;
	serverState.inPHS				= import->inPHS;
	serverState.SetAreaPortalState	= import->SetAreaPortalState;
	serverState.AreasConnected		= import->AreasConnected;

	serverState.LinkEntity		= import->linkentity;
	serverState.UnlinkEntity	= import->unlinkentity;
	serverState.BoxEdicts		= import->BoxEdicts;
	serverState.Pmove			= import->Pmove;

	serverState.MultiCast		= import->multicast;
	serverState.UniCast			= import->unicast;
	serverState.WriteChar		= import->WriteChar;
	serverState.WriteByte		= import->WriteByte;
	serverState.WriteShort		= import->WriteShort;
	serverState.WriteLong		= import->WriteLong;
	serverState.WriteFloat		= import->WriteFloat;
	serverState.WriteString		= import->WriteString;
	serverState.WritePosition	= import->WritePosition;
	serverState.WriteDir		= import->WriteDir;
	serverState.WriteAngle		= import->WriteAngle;
	
	serverState.DebugGraph		= import->DebugGraph;
	serverState.ForceCvar		= import->cvar_forceset;
	
	serverState.PositionedSound	= import->positioned_sound;
	serverState.ConfigString	= import->configstring;

	serverState.ModelIndex	= import->modelindex;
	serverState.SoundIndex	= import->soundindex;
	serverState.ImageIndex	= import->imageindex;

	serverState.bprintf		= import->bprintf;
	serverState.dprintf		= import->dprintf;
	serverState.cprintf		= import->cprintf;
	serverState.centerprintf= import->centerprintf;

	serverState.TagMalloc	= import->TagMalloc;
	serverState.TagFree		= import->TagFree;
	serverState.FreeTags	= import->FreeTags;

	//	set up pointers to global structures contained in physics.dll
	serverState.game	= &game;
	serverState.level	= &level;
	serverState.gi		= import;
	serverState.globals	= &globals;
	
	serverState.g_edicts= g_edicts;
}

