diff --git a/backup.lst b/backup.lst index a7ad03f5..ac2dd11e 100644 --- a/backup.lst +++ b/backup.lst @@ -12,9 +12,11 @@ release.bat launchers.bat todo.log -public\ baserc\ +cl_dll\ +public\ physic\ +sv_dll\ render\ vprogs\ vsound\ diff --git a/baserc/baserc.dsp b/baserc/baserc.dsp index 1223863c..97fd4daf 100644 --- a/baserc/baserc.dsp +++ b/baserc/baserc.dsp @@ -54,7 +54,8 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 -# ADD LINK32 msvcrt.lib /nologo /dll /profile /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# SUBTRACT LINK32 /profile /nodefaultlib # Begin Custom Build TargetDir=\Xash3D\src_main\temp\baserc\!release InputPath=\Xash3D\src_main\temp\baserc\!release\baserc.dll @@ -79,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 diff --git a/common/bsplib/map.c b/common/bsplib/map.c index 91cf7b1d..68020a91 100644 --- a/common/bsplib/map.c +++ b/common/bsplib/map.c @@ -1008,10 +1008,10 @@ bool ParseMapEntity( void ) b->contents = CONTENTS_AREAPORTAL; c_areaportals++; mapent->areaportalnum = c_areaportals; - // set the portal number as "style" - com.sprintf (str, "%i", c_areaportals); - SetKeyValue (mapent, "style", str); - MoveBrushesToWorld (mapent); + // set the portal number as "skin" + com.sprintf( str, "%i", c_areaportals ); + SetKeyValue( mapent, "skin", str ); + MoveBrushesToWorld( mapent ); return true; } diff --git a/common/common.dsp b/common/common.dsp index 31b11d95..d2f83b69 100644 --- a/common/common.dsp +++ b/common/common.dsp @@ -54,7 +54,8 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 -# ADD LINK32 msvcrt.lib /nologo /dll /profile /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# SUBTRACT LINK32 /profile # Begin Custom Build TargetDir=\Xash3D\src_main\temp\common\!release InputPath=\Xash3D\src_main\temp\common\!release\common.dll @@ -79,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /I "./" /I "../public" /I "./bsplib/" /I "./ripper" /I "./common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "./bsplib/" /I "./ripper" /I "./common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 diff --git a/debug.bat b/debug.bat index b834fd8b..a69f93f0 100644 --- a/debug.bat +++ b/debug.bat @@ -26,6 +26,9 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% render/render.dsp %CONFIG%"render - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 +%MSDEV% sv_dll/server.dsp %CONFIG%"server - Win32 Debug" %build_target% +if errorlevel 1 set BUILD_ERROR=1 + %MSDEV% vprogs/vprogs.dsp %CONFIG%"vprogs - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index e7c9f5cb..8f88333c 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -34,7 +34,7 @@ void CL_WriteDemoHeader( const char *name ) { char buf_data[MAX_MSGLEN]; entity_state_t *state, nullstate; - edict_t *ent; + pr_edict_t *ent; sizebuf_t buf; int i, len; diff --git a/engine/client/cl_effects.c b/engine/client/cl_effects.c index fbc323f7..92919185 100644 --- a/engine/client/cl_effects.c +++ b/engine/client/cl_effects.c @@ -245,7 +245,7 @@ DECALS MANAGEMENT ============================================================== */ -#define MAX_DECALS 2048 +#define MAX_DECAL_MARKS 2048 #define DECAL_FADETIME (30 * 1000) // 30 seconds #define DECAL_STAYTIME (120 * 1000) // 120 seconds @@ -263,7 +263,7 @@ typedef struct cdecal_s static cdecal_t cl_activeDecals; static cdecal_t *cl_freeDecals; -static cdecal_t cl_decalList[MAX_DECALS]; +static cdecal_t cl_decalList[MAX_DECAL_MARKS]; /* ================= @@ -324,7 +324,7 @@ void CL_ClearDecals( void ) cl_activeDecals.prev = &cl_activeDecals; cl_freeDecals = cl_decalList; - for( i = 0; i < MAX_DECALS - 1; i++ ) + for( i = 0; i < MAX_DECAL_MARKS - 1; i++ ) cl_decalList[i].next = &cl_decalList[i+1]; } @@ -682,7 +682,7 @@ void CL_AddParticles( void ) if( p->flags & PARTICLE_BOUNCE ) { - edict_t *clent = PRVM_EDICT_NUM( cl.frame.ps.number ); + pr_edict_t *clent = PRVM_EDICT_NUM( cl.frame.ps.number ); // bouncy particle VectorSet(mins, -radius, -radius, -radius); diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 8198fe70..251c6cbe 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -13,7 +13,7 @@ FRAME PARSING ========================================================================= */ -void CL_UpdateEntityFileds( edict_t *ent ) +void CL_UpdateEntityFileds( pr_edict_t *ent ) { // copy state to progs ent->progs.cl->classname = cl.edict_classnames[ent->priv.cl->current.classname]; @@ -34,7 +34,7 @@ to the current frame */ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t *old, bool unchanged ) { - edict_t *ent; + pr_edict_t *ent; entity_state_t *state; ent = PRVM_EDICT_NUM( newnum ); @@ -154,7 +154,7 @@ void CL_ParsePacketEntities( sizebuf_t *msg, frame_t *oldframe, frame_t *newfram if( oldnum > newnum ) { // delta from baseline - edict_t *ent = PRVM_EDICT_NUM( newnum ); + pr_edict_t *ent = PRVM_EDICT_NUM( newnum ); CL_DeltaEntity( msg, newframe, newnum, &ent->priv.cl->baseline, false ); continue; } @@ -188,7 +188,7 @@ CL_ParseFrame void CL_ParseFrame( sizebuf_t *msg ) { int cmd, len, idx; - edict_t *clent; + pr_edict_t *clent; frame_t *old; memset( &cl.frame, 0, sizeof(cl.frame)); @@ -304,7 +304,7 @@ CL_AddPacketEntities void CL_AddPacketEntities( frame_t *frame ) { entity_state_t *s1; - edict_t *ent; + pr_edict_t *ent; int pnum; for( pnum = 0; pnum < frame->num_entities; pnum++ ) @@ -324,7 +324,7 @@ CL_AddViewWeapon */ void CL_AddViewWeapon( entity_state_t *ps ) { - edict_t *view; // view model + pr_edict_t *view; // view model // allow the gun to be completely removed if( !cl_gun->value ) return; @@ -459,7 +459,7 @@ void CL_AddEntities( void ) void CL_GetEntitySoundSpatialization( int entnum, vec3_t origin, vec3_t velocity ) { - edict_t *ent; + pr_edict_t *ent; cmodel_t *cmodel; vec3_t midPoint; diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index 61905972..f07808a5 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -328,12 +328,10 @@ void CL_BaseMove( usercmd_t *cmd ) // adjust for speed key / running if( in_speed.state & 1 ^ cl_run->integer ) { - cmd->buttons &= ~BUTTON_WALKING; cmd->forwardmove *= 2; cmd->sidemove *= 2; cmd->upmove *= 2; } - else cmd->buttons |= BUTTON_WALKING; } void CL_ClampPitch (void) @@ -357,19 +355,19 @@ CL_CmdButtons void CL_CmdButtons( usercmd_t *cmd ) { if ( in_attack.state & 3 ) - cmd->buttons |= BUTTON_ATTACK; + cmd->buttons |= IN_ATTACK; in_attack.state &= ~2; if ( in_attack2.state & 3 ) - cmd->buttons |= BUTTON_ATTACK2; + cmd->buttons |= IN_ATTACK2; in_attack2.state &= ~2; if (in_use.state & 3) - cmd->buttons |= BUTTON_USE; + cmd->buttons |= IN_USE; in_use.state &= ~2; - if( anykeydown && cls.key_dest == key_game) - cmd->buttons |= BUTTON_ANY; + if (in_speed.state & 3) + cmd->buttons |= IN_RUN; } /* diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2e410e69..95d40f40 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -684,11 +684,11 @@ void CL_PrepSound( void ) { int i, sndcount; - for( i = 1, sndcount = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i][0]; i++ ) + for( i = 0, sndcount = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i][0]; i++ ) sndcount++; // total num sounds S_BeginRegistration(); - for( i = 1; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i][0]; i++ ) + for( i = 0; i < MAX_SOUNDS && cl.configstrings[CS_SOUNDS+i][0]; i++ ) { cl.sound_precache[i] = S_RegisterSound( cl.configstrings[CS_SOUNDS+i]); Cvar_SetValue( "scr_loading", scr_loading->value + 5.0f/sndcount ); @@ -737,6 +737,12 @@ void CL_PrepVideo( void ) SCR_UpdateScreen(); } + for( i = 0; i < MAX_DECALS && cl.configstrings[CS_DECALS+i][0]; i++ ) + { + com.strncpy( name, cl.configstrings[CS_DECALS+i], MAX_STRING ); + // FIXME: register shaders + } + // setup sky and free unneeded stuff re->EndRegistration( cl.configstrings[CS_SKYNAME] ); Cvar_SetValue("scr_loading", 100.0f ); // all done diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index cfc58e4b..e64cea6c 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -234,7 +234,7 @@ void CL_ParseBaseline( sizebuf_t *msg ) { int newnum; entity_state_t nullstate; - edict_t *ent; + pr_edict_t *ent; CL_VM_Begin(); memset( &nullstate, 0, sizeof(nullstate)); @@ -280,6 +280,14 @@ void CL_ParseConfigString( sizebuf_t *msg ) { cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound( cl.configstrings[i] ); } + else if( i >= CS_DECALS && i < CS_DECALS+MAX_DECALS && cl.video_prepped ) + { + // FIXME: register decal shaders here + } + else if( i >= CS_USER_MESSAGES && i < CS_USER_MESSAGES+MAX_USER_MESSAGES ) + { + // FIXME: register user message here + } else if( i >= CS_CLASSNAMES && i < CS_CLASSNAMES+MAX_CLASSNAMES ) { // prvm classnames for search by classname on client vm diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index a3a78d62..6e99ef7f 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -67,13 +67,13 @@ void CL_CheckPredictionError (void) CL_Trace ================== */ -trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, edict_t *passedict, int contentsmask ) +trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, pr_edict_t *passedict, int contentsmask ) { vec3_t hullmins, hullmaxs; int i, bodycontents; int passedictprog; bool pointtrace; - edict_t *traceowner, *touch; + pr_edict_t *traceowner, *touch; trace_t trace; vec3_t clipboxmins, clipboxmaxs; // bounding box of entire move area vec3_t clipmins, clipmaxs; // size of the moving object @@ -83,7 +83,7 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons matrix4x4 matrix, imatrix; // matrices to transform into/out of other entity's space cmodel_t *model; // model of other entity int numtouchedicts = 0; // list of entities to test for collisions - edict_t *touchedicts[MAX_EDICTS]; + pr_edict_t *touchedicts[MAX_EDICTS]; VectorCopy( start, clipstart ); VectorCopy( end, clipend ); @@ -95,7 +95,8 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons // clip to world pe->ClipToWorld( &cliptrace, cl.worldmodel, clipstart, clipmins, clipmaxs, clipend, contentsmask ); cliptrace.startstuck = cliptrace.startsolid; - if( cliptrace.startsolid || cliptrace.fraction < 1 ) cliptrace.ent = prog ? prog->edicts : NULL; + if( cliptrace.startsolid || cliptrace.fraction < 1 ) + cliptrace.ent = prog ? (edict_t *)prog->edicts : NULL; if( type == MOVE_WORLDONLY ) return cliptrace; if( type == MOVE_MISSILE ) @@ -178,7 +179,7 @@ trace_t CL_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons if((int)touch->progs.cl->flags & FL_MONSTER) pe->ClipToGenericEntity(&trace, model, touch->progs.cl->mins, touch->progs.cl->maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask ); else pe->ClipToGenericEntity(&trace, model, touch->progs.cl->mins, touch->progs.cl->maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask ); - pe->CombineTraces(&cliptrace, &trace, touch, touch->progs.cl->solid == SOLID_BSP ); + pe->CombineTraces( &cliptrace, &trace, (edict_t *)touch, touch->progs.cl->solid == SOLID_BSP ); } return cliptrace; } diff --git a/engine/client/cl_progs.c b/engine/client/cl_progs.c index ee566de3..edacf392 100644 --- a/engine/client/cl_progs.c +++ b/engine/client/cl_progs.c @@ -116,7 +116,7 @@ mathlib, debugger, and various misc helpers void CL_BeginIncreaseEdicts( void ) { int i; - edict_t *ent; + pr_edict_t *ent; // links don't survive the transition, so unlink everything for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++) @@ -127,20 +127,20 @@ void CL_BeginIncreaseEdicts( void ) void CL_EndIncreaseEdicts( void ) { int i; - edict_t *ent; + pr_edict_t *ent; for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++) { } } -void CL_InitEdict( edict_t *e ) +void CL_InitEdict( pr_edict_t *e ) { e->priv.cl->serialnumber = PRVM_NUM_FOR_EDICT(e); e->priv.cl->free = false; } -void CL_FreeEdict( edict_t *ed ) +void CL_FreeEdict( pr_edict_t *ed ) { ed->priv.cl->freetime = cl.time * 0.001f; ed->priv.cl->free = true; @@ -157,7 +157,7 @@ void CL_FreeEdict( edict_t *ed ) void CL_FreeEdicts( void ) { int i; - edict_t *ent; + pr_edict_t *ent; CL_VM_Begin(); for( i = 1; prog && i < prog->num_edicts; i++ ) @@ -170,7 +170,7 @@ void CL_FreeEdicts( void ) void CL_CountEdicts( void ) { - edict_t *ent; + pr_edict_t *ent; int i, active = 0, models = 0; for (i = 0; i < prog->num_edicts; i++) @@ -199,7 +199,7 @@ void CL_VM_End( void ) PRVM_End; } -bool CL_LoadEdict( edict_t *ent ) +bool CL_LoadEdict( pr_edict_t *ent ) { return true; } diff --git a/engine/client/client.h b/engine/client/client.h index b89ad40d..7e1b0552 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -31,13 +31,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_SERVERS 64 #define ColorIndex(c) (((c) - '0') & 7) -// button bits -#define BUTTON_ATTACK 1 -#define BUTTON_ATTACK2 2 -#define BUTTON_USE 4 -#define BUTTON_WALKING 8 -#define BUTTON_ANY 128 // any key whatsoever - //============================================================================= typedef struct frame_s { @@ -138,6 +131,7 @@ typedef struct string_t edict_classnames[MAX_CLASSNAMES]; sound_t sound_precache[MAX_SOUNDS]; + shader_t decal_shaders[MAX_DECALS]; } client_t; extern client_t cl; @@ -452,7 +446,7 @@ void CL_InitClientProgs( void ); void CL_FreeClientProgs( void ); int CL_GetMaxClients( void ); void CL_DrawHUD( void ); -edict_t *CL_GetEdict( int entnum ); +pr_edict_t *CL_GetEdict( int entnum ); float *CL_FadeColor( float starttime, float endtime ); bool CL_ParseUserMessage( int svc_number ); void CL_FreeEdicts( void ); @@ -538,7 +532,7 @@ void CL_PredictMove (void); void CL_CheckPredictionError (void); int CL_PointContents( const vec3_t point ); bool CL_AmbientLevel( const vec3_t point, float *volumes ); -trace_t CL_Trace( const vec3_t s1, const vec3_t m1, const vec3_t m2, const vec3_t s2, int type, edict_t *ed, int mask ); +trace_t CL_Trace(const vec3_t s1, const vec3_t m1, const vec3_t m2, const vec3_t s2, int type, pr_edict_t *e, int mask); // // cl_ents.c diff --git a/engine/common.h b/engine/common.h index 5feababe..979a26c9 100644 --- a/engine/common.h +++ b/engine/common.h @@ -116,16 +116,6 @@ CLIENT / SERVER SYSTEMS ============================================================== */ -#define FL_CLIENT (1<<0) // this is client -#define FL_MONSTER (1<<1) // this is npc -#define FL_DEADMONSTER (1<<2) // dead npc or dead player -#define FL_WORLDBRUSH (1<<3) // Not moveable/removeable brush entity -#define FL_DORMANT (1<<4) // Entity is dormant, no updates to client -#define FL_FRAMETHINK (1<<5) // entity will be thinking every frame -#define FL_GRAPHED (1<<6) // worldgraph has this ent listed as something that blocks a conection -#define FL_FLOAT (1<<7) // this entity can be floating. FIXME: remove this ? -#define FL_TRACKTRAIN (1<<8) // old stuff... - // encoded bmodel mask #define SOLID_BMODEL 0xffffff @@ -139,6 +129,13 @@ void SV_Shutdown( bool reconnect ); void SV_Frame( dword time ); void SV_PacketEvent( netadr_t from, sizebuf_t *msg ); +// exports +void SV_Transform( edict_t *ed, const vec3_t origin, const matrix3x3 transform ); +void SV_PlaySound( edict_t *ed, float volume, float pitch, const char *sample ); +float *SV_GetModelVerts( edict_t *ent, int *numvertices ); +void SV_PlayerMove( edict_t *ed ); +bool SV_Active( void ); + /* ============================================================== @@ -146,10 +143,12 @@ PRVM INTERACTIONS ============================================================== */ +char *ED_NewString( const char *string, byte *mempool ); + #define prog vm->prog // global callback to vprogs.dll #define PRVM_EDICT_NUM( num ) _PRVM_EDICT_NUM( num, __FILE__, __LINE__ ) -_inline edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line ) +_inline pr_edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line ) { if(!prog) Host_Error(" prog unset at (%s:%d)\n", file, line ); if((n >= 0) && (n < prog->max_edicts)) @@ -163,7 +162,7 @@ _inline edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line ) #define PRVM_NAME (prog->name ? prog->name : "unnamed.dat") #define PRVM_ERROR if( prog ) prog->error_cmd -#define PRVM_NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - prog->edicts)) +#define PRVM_NUM_FOR_EDICT(e) ((int)((pr_edict_t *)(e) - prog->edicts)) #define PRVM_NEXT_EDICT(e) ((e) + 1) #define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e)) #define PRVM_PROG_TO_EDICT(n) (PRVM_EDICT_NUM(n)) @@ -185,7 +184,6 @@ _inline edict_t *_PRVM_EDICT_NUM( int n, const char * file, const int line ) // helper common functions const char *VM_VarArgs( int start_arg ); bool VM_ValidateArgs( const char *builtin, int num_argc ); -void VM_SetTraceGlobals( const trace_t *trace ); #define VM_ValidateString( str ) _VM_ValidateString( str, __FILE__, __LINE__ ) void _VM_ValidateString( const char *s, const char *filename, const int fileline ); void VM_Cmd_Init( void ); @@ -223,6 +221,9 @@ void VM_Cmd_Reset( void ); #define PRVM_ED_FindGlobal vm->FindGlobal #define PRVM_ED_FindFunction vm->FindFunction +edict_t *ED_Alloc( void ); +void ED_Free( edict_t *e); + // builtins and other general functions void VM_ConPrintf( void ); void VM_ConDPrintf( void ); diff --git a/engine/common/com_edict.c b/engine/common/com_edict.c new file mode 100644 index 00000000..c03a4012 --- /dev/null +++ b/engine/common/com_edict.c @@ -0,0 +1,36 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// com_edict.c - generic edict manager +//======================================================================= + +#include "common.h" + +/* +============= +ED_NewString + +FIXME: hashtable ? +============= +*/ +char *ED_NewString( const char *string, byte *mempool ) +{ + char *data, *data_p; + int i, l; + + l = com.strlen( string ) + 1; + data = Mem_Alloc( mempool, l ); + data_p = data; + + for( i = 0; i < l; i++ ) + { + if( string[i] == '\\' && i < l - 1 ) + { + i++; + if( string[i] == 'n' ) + *data_p++ = '\n'; + else *data_p++ = '\\'; + } + else *data_p++ = string[i]; + } + return data; +} diff --git a/engine/common/com_library.h b/engine/common/com_library.h new file mode 100644 index 00000000..8156fe3d --- /dev/null +++ b/engine/common/com_library.h @@ -0,0 +1,125 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// com_library.h - custom dlls loader +//======================================================================= +#ifndef COM_LIBRARY +#define COM_LIBRARY + +#define DOS_SIGNATURE 0x5A4D // MZ +#define NT_SIGNATURE 0x00004550 // PE00 +#define NUMBEROF_DIRECTORY_ENTRIES 16 + +typedef struct +{ + // dos .exe header + word e_magic; // magic number + word e_cblp; // bytes on last page of file + word e_cp; // pages in file + word e_crlc; // relocations + word e_cparhdr; // size of header in paragraphs + word e_minalloc; // minimum extra paragraphs needed + word e_maxalloc; // maximum extra paragraphs needed + word e_ss; // initial (relative) SS value + word e_sp; // initial SP value + word e_csum; // checksum + word e_ip; // initial IP value + word e_cs; // initial (relative) CS value + word e_lfarlc; // file address of relocation table + word e_ovno; // overlay number + word e_res[4]; // reserved words + word e_oemid; // OEM identifier (for e_oeminfo) + word e_oeminfo; // OEM information; e_oemid specific + word e_res2[10]; // reserved words + long e_lfanew; // file address of new exe header +} DOS_HEADER; + +typedef struct +{ + // win .exe header + word Machine; + word NumberOfSections; + dword TimeDateStamp; + dword PointerToSymbolTable; + dword NumberOfSymbols; + word SizeOfOptionalHeader; + word Characteristics; +} PE_HEADER; + +typedef struct +{ + byte Name[8]; // dos name length + + union + { + dword PhysicalAddress; + dword VirtualSize; + } Misc; + + dword VirtualAddress; + dword SizeOfRawData; + dword PointerToRawData; + dword PointerToRelocations; + dword PointerToLinenumbers; + word NumberOfRelocations; + word NumberOfLinenumbers; + dword Characteristics; +} SECTION_HEADER; + +typedef struct +{ + dword VirtualAddress; + dword Size; +} DATA_DIRECTORY; + +typedef struct +{ + word Magic; + byte MajorLinkerVersion; + byte MinorLinkerVersion; + dword SizeOfCode; + dword SizeOfInitializedData; + dword SizeOfUninitializedData; + dword AddressOfEntryPoint; + dword BaseOfCode; + dword BaseOfData; + dword ImageBase; + dword SectionAlignment; + dword FileAlignment; + word MajorOperatingSystemVersion; + word MinorOperatingSystemVersion; + word MajorImageVersion; + word MinorImageVersion; + word MajorSubsystemVersion; + word MinorSubsystemVersion; + dword Win32VersionValue; + dword SizeOfImage; + dword SizeOfHeaders; + dword CheckSum; + word Subsystem; + word DllCharacteristics; + dword SizeOfStackReserve; + dword SizeOfStackCommit; + dword SizeOfHeapReserve; + dword SizeOfHeapCommit; + dword LoaderFlags; + dword NumberOfRvaAndSizes; + + DATA_DIRECTORY DataDirectory[NUMBEROF_DIRECTORY_ENTRIES]; +} OPTIONAL_HEADER; + +typedef struct +{ + dword Characteristics; + dword TimeDateStamp; + word MajorVersion; + word MinorVersion; + dword Name; + dword Base; + dword NumberOfFunctions; + dword NumberOfNames; + dword AddressOfFunctions; // RVA from base of image + dword AddressOfNames; // RVA from base of image + dword AddressOfNameOrdinals; // RVA from base of image +} EXPORT_DIRECTORY; + +#endif//COM_LIBRARY \ No newline at end of file diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index 418f7a56..98e00bcf 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -517,7 +517,7 @@ bool Cmd_CheckMapsList( void ) { Com_ReadToken( ents, 0, &token ); Msg("read token: %s\n", token.string ); - if(!com.strcmp( token.string, "info_player_deatchmatch" )) + if(!com.strcmp( token.string, "info_player_deathmatch" )) num_spawnpoints++; else if(!com.strcmp( token.string, "info_player_start" )) num_spawnpoints++; diff --git a/engine/common/engfuncs.c b/engine/common/engfuncs.c index 06c97d68..7a406358 100644 --- a/engine/common/engfuncs.c +++ b/engine/common/engfuncs.c @@ -8,7 +8,6 @@ #include "mathlib.h" #include "const.h" #include "client.h" -#include "server.h" /* ======================================================================= @@ -36,19 +35,6 @@ void _VM_ValidateString( const char *s, const char *filename, const int fileline if( s[0] <= ' ' ) PRVM_ERROR( "%s: bad string (called at %s:%i)\n", PRVM_NAME, filename, fileline ); } -void VM_SetTraceGlobals( const trace_t *trace ) -{ - prog->globals.sv->trace_allsolid = trace->allsolid; - prog->globals.sv->trace_startsolid = trace->startsolid; - prog->globals.sv->trace_fraction = trace->fraction; - prog->globals.sv->trace_contents = trace->contents; - VectorCopy (trace->endpos, prog->globals.sv->trace_endpos); - VectorCopy (trace->plane.normal, prog->globals.sv->trace_plane_normal); - prog->globals.sv->trace_plane_dist = trace->plane.dist; - if( trace->ent ) prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG( trace->ent ); - else prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG( prog->edicts ); // world -} - /* ========= VM_VarArgs @@ -208,7 +194,7 @@ void Com_Error( ... ) */ void VM_HostError( void ) { - edict_t *ed; + pr_edict_t *ed; const char *s = VM_VarArgs( 0 ); Msg( "====== %s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), s ); @@ -229,7 +215,7 @@ void Ed_Error( ... ) */ void VM_EdictError( void ) { - edict_t *ed; + pr_edict_t *ed; const char *s = VM_VarArgs( 0 ); Msg( "======OBJECT ERROR======\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), s ); @@ -836,7 +822,7 @@ entity spawn( void ) */ void VM_SpawnEdict( void ) { - edict_t *ed; + pr_edict_t *ed; prog->xfunction->builtinsprofile += 20; ed = PRVM_ED_Alloc(); @@ -852,7 +838,7 @@ void remove( entity ent ) */ void VM_RemoveEdict( void ) { - edict_t *ed; + pr_edict_t *ed; if(!VM_ValidateArgs( "remove", 1 )) return; @@ -881,8 +867,8 @@ void nextent( entity ent ) */ void VM_NextEdict( void ) { - edict_t *ent; - int i; + pr_edict_t *ent; + int i; if( !VM_ValidateArgs( "nextent", 1 )) return; @@ -915,7 +901,7 @@ void copyentity( entity src, entity dst ) */ void VM_CopyEdict( void ) { - edict_t *in, *out; + pr_edict_t *in, *out; if(!VM_ValidateArgs( "copyentity", 1 )) return; @@ -936,7 +922,7 @@ void VM_FindEdict( void ) { int e, f; const char *s, *t; - edict_t *ed; + pr_edict_t *ed; if(!VM_ValidateArgs( "find", 2 )) return; @@ -971,9 +957,9 @@ entity findfloat(entity start, .float field, float match) */ void VM_FindField( void ) { - int e, f; - float s; - edict_t *ed; + int e, f; + float s; + pr_edict_t *ed; if(!VM_ValidateArgs( "findfloat", 2 )) return; diff --git a/engine/common/infostring.c b/engine/common/infostring.c index 1a7f61a6..2a1031ed 100644 --- a/engine/common/infostring.c +++ b/engine/common/infostring.c @@ -206,19 +206,19 @@ void Info_SetValueForKey (char *s, char *key, char *value) *s = 0; } -static void Cvar_LookupBitInfo(const char *name, const char *string, const char *info, void *unused) +static void Cvar_LookupBitInfo( const char *name, const char *string, const char *info, void *unused ) { - Info_SetValueForKey((char *)info, (char *)name, (char *)string); + Info_SetValueForKey( (char *)info, (char *)name, (char *)string ); } -char *Cvar_Userinfo (void) +char *Cvar_Userinfo( void ) { sv_info[0] = 0; // clear previous calls Cvar_LookupVars( CVAR_USERINFO, sv_info, NULL, Cvar_LookupBitInfo ); return sv_info; } -char *Cvar_Serverinfo (void) +char *Cvar_Serverinfo( void ) { sv_info[0] = 0; // clear previous calls Cvar_LookupVars( CVAR_SERVERINFO, sv_info, NULL, Cvar_LookupBitInfo ); diff --git a/engine/common/net_msg.h b/engine/common/net_msg.h index d877a8ce..f12000b2 100644 --- a/engine/common/net_msg.h +++ b/engine/common/net_msg.h @@ -131,9 +131,11 @@ static const net_desc_t NWDesc[] = #define CS_MODELS 16 // configstrings starts here #define CS_SOUNDS (CS_MODELS+MAX_MODELS) // sound names -#define CS_CLASSNAMES (CS_SOUNDS+MAX_SOUNDS) // edicts classnames +#define CS_DECALS (CS_SOUNDS+MAX_SOUNDS) // server decal indexes +#define CS_CLASSNAMES (CS_DECALS+MAX_DECALS) // edicts classnames #define CS_LIGHTSTYLES (CS_CLASSNAMES+MAX_CLASSNAMES) // lightstyle patterns -#define MAX_CONFIGSTRINGS (CS_LIGHTSTYLES+MAX_LIGHTSTYLES) // total count +#define CS_USER_MESSAGES (CS_LIGHTSTYLES+MAX_LIGHTSTYLES) // names of user messages +#define MAX_CONFIGSTRINGS (CS_USER_MESSAGES+MAX_USER_MESSAGES) // total count // sound flags (get rid of this) #define SND_VOL (1<<0) // a scaled byte diff --git a/engine/engine.dsp b/engine/engine.dsp index 6eaf2a26..50c9cc49 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -162,6 +162,10 @@ SOURCE=.\client\cl_view.c # End Source File # Begin Source File +SOURCE=.\common\com_edict.c +# End Source File +# Begin Source File + SOURCE=.\common\con_keys.c # End Source File # Begin Source File @@ -222,6 +226,10 @@ SOURCE=.\server\sv_frame.c # End Source File # Begin Source File +SOURCE=.\server\sv_game.c +# End Source File +# Begin Source File + SOURCE=.\server\sv_init.c # End Source File # Begin Source File diff --git a/engine/host.c b/engine/host.c index d7cd361a..5bf258e9 100644 --- a/engine/host.c +++ b/engine/host.c @@ -5,7 +5,6 @@ #include "common.h" #include "input.h" -#include "server.h" #include "client.h" #define VID_NUM_MODES ( sizeof( vid_modes ) / sizeof( vid_modes[0] )) @@ -385,7 +384,7 @@ dword Host_EventLoop( void ) continue; } Mem_Copy( buf.data, (byte *)((netadr_t *)ev.data + 1), buf.cursize ); - if ( svs.initialized ) SV_PacketEvent( ev_from, &buf ); + if ( SV_Active()) SV_PacketEvent( ev_from, &buf ); else CL_PacketEvent( ev_from, &buf ); break; default: diff --git a/engine/server/server.h b/engine/server/server.h index f62d5969..dd5d44f6 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -22,9 +22,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SERVER_H #include "mathlib.h" -#include "sv_edict.h" +#include "svprog_def.h" +#include "svgame_api.h" //============================================================================= +#define NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - svg.edicts)) +#define EDICT_NUM( num ) _EDICT_NUM( num, __FILE__, __LINE__ ) #define AREA_SOLID 1 #define AREA_TRIGGERS 2 @@ -32,7 +35,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_MASTERS 8 // max recipients for heartbeat packets #define LATENCY_COUNTS 16 #define MAX_ENT_CLUSTERS 16 -#define DF_NO_FRIENDLY_FIRE 0x00000001 // FIXME: move to server.dat // classic quake flags #define SPAWNFLAG_NOT_EASY 0x00000100 @@ -40,21 +42,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define SPAWNFLAG_NOT_HARD 0x00000400 #define SPAWNFLAG_NOT_DEATHMATCH 0x00000800 -#define AI_FLY BIT(0) // monster is flying -#define AI_SWIM BIT(1) // swimming monster -#define AI_ONGROUND BIT(2) // monster is onground -#define AI_PARTIALONGROUND BIT(3) // monster is partially onground -#define AI_GODMODE BIT(4) // monster don't give damage at all -#define AI_NOTARGET BIT(5) // monster will no searching enemy's -#define AI_NOSTEP BIT(6) // Lazarus stuff -#define AI_DUCKED BIT(7) // monster (or player) is ducked -#define AI_JUMPING BIT(8) // monster (or player) is jumping -#define AI_FROZEN BIT(9) // stop moving, but continue thinking -#define AI_ACTOR BIT(10) // disable ai for actor -#define AI_DRIVER BIT(11) // npc or player driving vehcicle or train -#define AI_SPECTATOR BIT(12) // spectator mode for clients -#define AI_WATERJUMP BIT(13) // npc or player take out of water - typedef enum { ss_dead, // no map loaded @@ -155,16 +142,12 @@ typedef struct link_s { struct link_s *prev; struct link_s *next; - int entnum; // PRVM_EDICT_NUM + int entnum; // NUM_FOR_EDICT } link_t; -struct sv_edict_s +// sv_private_edict_t +struct ed_priv_s { - // generic_edict_t (don't move these fields!) - bool free; - float freetime; // sv.time when the object was freed - - // sv_private_edict_t link_t area; // linked to a division node or leaf struct sv_client_s *client; // filled for player ents int clipmask; // trace info @@ -182,7 +165,6 @@ struct sv_edict_s vec3_t moved_origin; // push old origin vec3_t moved_angles; // push old angles - int serialnumber; // unical entity #id int solid; // see entity_state_t for details physbody_t *physbody; // ptr to phys body @@ -213,12 +195,37 @@ typedef struct bool connected; } challenge_t; +typedef struct +{ + int msg_sizes[MAX_USER_MESSAGES]; // user messages bounds checker + int msg_leftsize; // left in bytes + int msg_index; // for debug messages + edict_t *edicts; + + // library exports table + word *ordinals; + dword *funcs; + char *names[MAX_SYSPATH]; // max 1024 exports supported + int num_ordinals; // actual exports count + dword funcBase; // base offset +} game_static_t; + typedef struct { bool initialized; // sv_init has completed dword realtime; // always increasing, no clamping, etc dword timeleft; + dll_info_t *game; // pointer to server.dll + globalvars_t *globals; // server globals + DLL_FUNCTIONS dllFuncs; // dll exported funcs + byte *mempool; // edicts pool + byte *private; // server.dll private pool + byte *stringpool; // sv.strings pool + int msg_dest; // msg destination ( MSG_ONE, MSG_ALL etc ) + edict_t *msg_ent; + vec3_t msg_org; + string mapcmd; // ie: *intro.cin+base string comment; // map name, e.t.c. @@ -229,7 +236,6 @@ typedef struct int next_client_entities; // next client_entity to use entity_state_t *client_entities; // [num_client_entities] entity_state_t *baselines; // [host.max_edicts] - func_t ClientMove; // qc client physic int last_heartbeat; @@ -241,6 +247,7 @@ typedef struct extern netadr_t master_adr[MAX_MASTERS]; // address of the master server extern const char *ed_name[]; extern server_static_t svs; // persistant server info +extern game_static_t svg; // persistant game info extern server_t sv; // local server extern cvar_t *sv_paused; @@ -276,6 +283,8 @@ void SV_DropClient (sv_client_t *drop); int SV_ModelIndex (const char *name); int SV_SoundIndex (const char *name); int SV_ClassIndex (const char *name); +int SV_DecalIndex (const char *name); +int SV_UserMessageIndex (const char *name); void SV_WriteClientdataToMessage (sv_client_t *client, sizebuf_t *msg); void SV_ExecuteUserCommand (char *s); @@ -294,14 +303,12 @@ void SV_Map( char *levelstring, char *savename ); void SV_SpawnServer( const char *server, const char *savename ); int SV_FindIndex (const char *name, int start, int end, bool create); void SV_ClassifyEdict( edict_t *ent ); -void SV_VM_Begin( void ); -void SV_VM_End( void ); // // sv_phys.c // void SV_Physics( void ); -void SV_PlayerMove( sv_edict_t *ed ); +void SV_PlayerMove( edict_t *ed ); void SV_DropToFloor( edict_t *ent ); void SV_CheckGround( edict_t *ent ); bool SV_UnstickEntity( edict_t *ent ); @@ -314,8 +321,8 @@ bool SV_CheckBottom (edict_t *ent); // // sv_move.c // -void SV_Transform( sv_edict_t *ed, const vec3_t origin, const matrix3x3 transform ); -void SV_PlaySound( sv_edict_t *ed, float volume, float pitch, const char *sample ); +void SV_Transform( edict_t *ed, const vec3_t origin, const matrix3x3 transform ); +void SV_PlaySound( edict_t *ed, float volume, float pitch, const char *sample ); bool SV_movestep( edict_t *ent, vec3_t move, bool relink, bool noenemy, bool settrace ); // @@ -356,33 +363,45 @@ void SV_Error (char *error, ...); // // sv_game.c // -void SV_InitServerProgs( void ); -void SV_FreeServerProgs( void ); - +bool SV_LoadProgs( const char *name ); +void SV_UnloadProgs( void ); void SV_InitEdict (edict_t *e); void SV_ConfigString (int index, const char *val); void SV_SetModel (edict_t *ent, const char *name); void SV_CreatePhysBody( edict_t *ent ); void SV_SetPhysForce( edict_t *ent ); void SV_SetMassCentre( edict_t *ent); +void SV_CopyTraceToGlobal( trace_t *trace ); +void SV_CopyTraceResult( TraceResult *out, trace_t trace ); float SV_AngleMod( float ideal, float current, float speed ); +void SV_SpawnEntities( const char *mapname, script_t *entities ); + +_inline edict_t *_EDICT_NUM( int n, const char * file, const int line ) +{ + if((n >= 0) && (n < svs.globals->maxEntities)) + return svg.edicts + n; + Host_Error( "EDICT_NUM: bad number %i (called at %s:%i)\n", n, file, line ); + return NULL; +} + +// for constant strings +#define STRING( offset ) (const char *)( svs.globals->pStringBase + (int)offset ) +#define MAKE_STRING(str) ((int)str - (int)STRING( 0 )) // // sv_studio.c // cmodel_t *SV_GetModelPtr( edict_t *ent ); -float *SV_GetModelVerts( sv_edict_t *ent, int *numvertices ); +float *SV_GetModelVerts( edict_t *ent, int *numvertices ); int SV_StudioExtractBbox( dstudiohdr_t *phdr, int sequence, float *mins, float *maxs ); bool SV_CreateMeshBuffer( edict_t *in, cmodel_t *out ); // // sv_spawn.c // -void SV_SpawnEntities( const char *mapname, const char *entities ); -void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count); -void SV_FreeEdict (edict_t *ed); -void SV_InitEdict (edict_t *e); -edict_t *SV_Spawn (void); +void SV_StartParticle( const float *org, const float *dir, int color, int count ); +void SV_FreeEdict( edict_t *ed ); +edict_t *SV_AllocEdict( void ); bool SV_ClientConnect (edict_t *ent, char *userinfo); void SV_TouchTriggers (edict_t *ent); diff --git a/engine/server/sv_client.c b/engine/server/sv_client.c index 6b7fdbd9..885bc78a 100644 --- a/engine/server/sv_client.c +++ b/engine/server/sv_client.c @@ -173,8 +173,8 @@ gotnewcl: sv_client = newcl; edictnum = (newcl - svs.clients) + 1; - ent = PRVM_EDICT_NUM( edictnum ); - ent->priv.sv->client = newcl; + ent = EDICT_NUM( edictnum ); + ent->pvEngineData->client = newcl; newcl->edict = ent; newcl->challenge = challenge; // save challenge for checksumming @@ -223,14 +223,12 @@ bool SV_ClientConnect( edict_t *ent, char *userinfo ) bool result = true; // make sure we start with known default - ent->progs.sv->flags = 0; - ent->progs.sv->aiflags = 0; + ent->v.flags = 0; + ent->v.aiflags = 0; MsgDev(D_NOTE, "SV_ClientConnect()\n"); - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram (prog->globals.sv->ClientConnect, "ClientConnect"); - result = (int)PRVM_G_FLOAT(OFS_RETURN); + svs.globals->time = sv.time; + result = svs.dllFuncs.pfnClientConnect( ent, userinfo ); return result; } @@ -250,15 +248,13 @@ void SV_DropClient( sv_client_t *drop ) if( drop->state == cs_zombie ) return; // already dropped - SV_VM_Begin(); - // add the disconnect MSG_WriteByte( &drop->netchan.message, svc_disconnect ); // let the game known about client state - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( drop->edict ); - PRVM_ExecuteProgram( prog->globals.sv->ClientDisconnect, "ClientDisconnect" ); + svs.globals->time = sv.time; + svs.dllFuncs.pfnClientDisconnect( drop->edict ); + SV_FreeEdict( drop->edict ); if( drop->download ) drop->download = NULL; @@ -351,7 +347,7 @@ char *SV_StatusString( void ) cl = &svs.clients[i]; if( cl->state == cs_connected || cl->state == cs_spawned ) { - com.sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->progs.sv->frags, cl->ping, cl->name ); + com.sprintf( player, "%i %i \"%s\"\n", (int)cl->edict->v.frags, cl->ping, cl->name ); playerLength = com.strlen(player); if( statusLength + playerLength >= sizeof(status)) break; // can't hold any more @@ -485,56 +481,53 @@ void SV_PutClientInServer( edict_t *ent ) edict_t *viewmodel; int i; - index = PRVM_NUM_FOR_EDICT( ent ) - 1; - client = ent->priv.sv->client; + index = NUM_FOR_EDICT( ent ) - 1; + client = ent->pvEngineData->client; - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent ); - - ent->priv.sv->free = false; - (int)ent->progs.sv->flags &= ~FL_DEADMONSTER; - ent->priv.sv->s.ed_type = ED_CLIENT; // init edict type + svs.globals->time = sv.time; + ent->free = false; + ent->pvEngineData->s.ed_type = ED_CLIENT; // init edict type if( !sv.loadgame ) { // fisrt entering - PRVM_ExecuteProgram( prog->globals.sv->PutClientInServer, "PutClientInServer" ); - ent->progs.sv->v_angle[ROLL] = 0; // cut off any camera rolling - ent->progs.sv->origin[2] += 1; // make sure off ground + svs.dllFuncs.pfnClientPutInServer( ent ); + ent->v.v_angle[ROLL] = 0; // cut off any camera rolling + ent->v.origin[2] += 1; // make sure off ground // create viewmodel - viewmodel = PRVM_ED_Alloc(); - viewmodel->progs.sv->classname = PRVM_SetEngineString( "viewmodel" ); - VectorCopy( ent->progs.sv->view_ofs, viewmodel->progs.sv->view_ofs ); - VectorCopy( ent->progs.sv->origin, viewmodel->progs.sv->origin ); - VectorCopy( ent->progs.sv->angles, viewmodel->progs.sv->angles ); - viewmodel->progs.sv->model = ent->progs.sv->v_model; - viewmodel->progs.sv->movetype = MOVETYPE_FOLLOW; + viewmodel = SV_AllocEdict(); + viewmodel->v.classname = MAKE_STRING( "viewmodel" ); + VectorCopy( ent->v.view_ofs, viewmodel->v.view_ofs ); + VectorCopy( ent->v.origin, viewmodel->v.origin ); + VectorCopy( ent->v.angles, viewmodel->v.angles ); + viewmodel->v.model = ent->v.viewmodel; + viewmodel->v.movetype = MOVETYPE_FOLLOW; // make cross links for consistency - viewmodel->progs.sv->aiment = PRVM_NUM_FOR_EDICT( ent ); - ent->progs.sv->aiment = PRVM_NUM_FOR_EDICT( viewmodel ); + viewmodel->v.aiment = ent; + ent->v.aiment = viewmodel; } else { // restore viewmodel - viewmodel = PRVM_EDICT_NUM( ent->progs.sv->aiment ); + viewmodel = ent->v.aiment; } - ent->priv.sv->s.fov = 90; // FIXME: get from qc - ent->priv.sv->s.fov = bound(1, ent->priv.sv->s.fov, 160); - ent->priv.sv->s.health = ent->progs.sv->health; - ent->priv.sv->s.classname = SV_ClassIndex(PRVM_GetString( ent->progs.sv->classname )); - ent->priv.sv->s.pmodel.index = SV_ModelIndex(PRVM_GetString( ent->progs.sv->p_model)); - VectorCopy( ent->progs.sv->origin, ent->priv.sv->s.origin ); - VectorCopy( ent->progs.sv->v_angle, ent->priv.sv->s.viewangles ); - for( i = 0; i < 3; i++ ) ent->priv.sv->s.delta_angles[i] = ANGLE2SHORT(ent->progs.sv->v_angle[i]); - viewmodel->priv.sv->s.ed_type = ED_VIEWMODEL; // set entity type - viewmodel->progs.sv->modelindex = SV_ModelIndex(PRVM_GetString(viewmodel->progs.sv->model)); - viewmodel->priv.sv->s.classname = SV_ClassIndex(PRVM_GetString(viewmodel->progs.sv->classname)); + ent->pvEngineData->s.fov = 90; // FIXME: get from qc + ent->pvEngineData->s.fov = bound(1, ent->pvEngineData->s.fov, 160); + ent->pvEngineData->s.health = ent->v.health; + ent->pvEngineData->s.classname = SV_ClassIndex( STRING( ent->v.classname )); + ent->pvEngineData->s.pmodel.index = SV_ModelIndex( STRING( ent->v.weaponmodel )); + VectorCopy( ent->v.origin, ent->pvEngineData->s.origin ); + VectorCopy( ent->v.v_angle, ent->pvEngineData->s.viewangles ); + for( i = 0; i < 3; i++ ) ent->pvEngineData->s.delta_angles[i] = ANGLE2SHORT(ent->v.v_angle[i]); + viewmodel->pvEngineData->s.ed_type = ED_VIEWMODEL; // set entity type + viewmodel->v.modelindex = SV_ModelIndex( STRING( viewmodel->v.model )); + viewmodel->pvEngineData->s.classname = SV_ClassIndex( STRING( viewmodel->v.classname )); SV_LinkEdict( ent ); // m_pmatrix calculated here, so we need call this before pe->CreatePlayer - ent->priv.sv->physbody = pe->CreatePlayer( ent->priv.sv, SV_GetModelPtr( ent ), ent->progs.sv->origin, ent->progs.sv->m_pmatrix ); + ent->pvEngineData->physbody = pe->CreatePlayer( ent, SV_GetModelPtr( ent ), ent->v.origin, ent->v.m_pmatrix ); } /* @@ -576,8 +569,8 @@ void SV_New_f( sv_client_t *cl ) if( sv.state == ss_active ) { // set up the entity for the client - ent = PRVM_EDICT_NUM( playernum + 1 ); - ent->priv.sv->serialnumber = playernum + 1; + ent = EDICT_NUM( playernum + 1 ); + ent->serialnumber = playernum + 1; cl->edict = ent; Mem_Set( &cl->lastcmd, 0, sizeof(cl->lastcmd)); @@ -841,11 +834,9 @@ static void SV_UpdateUserinfo_f( sv_client_t *cl ) SV_UserinfoChanged( cl ); // call prog code to allow overrides - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( cl->edict ); - prog->globals.sv->time = sv.time; - prog->globals.sv->frametime = sv.frametime; - PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString( cl->userinfo ); - PRVM_ExecuteProgram( prog->globals.sv->ClientUserInfoChanged, "ClientUserInfoChanged" ); + svs.globals->time = sv.time; + svs.globals->frametime = sv.frametime; + svs.dllFuncs.pfnClientUserInfoChanged( cl->edict, cl->userinfo ); } ucmd_t ucmds[] = @@ -884,10 +875,9 @@ void SV_ExecuteClientCommand( sv_client_t *cl, char *s ) if( !u->name && sv.state == ss_active ) { // custom client commands - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( cl->edict ); - prog->globals.sv->time = sv.time; - prog->globals.sv->frametime = sv.frametime; - PRVM_ExecuteProgram( prog->globals.sv->ClientCommand, "ClientCommand" ); + svs.globals->time = sv.time; + svs.globals->frametime = sv.frametime; + svs.dllFuncs.pfnClientCommand( cl->edict ); } } @@ -959,7 +949,7 @@ void _MSG_Send( msgtype_t msg_type, vec3_t origin, edict_t *ent, const char *fil // intentional fallthrough case MSG_ONE: if( ent == NULL ) return; - j = PRVM_NUM_FOR_EDICT( ent ); + j = NUM_FOR_EDICT( ent ); if( j < 1 || j > numclients ) return; current = svs.clients + (j - 1); numclients = 1; // send to one @@ -981,7 +971,7 @@ void _MSG_Send( msgtype_t msg_type, vec3_t origin, edict_t *ent, const char *fil { area2 = pe->LeafArea( leafnum ); cluster = pe->LeafCluster( leafnum ); - leafnum = pe->PointLeafnum( cl->edict->progs.sv->origin ); + leafnum = pe->PointLeafnum( cl->edict->v.origin ); if(!pe->AreasConnected( area1, area2 )) continue; if( mask && (!(mask[cluster>>3] & (1<<(cluster&7))))) continue; @@ -1033,48 +1023,48 @@ void SV_ApplyClientMove( sv_client_t *cl, usercmd_t *cmd ) int i; edict_t *ent = cl->edict; - // set the edict fields - ent->progs.sv->button0 = cmd->buttons & 1; - ent->progs.sv->button1 = (cmd->upmove < 0) ? 1 : 0; - ent->progs.sv->button2 = (cmd->upmove > 0) ? 1 : 0; - if( cmd->impulse ) ent->progs.sv->impulse = cmd->impulse; + ent->v.button = cmd->buttons; // initialize buttons + ent->v.button |= (cmd->upmove < 0) ? IN_DUCK : IN_JUMP; + ent->v.button |= (cmd->sidemove < 0) ? IN_MOVELEFT : IN_MOVERIGHT; + ent->v.button |= (cmd->forwardmove > 0) ? IN_FORWARD : IN_BACK; + if( cmd->impulse ) ent->v.impulse = cmd->impulse; cmd->impulse = 0; // only send the impulse to qc once // circularly clamp the angles with deltas for( i = 0; i < 3; i++ ) { - temp = cmd->angles[i] + ent->priv.sv->s.delta_angles[i]; - ent->priv.sv->s.viewangles[i] = SHORT2ANGLE( temp ); + temp = cmd->angles[i] + ent->pvEngineData->s.delta_angles[i]; + ent->pvEngineData->s.viewangles[i] = SHORT2ANGLE( temp ); } // don't let the player look up or down more than 90 degrees - if( ent->priv.sv->s.viewangles[PITCH] > 89 && ent->priv.sv->s.viewangles[PITCH] < 180 ) - ent->priv.sv->s.viewangles[PITCH] = 89; - else if( ent->priv.sv->s.viewangles[PITCH] < 271 && ent->priv.sv->s.viewangles[PITCH] >= 180 ) - ent->priv.sv->s.viewangles[PITCH] = 271; + if( ent->pvEngineData->s.viewangles[PITCH] > 89 && ent->pvEngineData->s.viewangles[PITCH] < 180 ) + ent->pvEngineData->s.viewangles[PITCH] = 89; + else if( ent->pvEngineData->s.viewangles[PITCH] < 271 && ent->pvEngineData->s.viewangles[PITCH] >= 180 ) + ent->pvEngineData->s.viewangles[PITCH] = 271; // test - if((int)ent->progs.sv->aiflags & AI_DUCKED ) + if((int)ent->v.aiflags & AI_DUCKED ) { cmd->forwardmove *= 0.333; cmd->sidemove *= 0.333; cmd->upmove *= 0.333; } - VectorCopy( ent->priv.sv->s.viewangles, cl->edict->progs.sv->v_angle ); - VectorCopy( ent->priv.sv->s.viewangles, cl->edict->progs.sv->angles ); - VectorCopy( ent->progs.sv->view_ofs, cl->edict->priv.sv->s.viewoffset ); + VectorCopy( ent->pvEngineData->s.viewangles, cl->edict->v.v_angle ); + VectorCopy( ent->pvEngineData->s.viewangles, cl->edict->v.angles ); + VectorCopy( ent->v.view_ofs, cl->edict->pvEngineData->s.viewoffset ); } void SV_DropPunchAngle( sv_client_t *cl ) { float len; - len = VectorNormalizeLength( cl->edict->progs.sv->punchangle ); + len = VectorNormalizeLength( cl->edict->v.punchangle ); len -= 10 * sv.frametime; if( len < 0 ) len = 0; - VectorScale( cl->edict->progs.sv->punchangle, len, cl->edict->progs.sv->punchangle ); + VectorScale( cl->edict->v.punchangle, len, cl->edict->v.punchangle ); } /* @@ -1090,13 +1080,13 @@ void SV_UserFriction( sv_client_t *cl ) vec3_t start, stop; trace_t trace; - speed = sqrt(cl->edict->progs.sv->velocity[0] * cl->edict->progs.sv->velocity[0] + cl->edict->progs.sv->velocity[1] * cl->edict->progs.sv->velocity[1]); + speed = sqrt(cl->edict->v.velocity[0] * cl->edict->v.velocity[0] + cl->edict->v.velocity[1] * cl->edict->v.velocity[1]); if( !speed ) return; // if the leading edge is over a dropoff, increase friction - start[0] = stop[0] = cl->edict->progs.sv->origin[0] + cl->edict->progs.sv->velocity[0] / speed * 16; - start[1] = stop[1] = cl->edict->progs.sv->origin[1] + cl->edict->progs.sv->velocity[1] / speed * 16; - start[2] = cl->edict->progs.sv->origin[2] + cl->edict->progs.sv->mins[2]; + start[0] = stop[0] = cl->edict->v.origin[0] + cl->edict->v.velocity[0] / speed * 16; + start[1] = stop[1] = cl->edict->v.origin[1] + cl->edict->v.velocity[1] / speed * 16; + start[2] = cl->edict->v.origin[2] + cl->edict->v.mins[2]; stop[2] = start[2] - 34; trace = SV_Trace( start, vec3_origin, vec3_origin, stop, MOVE_NOMONSTERS, cl->edict, SV_ContentsMask( cl->edict )); @@ -1110,7 +1100,7 @@ void SV_UserFriction( sv_client_t *cl ) if( newspeed < 0 ) newspeed = 0; else newspeed /= speed; - VectorScale( cl->edict->progs.sv->velocity, newspeed, cl->edict->progs.sv->velocity ); + VectorScale( cl->edict->v.velocity, newspeed, cl->edict->v.velocity ); } /* @@ -1151,12 +1141,12 @@ void SV_Accelerate( sv_client_t *cl ) float addspeed; float accelspeed, currentspeed; - currentspeed = DotProduct( cl->edict->progs.sv->velocity, wishdir ); + currentspeed = DotProduct( cl->edict->v.velocity, wishdir ); addspeed = wishspeed - currentspeed; if( addspeed <= 0 ) return; accelspeed = sv_accelerate->value * sv.frametime * wishspeed; if( accelspeed > addspeed ) accelspeed = addspeed; - for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishdir[i]; + for( i = 0; i < 3; i++ ) cl->edict->v.velocity[i] += accelspeed * wishdir[i]; } void SV_AirAccelerate( sv_client_t *cl, vec3_t wishveloc ) @@ -1167,13 +1157,13 @@ void SV_AirAccelerate( sv_client_t *cl, vec3_t wishveloc ) wishspd = VectorNormalizeLength( wishveloc ); if( wishspd > 30 ) wishspd = 30; - currentspeed = DotProduct( cl->edict->progs.sv->velocity, wishveloc ); + currentspeed = DotProduct( cl->edict->v.velocity, wishveloc ); addspeed = wishspd - currentspeed; if( addspeed <= 0 ) return; accelspeed = sv_accelerate->value * wishspeed * sv.frametime; if( accelspeed > addspeed ) accelspeed = addspeed; - for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishveloc[i]; + for( i = 0; i < 3; i++ ) cl->edict->v.velocity[i] += accelspeed * wishveloc[i]; } /* @@ -1191,7 +1181,7 @@ void SV_WaterMove( sv_client_t *cl, usercmd_t *cmd ) float accelspeed, temp; // user intentions - AngleVectors( cl->edict->progs.sv->v_angle, forward, right, up ); + AngleVectors( cl->edict->v.v_angle, forward, right, up ); for( i = 0; i < 3; i++ ) wishvel[i] = forward[i] * cmd->forwardmove + right[i] * cmd->sidemove; @@ -1209,13 +1199,13 @@ void SV_WaterMove( sv_client_t *cl, usercmd_t *cmd ) wishspeed *= 0.7; // water friction - speed = VectorLength( cl->edict->progs.sv->velocity ); + speed = VectorLength( cl->edict->v.velocity ); if( speed ) { newspeed = speed - sv.frametime * speed * sv_friction->value; if( newspeed < 0 ) newspeed = 0; temp = newspeed / speed; - VectorScale( cl->edict->progs.sv->velocity, temp, cl->edict->progs.sv->velocity ); + VectorScale( cl->edict->v.velocity, temp, cl->edict->v.velocity ); } else newspeed = 0; @@ -1229,18 +1219,18 @@ void SV_WaterMove( sv_client_t *cl, usercmd_t *cmd ) accelspeed = sv_accelerate->value * wishspeed * sv.frametime; if( accelspeed > addspeed ) accelspeed = addspeed; - for( i = 0; i < 3; i++ ) cl->edict->progs.sv->velocity[i] += accelspeed * wishvel[i]; + for( i = 0; i < 3; i++ ) cl->edict->v.velocity[i] += accelspeed * wishvel[i]; } void SV_WaterJump( sv_client_t *cl ) { - if (sv.time > cl->edict->progs.sv->teleport_time || !cl->edict->progs.sv->waterlevel ) + if (sv.time > cl->edict->v.teleport_time || !cl->edict->v.waterlevel ) { - cl->edict->progs.sv->flags = (int)cl->edict->progs.sv->aiflags & ~AI_WATERJUMP; - cl->edict->progs.sv->teleport_time = 0; + cl->edict->v.flags = (int)cl->edict->v.aiflags & ~AI_WATERJUMP; + cl->edict->v.teleport_time = 0; } - cl->edict->progs.sv->velocity[0] = cl->edict->progs.sv->movedir[0]; - cl->edict->progs.sv->velocity[1] = cl->edict->progs.sv->movedir[1]; + cl->edict->v.velocity[0] = cl->edict->v.movedir[0]; + cl->edict->v.velocity[1] = cl->edict->v.movedir[1]; } /* @@ -1256,19 +1246,19 @@ void SV_AirMove( sv_client_t *cl, usercmd_t *cmd ) float fmove, smove, temp; wishvel[0] = wishvel[2] = 0; - wishvel[1] = cl->edict->progs.sv->angles[1]; + wishvel[1] = cl->edict->v.angles[1]; AngleVectors( wishvel, forward, right, up ); fmove = cmd->forwardmove; smove = cmd->sidemove; // hack to not let you back into teleporter - if( sv.time < cl->edict->progs.sv->teleport_time && fmove < 0 ) + if( sv.time < cl->edict->v.teleport_time && fmove < 0 ) fmove = 0; for( i = 0; i < 3; i++ ) wishvel[i] = forward[i] * fmove + right[i] * smove; - if((int)cl->edict->progs.sv->movetype != MOVETYPE_WALK ) + if((int)cl->edict->v.movetype != MOVETYPE_WALK ) wishvel[2] += cmd->upmove; VectorCopy( wishvel, wishdir ); @@ -1280,10 +1270,10 @@ void SV_AirMove( sv_client_t *cl, usercmd_t *cmd ) wishspeed = sv_maxspeed->value; } - if( cl->edict->progs.sv->movetype == MOVETYPE_NOCLIP ) + if( cl->edict->v.movetype == MOVETYPE_NOCLIP ) { // noclip - VectorCopy( wishvel, cl->edict->progs.sv->velocity ); + VectorCopy( wishvel, cl->edict->v.velocity ); } else if( onground ) { @@ -1319,38 +1309,28 @@ void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd ) // make sure the velocity is sane (not a NaN) SV_CheckVelocity( cl->edict ); - // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) - /*if( svs.ClientMove ) - { - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( cl->edict ); - PRVM_ExecuteProgram( svs.ClientMove, "ClientMove" ); - SV_CheckVelocity( cl->edict ); - return; - }*/ - - if( cl->edict->progs.sv->movetype == MOVETYPE_NONE ) + if( cl->edict->v.movetype == MOVETYPE_NONE ) return; - onground = (int)cl->edict->progs.sv->aiflags & AI_ONGROUND; + onground = (cl->edict->v.flags & FL_ONGROUND); SV_DropPunchAngle( cl ); // if dead, behave differently - if( cl->edict->progs.sv->health <= 0 ) + if( cl->edict->v.health <= 0 ) return; // angles // show 1/3 the pitch angle and all the roll angle - VectorAdd( cl->edict->progs.sv->v_angle, cl->edict->progs.sv->punchangle, v_angle ); - cl->edict->progs.sv->angles[ROLL] = SV_CalcRoll( cl->edict->progs.sv->angles, cl->edict->progs.sv->velocity) * 4; - if( !cl->edict->progs.sv->fixangle ) + VectorAdd( cl->edict->v.v_angle, cl->edict->v.punchangle, v_angle ); + cl->edict->v.angles[ROLL] = SV_CalcRoll( cl->edict->v.angles, cl->edict->v.velocity) * 4; + if( !cl->edict->v.fixangle ) { - cl->edict->progs.sv->angles[PITCH] = -v_angle[PITCH]/3; - cl->edict->progs.sv->angles[YAW] = v_angle[YAW]; + cl->edict->v.angles[PITCH] = -v_angle[PITCH]/3; + cl->edict->v.angles[YAW] = v_angle[YAW]; } - if((int)cl->edict->progs.sv->aiflags & AI_WATERJUMP ) + if((int)cl->edict->v.aiflags & AI_WATERJUMP ) { SV_WaterJump( cl ); SV_CheckVelocity( cl->edict ); @@ -1358,7 +1338,7 @@ void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd ) } // walk - if((cl->edict->progs.sv->waterlevel >= 2) && (cl->edict->progs.sv->movetype != MOVETYPE_NOCLIP)) + if((cl->edict->v.waterlevel >= 2) && (cl->edict->v.movetype != MOVETYPE_NOCLIP)) { SV_WaterMove( cl, &cl->cmd ); SV_CheckVelocity( cl->edict ); @@ -1367,8 +1347,8 @@ void SV_ClientThink( sv_client_t *cl, usercmd_t *cmd ) SV_AirMove( cl, &cl->cmd ); SV_CheckVelocity( cl->edict ); - VectorCopy( cl->edict->progs.sv->origin, cl->edict->priv.sv->s.origin ); - VectorCopy( cl->edict->progs.sv->velocity, cl->edict->priv.sv->s.velocity ); + VectorCopy( cl->edict->v.origin, cl->edict->pvEngineData->s.origin ); + VectorCopy( cl->edict->v.velocity, cl->edict->pvEngineData->s.velocity ); } /* @@ -1427,8 +1407,8 @@ static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg ) if( !sv_paused->value ) { frametime[0] = sv.frametime; - frametime[1] = prog->globals.sv->frametime; - prog->globals.sv->frametime = sv.frametime = newcmd.msec * 0.001f; + frametime[1] = svs.globals->frametime; + svs.globals->frametime = sv.frametime = newcmd.msec * 0.001f; net_drop = cl->netchan.dropped; if( net_drop < 20 ) @@ -1444,7 +1424,7 @@ static void SV_UserMove( sv_client_t *cl, sizebuf_t *msg ) SV_Physics_ClientMove( cl, &newcmd ); } sv.frametime = frametime[0]; - prog->globals.sv->frametime = frametime[1]; + svs.globals->frametime = frametime[1]; cl->lastcmd = newcmd; } diff --git a/engine/server/sv_cmds.c b/engine/server/sv_cmds.c index 39dc1c3c..0278ddc2 100644 --- a/engine/server/sv_cmds.c +++ b/engine/server/sv_cmds.c @@ -308,14 +308,14 @@ void SV_ChangeLevel_f( void ) savedFree = Z_Malloc(Host_MaxClients() * sizeof(bool)); for (i = 0, cl = svs.clients; i < Host_MaxClients(); i++, cl++) { - savedFree[i] = cl->edict->priv.sv->free; - cl->edict->priv.sv->free = true; + savedFree[i] = cl->edict->free; + cl->edict->free = true; } SV_WriteSaveFile( "save0.bin" ); // autosave // we must restore these for clients to transfer over correctly for (i = 0, cl = svs.clients; i < Host_MaxClients(); i++, cl++) - cl->edict->priv.sv->free = savedFree[i]; - Mem_Free(savedFree); + cl->edict->free = savedFree[i]; + Mem_Free( savedFree ); } SV_InitGame(); // reset previous state @@ -404,7 +404,7 @@ void SV_Status_f( void ) if( !cl->state ) continue; Msg("%3i ", i); - Msg("%5i ", (int)cl->edict->progs.sv->frags ); + Msg("%5i ", (int)cl->edict->v.frags ); if (cl->state == cs_connected) Msg("Connect"); else if (cl->state == cs_zombie) Msg ("Zombie "); diff --git a/engine/server/sv_frame.c b/engine/server/sv_frame.c index e1ff3a5a..7b34061b 100644 --- a/engine/server/sv_frame.c +++ b/engine/server/sv_frame.c @@ -40,7 +40,7 @@ static int SV_EntityNumbers( const void *a, const void *b ) /* ============================================================================= -Copy PRVM values into entity state +Copy entvars into entity state ============================================================================= */ @@ -50,88 +50,89 @@ void SV_UpdateEntityState( edict_t *ent ) int i; // copy progs values to state - ent->priv.sv->s.number = ent->priv.sv->serialnumber; - ent->priv.sv->s.solid = ent->priv.sv->solid; + ent->pvEngineData->s.number = ent->serialnumber; + ent->pvEngineData->s.solid = ent->pvEngineData->solid; - VectorCopy (ent->progs.sv->origin, ent->priv.sv->s.origin); - VectorCopy (ent->progs.sv->angles, ent->priv.sv->s.angles); - ent->priv.sv->s.model.index = (int)ent->progs.sv->modelindex; - ent->priv.sv->s.health = ent->progs.sv->health; - ent->priv.sv->s.model.skin = (short)ent->progs.sv->skin; // studio model skin - ent->priv.sv->s.model.body = (byte)ent->progs.sv->body; // studio model submodel - ent->priv.sv->s.model.frame = ent->progs.sv->frame; // any model current frame - ent->priv.sv->s.model.gaitsequence = (int)ent->progs.sv->gaitsequence;// player sequence, that will be playing on client - ent->priv.sv->s.effects = (uint)ent->progs.sv->effects; // shared client and render flags - ent->priv.sv->s.renderfx = (int)ent->progs.sv->renderfx; // renderer flags - ent->priv.sv->s.rendermode = ent->progs.sv->rendermode; // rendering mode - ent->priv.sv->s.renderamt = ent->progs.sv->renderamt; // alpha value - ent->priv.sv->s.model.framerate = ent->progs.sv->framerate; - ent->priv.sv->s.model.animtime = (int)(1000.0 * ent->progs.sv->animtime) * 0.001; // sequence time - ent->priv.sv->s.aiment = ent->progs.sv->aiment; // viewmodel parent - ent->priv.sv->s.model.scale = ent->progs.sv->scale; // shared client and render flags - VectorCopy( ent->progs.sv->rendercolor, ent->priv.sv->s.rendercolor ); + VectorCopy (ent->v.origin, ent->pvEngineData->s.origin); + VectorCopy (ent->v.angles, ent->pvEngineData->s.angles); + ent->pvEngineData->s.model.index = ent->v.modelindex; + ent->pvEngineData->s.health = ent->v.health; + ent->pvEngineData->s.model.skin = ent->v.skin; // studio model skin + ent->pvEngineData->s.model.body = ent->v.body; // studio model submodel + ent->pvEngineData->s.model.frame = ent->v.frame; // any model current frame + ent->pvEngineData->s.model.gaitsequence = ent->v.gaitsequence;// player sequence, that will be playing on client + ent->pvEngineData->s.effects = ent->v.effects; // shared client and render flags + ent->pvEngineData->s.renderfx = ent->v.renderfx; // renderer flags + ent->pvEngineData->s.rendermode = ent->v.rendermode; // rendering mode + ent->pvEngineData->s.renderamt = ent->v.renderamt; // alpha value + ent->pvEngineData->s.model.framerate = ent->v.framerate; + ent->pvEngineData->s.model.animtime = (int)(1000.0 * ent->v.animtime) * 0.001; // sequence time + ent->pvEngineData->s.aiment = NUM_FOR_EDICT( ent->v.aiment ); // viewmodel parent + ent->pvEngineData->s.model.scale = ent->v.scale; // shared client and render flags + VectorCopy( ent->v.rendercolor, ent->pvEngineData->s.rendercolor ); // studio model sequence - if( ent->progs.sv->sequence != -1 ) ent->priv.sv->s.model.sequence = ent->progs.sv->sequence; + if( ent->v.sequence != -1 ) ent->pvEngineData->s.model.sequence = ent->v.sequence; for( i = 0; i < 16; i++ ) { // copy blendings and bone ctrls - ent->priv.sv->s.model.blending[i] = ent->progs.sv->blending[i]; - ent->priv.sv->s.model.controller[i] = ent->progs.sv->controller[i]; + ent->pvEngineData->s.model.blending[i] = ent->v.blending[i]; + ent->pvEngineData->s.model.controller[i] = ent->v.controller[i]; } - if( ent->priv.sv->s.ed_type != ED_VIEWMODEL ) - ent->priv.sv->s.movetype = ent->progs.sv->movetype; + if( ent->pvEngineData->s.ed_type != ED_VIEWMODEL ) + ent->pvEngineData->s.movetype = ent->v.movetype; - if( ent->priv.sv->s.ed_type == ED_MOVER || ent->priv.sv->s.ed_type == ED_BSPBRUSH ) + if( ent->pvEngineData->s.ed_type == ED_MOVER || ent->pvEngineData->s.ed_type == ED_BSPBRUSH ) { // these needs to right calculate direction of scroll texture - VectorCopy( ent->progs.sv->movedir, ent->priv.sv->s.velocity ); + VectorCopy( ent->v.movedir, ent->pvEngineData->s.velocity ); } - if( ent->priv.sv->s.ed_type == ED_VIEWMODEL ) + if( ent->pvEngineData->s.ed_type == ED_VIEWMODEL ) { // copy v_model state from client to viemodel entity - client = PRVM_EDICT_NUM( ent->progs.sv->aiment ); + client = ent->v.aiment; // update both arrays, because viewmodel are hidden for qc-coders - ent->priv.sv->s.model.index = ent->progs.sv->modelindex = SV_ModelIndex(PRVM_GetString(client->progs.sv->v_model)); - ent->priv.sv->s.model.frame = ent->progs.sv->frame = client->progs.sv->v_frame; - ent->priv.sv->s.model.body = ent->progs.sv->body = client->progs.sv->v_body; - ent->priv.sv->s.model.skin = ent->progs.sv->skin = client->progs.sv->v_skin; - ent->progs.sv->sequence = client->progs.sv->v_sequence; - if( ent->progs.sv->sequence != -1 ) ent->priv.sv->s.model.sequence = ent->progs.sv->sequence; - ent->priv.sv->s.model.colormap = ent->progs.sv->colormap = client->progs.sv->colormap; - ent->priv.sv->s.effects |= EF_MINLIGHT; // always have some light + ent->v.modelindex = SV_ModelIndex( STRING( client->v.viewmodel )); + ent->pvEngineData->s.model.index = ent->v.modelindex; + ent->pvEngineData->s.model.frame = ent->v.frame = client->v.weaponframe; + ent->pvEngineData->s.model.body = ent->v.body = client->v.weaponbody; + ent->pvEngineData->s.model.skin = ent->v.skin = client->v.weaponskin; + ent->v.sequence = client->v.weaponsequence; + if( ent->v.sequence != -1 ) ent->pvEngineData->s.model.sequence = ent->v.sequence; + ent->pvEngineData->s.model.colormap = ent->v.colormap = client->v.colormap; + ent->pvEngineData->s.effects |= EF_MINLIGHT; // always have some light } - else if( ent->priv.sv->s.ed_type == ED_CLIENT ) + else if( ent->pvEngineData->s.ed_type == ED_CLIENT ) { - if( ent->progs.sv->fixangle ) + if( ent->v.fixangle ) { // FIXME: set angles correctly for( i = 0; i < 2; i++ ) - ent->priv.sv->s.delta_angles[i] = ANGLE2SHORT( ent->priv.sv->s.angles[i] ); - VectorClear( ent->priv.sv->s.angles ); - VectorClear( ent->priv.sv->s.viewangles ); - VectorClear( ent->progs.sv->v_angle ); + ent->pvEngineData->s.delta_angles[i] = ANGLE2SHORT( ent->pvEngineData->s.angles[i] ); + VectorClear( ent->pvEngineData->s.angles ); + VectorClear( ent->pvEngineData->s.viewangles ); + VectorClear( ent->v.v_angle ); // and clear fixangle for the next frame - ent->progs.sv->fixangle = 0; + ent->v.fixangle = 0; } } - else if( ent->priv.sv->s.ed_type == ED_AMBIENT ) + else if( ent->pvEngineData->s.ed_type == ED_AMBIENT ) { - if( ent->progs.sv->solid == SOLID_TRIGGER ) + if( ent->v.solid == SOLID_TRIGGER ) { vec3_t midPoint; // NOTE: no reason to compute this shit on the client - save bandwidth - VectorAverage( ent->progs.sv->mins, ent->progs.sv->maxs, midPoint ); - VectorAdd( ent->priv.sv->s.origin, midPoint, ent->priv.sv->s.origin ); + VectorAverage( ent->v.mins, ent->v.maxs, midPoint ); + VectorAdd( ent->pvEngineData->s.origin, midPoint, ent->pvEngineData->s.origin ); } } - else if( ent->priv.sv->s.ed_type == ED_MOVER ) + else if( ent->pvEngineData->s.ed_type == ED_MOVER ) { // FIXME: send mins\maxs for sound spatialization and entity prediction ? } @@ -142,7 +143,7 @@ void SV_UpdateEntityState( edict_t *ent ) SV_AddEntToSnapshot =============== */ -static void SV_AddEntToSnapshot( sv_edict_t *svent, edict_t *ent, sv_ents_t *ents ) +static void SV_AddEntToSnapshot( ed_priv_t *svent, edict_t *ent, sv_ents_t *ents ) { // if we have already added this entity to this snapshot, don't add again if( svent->framenum == sv.net_framenum ) return; @@ -152,7 +153,7 @@ static void SV_AddEntToSnapshot( sv_edict_t *svent, edict_t *ent, sv_ents_t *ent if( ents->num_entities == MAX_VISIBLE_PACKET ) return; SV_UpdateEntityState( ent ); // copy entity state from progs - ents->entities[ents->num_entities] = svent->serialnumber; + ents->entities[ents->num_entities] = ent->serialnumber; ents->num_entities++; c_fullsend++; // debug counter } @@ -237,7 +238,7 @@ static void SV_AddEntitiesToPacket( vec3_t origin, client_frame_t *frame, sv_ent { int l, e, i; edict_t *ent; - sv_edict_t *svent; + ed_priv_t *svent; int leafnum; byte *clientphs; byte *bitvector; @@ -260,35 +261,35 @@ static void SV_AddEntitiesToPacket( vec3_t origin, client_frame_t *frame, sv_ent frame->areabits_size = pe->WriteAreaBits( frame->areabits, clientarea, portal ); clientphs = pe->ClusterPHS( clientcluster ); - for( e = 1; e < prog->num_edicts; e++ ) + for( e = 1; e < svs.globals->numEntities; e++ ) { - ent = PRVM_EDICT_NUM( e ); + ent = EDICT_NUM( e ); force = false; // clear forceflag // completely ignore dormant entity - if((int)ent->progs.sv->flags & FL_DORMANT ) + if((int)ent->v.flags & FL_DORMANT ) continue; // send viewmodel entity always // NOTE: never apply LinkEdict to viewmodel entity, because // we wan't see it in list of entities returned with SV_AreaEdicts - if( ent->priv.sv->s.ed_type == ED_VIEWMODEL ) + if( ent->pvEngineData->s.ed_type == ED_VIEWMODEL ) force = true; // NOTE: client index on client expected that entity will be valid - if( sv_newprotocol->integer && ent->priv.sv->s.ed_type == ED_CLIENT ) + if( sv_newprotocol->integer && ent->pvEngineData->s.ed_type == ED_CLIENT ) force = true; // never send entities that aren't linked in - if( !ent->priv.sv->linked && !force ) continue; + if( !ent->pvEngineData->linked && !force ) continue; - if( ent->priv.sv->serialnumber != e ) + if( ent->serialnumber != e ) { - MsgDev( D_WARN, "fixing ent->priv.sv->serialnumber\n"); - ent->priv.sv->serialnumber = e; + MsgDev( D_WARN, "fixing ent->pvEngineData->serialnumber\n"); + ent->serialnumber = e; } - svent = ent->priv.sv; + svent = ent->pvEngineData; // quick reject by type switch( svent->s.ed_type ) @@ -307,11 +308,11 @@ static void SV_AddEntitiesToPacket( vec3_t origin, client_frame_t *frame, sv_ent if( !force ) { // ignore if not touching a PV leaf check area - if( !pe->AreasConnected( clientarea, ent->priv.sv->areanum )) + if( !pe->AreasConnected( clientarea, ent->pvEngineData->areanum )) { // doors can legally straddle two areas, so // we may need to check another one - if( !pe->AreasConnected( clientarea, ent->priv.sv->areanum2 )) + if( !pe->AreasConnected( clientarea, ent->pvEngineData->areanum2 )) continue; // blocked by a door } } @@ -340,20 +341,20 @@ static void SV_AddEntitiesToPacket( vec3_t origin, client_frame_t *frame, sv_ent if( bitvector[l>>3] & (1<<(l & 7))) break; } - if( i == ent->priv.sv->num_clusters ) + if( i == ent->pvEngineData->num_clusters ) continue; // not visible } } - if( ent->priv.sv->s.ed_type == ED_AMBIENT ) + if( ent->pvEngineData->s.ed_type == ED_AMBIENT ) { vec3_t delta, entorigin; float len; // don't send sounds if they will be attenuated away - if( VectorIsNull( ent->progs.sv->origin )) - VectorAverage( ent->progs.sv->mins, ent->progs.sv->maxs, entorigin ); - else VectorCopy( ent->progs.sv->origin, entorigin ); + if( VectorIsNull( ent->v.origin )) + VectorAverage( ent->v.mins, ent->v.maxs, entorigin ); + else VectorCopy( ent->v.origin, entorigin ); VectorSubtract( origin, entorigin, delta ); len = VectorLength( delta ); @@ -419,7 +420,7 @@ void SV_WriteFrameToClient( sv_client_t *cl, sizebuf_t *msg ) MSG_WriteData( msg, frame->areabits, frame->areabits_size ); // just send an client index - // it's safe, because PRVM_NUM_FOR_EDICT always equal ed->serialnumber, + // it's safe, because NUM_FOR_EDICT always equal ed->serialnumber, // thats shared across network if( sv_newprotocol->integer ) { @@ -472,22 +473,22 @@ void SV_BuildClientFrame( sv_client_t *cl ) // clear everything in this snapshot frame_ents.num_entities = c_fullsend = 0; Mem_Set( frame->areabits, 0, sizeof( frame->areabits )); - if( !clent->priv.sv->client ) return; // not in game yet + if( !clent->pvEngineData->client ) return; // not in game yet // find the client's PVS - VectorCopy( clent->priv.sv->s.origin, org ); - VectorAdd( org, clent->priv.sv->s.viewoffset, org ); + VectorCopy( clent->pvEngineData->s.origin, org ); + VectorAdd( org, clent->pvEngineData->s.viewoffset, org ); if( sv_newprotocol->integer ) { // grab the current player index - frame->index = PRVM_NUM_FOR_EDICT( clent ); + frame->index = NUM_FOR_EDICT( clent ); } else { // grab the current player state - cl->edict->priv.sv->framenum = sv.net_framenum; - frame->ps = clent->priv.sv->s; + cl->edict->pvEngineData->framenum = sv.net_framenum; + frame->ps = clent->pvEngineData->s; } // add all the entities directly visible to the eye, which @@ -506,11 +507,11 @@ void SV_BuildClientFrame( sv_client_t *cl ) for( i = 0; i < frame_ents.num_entities; i++ ) { - ent = PRVM_EDICT_NUM( frame_ents.entities[i] ); + ent = EDICT_NUM( frame_ents.entities[i] ); // add it to the circular client_entities array state = &svs.client_entities[svs.next_client_entities % svs.num_client_entities]; - *state = ent->priv.sv->s; + *state = ent->pvEngineData->s; svs.next_client_entities++; // this should never hit, map should always be restarted first in SV_Frame diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c new file mode 100644 index 00000000..cd0683ff --- /dev/null +++ b/engine/server/sv_game.c @@ -0,0 +1,3202 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// sv_game.c - server dlls interaction +//======================================================================= + +#include "common.h" +#include "server.h" +#include "byteorder.h" +#include "matrix_lib.h" +#include "com_library.h" +#include "const.h" + +#define EOFS( x ) (int)&(((entvars_t *)0)->x) + +void Sys_FsGetString( file_t *f, char *str ) +{ + char ch; + + while( (ch = FS_Getc( f )) != EOF ) + { + *str++ = ch; + if( !ch ) break; + } +} + +void Sys_FreeNameFuncGlobals( void ) +{ + int i; + + if( svg.ordinals ) Mem_Free( svg.ordinals ); + if( svg.funcs) Mem_Free( svg.funcs); + + for( i = 0; i < svg.num_ordinals; i++ ) + { + if( svg.names[i] ) + Mem_Free( svg.names[i] ); + } + + svg.num_ordinals = 0; + svg.ordinals = NULL; + svg.funcs = NULL; +} + +char *Sys_GetMSVCName( const char *in_name ) +{ + char *pos, *out_name; + + if( in_name[0] == '?' ) // is this a MSVC C++ mangled name? + { + if(( pos = com.strstr( in_name, "@@" )) != NULL ) + { + int len = pos - in_name; + + out_name = copystring( in_name + 1 ); // strip off the leading '?' + out_name[len-1] = 0; // terminate string at the "@@" + return out_name; + } + } + + return copystring( in_name ); +} + +bool Sys_LoadSymbols( const char *filename ) +{ + file_t *f; + DOS_HEADER dos_header; + LONG nt_signature; + PE_HEADER pe_header; + SECTION_HEADER section_header; + bool edata_found; + OPTIONAL_HEADER optional_header; + long edata_offset; + long edata_delta; + EXPORT_DIRECTORY export_directory; + long name_offset; + long ordinal_offset; + long function_offset; + string function_name; + dword *p_Names = NULL; + int i, index; + + for( i = 0; i < svg.num_ordinals; i++ ) + svg.names[i] = NULL; + + f = FS_Open( filename, "rb" ); + if( !f ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s not found\n", filename ); + return false; + } + + if( FS_Read( f, &dos_header, sizeof(dos_header)) != sizeof( dos_header )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s has corrupted EXE header\n", filename ); + FS_Close( f ); + return false; + } + + if( dos_header.e_magic != DOS_SIGNATURE ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid dll signature\n", filename ); + FS_Close( f ); + return false; + } + + if( FS_Seek( f, dos_header.e_lfanew, SEEK_SET ) == -1 ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error seeking to new exe header\n", filename ); + FS_Close( f ); + return false; + } + + if( FS_Read( f, &nt_signature, sizeof( nt_signature )) != sizeof( nt_signature )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s has corrupted NT header\n", filename ); + FS_Close( f ); + return false; + } + + if( nt_signature != NT_SIGNATURE ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid NT signature\n", filename ); + FS_Close( f ); + return false; + } + + if( FS_Read( f, &pe_header, sizeof( pe_header )) != sizeof( pe_header )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid PE header\n", filename ); + FS_Close( f ); + return false; + } + + if( !pe_header.SizeOfOptionalHeader ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have an optional header\n", filename ); + FS_Close( f ); + return false; + } + + if( FS_Read( f, &optional_header, sizeof( optional_header )) != sizeof( optional_header )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s optional header probably corrupted\n", filename ); + FS_Close( f ); + return false; + } + + edata_found = false; + + for( i = 0; i < pe_header.NumberOfSections; i++ ) + { + + if( FS_Read( f, §ion_header, sizeof( section_header )) != sizeof( section_header )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading section header\n", filename ); + FS_Close( f ); + return false; + } + + if( !com.strcmp((char *)section_header.Name, ".edata" )) + { + edata_found = TRUE; + break; + } + } + + if( edata_found ) + { + edata_offset = section_header.PointerToRawData; + edata_delta = section_header.VirtualAddress - section_header.PointerToRawData; + } + else + { + edata_offset = optional_header.DataDirectory[0].VirtualAddress; + edata_delta = 0L; + } + + if( FS_Seek( f, edata_offset, SEEK_SET ) == -1 ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid exports section\n", filename ); + FS_Close( f ); + return false; + } + + if( FS_Read( f, &export_directory, sizeof( export_directory )) != sizeof( export_directory )) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid optional header\n", filename ); + FS_Close( f ); + return false; + } + + svg.num_ordinals = export_directory.NumberOfNames; // also number of ordinals + + if( svg.num_ordinals > MAX_SYSPATH ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s too many exports\n", filename ); + FS_Close( f ); + return false; + } + + ordinal_offset = export_directory.AddressOfNameOrdinals - edata_delta; + + if( FS_Seek( f, ordinal_offset, SEEK_SET ) == -1 ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid ordinals section\n", filename ); + FS_Close( f ); + return false; + } + + svg.ordinals = Z_Malloc( svg.num_ordinals * sizeof( word )); + + if( FS_Read( f, svg.ordinals, svg.num_ordinals * sizeof( word )) != (svg.num_ordinals * sizeof( word ))) + { + Sys_FreeNameFuncGlobals(); + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading ordinals table\n", filename ); + FS_Close( f ); + return false; + } + + function_offset = export_directory.AddressOfFunctions - edata_delta; + if( FS_Seek( f, function_offset, SEEK_SET ) == -1 ) + { + MsgDev( D_ERROR, "Sys_LoadSymbols: %s does not have a valid export address section\n", filename ); + FS_Close( f ); + return false; + } + + svg.funcs = Z_Malloc( svg.num_ordinals * sizeof( dword )); + + if( FS_Read( f, svg.funcs, svg.num_ordinals * sizeof( dword )) != (svg.num_ordinals * sizeof( dword ))) + { + Sys_FreeNameFuncGlobals(); + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading export address section\n", filename ); + FS_Close( f ); + return false; + } + + name_offset = export_directory.AddressOfNames - edata_delta; + + if( FS_Seek( f, name_offset, SEEK_SET ) == -1 ) + { + Sys_FreeNameFuncGlobals(); + MsgDev( D_ERROR, "Sys_LoadSymbols: %s file does not have a valid names section\n", filename ); + FS_Close( f ); + return false; + } + + p_Names = Z_Malloc( svg.num_ordinals * sizeof( dword )); + + if( FS_Read( f, p_Names, svg.num_ordinals * sizeof( dword )) != (svg.num_ordinals * sizeof( dword ))) + { + Sys_FreeNameFuncGlobals(); + if( p_Names ) Mem_Free( p_Names ); + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during reading names table\n", filename ); + FS_Close( f ); + return false; + } + + for( i = 0; i < svg.num_ordinals; i++ ) + { + name_offset = p_Names[i] - edata_delta; + + if( name_offset != 0 ) + { + if( FS_Seek( f, name_offset, SEEK_SET ) != -1 ) + { + Sys_FsGetString( f, function_name ); + svg.names[i] = Sys_GetMSVCName( function_name ); + } + else break; + } + } + + if( i != svg.num_ordinals ) + { + Sys_FreeNameFuncGlobals(); + if( p_Names ) Mem_Free( p_Names ); + MsgDev( D_ERROR, "Sys_LoadSymbols: %s error during loading names section\n", filename ); + FS_Close( f ); + return false; + } + FS_Close( f ); + + for( i = 0; i < svg.num_ordinals; i++ ) + { + if( com.strcmp( "GiveFnptrsToDll", svg.names[i] )) + { + void *fn_offset; + + index = svg.ordinals[i]; + fn_offset = (void *)Sys_GetProcAddress( svs.game, "GiveFnptrsToDll" ); + svg.funcBase = (dword)(fn_offset) - svg.funcs[index]; + break; + } + } + if( p_Names ) Mem_Free( p_Names ); + return true; +} + +/* +============ +SV_CalcBBox + +FIXME: get to work +============ +*/ +void SV_CalcBBox( edict_t *ent, const float *mins, const float *maxs ) +{ + vec3_t rmin, rmax; + int i, j, k, l; + float a, *angles; + vec3_t bounds[2]; + float xvector[2], yvector[2]; + vec3_t base, transformed; + + // find min / max for rotations + angles = ent->v.angles; + + a = angles[1]/180 * M_PI; + + xvector[0] = cos(a); + xvector[1] = sin(a); + yvector[0] = -sin(a); + yvector[1] = cos(a); + + VectorCopy( mins, bounds[0] ); + VectorCopy( maxs, bounds[1] ); + + rmin[0] = rmin[1] = rmin[2] = 9999; + rmax[0] = rmax[1] = rmax[2] = -9999; + + for( i = 0; i <= 1; i++ ) + { + base[0] = bounds[i][0]; + for( j = 0; j <= 1; j++ ) + { + base[1] = bounds[j][1]; + for( k = 0; k <= 1; k++ ) + { + base[2] = bounds[k][2]; + + // transform the point + transformed[0] = xvector[0] * base[0] + yvector[0] * base[1]; + transformed[1] = xvector[1] * base[0] + yvector[1] * base[1]; + transformed[2] = base[2]; + + for( l = 0; l < 3; l++ ) + { + if( transformed[l] < rmin[l] ) rmin[l] = transformed[l]; + if( transformed[l] > rmax[l] ) rmax[l] = transformed[l]; + } + } + } + } + + VectorCopy( rmin, ent->v.mins ); + VectorCopy( rmax, ent->v.maxs ); +} + +void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max, bool rotate ) +{ + int i; + + for( i = 0; i < 3; i++ ) + if( min[i] > max[i] ) + Host_Error( "SV_SetMinMaxSize: backwards mins/maxs\n" ); + + rotate = false; // FIXME + + // set derived values + if( rotate && e->v.solid == SOLID_BBOX ) + { + SV_CalcBBox( e, min, max ); + } + else + { + VectorCopy( min, e->v.mins); + VectorCopy( max, e->v.maxs); + } + VectorSubtract( max, min, e->v.size ); + + // TODO: fill also mass and density + SV_LinkEdict (e); +} + +void SV_CopyTraceResult( TraceResult *out, trace_t trace ) +{ + if( !out ) return; + + out->fAllSolid = trace.allsolid; + out->fStartSolid = trace.startsolid; + out->fStartStuck = trace.startstuck; + out->flFraction = trace.fraction; + out->iStartContents = trace.startcontents; + out->iContents = trace.contents; + out->iHitgroup = trace.hitgroup; + out->flPlaneDist = trace.plane.dist; + VectorCopy( trace.endpos, out->vecEndPos ); + VectorCopy( trace.plane.normal, out->vecPlaneNormal ); + + if( trace.surface ) + out->pTexName = trace.surface->name; + else out->pTexName = NULL; + out->pHit = trace.ent; +} + +void SV_CopyTraceToGlobal( trace_t *trace ) +{ + svs.globals->trace_allsolid = trace->allsolid; + svs.globals->trace_startsolid = trace->startsolid; + svs.globals->trace_startstuck = trace->startstuck; + svs.globals->trace_contents = trace->contents; + svs.globals->trace_start_contents = trace->startcontents; + svs.globals->trace_fraction = trace->fraction; + svs.globals->trace_plane_dist = trace->plane.dist; + svs.globals->trace_ent = trace->ent; + VectorCopy( trace->endpos, svs.globals->trace_endpos ); + VectorCopy( trace->plane.normal, svs.globals->trace_plane_normal ); + + if( trace->surface ) + svs.globals->trace_texture = trace->surface->name; + else svs.globals->trace_texture = NULL; + svs.globals->trace_hitgroup = trace->hitgroup; +} + +static trace_t SV_TraceToss( edict_t *tossent, edict_t *ignore) +{ + int i; + float gravity; + vec3_t move, end; + vec3_t original_origin; + vec3_t original_velocity; + vec3_t original_angles; + vec3_t original_avelocity; + trace_t trace; + + VectorCopy( tossent->v.origin, original_origin ); + VectorCopy( tossent->v.velocity, original_velocity ); + VectorCopy( tossent->v.angles, original_angles ); + VectorCopy( tossent->v.avelocity, original_avelocity ); + gravity = tossent->v.gravity * sv_gravity->value * 0.05; + + for( i = 0; i < 200; i++ ) + { + // LordHavoc: sanity check; never trace more than 10 seconds + SV_CheckVelocity( tossent ); + tossent->v.velocity[2] -= gravity; + VectorMA( tossent->v.angles, 0.05, tossent->v.avelocity, tossent->v.angles ); + VectorScale( tossent->v.velocity, 0.05, move ); + VectorAdd( tossent->v.origin, move, end ); + trace = SV_Trace( tossent->v.origin, tossent->v.mins, tossent->v.maxs, end, MOVE_NORMAL, tossent, SV_ContentsMask( tossent )); + VectorCopy( trace.endpos, tossent->v.origin ); + if( trace.fraction < 1 ) break; + } + VectorCopy( original_origin, tossent->v.origin ); + VectorCopy( original_velocity, tossent->v.velocity ); + VectorCopy( original_angles, tossent->v.angles ); + VectorCopy( original_avelocity, tossent->v.avelocity ); + + return trace; +} + +bool SV_CheckForPhysobject( edict_t *ent ) +{ + if( !ent ) return false; + + switch( (int)ent->v.solid ) + { + case SOLID_BSP: + switch( (int)ent->v.movetype ) + { + case MOVETYPE_NONE: // static physobject (no gravity) + case MOVETYPE_PUSH: // dynamic physobject (no gravity) + case MOVETYPE_CONVEYOR: + // return true; + default: return false; + } + break; + case SOLID_BOX: + case SOLID_SPHERE: + case SOLID_CYLINDER: + case SOLID_MESH: + switch( (int)ent->v.movetype ) + { + case MOVETYPE_PHYSIC: // dynamic physobject (with gravity) + return true; + default: return false; + } + break; + default: return false; + } +} + +void SV_CreatePhysBody( edict_t *ent ) +{ + if( !SV_CheckForPhysobject( ent )) return; + ent->pvEngineData->physbody = pe->CreateBody( ent, SV_GetModelPtr(ent), ent->v.origin, ent->v.m_pmatrix, ent->v.solid, ent->v.movetype ); + + pe->SetParameters( ent->pvEngineData->physbody, SV_GetModelPtr(ent), 0, ent->v.mass ); +} + +void SV_SetPhysForce( edict_t *ent ) +{ + if( !SV_CheckForPhysobject( ent )) return; + pe->SetForce( ent->pvEngineData->physbody, ent->v.velocity, ent->v.avelocity, ent->v.force, ent->v.torque ); +} + +void SV_SetMassCentre( edict_t *ent ) +{ + if( !SV_CheckForPhysobject( ent )) return; + pe->SetMassCentre( ent->pvEngineData->physbody, ent->v.m_pcentre ); +} + +void SV_SetModel( edict_t *ent, const char *name ) +{ + int i; + cmodel_t *mod; + vec3_t angles; + + i = SV_ModelIndex( name ); + if( i == 0 ) return; + // we can accept configstring as non moveable memory ? + ent->v.model = MAKE_STRING( sv.configstrings[CS_MODELS+i] ); + ent->v.modelindex = i; + + mod = pe->RegisterModel( name ); + if( mod ) SV_SetMinMaxSize( ent, mod->mins, mod->maxs, false ); + + switch( (int)ent->v.movetype ) + { + case MOVETYPE_PHYSIC: + // FIXME: translate angles correctly + angles[0] = ent->v.angles[0] - 180; + angles[1] = ent->v.angles[1]; + angles[2] = ent->v.angles[2] - 90; + break; + case MOVETYPE_NONE: + case MOVETYPE_PUSH: + case MOVETYPE_CONVEYOR: + VectorClear( angles ); + ent->v.mass = 0.0f; + break; + } + + Matrix3x3_FromAngles( angles, ent->v.m_pmatrix ); + Matrix3x3_Transpose( ent->v.m_pmatrix, ent->v.m_pmatrix ); + SV_CreatePhysBody( ent ); +} + +float SV_AngleMod( float ideal, float current, float speed ) +{ + float move; + + if (current == ideal) // already there? + return anglemod( current ); + + move = ideal - current; + if (ideal > current) + { + if (move >= 180) move = move - 360; + } + else + { + if (move <= -180) move = move + 360; + } + if (move > 0) + { + if (move > speed) move = speed; + } + else + { + if (move < -speed) move = -speed; + } + return anglemod(current + move); +} + +void SV_ConfigString( int index, const char *val ) +{ + if(index < 0 || index >= MAX_CONFIGSTRINGS) + Host_Error ("configstring: bad index %i value %s\n", index, val); + + if(!*val) val = ""; + + // change the string in sv + com.strcpy( sv.configstrings[index], val ); + + if( sv.state != ss_loading ) + { + // send the update to everyone + MSG_Clear( &sv.multicast ); + MSG_Begin(svc_configstring); + MSG_WriteShort (&sv.multicast, index); + MSG_WriteString (&sv.multicast, (char *)val); + MSG_Send(MSG_ALL_R, vec3_origin, NULL ); + } +} + +bool SV_EntitiesIn( bool mode, vec3_t v1, vec3_t v2 ) +{ + int leafnum, cluster; + int area1, area2; + byte *mask; + + leafnum = pe->PointLeafnum (v1); + cluster = pe->LeafCluster (leafnum); + area1 = pe->LeafArea (leafnum); + if( mode == DVIS_PHS ) mask = pe->ClusterPHS( cluster ); + else if( mode == DVIS_PVS ) mask = pe->ClusterPVS( cluster ); + else Host_Error( "SV_EntitiesIn: unsupported mode\n" ); + + leafnum = pe->PointLeafnum (v2); + cluster = pe->LeafCluster (leafnum); + area2 = pe->LeafArea (leafnum); + + if( mask && (!(mask[cluster>>3] & (1<<(cluster&7))))) + return false; + else if (!pe->AreasConnected (area1, area2)) + return false; + return true; +} + +edict_t *SV_AllocEdict( void ) +{ + edict_t *pEdict = svg.edicts; + int i; + + // search for free entity + for( i = svs.globals->maxClients; i < svs.globals->numEntities; i++ ) + { + pEdict = svg.edicts + i; + if( pEdict->free ) break; + } + + if( i == svs.globals->numEntities ) + { + if( ++svs.globals->numEntities == svs.globals->maxEntities ) + { + MsgDev( D_ERROR, "SV_AllocEdict: no free edicts\n" ); + return NULL; + } + } + + pEdict->pvEngineData = (ed_priv_t *)Mem_Alloc( svs.mempool, sizeof( ed_priv_t )); + pEdict->pvServerData = NULL; // will be alloced later by pfnAllocPrivateData + pEdict->serialnumber = pEdict->pvEngineData->s.number = NUM_FOR_EDICT( pEdict ); + pEdict->free = false; + + return pEdict; +} + +void SV_FreeEdict( edict_t *e ) +{ + // unlink from world + SV_UnlinkEdict( e ); + pe->RemoveBody( e->pvEngineData->physbody ); + + if( e->pvEngineData ) Mem_Free( e->pvEngineData ); + if( e->pvServerData ) Mem_Free( e->pvServerData ); + Mem_Set( &e->v, 0, sizeof( entvars_t )); + + e->pvEngineData = NULL; + e->pvServerData = NULL; + + // mark edict as freed + e->freetime = sv.time; + e->v.nextthink = -1; + e->serialnumber = 0; + e->free = true; +} + +/* +============ +Save\Load gamestate + +savegame operations +============ +*/ +static int s_table; + +void SV_AddSaveLump( wfile_t *f, const char *lumpname, void *data, size_t len, bool compress ) +{ + if( f ) WAD_Write( f, lumpname, data, len, TYPE_BINDATA, ( compress ? CMP_ZLIB : CMP_NONE )); +} + +static void SV_SetPair( const char *name, const char *value, dkeyvalue_t *cvars, int *numpairs ) +{ + if( !name || !value ) return; // SetString can't register null strings + cvars[*numpairs].epair[DENT_KEY] = StringTable_SetString( s_table, name ); + cvars[*numpairs].epair[DENT_VAL] = StringTable_SetString( s_table, value); + (*numpairs)++; // increase epairs +} + +void SV_AddCvarLump( wfile_t *f ) +{ + dkeyvalue_t cvbuffer[MAX_FIELDS]; + int numpairs = 0; + + Cvar_LookupVars( CVAR_LATCH, cvbuffer, &numpairs, SV_SetPair ); + SV_AddSaveLump( f, LUMP_GAMECVARS, cvbuffer, numpairs * sizeof(dkeyvalue_t), true ); +} + +void SV_AddCStrLump( wfile_t *f ) +{ + string_t csbuffer[MAX_CONFIGSTRINGS]; + int i; + + // pack the cfg string data + for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) + csbuffer[i] = StringTable_SetString( s_table, sv.configstrings[i] ); + SV_AddSaveLump( f, LUMP_CFGSTRING, &csbuffer, sizeof(csbuffer), true ); +} + +void SV_WriteGlobal( wfile_t *f ) +{ + dkeyvalue_t globals[MAX_FIELDS]; + int numpairs = 0; + + PRVM_ED_WriteGlobals( &globals, &numpairs, SV_SetPair ); + SV_AddSaveLump( f, LUMP_GAMESTATE, &globals, numpairs * sizeof(dkeyvalue_t), true ); +} + +void SV_WriteLocals( wfile_t *f ) +{ + dkeyvalue_t fields[MAX_FIELDS]; + vfile_t *h = VFS_Open( NULL, "wb" ); + int i, numpairs = 0; + + for( i = 0; i < svs.globals->numEntities; i++ ) + { + numpairs = 0; // reset fields info + PRVM_ED_Write( PRVM_EDICT_NUM( i ), &fields, &numpairs, SV_SetPair ); + VFS_Write( h, &numpairs, sizeof( int )); // numfields + VFS_Write( h, &fields, numpairs * sizeof( dkeyvalue_t )); // fields + } + + // all allocated memory will be freed at end of SV_WriteSaveFile + SV_AddSaveLump( f, LUMP_GAMEENTS, VFS_GetBuffer( h ), VFS_Tell( h ), true ); + VFS_Close( h ); // release virtual file +} + +/* +============= +SV_WriteSaveFile +============= +*/ +void SV_WriteSaveFile( const char *name ) +{ + string comment; + wfile_t *savfile = NULL; + bool autosave = false; + char path[MAX_SYSPATH]; + byte *portalstate = Z_Malloc( MAX_MAP_AREAPORTALS ); + int portalsize; + + if( sv.state != ss_active ) + return; + + if(Cvar_VariableValue("deathmatch") || Cvar_VariableValue("coop")) + { + MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame in a multiplayer\n"); + return; + } + if(Host_MaxClients() == 1 && svs.clients[0].edict->v.health <= 0 ) + { + MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame while dead!\n"); + return; + } + + if(!com.strcmp(name, "save0.bin")) autosave = true; + com.sprintf( path, "save/%s", name ); + savfile = WAD_Open( path, "wb" ); + + if( !savfile ) + { + MsgDev(D_ERROR, "SV_WriteSaveFile: failed to open %s\n", path ); + return; + } + + MsgDev( D_INFO, "Saving game..." ); + com.sprintf (comment, "%s - %s", sv.configstrings[CS_NAME], timestamp( TIME_FULL )); + s_table = StringTable_Create( name, 0x10000 ); // 65535 unique strings + + // write lumps + pe->GetAreaPortals( &portalstate, &portalsize ); + SV_AddSaveLump( savfile, LUMP_AREASTATE, portalstate, portalsize, true ); + SV_AddSaveLump( savfile, LUMP_COMMENTS, comment, sizeof(comment), false ); + SV_AddSaveLump( savfile, LUMP_MAPCMDS, svs.mapcmd, sizeof(svs.mapcmd), false ); + SV_AddCStrLump( savfile ); + SV_AddCvarLump( savfile ); + SV_WriteGlobal( savfile ); + SV_WriteLocals( savfile ); + StringTable_Save( s_table, savfile ); // now system released + Mem_Free( portalstate ); // release portalinfo + WAD_Close( savfile ); + + MsgDev( D_INFO, "done.\n" ); +} + +void Sav_LoadComment( wfile_t *l ) +{ + byte *in; + int size; + + in = WAD_Read( l, LUMP_COMMENTS, &size, TYPE_BINDATA ); + com.strncpy( svs.comment, in, size ); +} + +void Sav_LoadCvars( wfile_t *l ) +{ + dkeyvalue_t *in; + int i, numpairs; + const char *name, *value; + + in = (dkeyvalue_t *)WAD_Read( l, LUMP_GAMECVARS, &numpairs, TYPE_BINDATA ); + if( numpairs % sizeof(*in)) Host_Error( "Sav_LoadCvars: funny lump size\n" ); + numpairs /= sizeof( dkeyvalue_t ); + + for( i = 0; i < numpairs; i++ ) + { + name = StringTable_GetString( s_table, in[i].epair[DENT_KEY] ); + value = StringTable_GetString( s_table, in[i].epair[DENT_VAL] ); + Cvar_SetLatched( name, value ); + } +} + +void Sav_LoadMapCmds( wfile_t *l ) +{ + byte *in; + int size; + + in = WAD_Read( l, LUMP_MAPCMDS, &size, TYPE_BINDATA ); + com.strncpy( svs.mapcmd, in, size ); +} + +void Sav_LoadCfgString( wfile_t *l ) +{ + string_t *in; + int i, numstrings; + + in = (string_t *)WAD_Read( l, LUMP_CFGSTRING, &numstrings, TYPE_BINDATA ); + if( numstrings % sizeof(*in)) Host_Error( "Sav_LoadCfgString: funny lump size\n" ); + numstrings /= sizeof( string_t ); // because old saves can contain last values of MAX_CONFIGSTRINGS + + // unpack the cfg string data + for( i = 0; i < numstrings; i++ ) + com.strncpy( sv.configstrings[i], StringTable_GetString( s_table, in[i] ), CS_SIZE ); +} + +void Sav_LoadAreaPortals( wfile_t *l ) +{ + byte *in; + int size; + + in = WAD_Read( l, LUMP_AREASTATE, &size, TYPE_BINDATA ); + pe->SetAreaPortals( in, size ); // CM_ReadPortalState +} + +void Sav_LoadGlobal( wfile_t *l ) +{ + dkeyvalue_t *globals; + int numpairs; + + globals = (dkeyvalue_t *)WAD_Read( l, LUMP_GAMESTATE, &numpairs, TYPE_BINDATA ); + if( numpairs % sizeof(*globals)) Host_Error( "Sav_LoadGlobal: funny lump size\n" ); + numpairs /= sizeof( dkeyvalue_t ); + PRVM_ED_ReadGlobals( s_table, globals, numpairs ); +} + +void Sav_LoadLocals( wfile_t *l ) +{ + dkeyvalue_t fields[MAX_FIELDS]; + int numpairs, entnum = 0; + byte *buff; + size_t size; + vfile_t *h; + + buff = WAD_Read( l, LUMP_GAMEENTS, &size, TYPE_BINDATA ); + h = VFS_Create( buff, size ); + + while(!VFS_Eof( h )) + { + VFS_Read( h, &numpairs, sizeof( int )); + VFS_Read( h, &fields, numpairs * sizeof( dkeyvalue_t )); + PRVM_ED_Read( s_table, entnum, fields, numpairs ); + entnum++; + } + svs.globals->numEntities = entnum; +} + +/* +============= +SV_ReadSaveFile +============= +*/ +void SV_ReadSaveFile( const char *name ) +{ + char path[MAX_SYSPATH]; + wfile_t *savfile; + int s_table; + + com.sprintf(path, "save/%s", name ); + savfile = WAD_Open( path, "rb" ); + + if( !savfile ) + { + MsgDev(D_ERROR, "SV_ReadSaveFile: can't open %s\n", path ); + return; + } + + s_table = StringTable_Load( savfile, name ); + Sav_LoadComment( savfile ); + Sav_LoadCvars( savfile ); + StringTable_Delete( s_table ); + + SV_InitGame(); // start a new game fresh with new cvars + Sav_LoadMapCmds( savfile ); + WAD_Close( savfile ); + CL_Drop(); +} + +/* +============= +SV_ReadLevelFile +============= +*/ +void SV_ReadLevelFile( const char *name ) +{ + char path[MAX_SYSPATH]; + wfile_t *savfile; + int s_table; + + com.sprintf (path, "save/%s", name ); + savfile = WAD_Open( path, "rb" ); + + if( !savfile ) + { + MsgDev( D_ERROR, "SV_ReadLevelFile: can't open %s\n", path ); + return; + } + + s_table = StringTable_Load( savfile, name ); + Sav_LoadCfgString( savfile ); + Sav_LoadAreaPortals( savfile ); + Sav_LoadGlobal( savfile ); + Sav_LoadLocals( savfile ); + StringTable_Delete( s_table ); + WAD_Close( savfile ); +} + +bool SV_ReadComment( char *comment, int savenum ) +{ + wfile_t *savfile; + int result; + + if( !comment ) return false; + result = WAD_Check( va( "save/save%i.bin", savenum )); + + switch( result ) + { + case 0: + com.strncpy( comment, "", MAX_STRING ); + return false; + case 1: break; + default: + com.strncpy( comment, "", MAX_STRING ); + return false; + } + + savfile = WAD_Open( va("save/save%i.bin", savenum), "rb" ); + Sav_LoadComment( savfile ); + com.strncpy( comment, svs.comment, MAX_STRING ); + WAD_Close( savfile ); + + return true; +} + +/* +=============================================================================== + Game Builtin Functions + +=============================================================================== +*/ +/* +========= +pfnPrecacheModel + +========= +*/ +int pfnPrecacheModel( const char *s ) +{ + if( !com.strcmp( s, "" )) + return 0; + return SV_ModelIndex( s ); +} + +/* +========= +pfnPrecacheSound + +========= +*/ +int pfnPrecacheSound( const char *s ) +{ + if( !com.strcmp( s, "" )) + return 0; + return SV_SoundIndex( s ); +} + +/* +================= +pfnSetModel + +================= +*/ +void pfnSetModel( edict_t *e, const char *m ) +{ + if( e == svg.edicts ) + { + MsgDev( D_WARN, "SV_SetModel: can't modify world entity\n" ); + return; + } + + if( e->free ) + { + MsgDev( D_WARN, "SV_SetModel: can't modify free entity\n" ); + return; + } + + if( m[0] <= ' ' ) + { + MsgDev( D_WARN, "SV_SetModel: null name\n" ); + return; + } + SV_SetModel( e, m ); +} + +/* +================= +pfnModelIndex + +================= +*/ +int pfnModelIndex( const char *m ) +{ + int index; + + if( !com.strcmp( m, "" )) return 0; + index = SV_FindIndex( m, CS_MODELS, MAX_MODELS, false ); + + if( !index ) MsgDev( D_WARN, "SV_ModelIndex: %s not precached\n", m ); + return index; +} + +/* +================= +pfnModelFrames + +================= +*/ +int pfnModelFrames( int modelIndex ) +{ + cmodel_t *mod; + + // can be returned pointer on a registered model + mod = pe->RegisterModel( sv.configstrings[CS_MODELS + modelIndex] ); + + if( mod ) return mod->numframes; + MsgDev( D_WARN, "SV_ModelFrames: %s not found\n", sv.configstrings[CS_MODELS + modelIndex] ); + + return 0; +} + +/* +================= +pfnSetSize + +================= +*/ +void pfnSetSize( edict_t *e, const float *rgflMin, const float *rgflMax ) +{ + if( !e || !e->pvServerData ) + { + MsgDev( D_ERROR, "SV_SetSize: entity not exist\n" ); + return; + } + else if( e == svg.edicts ) + { + MsgDev( D_ERROR, "SV_SetSize: can't modify world entity\n" ); + return; + } + else if( e->free ) + { + MsgDev( D_ERROR, "SV_SetSize: can't modify free entity\n" ); + return; + } + + SV_SetMinMaxSize( e, rgflMin, rgflMax, !VectorIsNull( e->v.angles )); +} + +/* +================= +pfnChangeLevel + +================= +*/ +void pfnChangeLevel( const char* s1, const char* s2 ) +{ + string changelevel_cmd; + + com.snprintf( changelevel_cmd, MAX_STRING, "changelevel %s %s\n", s1, s2 ); + Cbuf_ExecuteText( EXEC_APPEND, changelevel_cmd ); +} + +/* +================= +pfnVecToYaw + +================= +*/ +float pfnVecToYaw( const float *rgflVector ) +{ + float yaw; + + if( rgflVector[1] == 0 && rgflVector[0] == 0 ) + { + yaw = 0; + } + else + { + yaw = (int)( com.atan2(rgflVector[1], rgflVector[0]) * 180 / M_PI ); + if( yaw < 0 ) yaw += 360; + } + return yaw; +} + +/* +================= +pfnVecToAngles + +================= +*/ +void pfnVecToAngles( const float *rgflVectorIn, float *rgflVectorOut ) +{ + float forward; + float yaw, pitch; + + if( rgflVectorIn[1] == 0 && rgflVectorIn[0] == 0 ) + { + yaw = 0; + if( rgflVectorIn[2] > 0 ) + pitch = 90; + else pitch = 270; + } + else + { + if( rgflVectorIn[0] ) + { + yaw = (int)( com.atan2( rgflVectorIn[1], rgflVectorIn[0] ) * 180 / M_PI ); + if( yaw < 0 ) yaw += 360; + } + else if( rgflVectorIn[1] > 0 ) + yaw = 90; + else yaw = 270; + + forward = com.sqrt( rgflVectorIn[0] * rgflVectorIn[0] + rgflVectorIn[1] * rgflVectorIn[1] ); + pitch = (int)( com.atan2( rgflVectorIn[2], forward ) * 180 / M_PI ); + if( pitch < 0 ) pitch += 360; + } + + if( rgflVectorOut ) VectorSet( rgflVectorOut, pitch, yaw, 0 ); + else MsgDev( D_ERROR, "SV_VecToAngles: no output vector specified\n" ); +} + +/* +================= +pfnMoveToOrigin + +FIXME: i'm not sure what is what you want +================= +*/ +void pfnMoveToOrigin( edict_t *ent, const float *pflGoal, float dist, int iMoveType ) +{ + vec3_t targetDir; + float accelXY = 300.0f, accelZ = 600.0f; + float decay = 9.0f, flInterval = 0.1f; // FIXME + + VectorCopy( pflGoal, targetDir ); + VectorNormalize( targetDir ); + + decay = exp( log( decay ) / 1.0f * flInterval ); + accelXY *= flInterval; + accelZ *= flInterval; + + ent->v.velocity[0] = ( decay * ent->v.velocity[0] + accelXY * targetDir[0] ); + ent->v.velocity[1] = ( decay * ent->v.velocity[1] + accelXY * targetDir[1] ); + ent->v.velocity[2] = ( decay * ent->v.velocity[2] + accelZ * targetDir[2] ); +} + +/* +============== +pfnChangeYaw + +============== +*/ +void pfnChangeYaw( edict_t* ent ) +{ + float current; + + if( ent == svg.edicts ) + { + MsgDev( D_WARN, "SV_ChangeYaw: can't modify world entity\n" ); + return; + } + if( ent->free ) + { + MsgDev( D_WARN, "SV_ChangeYaw: can't modify free entity\n" ); + return; + } + + current = anglemod( ent->v.angles[YAW] ); + ent->v.angles[YAW] = SV_AngleMod( ent->v.ideal_yaw, current, ent->v.yaw_speed ); +} + +/* +============== +pfnChangePitch + +============== +*/ +void pfnChangePitch( edict_t* ent ) +{ + float current; + + if( ent == svg.edicts ) + { + MsgDev( D_WARN, "SV_ChangePitch: can't modify world entity\n" ); + return; + } + if( ent->free ) + { + MsgDev( D_WARN, "SV_ChangePitch: can't modify free entity\n" ); + return; + } + + current = anglemod( ent->v.angles[PITCH] ); + ent->v.angles[PITCH] = SV_AngleMod( ent->v.idealpitch, current, ent->v.pitch_speed ); +} + +/* +========= +pfnFindEntityByString + +========= +*/ +edict_t* pfnFindEntityByString( edict_t *pStartEdict, const char *pszField, const char *pszValue ) +{ + int e, f; + const char *t; + edict_t *ed; + + e = NUM_FOR_EDICT( pStartEdict ); + if( !pszValue ) pszValue = ""; + + if( !com.strcmp( pszField, "classname" )) + f = EOFS( classname ); + else if( !com.strcmp( pszField, "globalname" )) + f = EOFS( globalname ); + else if( !com.strcmp( pszField, "targetname" )) + f = EOFS( targetname ); + else + { + // FIXME: make cases for all fileds + MsgDev( D_ERROR, "field %s unsupported\n", pszField ); + return pStartEdict; + } + + for( e++; e < svs.globals->numEntities; e++ ) + { + ed = EDICT_NUM( e ); + if( ed->free ) continue; + + t = STRING( *(string_t *)&((int *)&ed->v)[f] ); + if( !t ) t = ""; + if( !com.strcmp( t, pszValue )) + return ed; + } + return svg.edicts; +} + +/* +============== +pfnGetEntityIllum + +============== +*/ +int pfnGetEntityIllum( edict_t* pEnt ) +{ + if( pEnt == svg.edicts ) + { + MsgDev( D_WARN, "SV_GetEntityIllum: can't get light level at world entity\n" ); + return 0; + } + if( pEnt->free ) + { + MsgDev( D_WARN, "SV_GetEntityIllum: can't get light level at free entity\n" ); + return 0; + } + return 255; //FIXME: implement +} + +/* +================= +pfnFindEntityInSphere + +return NULL instead of world +================= +*/ +edict_t* pfnFindEntityInSphere( edict_t *pStartEdict, const float *org, float rad ) +{ + edict_t *ent, *chain; + float radSquare; + vec3_t eorg; + int e; + + radSquare = rad * rad; + chain = pStartEdict; + e = NUM_FOR_EDICT( pStartEdict ); + + for( e++; e < svs.globals->numEntities; e++ ) + { + ent = EDICT_NUM( e ); + if( ent->free ) continue; + if( ent->v.solid == SOLID_NOT ) continue; + + VectorSubtract( org, ent->v.origin, eorg ); + VectorMAMAM( 1, eorg, 0.5f, ent->v.mins, 0.5f, ent->v.maxs, eorg ); + + if(DotProduct( eorg, eorg ) < radSquare ) + { + ent->v.chain = chain; + chain = ent; + } + } + + return chain; // fisrt chain +} + +/* +================= +pfnFindClientInPVS + +return NULL instead of world +================= +*/ +edict_t* pfnFindClientInPVS( edict_t *pEdict ) +{ + edict_t *pClient, *chain; + int i, numents; + + chain = NULL; + numents = svs.globals->maxClients; + + for( i = 1; i < numents; i++ ) + { + pClient = svg.edicts + i; + if( pClient->free ) continue; + if( SV_EntitiesIn( DVIS_PVS, pEdict->v.origin, pClient->v.origin )) + { + Msg( "found client %d\n", pClient->serialnumber ); + pEdict->v.chain = chain; + chain = pEdict; + } + } + return chain; // fisrt entry +} + +/* +================= +pfnFindClientInPHS + +return NULL instead of world +================= +*/ +edict_t* pfnFindClientInPHS( edict_t *pEdict ) +{ + edict_t *pClient, *chain; + int i, numents; + + chain = NULL; + numents = svs.globals->maxClients; + + for( i = 1; i < numents; i++ ) + { + pClient = svg.edicts + i; + if( pClient->free ) continue; + if( SV_EntitiesIn( DVIS_PHS, pClient->v.origin, pEdict->v.origin )) + { + Msg( "found client %d\n", pClient->serialnumber ); + pClient->v.chain = chain; + chain = pClient; + } + } + return chain; // fisrt entry +} + +/* +================= +pfnEntitiesInPVS + +================= +*/ +edict_t* pfnEntitiesInPVS( edict_t *pplayer ) +{ + edict_t *pEdict, *chain; + int i, numents; + + chain = NULL; + numents = svs.globals->numEntities; + + for( i = svs.globals->maxClients; i < numents; i++ ) + { + pEdict = svg.edicts + i; + if( pEdict->free ) continue; + if( SV_EntitiesIn( DVIS_PVS, pEdict->v.origin, pplayer->v.origin )) + { + Msg( "found entity %d\n", pEdict->serialnumber ); + pEdict->v.chain = chain; + chain = pEdict; + } + } + return chain; // fisrt entry +} + +/* +================= +pfnEntitiesInPHS + +================= +*/ +edict_t* pfnEntitiesInPHS( edict_t *pplayer ) +{ + edict_t *pEdict, *chain; + int i, numents; + + chain = NULL; + numents = svs.globals->numEntities; + + for( i = svs.globals->maxClients; i < numents; i++ ) + { + pEdict = svg.edicts + i; + if( pEdict->free ) continue; + if( SV_EntitiesIn( DVIS_PHS, pEdict->v.origin, pplayer->v.origin )) + { + Msg( "found entity %d\n", pEdict->serialnumber ); + pEdict->v.chain = chain; + chain = pEdict; + } + } + return chain; // fisrt entry +} + +/* +============== +pfnMakeVectors + +============== +*/ +void pfnMakeVectors( const float *rgflVector ) +{ + AngleVectors( rgflVector, svs.globals->v_forward, svs.globals->v_right, svs.globals->v_up ); +} + +/* +============== +pfnAngleVectors + +can receive NULL output args +============== +*/ +void pfnAngleVectors( const float *rgflVector, float *forward, float *right, float *up ) +{ + AngleVectors( rgflVector, forward, right, up ); +} + +/* +============== +pfnCreateEntity + +just allocate new one +============== +*/ +edict_t* pfnCreateEntity( void ) +{ + return SV_AllocEdict(); +} + +/* +============== +pfnRemoveEntity + +free edict private mem, unlink physics etc +============== +*/ +void pfnRemoveEntity( edict_t* e ) +{ + // never free client or world entity + if( NUM_FOR_EDICT( e ) < svs.globals->maxClients ) + { + MsgDev( D_ERROR, "SV_RemoveEntity: can't delete %s\n", (e == svg.edicts) ? "world" : "client" ); + return; + } + SV_FreeEdict( e ); +} + +/* +============== +pfnCreateNamedEntity + +============== +*/ +edict_t* pfnCreateNamedEntity( string_t className ) +{ + edict_t *ed; + const char *pszClassName; + + pszClassName = STRING( className ); + ed = pfnCreateEntity(); + ed->v.classname = className; + + // also register classname to send for client + ed->pvEngineData->s.classname = SV_ClassIndex( pszClassName ); + + return ed; +} + +/* +============= +pfnMakeStatic + +disable entity updates to client +============= +*/ +void pfnMakeStatic( edict_t *ent ) +{ + ent->pvEngineData->s.ed_type = ED_STATIC; +} + +/* +============= +pfnEntIsOnFloor + +stupid unused bulletin +============= +*/ +int pfnEntIsOnFloor( edict_t *e ) +{ + return (e->v.flags & FL_ONGROUND) ? true : false; +} + +/* +=============== +pfnDropToFloor + +=============== +*/ +int pfnDropToFloor( edict_t* e ) +{ + vec3_t end; + trace_t trace; + + // ignore world silently + if( e == svg.edicts ) return false; + if( e->free ) + { + MsgDev( D_ERROR, "SV_DropToFloor: can't modify free entity\n" ); + return false; + } + + VectorCopy( e->v.origin, end ); + end[2] -= 256; + SV_UnstickEntity( e ); + + trace = SV_Trace( e->v.origin, e->v.mins, e->v.maxs, end, MOVE_NORMAL, e, SV_ContentsMask( e )); + + if( trace.startsolid ) + { + vec3_t offset, org; + + VectorSet( offset, 0.5f * (e->v.mins[0] + e->v.maxs[0]), 0.5f * (e->v.mins[1] + e->v.maxs[1]), e->v.mins[2] ); + VectorAdd( e->v.origin, offset, org ); + trace = SV_Trace( org, vec3_origin, vec3_origin, end, MOVE_NORMAL, e, SV_ContentsMask( e )); + VectorSubtract( trace.endpos, offset, trace.endpos ); + + if( trace.startsolid ) + { + MsgDev( D_WARN, "SV_DropToFloor: startsolid at %g %g %g\n", e->v.origin[0], e->v.origin[1], e->v.origin[2] ); + SV_UnstickEntity( e ); + SV_LinkEdict( e ); + e->v.flags |= FL_ONGROUND; + e->v.groundentity = 0; + } + else if( trace.fraction < 1 ) + { + MsgDev( D_WARN, "SV_DropToFloor: moved to %g %g %g\n", e->v.origin[0], e->v.origin[1], e->v.origin[2] ); + VectorCopy( trace.endpos, e->v.origin ); + SV_UnstickEntity( e ); + SV_LinkEdict( e ); + e->v.flags |= FL_ONGROUND; + e->v.groundentity = trace.ent; + // if support is destroyed, keep suspended + // (gross hack for floating items in various maps) + e->pvEngineData->suspended = true; + return true; + } + + MsgDev( D_WARN, "SV_DropToFloor: startsolid at %g %g %g\n", e->v.origin[0], e->v.origin[1], e->v.origin[2] ); + pfnRemoveEntity( e ); + return false; + } + else + { + if( trace.fraction != 1 ) + { + if( trace.fraction < 1 ) + VectorCopy( trace.endpos, e->v.origin ); + SV_LinkEdict( e ); + e->v.flags |= FL_ONGROUND; + e->v.groundentity = trace.ent; + // if support is destroyed, keep suspended + // (gross hack for floating items in various maps) + e->pvEngineData->suspended = true; + return true; + } + } + return false; +} + +/* +=============== +pfnWalkMove + +FIXME: tune modes +=============== +*/ +int pfnWalkMove( edict_t *ent, float yaw, float dist, int iMode ) +{ + vec3_t move; + + // ignore world silently + if( ent == svg.edicts ) return false; + if( ent->free ) + { + MsgDev( D_WARN, "SV_DropToFloor: can't modify free entity\n" ); + return false; + } + + if(!(ent->v.aiflags & AI_FLY|AI_SWIM) || !(ent->v.flags & FL_ONGROUND)) + return false; + yaw = yaw * M_PI * 2 / 360; + + VectorSet( move, com.cos( yaw ) * dist, com.sin( yaw ) * dist, 0.0f ); + return SV_movestep( ent, move, true, iMode, false ); +} + +/* +================= +pfnSetOrigin + +================= +*/ +void pfnSetOrigin( edict_t *e, const float *rgflOrigin ) +{ + // ignore world silently + if( e == svg.edicts ) return; + if( e->free ) + { + MsgDev( D_ERROR, "SV_SetOrigin: can't modify free entity\n" ); + return; + } + + if( VectorCompare( rgflOrigin, e->v.origin )) + return; // already there ? + + VectorCopy( rgflOrigin, e->v.origin ); + pe->SetOrigin( e->pvEngineData->physbody, e->v.origin ); + SV_LinkEdict( e ); +} + +/* +================= +pfnSetAngles + +================= +*/ +void pfnSetAngles( edict_t *e, const float *rgflAngles ) +{ + if( e == svg.edicts ) return; + if( e->free ) + { + MsgDev( D_ERROR, "SV_SetAngles: can't modify free entity\n" ); + return; + } + + if( VectorCompare( rgflAngles, e->v.angles )) + return; // already there ? + + VectorCopy( rgflAngles, e->v.angles ); + Matrix3x3_FromAngles( e->v.angles, e->v.m_pmatrix ); + Matrix3x3_Transpose( e->v.m_pmatrix, e->v.m_pmatrix ); +} + +/* +================= +pfnEmitSound + +================= +*/ +void pfnEmitSound( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ) +{ + // FIXME: implement +} + +/* +================= +pfnEmitAmbientSound + +================= +*/ +void pfnEmitAmbientSound( edict_t *ent, float *pos, const char *samp, float vol, float attn, int flags, int pitch ) +{ + // FIXME: implement +} + +/* +================= +pfnTraceLine + +================= +*/ +void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ) +{ + trace_t trace; + int move; + + move = (fNoMonsters) ? MOVE_NOMONSTERS : MOVE_NORMAL; + + if( IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2] )) + Host_Error( "SV_Trace: NAN errors detected ('%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] ); + + trace = SV_Trace( v1, vec3_origin, vec3_origin, v2, move, pentToSkip, SV_ContentsMask( pentToSkip )); + SV_CopyTraceResult( ptr, trace ); +} + +/* +================= +pfnTraceToss + +================= +*/ +void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ) +{ + trace_t trace; + + if( pent == svg.edicts ) return; + trace = SV_TraceToss( pent, pentToIgnore ); + SV_CopyTraceResult( ptr, trace ); +} + +/* +================= +pfnTraceHull + +FIXME: replace constant hulls with mins/maxs +================= +*/ +void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ) +{ + vec3_t mins, maxs; + trace_t trace; + int move; + + move = (fNoMonsters) ? MOVE_NOMONSTERS : MOVE_NORMAL; + + switch( hullNumber ) + { + case human_hull: + VectorSet( mins, -16, -16, 0 ); + VectorSet( maxs, 16, 16, 72); + break; + case large_hull: + VectorSet( mins, -32, -32,-32); + VectorSet( maxs, 32, 32, 32); + break; + case head_hull: // ducked + VectorSet( mins, -16, -16,-18); + VectorSet( maxs, 16, 16, 18); + break; + case point_hull: + default: VectorCopy( vec3_origin, mins ); + VectorCopy( vec3_origin, maxs ); + break; + } + + if( IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2] )) + Host_Error( "SV_TraceHull: NAN errors detected ('%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] ); + + trace = SV_Trace( v1, mins, mins, v2, move, pentToSkip, SV_ContentsMask( pentToSkip )); + SV_CopyTraceResult( ptr, trace ); +} + +void pfnTraceModel( const float *v1, const float *v2, edict_t *pent, TraceResult *ptr ) +{ + // FIXME: implement +} + +const char *pfnTraceTexture( edict_t *pTextureEntity, const float *v1, const float *v2 ) +{ + trace_t trace; + + if( IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2] )) + Host_Error( "SV_TraceTexture: NAN errors detected ('%f %f %f', '%f %f %f'\n", v1[0], v1[1], v1[2], v2[0], v2[1], v2[2] ); + + trace = SV_Trace( v1, vec3_origin, vec3_origin, v2, MOVE_NOMONSTERS, NULL, SV_ContentsMask( pTextureEntity )); + + if( trace.surface ) + return trace.surface->name; + return NULL; +} + +/* +============= +pfnGetAimVector + +FIXME: use speed for reduce aiming accuracy +============= +*/ +void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn ) +{ + edict_t *check, *bestent; + vec3_t start, dir, end, bestdir; + float dist, bestdist; + bool fNoFriendlyFire; + int i, j; + trace_t tr; + + // these vairable defined in server.dll + fNoFriendlyFire = Cvar_VariableValue( "mp_friendlyfire" ); + VectorCopy( svs.globals->v_forward, rgflReturn ); // assume failure if it returns early + + if( ent == svg.edicts ) return; + if( ent->free ) + { + MsgDev( D_ERROR, "SV_GetAimVector: can't aiming at free entity\n" ); + return; + } + + VectorCopy( ent->v.origin, start ); + start[2] += 20; + + // try sending a trace straight + VectorCopy( svs.globals->v_forward, dir ); + VectorMA( start, 2048, dir, end ); + tr = SV_Trace( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, -1 ); + + if( tr.ent && (tr.ent->v.takedamage == DAMAGE_AIM && fNoFriendlyFire || ent->v.team <= 0 || ent->v.team != tr.ent->v.team )) + { + VectorCopy( svs.globals->v_forward, rgflReturn ); + return; + } + + // try all possible entities + VectorCopy( dir, bestdir ); + bestdist = 0.5f; + bestent = NULL; + + check = svg.edicts + 1; // start at first client + for( i = 1; i < svs.globals->numEntities; i++, check++ ) + { + if( check->v.takedamage != DAMAGE_AIM ) continue; + if( check == ent ) continue; + if( fNoFriendlyFire && ent->v.team > 0 && ent->v.team == check->v.team ) + continue; // don't aim at teammate + for( j = 0; j < 3; j++ ) + end[j] = check->v.origin[j] + 0.5 * (check->v.mins[j] + check->v.maxs[j]); + VectorSubtract( end, start, dir ); + VectorNormalize( dir ); + dist = DotProduct( dir, svs.globals->v_forward ); + if( dist < bestdist ) continue; // to far to turn + tr = SV_Trace( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, -1 ); + if( tr.ent == check ) + { + // can shoot at this one + bestdist = dist; + bestent = check; + } + } + + if( bestent ) + { + VectorSubtract( bestent->v.origin, ent->v.origin, dir ); + dist = DotProduct( dir, svs.globals->v_forward ); + VectorScale( svs.globals->v_forward, dist, end ); + end[2] = dir[2]; + VectorNormalize( end ); + VectorCopy( end, rgflReturn ); + } + else VectorCopy( bestdir, rgflReturn ); +} + +/* +========= +pfnServerCommand + +========= +*/ +void pfnServerCommand( const char* str ) +{ + Cbuf_AddText( str ); +} + +/* +========= +pfnServerExecute + +========= +*/ +void pfnServerExecute( void ) +{ + Cbuf_Execute(); +} + +/* +========= +pfnClientCommand + +========= +*/ +void pfnClientCommand( edict_t* pEdict, char* szFmt, ... ) +{ + sv_client_t *client; + string buffer; + va_list args; + int i; + + i = NUM_FOR_EDICT( pEdict ); + if( sv.state != ss_active || i < 0 || i >= Host_MaxClients() || svs.clients[i].state != cs_spawned ) + { + MsgDev( D_ERROR, "SV_ClientCommand: client/server is not active!\n" ); + return; + } + + client = svs.clients + i; + va_start( args, szFmt ); + com.vsnprintf( buffer, MAX_STRING, szFmt, args ); + va_end( args ); + + + MSG_WriteByte( &client->netchan.message, svc_stufftext ); + MSG_WriteString( &client->netchan.message, buffer ); + MSG_Send( MSG_ONE_R, NULL, client->edict ); +} + +/* +================= +pfnParticleEffect + +================= +*/ +void pfnParticleEffect( const float *org, const float *dir, float color, float count ) +{ + SV_StartParticle( org, dir, (int)color, (int)count ); +} + +/* +=============== +pfnLightStyle + +=============== +*/ +void pfnLightStyle( int style, char* val ) +{ + if((uint)style >= MAX_LIGHTSTYLES ) + Host_Error( "SV_LightStyle: style: %i >= %d", style, MAX_LIGHTSTYLES ); + SV_ConfigString( CS_LIGHTSTYLES + style, val ); +} + +/* +================= +pfnDecalIndex + +register decal shader on client +================= +*/ +int pfnDecalIndex( const char *m ) +{ + return SV_DecalIndex( m ); +} + +/* +============= +pfnPointContents + +============= +*/ +int pfnPointContents( const float *rgflVector ) +{ + return SV_PointContents( rgflVector ); +} + +/* +============= +pfnMessageBegin + +============= +*/ +void pfnMessageBegin( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ) +{ + // some users can send message with engine index + // reduce number to avoid overflow problems or cheating + svg.msg_index = bound( svc_bad, msg_type, svc_nop ); + + MSG_Begin( svg.msg_index ); + + // save message destination + if( pOrigin ) VectorCopy( pOrigin, svs.msg_org ); + else VectorClear( svs.msg_org ); + svg.msg_leftsize = svg.msg_sizes[msg_type]; + svs.msg_dest = msg_dest; + svs.msg_ent = ed; +} + +/* +============= +pfnMessageEnd + +============= +*/ +void pfnMessageEnd( void ) +{ + if( svg.msg_leftsize != 0xFFFF && svg.msg_leftsize != 0 ) + { + const char *name = sv.configstrings[CS_USER_MESSAGES + svg.msg_index]; + int size = svg.msg_sizes[svg.msg_index]; + int realsize = size - svg.msg_leftsize; + + MsgDev( D_ERROR, "SV_Message: %s expected %i bytes, it written %i\n", name, size, realsize ); + MSG_Clear( &sv.multicast ); + return; + } + + svs.msg_dest = bound( MSG_ONE, svs.msg_dest, MSG_PVS_R ); + MSG_Send( svs.msg_dest, svs.msg_org, svs.msg_ent ); +} + +/* +============= +pfnWriteByte + +============= +*/ +void pfnWriteByte( int iValue ) +{ + MSG_WriteByte( &sv.multicast, (int)iValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize--; +} + +/* +============= +pfnWriteChar + +============= +*/ +void pfnWriteChar( int iValue ) +{ + MSG_WriteChar( &sv.multicast, (int)iValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize--; +} + +/* +============= +pfnWriteShort + +============= +*/ +void pfnWriteShort( int iValue ) +{ + MSG_WriteShort( &sv.multicast, (int)iValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize -= 2; +} + +/* +============= +pfnWriteLong + +============= +*/ +void pfnWriteLong( int iValue ) +{ + MSG_WriteLong( &sv.multicast, (int)iValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize -= 4; +} + +/* +============= +pfnWriteAngle + +============= +*/ +void pfnWriteAngle( float flValue ) +{ + MSG_WriteAngle32( &sv.multicast, flValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize -= 4; +} + +/* +============= +pfnWriteCoord + +============= +*/ +void pfnWriteCoord( float flValue ) +{ + MSG_WriteCoord32( &sv.multicast, flValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize -= 4; +} + +/* +============= +pfnWriteString + +============= +*/ +void pfnWriteString( const char *sz ) +{ + int cur_size = sv.multicast.cursize; + int total_size; + + MSG_WriteString( &sv.multicast, sz ); + total_size = sv.multicast.cursize - cur_size; + + // some messages with constant strings can be marked as known sized + if( svg.msg_leftsize != 0xFFFF ) + svg.msg_leftsize -= total_size; +} + +/* +============= +pfnWriteEntity + +============= +*/ +void pfnWriteEntity( int iValue ) +{ + if( iValue < 0 || iValue > svs.globals->numEntities ) + Host_Error( "MSG_WriteEntity: invalid entnumber %d\n", iValue ); + MSG_WriteShort( &sv.multicast, iValue ); + if( svg.msg_leftsize != 0xFFFF ) svg.msg_leftsize -= 2; +} + +/* +============= +pfnCVarRegister + +============= +*/ +void pfnCVarRegister( const char *name, const char *value, int flags, const char *desc ) +{ + // FIXME: translate server.dll flags to real cvar flags + Cvar_Get( name, value, flags, desc ); +} + +/* +============= +pfnCVarGetFloat + +============= +*/ +float pfnCVarGetFloat( const char *szVarName ) +{ + return Cvar_VariableValue( szVarName ); +} + +/* +============= +pfnCVarGetString + +============= +*/ +const char* pfnCVarGetString( const char *szVarName ) +{ + return Cvar_VariableString( szVarName ); +} + +/* +============= +pfnCVarSetFloat + +============= +*/ +void pfnCVarSetFloat( const char *szVarName, float flValue ) +{ + Cvar_SetValue( szVarName, flValue ); +} + +/* +============= +pfnCVarSetString + +============= +*/ +void pfnCVarSetString( const char *szVarName, const char *szValue ) +{ + Cvar_Set( szVarName, szValue ); +} + +/* +============= +pfnAlertMessage + +============= +*/ +void pfnAlertMessage( ALERT_TYPE level, char *szFmt, ... ) +{ + char buffer[2048]; // must support > 1k messages + va_list args; + + va_start( args, szFmt ); + com.vsnprintf( buffer, 2048, szFmt, args ); + va_end( args ); + + // FIXME: implement message filter + com.print( buffer ); +} + +/* +============= +pfnPvAllocEntPrivateData + +============= +*/ +void *pfnPvAllocEntPrivateData( edict_t *pEdict, long cb ) +{ + Msg("Alloc %s\n", memprint( cb )); + Com_Assert( pEdict == NULL ); + + // to avoid multiple alloc + pEdict->pvServerData = (void *)Mem_Alloc( svs.private, cb ); + + return pEdict->pvServerData; +} + +/* +============= +pfnFreeEntPrivateData + +============= +*/ +void pfnFreeEntPrivateData( edict_t *pEdict ) +{ + if( pEdict->pvServerData ) Mem_Free( pEdict->pvServerData ); + pEdict->pvServerData = NULL; // freed +} + +/* +============= +pfnAllocString + +FIXME: make work +============= +*/ +string_t pfnAllocString( const char *szValue ) +{ + return ED_NewString( szValue, svs.stringpool ) - svs.globals->pStringBase; +} + +/* +============= +pfnPEntityOfEntOffset + +FIXME: this is correct ? +============= +*/ +edict_t* pfnPEntityOfEntOffset( int iEntOffset ) +{ + return svg.edicts + iEntOffset; +} + +/* +============= +pfnEntOffsetOfPEntity + +FIXME: this is correct ? +============= +*/ +int pfnEntOffsetOfPEntity( const edict_t *pEdict ) +{ + return pEdict - svg.edicts; +} + +/* +============= +pfnIndexOfEdict + +============= +*/ +int pfnIndexOfEdict( const edict_t *pEdict ) +{ + return pEdict - svg.edicts; +} + +/* +============= +pfnPEntityOfEntIndex + +============= +*/ +edict_t* pfnPEntityOfEntIndex( int iEntIndex ) +{ + return svg.edicts + iEntIndex; +} + +/* +============= +pfnFindEntityByVars + +slow linear brute force +============= +*/ +edict_t* pfnFindEntityByVars( entvars_t* pvars ) +{ + edict_t *e = svg.edicts; + int i; + + for( i = 0; i < svs.globals->numEntities; i++, e++ ) + { + if( e->free ) continue; + if( !memcmp( &e->v, pvars, sizeof( entvars_t ))) + return e; + } + return NULL; +} + +/* +============= +pfnGetModelPtr + +returns pointer to a studiomodel +============= +*/ +void* pfnGetModelPtr( edict_t* pEdict ) +{ + cmodel_t *mod; + + mod = pe->RegisterModel( sv.configstrings[CS_MODELS + pEdict->v.modelindex] ); + + if( !mod ) return NULL; + return mod->extradata; +} + +/* +============= +pfnRegUserMsg + +============= +*/ +int pfnRegUserMsg( const char *pszName, int iSize ) +{ + // register message first + int msg_index; + + msg_index = SV_UserMessageIndex( pszName ); + if( iSize == -1 ) + svg.msg_sizes[msg_index] = 0xFFFF; + else svg.msg_sizes[msg_index] = iSize; + + return msg_index; +} + +/* +============= +pfnAnimationAutomove + +============= +*/ +void pfnAnimationAutomove( const edict_t* pEdict, float flTime ) +{ + // FIXME: implement +} + +/* +============= +pfnGetBonePosition + +============= +*/ +void pfnGetBonePosition( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ) +{ + // FIXME: implement +} + +/* +============= +pfnFunctionFromName + +============= +*/ +dword pfnFunctionFromName( const char *pName ) +{ + int i, index; + + for( i = 0; i < svg.num_ordinals; i++ ) + { + if( !com.strcmp( pName, svg.names[i] )) + { + index = svg.ordinals[i]; + return svg.funcs[index] + svg.funcBase; + } + } + + // couldn't find the function name to return address + return 0; +} + +/* +============= +pfnNameForFunction + +============= +*/ +const char *pfnNameForFunction( dword function ) +{ + int i, index; + + for( i = 0; i < svg.num_ordinals; i++ ) + { + index = svg.ordinals[i]; + + if((function - svg.funcBase) == svg.funcs[index] ) + return svg.names[i]; + } + // couldn't find the function address to return name + return NULL; +} + +/* +============= +pfnClientPrintf + +============= +*/ +void pfnClientPrintf( edict_t* pEdict, int ptype, const char *szMsg ) +{ + sv_client_t *client; + int num; + + num = NUM_FOR_EDICT( pEdict ); + if( num < 1 || num > svs.globals->maxClients || svs.clients[num - 1].state != cs_spawned ) + { + MsgDev( D_WARN, "SV_ClientPrintf: tired print to a non-client!\n" ); + return; + } + client = svs.clients + num - 1; + + switch( ptype ) + { + case PRINT_CONSOLE: + SV_ClientPrintf (client, PRINT_CONSOLE, (char *)szMsg ); + break; + case PRINT_CENTER: + MSG_Begin( svc_centerprint ); + MSG_WriteString( &sv.multicast, szMsg ); + MSG_Send( MSG_ONE_R, NULL, pEdict ); + break; + case PRINT_CHAT: + SV_ClientPrintf( client, PRINT_CHAT, (char *)szMsg ); + break; + default: + MsgDev( D_ERROR, "SV_ClientPrintf: invalid destination\n" ); + break; + } +} + +/* +============= +pfnServerPrint + +============= +*/ +void pfnServerPrint( const char *szMsg ) +{ + if( sv.state == ss_loading ) + { + // while loading in-progress we can sending message + com.print( szMsg ); // only for local client + } + else SV_BroadcastPrintf( PRINT_CONSOLE, (char *)szMsg ); +} + +/* +============= +pfnAreaPortal + +changes area portal state +============= +*/ +void pfnAreaPortal( edict_t *pEdict, bool enable ) +{ + if( pEdict == svg.edicts ) return; + if( pEdict->free ) + { + MsgDev( D_ERROR, "SV_AreaPortal: can't modify free entity\n" ); + return; + } + pe->SetAreaPortalState( pEdict->v.skin, enable ); +} + +/* +============= +pfnCmd_Args + +============= +*/ +const char *pfnCmd_Args( void ) +{ + return Cmd_Args(); +} + +/* +============= +pfnCmd_Argv + +============= +*/ +const char *pfnCmd_Argv( int argc ) +{ + if( argc >= 0 && argc < Cmd_Argc()) + return Cmd_Argv( argc ); + return ""; +} + +/* +============= +pfnCmd_Argc + +============= +*/ +int pfnCmd_Argc( void ) +{ + return Cmd_Argc(); +} + +/* +============= +pfnGetAttachment + +============= +*/ +void pfnGetAttachment( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ) +{ + // FIXME: implement +} + +/* +============= +pfnCRC_Init + +============= +*/ +void pfnCRC_Init( word *pulCRC ) +{ + CRC_Init( pulCRC ); +} + +/* +============= +pfnCRC_ProcessBuffer + +============= +*/ +void pfnCRC_ProcessBuffer( word *pulCRC, void *p, int len ) +{ + byte *start = (byte *)p; + + while( len-- ) CRC_ProcessByte( pulCRC, *start++ ); +} + +/* +============= +pfnCRC_Final + +============= +*/ +word pfnCRC_Final( word pulCRC ) +{ + return pulCRC ^ 0x0000; +} + +/* +============= +pfnRandomLong + +============= +*/ +long pfnRandomLong( long lLow, long lHigh ) +{ + return Com_RandomLong( lLow, lHigh ); +} + +/* +============= +pfnRandomFloat + +============= +*/ +float pfnRandomFloat( float flLow, float flHigh ) +{ + return Com_RandomFloat( flLow, flHigh ); +} + +/* +============= +pfnSetView + +============= +*/ +void pfnSetView( const edict_t *pClient, const edict_t *pViewent ) +{ + // FIXME: implement +} + +/* +============= +pfnCrosshairAngle + +============= +*/ +void pfnCrosshairAngle( const edict_t *pClient, float pitch, float yaw ) +{ + // FIXME: implement +} + +/* +============= +pfnLoadFile + +============= +*/ +byte* pfnLoadFile( const char *filename, int *pLength ) +{ + return FS_LoadFile( filename, pLength ); +} + +/* +============= +pfnFreeFile + +============= +*/ +void pfnFreeFile( void *buffer ) +{ + if( buffer ) Mem_Free( buffer ); +} + +/* +============= +pfnCompareFileTime + +============= +*/ +int pfnCompareFileTime( const char *filename1, const char *filename2, int *iCompare ) +{ + int time1 = FS_FileTime( filename1 ); + int time2 = FS_FileTime( filename2 ); + + if( iCompare ) + { + if( time1 > time2 ) + *iCompare = 1; + else if( time1 < time2 ) + *iCompare = -1; + else *iCompare = 0; + } + return (time1 != time2); +} + +/* +============= +pfnGetGameDir + +============= +*/ +void pfnGetGameDir( char *szGetGameDir ) +{ + // FIXME: potentially crashpoint + com.strcpy( szGetGameDir, FS_Gamedir ); +} + +/* +============= +pfnGetGameDir + +============= +*/ +void pfnStaticDecal( const float *origin, int decalIndex, int entityIndex, int modelIndex ) +{ + // FIXME: implement +} + +/* +============= +pfnPrecacheGeneric + +can be used for precache scripts +============= +*/ +int pfnPrecacheGeneric( const char* s ) +{ + // FIXME: implement + return 0; +} + +/* +============= +pfnIsDedicatedServer + +============= +*/ +int pfnIsDedicatedServer( void ) +{ + return (host.type == HOST_DEDICATED); +} + +/* +============= +pfnIsMapValid + +vaild map must contain one info_player_deatchmatch +============= +*/ +int pfnIsMapValid( char *filename ) +{ + wfile_t *wad; + dheader_t *hdr; + bool valid; + + wad = WAD_Open( filename, "rb" ); + if( !wad ) return false; + + hdr = (dheader_t *)WAD_Read( wad, LUMP_MAPINFO, NULL, TYPE_BINDATA ); + valid = (LittleLong( hdr->flags ) & MAP_DEATHMATCH) ? true : false; + WAD_Close( wad ); + + return valid; +} + +/* +============= +pfnInfo_RemoveKey + +============= +*/ +void pfnInfo_RemoveKey( char *s, char *key ) +{ + Info_RemoveKey( s, key ); +} + +/* +============= +pfnInfoKeyValue + +============= +*/ +char *pfnInfoKeyValue( char *infobuffer, char *key ) +{ + return Info_ValueForKey( infobuffer, key ); +} + +/* +============= +pfnSetKeyValue + +============= +*/ +void pfnSetKeyValue( char *infobuffer, char *key, char *value ) +{ + Info_SetValueForKey( infobuffer, key, value ); +} + +/* +============= +pfnGetInfoKeyBuffer + +============= +*/ +char *pfnGetInfoKeyBuffer( edict_t *e ) +{ + int index; + + index = NUM_FOR_EDICT( e ); + if( index > 0 && index < svs.globals->numClients ) + return e->pvEngineData->client->userinfo; + return Cvar_Serverinfo(); // otherwise return ServerInfo +} + +/* +============= +pfnSetClientKeyValue + +============= +*/ +void pfnSetClientKeyValue( int clientIndex, char *infobuffer, char *key, char *value ) +{ + if( clientIndex > 0 && clientIndex < svs.globals->numClients ) + { + sv_client_t *client = svs.clients + clientIndex; + Info_SetValueForKey( client->userinfo, key, value ); + } +} + +/* +============= +pfnSetSkybox + +============= +*/ +void pfnSetSkybox( const char *name ) +{ + SV_ConfigString( CS_SKYNAME, name ); +} + +/* +============= +pfnPlayMusic + +============= +*/ +void pfnPlayMusic( const char *trackname, int flags ) +{ + SV_ConfigString( CS_BACKGROUND_TRACK, trackname ); +} + +/* +============= +pfnDropClient + +============= +*/ +void pfnDropClient( int clientIndex ) +{ + if( clientIndex < 0 || clientIndex >= svs.globals->maxClients ) + { + MsgDev( D_ERROR, "SV_DropClient: not a client\n" ); + return; + } + if( svs.clients[clientIndex].state != cs_spawned ) + { + MsgDev( D_ERROR, "SV_DropClient: that client slot is not connected\n" ); + return; + } + SV_DropClient( svs.clients + clientIndex ); +} + +// engine callbacks +static enginefuncs_t gEngfuncs = +{ + sizeof( enginefuncs_t ), + pfnPrecacheModel, + pfnPrecacheSound, + pfnSetModel, + pfnModelIndex, + pfnModelFrames, + pfnSetSize, + pfnChangeLevel, + pfnVecToYaw, + pfnVecToAngles, + pfnMoveToOrigin, + pfnChangeYaw, + pfnChangePitch, + pfnFindEntityByString, + pfnGetEntityIllum, + pfnFindEntityInSphere, + pfnFindClientInPVS, + pfnFindClientInPHS, + pfnEntitiesInPVS, + pfnEntitiesInPHS, + pfnMakeVectors, + pfnAngleVectors, + pfnCreateEntity, + pfnRemoveEntity, + pfnCreateNamedEntity, + pfnMakeStatic, + pfnEntIsOnFloor, + pfnDropToFloor, + pfnWalkMove, + pfnSetOrigin, + pfnSetAngles, + pfnEmitSound, + pfnEmitAmbientSound, + pfnTraceLine, + pfnTraceToss, + pfnTraceHull, + pfnTraceModel, + pfnTraceTexture, + pfnGetAimVector, + pfnServerCommand, + pfnServerExecute, + pfnClientCommand, + pfnParticleEffect, + pfnLightStyle, + pfnDecalIndex, + pfnPointContents, + pfnMessageBegin, + pfnMessageEnd, + pfnWriteByte, + pfnWriteChar, + pfnWriteShort, + pfnWriteLong, + pfnWriteAngle, + pfnWriteCoord, + pfnWriteString, + pfnWriteEntity, + pfnCVarRegister, + pfnCVarGetFloat, + pfnCVarGetString, + pfnCVarSetFloat, + pfnCVarSetString, + pfnAlertMessage, + pfnPvAllocEntPrivateData, + pfnFreeEntPrivateData, + pfnAllocString, + pfnPEntityOfEntOffset, + pfnEntOffsetOfPEntity, + pfnIndexOfEdict, + pfnPEntityOfEntIndex, + pfnFindEntityByVars, + pfnGetModelPtr, + pfnRegUserMsg, + pfnAnimationAutomove, + pfnGetBonePosition, + pfnFunctionFromName, + pfnNameForFunction, + pfnClientPrintf, + pfnServerPrint, + pfnAreaPortal, + pfnCmd_Args, + pfnCmd_Argv, + pfnCmd_Argc, + pfnGetAttachment, + pfnCRC_Init, + pfnCRC_ProcessBuffer, + pfnCRC_Final, + pfnRandomLong, + pfnRandomFloat, + pfnSetView, + pfnCrosshairAngle, + pfnLoadFile, + pfnFreeFile, + pfnCompareFileTime, + pfnGetGameDir, + pfnStaticDecal, + pfnPrecacheGeneric, + pfnIsDedicatedServer, + pfnIsMapValid, + pfnInfo_RemoveKey, + pfnInfoKeyValue, + pfnSetKeyValue, + pfnGetInfoKeyBuffer, + pfnSetClientKeyValue, + pfnSetSkybox, + pfnPlayMusic, + pfnDropClient +}; + +/* +==================== +SV_ParseEdict + +Parses an edict out of the given string, returning the new position +ed should be a properly initialized empty edict. +==================== +*/ +bool SV_ParseEdict( script_t *script, edict_t *ent ) +{ + KeyValueData pkvd[256]; // per one entity + int i, numpairs = 0; + const char *classname = NULL; + LINK_ENTITY_FUNC SpawnEdict; + token_t token; + + // go through all the dictionary pairs + while( 1 ) + { + string keyname; + + // parse key + if( !Com_ReadToken( script, SC_ALLOW_NEWLINES, &token )) + Host_Error( "SV_ParseEdict: EOF without closing brace\n" ); + if( token.string[0] == '}' ) break; // end of desc + com.strncpy( keyname, token.string, sizeof( keyname ) - 1 ); + + // parse value + if( !Com_ReadToken( script, SC_ALLOW_PATHNAMES2, &token )) + Host_Error( "SV_ParseEdict: EOF without closing brace\n" ); + + if( token.string[0] == '}' ) + Host_Error( "SV_ParseEdict: closing brace without data\n" ); + + // keynames with a leading underscore are used for utility comments, + // and are immediately discarded by engine + if( keyname[0] == '_' ) continue; + + // create keyvalue strings + pkvd[numpairs].szClassName = (char *)classname; // unknown at this moment + pkvd[numpairs].szKeyName = ED_NewString( keyname, svs.stringpool ); + pkvd[numpairs].szValue = ED_NewString( token.string, svs.stringpool ); + pkvd[numpairs].fHandled = false; + + if( !com.strcmp( keyname, "classname" ) && classname == NULL ) + classname = pkvd[numpairs].szValue; + if( ++numpairs >= 256 ) break; + } + + // allocate edict private memory (passed by dlls) + SpawnEdict = (LINK_ENTITY_FUNC)Sys_GetProcAddress( svs.game, classname ); + if( !SpawnEdict ) + { + MsgDev( D_ERROR, "No spawn function for %s\n", classname ); + return false; + } + + SpawnEdict( NULL ); // same as ED_Alloc + Com_Assert( 1 ); + + // apply classname to keyvalue containers and parse fields + for( i = 0; i < numpairs; i++ ) + { + if( pkvd[i].fHandled ) continue; + pkvd[i].szClassName = (char *)classname; + svs.dllFuncs.pfnKeyValue( ent, &pkvd[i] ); + } + + // initialize network classname + ent->pvEngineData->s.classname = SV_ClassIndex( classname ); + return true; +} + +/* +================ +SV_LoadFromFile + +The entities are directly placed in the array, rather than allocated with +ED_Alloc, because otherwise an error loading the map would have entity +number references out of order. + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. +================ +*/ +void SV_LoadFromFile( script_t *entities ) +{ + token_t token; + int inhibited, spawned, died; + edict_t *ent = svg.edicts; + + inhibited = 0; + spawned = 0; + died = 0; + + // parse ents + while( Com_ReadToken( entities, SC_ALLOW_NEWLINES, &token )) + { + if( token.string[0] != '{' ) + Host_Error( "SV_LoadFromFile: found %s when expecting {\n", token.string ); + + if( !SV_ParseEdict( entities, ent )) + continue; + spawned++; + if( ent->free ) died++; + } + MsgDev( D_INFO, "%i entities inhibited\n", inhibited ); +} + +/* +============== +SpawnEntities + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. +============== +*/ +void SV_SpawnEntities( const char *mapname, script_t *entities ) +{ + edict_t *ent; + int i; + + MsgDev( D_NOTE, "SV_SpawnEntities()\n" ); + + ent = svg.edicts; + Mem_Set( &ent->v, 0, sizeof( entvars_t )); + ent->v.model = pfnAllocString( sv.configstrings[CS_MODELS] ); + ent->v.modelindex = 1; // world model + ent->v.solid = SOLID_BSP; + ent->v.movetype = MOVETYPE_PUSH; + ent->free = false; + + SV_ConfigString( CS_MAXCLIENTS, va("%i", Host_MaxClients())); + svs.globals->mapname = pfnAllocString( sv.name ); + svs.globals->time = sv.time; + + // spawn the rest of the entities on the map + SV_LoadFromFile( entities ); + + // set client fields on player ents + /* + for( i = 0; i < svs.globals->maxClients; i++ ) + { + // setup all clients + ent = EDICT_NUM( i + 1 ); + ent->pvEngineData->client = svs.clients + i; + } + */ +} + +void SV_UnloadProgs( void ) +{ + Sys_FreeNameFuncGlobals(); + + if( svs.game && svs.game->link ) + { + Sys_FreeLibrary( svs.game ); + svs.game->link = NULL; + } + + Mem_FreePool( &svs.mempool ); + Mem_FreePool( &svs.stringpool ); + Mem_FreePool( &svs.private ); +} + +bool SV_LoadProgs( const char *name ) +{ + static APIFUNCTION GetEntityAPI; + static GIVEFNPTRSTODLL GiveFnptrsToDll; + static globalvars_t gpGlobals; + edict_t *e; + int i; + + if( !svs.game ) svs.game = Z_Malloc( sizeof( dll_info_t )); + if( svs.game->link ) SV_UnloadProgs(); + + // fill it in + svs.globals = &gpGlobals; + svs.game->name = copystring( va( "%s/bin/%s.dll", FS_Gamedir, name )); + svs.game->crash = false; + svs.mempool = Mem_AllocPool( "Server Edicts Zone" ); + svs.stringpool = Mem_AllocPool( "Server Strings Zone" ); + svs.private = Mem_AllocPool( "Server Private Zone" ); + + if( !Sys_LoadLibrary( svs.game )) + return false; + + GetEntityAPI = (APIFUNCTION)Sys_GetProcAddress( svs.game, "GetEntityAPI" ); + + if( !GetEntityAPI ) + { + MsgDev( D_ERROR, "SV_LoadProgs: failed to get address of GetEntityAPI proc\n" ); + return false; + } + + GiveFnptrsToDll = (GIVEFNPTRSTODLL)Sys_GetProcAddress( svs.game, "GiveFnptrsToDll" ); + + if( !GiveFnptrsToDll ) + { + // can't find GiveFnptrsToDll! + MsgDev( D_ERROR, "SV_LoadProgs: failed to get address of GiveFnptrsToDll proc\n" ); + return false; + } + + if( !Sys_LoadSymbols( va( "bin/%s.dll", name ))) + return false; + + GiveFnptrsToDll( &gEngfuncs, svs.globals ); + + if( !GetEntityAPI( &svs.dllFuncs, INTERFACE_VERSION )) + { + MsgDev( D_ERROR, "SV_LoadProgs: couldn't get entity API\n" ); + return false; + } + + // get pointer as really static object + svs.globals->pStringBase = (const char *)&svs; + svs.globals->maxEntities = host.max_edicts; + svs.globals->maxClients = Host_MaxClients(); + svg.edicts = Mem_Alloc( svs.mempool, sizeof( edict_t ) * svs.globals->maxEntities ); + svs.globals->numClients = svs.globals->numEntities = 0; + for( i = 0, e = svg.edicts; i < svs.globals->maxEntities; i++, e++ ) + e->free = true; // mark all edicts as freed + + // initialize game + svs.dllFuncs.pfnGameInit(); + + return true; +} \ No newline at end of file diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 016b5d06..d7d66364 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -22,6 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "server.h" server_static_t svs; // persistant server info +game_static_t svg; // persistant game info server_t sv; // local server /* @@ -62,19 +63,29 @@ int SV_FindIndex (const char *name, int start, int end, bool create) } -int SV_ModelIndex (const char *name) +int SV_ModelIndex( const char *name ) { - return SV_FindIndex (name, CS_MODELS, MAX_MODELS, true); + return SV_FindIndex( name, CS_MODELS, MAX_MODELS, true ); } -int SV_SoundIndex (const char *name) +int SV_SoundIndex( const char *name ) { - return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true); + return SV_FindIndex (name, CS_SOUNDS, MAX_SOUNDS, true ); +} + +int SV_UserMessageIndex( const char *name ) +{ + return SV_FindIndex (name, CS_USER_MESSAGES, MAX_USER_MESSAGES, true ); +} + +int SV_DecalIndex( const char *name ) +{ + return SV_FindIndex( name, CS_DECALS, MAX_DECALS, true ); } int SV_ClassIndex( const char *name ) { - return SV_FindIndex (name, CS_CLASSNAMES, MAX_CLASSNAMES, true); + return SV_FindIndex( name, CS_CLASSNAMES, MAX_CLASSNAMES, true ); } /* ================ @@ -90,18 +101,18 @@ void SV_CreateBaseline( void ) edict_t *svent; int entnum; - for( entnum = 1; entnum < prog->num_edicts ; entnum++ ) + for( entnum = 1; entnum < svs.globals->numEntities; entnum++ ) { - svent = PRVM_EDICT_NUM( entnum ); - if( svent->priv.sv->free ) continue; - if( !svent->progs.sv->modelindex && !svent->priv.sv->s.soundindex && !svent->progs.sv->effects ) + svent = EDICT_NUM( entnum ); + if( svent->free ) continue; + if( !svent->v.modelindex && !svent->pvEngineData->s.soundindex && !svent->v.effects ) continue; - svent->priv.sv->serialnumber = entnum; + svent->serialnumber = entnum; // take current state as baseline SV_UpdateEntityState( svent ); - svs.baselines[entnum] = svent->priv.sv->s; + svs.baselines[entnum] = svent->pvEngineData->s; } } @@ -155,8 +166,6 @@ void SV_SpawnServer( const char *server, const char *savename ) MSG_Init( &sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); com.strcpy( sv.name, server ); - SV_VM_Begin(); - // leave slots at start for clients only for( i = 0; i < Host_MaxClients(); i++ ) { @@ -198,7 +207,7 @@ void SV_SpawnServer( const char *server, const char *savename ) SV_CheckForSavegame( savename ); if( sv.loadgame ) SV_ReadLevelFile( savename ); - else SV_SpawnEntities( sv.name, pe->GetEntityString()); + else SV_SpawnEntities( sv.name, pe->GetEntityScript()); // run two frames to allow everything to settle for( i = 0; i < 2; i++ ) @@ -215,16 +224,15 @@ void SV_SpawnServer( const char *server, const char *savename ) SV_CreateBaseline(); // classify edicts for quick network sorting - for( i = 0; i < prog->num_edicts; i++ ) + for( i = 0; i < svs.globals->numEntities; i++ ) { - edict_t *ent = PRVM_EDICT_NUM( i ); + edict_t *ent = EDICT_NUM( i ); SV_ClassifyEdict( ent ); } // set serverinfo variable Cvar_FullSet( "mapname", sv.name, CVAR_SERVERINFO|CVAR_INIT ); pe->EndRegistration(); // free unused models - SV_VM_End(); } /* @@ -299,16 +307,21 @@ void SV_InitGame( void ) NET_StringToAdr( idmaster, &master_adr[0] ); // init game - SV_InitServerProgs(); - - SV_VM_Begin(); + if(!SV_LoadProgs( "server" )) + { + Host_Error( "SV_InitGame: can't initialize server.dll\n" ); + } for( i = 0; i < Host_MaxClients(); i++ ) { - ent = PRVM_EDICT_NUM( i + 1 ); - ent->priv.sv->serialnumber = i + 1; + ent = EDICT_NUM( i + 1 ); + ent->serialnumber = i + 1; svs.clients[i].edict = ent; - Mem_Set (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); + Mem_Set( &svs.clients[i].lastcmd, 0, sizeof( svs.clients[i].lastcmd )); } - SV_VM_End(); +} + +bool SV_Active( void ) +{ + return svs.initialized; } \ No newline at end of file diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index b2d1608a..d17d049b 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -71,7 +71,7 @@ void SV_CalcPings( void ) else cl->ping = total / count; // let the game dll know about the ping - cl->edict->priv.sv->client->ping = cl->ping; + cl->edict->pvEngineData->client->ping = cl->ping; } } @@ -88,8 +88,6 @@ void SV_PacketEvent( netadr_t from, sizebuf_t *msg ) if( !svs.initialized ) return; - SV_VM_Begin(); - // check for connectionless packet (0xffffffff) first if( msg->cursize >= 4 && *(int *)msg->data == -1 ) { @@ -127,7 +125,6 @@ void SV_PacketEvent( netadr_t from, sizebuf_t *msg ) break; } if( i != Host_MaxClients()) return; - SV_VM_End(); } /* @@ -238,9 +235,6 @@ void SV_Frame( dword time ) return; } - // setup the VM frame - SV_VM_Begin(); - // update ping based on the last known frame from all clients SV_CalcPings (); @@ -252,9 +246,6 @@ void SV_Frame( dword time ) // send a heartbeat to the master if needed Master_Heartbeat (); - - // end the server VM frame - SV_VM_End(); } //============================================================================ @@ -337,7 +328,7 @@ void Master_Shutdown (void) =============== SV_Init -Only called at xash.exe startup, not for each game +Only called at startup, not for each game =============== */ void SV_Init( void ) @@ -438,19 +429,19 @@ void SV_Shutdown( bool reconnect ) if( !svs.initialized ) return; MsgDev( D_INFO, "SV_Shutdown: %s\n", host.finalmsg ); - if( svs.clients ) SV_FinalMessage( host.finalmsg, reconnect); + if( svs.clients ) SV_FinalMessage( host.finalmsg, reconnect ); Master_Shutdown(); - SV_FreeServerProgs(); + SV_UnloadProgs(); // free current level - memset( &sv, 0, sizeof( sv )); + Mem_Set( &sv, 0, sizeof( sv )); Host_SetServerState( sv.state ); // free server static data if( svs.clients ) Mem_Free( svs.clients ); if( svs.baselines ) Mem_Free( svs.baselines ); if( svs.client_entities ) Mem_Free( svs.client_entities ); - memset( &svs, 0, sizeof( svs )); + Mem_Set( &svs, 0, sizeof( svs )); } diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 181fda3b..2067f4e7 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -25,8 +25,8 @@ bool SV_CheckBottom( edict_t *ent ) trace_t trace; int x, y; - VectorAdd (ent->progs.sv->origin, ent->progs.sv->mins, mins); - VectorAdd (ent->progs.sv->origin, ent->progs.sv->maxs, maxs); + VectorAdd (ent->v.origin, ent->v.mins, mins); + VectorAdd (ent->v.origin, ent->v.maxs, maxs); // if all of the points under the corners are solid world, don't bother // with the tougher checks @@ -96,40 +96,40 @@ bool SV_movestep( edict_t *ent, vec3_t move, bool relink, bool noenemy, bool set int i; // try the move - VectorCopy (ent->progs.sv->origin, oldorg); - VectorAdd (ent->progs.sv->origin, move, neworg); + VectorCopy (ent->v.origin, oldorg); + VectorAdd (ent->v.origin, move, neworg); // flying monsters don't step up - if((int)ent->progs.sv->aiflags & (AI_SWIM|AI_FLY)) + if((int)ent->v.aiflags & (AI_SWIM|AI_FLY)) { // try one move with vertical motion, then one without for( i = 0; i < 2; i++ ) { - VectorAdd( ent->progs.sv->origin, move, neworg ); - if( noenemy ) enemy = prog->edicts; + VectorAdd( ent->v.origin, move, neworg ); + if( noenemy ) enemy = svg.edicts; else { - enemy = PRVM_PROG_TO_EDICT( ent->progs.sv->enemy ); - if( i == 0 && enemy != prog->edicts ) + enemy = ent->v.enemy; + if( i == 0 && enemy != svg.edicts ) { - dz = ent->progs.sv->origin[2] - PRVM_PROG_TO_EDICT(ent->progs.sv->enemy)->progs.sv->origin[2]; + dz = ent->v.origin[2] - ent->v.enemy->v.origin[2]; if( dz > 40 ) neworg[2] -= 8; if( dz < 30 ) neworg[2] += 8; } } - trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, neworg, MOVE_NORMAL, ent, SV_ContentsMask(ent)); + trace = SV_Trace( ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent, SV_ContentsMask(ent)); if( trace.fraction == 1 ) { VectorCopy( trace.endpos, traceendpos ); - if(((int)ent->progs.sv->aiflags & AI_SWIM) && !(SV_PointContents(traceendpos) & MASK_WATER)) + if(((int)ent->v.aiflags & AI_SWIM) && !(SV_PointContents(traceendpos) & MASK_WATER)) return false; // swim monster left water - VectorCopy( traceendpos, ent->progs.sv->origin ); + VectorCopy( traceendpos, ent->v.origin ); if( relink ) SV_LinkEdict( ent ); return true; } - if( enemy == prog->edicts ) break; + if( enemy == svg.edicts ) break; } return false; } @@ -139,47 +139,47 @@ bool SV_movestep( edict_t *ent, vec3_t move, bool relink, bool noenemy, bool set VectorCopy( neworg, end ); end[2] -= sv_stepheight->value * 2; - trace = SV_Trace( neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent)); + trace = SV_Trace( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent)); if( trace.startsolid ) { neworg[2] -= sv_stepheight->value; - trace = SV_Trace( neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent)); + trace = SV_Trace( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, SV_ContentsMask(ent)); if( trace.startsolid ) return false; } if( trace.fraction == 1 ) { // if monster had the ground pulled out, go ahead and fall - if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) + if( ent->v.flags & FL_PARTIALONGROUND ) { - VectorAdd( ent->progs.sv->origin, move, ent->progs.sv->origin ); + VectorAdd( ent->v.origin, move, ent->v.origin ); if (relink) SV_LinkEdict( ent ); - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND; + ent->v.flags &= ~FL_ONGROUND; return true; } return false; // walked off an edge } // check point traces down for dangling corners - VectorCopy( trace.endpos, ent->progs.sv->origin ); + VectorCopy( trace.endpos, ent->v.origin ); if(!SV_CheckBottom( ent )) { - if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) + if( ent->v.flags & FL_PARTIALONGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if( relink ) SV_LinkEdict( ent ); return true; } - VectorCopy( oldorg, ent->progs.sv->origin ); + VectorCopy( oldorg, ent->v.origin ); return false; } - if((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) - ent->progs.sv->flags = (int)ent->progs.sv->flags & ~AI_PARTIALONGROUND; + if( ent->v.flags & FL_PARTIALONGROUND ) + ent->v.flags &= ~FL_PARTIALONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( trace.ent ); + ent->v.groundentity = trace.ent; // the move is ok if( relink ) SV_LinkEdict( ent ); @@ -203,23 +203,23 @@ bool SV_StepDirection( edict_t *ent, float yaw, float dist ) vec3_t move, oldorigin; float delta, current; - ent->progs.sv->ideal_yaw = yaw; - current = anglemod( ent->progs.sv->angles[1] ); - ent->progs.sv->angles[1] = SV_AngleMod( ent->progs.sv->ideal_yaw, current, ent->progs.sv->yaw_speed ); + ent->v.ideal_yaw = yaw; + current = anglemod( ent->v.angles[1] ); + ent->v.angles[1] = SV_AngleMod( ent->v.ideal_yaw, current, ent->v.yaw_speed ); yaw = yaw * M_PI*2 / 360; move[0] = cos(yaw)*dist; move[1] = sin(yaw)*dist; move[2] = 0; - VectorCopy( ent->progs.sv->origin, oldorigin ); + VectorCopy( ent->v.origin, oldorigin ); if(SV_movestep( ent, move, false, false, false )) { - delta = ent->progs.sv->angles[YAW] - ent->progs.sv->ideal_yaw; + delta = ent->v.angles[YAW] - ent->v.ideal_yaw; if( delta > 45 && delta < 315 ) { // not turned far enough, so don't take the step - VectorCopy( oldorigin, ent->progs.sv->origin ); + VectorCopy( oldorigin, ent->v.origin ); } SV_LinkEdict( ent ); return true; @@ -237,11 +237,9 @@ SV_FixCheckBottom */ void SV_FixCheckBottom( edict_t *ent ) { - ent->progs.sv->flags = (int)ent->progs.sv->aiflags | AI_PARTIALONGROUND; + ent->v.flags |= FL_PARTIALONGROUND; } - - /* ================ SV_NewChaseDir @@ -253,11 +251,11 @@ void SV_NewChaseDir( edict_t *actor, edict_t *enemy, float dist ) float deltax, deltay; float d[3], tdir, olddir, turnaround; - olddir = anglemod((int)(actor->progs.sv->ideal_yaw/45) * 45); + olddir = anglemod((int)(actor->v.ideal_yaw/45) * 45); turnaround = anglemod( olddir - 180 ); - deltax = enemy->progs.sv->origin[0] - actor->progs.sv->origin[0]; - deltay = enemy->progs.sv->origin[1] - actor->progs.sv->origin[1]; + deltax = enemy->v.origin[0] - actor->v.origin[0]; + deltay = enemy->v.origin[1] - actor->v.origin[1]; if( deltax > 10 ) d[1]= 0; else if( deltax < -10 ) d[1] = 180; else d[1] = -1; @@ -310,7 +308,7 @@ void SV_NewChaseDir( edict_t *actor, edict_t *enemy, float dist ) if( turnaround != -1 && SV_StepDirection( actor, turnaround, dist )) return; - actor->progs.sv->ideal_yaw = olddir; // can't move + actor->v.ideal_yaw = olddir; // can't move // if a bridge was pulled out from underneath a monster, it may not have // a valid standing position at all @@ -329,9 +327,9 @@ bool SV_CloseEnough( edict_t *ent, edict_t *goal, float dist ) for( i = 0; i < 3; i++ ) { - if( goal->progs.sv->absmin[i] > ent->progs.sv->absmax[i] + dist ) + if( goal->v.absmin[i] > ent->v.absmax[i] + dist ) return false; - if( goal->progs.sv->absmax[i] < ent->progs.sv->absmin[i] - dist ) + if( goal->v.absmax[i] < ent->v.absmin[i] - dist ) return false; } return true; @@ -343,52 +341,40 @@ SV_MoveToGoal ====================== */ -void SV_MoveToGoal( void ) +bool SV_MoveToGoal( edict_t *ent, edict_t *goal, float dist ) { - edict_t *ent, *goal; - float dist; - - if(!VM_ValidateArgs( "movetogoal", 1 )) - return; - - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - goal = PRVM_PROG_TO_EDICT( ent->progs.sv->goalentity ); - dist = PRVM_G_FLOAT( OFS_PARM0 ); - - if(!((int)ent->progs.sv->aiflags & (AI_ONGROUND|AI_FLY|AI_SWIM))) + if(!(ent->v.aiflags & (AI_FLY|AI_SWIM)) && !(ent->v.flags & FL_ONGROUND)) { - PRVM_G_FLOAT(OFS_RETURN) = 0; - return; + return false; } // if the next step hits the enemy, return immediately - if(PRVM_PROG_TO_EDICT(ent->progs.sv->enemy) != prog->edicts && SV_CloseEnough( ent, goal, dist)) - return; + if( ent->v.enemy != svg.edicts && SV_CloseEnough( ent, goal, dist )) + return false; // bump around... - if(( rand() & 3) == 1 || !SV_StepDirection( ent, ent->progs.sv->ideal_yaw, dist )) + if(( rand() & 3) == 1 || !SV_StepDirection( ent, ent->v.ideal_yaw, dist )) { SV_NewChaseDir( ent, goal, dist ); } + return true; } // g-cont: my stupid callbacks cmodel_t *SV_GetModelPtr( edict_t *ent ) { - return pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] ); + return pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->v.modelindex] ); } -float *SV_GetModelVerts( sv_edict_t *ed, int *numvertices ) +float *SV_GetModelVerts( edict_t *ent, int *numvertices ) { cmodel_t *cmod; - edict_t *ent; - ent = PRVM_EDICT_NUM(ed->serialnumber); - cmod = pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->progs.sv->modelindex] ); + cmod = pe->RegisterModel( sv.configstrings[CS_MODELS + (int)ent->v.modelindex] ); if( cmod ) { - int i = (int)ent->progs.sv->body; + int i = (int)ent->v.body; i = bound( 0, i, cmod->numbodies ); // make sure what body exist if( cmod->col[i] ) @@ -400,41 +386,39 @@ float *SV_GetModelVerts( sv_edict_t *ed, int *numvertices ) return NULL; } -void SV_Transform( sv_edict_t *ed, const vec3_t origin, const matrix3x3 matrix ) +void SV_Transform( edict_t *edict, const vec3_t origin, const matrix3x3 matrix ) { - edict_t *edict; vec3_t angles; - if( !ed ) return; - edict = PRVM_EDICT_NUM( ed->serialnumber ); + if( !edict ) return; - Matrix3x3_Transpose( edict->progs.sv->m_pmatrix, matrix ); + Matrix3x3_Transpose( edict->v.m_pmatrix, matrix ); #if 0 - edict->progs.sv->m_pmatrix[0][0] = matrix[0][0]; - edict->progs.sv->m_pmatrix[0][1] = matrix[0][2]; - edict->progs.sv->m_pmatrix[0][2] = matrix[0][1]; - edict->progs.sv->m_pmatrix[1][0] = matrix[1][0]; - edict->progs.sv->m_pmatrix[1][1] = matrix[1][2]; - edict->progs.sv->m_pmatrix[1][2] = matrix[1][1]; - edict->progs.sv->m_pmatrix[2][0] = matrix[2][0]; - edict->progs.sv->m_pmatrix[2][1] = matrix[2][2]; - edict->progs.sv->m_pmatrix[2][2] = matrix[2][1]; + edict->v.m_pmatrix[0][0] = matrix[0][0]; + edict->v.m_pmatrix[0][1] = matrix[0][2]; + edict->v.m_pmatrix[0][2] = matrix[0][1]; + edict->v.m_pmatrix[1][0] = matrix[1][0]; + edict->v.m_pmatrix[1][1] = matrix[1][2]; + edict->v.m_pmatrix[1][2] = matrix[1][1]; + edict->v.m_pmatrix[2][0] = matrix[2][0]; + edict->v.m_pmatrix[2][1] = matrix[2][2]; + edict->v.m_pmatrix[2][2] = matrix[2][1]; - Matrix3x3_ConcatRotate( edict->progs.sv->m_pmatrix, -90, 1, 0, 0 ); - Matrix3x3_ConcatRotate( edict->progs.sv->m_pmatrix, 180, 0, 1, 0 ); - Matrix3x3_ConcatRotate( edict->progs.sv->m_pmatrix, 90, 0, 0, 1 ); - Matrix3x3_ToAngles( edict->progs.sv->m_pmatrix, angles ); + Matrix3x3_ConcatRotate( edict->v.m_pmatrix, -90, 1, 0, 0 ); + Matrix3x3_ConcatRotate( edict->v.m_pmatrix, 180, 0, 1, 0 ); + Matrix3x3_ConcatRotate( edict->v.m_pmatrix, 90, 0, 0, 1 ); + Matrix3x3_ToAngles( edict->v.m_pmatrix, angles ); #endif - VectorCopy( origin, edict->progs.sv->origin ); + VectorCopy( origin, edict->v.origin ); - MatrixAngles( edict->progs.sv->m_pmatrix, angles ); - edict->progs.sv->angles[0] = angles[0]; - edict->progs.sv->angles[1] = angles[1]; - edict->progs.sv->angles[2] = angles[2]; + MatrixAngles( edict->v.m_pmatrix, angles ); + edict->v.angles[0] = angles[0]; + edict->v.angles[1] = angles[1]; + edict->v.angles[2] = angles[2]; // refresh force and torque - pe->GetForce( ed->physbody, edict->progs.sv->velocity, edict->progs.sv->avelocity, edict->progs.sv->force, edict->progs.sv->torque ); - pe->GetMassCentre( ed->physbody, edict->progs.sv->m_pcentre ); + pe->GetForce( edict->pvEngineData->physbody, edict->v.velocity, edict->v.avelocity, edict->v.force, edict->v.torque ); + pe->GetMassCentre( edict->pvEngineData->physbody, edict->v.m_pcentre ); } /* @@ -445,53 +429,43 @@ grab user cmd from player state send it to transform callback ============== */ -void SV_PlayerMove( sv_edict_t *ed ) +void SV_PlayerMove( edict_t *player ) { pmove_t pm; sv_client_t *client; - edict_t *player; - client = ed->client; - player = PRVM_PROG_TO_EDICT( ed->serialnumber ); + client = player->pvEngineData->client; memset( &pm, 0, sizeof(pm) ); - if( player->progs.sv->movetype == MOVETYPE_NOCLIP ) - player->priv.sv->s.pm_type = PM_SPECTATOR; - else player->priv.sv->s.pm_type = PM_NORMAL; - player->priv.sv->s.gravity = sv_gravity->value; + if( player->v.movetype == MOVETYPE_NOCLIP ) + player->pvEngineData->s.pm_type = PM_SPECTATOR; + else player->pvEngineData->s.pm_type = PM_NORMAL; + player->pvEngineData->s.gravity = sv_gravity->value; - if( player->progs.sv->teleport_time ) - player->priv.sv->s.pm_flags |= PMF_TIME_TELEPORT; - else player->priv.sv->s.pm_flags &= ~PMF_TIME_TELEPORT; + if( player->v.teleport_time ) + player->pvEngineData->s.pm_flags |= PMF_TIME_TELEPORT; + else player->pvEngineData->s.pm_flags &= ~PMF_TIME_TELEPORT; - pm.ps = player->priv.sv->s; + pm.ps = player->pvEngineData->s; pm.cmd = client->lastcmd; - pm.body = ed->physbody; // member body ptr + pm.body = player->pvEngineData->physbody; // member body ptr - VectorCopy( player->progs.sv->origin, pm.ps.origin ); - VectorCopy( player->progs.sv->velocity, pm.ps.velocity ); + VectorCopy( player->v.origin, pm.ps.origin ); + VectorCopy( player->v.velocity, pm.ps.velocity ); pe->PlayerMove( &pm, false ); // server move // save results of pmove - player->priv.sv->s = pm.ps; + player->pvEngineData->s = pm.ps; - VectorCopy(pm.ps.origin, player->progs.sv->origin); - VectorCopy(pm.ps.velocity, player->progs.sv->velocity); - VectorCopy(pm.mins, player->progs.sv->mins); - VectorCopy(pm.maxs, player->progs.sv->maxs); - VectorCopy(pm.ps.viewangles, player->priv.sv->s.viewangles ); + VectorCopy(pm.ps.origin, player->v.origin); + VectorCopy(pm.ps.velocity, player->v.velocity); + VectorCopy(pm.mins, player->v.mins); + VectorCopy(pm.maxs, player->v.maxs); + VectorCopy(pm.ps.viewangles, player->pvEngineData->s.viewangles ); } -void SV_PlaySound( sv_edict_t *ed, float volume, float pitch, const char *sample ) +void SV_PlaySound( edict_t *ed, float volume, float pitch, const char *sample ) { - if( !ed ) ed = prog->edicts->priv.sv; - - PRVM_G_INT(OFS_PARM0) = ed->serialnumber; - PRVM_G_FLOAT(OFS_PARM1) = CHAN_AUTO; - PRVM_G_INT(OFS_PARM2) = PRVM_SetEngineString( sample ); - PRVM_G_FLOAT(OFS_PARM3) = volume; - PRVM_G_FLOAT(OFS_PARM4) = ATTN_NORM; - PRVM_G_FLOAT(OFS_PARM5) = bound( 1, pitch * PITCH_NORM, 255 ); - PRVM_ExecuteProgram( prog->globals.sv->EmitSound, "EmitSound" ); + // FIXME: send sound } \ No newline at end of file diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index e770a710..0e784dc0 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -38,11 +38,11 @@ int SV_ContentsMask( const edict_t *passedict ) { if( passedict ) { - if((int)passedict->progs.sv->flags & FL_MONSTER) + if((int)passedict->v.flags & FL_MONSTER) return MASK_MONSTERSOLID; - else if((int)passedict->progs.sv->flags & FL_CLIENT) + else if((int)passedict->v.flags & FL_CLIENT) return MASK_PLAYERSOLID; - else if( passedict->progs.sv->solid == SOLID_TRIGGER ) + else if( passedict->v.solid == SOLID_TRIGGER ) return CONTENTS_SOLID|CONTENTS_BODY; return MASK_SOLID; } @@ -58,7 +58,6 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons { vec3_t hullmins, hullmaxs; int i, bodycontents; - int passedictprog; bool pointtrace; edict_t *traceowner, *touch; trace_t trace; @@ -83,7 +82,7 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons pe->ClipToWorld( &cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, contentsmask ); cliptrace.startstuck = cliptrace.startsolid; if( cliptrace.startsolid || cliptrace.fraction < 1 ) - cliptrace.ent = prog->edicts; + cliptrace.ent = svg.edicts; if( type == MOVE_WORLDONLY ) return cliptrace; @@ -108,13 +107,11 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons } // if the passedict is world, make it NULL (to avoid two checks each time) - if( passedict == prog->edicts ) passedict = NULL; - // precalculate prog value for passedict for comparisons - passedictprog = PRVM_EDICT_TO_PROG(passedict); + if( passedict == svg.edicts ) passedict = NULL; // figure out whether this is a point trace for comparisons pointtrace = VectorCompare(clipmins, clipmaxs); // precalculate passedict's owner edict pointer for comparisons - traceowner = passedict ? PRVM_PROG_TO_EDICT(passedict->progs.sv->owner) : 0; + traceowner = passedict ? passedict->v.owner : svg.edicts; // clip to entities // because this uses SV_AreaEdicts, we know all entity boxes overlap @@ -129,8 +126,8 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons for( i = 0; i < numtouchedicts; i++ ) { touch = touchedicts[i]; - if( touch->progs.sv->solid < SOLID_BBOX ) continue; - if( type == MOVE_NOMONSTERS && touch->progs.sv->solid != SOLID_BSP ) + if( touch->v.solid < SOLID_BBOX ) continue; + if( type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP ) continue; if( passedict ) @@ -140,9 +137,9 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons // don't clip owned entities against owner if( traceowner == touch ) continue; // don't clip owner against owned entities - if( passedictprog == touch->progs.sv->owner ) continue; + if( passedict == touch->v.owner ) continue; // don't clip points against points (they can't collide) - if( pointtrace && VectorCompare( touch->progs.sv->mins, touch->progs.sv->maxs ) && (type != MOVE_MISSILE || !((int)touch->progs.sv->flags & FL_MONSTER))) + if( pointtrace && VectorCompare( touch->v.mins, touch->v.maxs ) && (type != MOVE_MISSILE || !((int)touch->v.flags & FL_MONSTER))) continue; } @@ -150,21 +147,21 @@ trace_t SV_Trace( const vec3_t start, const vec3_t mins, const vec3_t maxs, cons // might interact, so do an exact clip model = NULL; - if((int)touch->progs.sv->solid == SOLID_BSP || type == MOVE_HITMODEL ) + if((int)touch->v.solid == SOLID_BSP || type == MOVE_HITMODEL ) { - uint modelindex = (uint)touch->progs.sv->modelindex; + uint modelindex = (uint)touch->v.modelindex; // if the modelindex is 0, it shouldn't be SOLID_BSP! if( modelindex > 0 && modelindex < MAX_MODELS ) - model = sv.models[(int)touch->progs.sv->modelindex]; + model = sv.models[(int)touch->v.modelindex]; } - if( model ) Matrix4x4_CreateFromEntity( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2], touch->progs.sv->angles[0], touch->progs.sv->angles[1], touch->progs.sv->angles[2], 1 ); - else Matrix4x4_CreateTranslate( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2] ); + if( model ) Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 ); + else Matrix4x4_CreateTranslate( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2] ); Matrix4x4_Invert_Simple( imatrix, matrix ); - if((int)touch->progs.sv->flags & FL_MONSTER) - pe->ClipToGenericEntity(&trace, model, touch->progs.sv->mins, touch->progs.sv->maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask ); - else pe->ClipToGenericEntity(&trace, model, touch->progs.sv->mins, touch->progs.sv->maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask ); + if((int)touch->v.flags & FL_MONSTER) + pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins2, clipmaxs2, clipend, contentsmask ); + else pe->ClipToGenericEntity(&trace, model, touch->v.mins, touch->v.maxs, bodycontents, matrix, imatrix, clipstart, clipmins, clipmaxs, clipend, contentsmask ); - pe->CombineTraces( &cliptrace, &trace, touch, touch->progs.sv->solid == SOLID_BSP ); + pe->CombineTraces( &cliptrace, &trace, touch, touch->v.solid == SOLID_BSP ); } return cliptrace; @@ -198,14 +195,14 @@ int SV_PointContents( const vec3_t point ) touch = touchedicts[i]; // we only care about SOLID_BSP for pointcontents - if( touch->progs.sv->solid != SOLID_BSP ) continue; + if( touch->v.solid != SOLID_BSP ) continue; // might interact, so do an exact clip - modelindex = (uint)touch->progs.sv->modelindex; + modelindex = (uint)touch->v.modelindex; if( modelindex >= MAX_MODELS ) continue; - model = sv.models[(int)touch->progs.sv->modelindex]; + model = sv.models[(int)touch->v.modelindex]; if( !model || !model->PointContents ) continue; - Matrix4x4_CreateFromEntity( matrix, touch->progs.sv->origin[0], touch->progs.sv->origin[1], touch->progs.sv->origin[2], touch->progs.sv->angles[0], touch->progs.sv->angles[1], touch->progs.sv->angles[2], 1 ); + Matrix4x4_CreateFromEntity( matrix, touch->v.origin[0], touch->v.origin[1], touch->v.origin[2], touch->v.angles[0], touch->v.angles[1], touch->v.angles[2], 1 ); Matrix4x4_Invert_Simple( imatrix, matrix ); Matrix4x4_Transform( imatrix, point, transformed); contents |= model->PointContents( transformed, model ); @@ -233,13 +230,13 @@ static int SV_TestEntityPosition( edict_t *ent, vec3_t offset ) vec3_t org; trace_t trace; - VectorAdd( ent->progs.sv->origin, offset, org ); - trace = SV_Trace( org, ent->progs.sv->mins, ent->progs.sv->maxs, ent->progs.sv->origin, MOVE_NOMONSTERS, ent, CONTENTS_SOLID ); + VectorAdd( ent->v.origin, offset, org ); + trace = SV_Trace( org, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NOMONSTERS, ent, CONTENTS_SOLID ); if( trace.startcontents & CONTENTS_SOLID ) return true; // if the trace found a better position for the entity, move it there - if( VectorDistance2( trace.endpos, ent->progs.sv->origin ) >= 0.0001 ) - VectorCopy( trace.endpos, ent->progs.sv->origin ); + if( VectorDistance2( trace.endpos, ent->v.origin ) >= 0.0001 ) + VectorCopy( trace.endpos, ent->v.origin ); return false; } @@ -254,11 +251,11 @@ void SV_CheckAllEnts( void ) edict_t *check; // see if any solid entities are inside the final position - check = PRVM_NEXT_EDICT( prog->edicts ); - for( e = 1; e < prog->num_edicts; e++, check = PRVM_NEXT_EDICT(check)) + check = svg.edicts + 1; + for( e = 1; e < svs.globals->numEntities; e++, check++ ) { - if( check->priv.sv->free ) continue; - switch((int)check->progs.sv->movetype ) + if( check->free ) continue; + switch( check->v.movetype ) { case MOVETYPE_PUSH: case MOVETYPE_NONE: @@ -286,26 +283,26 @@ void SV_CheckVelocity( edict_t *ent ) // bound velocity for( i = 0; i < 3; i++ ) { - if(IS_NAN(ent->progs.sv->velocity[i])) + if(IS_NAN(ent->v.velocity[i])) { - MsgDev( D_INFO, "Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->progs.sv->classname)); - ent->progs.sv->velocity[i] = 0; + MsgDev( D_INFO, "Got a NaN velocity on entity #%i (%s)\n", NUM_FOR_EDICT( ent ), STRING( ent->v.classname )); + ent->v.velocity[i] = 0; } - if (IS_NAN(ent->progs.sv->origin[i])) + if (IS_NAN(ent->v.origin[i])) { - MsgDev( D_INFO, "Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(ent->progs.sv->classname)); - ent->progs.sv->origin[i] = 0; + MsgDev( D_INFO, "Got a NaN origin on entity #%i (%s)\n", NUM_FOR_EDICT( ent ), STRING( ent->v.classname )); + ent->v.origin[i] = 0; } } // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster - wishspeed = DotProduct( ent->progs.sv->velocity, ent->progs.sv->velocity ); + wishspeed = DotProduct( ent->v.velocity, ent->v.velocity ); if( wishspeed > sv_maxvelocity->value * sv_maxvelocity->value ) { wishspeed = sv_maxvelocity->value / sqrt(wishspeed); - ent->progs.sv->velocity[0] *= wishspeed; - ent->progs.sv->velocity[1] *= wishspeed; - ent->progs.sv->velocity[2] *= wishspeed; + ent->v.velocity[0] *= wishspeed; + ent->v.velocity[1] *= wishspeed; + ent->v.velocity[2] *= wishspeed; } } @@ -325,23 +322,21 @@ bool SV_RunThink( edict_t *ent ) // don't let things stay in the past. // it is possible to start that way by a trigger with a local time. - if( ent->progs.sv->nextthink <= 0 || ent->progs.sv->nextthink > sv.time + sv.frametime ) + if( ent->v.nextthink <= 0 || ent->v.nextthink > sv.time + sv.frametime ) return true; - for( iterations = 0; iterations < 128 && !ent->priv.sv->free; iterations++ ) + for( iterations = 0; iterations < 128 && !ent->free; iterations++ ) { - prog->globals.sv->time = max( sv.time, ent->progs.sv->nextthink ); - ent->progs.sv->nextthink = 0; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent ); - prog->globals.sv->other = PRVM_EDICT_TO_PROG( prog->edicts ); - PRVM_ExecuteProgram( ent->progs.sv->think, "pev->think" ); + svs.globals->time = max( sv.time, ent->v.nextthink ); + ent->v.nextthink = 0; + svs.dllFuncs.pfnThink( ent ); // mods often set nextthink to time to cause a think every frame, // we don't want to loop in that case, so exit if the new nextthink is // <= the time the qc was told, also exit if it is past the end of the frame - if( ent->progs.sv->nextthink <= prog->globals.sv->time || ent->progs.sv->nextthink > sv.time + sv.frametime ) + if( ent->v.nextthink <= svs.globals->time || ent->v.nextthink > sv.time + sv.frametime ) break; } - return !ent->priv.sv->free; + return !ent->free; } /* @@ -353,30 +348,24 @@ Two entities have touched, so run their touch functions */ void SV_Impact( edict_t *e1, trace_t *trace ) { - edict_t *e2 = (edict_t *)trace->ent; + edict_t *e2 = trace->ent; - PRVM_PUSH_GLOBALS; - VM_SetTraceGlobals( trace ); + SV_CopyTraceToGlobal( trace ); - prog->globals.sv->time = sv.time; - if( !e1->priv.sv->free && !e2->priv.sv->free && e1->progs.sv->touch && e1->progs.sv->solid != SOLID_NOT ) + svs.globals->time = sv.time; + if( !e1->free && !e2->free && e1->v.solid != SOLID_NOT ) { - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( e1 ); - prog->globals.sv->other = PRVM_EDICT_TO_PROG( e2 ); - PRVM_ExecuteProgram( e1->progs.sv->touch, "pev->touch" ); + svs.dllFuncs.pfnTouch( e1, e2 ); } - if( !e1->priv.sv->free && !e2->priv.sv->free && e2->progs.sv->touch && e2->progs.sv->solid != SOLID_NOT ) + if( !e1->free && !e2->free && e2->v.solid != SOLID_NOT ) { - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(e2); - prog->globals.sv->other = PRVM_EDICT_TO_PROG(e1); - VectorCopy( e2->progs.sv->origin, prog->globals.sv->trace_endpos ); - VectorNegate( trace->plane.normal, prog->globals.sv->trace_plane_normal ); - prog->globals.sv->trace_plane_dist = -trace->plane.dist; - prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(e1); - PRVM_ExecuteProgram( e2->progs.sv->touch, "pev->touch" ); + VectorCopy( e2->v.origin, svs.globals->trace_endpos ); + VectorNegate( trace->plane.normal, svs.globals->trace_plane_normal ); + svs.globals->trace_plane_dist = -trace->plane.dist; + svs.globals->trace_ent = e1; + svs.dllFuncs.pfnTouch( e2, e1 ); } - PRVM_POP_GLOBALS; } /* @@ -392,27 +381,19 @@ void SV_TouchTriggers( edict_t *ent ) edict_t *touch[MAX_EDICTS]; // dead things don't activate triggers! - if(!((int)ent->progs.sv->flags & FL_CLIENT) && (ent->progs.sv->health <= 0)) + if(!(ent->v.flags & FL_CLIENT) && (ent->v.health <= 0)) return; - num = SV_AreaEdicts( ent->progs.sv->absmin, ent->progs.sv->absmax, touch, host.max_edicts, AREA_TRIGGERS ); - - PRVM_PUSH_GLOBALS; + num = SV_AreaEdicts( ent->v.absmin, ent->v.absmax, touch, host.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++ ) { - if( touch[i]->priv.sv->free ) continue; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(touch[i]); - prog->globals.sv->other = PRVM_EDICT_TO_PROG(ent); - prog->globals.sv->time = sv.time; - if(touch[i]->progs.sv->touch) - PRVM_ExecuteProgram( touch[i]->progs.sv->touch, "pev->touch"); + if( touch[i]->free ) continue; + svs.globals->time = sv.time; + svs.dllFuncs.pfnTouch( touch[i], ent ); } - - // restore state - PRVM_POP_GLOBALS; } /* @@ -474,33 +455,33 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) trace_t trace; if( time <= 0 ) return 0; - VectorCopy(ent->progs.sv->velocity, original_velocity); - VectorCopy(ent->progs.sv->velocity, primal_velocity); + VectorCopy(ent->v.velocity, original_velocity); + VectorCopy(ent->v.velocity, primal_velocity); numplanes = 0; time_left = time; for( bumpcount = 0; bumpcount < MAX_CLIP_PLANES; bumpcount++ ) { - if(!ent->progs.sv->velocity[0] && !ent->progs.sv->velocity[1] && !ent->progs.sv->velocity[2]) + if(!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2]) break; - VectorMA( ent->progs.sv->origin, time_left, ent->progs.sv->velocity, end ); - trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, contentsmask ); + VectorMA( ent->v.origin, time_left, ent->v.velocity, end ); + trace = SV_Trace( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent, contentsmask ); // break if it moved the entire distance if( trace.fraction == 1 ) { - VectorCopy( trace.endpos, ent->progs.sv->origin ); + VectorCopy( trace.endpos, ent->v.origin ); break; } if( !trace.ent ) { MsgDev( D_WARN, "SV_FlyMove: trace.ent == NULL\n" ); - trace.ent = prog->edicts; + trace.ent = svg.edicts; } - impact = !((int)ent->progs.sv->aiflags & AI_ONGROUND) || ent->progs.sv->groundentity != PRVM_EDICT_TO_PROG(trace.ent); + impact = !(ent->v.flags & FL_ONGROUND) || ent->v.groundentity != trace.ent; if( trace.plane.normal[2] ) { @@ -508,8 +489,8 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) { // floor blocked |= 1; - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; } } else @@ -523,8 +504,8 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) if( trace.fraction >= 0.001 ) { // actually covered some distance - VectorCopy( trace.endpos, ent->progs.sv->origin ); - VectorCopy( ent->progs.sv->velocity, original_velocity ); + VectorCopy( trace.endpos, ent->v.origin ); + VectorCopy( ent->v.velocity, original_velocity ); numplanes = 0; } @@ -534,7 +515,7 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) SV_Impact( ent, &trace ); // break if removed by the impact function - if( ent->priv.sv->free ) break; + if( ent->free ) break; } time_left *= 1 - trace.fraction; @@ -543,7 +524,7 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) if( numplanes >= MAX_CLIP_PLANES ) { // this shouldn't really happen - VectorClear( ent->progs.sv->velocity ); + VectorClear( ent->v.velocity ); blocked = 3; break; } @@ -569,35 +550,35 @@ int SV_FlyMove( edict_t *ent, float time, float *stepnormal, int contentsmask ) if( i != numplanes ) { // go along this plane - VectorCopy(new_velocity, ent->progs.sv->velocity); + VectorCopy(new_velocity, ent->v.velocity); } else { // go along the crease if( numplanes != 2 ) { - VectorClear( ent->progs.sv->velocity ); + VectorClear( ent->v.velocity ); blocked = 7; break; } CrossProduct( planes[0], planes[1], dir ); VectorNormalize( dir ); - d = DotProduct( dir, ent->progs.sv->velocity ); - VectorScale( dir, d, ent->progs.sv->velocity ); + d = DotProduct( dir, ent->v.velocity ); + VectorScale( dir, d, ent->v.velocity ); } // if current velocity is against the original velocity, // stop dead to avoid tiny occilations in sloping corners - if( DotProduct(ent->progs.sv->velocity, primal_velocity ) <= 0 ) + if( DotProduct(ent->v.velocity, primal_velocity ) <= 0 ) { - VectorClear( ent->progs.sv->velocity ); + VectorClear( ent->v.velocity ); break; } } // this came from QW and allows you to get out of water more easily - if(((int)ent->progs.sv->aiflags & AI_WATERJUMP)) - VectorCopy( primal_velocity, ent->progs.sv->velocity ); + if(((int)ent->v.aiflags & AI_WATERJUMP)) + VectorCopy( primal_velocity, ent->v.velocity ); return blocked; } @@ -610,9 +591,9 @@ SV_AddGravity */ void SV_AddGravity( edict_t *ent ) { - if( ent->progs.sv->gravity ) - ent->progs.sv->velocity[2] -= ent->progs.sv->gravity * sv.frametime; - else ent->progs.sv->velocity[2] -= sv_gravity->value * sv.frametime; + if( ent->v.gravity ) + ent->v.velocity[2] -= ent->v.gravity * sv.frametime; + else ent->v.velocity[2] -= sv_gravity->value * sv.frametime; } /* @@ -636,20 +617,20 @@ static trace_t SV_PushEntity( edict_t *ent, vec3_t push, bool failonstartstuck ) trace_t trace; vec3_t end; - VectorAdd( ent->progs.sv->origin, push, end ); + VectorAdd( ent->v.origin, push, end ); - if( ent->progs.sv->solid == SOLID_TRIGGER || ent->progs.sv->solid == SOLID_NOT ) + if( ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT ) type = MOVE_NOMONSTERS; // only clip against bmodels else type = MOVE_NORMAL; - trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, type, ent, SV_ContentsMask( ent )); + trace = SV_Trace( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent, SV_ContentsMask( ent )); if( trace.startstuck && failonstartstuck ) return trace; - VectorCopy( trace.endpos, ent->progs.sv->origin ); + VectorCopy( trace.endpos, ent->v.origin ); SV_LinkEdict( ent ); - if( ent->progs.sv->solid >= SOLID_TRIGGER && ent->progs.sv->solid < SOLID_BOX && trace.ent && (!((int)ent->progs.sv->aiflags & AI_ONGROUND) || ent->progs.sv->groundentity != PRVM_EDICT_TO_PROG(trace.ent))) + if( ent->v.solid >= SOLID_TRIGGER && ent->v.solid < SOLID_BOX && trace.ent && (!(ent->v.flags & FL_ONGROUND) || ent->v.groundentity != trace.ent )) SV_Impact( ent, &trace ); return trace; } @@ -675,55 +656,55 @@ void SV_PushMove( edict_t *pusher, float movetime ) matrix4x4 pusherfinalmatrix, pusherfinalimatrix; word moved_edicts[MAX_EDICTS]; - if (!pusher->progs.sv->velocity[0] && !pusher->progs.sv->velocity[1] && !pusher->progs.sv->velocity[2] && !pusher->progs.sv->avelocity[0] && !pusher->progs.sv->avelocity[1] && !pusher->progs.sv->avelocity[2]) + if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2] && !pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2]) { - pusher->progs.sv->ltime += movetime; + pusher->v.ltime += movetime; return; } - switch((int) pusher->progs.sv->solid ) + switch((int) pusher->v.solid ) { case SOLID_BSP: case SOLID_BBOX: break; case SOLID_NOT: case SOLID_TRIGGER: - VectorMA (pusher->progs.sv->origin, movetime, pusher->progs.sv->velocity, pusher->progs.sv->origin); - VectorMA (pusher->progs.sv->angles, movetime, pusher->progs.sv->avelocity, pusher->progs.sv->angles); - SV_ClampAngle( pusher->progs.sv->angles ); - pusher->progs.sv->ltime += movetime; + VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin); + VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles); + SV_ClampAngle( pusher->v.angles ); + pusher->v.ltime += movetime; SV_LinkEdict( pusher ); return; default: - MsgDev( D_WARN, "SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->progs.sv->solid ); + MsgDev( D_WARN, "SV_PushMove: entity #%i, unrecognized solid type %f\n", NUM_FOR_EDICT( pusher ), pusher->v.solid ); return; } - index = (int)pusher->progs.sv->modelindex; + index = (int)pusher->v.modelindex; if( index < 1 || index >= MAX_MODELS ) { - MsgDev( D_WARN, "SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->progs.sv->modelindex ); + MsgDev( D_WARN, "SV_PushMove: entity #%i has an invalid modelindex %f\n", NUM_FOR_EDICT( pusher ), pusher->v.modelindex ); return; } pushermodel = sv.models[index]; - rotated = VectorLength2(pusher->progs.sv->angles) + VectorLength2(pusher->progs.sv->avelocity) > 0; + rotated = VectorLength2(pusher->v.angles) + VectorLength2(pusher->v.avelocity) > 0; movetime2 = movetime; - VectorScale( pusher->progs.sv->velocity, movetime2, move1 ); - VectorScale( pusher->progs.sv->avelocity, movetime2, moveangle ); + VectorScale( pusher->v.velocity, movetime2, move1 ); + VectorScale( pusher->v.avelocity, movetime2, moveangle ); if( moveangle[0] || moveangle[2] ) { for( i = 0; i < 3; i++ ) { if( move1[i] > 0 ) { - mins[i] = pushermodel->rotatedmins[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1; } else { - mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1; } } } @@ -733,13 +714,13 @@ void SV_PushMove( edict_t *pusher, float movetime ) { if( move1[i] > 0 ) { - mins[i] = pushermodel->yawmins[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1; } else { - mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1; } } } @@ -749,13 +730,13 @@ void SV_PushMove( edict_t *pusher, float movetime ) { if( move1[i] > 0 ) { - mins[i] = pushermodel->normalmins[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1; } else { - mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->progs.sv->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + pusher->progs.sv->origin[i] + 1; + mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1; } } } @@ -763,23 +744,23 @@ void SV_PushMove( edict_t *pusher, float movetime ) VectorNegate( moveangle, a ); AngleVectorsFLU( a, forward, left, up ); - VectorCopy( pusher->progs.sv->origin, pushorig ); - VectorCopy( pusher->progs.sv->angles, pushang ); - pushltime = pusher->progs.sv->ltime; + VectorCopy( pusher->v.origin, pushorig ); + VectorCopy( pusher->v.angles, pushang ); + pushltime = pusher->v.ltime; // move the pusher to its final position - VectorMA( pusher->progs.sv->origin, movetime, pusher->progs.sv->velocity, pusher->progs.sv->origin ); - VectorMA( pusher->progs.sv->angles, movetime, pusher->progs.sv->avelocity, pusher->progs.sv->angles ); - pusher->progs.sv->ltime += movetime; + VectorMA( pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin ); + VectorMA( pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles ); + pusher->v.ltime += movetime; SV_LinkEdict( pusher ); pushermodel = NULL; - if( pusher->progs.sv->modelindex >= 1 && pusher->progs.sv->modelindex < MAX_MODELS ) - pushermodel = sv.models[(int)pusher->progs.sv->modelindex]; - Matrix4x4_CreateFromEntity( pusherfinalmatrix, pusher->progs.sv->origin[0], pusher->progs.sv->origin[1], pusher->progs.sv->origin[2], pusher->progs.sv->angles[0], pusher->progs.sv->angles[1], pusher->progs.sv->angles[2], 1 ); + if( pusher->v.modelindex >= 1 && pusher->v.modelindex < MAX_MODELS ) + pushermodel = sv.models[(int)pusher->v.modelindex]; + Matrix4x4_CreateFromEntity( pusherfinalmatrix, pusher->v.origin[0], pusher->v.origin[1], pusher->v.origin[2], pusher->v.angles[0], pusher->v.angles[1], pusher->v.angles[2], 1 ); Matrix4x4_Invert_Simple( pusherfinalimatrix, pusherfinalmatrix ); - savesolid = pusher->progs.sv->solid; + savesolid = pusher->v.solid; // see if any solid entities are inside the final position num_moved = 0; @@ -789,7 +770,7 @@ void SV_PushMove( edict_t *pusher, float movetime ) { edict_t *check = checkentities[e]; - switch((int)check->progs.sv->movetype) + switch( check->v.movetype ) { case MOVETYPE_NONE: case MOVETYPE_PUSH: @@ -799,22 +780,22 @@ void SV_PushMove( edict_t *pusher, float movetime ) } // tell any MOVETYPE_STEP entity that it may need to check for water transitions - check->priv.sv->forceupdate = true; + check->pvEngineData->forceupdate = true; checkcontents = SV_ContentsMask( check ); // if the entity is standing on the pusher, it will definitely be moved // if the entity is not standing on the pusher, but is in the pusher's // final position, move it - if(!((int)check->progs.sv->aiflags & AI_ONGROUND) || PRVM_PROG_TO_EDICT(check->progs.sv->groundentity) != pusher ) + if(!( check->v.flags & FL_ONGROUND) || check->v.groundentity != pusher ) { - pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents ); + pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents ); if( !trace.startsolid ) continue; } if( rotated ) { vec3_t org2; - VectorSubtract( check->progs.sv->origin, pusher->progs.sv->origin, org ); + VectorSubtract( check->v.origin, pusher->v.origin, org ); org2[0] = DotProduct( org, forward ); org2[1] = DotProduct( org, left ); org2[2] = DotProduct( org, up ); @@ -827,87 +808,82 @@ void SV_PushMove( edict_t *pusher, float movetime ) } //Msg("- pushing %f %f %f\n", move[0], move[1], move[2]); - VectorCopy (check->progs.sv->origin, check->priv.sv->moved_origin ); - VectorCopy (check->progs.sv->angles, check->priv.sv->moved_angles ); - moved_edicts[num_moved++] = PRVM_NUM_FOR_EDICT(check); + VectorCopy (check->v.origin, check->pvEngineData->moved_origin ); + VectorCopy (check->v.angles, check->pvEngineData->moved_angles ); + moved_edicts[num_moved++] = NUM_FOR_EDICT( check ); // try moving the contacted entity - pusher->progs.sv->solid = SOLID_NOT; + pusher->v.solid = SOLID_NOT; trace = SV_PushEntity( check, move, true ); // FIXME: turn players specially - check->progs.sv->angles[1] += trace.fraction * moveangle[1]; - pusher->progs.sv->solid = savesolid; // was SOLID_BSP + check->v.angles[1] += trace.fraction * moveangle[1]; + pusher->v.solid = savesolid; // was SOLID_BSP // this trace.fraction < 1 check causes items to fall off of pushers // if they pass under or through a wall // the groundentity check causes items to fall off of ledges - if( check->progs.sv->movetype != MOVETYPE_WALK && (trace.fraction < 1 || PRVM_PROG_TO_EDICT(check->progs.sv->groundentity) != pusher)) - check->progs.sv->aiflags = (int)check->progs.sv->aiflags & ~AI_ONGROUND; + if( check->v.movetype != MOVETYPE_WALK && (trace.fraction < 1 || check->v.groundentity != pusher )) + check->v.flags &= ~FL_ONGROUND; // if it is still inside the pusher, block - pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents ); + pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents ); if (trace.startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors vec3_t move2; - pusher->progs.sv->solid = SOLID_NOT; + pusher->v.solid = SOLID_NOT; VectorScale( move, 1.1f, move2 ); - VectorCopy( check->priv.sv->moved_origin, check->progs.sv->origin ); - VectorCopy( check->priv.sv->moved_angles, check->progs.sv->angles ); + VectorCopy( check->pvEngineData->moved_origin, check->v.origin ); + VectorCopy( check->pvEngineData->moved_angles, check->v.angles ); SV_PushEntity( check, move2, true ); - pusher->progs.sv->solid = savesolid; - pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents ); + pusher->v.solid = savesolid; + pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents ); if( trace.startsolid ) { // try moving the contacted entity a tiny bit less to account for precision errors - pusher->progs.sv->solid = SOLID_NOT; + pusher->v.solid = SOLID_NOT; VectorScale( move, 0.9, move2 ); - VectorCopy( check->priv.sv->moved_origin, check->progs.sv->origin ); - VectorCopy( check->priv.sv->moved_angles, check->progs.sv->angles ); + VectorCopy( check->pvEngineData->moved_origin, check->v.origin ); + VectorCopy( check->pvEngineData->moved_angles, check->v.angles ); SV_PushEntity( check, move2, true ); - pusher->progs.sv->solid = savesolid; - pe->ClipToGenericEntity( &trace, pushermodel, pusher->progs.sv->mins, pusher->progs.sv->maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->progs.sv->origin, check->progs.sv->mins, check->progs.sv->maxs, check->progs.sv->origin, checkcontents ); + pusher->v.solid = savesolid; + pe->ClipToGenericEntity( &trace, pushermodel, pusher->v.mins, pusher->v.maxs, CONTENTS_BODY, pusherfinalmatrix, pusherfinalimatrix, check->v.origin, check->v.mins, check->v.maxs, check->v.origin, checkcontents ); if( trace.startsolid ) { // still inside pusher, so it's really blocked // fail the move - if( check->progs.sv->mins[0] == check->progs.sv->maxs[0] ) continue; - if( check->progs.sv->solid == SOLID_NOT || check->progs.sv->solid == SOLID_TRIGGER ) + if( check->v.mins[0] == check->v.maxs[0] ) continue; + if( check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER ) { // corpse - check->progs.sv->mins[0] = check->progs.sv->mins[1] = 0; - VectorCopy( check->progs.sv->mins, check->progs.sv->maxs ); + check->v.mins[0] = check->v.mins[1] = 0; + VectorCopy( check->v.mins, check->v.maxs ); continue; } - VectorCopy( pushorig, pusher->progs.sv->origin ); - VectorCopy( pushang, pusher->progs.sv->angles ); - pusher->progs.sv->ltime = pushltime; + VectorCopy( pushorig, pusher->v.origin ); + VectorCopy( pushang, pusher->v.angles ); + pusher->v.ltime = pushltime; SV_LinkEdict( pusher ); // move back any entities we already moved for( i = 0; i < num_moved; i++ ) { - edict_t *ed = PRVM_EDICT_NUM( moved_edicts[i] ); - VectorCopy( ed->priv.sv->moved_origin, ed->progs.sv->origin ); - VectorCopy( ed->priv.sv->moved_angles, ed->progs.sv->angles ); + edict_t *ed = EDICT_NUM( moved_edicts[i] ); + VectorCopy( ed->pvEngineData->moved_origin, ed->v.origin ); + VectorCopy( ed->pvEngineData->moved_angles, ed->v.angles ); SV_LinkEdict( ed ); } // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if( pusher->progs.sv->blocked ) - { - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( pusher ); - prog->globals.sv->other = PRVM_EDICT_TO_PROG( check ); - PRVM_ExecuteProgram( pusher->progs.sv->blocked, "pev->blocked" ); - } + svs.dllFuncs.pfnBlocked( pusher, check ); break; } } } } - SV_ClampAngle( pusher->progs.sv->angles ); + SV_ClampAngle( pusher->v.angles ); } /* @@ -920,25 +896,23 @@ void SV_Physics_Pusher( edict_t *ent ) { float thinktime, oldltime, movetime; - oldltime = ent->progs.sv->ltime; - thinktime = ent->progs.sv->nextthink; + oldltime = ent->v.ltime; + thinktime = ent->v.nextthink; - if( thinktime < ent->progs.sv->ltime + sv.frametime) + if( thinktime < ent->v.ltime + sv.frametime) { - movetime = thinktime - ent->progs.sv->ltime; + movetime = thinktime - ent->v.ltime; if( movetime < 0 ) movetime = 0; } else movetime = sv.frametime; - // advances ent->progs.sv->ltime if not blocked + // advances ent->v.ltime if not blocked if( movetime ) SV_PushMove( ent, movetime ); - if( thinktime > oldltime && thinktime <= ent->progs.sv->ltime ) + if( thinktime > oldltime && thinktime <= ent->v.ltime ) { - ent->progs.sv->nextthink = 0; - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent); - prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts); - PRVM_ExecuteProgram( ent->progs.sv->think, "pev->think" ); + ent->v.nextthink = 0; + svs.globals->time = sv.time; + svs.dllFuncs.pfnThink( ent ); } } @@ -974,7 +948,7 @@ void SV_CheckStuck( edict_t *ent ) vec3_t offset; VectorClear( offset ); - if((int)ent->progs.sv->aiflags & AI_DUCKED ) + if((int)ent->v.aiflags & AI_DUCKED ) { offset[0] += 1; offset[1] += 1; @@ -982,7 +956,7 @@ void SV_CheckStuck( edict_t *ent ) } if(!SV_TestEntityPosition( ent, offset )) { - VectorCopy( ent->progs.sv->origin, ent->progs.sv->old_origin ); + VectorCopy( ent->v.origin, ent->v.oldorigin ); return; } @@ -996,7 +970,7 @@ void SV_CheckStuck( edict_t *ent ) } } - VectorSubtract( ent->progs.sv->old_origin, ent->progs.sv->origin, offset ); + VectorSubtract( ent->v.oldorigin, ent->v.origin, offset ); if(!SV_TestEntityPosition( ent, offset )) { MsgDev( D_INFO, "Unstuck player by restoring oldorigin.\n" ); @@ -1018,13 +992,13 @@ bool SV_UnstickEntity( edict_t *ent ) { if(!SV_TestEntityPosition( ent, unstickoffsets + i )) { - MsgDev( D_INFO, "Unstuck entity \"%s\" with offset %g %g %g.\n", PRVM_GetString(ent->progs.sv->classname), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2]); + MsgDev( D_INFO, "Unstuck entity \"%s\" with offset %g %g %g.\n", STRING( ent->v.classname ), unstickoffsets[i+0], unstickoffsets[i+1], unstickoffsets[i+2] ); SV_LinkEdict( ent ); return true; } } - MsgDev( D_INFO, "Stuck entity \"%s\".\n", PRVM_GetString(ent->progs.sv->classname)); + MsgDev( D_INFO, "Stuck entity \"%s\".\n", STRING( ent->v.classname )); return false; } @@ -1038,36 +1012,36 @@ bool SV_CheckWater( edict_t *ent ) int cont; vec3_t point; - point[0] = ent->progs.sv->origin[0]; - point[1] = ent->progs.sv->origin[1]; - point[2] = ent->progs.sv->origin[2] + ent->progs.sv->mins[2] + 1; + point[0] = ent->v.origin[0]; + point[1] = ent->v.origin[1]; + point[2] = ent->v.origin[2] + ent->v.mins[2] + 1; - ent->progs.sv->waterlevel = 0; - ent->progs.sv->watertype = 0; + ent->v.waterlevel = 0; + ent->v.watertype = 0; cont = SV_PointContents( point ); if( cont & (MASK_WATER)) { - ent->progs.sv->watertype = cont; - ent->progs.sv->waterlevel = 1; - point[2] = ent->progs.sv->origin[2] + (ent->progs.sv->mins[2] + ent->progs.sv->maxs[2])*0.5; + ent->v.watertype = cont; + ent->v.waterlevel = 1; + point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5; if(SV_PointContents( point ) & (MASK_WATER)) { - ent->progs.sv->waterlevel = 2; - point[2] = ent->progs.sv->origin[2] + ent->progs.sv->view_ofs[2]; + ent->v.waterlevel = 2; + point[2] = ent->v.origin[2] + ent->v.view_ofs[2]; if(SV_PointContents(point) & (MASK_WATER)) { - ent->progs.sv->waterlevel = 3; - if( ent->priv.sv->s.ed_type == ED_CLIENT ) - ent->progs.sv->renderfx = (int)ent->progs.sv->renderfx | RDF_UNDERWATER; + ent->v.waterlevel = 3; + if( ent->pvEngineData->s.ed_type == ED_CLIENT ) + ent->v.renderfx = (int)ent->v.renderfx | RDF_UNDERWATER; } else { - if( ent->priv.sv->s.ed_type == ED_CLIENT ) - ent->progs.sv->renderfx = (int)ent->progs.sv->renderfx & ~RDF_UNDERWATER; + if( ent->pvEngineData->s.ed_type == ED_CLIENT ) + ent->v.renderfx = (int)ent->v.renderfx & ~RDF_UNDERWATER; } } } - return ent->progs.sv->waterlevel > 1; + return ent->v.waterlevel > 1; } /* @@ -1081,15 +1055,15 @@ void SV_WallFriction( edict_t *ent, float *stepnormal ) float d, i; vec3_t forward, into, side; - AngleVectors (ent->progs.sv->v_angle, forward, NULL, NULL); + AngleVectors (ent->v.v_angle, forward, NULL, NULL); if ((d = DotProduct (stepnormal, forward) + 0.5) < 0) { // cut the tangential velocity - i = DotProduct (stepnormal, ent->progs.sv->velocity); + i = DotProduct (stepnormal, ent->v.velocity); VectorScale (stepnormal, i, into); - VectorSubtract (ent->progs.sv->velocity, into, side); - ent->progs.sv->velocity[0] = side[0] * (1 + d); - ent->progs.sv->velocity[1] = side[1] * (1 + d); + VectorSubtract (ent->v.velocity, into, side); + ent->v.velocity[0] = side[0] * (1 + d); + ent->v.velocity[1] = side[1] * (1 + d); } } @@ -1102,10 +1076,11 @@ Only used by players */ void SV_WalkMove( edict_t *ent ) { + int contentsmask; int clip, oldonground, originalmove_clip, originalmove_aiflags; - int originalmove_groundentity, contentsmask; vec3_t upmove, downmove, start_origin, start_velocity, stepnormal; vec3_t originalmove_origin, originalmove_velocity; + edict_t *originalmove_groundentity; trace_t downtrace; // if frametime is 0 (due to client sending the same timestamp twice), don't move @@ -1115,24 +1090,24 @@ void SV_WalkMove( edict_t *ent ) SV_CheckVelocity( ent ); // do a regular slide move unless it looks like you ran into a step - oldonground = (int)ent->progs.sv->aiflags & AI_ONGROUND; + oldonground = (ent->v.flags & FL_ONGROUND); - VectorCopy( ent->progs.sv->origin, start_origin ); - VectorCopy( ent->progs.sv->velocity, start_velocity ); + VectorCopy( ent->v.origin, start_origin ); + VectorCopy( ent->v.velocity, start_velocity ); clip = SV_FlyMove( ent, sv.frametime, NULL, contentsmask ); // if the move did not hit the ground at any point, we're not on ground - if(!(clip & 1)) ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND; + if(!(clip & 1)) ent->v.flags &= ~FL_ONGROUND; SV_CheckVelocity( ent ); - VectorCopy( ent->progs.sv->origin, originalmove_origin ); - VectorCopy( ent->progs.sv->velocity, originalmove_velocity ); + VectorCopy( ent->v.origin, originalmove_origin ); + VectorCopy( ent->v.velocity, originalmove_velocity ); originalmove_clip = clip; - originalmove_aiflags = (int)ent->progs.sv->aiflags; - originalmove_groundentity = ent->progs.sv->groundentity; + originalmove_aiflags = ent->v.aiflags; + originalmove_groundentity = ent->v.groundentity; - if((int)ent->progs.sv->aiflags & AI_WATERJUMP) + if( ent->v.aiflags & AI_WATERJUMP ) return; // if move didn't block on a step, return @@ -1142,21 +1117,21 @@ void SV_WalkMove( edict_t *ent ) if(fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125) return; - if( ent->progs.sv->movetype != MOVETYPE_FLY ) + if( ent->v.movetype != MOVETYPE_FLY ) { // return if gibbed by a trigger - if( ent->progs.sv->movetype != MOVETYPE_WALK ) + if( ent->v.movetype != MOVETYPE_WALK ) return; // only step up while jumping if that is enabled - if( !oldonground && ent->progs.sv->waterlevel == 0 ) + if( !oldonground && ent->v.waterlevel == 0 ) return; } // try moving up and forward to go up a step // back to start pos - VectorCopy( start_origin, ent->progs.sv->origin ); - VectorCopy( start_velocity, ent->progs.sv->velocity ); + VectorCopy( start_origin, ent->v.origin ); + VectorCopy( start_velocity, ent->v.velocity ); // move up VectorClear( upmove ); @@ -1165,21 +1140,21 @@ void SV_WalkMove( edict_t *ent ) SV_PushEntity( ent, upmove, false ); // FIXME: don't link? // move forward - ent->progs.sv->velocity[2] = 0; + ent->v.velocity[2] = 0; clip = SV_FlyMove( ent, sv.frametime, stepnormal, contentsmask ); - ent->progs.sv->velocity[2] += start_velocity[2]; + ent->v.velocity[2] += start_velocity[2]; SV_CheckVelocity( ent ); // check for stuckness, possibly due to the limited precision of floats // in the clipping hulls - if( clip && fabs(originalmove_origin[1] - ent->progs.sv->origin[1]) < 0.03125 && fabs(originalmove_origin[0] - ent->progs.sv->origin[0]) < 0.03125 ) + if( clip && fabs(originalmove_origin[1] - ent->v.origin[1]) < 0.03125 && fabs(originalmove_origin[0] - ent->v.origin[0]) < 0.03125 ) { // stepping up didn't make any progress, revert to original move - VectorCopy( originalmove_origin, ent->progs.sv->origin ); - VectorCopy( originalmove_velocity, ent->progs.sv->velocity ); - ent->progs.sv->aiflags = originalmove_aiflags; - ent->progs.sv->groundentity = originalmove_groundentity; + VectorCopy( originalmove_origin, ent->v.origin ); + VectorCopy( originalmove_velocity, ent->v.velocity ); + ent->v.aiflags = originalmove_aiflags; + ent->v.groundentity = originalmove_groundentity; return; } @@ -1187,7 +1162,7 @@ void SV_WalkMove( edict_t *ent ) if( clip & 2 ) SV_WallFriction( ent, stepnormal ); } // don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground - else if( ent->progs.sv->waterlevel >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || ((int)ent->progs.sv->aiflags & AI_ONGROUND)) + else if( ent->v.waterlevel >= 3 || start_velocity[2] >= (1.0 / 32.0) || !oldonground || (ent->v.flags & FL_ONGROUND)) return; // move down @@ -1201,11 +1176,11 @@ void SV_WalkMove( edict_t *ent ) // up while already jumping (also known as the Quake2 double jump bug) #if 0 // LordHavoc: disabled this check so you can walk on monsters/players - //if (ent->progs.sv->solid == SOLID_BSP) + //if (ent->v.solid == SOLID_BSP) { //Con_Printf("onground\n"); - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(downtrace.ent); + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = downtrace.ent; } #endif } @@ -1214,10 +1189,10 @@ void SV_WalkMove( edict_t *ent ) // if the push down didn't end up on good ground, use the move without // the step up. This happens near wall / slope combinations, and can // cause the player to hop up higher on a slope too steep to climb - VectorCopy( originalmove_origin, ent->progs.sv->origin ); - VectorCopy( originalmove_velocity, ent->progs.sv->velocity ); - ent->progs.sv->aiflags = originalmove_aiflags; - ent->progs.sv->groundentity = originalmove_groundentity; + VectorCopy( originalmove_origin, ent->v.origin ); + VectorCopy( originalmove_velocity, ent->v.velocity ); + ent->v.aiflags = originalmove_aiflags; + ent->v.groundentity = originalmove_groundentity; } SV_CheckVelocity( ent ); } @@ -1239,30 +1214,30 @@ void SV_Physics_Follow( edict_t *ent ) // regular thinking if(!SV_RunThink( ent )) return; - e = PRVM_PROG_TO_EDICT( ent->progs.sv->aiment ); - if(VectorCompare( e->progs.sv->angles, ent->progs.sv->punchangle )) + e = ent->v.aiment; + if(VectorCompare( e->v.angles, ent->v.punchangle )) { // quick case for no rotation - VectorAdd( e->progs.sv->origin, ent->progs.sv->view_ofs, ent->progs.sv->origin ); + VectorAdd( e->v.origin, ent->v.view_ofs, ent->v.origin ); } else { - angles[0] = -ent->progs.sv->punchangle[0]; - angles[1] = ent->progs.sv->punchangle[1]; - angles[2] = ent->progs.sv->punchangle[2]; + angles[0] = -ent->v.punchangle[0]; + angles[1] = ent->v.punchangle[1]; + angles[2] = ent->v.punchangle[2]; AngleVectors( angles, vf, vr, vu ); - v[0] = ent->progs.sv->view_ofs[0] * vf[0] + ent->progs.sv->view_ofs[1] * vr[0] + ent->progs.sv->view_ofs[2] * vu[0]; - v[1] = ent->progs.sv->view_ofs[0] * vf[1] + ent->progs.sv->view_ofs[1] * vr[1] + ent->progs.sv->view_ofs[2] * vu[1]; - v[2] = ent->progs.sv->view_ofs[0] * vf[2] + ent->progs.sv->view_ofs[1] * vr[2] + ent->progs.sv->view_ofs[2] * vu[2]; - angles[0] = -e->progs.sv->angles[0]; - angles[1] = e->progs.sv->angles[1]; - angles[2] = e->progs.sv->angles[2]; + v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0]; + v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1]; + v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2]; + angles[0] = -e->v.angles[0]; + angles[1] = e->v.angles[1]; + angles[2] = e->v.angles[2]; AngleVectors( angles, vf, vr, vu ); - ent->progs.sv->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->progs.sv->origin[0]; - ent->progs.sv->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->progs.sv->origin[1]; - ent->progs.sv->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->progs.sv->origin[2]; + ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0]; + ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1]; + ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2]; } - VectorAdd( e->progs.sv->angles, ent->progs.sv->v_angle, ent->progs.sv->angles ); + VectorAdd( e->v.angles, ent->v.v_angle, ent->v.angles ); SV_LinkEdict( ent ); } @@ -1282,18 +1257,18 @@ SV_CheckWaterTransition */ void SV_CheckWaterTransition( edict_t *ent ) { - int cont = SV_PointContents( ent->progs.sv->origin ); + int cont = SV_PointContents( ent->v.origin ); - if( !ent->progs.sv->watertype ) + if( !ent->v.watertype ) { // just spawned here - ent->progs.sv->watertype = cont; - ent->progs.sv->waterlevel = 1; + ent->v.watertype = cont; + ent->v.waterlevel = 1; return; } // check if the entity crossed into or out of water - if((int)ent->progs.sv->watertype & MASK_WATER ) + if( ent->v.watertype & MASK_WATER ) { Msg( "water splash!\n" ); //SV_StartSound (ent, 0, "", 255, 1); @@ -1301,13 +1276,13 @@ void SV_CheckWaterTransition( edict_t *ent ) if( cont <= CONTENTS_WATER ) { - ent->progs.sv->watertype = cont; - ent->progs.sv->waterlevel = 1; + ent->v.watertype = cont; + ent->v.waterlevel = 1; } else { - ent->progs.sv->watertype = 0; - ent->progs.sv->waterlevel = 0; + ent->v.watertype = 0; + ent->v.waterlevel = 0; } } @@ -1324,81 +1299,81 @@ void SV_Physics_Toss( edict_t *ent ) vec3_t move; // if onground, return without moving - if((int)ent->progs.sv->aiflags & AI_ONGROUND) + if( ent->v.flags & FL_ONGROUND ) { - if( ent->progs.sv->velocity[2] >= (1.0 / 32.0)) + if( ent->v.velocity[2] >= (1.0 / 32.0)) { // don't stick to ground if onground and moving upward - ent->progs.sv->aiflags -= AI_ONGROUND; + ent->v.flags &= FL_ONGROUND; } - else if( !ent->progs.sv->groundentity ) + else if( !ent->v.groundentity ) { - // we can trust AI_ONGROUND if groundentity is world because it never moves + // we can trust FL_ONGROUND if groundentity is world because it never moves return; } - else if( ent->priv.sv->suspended && PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity)->priv.sv->free ) + else if( ent->pvEngineData->suspended && ent->v.groundentity->free ) { // if ent was supported by a brush model on previous frame, // and groundentity is now freed, set groundentity to 0 (world) // which leaves it suspended in the air - ent->progs.sv->groundentity = 0; + ent->v.groundentity = svg.edicts; return; } } - ent->priv.sv->suspended = false; + ent->pvEngineData->suspended = false; SV_CheckVelocity( ent ); // add gravity - if( ent->progs.sv->movetype == MOVETYPE_TOSS || ent->progs.sv->movetype == MOVETYPE_BOUNCE ) + if( ent->v.movetype == MOVETYPE_TOSS || ent->v.movetype == MOVETYPE_BOUNCE ) SV_AddGravity( ent ); // move angles - VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles ); + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles ); // move origin - VectorScale( ent->progs.sv->velocity, sv.frametime, move ); + VectorScale( ent->v.velocity, sv.frametime, move ); trace = SV_PushEntity( ent, move, true ); - if( ent->priv.sv->free ) return; + if( ent->free ) return; if( trace.startstuck ) { // try to unstick the entity SV_UnstickEntity( ent ); trace = SV_PushEntity( ent, move, false ); - if( ent->priv.sv->free ) + if( ent->free ) return; } if( trace.fraction < 1 ) { - if( ent->progs.sv->movetype == MOVETYPE_BOUNCE ) + if( ent->v.movetype == MOVETYPE_BOUNCE ) { float d; - SV_ClipVelocity( ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, 1.5 ); - d = DotProduct( trace.plane.normal, ent->progs.sv->velocity ); + SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5 ); + d = DotProduct( trace.plane.normal, ent->v.velocity ); if( trace.plane.normal[2] > 0.7 && fabs(d) < 60 ) { - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); - VectorClear( ent->progs.sv->velocity ); - VectorClear( ent->progs.sv->avelocity ); + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + VectorClear( ent->v.velocity ); + VectorClear( ent->v.avelocity ); } - else ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND; + else ent->v.flags &= ~FL_ONGROUND; } else { - SV_ClipVelocity( ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, 1.0 ); + SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0 ); if( trace.plane.normal[2] > 0.7 ) { - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); - if( trace.ent->progs.sv->solid == SOLID_BSP ) - ent->priv.sv->suspended = true; - VectorClear( ent->progs.sv->velocity ); - VectorClear( ent->progs.sv->avelocity ); + ent->v.flags |= FL_ONGROUND; + ent->v.groundentity = trace.ent; + if( trace.ent->v.solid == SOLID_BSP ) + ent->pvEngineData->suspended = true; + VectorClear( ent->v.velocity ); + VectorClear( ent->v.avelocity ); } - else ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags & ~AI_ONGROUND; + else ent->v.flags &= ~FL_ONGROUND; } } @@ -1426,28 +1401,28 @@ will fall if the floor is pulled out from under them. */ void SV_Physics_Step( edict_t *ent ) { - int flags = (int)ent->progs.sv->aiflags; + int flags = ent->v.aiflags; - if(!(flags & (AI_FLY | AI_SWIM))) + if(!(flags & (AI_FLY|AI_SWIM))) { - if( flags & AI_ONGROUND ) + if( ent->v.flags & FL_ONGROUND ) { // freefall if onground and moving upward // freefall if not standing on a world surface (it may be a lift or trap door) - if(ent->progs.sv->velocity[2] >= (1.0 / 32.0) || ent->progs.sv->groundentity) + if(ent->v.velocity[2] >= (1.0 / 32.0) || ent->v.groundentity) { - ent->progs.sv->aiflags -= AI_ONGROUND; + ent->v.flags &= ~FL_ONGROUND; SV_AddGravity( ent ); SV_CheckVelocity( ent ); SV_FlyMove( ent, sv.frametime, NULL, SV_ContentsMask( ent )); SV_LinkEdict( ent ); - ent->priv.sv->forceupdate = true; + ent->pvEngineData->forceupdate = true; } } else { // freefall if not onground - int hitsound = ent->progs.sv->velocity[2] < sv_gravity->value * -0.1; + int hitsound = ent->v.velocity[2] < sv_gravity->value * -0.1; SV_AddGravity( ent ); SV_CheckVelocity( ent ); @@ -1455,22 +1430,22 @@ void SV_Physics_Step( edict_t *ent ) SV_LinkEdict( ent ); // just hit ground - if( hitsound && (int)ent->progs.sv->aiflags & AI_ONGROUND ) + if( hitsound && ent->v.flags & FL_ONGROUND ) { Msg("Landing crash\n"); //SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); } - ent->priv.sv->forceupdate = true; + ent->pvEngineData->forceupdate = true; } } // regular thinking if(!SV_RunThink( ent )) return; - if( ent->priv.sv->forceupdate || !VectorCompare( ent->progs.sv->origin, ent->priv.sv->water_origin)) + if( ent->pvEngineData->forceupdate || !VectorCompare( ent->v.origin, ent->pvEngineData->water_origin)) { - ent->priv.sv->forceupdate = false; - VectorCopy( ent->progs.sv->origin, ent->priv.sv->water_origin ); + ent->pvEngineData->forceupdate = false; + VectorCopy( ent->v.origin, ent->pvEngineData->water_origin ); SV_CheckWaterTransition( ent ); } } @@ -1493,37 +1468,37 @@ void SV_Physics_Conveyor( edict_t *ent ) vec3_t v, move; vec3_t point, end; - VectorScale( ent->progs.sv->movedir, ent->progs.sv->speed, v ); + VectorScale( ent->v.movedir, ent->v.speed, v ); VectorScale( v, 0.1f, move ); for( i = 0; i < Host_MaxClients(); i++ ) { - player = PRVM_EDICT_NUM(i) + 1; - if( player->priv.sv->free ) continue; - if( !player->progs.sv->groundentity ) continue; - if( player->progs.sv->groundentity != PRVM_EDICT_TO_PROG(ent)) + player = EDICT_NUM(i) + 1; + if( player->free ) continue; + if( !player->v.groundentity ) continue; + if( player->v.groundentity != ent ) continue; // Look below player; make sure he's on a conveyor - VectorCopy( player->progs.sv->origin, point ); + VectorCopy( player->v.origin, point ); point[2] += 1; VectorCopy( point, end ); end[2] -= 256; - tr = SV_Trace( point, player->progs.sv->mins, player->progs.sv->maxs, end, MOVE_NORMAL, player, MASK_SOLID ); + tr = SV_Trace( point, player->v.mins, player->v.maxs, end, MOVE_NORMAL, player, MASK_SOLID ); // tr.ent HAS to be conveyor, but just in case we screwed something up: if( tr.ent == ent ) { if( tr.plane.normal[2] > 0 ) { - v[2] = ent->progs.sv->speed * com.sqrt( 1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; - if(DotProduct( ent->progs.sv->movedir, tr.plane.normal) > 0) + v[2] = ent->v.speed * com.sqrt( 1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; + if(DotProduct( ent->v.movedir, tr.plane.normal) > 0) v[2] = -v[2]; // then we're moving down move[2] = v[2] * 0.1f; } - VectorAdd( player->progs.sv->origin, move, end ); - tr = SV_Trace( player->progs.sv->origin, player->progs.sv->mins, player->progs.sv->maxs, end, MOVE_NORMAL, player, player->priv.sv->clipmask ); - VectorCopy( tr.endpos, player->progs.sv->origin ); + VectorAdd( player->v.origin, move, end ); + tr = SV_Trace( player->v.origin, player->v.mins, player->v.maxs, end, MOVE_NORMAL, player, player->pvEngineData->clipmask ); + VectorCopy( tr.endpos, player->v.origin ); SV_LinkEdict( player ); } } @@ -1542,8 +1517,8 @@ void SV_Physics_Noclip( edict_t *ent ) if(SV_RunThink( ent )) { SV_CheckWater( ent ); - VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles ); - VectorMA( ent->progs.sv->origin, sv.frametime, ent->progs.sv->velocity, ent->progs.sv->origin ); + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles ); + VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin ); } SV_LinkEdict( ent ); } @@ -1558,7 +1533,7 @@ Non moving objects can only think */ void SV_Physics_None( edict_t *ent ) { - if (ent->progs.sv->nextthink > 0 && ent->progs.sv->nextthink <= sv.time + sv.frametime) + if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime) SV_RunThink (ent); } @@ -1567,7 +1542,7 @@ void SV_Physics_None( edict_t *ent ) static void SV_Physics_Entity( edict_t *ent ) { - switch((int)ent->progs.sv->movetype) + switch((int)ent->v.movetype) { case MOVETYPE_PUSH: SV_Physics_Pusher( ent ); @@ -1588,7 +1563,7 @@ static void SV_Physics_Entity( edict_t *ent ) case MOVETYPE_WALK: if(SV_RunThink( ent )) { - if(!SV_CheckWater( ent ) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP )) + if(!SV_CheckWater( ent ) && !((int)ent->v.aiflags & AI_WATERJUMP )) SV_AddGravity( ent ); SV_CheckStuck( ent ); SV_WalkMove( ent ); @@ -1604,14 +1579,14 @@ static void SV_Physics_Entity( edict_t *ent ) SV_Physics_Conveyor( ent ); break; default: - MsgDev( D_ERROR, "SV_Physics: bad movetype %i\n", (int)ent->progs.sv->movetype ); + MsgDev( D_ERROR, "SV_Physics: bad movetype %i\n", (int)ent->v.movetype ); break; } } void SV_Physics_ClientEntity( edict_t *ent ) { - sv_client_t *client = ent->priv.sv->client; + sv_client_t *client = ent->pvEngineData->client; if( !client ) return;//Host_Error( "SV_Physics_ClientEntity: tired to apply physic to a non-client entity\n" ); @@ -1627,16 +1602,15 @@ void SV_Physics_ClientEntity( edict_t *ent ) // make sure the velocity is sane (not a NaN) SV_CheckVelocity( ent ); - if( DotProduct( ent->progs.sv->velocity, ent->progs.sv->velocity ) < 0.0001 ) - VectorClear( ent->progs.sv->velocity ); + if( DotProduct( ent->v.velocity, ent->v.velocity ) < 0.0001 ) + VectorClear( ent->v.velocity ); // call standard client pre-think - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent ); - PRVM_ExecuteProgram (prog->globals.sv->PlayerPreThink, "PlayerPreThink" ); + svs.globals->time = sv.time; + svs.dllFuncs.pfnPlayerPreThink( ent ); SV_CheckVelocity( ent ); - switch((int)ent->progs.sv->movetype ) + switch((int)ent->v.movetype ) { case MOVETYPE_PUSH: SV_Physics_Pusher( ent ); @@ -1651,8 +1625,8 @@ void SV_Physics_ClientEntity( edict_t *ent ) case MOVETYPE_NOCLIP: SV_RunThink( ent ); SV_CheckWater( ent ); - VectorMA( ent->progs.sv->origin, sv.frametime, ent->progs.sv->velocity, ent->progs.sv->origin ); - VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles ); + VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin ); + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles ); break; case MOVETYPE_STEP: SV_Physics_Step( ent ); @@ -1662,7 +1636,7 @@ void SV_Physics_ClientEntity( edict_t *ent ) // don't run physics here if running asynchronously if( client->skipframes <= 0 ) { - if(!SV_CheckWater( ent ) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP) ) + if(!SV_CheckWater( ent ) && !((int)ent->v.aiflags & AI_WATERJUMP) ) SV_AddGravity (ent); SV_CheckStuck (ent); SV_WalkMove (ent); @@ -1680,7 +1654,7 @@ void SV_Physics_ClientEntity( edict_t *ent ) SV_WalkMove( ent ); break; default: - MsgDev( D_ERROR, "SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->progs.sv->movetype); + MsgDev( D_ERROR, "SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->v.movetype); break; } @@ -1691,13 +1665,12 @@ void SV_Physics_ClientEntity( edict_t *ent ) SV_LinkEdict( ent ); SV_CheckVelocity( ent ); - if( ent->progs.sv->movetype != MOVETYPE_NOCLIP ) + if( ent->v.movetype != MOVETYPE_NOCLIP ) SV_TouchTriggers( ent ); // call standard player post-think - prog->globals.sv->time = sv.time; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram( prog->globals.sv->PlayerPostThink, "PlayerPostThink" ); + svs.globals->time = sv.time; + svs.dllFuncs.pfnPlayerPostThink( ent ); } void SV_Physics_ClientMove( sv_client_t *client, usercmd_t *cmd ) @@ -1705,36 +1678,35 @@ void SV_Physics_ClientMove( sv_client_t *client, usercmd_t *cmd ) edict_t *ent = client->edict; // call player physics, this needs the proper frametime - prog->globals.sv->frametime = sv.frametime; + svs.globals->frametime = sv.frametime; SV_ClientThink( client, cmd ); // call standard client pre-think, with frametime = 0 - prog->globals.sv->time = sv.time; - prog->globals.sv->frametime = 0; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram( prog->globals.sv->PlayerPreThink, "PlayerPreThink" ); - prog->globals.sv->frametime = sv.frametime; + svs.globals->time = sv.time; + svs.globals->frametime = 0; + svs.dllFuncs.pfnPlayerPreThink( ent ); + svs.globals->frametime = sv.frametime; if( !sv_physics->integer ) { // make sure the velocity is sane (not a NaN) SV_CheckVelocity( ent ); - if( DotProduct(ent->progs.sv->velocity, ent->progs.sv->velocity) < 0.0001) - VectorClear( ent->progs.sv->velocity ); + if( DotProduct(ent->v.velocity, ent->v.velocity) < 0.0001) + VectorClear( ent->v.velocity ); - switch((int)ent->progs.sv->movetype ) + switch((int)ent->v.movetype ) { case MOVETYPE_WALK: // perform MOVETYPE_WALK behavior - if(!SV_CheckWater (ent) && !((int)ent->progs.sv->aiflags & AI_WATERJUMP)) + if(!SV_CheckWater (ent) && !((int)ent->v.aiflags & AI_WATERJUMP)) SV_AddGravity( ent ); SV_CheckStuck( ent ); SV_WalkMove( ent ); break; case MOVETYPE_NOCLIP: SV_CheckWater( ent ); - VectorMA( ent->progs.sv->origin, sv.frametime, ent->progs.sv->velocity, ent->progs.sv->origin ); - VectorMA( ent->progs.sv->angles, sv.frametime, ent->progs.sv->avelocity, ent->progs.sv->angles ); + VectorMA( ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin ); + VectorMA( ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles ); break; } SV_CheckVelocity( ent ); @@ -1743,15 +1715,14 @@ void SV_Physics_ClientMove( sv_client_t *client, usercmd_t *cmd ) } else SV_LinkEdict( ent ); - if( ent->progs.sv->movetype != MOVETYPE_NOCLIP ) + if( ent->v.movetype != MOVETYPE_NOCLIP ) SV_TouchTriggers( ent ); // call standard player post-think, with frametime = 0 - prog->globals.sv->time = sv.time; - prog->globals.sv->frametime = 0; - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent ); - PRVM_ExecuteProgram( prog->globals.sv->PlayerPostThink, "PlayerPostThink" ); - prog->globals.sv->frametime = sv.frametime; + svs.globals->time = sv.time; + svs.globals->frametime = 0; + svs.dllFuncs.pfnPlayerPostThink( ent ); + svs.globals->frametime = sv.frametime; } /* @@ -1768,21 +1739,19 @@ void SV_Physics( void ) int num_physframes = 0; // let the progs know that a new frame has started - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.sv->time = sv.time; - prog->globals.sv->frametime = sv.frametime; - PRVM_ExecuteProgram( prog->globals.sv->StartFrame, "StartFrame" ); + svs.globals->time = sv.time; + svs.globals->frametime = sv.frametime; + svs.dllFuncs.pfnStartFrame(); // treat each object in turn - for( i = 1; i < prog->num_edicts; i++ ) + for( i = 1; i < svs.globals->numEntities; i++ ) { - ent = PRVM_EDICT_NUM(i); - if( ent->priv.sv->free ) continue; + ent = EDICT_NUM( i ); + if( ent->free ) continue; - VectorCopy( ent->progs.sv->origin, ent->progs.sv->old_origin ); + VectorCopy( ent->v.origin, ent->v.oldorigin ); if(i <= Host_MaxClients());// SV_Physics_ClientEntity( ent ); - else if(!sv_playersonly->integer)SV_Physics_Entity( ent ); + else if( !sv_playersonly->integer ) SV_Physics_Entity( ent ); } // let everything in the world think and move @@ -1792,13 +1761,19 @@ void SV_Physics( void ) pe->Frame( frametime * 0.001f ); num_physframes++; } - prog->globals.sv->pev = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.sv->other = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.sv->time = sv.time; - PRVM_ExecuteProgram( prog->globals.sv->EndFrame, "EndFrame" ); - // decrement prog->num_edicts if the highest number entities died - for( ;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.sv->free; prog->num_edicts-- ); + // at end of frame kill all entities which supposed to it + for( i = svs.globals->maxClients; i < svs.globals->numEntities; i++ ) + { + if( ent->v.flags & FL_KILLME ) + SV_FreeEdict( EDICT_NUM( i )); + } + + svs.globals->time = sv.time; + // svs.dllFuncs.pfnEndFrame(); + + // decrement svs.globals->numEntities if the highest number entities died + for( ; EDICT_NUM( svs.globals->numEntities - 1)->free; svs.globals->numEntities-- ); if( !sv_playersonly->integer ) sv.time += sv.frametime; } \ No newline at end of file diff --git a/engine/server/sv_progs.c b/engine/server/sv_progs.c index 2add720d..71eb84f5 100644 --- a/engine/server/sv_progs.c +++ b/engine/server/sv_progs.c @@ -9,608 +9,16 @@ #include "matrix_lib.h" #include "const.h" -/* -============ -SV_CalcBBox - -FIXME: get to work -============ -*/ -void SV_CalcBBox( edict_t *ent, vec3_t mins, vec3_t maxs ) -{ - vec3_t rmin, rmax; - int i, j, k, l; - float a, *angles; - vec3_t bounds[2]; - float xvector[2], yvector[2]; - vec3_t base, transformed; - - // find min / max for rotations - angles = ent->progs.sv->angles; - - a = angles[1]/180 * M_PI; - - xvector[0] = cos(a); - xvector[1] = sin(a); - yvector[0] = -sin(a); - yvector[1] = cos(a); - - VectorCopy( mins, bounds[0] ); - VectorCopy( maxs, bounds[1] ); - - rmin[0] = rmin[1] = rmin[2] = 9999; - rmax[0] = rmax[1] = rmax[2] = -9999; - - for( i = 0; i <= 1; i++ ) - { - base[0] = bounds[i][0]; - for( j = 0; j <= 1; j++ ) - { - base[1] = bounds[j][1]; - for( k = 0; k <= 1; k++ ) - { - base[2] = bounds[k][2]; - - // transform the point - transformed[0] = xvector[0] * base[0] + yvector[0] * base[1]; - transformed[1] = xvector[1] * base[0] + yvector[1] * base[1]; - transformed[2] = base[2]; - - for( l = 0; l < 3; l++ ) - { - if( transformed[l] < rmin[l] ) rmin[l] = transformed[l]; - if( transformed[l] > rmax[l] ) rmax[l] = transformed[l]; - } - } - } - } - - VectorCopy( rmin, ent->progs.sv->mins ); - VectorCopy( rmax, ent->progs.sv->maxs ); -} - -void SV_SetMinMaxSize( edict_t *e, float *min, float *max, bool rotate ) -{ - int i; - - for( i = 0; i < 3; i++ ) - if( min[i] > max[i] ) - PRVM_ERROR("SV_SetMinMaxSize: backwards mins/maxs"); - - rotate = false; // FIXME - - // set derived values - if( rotate && e->progs.sv->solid == SOLID_BBOX ) - { - SV_CalcBBox( e, min, max ); - } - else - { - VectorCopy( min, e->progs.sv->mins); - VectorCopy( max, e->progs.sv->maxs); - } - VectorSubtract( max, min, e->progs.sv->size ); - - // TODO: fill also mass and density - SV_LinkEdict (e); -} - -static trace_t SV_TraceToss( edict_t *tossent, edict_t *ignore) -{ - int i; - float gravity; - vec3_t move, end; - vec3_t original_origin; - vec3_t original_velocity; - vec3_t original_angles; - vec3_t original_avelocity; - trace_t trace; - - VectorCopy( tossent->progs.sv->origin, original_origin ); - VectorCopy( tossent->progs.sv->velocity, original_velocity ); - VectorCopy( tossent->progs.sv->angles, original_angles ); - VectorCopy( tossent->progs.sv->avelocity, original_avelocity ); - gravity = tossent->progs.sv->gravity * sv_gravity->value * 0.05; - - for( i = 0; i < 200; i++ ) - { - // LordHavoc: sanity check; never trace more than 10 seconds - SV_CheckVelocity( tossent ); - tossent->progs.sv->velocity[2] -= gravity; - VectorMA( tossent->progs.sv->angles, 0.05, tossent->progs.sv->avelocity, tossent->progs.sv->angles ); - VectorScale( tossent->progs.sv->velocity, 0.05, move ); - VectorAdd( tossent->progs.sv->origin, move, end ); - trace = SV_Trace( tossent->progs.sv->origin, tossent->progs.sv->mins, tossent->progs.sv->maxs, end, MOVE_NORMAL, tossent, SV_ContentsMask( tossent )); - VectorCopy( trace.endpos, tossent->progs.sv->origin ); - if( trace.fraction < 1 ) break; - } - VectorCopy( original_origin, tossent->progs.sv->origin ); - VectorCopy( original_velocity, tossent->progs.sv->velocity ); - VectorCopy( original_angles, tossent->progs.sv->angles ); - VectorCopy( original_avelocity, tossent->progs.sv->avelocity ); - - return trace; -} - -bool SV_CheckForPhysobject( edict_t *ent ) -{ - if( !ent ) return false; - - switch( (int)ent->progs.sv->solid ) - { - case SOLID_BSP: - switch( (int)ent->progs.sv->movetype ) - { - case MOVETYPE_NONE: // static physobject (no gravity) - case MOVETYPE_PUSH: // dynamic physobject (no gravity) - case MOVETYPE_CONVEYOR: - // return true; - default: return false; - } - break; - case SOLID_BOX: - case SOLID_SPHERE: - case SOLID_CYLINDER: - case SOLID_MESH: - switch( (int)ent->progs.sv->movetype ) - { - case MOVETYPE_PHYSIC: // dynamic physobject (with gravity) - return true; - default: return false; - } - break; - default: return false; - } -} - -void SV_CreatePhysBody( edict_t *ent ) -{ - if( !SV_CheckForPhysobject( ent )) return; - ent->priv.sv->physbody = pe->CreateBody( ent->priv.sv, SV_GetModelPtr(ent), ent->progs.sv->origin, ent->progs.sv->m_pmatrix, ent->progs.sv->solid, ent->progs.sv->movetype ); - - pe->SetParameters( ent->priv.sv->physbody, SV_GetModelPtr(ent), 0, ent->progs.sv->mass ); -} - -void SV_SetPhysForce( edict_t *ent ) -{ - if( !SV_CheckForPhysobject( ent )) return; - pe->SetForce( ent->priv.sv->physbody, ent->progs.sv->velocity, ent->progs.sv->avelocity, ent->progs.sv->force, ent->progs.sv->torque ); -} - -void SV_SetMassCentre( edict_t *ent ) -{ - if( !SV_CheckForPhysobject( ent )) return; - pe->SetMassCentre( ent->priv.sv->physbody, ent->progs.sv->m_pcentre ); -} - -void SV_SetModel( edict_t *ent, const char *name ) -{ - int i; - cmodel_t *mod; - vec3_t angles; - - i = SV_ModelIndex( name ); - if( i == 0 ) return; - ent->progs.sv->model = PRVM_SetEngineString( sv.configstrings[CS_MODELS+i] ); - ent->progs.sv->modelindex = i; - - mod = pe->RegisterModel( name ); - if( mod ) SV_SetMinMaxSize( ent, mod->mins, mod->maxs, false ); - - switch( (int)ent->progs.sv->movetype ) - { - case MOVETYPE_PHYSIC: - // FIXME: translate angles correctly - angles[0] = ent->progs.sv->angles[0] - 180; - angles[1] = ent->progs.sv->angles[1]; - angles[2] = ent->progs.sv->angles[2] - 90; - break; - case MOVETYPE_NONE: - case MOVETYPE_PUSH: - case MOVETYPE_CONVEYOR: - VectorClear( angles ); - ent->progs.sv->mass = 0.0f; - break; - } - - Matrix3x3_FromAngles( angles, ent->progs.sv->m_pmatrix ); - Matrix3x3_Transpose( ent->progs.sv->m_pmatrix, ent->progs.sv->m_pmatrix ); - SV_CreatePhysBody( ent ); -} - -float SV_AngleMod( float ideal, float current, float speed ) -{ - float move; - - if (current == ideal) // already there? - return anglemod( current ); - - move = ideal - current; - if (ideal > current) - { - if (move >= 180) move = move - 360; - } - else - { - if (move <= -180) move = move + 360; - } - if (move > 0) - { - if (move > speed) move = speed; - } - else - { - if (move < -speed) move = -speed; - } - return anglemod(current + move); -} - -void SV_ConfigString( int index, const char *val ) -{ - if(index < 0 || index >= MAX_CONFIGSTRINGS) - Host_Error ("configstring: bad index %i value %s\n", index, val); - - if(!*val) val = ""; - - // change the string in sv - com.strcpy( sv.configstrings[index], val ); - - if( sv.state != ss_loading ) - { - // send the update to everyone - MSG_Clear( &sv.multicast ); - MSG_Begin(svc_configstring); - MSG_WriteShort (&sv.multicast, index); - MSG_WriteString (&sv.multicast, (char *)val); - MSG_Send(MSG_ALL_R, vec3_origin, NULL ); - } -} - -bool SV_EntitiesIn( bool mode, vec3_t v1, vec3_t v2 ) -{ - int leafnum, cluster; - int area1, area2; - byte *mask; - - leafnum = pe->PointLeafnum (v1); - cluster = pe->LeafCluster (leafnum); - area1 = pe->LeafArea (leafnum); - if( mode == DVIS_PHS ) mask = pe->ClusterPHS( cluster ); - else if( mode == DVIS_PVS ) mask = pe->ClusterPVS( cluster ); - else Host_Error( "SV_EntitiesIn: unsupported mode\n" ); - - leafnum = pe->PointLeafnum (v2); - cluster = pe->LeafCluster (leafnum); - area2 = pe->LeafArea (leafnum); - - if( mask && (!(mask[cluster>>3] & (1<<(cluster&7))))) - return false; - else if (!pe->AreasConnected (area1, area2)) - return false; - return true; -} - -/* -============ -Save\Load gamestate - -savegame operations -============ -*/ -static int s_table; - -void SV_AddSaveLump( wfile_t *f, const char *lumpname, void *data, size_t len, bool compress ) -{ - if( f ) WAD_Write( f, lumpname, data, len, TYPE_BINDATA, ( compress ? CMP_ZLIB : CMP_NONE )); -} - -static void SV_SetPair( const char *name, const char *value, dkeyvalue_t *cvars, int *numpairs ) -{ - if( !name || !value ) return; // SetString can't register null strings - cvars[*numpairs].epair[DENT_KEY] = StringTable_SetString( s_table, name ); - cvars[*numpairs].epair[DENT_VAL] = StringTable_SetString( s_table, value); - (*numpairs)++; // increase epairs -} - -void SV_AddCvarLump( wfile_t *f ) -{ - dkeyvalue_t cvbuffer[MAX_FIELDS]; - int numpairs = 0; - - Cvar_LookupVars( CVAR_LATCH, cvbuffer, &numpairs, SV_SetPair ); - SV_AddSaveLump( f, LUMP_GAMECVARS, cvbuffer, numpairs * sizeof(dkeyvalue_t), true ); -} - -void SV_AddCStrLump( wfile_t *f ) -{ - string_t csbuffer[MAX_CONFIGSTRINGS]; - int i; - - // pack the cfg string data - for( i = 0; i < MAX_CONFIGSTRINGS; i++ ) - csbuffer[i] = StringTable_SetString( s_table, sv.configstrings[i] ); - SV_AddSaveLump( f, LUMP_CFGSTRING, &csbuffer, sizeof(csbuffer), true ); -} - -void SV_WriteGlobal( wfile_t *f ) -{ - dkeyvalue_t globals[MAX_FIELDS]; - int numpairs = 0; - - SV_VM_Begin(); - PRVM_ED_WriteGlobals( &globals, &numpairs, SV_SetPair ); - SV_VM_End(); - - SV_AddSaveLump( f, LUMP_GAMESTATE, &globals, numpairs * sizeof(dkeyvalue_t), true ); -} - -void SV_WriteLocals( wfile_t *f ) -{ - dkeyvalue_t fields[MAX_FIELDS]; - vfile_t *h = VFS_Open( NULL, "wb" ); - int i, numpairs = 0; - - SV_VM_Begin(); - for( i = 0; i < prog->num_edicts; i++ ) - { - numpairs = 0; // reset fields info - PRVM_ED_Write( PRVM_EDICT_NUM( i ), &fields, &numpairs, SV_SetPair ); - VFS_Write( h, &numpairs, sizeof( int )); // numfields - VFS_Write( h, &fields, numpairs * sizeof( dkeyvalue_t )); // fields - } - SV_VM_End(); - - // all allocated memory will be freed at end of SV_WriteSaveFile - SV_AddSaveLump( f, LUMP_GAMEENTS, VFS_GetBuffer( h ), VFS_Tell( h ), true ); - VFS_Close( h ); // release virtual file -} - -/* -============= -SV_WriteSaveFile -============= -*/ -void SV_WriteSaveFile( const char *name ) -{ - string comment; - wfile_t *savfile = NULL; - bool autosave = false; - char path[MAX_SYSPATH]; - byte *portalstate = Z_Malloc( MAX_MAP_AREAPORTALS ); - int portalsize; - - if( sv.state != ss_active ) - return; - - if(Cvar_VariableValue("deathmatch") || Cvar_VariableValue("coop")) - { - MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame in a multiplayer\n"); - return; - } - if(Host_MaxClients() == 1 && svs.clients[0].edict->progs.sv->health <= 0 ) - { - MsgDev(D_ERROR, "SV_WriteSaveFile: can't savegame while dead!\n"); - return; - } - - if(!com.strcmp(name, "save0.bin")) autosave = true; - com.sprintf( path, "save/%s", name ); - savfile = WAD_Open( path, "wb" ); - - if( !savfile ) - { - MsgDev(D_ERROR, "SV_WriteSaveFile: failed to open %s\n", path ); - return; - } - - MsgDev( D_INFO, "Saving game..." ); - com.sprintf (comment, "%s - %s", sv.configstrings[CS_NAME], timestamp( TIME_FULL )); - s_table = StringTable_Create( name, 0x10000 ); // 65535 unique strings - - // write lumps - pe->GetAreaPortals( &portalstate, &portalsize ); - SV_AddSaveLump( savfile, LUMP_AREASTATE, portalstate, portalsize, true ); - SV_AddSaveLump( savfile, LUMP_COMMENTS, comment, sizeof(comment), false ); - SV_AddSaveLump( savfile, LUMP_MAPCMDS, svs.mapcmd, sizeof(svs.mapcmd), false ); - SV_AddCStrLump( savfile ); - SV_AddCvarLump( savfile ); - SV_WriteGlobal( savfile ); - SV_WriteLocals( savfile ); - StringTable_Save( s_table, savfile ); // now system released - Mem_Free( portalstate ); // release portalinfo - WAD_Close( savfile ); - - MsgDev( D_INFO, "done.\n" ); -} - -void Sav_LoadComment( wfile_t *l ) -{ - byte *in; - int size; - - in = WAD_Read( l, LUMP_COMMENTS, &size, TYPE_BINDATA ); - com.strncpy( svs.comment, in, size ); -} - -void Sav_LoadCvars( wfile_t *l ) -{ - dkeyvalue_t *in; - int i, numpairs; - const char *name, *value; - - in = (dkeyvalue_t *)WAD_Read( l, LUMP_GAMECVARS, &numpairs, TYPE_BINDATA ); - if( numpairs % sizeof(*in)) Host_Error( "Sav_LoadCvars: funny lump size\n" ); - numpairs /= sizeof( dkeyvalue_t ); - - for( i = 0; i < numpairs; i++ ) - { - name = StringTable_GetString( s_table, in[i].epair[DENT_KEY] ); - value = StringTable_GetString( s_table, in[i].epair[DENT_VAL] ); - Cvar_SetLatched( name, value ); - } -} - -void Sav_LoadMapCmds( wfile_t *l ) -{ - byte *in; - int size; - - in = WAD_Read( l, LUMP_MAPCMDS, &size, TYPE_BINDATA ); - com.strncpy( svs.mapcmd, in, size ); -} - -void Sav_LoadCfgString( wfile_t *l ) -{ - string_t *in; - int i, numstrings; - - in = (string_t *)WAD_Read( l, LUMP_CFGSTRING, &numstrings, TYPE_BINDATA ); - if( numstrings % sizeof(*in)) Host_Error( "Sav_LoadCfgString: funny lump size\n" ); - numstrings /= sizeof( string_t ); // because old saves can contain last values of MAX_CONFIGSTRINGS - - // unpack the cfg string data - for( i = 0; i < numstrings; i++ ) - com.strncpy( sv.configstrings[i], StringTable_GetString( s_table, in[i] ), CS_SIZE ); -} - -void Sav_LoadAreaPortals( wfile_t *l ) -{ - byte *in; - int size; - - in = WAD_Read( l, LUMP_AREASTATE, &size, TYPE_BINDATA ); - pe->SetAreaPortals( in, size ); // CM_ReadPortalState -} - -void Sav_LoadGlobal( wfile_t *l ) -{ - dkeyvalue_t *globals; - int numpairs; - - globals = (dkeyvalue_t *)WAD_Read( l, LUMP_GAMESTATE, &numpairs, TYPE_BINDATA ); - if( numpairs % sizeof(*globals)) Host_Error( "Sav_LoadGlobal: funny lump size\n" ); - numpairs /= sizeof( dkeyvalue_t ); - PRVM_ED_ReadGlobals( s_table, globals, numpairs ); -} - -void Sav_LoadLocals( wfile_t *l ) -{ - dkeyvalue_t fields[MAX_FIELDS]; - int numpairs, entnum = 0; - byte *buff; - size_t size; - vfile_t *h; - - buff = WAD_Read( l, LUMP_GAMEENTS, &size, TYPE_BINDATA ); - h = VFS_Create( buff, size ); - - while(!VFS_Eof( h )) - { - VFS_Read( h, &numpairs, sizeof( int )); - VFS_Read( h, &fields, numpairs * sizeof( dkeyvalue_t )); - PRVM_ED_Read( s_table, entnum, fields, numpairs ); - entnum++; - } - prog->num_edicts = entnum; -} - -/* -============= -SV_ReadSaveFile -============= -*/ -void SV_ReadSaveFile( const char *name ) -{ - char path[MAX_SYSPATH]; - wfile_t *savfile; - int s_table; - - com.sprintf(path, "save/%s", name ); - savfile = WAD_Open( path, "rb" ); - - if( !savfile ) - { - MsgDev(D_ERROR, "SV_ReadSaveFile: can't open %s\n", path ); - return; - } - - s_table = StringTable_Load( savfile, name ); - Sav_LoadComment( savfile ); - Sav_LoadCvars( savfile ); - StringTable_Delete( s_table ); - - SV_InitGame(); // start a new game fresh with new cvars - Sav_LoadMapCmds( savfile ); - WAD_Close( savfile ); - CL_Drop(); -} - -/* -============= -SV_ReadLevelFile -============= -*/ -void SV_ReadLevelFile( const char *name ) -{ - char path[MAX_SYSPATH]; - wfile_t *savfile; - int s_table; - - com.sprintf (path, "save/%s", name ); - savfile = WAD_Open( path, "rb" ); - - if( !savfile ) - { - MsgDev( D_ERROR, "SV_ReadLevelFile: can't open %s\n", path ); - return; - } - - s_table = StringTable_Load( savfile, name ); - Sav_LoadCfgString( savfile ); - Sav_LoadAreaPortals( savfile ); - Sav_LoadGlobal( savfile ); - Sav_LoadLocals( savfile ); - StringTable_Delete( s_table ); - WAD_Close( savfile ); -} - -bool SV_ReadComment( char *comment, int savenum ) -{ - wfile_t *savfile; - int result; - - if( !comment ) return false; - result = WAD_Check( va( "save/save%i.bin", savenum )); - - switch( result ) - { - case 0: - com.strncpy( comment, "", MAX_STRING ); - return false; - case 1: break; - default: - com.strncpy( comment, "", MAX_STRING ); - return false; - } - - savfile = WAD_Open( va("save/save%i.bin", savenum), "rb" ); - Sav_LoadComment( savfile ); - com.strncpy( comment, svs.comment, MAX_STRING ); - WAD_Close( savfile ); - - return true; -} - void SV_BeginIncreaseEdicts( void ) { int i; edict_t *ent; // links don't survive the transition, so unlink everything - for( i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++ ) + for( i = 0, ent = svg.edicts; i < svs.globals->maxEntities; i++, ent++ ) { - if( !ent->priv.sv->free ) SV_UnlinkEdict( prog->edicts + i ); // free old entity - Mem_Set( &ent->priv.sv->clusternums, 0, sizeof( ent->priv.sv->clusternums )); + if( !ent->free ) SV_UnlinkEdict( svg.edicts + i ); // free old entity + Mem_Set( &ent->pvEngineData->clusternums, 0, sizeof( ent->pvEngineData->clusternums )); } SV_ClearWorld(); } @@ -620,91 +28,13 @@ void SV_EndIncreaseEdicts(void) int i; edict_t *ent; - for( i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++ ) + for( i = 0, ent = svg.edicts; i < svs.globals->maxEntities; i++, ent++ ) { // link every entity except world - if( !ent->priv.sv->free ) SV_LinkEdict(ent); + if( !ent->free ) SV_LinkEdict(ent); } } -/* -================= -SV_InitEdict - -Alloc new edict from list -================= -*/ -void SV_InitEdict (edict_t *e) -{ - e->priv.sv->serialnumber = PRVM_NUM_FOR_EDICT(e); -} - -/* -================= -SV_FreeEdict - -Marks the edict as free -================= -*/ -void SV_FreeEdict( edict_t *ed ) -{ - // unlink from world - SV_UnlinkEdict( ed ); - pe->RemoveBody( ed->priv.sv->physbody ); - - Mem_Set( ed->priv.sv, 0, sizeof( sv_edict_t )); - Mem_Set( ed->progs.sv, 0, sizeof( sv_entvars_t )); - - // mark edict as freed - ed->priv.sv->freetime = sv.time; - ed->priv.sv->free = true; - ed->progs.sv->nextthink = -1; -} - -void SV_CountEdicts( void ) -{ - edict_t *ent; - int i, active = 0, models = 0, solid = 0, step = 0; - - for (i = 0; i < prog->num_edicts; i++) - { - ent = PRVM_EDICT_NUM(i); - if (ent->priv.sv->free) continue; - active++; - if (ent->progs.sv->solid) solid++; - if (ent->progs.sv->model) models++; - if (ent->progs.sv->movetype == MOVETYPE_STEP) step++; - } - - Msg("num_edicts:%3i\n", prog->num_edicts); - Msg("active :%3i\n", active); - Msg("view :%3i\n", models); - Msg("touch :%3i\n", solid); - Msg("step :%3i\n", step); -} - -bool SV_LoadEdict( edict_t *ent ) -{ - int current_skill = (int)Cvar_VariableValue("skill"); - - // remove things from different skill levels or deathmatch - if(Cvar_VariableValue ("deathmatch")) - { - if( (int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) - return false; - } - else if(current_skill <= 0 && (int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_EASY ) - return false; - else if(current_skill == 1 && (int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_MEDIUM) - return false; - else if(current_skill >= 2 && (int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_HARD ) - return false; - - // apply edict classname - ent->priv.sv->s.classname = SV_ClassIndex(PRVM_GetString( ent->progs.sv->classname )); - return true; -} - void SV_RestoreEdict( edict_t *ent ) { // link it into the bsp tree @@ -713,2061 +43,6 @@ void SV_RestoreEdict( edict_t *ent ) SV_SetPhysForce( ent ); // restore forces ... SV_SetMassCentre( ent ); // and mass force - if( ent->progs.sv->loopsound ) // restore loopsound - ent->priv.sv->s.soundindex = SV_SoundIndex(PRVM_GetString(ent->progs.sv->loopsound)); -} - -void SV_ParseKeyValue( edict_t *ent, const char *key, const char *value ) -{ - prog->globals.sv->pev = PRVM_EDICT_TO_PROG( ent ); - PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString( key ); - PRVM_G_INT(OFS_PARM1) = PRVM_SetEngineString( value ); - PRVM_ExecuteProgram (prog->globals.sv->KeyValue, "KeyValue" ); -} - -void SV_VM_Begin( void ) -{ - PRVM_Begin; - PRVM_SetProg( PRVM_SERVERPROG ); - - if( prog ) *prog->time = sv.time; -} - -void SV_VM_End( void ) -{ - PRVM_End; -} - - - -/* -=============================================================================== -Game Builtin Functions - -mathlib, debugger, and various misc helpers -=============================================================================== -*/ -/* -========= -PF_precache_model - -float precache_model( string s ) -========= -*/ -void PF_precache_model( void ) -{ - if(!VM_ValidateArgs( "precache_model", 1 )) - return; - - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = SV_ModelIndex(PRVM_G_STRING(OFS_PARM0)); -} - -/* -========= -PF_precache_sound - -float precache_sound( string s ) -========= -*/ -void PF_precache_sound( void ) -{ - if(!VM_ValidateArgs( "precache_sound", 1 )) - return; - - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = SV_SoundIndex(PRVM_G_STRING(OFS_PARM0)); -} - -/* -================= -PF_setmodel - -float setmodel( entity ent, string m ) -================= -*/ -void PF_setmodel( void ) -{ - edict_t *e; - - if(!VM_ValidateArgs( "setmodel", 2 )) - return; - - e = PRVM_G_EDICT(OFS_PARM0); - if(e == prog->edicts) - { - VM_Warning("setmodel: can't modify world entity\n"); - return; - } - if(e->priv.sv->free) - { - VM_Warning("setmodel: can't modify free entity\n"); - return; - } - - if( PRVM_G_STRING(OFS_PARM1)[0] <= ' ' ) - { - VM_Warning("setmodel: null name\n"); - return; - } - SV_SetModel( e, PRVM_G_STRING(OFS_PARM1)); -} - -/* -================= -PF_model_index - -float model_index( string s ) -================= -*/ -void PF_modelindex( void ) -{ - int index; - - if(!VM_ValidateArgs( "model_index", 1 )) - return; - - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - index = SV_FindIndex( PRVM_G_STRING(OFS_PARM0), CS_MODELS, MAX_MODELS, false ); - - if(!index) VM_Warning("modelindex: %s not precached\n", PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = index; -} - -/* -================= -PF_modelframes - -float model_frames( float modelindex ) -================= -*/ -void PF_modelframes( void ) -{ - cmodel_t *mod; - float framecount = 0.0f; - - if(!VM_ValidateArgs( "model_frames", 1 )) - return; - - // can be returned pointer on a registered model - mod = pe->RegisterModel( sv.configstrings[CS_MODELS + (int)PRVM_G_FLOAT(OFS_PARM0)] ); - - if( mod ) framecount = ( float )mod->numframes; - PRVM_G_FLOAT(OFS_RETURN) = framecount; -} - -/* -================= -PF_setsize - -void setsize( entity e, vector min, vector max ) -================= -*/ -void PF_setsize( void ) -{ - edict_t *e; - float *min, *max; - - if(!VM_ValidateArgs( "setsize", 3 )) - return; - - e = PRVM_G_EDICT(OFS_PARM0); - if(!e) - { - VM_Warning("setsize: entity not exist\n"); - return; - } - else if(e == prog->edicts) - { - VM_Warning("setsize: can't modify world entity\n"); - return; - } - else if(e->priv.sv->free) - { - VM_Warning("setsize: can't modify free entity\n"); - return; - } - - min = PRVM_G_VECTOR(OFS_PARM1); - max = PRVM_G_VECTOR(OFS_PARM2); - SV_SetMinMaxSize( e, min, max, !VectorIsNull(e->progs.sv->angles)); -} - -/* -================= -PF_changelevel - -void changelevel( string mapname, string spotname ) -================= -*/ -void PF_changelevel( void ) -{ - if(!VM_ValidateArgs( "changlevel", 2 )) - return; - - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - Cbuf_ExecuteText(EXEC_APPEND, va("changelevel %s %s\n", PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1))); -} - -/* -================= -PF_vectoyaw - -float vectoyaw( vector ) -================= -*/ -void PF_vectoyaw( void ) -{ - float *value1, yaw; - - if(!VM_ValidateArgs( "vecToYaw", 1 )) - return; - - value1 = PRVM_G_VECTOR(OFS_PARM0); - - if( value1[1] == 0 && value1[0] == 0 ) yaw = 0; - else - { - yaw = (int)(atan2(value1[1], value1[0]) * 180 / M_PI); - if( yaw < 0 ) yaw += 360; - } - PRVM_G_FLOAT(OFS_RETURN) = yaw; -} - - -/* -================= -VM_vectoangles - -vector vectoangles( vector v ) -================= -*/ -void PF_vectoangles( void ) -{ - float *value1, forward; - float yaw, pitch; - - if(!VM_ValidateArgs( "vecToAngles", 1 )) - return; - - value1 = PRVM_G_VECTOR(OFS_PARM0); - - if( value1[1] == 0 && value1[0] == 0 ) - { - yaw = 0; - if( value1[2] > 0 ) pitch = 90; - else pitch = 270; - } - else - { - if( value1[0] ) - { - yaw = (atan2(value1[1], value1[0]) * 180 / M_PI); - if( yaw < 0 ) yaw += 360; - } - else if( value1[1] > 0 ) yaw = 90; - else yaw = 270; - - forward = sqrt(value1[0] * value1[0] + value1[1] * value1[1]); - pitch = (atan2(value1[2], forward) * 180 / M_PI); - if( pitch < 0 ) pitch += 360; - } - VectorSet( PRVM_G_VECTOR(OFS_RETURN), pitch, yaw, 0 ); -} - -/* -============== -PF_changeyaw - -void ChangeYaw( void ) -============== -*/ -void PF_changeyaw( void ) -{ - edict_t *ent; - float current; - - if(!VM_ValidateArgs( "ChangeYaw", 0 )) - return; - - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - if( ent == prog->edicts ) - { - VM_Warning("changeyaw: can't modify world entity\n"); - return; - } - if( ent->priv.sv->free ) - { - VM_Warning("changeyaw: can't modify free entity\n"); - return; - } - - current = anglemod( ent->progs.sv->angles[1] ); - ent->progs.sv->angles[1] = SV_AngleMod( ent->progs.sv->ideal_yaw, current, ent->progs.sv->yaw_speed ); -} - -/* -============== -PF_changepitch - -void ChangePitch( void ) -============== -*/ -void PF_changepitch( void ) -{ - edict_t *ent; - float ideal_pitch = 30.0f; // constant - - if(!VM_ValidateArgs( "ChangePitch", 0 )) - return; - - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - if( ent == prog->edicts ) - { - VM_Warning("ChangePitch: can't modify world entity\n"); - return; - } - if (ent->priv.sv->free) - { - VM_Warning("changepitch: can't modify free entity\n"); - return; - } - ent->progs.sv->angles[0] = SV_AngleMod( ideal_pitch, anglemod(ent->progs.sv->angles[0]), ideal_pitch ); -} - -/* -============== -PF_getlightlevel - -float getEntityIllum( entity e ) -============== -*/ -void PF_getlightlevel( void ) -{ - edict_t *ent; - - if(!VM_ValidateArgs( "getEntityIllum", 1 )) return; - ent = PRVM_G_EDICT(OFS_PARM0); - - if(ent == prog->edicts) - { - VM_Warning("getlightlevel: can't get light level at world entity\n"); - return; - } - if(ent->priv.sv->free) - { - VM_Warning("getlightlevel: can't get light level at free entity\n"); - return; - } - - PRVM_G_FLOAT(OFS_RETURN) = 1.0; //FIXME: implement -} - -/* -================= -PF_findradius - -entity FindInSphere( vector org, float rad ) -================= -*/ -void PF_findradius( void ) -{ - edict_t *ent, *chain; - vec_t radius, radius2; - vec3_t org, eorg; - int i; - - if(!VM_ValidateArgs( "FindInSphere", 2 )) return; - VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); - radius = PRVM_G_FLOAT(OFS_PARM1); - radius2 = radius * radius; - chain = (edict_t *)prog->edicts; - - ent = prog->edicts; - for( i = 1; i < prog->num_edicts ; i++, ent = PRVM_NEXT_EDICT(ent)) - { - if(ent->priv.sv->free) continue; - if(ent->progs.sv->solid == SOLID_NOT) continue; - VectorSubtract(org, ent->progs.sv->origin, eorg); - VectorMAMAM( 1, eorg, 0.5f, ent->progs.sv->mins, 0.5f, ent->progs.sv->maxs, eorg ); - - if(DotProduct(eorg, eorg) < radius2) - { - ent->progs.sv->chain = PRVM_EDICT_TO_PROG(chain); - chain = ent; - } - } - VM_RETURN_EDICT( chain ); // fisrt chain -} - -/* -================= -PF_inpvs - -entity EntitiesInPVS( entity ent, float player ) -================= -*/ -void PF_inpvs( void ) -{ - edict_t *ent, *chain; - edict_t *pvsent; - bool playeronly; - int i, numents; - - if(!VM_ValidateArgs( "EntitiesInPVS", 2 )) return; - pvsent = PRVM_G_EDICT(OFS_PARM0); - playeronly = (bool)PRVM_G_FLOAT(OFS_PARM1); - chain = (edict_t *)prog->edicts; - - if( playeronly ) - { - numents = prog->reserved_edicts; - ent = prog->edicts, i = 1; - } - else - { - numents = prog->num_edicts - prog->reserved_edicts; - ent = prog->edicts + prog->reserved_edicts; - i = prog->reserved_edicts; - } - - if( playeronly ) Msg("FindClientInPVS: startent %d, numents %d\n", i, numents ); - else Msg("FindEntitiesInPVS: startent %d, numents %d\n", i, numents ); - - for(; i < numents; i++, ent = PRVM_NEXT_EDICT(ent)) - { - if( ent->priv.sv->free ) continue; - if(SV_EntitiesIn( DVIS_PVS, pvsent->progs.sv->origin, ent->progs.sv->origin )) - { - Msg("found entity %d\n", ent->priv.sv->serialnumber ); - ent->progs.sv->chain = PRVM_EDICT_TO_PROG(chain); - chain = ent; - } - } - VM_RETURN_EDICT( chain ); // fisrt chain -} - -/* -================= -PF_inphs - -entity EntitiesInPHS( entity ent, float player ) -================= -*/ -void PF_inphs( void ) -{ - edict_t *ent, *chain; - edict_t *pvsent; - bool playeronly; - int i, numents; - - if(!VM_ValidateArgs( "EntitiesInPHS", 2 )) return; - pvsent = PRVM_G_EDICT(OFS_PARM0); - playeronly = (bool)PRVM_G_FLOAT(OFS_PARM1); - chain = (edict_t *)prog->edicts; - - if( playeronly ) - { - numents = prog->reserved_edicts; - ent = prog->edicts, i = 1; - } - else - { - numents = prog->num_edicts - prog->reserved_edicts; - ent = prog->edicts + prog->reserved_edicts; - i = prog->reserved_edicts; - } - - if( playeronly ) Msg("FindClientInPHS: startent %d, numents %d\n", i, numents ); - else Msg("FindEntitiesInPHS: startent %d, numents %d\n", i, numents ); - - for(; i < numents; i++, ent = PRVM_NEXT_EDICT(ent)) - { - if( ent->priv.sv->free ) continue; - if(SV_EntitiesIn( DVIS_PHS, pvsent->progs.sv->origin, ent->progs.sv->origin )) - { - Msg("found entity %d\n", ent->priv.sv->serialnumber ); - ent->progs.sv->chain = PRVM_EDICT_TO_PROG(chain); - chain = ent; - } - } - VM_RETURN_EDICT( chain ); // fisrt chain -} - -/* -============== -PF_makevectors - -void makevectors( vector dir, float hand ) -============== -*/ -void PF_makevectors( void ) -{ - float *v1; - - if(!VM_ValidateArgs( "makevectors", 2 )) - return; - - v1 = PRVM_G_VECTOR(OFS_PARM0); - if(PRVM_G_FLOAT(OFS_PARM1)) // left-handed coords - AngleVectorsFLU( v1, prog->globals.sv->v_forward, prog->globals.sv->v_right, prog->globals.sv->v_up); - else AngleVectors( v1, prog->globals.sv->v_forward, prog->globals.sv->v_right, prog->globals.sv->v_up); -} - -/* -============== -PF_create - -entity CreateNamedEntity( string classname, vector org, vector ang ) -============== -*/ -void PF_create( void ) -{ - edict_t *ed; - mfunction_t *func, *oldf; - - if(!VM_ValidateArgs( "CreateNamedEntity", 3 )) - return; - - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - prog->xfunction->builtinsprofile += 20; - ed = PRVM_ED_Alloc(); - - VectorCopy( PRVM_G_VECTOR(OFS_PARM1), ed->progs.sv->origin ); - VectorCopy( PRVM_G_VECTOR(OFS_PARM2), ed->progs.sv->angles ); - - // look for the spawn function - func = PRVM_ED_FindFunction(PRVM_G_STRING(OFS_PARM0)); - - if(!func) - { - Host_Error("CreateNamedEntity: no spawn function for: %s\n", PRVM_G_STRING(OFS_PARM0)); - return; - } - - PRVM_PUSH_GLOBALS; - oldf = prog->xfunction; - - PRVM_G_INT( prog->pev->ofs) = PRVM_EDICT_TO_PROG( ed ); - PRVM_ExecuteProgram( func - prog->functions, "" ); - - PRVM_POP_GLOBALS; - prog->xfunction = oldf; - - VM_RETURN_EDICT( ed ); -} - -/* -============= -PF_makestatic - -void makestatic( entity e ) -============= -*/ -void PF_makestatic( void ) -{ - if(!VM_ValidateArgs( "makestatic", 1 )) - return; - - // FIXME: implement -} - -/* -=============== -PF_droptofloor - -void droptofloor( void ) -=============== -*/ -void PF_droptofloor( void ) -{ - edict_t *ent; - vec3_t end; - trace_t trace; - - if( !VM_ValidateArgs( "droptofloor", 0 )) return; - PRVM_G_FLOAT(OFS_RETURN) = 0; // assume failure if it returns early - ent = PRVM_PROG_TO_EDICT(prog->globals.sv->pev); - - if( ent == prog->edicts ) - { - VM_Warning("droptofloor: can't modify world entity\n"); - return; - } - if (ent->priv.sv->free) - { - VM_Warning("droptofloor: can't modify free entity\n"); - return; - } - - VectorCopy( ent->progs.sv->origin, end ); - end[2] -= 256; - SV_UnstickEntity( ent ); - - trace = SV_Trace( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, MOVE_NORMAL, ent, SV_ContentsMask( ent )); - - if( trace.startsolid ) - { - vec3_t offset, org; - VectorSet( offset, 0.5f * (ent->progs.sv->mins[0] + ent->progs.sv->maxs[0]), 0.5f * (ent->progs.sv->mins[1] + ent->progs.sv->maxs[1]), ent->progs.sv->mins[2]); - VectorAdd( ent->progs.sv->origin, offset, org ); - trace = SV_Trace( org, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, SV_ContentsMask( ent )); - VectorSubtract( trace.endpos, offset, trace.endpos ); - if( trace.startsolid ) - { - VM_Warning( "droptofloor: startsolid at %g %g %g\n", ent->progs.sv->origin[0], ent->progs.sv->origin[1], ent->progs.sv->origin[2] ); - SV_UnstickEntity( ent ); - SV_LinkEdict( ent ); - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = 0; - PRVM_G_FLOAT(OFS_RETURN) = 1; - } - else if( trace.fraction < 1 ) - { - VM_Warning( "droptofloor moved to %g %g %g\n", ent->progs.sv->origin[0], ent->progs.sv->origin[1], ent->progs.sv->origin[2] ); - VectorCopy( trace.endpos, ent->progs.sv->origin ); - SV_UnstickEntity( ent ); - SV_LinkEdict( ent ); - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( trace.ent ); - PRVM_G_FLOAT(OFS_RETURN) = 1; - // if support is destroyed, keep suspended (gross hack for floating items in various maps) - ent->priv.sv->suspended = true; - } - - VM_Warning( "droptofloor: startsolid at %g %g %g\n", ent->progs.sv->origin[0], ent->progs.sv->origin[1], ent->progs.sv->origin[2] ); - SV_FreeEdict( ent ); - return; - } - else - { - if( trace.fraction != 1 ) - { - if( trace.fraction < 1 ) VectorCopy( trace.endpos, ent->progs.sv->origin ); - SV_LinkEdict( ent ); - ent->progs.sv->aiflags = (int)ent->progs.sv->aiflags | AI_ONGROUND; - ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG( trace.ent ); - PRVM_G_FLOAT(OFS_RETURN) = 1; - // if support is destroyed, keep suspended (gross hack for floating items in various maps) - ent->priv.sv->suspended = true; - } - } -} - -/* -=============== -PF_walkmove - -float walkmove( float yaw, float dist, float settrace ) -=============== -*/ -void PF_walkmove( void ) -{ - edict_t *ent; - float yaw, dist; - vec3_t move; - mfunction_t *oldf; - int oldpev; - bool settrace; - - if(!VM_ValidateArgs( "walkmove", 3 )) return; - PRVM_G_FLOAT(OFS_RETURN) = 0; // assume failure if it returns early - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - - if (ent == prog->edicts) - { - VM_Warning("walkmove: can't modify world entity\n"); - return; - } - if (ent->priv.sv->free) - { - VM_Warning("walkmove: can't modify free entity\n"); - return; - } - - yaw = PRVM_G_FLOAT(OFS_PARM0); - dist = PRVM_G_FLOAT(OFS_PARM1); - settrace = (int)PRVM_G_FLOAT(OFS_PARM2); - - if(!((int)ent->progs.sv->aiflags & (AI_ONGROUND|AI_FLY|AI_SWIM))) - return; - yaw = yaw * M_PI*2 / 360; - - VectorSet( move, (cos(yaw) * dist), (sin(yaw) * dist), 0.0f ); - - // save program state, because SV_MoveStep may call other progs - oldf = prog->xfunction; - oldpev = prog->globals.sv->pev; - - PRVM_G_FLOAT(OFS_RETURN) = SV_movestep( ent, move, true, false, settrace ); - - // restore program state - prog->xfunction = oldf; - prog->globals.sv->pev = oldpev; -} - -/* -================= -PF_setorigin - -void setorigin( entity e, vector org ) -================= -*/ -void PF_setorigin( void ) -{ - edict_t *e; - - if(!VM_ValidateArgs( "setorigin", 2 )) return; - e = PRVM_G_EDICT(OFS_PARM0); - if (e == prog->edicts) - { - VM_Warning("setorigin: can't modify world entity\n"); - return; - } - if (e->priv.sv->free) - { - VM_Warning("setorigin: can't modify free entity\n"); - return; - } - - VectorCopy( PRVM_G_VECTOR(OFS_PARM1), e->progs.sv->origin ); - pe->SetOrigin( e->priv.sv->physbody, e->progs.sv->origin ); - SV_LinkEdict( e ); -} - -/* -================= -PF_setangles - -void setangles( entity e, vector ang ) -================= -*/ -void PF_setangles( void ) -{ - edict_t *e; - - if(!VM_ValidateArgs( "setangles", 2 )) return; - e = PRVM_G_EDICT(OFS_PARM0); - if (e == prog->edicts) - { - VM_Warning("setangles: can't modify world entity\n"); - return; - } - if (e->priv.sv->free) - { - VM_Warning("setangles: can't modify free entity\n"); - return; - } - - VectorCopy( PRVM_G_VECTOR(OFS_PARM1), e->progs.sv->angles ); - Matrix3x3_FromAngles( e->progs.sv->angles, e->progs.sv->m_pmatrix ); - Matrix3x3_Transpose( e->progs.sv->m_pmatrix, e->progs.sv->m_pmatrix ); -} - -/* -================= -PF_traceline - -void traceline( vector v1, vector v2, float move, entity ignore ) -================= -*/ -void PF_traceline( void ) -{ - float *v1, *v2; - trace_t trace; - int move; - edict_t *ent; - - if(!VM_ValidateArgs( "traceline", 4 )) return; - prog->xfunction->builtinsprofile += 30; - - v1 = PRVM_G_VECTOR(OFS_PARM0); - v2 = PRVM_G_VECTOR(OFS_PARM1); - move = (int)PRVM_G_FLOAT(OFS_PARM2); - ent = PRVM_G_EDICT(OFS_PARM3); - - if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2])) - PRVM_ERROR("%s: NAN errors detected in traceline('%f %f %f', '%f %f %f', %i, entity %i)\n", - PRVM_NAME, v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); - - trace = SV_Trace( v1, vec3_origin, vec3_origin, v2, move, ent, SV_ContentsMask(ent)); - - VM_SetTraceGlobals( &trace ); -} - -/* -================= -PF_tracetoss - -void tracetoss( entity e, entity ignore ) -================= -*/ -void PF_tracetoss( void ) -{ - trace_t trace; - edict_t *ent; - edict_t *ignore; - - if(!VM_ValidateArgs( "tracetoss", 2 )) return; - prog->xfunction->builtinsprofile += 600; - - ent = PRVM_G_EDICT(OFS_PARM0); - if (ent == prog->edicts) - { - VM_Warning("tracetoss: can not use world entity\n"); - return; - } - ignore = PRVM_G_EDICT(OFS_PARM1); - - trace = SV_TraceToss( ent, ignore ); - - prog->globals.sv->trace_allsolid = trace.allsolid; - prog->globals.sv->trace_startsolid = trace.startsolid; - prog->globals.sv->trace_fraction = trace.fraction; - prog->globals.sv->trace_contents = trace.contents; - - VectorCopy (trace.endpos, prog->globals.sv->trace_endpos); - VectorCopy (trace.plane.normal, prog->globals.sv->trace_plane_normal); - prog->globals.sv->trace_plane_dist = trace.plane.dist; - if (trace.ent) prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); - else prog->globals.sv->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); -} - -/* -================= -PF_tracebox - -void tracebox( vector v1, vector mins, vector maxs, vector v2, float move, entity ignore ) -================= -*/ -void PF_tracebox( void ) -{ - float *v1, *v2, *m1, *m2; - trace_t trace; - int move; - edict_t *ent; - - if(!VM_ValidateArgs( "tracebox", 6 )) return; - prog->xfunction->builtinsprofile += 30; - - v1 = PRVM_G_VECTOR(OFS_PARM0); - m1 = PRVM_G_VECTOR(OFS_PARM1); - m2 = PRVM_G_VECTOR(OFS_PARM2); - v2 = PRVM_G_VECTOR(OFS_PARM3); - move = (int)PRVM_G_FLOAT(OFS_PARM4); - ent = PRVM_G_EDICT(OFS_PARM5); - - if (IS_NAN(v1[0]) || IS_NAN(v1[1]) || IS_NAN(v1[2]) || IS_NAN(v2[0]) || IS_NAN(v1[2]) || IS_NAN(v2[2])) - PRVM_ERROR("%s: NAN errors detected in tracebox('%f %f %f', '%f %f %f', '%f %f %f', '%f %f %f', %i, entity %i)\n", - PRVM_NAME, v1[0], v1[1], v1[2], m1[0], m1[1], m1[2], m2[0], m2[1], m2[2], v2[0], v2[1], v2[2], move, PRVM_EDICT_TO_PROG(ent)); - - trace = SV_Trace( v1, m1, m2, v2, move, ent, SV_ContentsMask( ent )); - - VM_SetTraceGlobals( &trace ); -} - -/* -============= -PF_lookupactivity - -float LookupActivity( string model, float activity ) -============= -*/ -void PF_lookupactivity( void ) -{ - cmodel_t *mod; - dstudioseqdesc_t *pseqdesc; - dstudiohdr_t *pstudiohdr; - int i, seq = -1; - int activity, weighttotal = 0; - - if(!VM_ValidateArgs( "LookupActivity", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = 0; - - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - activity = (int)PRVM_G_FLOAT(OFS_PARM1); - - for( i = 0; i < pstudiohdr->numseq; i++) - { - if( pseqdesc[i].activity == activity ) - { - weighttotal += pseqdesc[i].actweight; - if( !weighttotal || RANDOM_LONG( 0, weighttotal - 1 ) < pseqdesc[i].actweight ) - seq = i; - } - } - PRVM_G_FLOAT(OFS_RETURN) = seq; -} - -/* -============= -PF_lookupactivity - -float LookupActivityHeaviest( string model, float activity ) -============= -*/ -void PF_lookupactivityheaviest( void ) -{ - cmodel_t *mod; - dstudioseqdesc_t *pseqdesc; - dstudiohdr_t *pstudiohdr; - int i, seq = -1; - int activity, weight = 0; - - if(!VM_ValidateArgs( "LookupActivityHeaviest", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = 0; - - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - activity = (int)PRVM_G_FLOAT(OFS_PARM1); - - for( i = 0; i < pstudiohdr->numseq; i++ ) - { - if( pseqdesc[i].activity == activity ) - { - if( pseqdesc[i].actweight > weight ) - { - weight = pseqdesc[i].actweight; - seq = i; - } - } - } - PRVM_G_FLOAT(OFS_RETURN) = seq; -} - -/* -============= -PF_geteyepos - -vector GetEyePosition( string model ) -============= -*/ -void PF_geteyepos( void ) -{ - cmodel_t *mod; - dstudiohdr_t *pstudiohdr; - - if(!VM_ValidateArgs( "GetEyePosition", 1 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - VectorCopy( vec3_origin, PRVM_G_VECTOR(OFS_RETURN)); - - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - VectorCopy( pstudiohdr->eyeposition, PRVM_G_VECTOR(OFS_RETURN)); -} - -/* -============= -PF_lookupsequence - -float LookupSequence( string model, string label ) -============= -*/ -void PF_lookupsequence( void ) -{ - cmodel_t *mod; - dstudiohdr_t *pstudiohdr; - dstudioseqdesc_t *pseqdesc; - int i; - - PRVM_G_FLOAT(OFS_RETURN) = -1; - if( !VM_ValidateArgs( "LookupSequence", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex); - for( i = 0; i < pstudiohdr->numseq; i++ ) - { - if(!com.stricmp( pseqdesc[i].label, PRVM_G_STRING(OFS_PARM1))) - { - PRVM_G_FLOAT(OFS_RETURN) = i; - break; - } - } -} - -/* -============= -PF_getsequenceinfo - -float GetSequenceInfo( string model, float sequence ) -============= -*/ -void PF_getsequenceinfo( void ) -{ - cmodel_t *mod; - edict_t *ent; - dstudiohdr_t *pstudiohdr; - dstudioseqdesc_t *pseqdesc; - int sequence; - - if(!VM_ValidateArgs( "GetSequenceInfo", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = 0; - - sequence = (int)PRVM_G_FLOAT(OFS_PARM1); - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - if( sequence >= pstudiohdr->numseq ) - { - ent->progs.sv->m_flFrameRate = 0.0; - ent->progs.sv->m_flGroundSpeed = 0.0; - return; - } - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; - if( pseqdesc->numframes > 1 ) - { - ent->progs.sv->m_flFrameRate = 256.0 * (pseqdesc->fps / (pseqdesc->numframes - 1)); - ent->progs.sv->m_flGroundSpeed = VectorLength( pseqdesc->linearmovement ); - ent->progs.sv->m_flGroundSpeed = ent->progs.sv->m_flGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); - } - else - { - ent->progs.sv->m_flFrameRate = 256.0; - ent->progs.sv->m_flGroundSpeed = 0.0; - } - PRVM_G_FLOAT(OFS_RETURN) = 1; // all done -} - -/* -============= -PF_getweaponsequenceinfo - -float GetWeaponSequenceInfo( string model, float sequence ) -============= -*/ -void PF_getweaponsequenceinfo( void ) -{ - cmodel_t *mod; - edict_t *ent; - dstudiohdr_t *pstudiohdr; - dstudioseqdesc_t *pseqdesc; - int sequence; - - if(!VM_ValidateArgs( "GetWeaponSequenceInfo", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = 0; - - sequence = (int)PRVM_G_FLOAT(OFS_PARM1); - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - if( sequence >= pstudiohdr->numseq ) - { - ent->progs.sv->m_flWeaponFrameRate = 0.0; - return; - } - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; - if( pseqdesc->numframes > 1 ) - { - ent->progs.sv->m_flWeaponFrameRate = 256.0 * (pseqdesc->fps / (pseqdesc->numframes - 1)); - } - else - { - ent->progs.sv->m_flWeaponFrameRate = 256.0; - } - PRVM_G_FLOAT(OFS_RETURN) = 1; // all done -} - -/* -============= -PF_getsequenceflags - -float GetSequenceFlags( string model, float sequence ) -============= -*/ -void PF_getsequenceflags( void ) -{ - cmodel_t *mod; - edict_t *ent; - dstudiohdr_t *pstudiohdr; - dstudioseqdesc_t *pseqdesc; - int sequence; - - if(!VM_ValidateArgs( "GetSequenceFlags", 2 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - PRVM_G_FLOAT(OFS_RETURN) = -1; - - sequence = (int)PRVM_G_FLOAT(OFS_PARM1); - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - if( sequence >= pstudiohdr->numseq ) return; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + sequence; - PRVM_G_FLOAT(OFS_RETURN) = (float )pseqdesc->flags; -} - -/* -============= -PF_setcontroller - -float SetController( string model, float controller, float value ) -============= -*/ -void PF_setcontroller( void ) -{ - cmodel_t *mod; - edict_t *ent; - dstudiohdr_t *pstudiohdr; - dstudiobonecontroller_t *pbonecontroller; - int i, iController; - int setting; - float flValue; - - if(!VM_ValidateArgs( "SetController", 3 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - flValue = PRVM_G_FLOAT(OFS_PARM2); // not modified value - PRVM_G_FLOAT(OFS_RETURN) = flValue; - - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - iController = (int)PRVM_G_FLOAT(OFS_PARM1); - - pbonecontroller = (dstudiobonecontroller_t *)((byte *)pstudiohdr + pstudiohdr->bonecontrollerindex ); - - // find first controller that matches the index - for( i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++ ) - if( pbonecontroller->index == iController ) break; - if( i >= pstudiohdr->numbonecontrollers ) return; - - // wrap 0..360 if it's a rotational controller - if( pbonecontroller->type & (STUDIO_XR|STUDIO_YR|STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if( pbonecontroller->end < pbonecontroller->start) - flValue = -flValue; - - // does the controller not wrap? - if( pbonecontroller->start + 359.0 >= pbonecontroller->end ) - { - if( flValue > ((pbonecontroller->start + pbonecontroller->end) / 2.0f) + 180.0f ) - flValue = flValue - 360.0f; - if( flValue < ((pbonecontroller->start + pbonecontroller->end) / 2.0f) - 180.0f ) - flValue = flValue + 360.0f; - } - else - { - if( flValue > 360.0f ) flValue = flValue - (int)(flValue / 360.0f) * 360.0f; - else if( flValue < 0.0f ) flValue = flValue + (int)((flValue / -360.0f) + 1) * 360.0f; - } - } - - // round to byte - setting = 255 * (flValue - pbonecontroller->start) / (pbonecontroller->end - pbonecontroller->start); - ent->progs.sv->controller[iController] = setting = bound( 0, setting, 255 ); - - // returns full range value - PRVM_G_FLOAT(OFS_RETURN) = setting * (1.0f / 255.0f) * (pbonecontroller->end - pbonecontroller->start) + pbonecontroller->start; -} - -/* -============= -PF_setblending - -float SetBlending( string model, float blender, float value ) -============= -*/ -void PF_setblending( void ) -{ - cmodel_t *mod; - edict_t *ent; - dstudioseqdesc_t *pseqdesc; - dstudiohdr_t *pstudiohdr; - int iBlender; - int setting; - float flValue; - - if(!VM_ValidateArgs( "SetBlending", 3 )) return; - if( !com.strcmp( PRVM_G_STRING( OFS_PARM0 ), "" )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - flValue = PRVM_G_FLOAT(OFS_PARM2); // not modified value - PRVM_G_FLOAT(OFS_RETURN) = flValue; - - ent = PRVM_PROG_TO_EDICT( prog->globals.sv->pev ); - mod = pe->RegisterModel(PRVM_G_STRING(OFS_PARM0)); - if( !mod ) return; - pstudiohdr = (dstudiohdr_t *)mod->extradata; - if( !pstudiohdr ) return; - - pseqdesc = (dstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)ent->progs.sv->sequence; - iBlender = (int)PRVM_G_FLOAT(OFS_PARM1); - if( pseqdesc->blendtype[iBlender] == 0 ) return; - - if( pseqdesc->blendtype[iBlender] & (STUDIO_XR|STUDIO_YR|STUDIO_ZR)) - { - // ugly hack, invert value if end < start - if( pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender] ) - flValue = -flValue; - - // does the controller not wrap? - if( pseqdesc->blendstart[iBlender] + 359.0f >= pseqdesc->blendend[iBlender] ) - { - if( flValue > ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0f) + 180.0f) - flValue = flValue - 360.0f; - if( flValue < ((pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender]) / 2.0f) - 180.0f) - flValue = flValue + 360.0f; - } - } - - setting = 255 * (flValue - pseqdesc->blendstart[iBlender]) / (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]); - ent->progs.sv->blending[iBlender] = setting = bound( 0, setting, 255 ); - - // returns full range value - PRVM_G_FLOAT(OFS_RETURN) = setting * (1.0f / 255.0f) * (pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender]) + pseqdesc->blendstart[iBlender]; -} - -/* -============= -PF_aim - -vector aim( entity e, float speed ) -============= -*/ -void PF_aim( void ) -{ - edict_t *ent, *check, *bestent; - vec3_t start, dir, end, bestdir; - int i, j; - trace_t tr; - float dist, bestdist; - float speed; - int flags = Cvar_VariableValue( "dmflags" ); - - if(!VM_ValidateArgs( "tracebox", 2 )) return; - VectorCopy(prog->globals.sv->v_forward, PRVM_G_VECTOR(OFS_RETURN)); // assume failure if it returns early - - ent = PRVM_G_EDICT(OFS_PARM0); - if( ent == prog->edicts ) - { - VM_Warning("aim: can't use world entity\n"); - return; - } - if( ent->priv.sv->free ) - { - VM_Warning("aim: can't use free entity\n"); - return; - } - speed = PRVM_G_FLOAT(OFS_PARM1); - - VectorCopy (ent->progs.sv->origin, start); - start[2] += 20; - - // try sending a trace straight - VectorCopy(prog->globals.sv->v_forward, dir); - VectorMA(start, 2048, dir, end); - tr = SV_Trace( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, -1 ); - - if( tr.ent && ((edict_t *)tr.ent)->progs.sv->takedamage == 2 && (flags & DF_NO_FRIENDLY_FIRE - || ent->progs.sv->team <=0 || ent->progs.sv->team != ((edict_t *)tr.ent)->progs.sv->team)) - { - VectorCopy (prog->globals.sv->v_forward, PRVM_G_VECTOR(OFS_RETURN)); - return; - } - - // try all possible entities - VectorCopy( dir, bestdir ); - bestdist = 0.5f; - bestent = NULL; - - check = PRVM_NEXT_EDICT(prog->edicts); - for( i = 1; i < prog->num_edicts; i++, check = PRVM_NEXT_EDICT(check)) - { - prog->xfunction->builtinsprofile++; - if (check->progs.sv->takedamage != 2) // DAMAGE_AIM - continue; - if (check == ent) continue; - if (flags & DF_NO_FRIENDLY_FIRE && ent->progs.sv->team > 0 && ent->progs.sv->team == check->progs.sv->team) - continue; // don't aim at teammate - for (j = 0; j < 3; j++) - end[j] = check->progs.sv->origin[j] + 0.5 * (check->progs.sv->mins[j] + check->progs.sv->maxs[j]); - VectorSubtract (end, start, dir); - VectorNormalize (dir); - dist = DotProduct (dir, prog->globals.sv->v_forward); - if (dist < bestdist) continue; // to far to turn - tr = SV_Trace (start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent, -1 ); - if (tr.ent == check) - { - // can shoot at this one - bestdist = dist; - bestent = check; - } - } - - if( bestent ) - { - VectorSubtract (bestent->progs.sv->origin, ent->progs.sv->origin, dir); - dist = DotProduct (dir, prog->globals.sv->v_forward); - VectorScale (prog->globals.sv->v_forward, dist, end); - end[2] = dir[2]; - VectorNormalize(end); - VectorCopy(end, PRVM_G_VECTOR(OFS_RETURN)); - } - else - { - VectorCopy(bestdir, PRVM_G_VECTOR(OFS_RETURN)); - } -} - -/* -========= -PF_servercmd - -void servercommand( string s, ... ) -========= -*/ -void PF_servercmd( void ) -{ - Cbuf_AddText(VM_VarArgs( 0 )); -} - -/* -========= -PF_serverexec - -void server_execute( void ) -========= -*/ -void PF_serverexec( void ) -{ - if(VM_ValidateArgs( "ServerExecute", 0 )) - Cbuf_Execute(); -} - -/* -========= -PF_clientcmd - -void clientcommand( float client, string s ) -========= -*/ -void PF_clientcmd( void ) -{ - sv_client_t *client; - int i; - - if(!VM_ValidateArgs( "ClientCommand", 2 )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - - i = (int)PRVM_G_FLOAT(OFS_PARM0); - if( sv.state != ss_active || i < 0 || i >= Host_MaxClients() || svs.clients[i].state != cs_spawned) - { - VM_Warning( "ClientCommand: client/server is not active!\n" ); - return; - } - - client = svs.clients + i; - MSG_WriteByte(&client->netchan.message, svc_stufftext ); - MSG_WriteString( &client->netchan.message, PRVM_G_STRING(OFS_PARM1)); - MSG_Send(MSG_ONE_R, NULL, client->edict ); -} - -/* -================= -PF_particle - -void particle( vector origin, vector dir, float color, float count ) -================= -*/ -void PF_particle( void ) -{ - float *org, *dir; - float color, count; - - if(!VM_ValidateArgs( "particle", 4 )) - return; - - org = PRVM_G_VECTOR(OFS_PARM0); - dir = PRVM_G_VECTOR(OFS_PARM1); - color = PRVM_G_FLOAT(OFS_PARM2); - count = PRVM_G_FLOAT(OFS_PARM3); - - SV_StartParticle( org, dir, (int)color, (int)count); -} - -/* -=============== -PF_lightstyle - -void lightstyle( float style, string value ) -=============== -*/ -static void PF_lightstyle( void ) -{ - int style; - const char *val; - - if(!VM_ValidateArgs( "lightstyle", 2 )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - - style = (int)PRVM_G_FLOAT(OFS_PARM0); - val = PRVM_G_STRING(OFS_PARM1); - - if((uint)style >= MAX_LIGHTSTYLES ) - PRVM_ERROR( "PF_lightstyle: style: %i >= %d", style, MAX_LIGHTSTYLES ); - SV_ConfigString( CS_LIGHTSTYLES + style, val ); -} - -/* -============= -PF_pointcontents - -float pointcontents( vector v ) -============= -*/ -static void PF_pointcontents( void ) -{ - if(!VM_ValidateArgs( "pointcontents", 1 )) return; - PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0)); -} - -/* -============= -PF_BeginMessage - -void MsgBegin( float dest ) -============= -*/ -void PF_BeginMessage( void ) -{ - int svc_dest = (int)PRVM_G_FLOAT(OFS_PARM0); - - if(!VM_ValidateArgs( "MsgBegin", 1 )) return; - - // some users can send message with engine index - // reduce number to avoid overflow problems or cheating - svc_dest = bound( svc_bad, svc_dest, svc_nop ); - - MSG_Begin( svc_dest ); -} - -/* -============= -PF_EndMessage - -void MsgEnd(float to, vector pos, entity e) -============= -*/ -void PF_EndMessage( void ) -{ - int send_to = (int)PRVM_G_FLOAT(OFS_PARM0); - edict_t *ed = PRVM_G_EDICT(OFS_PARM2); - - if(!VM_ValidateArgs( "MsgEnd", 3 )) return; - if(PRVM_NUM_FOR_EDICT(ed) > prog->num_edicts) - { - VM_Warning("MsgEnd: sending message from killed entity\n"); - return; - } - // align range - send_to = bound( MSG_ONE, send_to, MSG_PVS_R ); - MSG_Send( send_to, PRVM_G_VECTOR(OFS_PARM1), ed ); -} - -// various network messages -void PF_WriteByte (void){ MSG_WriteByte(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteChar (void){ MSG_WriteChar(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteShort (void){ MSG_WriteShort(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteLong (void){ MSG_WriteLong(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteAngle (void){ MSG_WriteAngle32(&sv.multicast, PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteCoord (void){ MSG_WriteCoord32(&sv.multicast, PRVM_G_FLOAT(OFS_PARM0)); } -void PF_WriteString (void){ MSG_WriteString(&sv.multicast, PRVM_G_STRING(OFS_PARM0)); } -void PF_WriteEntity (void){ MSG_WriteShort(&sv.multicast, PRVM_G_EDICTNUM(OFS_PARM0)); } - -/* -============= -PF_checkbottom - -float checkbottom( entity e ) -============= -*/ -void PF_checkbottom( void ) -{ - if(!VM_ValidateArgs( "checkbottom", 1 )) return; - PRVM_G_FLOAT(OFS_RETURN) = SV_CheckBottom(PRVM_G_EDICT(OFS_PARM0)); -} - -/* -================= -PF_ClientPrint - -void ClientPrintf( float type, entity client, string s ) -================= -*/ -void PF_ClientPrint( void ) -{ - sv_client_t *client; - int num, type; - const char *s; - - num = PRVM_G_EDICTNUM( OFS_PARM1 ); - type = (int)PRVM_G_FLOAT( OFS_PARM0 ); - if( num < 1 || num > Host_MaxClients() || svs.clients[num - 1].state != cs_spawned ) - { - VM_Warning("ClientPrint: tired print to a non-client!\n"); - return; - } - client = svs.clients + num - 1; - s = VM_VarArgs( 2 ); - - switch( type ) - { - case PRINT_CONSOLE: - SV_ClientPrintf (client, PRINT_CONSOLE, (char *)s ); - break; - case PRINT_CENTER: - MSG_Begin( svc_centerprint ); - MSG_WriteString( &sv.multicast, s ); - MSG_Send( MSG_ONE_R, NULL, client->edict ); - break; - case PRINT_CHAT: - SV_ClientPrintf (client, PRINT_CHAT, (char *)s ); - break; - default: - Msg("ClientPrintf: invalid destination\n" ); - break; - } -} - -/* -================= -PF_ServerPrint - -void ServerPrint( string s ) -================= -*/ -void PF_ServerPrint( void ) -{ - const char *s = VM_VarArgs( 0 ); - - if( sv.state == ss_loading ) - { - // while loading in-progress we can sending message - Msg( s ); // only for local client - } - else SV_BroadcastPrintf( PRINT_CONSOLE, (char *)s ); - -} - -/* -================= -PF_AreaPortalState - -void areaportal( entity ent, float state ) -================= -*/ -void PF_AreaPortalState( void ) -{ - edict_t *ent; - bool open; - - if( !VM_ValidateArgs( "areaportal", 2 )) - return; - - ent = PRVM_G_EDICT( OFS_PARM0 ); - open = (bool)PRVM_G_FLOAT( OFS_PARM1 ); - pe->SetAreaPortalState( ent->progs.sv->style, open ); -} - -/* -================= -PF_InfoPrint - -void Info_Print( entity client ) -================= -*/ -void PF_InfoPrint( void ) -{ - sv_client_t *client; - int num; - - if(!VM_ValidateArgs( "Info_Print", 1 )) return; - num = PRVM_G_EDICTNUM(OFS_PARM0); - if( num < 1 || num > Host_MaxClients()) - { - VM_Warning( "Info_Print: not a client\n" ); - return; - } - client = svs.clients + num - 1; - Info_Print( client->userinfo ); -} - -/* -================= -PF_InfoValueForKey - -string Info_ValueForKey( entity client, string key ) -================= -*/ -void PF_InfoValueForKey( void ) -{ - sv_client_t *client; - int num; - const char *key; - - if(!VM_ValidateArgs( "Info_ValueForKey", 2 )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - - num = PRVM_G_EDICTNUM(OFS_PARM0); - if( num < 1 || num > Host_MaxClients()) - { - VM_Warning("Info_ValueForKey: not a client\n" ); - return; - } - - client = svs.clients + num - 1; - key = PRVM_G_STRING(OFS_PARM1); - PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(Info_ValueForKey( client->userinfo, (char *)key)); -} - -/* -================= -PF_InfoRemoveKey - -void Info_RemoveKey( entity client, string key ) -================= -*/ -void PF_InfoRemoveKey( void ) -{ - sv_client_t *client; - int num; - const char *key; - - if(!VM_ValidateArgs( "Info_RemoveKey", 2 )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - - num = PRVM_G_EDICTNUM(OFS_PARM0); - if( num < 1 || num > Host_MaxClients()) - { - VM_Warning("Info_RemoveKey: not a client\n" ); - return; - } - - client = svs.clients + num - 1; - key = PRVM_G_STRING(OFS_PARM1); - Info_RemoveKey( client->userinfo, (char *)key); -} - -/* -================= -PF_InfoSetValueForKey - -void Info_SetValueForKey( entity client, string key, string value ) -================= -*/ -void PF_InfoSetValueForKey( void ) -{ - sv_client_t *client; - int num; - const char *key, *value; - - if(!VM_ValidateArgs( "Info_SetValueForKey", 3 )) return; - VM_ValidateString(PRVM_G_STRING(OFS_PARM1)); - VM_ValidateString(PRVM_G_STRING(OFS_PARM2)); - - num = PRVM_G_EDICTNUM(OFS_PARM0); - if( num < 1 || num > Host_MaxClients()) - { - VM_Warning("InfoSetValueForKey: not a client\n" ); - return; - } - - client = svs.clients + num - 1; - key = PRVM_G_STRING(OFS_PARM1); - value = PRVM_G_STRING(OFS_PARM2); - Info_SetValueForKey( client->userinfo, (char *)key, (char *)value ); -} - -/* -=============== -PF_setsky - -void setsky( string name, vector angles, float speed ) -=============== -*/ -void PF_setsky( void ) -{ - if(!VM_ValidateArgs( "setsky", 1 )) - return; - - VM_ValidateString(PRVM_G_STRING(OFS_PARM0)); - SV_ConfigString( CS_SKYNAME, PRVM_G_STRING(OFS_PARM0)); -} - -/* -=============== -PF_music - -void music( string trackname ) -=============== -*/ -void PF_music( void ) -{ - if(!VM_ValidateArgs( "music", 1 )) - return; - SV_ConfigString( CS_BACKGROUND_TRACK, PRVM_G_STRING(OFS_PARM0)); -} - -/* -============== -PF_dropclient - -void dropclient( entity client ) -============== -*/ -void PF_dropclient( void ) -{ - int clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1; - - if( clientnum < 0 || clientnum >= Host_MaxClients()) - { - VM_Warning("dropclient: not a client\n"); - return; - } - if( svs.clients[clientnum].state != cs_spawned ) - { - VM_Warning("dropclient: that client slot is not connected\n"); - return; - } - SV_DropClient( svs.clients + clientnum ); -} - - - -//NOTE: intervals between various "interfaces" was leave for future expansions -prvm_builtin_t vm_sv_builtins[] = -{ -NULL, // #0 (leave blank as default, but can include easter egg ) - -// system events -VM_ConPrintf, // #1 void Con_Printf( ... ) -VM_ConDPrintf, // #2 void Con_DPrintf( float level, ... ) -VM_HostError, // #3 void Com_Error( ... ) -VM_SysExit, // #4 void Sys_Exit( void ) -VM_CmdArgv, // #5 string Cmd_Argv( float arg ) -VM_CmdArgc, // #6 float Cmd_Argc( void ) -NULL, // #7 -- reserved -- -NULL, // #8 -- reserved -- -NULL, // #9 -- reserved -- -NULL, // #10 -- reserved -- - -// common tools -VM_ComTrace, // #11 void Com_Trace( float enable ) -VM_ComFileExists, // #12 float Com_FileExists( string filename ) -VM_ComFileSize, // #13 float Com_FileSize( string filename ) -VM_ComFileTime, // #14 float Com_FileTime( string filename ) -VM_ComLoadScript, // #15 float Com_LoadScript( string filename ) -VM_ComResetScript, // #16 void Com_ResetScript( void ) -VM_ComReadToken, // #17 string Com_ReadToken( float newline ) -VM_Random, // #18 float Random( void ) -VM_ComSearchFiles, // #19 float Com_Search( string mask, float casecmp ) -VM_ComSearchNames, // #20 string Com_SearchFilename( float num ) -VM_RandomLong, // #21 float RandomLong( float min, float max ) -VM_RandomFloat, // #22 float RandomFloat( float min, float max ) -VM_RandomVector, // #23 vector RandomVector( vector min, vector max ) -VM_CvarRegister, // #24 void Cvar_Register( string name, string value, float flags ) -VM_CvarSetValue, // #25 void Cvar_SetValue( string name, float value ) -VM_CvarGetValue, // #26 float Cvar_GetValue( string name ) -VM_CvarSetString, // #27 void Cvar_SetString( string name, string value ) -VM_CvarGetString, // #28 void VM_CvarGetString( void ) -VM_ComVA, // #29 string va( ... ) -VM_ComStrlen, // #30 float strlen( string text ) -VM_TimeStamp, // #31 string Com_TimeStamp( float format ) -VM_LocalCmd, // #32 void LocalCmd( ... ) -VM_SubString, // #33 string substring( string s, float start, float length ) -VM_AddCommand, // #34 void Add_Command( string s ) -VM_atof, // #35 float atof( string s ) -VM_atoi, // #36 float atoi( string s ) -VM_atov, // #37 vector atov( string s ) -NULL, // #38 -- reserved -- -NULL, // #39 -- reserved -- -NULL, // #40 -- reserved -- - -// quakec intrinsics ( compiler will be lookup this functions, don't remove or rename ) -VM_SpawnEdict, // #41 entity spawn( void ) -VM_RemoveEdict, // #42 void remove( entity ent ) -VM_NextEdict, // #43 entity nextent( entity ent ) -VM_CopyEdict, // #44 void copyentity( entity src, entity dst ) -NULL, // #45 -- reserved -- -NULL, // #46 -- reserved -- -NULL, // #47 -- reserved -- -NULL, // #48 -- reserved -- -NULL, // #49 -- reserved -- -NULL, // #50 -- reserved -- - -// filesystem -VM_FS_Open, // #51 float fopen( string filename, float mode ) -VM_FS_Close, // #52 void fclose( float handle ) -VM_FS_Gets, // #53 string fgets( float handle ) -VM_FS_Puts, // #54 void fputs( float handle, string s ) -NULL, // #55 -- reserved -- -NULL, // #56 -- reserved -- -NULL, // #57 -- reserved -- -NULL, // #58 -- reserved -- -NULL, // #59 -- reserved -- -NULL, // #60 -- reserved -- - -// mathlib -VM_min, // #61 float min(float a, float b ) -VM_max, // #62 float max(float a, float b ) -VM_bound, // #63 float bound(float min, float val, float max) -VM_pow, // #64 float pow(float x, float y) -VM_sin, // #65 float sin(float f) -VM_cos, // #66 float cos(float f) -VM_tan, // #67 float tan(float f) -VM_asin, // #68 float asin(float f) -VM_acos, // #69 float acos(float f) -VM_atan, // #70 float atan(float f) -VM_sqrt, // #71 float sqrt(float f) -VM_rint, // #72 float rint (float v) -VM_floor, // #73 float floor(float v) -VM_ceil, // #74 float ceil (float v) -VM_fabs, // #75 float fabs (float f) -VM_abs, // #76 float abs (float f) -NULL, // #77 -- reserved -- -NULL, // #78 -- reserved -- -VM_VectorNormalize, // #79 vector VectorNormalize( vector v ) -VM_VectorLength, // #80 float VectorLength( vector v ) -e10, e10, // #81 - #100 are reserved for future expansions - -// engine functions (like half-life enginefuncs_s) -PF_precache_model, // #101 float precache_model(string s) -PF_precache_sound, // #102 float precache_sound(string s) -PF_setmodel, // #103 float setmodel(entity e, string m) -PF_modelindex, // #104 float model_index(string s) -PF_modelframes, // #105 float model_frames(float modelindex) -PF_setsize, // #106 void setsize(entity e, vector min, vector max) -PF_changelevel, // #107 void changelevel(string mapname, string spotname) -NULL, // #108 getSpawnParms -NULL, // #109 SaveSpawnParms -PF_vectoyaw, // #110 float vectoyaw(vector v) -PF_vectoangles, // #111 vector vectoangles(vector v) -NULL, // #112 moveToOrigin -PF_changeyaw, // #113 void ChangeYaw( void ) -PF_changepitch, // #114 void ChangePitch( void ) -VM_FindEdict, // #115 entity find(entity start, .string fld, string match) -PF_getlightlevel, // #116 float getEntityIllum( entity e ) -PF_findradius, // #117 entity FindInSphere(vector org, float rad) -PF_inpvs, // #118 entity EntitiesInPVS( entity ent, float player ) -PF_inphs, // #119 entity EntitiesInPHS( entity ent, float player ) -PF_makevectors, // #120 void makevectors( vector dir, float hand ) -VM_EdictError, // #121 void objerror( string s ) -PF_dropclient, // #122 void dropclient( entity client ) -PF_lookupactivity, // #123 float LookupActivity( string model, float activity ) -PF_create, // #124 void CreateNamedEntity( string classname, vector org, vector ang ) -PF_makestatic, // #125 void makestatic(entity e) -NULL, // #126 isEntOnFloor -PF_droptofloor, // #127 float droptofloor( void ) -PF_walkmove, // #128 float walkmove(float yaw, float dist) -PF_setorigin, // #129 void setorigin( entity e, vector org ) -PF_setangles, // #130 void setangles( entity e, vector ang ) -PF_music, // #131 void music( string trackname ) -PF_traceline, // #132 void traceline(vector v1, vector v2, float mask, entity ignore) -PF_tracetoss, // #133 void tracetoss (entity e, entity ignore) -NULL, // #134 traceMonsterHull -PF_tracebox, // #135 void tracebox (vector v1, vector mins, vector maxs, vector v2, float mask, entity ignore) -NULL, // #136 traceModel -NULL, // #137 traceTexture -NULL, // #138 traceSphere -PF_aim, // #139 vector aim(entity e, float speed) -PF_servercmd, // #140 void server_command( string command ) -PF_serverexec, // #141 void server_execute( void ) -PF_clientcmd, // #142 void client_command( entity e, string s) -PF_particle, // #143 void particle( vector origin, vector dir, float color, float count ) -PF_lightstyle, // #144 void lightstyle(float style, string value) -PF_getsequenceinfo, // #145 float GetSequenceInfo( string model, float sequence ) -PF_pointcontents, // #146 float pointcontents(vector v) -PF_BeginMessage, // #147 void MsgBegin (float dest) -PF_EndMessage, // #148 void MsgEnd(float to, vector pos, entity e) -PF_WriteByte, // #149 void WriteByte (float f) -PF_WriteChar, // #150 void WriteChar (float f) -PF_WriteShort, // #151 void WriteShort (float f) -PF_WriteLong, // #152 void WriteLong (float f) -PF_WriteAngle, // #153 void WriteAngle (float f) -PF_WriteCoord, // #154 void WriteCoord (float f) -PF_WriteString, // #155 void WriteString (string s) -PF_WriteEntity, // #156 void WriteEntity (entity s) -PF_getsequenceflags, // #157 float GetSequenceFlags( string model, float sequence ) -NULL, // #158 regUserMsg -PF_checkbottom, // #159 float checkbottom(entity e) -NULL, // #160 getBonePosition -PF_ClientPrint, // #161 void ClientPrint( float type, entity client, string s) -PF_ServerPrint, // #162 void ServerPrint(string s) -NULL, // #163 getAttachment -NULL, // #164 setView -NULL, // #165 crosshairangle -PF_AreaPortalState, // #166 void areaportal( entity ent, float state ) -PF_lookupactivityheaviest, // #167 float LookupActivityHeaviest( string model, float activity ) -PF_geteyepos, // #168 vector GetEyePosition( string model ) -PF_InfoPrint, // #169 void Info_Print( entity client ) -PF_InfoValueForKey, // #170 string Info_ValueForKey( entity client, string key ) -PF_InfoRemoveKey, // #171 void Info_RemoveKey( entity client, string key ) -PF_InfoSetValueForKey, // #172 void Info_SetValueForKey( entity client, string key, string value ) -PF_setsky, // #173 void setsky( string name, vector angles, float speed ) -NULL, // #174 staticDecal -PF_lookupsequence, // #175 float LookupSequence( string model, string label ) -PF_setcontroller, // #176 float SetController( string model, float controller, float value ) -PF_setblending, // #177 float SetBlending( string model, float blender, float value ) -PF_getweaponsequenceinfo, // #178 float GetWeaponSequenceInfo( string model, float sequence ) -}; - -const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t); //num of builtins - -/* -============== -SpawnEntities - -Creates a server's entity / program execution context by -parsing textual entity definitions out of an ent file. -============== -*/ -void SV_SpawnEntities( const char *mapname, const char *entities ) -{ - edict_t *ent; - int i; - - MsgDev( D_NOTE, "SV_SpawnEntities()\n" ); - - prog->protect_world = false; // allow to change world parms - - ent = PRVM_EDICT_NUM( 0 ); - memset (ent->progs.sv, 0, prog->progs->entityfields * 4); - ent->priv.sv->free = false; - ent->progs.sv->model = PRVM_SetEngineString( sv.configstrings[CS_MODELS] ); - ent->progs.sv->modelindex = 1; // world model - ent->progs.sv->solid = SOLID_BSP; - ent->progs.sv->movetype = MOVETYPE_PUSH; - - SV_ConfigString (CS_MAXCLIENTS, va("%i", Host_MaxClients())); - prog->globals.sv->mapname = PRVM_SetEngineString( sv.name ); - - // spawn the rest of the entities on the map - *prog->time = sv.time; - - // set client fields on player ents - for( i = 0; i < Host_MaxClients(); i++ ) - { - // setup all clients - ent = PRVM_EDICT_NUM( i ); - ent->priv.sv->client = svs.clients + i; - } - - PRVM_ED_LoadFromFile( entities ); - prog->protect_world = true; // make world read-only -} - -/* -=============== -SV_InitGameProgs - -Init the game subsystem for a new map -=============== -*/ -void SV_InitServerProgs( void ) -{ - Msg( "\n" ); - PRVM_Begin; - PRVM_InitProg( PRVM_SERVERPROG ); - - prog->reserved_edicts = Host_MaxClients(); - prog->loadintoworld = true; - - if( !prog->loaded ) - { - prog->progs_mempool = Mem_AllocPool("Server Progs" ); - prog->name = "server"; - prog->builtins = vm_sv_builtins; - prog->numbuiltins = vm_sv_numbuiltins; - prog->max_edicts = host.max_edicts<<2; - prog->limit_edicts = host.max_edicts; - prog->edictprivate_size = sizeof(sv_edict_t); - prog->begin_increase_edicts = SV_BeginIncreaseEdicts; - prog->end_increase_edicts = SV_EndIncreaseEdicts; - prog->init_edict = SV_InitEdict; - prog->free_edict = SV_FreeEdict; - prog->count_edicts = SV_CountEdicts; - prog->load_edict = SV_LoadEdict; - prog->keyvalue_edict = SV_ParseKeyValue; - prog->restore_edict = SV_RestoreEdict; - prog->filecrc = PROG_CRC_SERVER; - - // using default builtins - prog->init_cmd = VM_Cmd_Init; - prog->reset_cmd = VM_Cmd_Reset; - prog->error_cmd = VM_Error; - PRVM_LoadProgs( va("%s/server.dat", GI->vprogs_dir )); - } - - // try to get custom movement function from qc code - svs.ClientMove = PRVM_ED_FindFunctionOffset( "ClientMove" ); - PRVM_End; -} - -/* -=============== -SV_ShutdownGameProgs - -Called when either the entire server is being killed, or -it is changing to a different game directory. -=============== -*/ -void SV_FreeServerProgs( void ) -{ - edict_t *ent; - int i; - - if(!PRVM_ProgLoaded( PRVM_SERVERPROG )) - return; - - SV_VM_Begin(); - for (i = 1; prog && i < prog->num_edicts; i++) - { - ent = PRVM_EDICT_NUM(i); - SV_FreeEdict( ent );// release physic - } - SV_VM_End(); + if( ent->v.ambient ) // restore loopsound + ent->pvEngineData->s.soundindex = SV_SoundIndex( STRING( ent->v.ambient )); } \ No newline at end of file diff --git a/engine/server/sv_spawn.c b/engine/server/sv_spawn.c index cd0888fd..e3daea44 100644 --- a/engine/server/sv_spawn.c +++ b/engine/server/sv_spawn.c @@ -8,7 +8,7 @@ SV_StartParticle Make sure the event gets sent to all clients ================== */ -void SV_StartParticle( vec3_t org, vec3_t dir, int color, int count ) +void SV_StartParticle( const float *org, const float *dir, int color, int count ) { MsgDev( D_ERROR, "SV_StartParticle: implement me\n"); } \ No newline at end of file diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index ba16261c..10bf4497 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -15,7 +15,7 @@ ENTITY AREA CHECKING FIXME: this use of "area" is different from the bsp file use =============================================================================== */ -#define EDICT_FROM_AREA( l ) PRVM_EDICT_NUM( l->entnum ) +#define EDICT_FROM_AREA( l ) EDICT_NUM( l->entnum ) #define MAX_TOTAL_ENT_LEAFS 128 #define AREA_NODES 32 #define AREA_DEPTH 4 @@ -105,7 +105,7 @@ void SV_InsertLinkBefore( link_t *l, link_t *before, edict_t *ent ) l->prev = before->prev; l->prev->next = l; l->next->prev = l; - l->entnum = PRVM_NUM_FOR_EDICT(ent); + l->entnum = NUM_FOR_EDICT( ent ); } /* @@ -176,17 +176,17 @@ sorting edict by type */ void SV_ClassifyEdict( edict_t *ent ) { - sv_edict_t *sv_ent; + ed_priv_t *sv_ent; const char *classname; - sv_ent = ent->priv.sv; + sv_ent = ent->pvEngineData; if( sv_ent->s.ed_type != ED_SPAWNED ) return; // null state ? if( !sv_ent->s.number ) SV_UpdateEntityState( ent ); - classname = PRVM_GetString( ent->progs.sv->classname ); + classname = STRING( ent->v.classname ); if( !com.strnicmp( "worldspawn", classname, 10 )) { @@ -194,28 +194,28 @@ void SV_ClassifyEdict( edict_t *ent ) return; } // first pass: determine type by explicit parms - if( ent->progs.sv->solid == SOLID_TRIGGER ) + if( ent->v.solid == SOLID_TRIGGER ) { if( sv_ent->s.soundindex ) sv_ent->s.ed_type = ED_AMBIENT; // e.g. trigger_teleport else sv_ent->s.ed_type = ED_TRIGGER; // never sending to client } - else if( ent->progs.sv->movetype == MOVETYPE_PHYSIC ) + else if( ent->v.movetype == MOVETYPE_PHYSIC ) sv_ent->s.ed_type = ED_RIGIDBODY; - else if( ent->progs.sv->solid == SOLID_BSP || VectorIsNull( ent->progs.sv->origin )) + else if( ent->v.solid == SOLID_BSP || VectorIsNull( ent->v.origin )) { - if( ent->progs.sv->movetype == MOVETYPE_CONVEYOR ) + if( ent->v.movetype == MOVETYPE_CONVEYOR ) sv_ent->s.ed_type = ED_MOVER; - else if((int)ent->progs.sv->flags & FL_WORLDBRUSH ) + else if((int)ent->v.flags & FL_WORLDBRUSH ) sv_ent->s.ed_type = ED_BSPBRUSH; - else if( ent->progs.sv->movetype == MOVETYPE_PUSH ) + else if( ent->v.movetype == MOVETYPE_PUSH ) sv_ent->s.ed_type = ED_MOVER; - else if( ent->progs.sv->movetype == MOVETYPE_NONE ) + else if( ent->v.movetype == MOVETYPE_NONE ) sv_ent->s.ed_type = ED_BSPBRUSH; } - else if((int)ent->progs.sv->flags & FL_MONSTER ) + else if((int)ent->v.flags & FL_MONSTER ) sv_ent->s.ed_type = ED_MONSTER; - else if((int)ent->progs.sv->flags & FL_CLIENT ) + else if((int)ent->v.flags & FL_CLIENT ) sv_ent->s.ed_type = ED_CLIENT; else if( !sv_ent->s.model.index && !sv_ent->s.aiment ) { @@ -232,7 +232,7 @@ void SV_ClassifyEdict( edict_t *ent ) } // or leave unclassified, wait for next SV_LinkEdict... - // Msg( "%s: <%s>\n", PRVM_GetString( ent->progs.sv->classname ), ed_name[sv_ent->s.ed_type] ); + // Msg( "%s: <%s>\n", STRING( ent->v.classname ), ed_name[sv_ent->s.ed_type] ); } /* @@ -243,10 +243,10 @@ SV_UnlinkEdict void SV_UnlinkEdict( edict_t *ent ) { // not linked in anywhere - if( !ent->priv.sv->area.prev ) return; + if( !ent->pvEngineData->area.prev ) return; - SV_RemoveLink( &ent->priv.sv->area ); - ent->priv.sv->area.prev = ent->priv.sv->area.next = NULL; + SV_RemoveLink( &ent->pvEngineData->area ); + ent->pvEngineData->area.prev = ent->pvEngineData->area.next = NULL; } /* @@ -263,71 +263,71 @@ void SV_LinkEdict( edict_t *ent ) int i, j, k; int area; int topnode; - sv_edict_t *sv_ent; + ed_priv_t *sv_ent; - sv_ent = ent->priv.sv; + sv_ent = ent->pvEngineData; if( sv_ent->area.prev ) SV_UnlinkEdict( ent ); // unlink from old position - if( ent == prog->edicts ) return; // don't add the world - if( sv_ent->free ) return; + if( ent == svg.edicts ) return; // don't add the world + if( ent->free ) return; // trying to classify unclassified edicts if( sv.state == ss_active && sv_ent->s.ed_type == ED_SPAWNED ) SV_ClassifyEdict( ent ); // set the size - VectorSubtract( ent->progs.sv->maxs, ent->progs.sv->mins, ent->progs.sv->size ); + VectorSubtract( ent->v.maxs, ent->v.mins, ent->v.size ); - if( ent->progs.sv->solid == SOLID_BSP ) + if( ent->v.solid == SOLID_BSP ) { // a solid_bbox will never create this value sv_ent->solid = SOLID_BMODEL; } - else if(( int )ent->progs.sv->contents & ( CONTENTS_SOLID|CONTENTS_BODY )) + else if(( int )ent->v.contents & ( CONTENTS_SOLID|CONTENTS_BODY )) { // encode the size into the entity_state for client prediction // assume that x/y are equal and symetric - i = ent->progs.sv->maxs[0]; + i = ent->v.maxs[0]; i = bound( 1, i, 255 ); // z is not symetric - j = (-ent->progs.sv->mins[2]); + j = (-ent->v.mins[2]); j = bound( 1, j, 255 ); // and z maxs can be negative... - k = (ent->progs.sv->maxs[2] + 32); + k = (ent->v.maxs[2] + 32); k = bound( 1, k, 255 ); sv_ent->solid = (k<<16)|(j<<8)|i; } else sv_ent->solid = 0; // set the abs box - if( ent->progs.sv->solid == SOLID_BSP && !VectorIsNull( ent->progs.sv->angles )) + if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles )) { // expand for rotation int i; - float max = RadiusFromBounds( ent->progs.sv->mins, ent->progs.sv->maxs ); + float max = RadiusFromBounds( ent->v.mins, ent->v.maxs ); for( i = 0; i < 3; i++ ) { - ent->progs.sv->absmin[i] = ent->progs.sv->origin[i] - max; - ent->progs.sv->absmax[i] = ent->progs.sv->origin[i] + max; + ent->v.absmin[i] = ent->v.origin[i] - max; + ent->v.absmax[i] = ent->v.origin[i] + max; } } else { // normal - VectorAdd( ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->absmin ); - VectorAdd( ent->progs.sv->origin, ent->progs.sv->maxs, ent->progs.sv->absmax ); + VectorAdd( ent->v.origin, ent->v.mins, ent->v.absmin ); + VectorAdd( ent->v.origin, ent->v.maxs, ent->v.absmax ); } // because movement is clipped an epsilon away from an actual edge, // we must fully check even when bounding boxes don't quite touch - ent->progs.sv->absmin[0] -= 1; - ent->progs.sv->absmin[1] -= 1; - ent->progs.sv->absmin[2] -= 1; - ent->progs.sv->absmax[0] += 1; - ent->progs.sv->absmax[1] += 1; - ent->progs.sv->absmax[2] += 1; + ent->v.absmin[0] -= 1; + ent->v.absmin[1] -= 1; + ent->v.absmin[2] -= 1; + ent->v.absmax[0] += 1; + ent->v.absmax[1] += 1; + ent->v.absmax[2] += 1; // link to PVS leafs sv_ent->num_clusters = 0; @@ -335,7 +335,7 @@ void SV_LinkEdict( edict_t *ent ) sv_ent->areanum2 = 0; // get all leafs, including solids - num_leafs = pe->BoxLeafnums( ent->progs.sv->absmin, ent->progs.sv->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode ); + num_leafs = pe->BoxLeafnums( ent->v.absmin, ent->v.absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode ); // if none of the leafs were inside the map, the // entity is outside the world and can be considered unlinked @@ -354,7 +354,7 @@ void SV_LinkEdict( edict_t *ent ) { if( sv_ent->areanum2 && sv_ent->areanum2 != area && sv.state == ss_loading ) { - float *v = ent->progs.sv->absmin; + float *v = ent->v.absmin; MsgDev( D_WARN, "SV_LinkEdict: object touching 3 areas at %f %f %f\n", v[0], v[1], v[2] ); } sv_ent->areanum2 = area; @@ -394,16 +394,16 @@ void SV_LinkEdict( edict_t *ent ) } } - ent->priv.sv->linkcount++; + ent->pvEngineData->linkcount++; // update ambient sound here - if( ent->progs.sv->loopsound ) + if( ent->v.ambient ) { - ent->priv.sv->s.soundindex = SV_SoundIndex( PRVM_GetString( ent->progs.sv->loopsound )); + ent->pvEngineData->s.soundindex = SV_SoundIndex( STRING( ent->v.ambient )); } // don't link not solid or rigid bodies - if( ent->progs.sv->solid == SOLID_NOT || ent->progs.sv->solid >= SOLID_BOX ) + if( ent->v.solid == SOLID_NOT || ent->v.solid >= SOLID_BOX ) { sv_ent->linked = true; return; @@ -414,15 +414,15 @@ void SV_LinkEdict( edict_t *ent ) while( 1 ) { if( node->axis == -1 ) break; - if( ent->progs.sv->absmin[node->axis] > node->dist ) + if( ent->v.absmin[node->axis] > node->dist ) node = node->children[0]; - else if( ent->progs.sv->absmax[node->axis] < node->dist ) + else if( ent->v.absmax[node->axis] < node->dist ) node = node->children[1]; else break; // crosses the node } // link it in - if( ent->progs.sv->solid == SOLID_TRIGGER ) + if( ent->v.solid == SOLID_TRIGGER ) SV_InsertLinkBefore( &sv_ent->area, &node->trigger_edicts, ent ); else SV_InsertLinkBefore (&sv_ent->area, &node->solid_edicts, ent ); sv_ent->linked = true; @@ -458,10 +458,10 @@ void SV_AreaEdicts_r( areanode_t *node, area_t *ap ) next = l->next; check = EDICT_FROM_AREA( l ); - if( check->progs.sv->solid == SOLID_NOT ) continue; // deactivated - if( check->progs.sv->absmin[0] > ap->maxs[0] || check->progs.sv->absmin[1] > ap->maxs[1] - || check->progs.sv->absmin[2] > ap->maxs[2] || check->progs.sv->absmax[0] < ap->mins[0] - || check->progs.sv->absmax[1] < ap->mins[1] || check->progs.sv->absmax[2] < ap->mins[2] ) + if( check->v.solid == SOLID_NOT ) continue; // deactivated + if( check->v.absmin[0] > ap->maxs[0] || check->v.absmin[1] > ap->maxs[1] + || check->v.absmin[2] > ap->maxs[2] || check->v.absmax[0] < ap->mins[0] + || check->v.absmax[1] < ap->mins[1] || check->v.absmax[2] < ap->mins[2] ) continue; // not touching if( ap->count == ap->maxcount ) diff --git a/launch/crclib.c b/launch/crclib.c index b124dfbb..b5cab274 100644 --- a/launch/crclib.c +++ b/launch/crclib.c @@ -119,17 +119,17 @@ static byte chktbl[1024] = 0x39, 0x4f, 0xdd, 0xe4, 0xb6, 0x19, 0x27, 0xfb, 0xb8, 0xf5, 0x32, 0x73, 0xe5, 0xcb, 0x32 }; -void CRC_Init(word *crcvalue) +void CRC_Init( word *crcvalue ) { *crcvalue = CRC_INIT_VALUE; } -void CRC_ProcessByte(word *crcvalue, byte data) +void CRC_ProcessByte( word *crcvalue, byte data ) { *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; } -word CRC_Block (byte *start, int count) +word CRC_Block( byte *start, int count ) { word crc; diff --git a/launch/system.c b/launch/system.c index c7b50ced..5ced160d 100644 --- a/launch/system.c +++ b/launch/system.c @@ -154,6 +154,7 @@ void Sys_GetStdAPI( void ) com.fread = FS_Read; // same as fread, can see trough pakfile com.fprint = FS_Print; // printed message into file com.fprintf = FS_Printf; // same as fprintf + com.fgetc = FS_Getc; // same as fgetc com.fgets = FS_Gets; // like a fgets, but can return EOF com.fseek = FS_Seek; // fseek, can seek in packfiles too com.fremove = FS_Remove; // like remove diff --git a/physic/cm_callback.c b/physic/cm_callback.c index 6803fadd..7d508687 100644 --- a/physic/cm_callback.c +++ b/physic/cm_callback.c @@ -54,7 +54,7 @@ int Callback_ContactProcess( const NewtonMaterial* material, const NewtonContact // this function is call after all contacts for this pairs is processed void Callback_ContactEnd( const NewtonMaterial* material ) { - sv_edict_t *edict = (sv_edict_t *)NewtonBodyGetUserData( cms.touch_info.m_body0 ); + edict_t *edict = (edict_t *)NewtonBodyGetUserData( cms.touch_info.m_body0 ); int id = NewtonBodyGetMaterialGroupID( cms.touch_info.m_body0 ); // if the max contact speed is larger than some minimum value. play a sound @@ -110,12 +110,12 @@ void Callback_ApplyForce_NoGravity( const NewtonBody* body ) void Callback_PmoveApplyForce( const NewtonBody* body ) { // grab state and jump to CM_ServerMove - pi.ClientMove((sv_edict_t *)NewtonBodyGetUserData( body )); + pi.ClientMove((edict_t *)NewtonBodyGetUserData( body )); } void Callback_ApplyTransform( const NewtonBody* body, const float* src ) { - sv_edict_t *edict = (sv_edict_t *)NewtonBodyGetUserData( body ); + edict_t *edict = (edict_t *)NewtonBodyGetUserData( body ); matrix4x4 tmp; matrix3x3 dst; vec3_t origin; diff --git a/physic/cm_local.h b/physic/cm_local.h index 246eff82..0d2bf21c 100644 --- a/physic/cm_local.h +++ b/physic/cm_local.h @@ -145,7 +145,7 @@ typedef struct clipmap_s uint checksum; // map checksum // shared copy of map (client - server) - char *entitystring; + script_t *entityscript; cplane_t *planes; // 12 extra planes for box hull cleaf_t *leafs; // 1 extra leaf for box hull dleafbrush_t *leafbrushes; diff --git a/physic/cm_model.c b/physic/cm_model.c index 0e389899..ae4bd4e4 100644 --- a/physic/cm_model.c +++ b/physic/cm_model.c @@ -77,7 +77,7 @@ void CM_FreeModel( cmodel_t *mod ) int CM_NumTextures( void ) { return cm.numshaders; } int CM_NumClusters( void ) { return cm.numclusters; } int CM_NumInlineModels( void ) { return cms.numbmodels; } -const char *CM_EntityString( void ) { return cm.entitystring; } +script_t *CM_EntityScript( void ) { return cm.entityscript; } const char *CM_TexName( int index ) { return cm.shaders[index].name; } /* @@ -619,9 +619,8 @@ void BSP_LoadEntityString( wfile_t *l ) byte *in; in = WAD_Read( l, LUMP_ENTITIES, &filelen, TYPE_SCRIPT ); - cm.entitystring = (byte *)Mem_Alloc( cmappool, filelen ); + cm.entityscript = Com_OpenScript( LUMP_ENTITIES, in, filelen ); cm.checksum = LittleLong(Com_BlockChecksum( in, filelen )); - Mem_Copy( cm.entitystring, in, filelen ); } /* @@ -935,7 +934,11 @@ void CM_FreeWorld( void ) cmodel_t *mod; // free old stuff - if( cms.loaded ) Mem_EmptyPool( cmappool ); + if( cms.loaded ) + { + Com_CloseScript( cm.entityscript ); + Mem_EmptyPool( cmappool ); + } Mem_Set( &cm, 0, sizeof( cm )); for( i = 0, mod = cms.bmodels; i < cms.numbmodels; i++, mod++ ) @@ -978,13 +981,16 @@ cmodel_t *CM_BeginRegistration( const char *name, bool clientload, uint *checksu if(!com.strcmp( cm.name, name ) && cms.loaded ) { - // singleplayer mode: serever already loading map + // singleplayer mode: server already loading map *checksum = cm.checksum; if( !clientload ) { // rebuild portals for server Mem_Set( cms.portalopen, 0, sizeof( cms.portalopen )); CM_FloodAreaConnections(); + + // and reset entity script + Com_ResetScript( cm.entityscript ); } // still have the right version return &cms.bmodels[0]; diff --git a/physic/cm_pmove.c b/physic/cm_pmove.c index 618fbbff..94321ce2 100644 --- a/physic/cm_pmove.c +++ b/physic/cm_pmove.c @@ -238,7 +238,7 @@ void CM_ClientMove( pmove_t *pmove ) } -physbody_t *Phys_CreatePlayer( sv_edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ) +physbody_t *Phys_CreatePlayer( edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ) { NewtonCollision *col, *hull; NewtonBody *body; diff --git a/physic/cm_rigidbody.c b/physic/cm_rigidbody.c index 774670d4..ae723e6b 100644 --- a/physic/cm_rigidbody.c +++ b/physic/cm_rigidbody.c @@ -8,7 +8,7 @@ #include "matrix_lib.h" #include "cm_local.h" -physbody_t *Phys_CreateBody( sv_edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ) +physbody_t *Phys_CreateBody( edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ) { NewtonCollision *col; NewtonBody *body; diff --git a/physic/cm_utils.h b/physic/cm_utils.h index 9d032b35..53c0ef59 100644 --- a/physic/cm_utils.h +++ b/physic/cm_utils.h @@ -54,7 +54,7 @@ byte *CM_FatPVS( const vec3_t org, bool portal ); int CM_NumClusters( void ); int CM_NumTextures( void ); int CM_NumInlineModels( void ); -const char *CM_EntityString( void ); +script_t *CM_EntityScript( void ); const char *CM_TexName( int index ); int CM_PointContents( const vec3_t p, cmodel_t *model ); int CM_TransformedPointContents( const vec3_t p, cmodel_t *model, const vec3_t origin, const vec3_t angles ); diff --git a/physic/physic.c b/physic/physic.c index fd53b4af..c40c56f1 100644 --- a/physic/physic.c +++ b/physic/physic.c @@ -96,7 +96,7 @@ physic_exp_t DLLEXPORT *CreateAPI ( stdlib_api_t *input, physic_imp_t *engfuncs Phys.NumClusters = CM_NumClusters; Phys.NumTextures = CM_NumTextures; Phys.NumBmodels = CM_NumInlineModels; - Phys.GetEntityString = CM_EntityString; + Phys.GetEntityScript = CM_EntityScript; Phys.GetTextureName = CM_TexName; Phys.ClipToGenericEntity = CM_CollisionClipToGenericEntity; Phys.ClipToWorld = CM_CollisionClipToWorld; diff --git a/physic/physic.dsp b/physic/physic.dsp index 27d1ffb1..d3a3683d 100644 --- a/physic/physic.dsp +++ b/physic/physic.dsp @@ -90,7 +90,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept -# ADD LINK32 user32.lib msvcrtd.lib newton.lib opengl32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept /libpath:"../public/libs/" +# ADD LINK32 user32.lib msvcrtd.lib newton.lib opengl32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept # SUBTRACT LINK32 /nodefaultlib # Begin Custom Build TargetDir=\Xash3D\src_main\temp\physic\!debug diff --git a/physic/physic.h b/physic/physic.h index d1fbb356..c2bcbf9d 100644 --- a/physic/physic.h +++ b/physic/physic.h @@ -44,8 +44,8 @@ void Phys_Frame( float time ); // // cm_rigidbody.c // -physbody_t *Phys_CreateBody( sv_edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ); -physbody_t *Phys_CreatePlayer( sv_edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ); +physbody_t *Phys_CreateBody( edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ); +physbody_t *Phys_CreatePlayer( edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ); void Phys_SetParameters( physbody_t *body, cmodel_t *mod, int material, float mass ); bool Phys_GetForce( physbody_t *body, vec3_t velocity, vec3_t avelocity, vec3_t force, vec3_t torque ); void Phys_SetForce( physbody_t *body, vec3_t velocity, vec3_t avelocity, vec3_t force, vec3_t torque ); diff --git a/public/const.h b/public/const.h index dad01fab..918a9df7 100644 --- a/public/const.h +++ b/public/const.h @@ -5,9 +5,95 @@ #ifndef CONST_H #define CONST_H +// euler angle order +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + +#define VOL_NORM 1.0 // volume values + +// pitch values +#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high +#define PITCH_NORM 100 // non-pitch shifted +#define PITCH_HIGH 120 + +// attenuation values +#define ATTN_NONE 0 +#define ATTN_NORM 0.8f +#define ATTN_IDLE 2.0f +#define ATTN_STATIC 1.25f + +// channels +#define CHAN_AUTO 0 +#define CHAN_WEAPON 1 +#define CHAN_VOICE 2 +#define CHAN_ITEM 3 +#define CHAN_BODY 4 +#define CHAN_STREAM 5 // allocate stream channel from the static or dynamic area +#define CHAN_STATIC 6 // allocate channel from the static area + +// in buttons +#define IN_ATTACK (1<<0) +#define IN_JUMP (1<<1) +#define IN_DUCK (1<<2) +#define IN_FORWARD (1<<3) +#define IN_BACK (1<<4) +#define IN_USE (1<<5) +#define IN_CANCEL (1<<6) +#define IN_LEFT (1<<7) +#define IN_RIGHT (1<<8) +#define IN_MOVELEFT (1<<9) +#define IN_MOVERIGHT (1<<10) +#define IN_ATTACK2 (1<<11) +#define IN_RUN (1<<12) +#define IN_RELOAD (1<<13) +#define IN_ALT1 (1<<14) +#define IN_SCORE (1<<15) // Used by client.dll for when scoreboard is held down + // edict_t->spawnflags #define SF_START_ON 0x1 +// edict->flags +#define FL_CLIENT (1<<0) +#define FL_MONSTER (1<<1) // monster bit +#define FL_INWATER (1<<2) +#define FL_INTERMISSION (1<<3) +#define FL_ONGROUND (1<<2) // at rest / on the ground +#define FL_SKYENTITY (1<<5) // it's a env_sky entity +#define FL_WATERJUMP (1<<6) // player jumping out of water +#define FL_FLOAT (1<<7) // Apply floating force to this entity when in water +#define FL_GRAPHED (1<<8) // worldgraph has this ent listed as something that blocks a connection +#define FL_TANK (1<<9) // this is func tank +#define FL_ROCKET (1<<10) // this is rocket entity +#define FL_POINTENTITY (1<<11) // this is point entity +#define FL_PROXY (1<<12) // This is a spectator proxy +#define FL_FRAMETHINK (1<<13) // Brush model flag -- call think every frame regardless of nextthink - ltime (for constantly changing velocity/path) +#define FL_BASEVELOCITY (1<<14) // Base velocity has been applied this frame (used to convert base velocity into momentum) +#define FL_MONSTERCLIP (1<<15) // Only collide in with monsters who have FL_MONSTERCLIP set +#define FL_ONTRAIN (1<<16) // Player is _controlling_ a train, so movement commands should be ignored on client during prediction. +#define FL_WORLDBRUSH (1<<17) // Not moveable/removeable brush entity (really part of the world, but represented as an entity for transparency or something) +#define FL_SPECTATOR (1<<18) // This client is a spectator, don't run touch functions, etc. +#define FL_CUSTOMENTITY (1<<19) // This is a custom entity +#define FL_KILLME (1<<20) // This entity is marked for death -- This allows the engine to kill ents at the appropriate time +#define FL_DORMANT (1<<21) // Entity is dormant, no updates to client +#define FL_PARTIALONGROUND (1<<22) // not corners are valid + +// edict->aiflags +#define AI_FLY (1<<0) // changes the SV_Movestep() behavior to not need to be on ground +#define AI_SWIM (1<<1) // same as AI_FLY but stay in water +#define AI_WATERJUMP (1<<2) // -- reserved -- + +#define AI_GODMODE (1<<4) // invulnerability npc or client +#define AI_NOTARGET (1<<5) // mark any npc as neytral +#define AI_NOSTEP (1<<6) // -- reserved -- +#define AI_DUCKED (1<<7) // monster (or player) is ducked +#define AI_JUMPING (1<<8) // monster (or player) is jumping +#define AI_FROZEN (1<<9) // stop moving, but continue thinking (e.g. for thirdperson camera) +#define AI_ACTOR (1<<10) // npc that playing scriped_sequence +#define AI_DRIVER (1<<11) // npc or player driving vehcicle or train +#define AI_SPECTATOR (1<<12) // spectator mode for clients + + // entity_state_t->effects #define EF_BRIGHTFIELD (1<<0) // swirling cloud of particles #define EF_MUZZLEFLASH (1<<1) // single frame ELIGHT on entity attachment 0 @@ -18,9 +104,101 @@ #define EF_NODRAW (1<<6) // don't draw entity #define EF_ROTATE (1<<7) // rotate bonus item #define EF_MINLIGHT (1<<8) // allways have some light (viewmodel) +#define EF_LIGHT (1<<9) // dynamic light (rockets use) + +// edict->deadflag values +#define DEAD_NO 0 // alive +#define DEAD_DYING 1 // playing death animation or still falling off of a ledge waiting to hit ground +#define DEAD_DEAD 2 // dead. lying still. +#define DEAD_RESPAWNABLE 3 // wait for respawn +#define DEAD_DISCARDBODY 4 + +#define DAMAGE_NO 0 +#define DAMAGE_YES 1 +#define DAMAGE_AIM 2 + +// engine edict types +typedef enum +{ + ED_SPAWNED = 0, // this entity requris to set own type with SV_ClassifyEdict + ED_WORLDSPAWN, // this is a worldspawn + ED_STATIC, // this is a logic without model or entity with static model + ED_AMBIENT, // this is entity emitted ambient sounds only + ED_NORMAL, // normal entity with model (and\or) sound + ED_BSPBRUSH, // brush entity (a part of level) + ED_CLIENT, // this is a client entity + ED_MONSTER, // monster or bot (generic npc with AI) + ED_TEMPENTITY, // this edict will be removed on server when "lifetime" exceeds + ED_BEAM, // laser beam (needs to recalculate pvs and frustum) + ED_MOVER, // func_train, func_door and another bsp or mdl movers + ED_VIEWMODEL, // client or bot viewmodel (for spectating) + ED_ITEM, // holdable items + ED_RAGDOLL, // dead body with simulated ragdolls + ED_RIGIDBODY, // simulated physic + ED_TRIGGER, // just for sorting on a server + ED_PORTAL, // realtime display, portal or mirror brush or model + ED_MISSILE, // greande, rocket e.t.c + ED_DECAL, // render will be merge real coords and normal + ED_VEHICLE, // controllable vehicle + ED_MAXTYPES, +} edtype_t; + +// edict movetype +typedef enum +{ + MOVETYPE_NONE, // never moves + MOVETYPE_NOCLIP, // origin and angles change with no interaction + MOVETYPE_PUSH, // no clip to world, push on box contact + MOVETYPE_WALK, // gravity + MOVETYPE_STEP, // gravity, special edge handling + MOVETYPE_FLY, + MOVETYPE_TOSS, // gravity + MOVETYPE_BOUNCE, + MOVETYPE_FOLLOW, // attached models + MOVETYPE_CONVEYOR, + MOVETYPE_PUSHSTEP, + MOVETYPE_PHYSIC, // phys simulation +} movetype_t; + +// edict collision modes +typedef enum +{ + SOLID_NOT = 0, // no interaction with other objects + SOLID_TRIGGER, // only touch when inside, after moving + SOLID_BBOX, // touch on edge + SOLID_SLIDEBOX, // + SOLID_BSP, // bsp clip, touch on edge + SOLID_BOX, // physbox + SOLID_SPHERE, // sphere + SOLID_CYLINDER, // cylinder e.g. barrel + SOLID_MESH, // custom convex hull +} solid_t; + +typedef enum +{ + point_hull = 0, + human_hull = 1, + large_hull = 2, + head_hull = 3 +}; + +// beam types, encoded as a byte +typedef enum +{ + BEAM_POINTS = 0, + BEAM_ENTPOINT, + BEAM_ENTS, + BEAM_HOSE, +} kBeamType_t; + +// lower bits encoded as kBeamType_t (max 8 types) +#define BEAM_FSINE (1<<3) +#define BEAM_FSOLID (1<<4) +#define BEAM_FSHADEIN (1<<5) +#define BEAM_FSHADEOUT (1<<6) // rendering constants -enum +typedef enum { kRenderNormal, // src kRenderTransColor, // c*a+dest*(1-a) @@ -30,12 +208,21 @@ enum kRenderTransAdd, // src*a+dest } kRenderMode_t; -enum +typedef enum { kRenderFxNone = 0, + + // legacy stuff are not supported + + kRenderFxNoDissipation = 14, + kRenderFxDistort, // Distort/scale/translate flicker kRenderFxHologram, // kRenderFxDistort + distance fade + kRenderFxDeadPlayer, // kRenderAmt is the player index + kRenderFxExplode, // Scale up really big! kRenderFxGlowShell, // Glowing Shell - kRenderFxNoReflect, // Don't reflecting in mirrors + kRenderFxClampMinScale, // Keep this sprite from getting very small (SPRITES only!) + kRenderFxAurora, // set particle trail for this entity + kRenderFxNoReflect, // don't reflecting in mirrors } kRenderFx_t; #endif//CONST_H \ No newline at end of file diff --git a/public/engine_api.h b/public/engine_api.h index ca2f30ea..c09cbff9 100644 --- a/public/engine_api.h +++ b/public/engine_api.h @@ -5,11 +5,15 @@ #ifndef ENGINE_API_H #define ENGINE_API_H +#include "const.h" + // // engine constant limits, touching networking protocol modify with precaution // #define MAX_DLIGHTS 128 // dynamic lights (per one frame) -#define MAX_LIGHTSTYLES 256 // can be blindly increased +#define MAX_LIGHTSTYLES 256 // can't be blindly increased +#define MAX_DECALS 256 // server decal indexes +#define MAX_USER_MESSAGES 200 // another 56 messages reserved for engine routines #define MAX_CLASSNAMES 512 // maxcount of various edicts classnames #define MAX_SOUNDS 512 // openal software limit #define MAX_MODELS 4096 // total count of brush & studio various models per one map @@ -17,62 +21,6 @@ #define MAX_EDICTS 65535 // absolute limit that never be reached, (do not edit!) #define MAX_VERTS_ON_POLY 10 // decal vertices -// engine edict types -typedef enum -{ - ED_SPAWNED = 0, // this entity requris to set own type with SV_ClassifyEdict - ED_WORLDSPAWN, // this is a worldspawn - ED_STATIC, // this is a logic without model or entity with static model - ED_AMBIENT, // this is entity emitted ambient sounds only - ED_NORMAL, // normal entity with model (and\or) sound - ED_BSPBRUSH, // brush entity (a part of level) - ED_CLIENT, // this is a client entity - ED_MONSTER, // monster or bot (generic npc with AI) - ED_TEMPENTITY, // this edict will be removed on server when "lifetime" exceeds - ED_BEAM, // laser beam (needs to recalculate pvs and frustum) - ED_MOVER, // func_train, func_door and another bsp or mdl movers - ED_VIEWMODEL, // client or bot viewmodel (for spectating) - ED_ITEM, // holdable items - ED_RAGDOLL, // dead body with simulated ragdolls - ED_RIGIDBODY, // simulated physic - ED_TRIGGER, // just for sorting on a server - ED_PORTAL, // realtime display, portal or mirror brush or model - ED_MISSILE, // greande, rocket e.t.c - ED_DECAL, // render will be merge real coords and normal - ED_VEHICLE, // controllable vehicle - ED_MAXTYPES, -} edtype_t; - -// edict movetype -typedef enum -{ - MOVETYPE_NONE, // never moves - MOVETYPE_NOCLIP, // origin and angles change with no interaction - MOVETYPE_PUSH, // no clip to world, push on box contact - MOVETYPE_WALK, // gravity - MOVETYPE_STEP, // gravity, special edge handling - MOVETYPE_FLY, - MOVETYPE_TOSS, // gravity - MOVETYPE_BOUNCE, - MOVETYPE_FOLLOW, // attached models - MOVETYPE_CONVEYOR, - MOVETYPE_PUSHABLE, - MOVETYPE_PHYSIC, // phys simulation -} movetype_t; - -// edict collision modes -typedef enum -{ - SOLID_NOT = 0, // no interaction with other objects - SOLID_TRIGGER, // only touch when inside, after moving - SOLID_BBOX, // touch on edge - SOLID_BSP, // bsp clip, touch on edge - SOLID_BOX, // physbox - SOLID_SPHERE, // sphere - SOLID_CYLINDER, // cylinder e.g. barrel - SOLID_MESH, // custom convex hull -} solid_t; - // model_state_t communication (a part of network protocol) typedef struct model_state_s { diff --git a/public/launch_api.h b/public/launch_api.h index df735c57..7b697cb7 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -19,7 +19,10 @@ #define DLLEXPORT __declspec( dllexport ) // generic engine types +#ifndef __cplusplus typedef enum { false, true } bool; +#endif + typedef unsigned char byte; typedef unsigned short word; typedef unsigned long dword; @@ -38,13 +41,11 @@ typedef vec_t matrix3x3[3][3]; typedef vec_t matrix4x4[4][4]; typedef char string[MAX_STRING]; typedef struct edict_s edict_t; -typedef struct sv_edict_s sv_edict_t; +typedef struct pr_edict_s pr_edict_t; typedef struct cl_edict_s cl_edict_t; typedef struct ui_edict_s ui_edict_t; -typedef struct sv_entvars_s sv_entvars_t; typedef struct cl_entvars_s cl_entvars_t; typedef struct ui_entvars_s ui_entvars_t; -typedef struct sv_globalvars_s sv_globalvars_t; typedef struct cl_globalvars_s cl_globalvars_t; typedef struct ui_globalvars_s ui_globalvars_t; typedef struct physbody_s physbody_t; @@ -532,6 +533,7 @@ typedef struct stdilib_api_s long (*fread)(file_t* file, void* buffer, size_t buffersize); // same as fread, can see trough pakfile int (*fprint)(file_t* file, const char *msg); // printed message into file int (*fprintf)(file_t* file, const char* format, ...); // same as fprintf + int (*fgetc)( file_t* file ); // same as fgetc int (*fgets)(file_t* file, byte *string, size_t bufsize ); // like a fgets, but can return EOF int (*fseek)(file_t* file, fs_offset_t offset, int whence); // fseek, can seek in packfiles too bool (*fremove)( const char *path ); // remove sepcified file @@ -746,6 +748,7 @@ filesystem manager #define FS_Print com.fprint #define FS_Seek com.fseek #define FS_Tell com.ftell +#define FS_Getc com.fgetc #define FS_Gets com.fgets #define FS_Delete com.fremove #define FS_Gamedir com.GameInfo->gamedir diff --git a/public/mathlib.h b/public/mathlib.h index e0760ff4..e1f3ca29 100644 --- a/public/mathlib.h +++ b/public/mathlib.h @@ -6,6 +6,7 @@ #define BASEMATH_H #include +#include "const.h" #ifndef M_PI #define M_PI (float)3.14159265358979323846 @@ -15,11 +16,6 @@ #define M_PI2 (float)6.28318530717958647692 #endif -// euler angle order -#define PITCH 0 -#define YAW 1 -#define ROLL 2 - #define METERS_PER_INCH 0.0254f #define EQUAL_EPSILON 0.001f #define STOP_EPSILON 0.1f diff --git a/public/physic_api.h b/public/physic_api.h index 77ee7c4c..262d6dbb 100644 --- a/public/physic_api.h +++ b/public/physic_api.h @@ -80,7 +80,7 @@ typedef struct physic_exp_s int (*NumClusters)( void ); int (*NumTextures)( void ); int (*NumBmodels )( void ); - const char *(*GetEntityString)( void ); + script_t *(*GetEntityScript)( void ); const char *(*GetTextureName)( int index ); byte *(*ClusterPVS)( int cluster ); byte *(*ClusterPHS)( int cluster ); @@ -101,8 +101,8 @@ typedef struct physic_exp_s void (*PlayerMove)( pmove_t *pmove, bool clientmove ); // simple objects - physbody_t *(*CreateBody)( sv_edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ); - physbody_t *(*CreatePlayer)( sv_edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ); + physbody_t *(*CreateBody)( edict_t *ed, cmodel_t *mod, const vec3_t org, const matrix3x3 m, int solid, int move ); + physbody_t *(*CreatePlayer)( edict_t *ed, cmodel_t *mod, const vec3_t origin, const matrix3x3 matrix ); void (*SetOrigin)( physbody_t *body, vec3_t origin ); void (*SetParameters)( physbody_t *body, cmodel_t *mod, int material, float mass ); @@ -118,10 +118,10 @@ typedef struct physic_imp_s // interface validator size_t api_size; // must matched with sizeof(physic_imp_t) - void (*ClientMove)( sv_edict_t *ed ); - void (*Transform)( sv_edict_t *ed, const vec3_t org, const matrix3x3 matrix ); - void (*PlaySound)( sv_edict_t *ed, float volume, float pitch, const char *sample ); - float *(*GetModelVerts)( sv_edict_t *ent, int *numvertices ); + void (*ClientMove)( edict_t *ed ); + void (*Transform)( edict_t *ed, const vec3_t org, const matrix3x3 matrix ); + void (*PlaySound)( edict_t *ed, float volume, float pitch, const char *sample ); + float *(*GetModelVerts)( edict_t *ent, int *numvertices ); } physic_imp_t; #endif//PHYSIC_API_H \ No newline at end of file diff --git a/public/qfiles_ref.h b/public/qfiles_ref.h index e338933f..99c030e3 100644 --- a/public/qfiles_ref.h +++ b/public/qfiles_ref.h @@ -245,6 +245,13 @@ typedef enum #define LUMP_AREAS "areas" #define LUMP_AREAPORTALS "areaportals" +#define MAP_SINGLEPLAYER BIT(0) +#define MAP_DEATHMATCH BIT(1) // Classic DeathMatch +#define MAP_COOPERATIVE BIT(2) // Cooperative mode +#define MAP_TEAMPLAY_CTF BIT(3) // teamplay Capture The Flag +#define MAP_TEAMPLAY_DOM BIT(4) // teamplay dominate +#define MAP_LASTMANSTANDING BIT(5) + typedef enum { SURF_NONE = 0, // just a mask for source tabulation @@ -310,7 +317,8 @@ typedef struct int ident; int version; char message[64]; // map message - int reserved[14]; // future expansions + int flags; // map flags + int reserved[13]; // future expansions } dheader_t; typedef struct diff --git a/public/svgame_api.h b/public/svgame_api.h new file mode 100644 index 00000000..37cceb15 --- /dev/null +++ b/public/svgame_api.h @@ -0,0 +1,327 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// svgame_api.h - entity interface between engine and svgame +//======================================================================= +#ifndef SVGAME_API_H +#define SVGAME_API_H + +#define INTERFACE_VERSION 138 + +typedef enum +{ + at_console = 1, // format: [msg] + at_warning, // format: Warning: [msg] + at_error, // format: Error: [msg] + at_loading, // print messages during loading + at_aiconsole, // same as at_console, but only shown if developer level is 5! + at_logged // server print to console ( only in multiplayer games ). +} ALERT_TYPE; + +// Client_Printf modes +enum +{ + print_console = 0, + print_center, + print_chat +}; + +enum +{ + WALKMOVE_NORMAL = 0, + WALKMOVE_NOMONSTERS, + WALKMOVE_MISSILE, + WALKMOVE_WORLDONLY, + WALKMOVE_HITMODEL, + WALKMOVE_CHECKONLY, +}; + +#define at_debug at_console // FIXME: stupid Laurie stuff + +// NOTE: engine trace struct not matched with svgame trace +typedef struct +{ + bool fAllSolid; // if true, plane is not valid + bool fStartSolid; // if true, the initial point was in a solid area + bool fStartStuck; // if true, trace started from solid entity + float flFraction; // time completed, 1.0 = didn't hit anything + vec3_t vecEndPos; // final position + int iStartContents; // start pos conetnts + int iContents; // final pos contents + int iHitgroup; // 0 == generic, non zero is specific body part + float flPlaneDist; // planes distance + vec3_t vecPlaneNormal; // surface normal at impact + const char *pTexName; // texture name that we hitting (brushes and studiomodels) + edict_t *pHit; // entity the surface is on +} TraceResult; + +// engine hands this to DLLs for functionality callbacks +typedef struct enginefuncs_s +{ + // interface validator + int api_size; // must matched with sizeof( enginefuncs_t ) + + int (*pfnPrecacheModel)( const char* s ); + int (*pfnPrecacheSound)( const char* s ); + void (*pfnSetModel)( edict_t *e, const char *m ); + int (*pfnModelIndex)( const char *m ); + int (*pfnModelFrames)( int modelIndex ); + void (*pfnSetSize)( edict_t *e, const float *rgflMin, const float *rgflMax ); + void (*pfnChangeLevel)( const char* s1, const char* s2 ); + float (*pfnVecToYaw)( const float *rgflVector ); + void (*pfnVecToAngles)( const float *rgflVectorIn, float *rgflVectorOut ); + void (*pfnMoveToOrigin)( edict_t *ent, const float *pflGoal, float dist, int iMoveType ); + void (*pfnChangeYaw)( edict_t* ent ); + void (*pfnChangePitch)( edict_t* ent ); + edict_t* (*pfnFindEntityByString)( edict_t *pStartEdict, const char *pszField, const char *pszValue); + int (*pfnGetEntityIllum)( edict_t* pEnt ); + edict_t* (*pfnFindEntityInSphere)( edict_t *pStartEdict, const float *org, float rad ); + edict_t* (*pfnFindClientInPVS)( edict_t *pEdict ); + edict_t* (*pfnFindClientInPHS)( edict_t *pEdict ); + edict_t* (*pfnEntitiesInPVS)( edict_t *pplayer ); + edict_t* (*pfnEntitiesInPHS)( edict_t *pplayer ); + void (*pfnMakeVectors)( const float *rgflVector ); + void (*pfnAngleVectors)( const float *rgflVector, float *forward, float *right, float *up ); + edict_t* (*pfnCreateEntity)( void ); + void (*pfnRemoveEntity)( edict_t* e ); + edict_t* (*pfnCreateNamedEntity)( string_t className ); + void (*pfnMakeStatic)( edict_t *ent ); + int (*pfnEntIsOnFloor)( edict_t *e ); + int (*pfnDropToFloor)( edict_t* e ); + int (*pfnWalkMove)( edict_t *ent, float yaw, float dist, int iMode ); + void (*pfnSetOrigin)( edict_t *e, const float *rgflOrigin ); + void (*pfnSetAngles)( edict_t *e, const float *rgflAngles ); + void (*pfnEmitSound)( edict_t *ent, int chan, const char *sample, float vol, float attn, int flags, int pitch ); + void (*pfnEmitAmbientSound)( edict_t *ent, float *pos, const char *samp, float vol, float attn, int flags, int pitch ); + void (*pfnTraceLine)( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceToss)( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ); + void (*pfnTraceHull)( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ); + void (*pfnTraceModel)( const float *v1, const float *v2, edict_t *pent, TraceResult *ptr ); + const char *(*pfnTraceTexture)( edict_t *pTextureEntity, const float *v1, const float *v2 ); + void (*pfnGetAimVector)( edict_t* ent, float speed, float *rgflReturn ); + void (*pfnServerCommand)( const char* str ); + void (*pfnServerExecute)( void ); + void (*pfnClientCommand)( edict_t* pEdict, char* szFmt, ... ); + void (*pfnParticleEffect)( const float *org, const float *dir, float color, float count ); + void (*pfnLightStyle)( int style, char* val ); + int (*pfnDecalIndex)( const char *name ); + int (*pfnPointContents)( const float *rgflVector); + void (*pfnMessageBegin)( int msg_dest, int msg_type, const float *pOrigin, edict_t *ed ); + void (*pfnMessageEnd)( void ); + void (*pfnWriteByte)( int iValue ); + void (*pfnWriteChar)( int iValue ); + void (*pfnWriteShort)( int iValue ); + void (*pfnWriteLong)( int iValue ); + void (*pfnWriteAngle)( float flValue ); + void (*pfnWriteCoord)( float flValue ); + void (*pfnWriteString)( const char *sz ); + void (*pfnWriteEntity)( int iValue ); + void (*pfnCVarRegister)( const char *name, const char *value, int flags, const char *desc ); + float (*pfnCVarGetFloat)( const char *szVarName ); + const char* (*pfnCVarGetString)( const char *szVarName ); + void (*pfnCVarSetFloat)( const char *szVarName, float flValue ); + void (*pfnCVarSetString)( const char *szVarName, const char *szValue ); + void (*pfnAlertMessage)( ALERT_TYPE level, char *szFmt, ... ); + void* (*pfnPvAllocEntPrivateData)( edict_t *pEdict, long cb ); + void (*pfnFreeEntPrivateData)( edict_t *pEdict ); + string_t (*pfnAllocString)( const char *szValue ); + edict_t* (*pfnPEntityOfEntOffset)( int iEntOffset ); + int (*pfnEntOffsetOfPEntity)( const edict_t *pEdict ); + int (*pfnIndexOfEdict)( const edict_t *pEdict ); + edict_t* (*pfnPEntityOfEntIndex)( int iEntIndex ); + edict_t* (*pfnFindEntityByVars)( entvars_t* pvars ); + void* (*pfnGetModelPtr)( edict_t* pEdict ); + int (*pfnRegUserMsg)( const char *pszName, int iSize ); + void (*pfnAnimationAutomove)( const edict_t* pEdict, float flTime ); + void (*pfnGetBonePosition)( const edict_t* pEdict, int iBone, float *rgflOrigin, float *rgflAngles ); + dword (*pfnFunctionFromName)( const char *pName ); + const char *(*pfnNameForFunction)( dword function ); + void (*pfnClientPrintf)( edict_t* pEdict, int ptype, const char *szMsg ); + void (*pfnServerPrint)( const char *szMsg ); + void (*pfnAreaPortal)( edict_t *pEdict, bool enable ); + const char *(*pfnCmd_Args)( void ); + const char *(*pfnCmd_Argv)( int argc ); + int (*pfnCmd_Argc)( void ); + void (*pfnGetAttachment)( const edict_t *pEdict, int iAttachment, float *rgflOrigin, float *rgflAngles ); + void (*pfnCRC_Init)( word *pulCRC ); + void (*pfnCRC_ProcessBuffer)( word *pulCRC, void *p, int len ); + word (*pfnCRC_Final)( word pulCRC ); + long (*pfnRandomLong)( long lLow, long lHigh ); + float (*pfnRandomFloat)( float flLow, float flHigh ); + void (*pfnSetView)( const edict_t *pClient, const edict_t *pViewent ); + void (*pfnCrosshairAngle)( const edict_t *pClient, float pitch, float yaw ); + byte* (*pfnLoadFile)( const char *filename, int *pLength ); + void (*pfnFreeFile)( void *buffer ); + int (*pfnCompareFileTime)( const char *filename1, const char *filename2, int *iCompare ); + void (*pfnGetGameDir)( char *szGetGameDir ); + void (*pfnStaticDecal)( const float *origin, int decalIndex, int entityIndex, int modelIndex ); + int (*pfnPrecacheGeneric)( const char* s ); + int (*pfnIsDedicatedServer)( void ); // is this a dedicated server? + int (*pfnIsMapValid)( char *filename ); + + void (*pfnInfo_RemoveKey)( char *s, char *key ); + char* (*pfnInfoKeyValue)( char *infobuffer, char *key ); + void (*pfnSetKeyValue)( char *infobuffer, char *key, char *value ); + char* (*pfnGetInfoKeyBuffer)( edict_t *e ); // passing in NULL gets the serverinfo + void (*pfnSetClientKeyValue)( int clientIndex, char *infobuffer, char *key, char *value ); + + void (*pfnSetSkybox)( const char *name ); + void (*pfnPlayMusic)( const char *trackname, int flags ); // background track + void (*pfnDropClient)( int clientIndex ); // used for kick cheaters from server +} enginefuncs_t; + +// passed to pfnKeyValue +typedef struct KeyValueData_s +{ + char *szClassName; // in: entity classname + char *szKeyName; // in: name of key + char *szValue; // in: value of key + long fHandled; // out: DLL sets to true if key-value pair was understood +} KeyValueData; + +typedef struct +{ + char mapName[64]; + char landmarkName[64]; + edict_t *pentLandmark; + vec3_t vecLandmarkOrigin; +} LEVELLIST; + +typedef struct +{ + int id; // ordinal ID of this entity (used for entity <--> pointer conversions) + edict_t *pent; // pointer to the in-game entity + + int location; // offset from the base data of this entity + int size; // byte size of this entity's data + int flags; // bit mask of transitions that this entity is in the PVS of + string_t classname; // entity class name +} ENTITYTABLE; + +#define FTYPEDESC_GLOBAL 0x0001 // This field is masked for global entity save/restore +#define MAX_LEVEL_CONNECTIONS 32 // These are encoded in the lower 16bits of ENTITYTABLE->flags + +#define FENTTABLE_GLOBAL 0x10000000 +#define FENTTABLE_MOVEABLE 0x20000000 +#define FENTTABLE_REMOVED 0x40000000 +#define FENTTABLE_PLAYER 0x80000000 + +typedef struct saverestore_s +{ + char *pBaseData; // start of all entity save data + char *pCurrentData; // current buffer pointer for sequential access + int size; // current data size + int bufferSize; // total space for data + int tokenSize; // size of the linear list of tokens + int tokenCount; // number of elements in the pTokens table + char **pTokens; // hash table of entity strings (sparse) + int currentIndex; // holds a global entity table ID + int tableCount; // number of elements in the entity table + int connectionCount; // number of elements in the levelList[] + ENTITYTABLE *pTable; // array of ENTITYTABLE elements (1 for each entity) + LEVELLIST levelList[MAX_LEVEL_CONNECTIONS]; // list of connections from this level + + // smooth transition + int fUseLandmark; + char szLandmarkName[64]; // landmark we'll spawn near in next level + vec3_t vecLandmarkOffset; // for landmark transitions + float time; + char szCurrentMap[64]; // To check global entities +} SAVERESTOREDATA; + +typedef enum _fieldtypes +{ + FIELD_FLOAT = 0, // any floating point value + FIELD_STRING, // a string ID (return from ALLOC_STRING) + FIELD_ENTITY, // an entity offset (EOFFSET) + FIELD_CLASSPTR, // CBaseEntity * + FIELD_EHANDLE, // entity handle + FIELD_EVARS, // EVARS * + FIELD_EDICT, // edict_t *, or edict_t * (same thing) + FIELD_VECTOR, // any vector + FIELD_POSITION_VECTOR, // a world coordinate (these are fixed up across level transitions automagically) + FIELD_POINTER, // arbitrary data pointer... to be removed, use an array of FIELD_CHARACTER + FIELD_INTEGER, // any integer or enum + FIELD_FUNCTION, // a class function pointer (Think, Use, etc) + FIELD_BOOLEAN, // boolean, implemented as an int, I may use this as a hint for compression + FIELD_SHORT, // 2 byte integer + FIELD_CHARACTER, // a byte + FIELD_TIME, // a floating point time (these are fixed up automatically too!) + FIELD_MODELNAME, // engine string that is a model name (needs precache) + FIELD_SOUNDNAME, // engine string that is a sound name (needs precache) + FIELD_RANGE, // Min and Max range for generate random value + + FIELD_TYPECOUNT, // MUST BE LAST +} FIELDTYPE; + +typedef struct +{ + FIELDTYPE fieldType; + char *fieldName; + int fieldOffset; + short fieldSize; + short flags; +} TYPEDESCRIPTION; + +#define offsetof( s, m ) (size_t)&(((s *)0)->m) +#define ARRAYSIZE( p ) (sizeof( p ) / sizeof( p[0] )) +#define _FIELD( type, name, fieldtype, count, flags ) { fieldtype, #name, offsetof( type, name ), count, flags } +#define DEFINE_FIELD( type, name, fieldtype ) _FIELD( type, name, fieldtype, 1, 0 ) +#define DEFINE_ARRAY( type, name, fieldtype, count ) _FIELD( type, name, fieldtype, count, 0 ) +#define DEFINE_ENTITY_FIELD( name, fieldtype ) _FIELD( entvars_t, name, fieldtype, 1, 0 ) +#define DEFINE_ENTITY_GLOBAL_FIELD( name, fieldtype ) _FIELD( entvars_t, name, fieldtype, 1, FTYPEDESC_GLOBAL ) +#define DEFINE_GLOBAL_FIELD( type, name, fieldtype ) _FIELD( type, name, fieldtype, 1, FTYPEDESC_GLOBAL ) + +typedef struct +{ + // interface validator + size_t api_size; // must matched with sizeof(DLL_FUNCTIONS) + + // initialize/shutdown the game (one-time call after loading of game .dll ) + void (*pfnGameInit)( void ); + int (*pfnSpawn)( edict_t *pent ); + void (*pfnThink)( edict_t *pent ); + void (*pfnUse)( edict_t *pentUsed, edict_t *pentOther ); + void (*pfnTouch)( edict_t *pentTouched, edict_t *pentOther ); + void (*pfnBlocked)( edict_t *pentBlocked, edict_t *pentOther ); + void (*pfnKeyValue)( edict_t *pentKeyvalue, KeyValueData *pkvd ); + void (*pfnSave)( edict_t *pent, SAVERESTOREDATA *pSaveData ); + int (*pfnRestore)( edict_t *pent, SAVERESTOREDATA *pSaveData, int globalEntity ); + void (*pfnSetAbsBox)( edict_t *pent ); + + void (*pfnSaveWriteFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveReadFields)( SAVERESTOREDATA*, const char*, void*, TYPEDESCRIPTION*, int ); + void (*pfnSaveGlobalState)( SAVERESTOREDATA * ); + void (*pfnRestoreGlobalState)( SAVERESTOREDATA * ); + void (*pfnResetGlobalState)( void ); + + int (*pfnClientConnect)( edict_t *pEntity, const char *userinfo ); + + void (*pfnClientDisconnect)( edict_t *pEntity ); + void (*pfnClientKill)( edict_t *pEntity ); + void (*pfnClientPutInServer)( edict_t *pEntity ); + void (*pfnClientCommand)( edict_t *pEntity ); + void (*pfnClientUserInfoChanged)( edict_t *pEntity, char *infobuffer ); + void (*pfnServerActivate)( edict_t *pEdictList, int edictCount, int clientMax ); + void (*pfnServerDeactivate)( void ); + void (*pfnPlayerPreThink)( edict_t *pEntity ); + void (*pfnPlayerPostThink)( edict_t *pEntity ); + + void (*pfnStartFrame)( void ); + void (*pfnParmsNewLevel)( void ); + void (*pfnParmsChangeLevel)( void ); + + // returns string describing current .dll. E.g., TeamFotrress 2, Half-Life + const char *(*pfnGetGameDescription)( void ); + // notify game .dll that engine is going to shut down. Allows mod authors to set a breakpoint. + void (*pfnHostError)( const char *error_string ); +} DLL_FUNCTIONS; + +// TODO: create single func +// typedef DLL_FUNCTIONS *(*GetEntityAPI)( enginefuncs_t* engfuncs, globalvars_t *pGlobals ); +// set pointer to globals, returns export of dll_functions and use CreateAPI as base offset + +typedef void (*GIVEFNPTRSTODLL)( enginefuncs_t* engfuncs, globalvars_t *pGlobals ); +typedef int (*APIFUNCTION)( DLL_FUNCTIONS *pFunctionTable, int interfaceVersion ); +typedef void (*LINK_ENTITY_FUNC)( entvars_t *pev ); + +#endif//SVGAME_API_H \ No newline at end of file diff --git a/public/svprog_def.h b/public/svprog_def.h new file mode 100644 index 00000000..631811b5 --- /dev/null +++ b/public/svprog_def.h @@ -0,0 +1,204 @@ +//======================================================================= +// Copyright XashXT Group 2008 © +// svprog_def.h - engine <-> svgame communications +//======================================================================= +#ifndef SVDEFS_API_H +#define SVDEFS_API_H + +typedef struct ed_priv_s ed_priv_t; // engine private data +typedef struct edict_s edict_t; + +typedef struct globalvars_s +{ + float time; + float frametime; + string_t mapname; + string_t startspot; + vec3_t spotOffset; // landmark offset + + bool deathmatch; + bool coop; + bool teamplay; + + int serverflags; + int maxClients; + int numClients; // actual clients count + int maxEntities; + int numEntities; // actual ents count + + vec3_t v_forward; + vec3_t v_right; + vec3_t v_up; + + bool trace_allsolid; + bool trace_startsolid; + bool trace_startstuck; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + int trace_start_contents; + int trace_contents; + int trace_hitgroup; + const char *trace_texture; // texture name that we hitting (brushes and studiomodels) + edict_t *trace_ent; + + int total_secrets; + int found_secrets; // number of secrets found + int total_monsters; + int killed_monsters; // number of monsters killed + + const char *pStringBase; // stringtable base offset + void *pSaveData; // savedata base offset +} globalvars_t; + +// NOT FINALIZED! +typedef struct entvars_s +{ + string_t classname; + string_t globalname; + edict_t *chain; // entity pointer when linked into a linked list + + vec3_t origin; + vec3_t angles; // model angles + int modelindex; + vec3_t oldorigin; // interpolated values + vec3_t oldangles; + + vec3_t m_pmatrix[3]; // rotational matrix + vec3_t m_pcentre[3]; // physical centre of mass + + vec3_t velocity; + vec3_t avelocity; // angle velocity (degrees per second) + vec3_t basevelocity; + vec3_t movedir; + vec3_t force; // linear physical impulse vector + vec3_t torque; // angular physical impulse vector + + string_t model; + string_t weaponmodel; // monster or player weaponmodel + + vec3_t absmin; // bbox max translated to world coord + vec3_t absmax; // bbox max translated to world coord + vec3_t mins; // local bbox min + vec3_t maxs; // local bbox max + vec3_t size; // maxs - mins + float mass; // physobject mass + + float ltime; + float nextthink; + + int movetype; + int solid; + + int skin; // + int body; // sub-model selection for studiomodels + int effects; + float gravity; // % of "normal" gravity + float friction; // inverse elasticity of MOVETYPE_BOUNCE + + int sequence; // animation sequence + float frame; // % playback position in animation sequences (0..255) + float animtime; // world time when frame was set + float framerate; // animation playback rate (-8x to 8x) + float controller[16]; // bone controller setting (0..255) + float blending[16]; // blending amount between sub-sequences (0..255) + + float scale; // model rendering scale (0..255) + int waterlevel; + int watertype; + int contents; + + float idealpitch; + float pitch_speed; + float ideal_yaw; + float yaw_speed; + + int rendermode; + float renderamt; + vec3_t rendercolor; + int renderfx; + + float health; + float frags; + int weapons; // bit mask for available weapons + float takedamage; + + int deadflag; + vec3_t view_ofs; // eye position + + int button; + int impulse; + + + edict_t *dmg_inflictor; + edict_t *enemy; + edict_t *aiment; // entity pointer when MOVETYPE_FOLLOW + edict_t *owner; + edict_t *groundentity; + + int spawnflags; // spwanflags are used only during level loading + int aiflags; // monsters and player flags + int phflags; // physic state flags + int flags; // generic flags that can be send to client + + // player specific only + vec3_t punchangle; // auto-decaying view angle adjustment + vec3_t v_angle; // viewing angle (player only) + int fixangle; // 0 - nothing, 1 - force view angles, 2 - add avelocity + string_t viewmodel; // player's viewmodel + float weaponframe; // viewmodel frame + int weaponsequence; + int weaponbody; // viewmodel body + int weaponskin; // viewmodel skin + int gaitsequence; // movement animation sequence for player (0 for none) + short colormap; // lowbyte topcolor, highbyte bottomcolor + int playerclass; + int team; // for teamplay + int weaponanim; + + float max_health; + float teleport_time; + int armortype; + float armorvalue; + + string_t target; + string_t targetname; + string_t netname; + string_t message; + + float dmg_take; + float dmg_save; + float dmgtime; + float dmg; + + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; + string_t ambient; + + float speed; + float air_finished; + float pain_finished; + float radsuit_finished; + + edict_t *pContainingEntity; // ptr to class for consistency +} entvars_t; + +// FIXME: make pvEngineData as generic ptr for both types (client and server are valid, entvars are shared) + +struct edict_s +{ + bool free; + float freetime; // sv.time when the object was freed + int serialnumber; + + ed_priv_t *pvEngineData; // alloced, freed and used by engine only + void *pvServerData; // alloced and freed by engine, used by DLLs + entvars_t v; // C exported fields from progs (network relative) + + // other fields from progs come immediately after +}; + +#endif//SVDEFS_API_H \ No newline at end of file diff --git a/public/vector_lib.h b/public/vector_lib.h deleted file mode 100644 index b01c060a..00000000 --- a/public/vector_lib.h +++ /dev/null @@ -1,11 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// mathlib.h - base math functions -//======================================================================= -#ifndef VECTOR_LIB_H -#define VECTOR_LIB_H - -#include "mathlib.h" //FIXME - - -#endif//VECTOR_LIB_H \ No newline at end of file diff --git a/public/vprogs_api.h b/public/vprogs_api.h index 603a6826..4a615610 100644 --- a/public/vprogs_api.h +++ b/public/vprogs_api.h @@ -32,21 +32,19 @@ enum }; typedef void (*prvm_builtin_t)( void ); -typedef struct edict_state_s +typedef struct vm_edict_s { bool free; float freetime; - } vm_edict_t; -struct edict_s +struct pr_edict_s { // engine-private fields (stored in dynamically resized array) union { void *vp; // generic edict vm_edict_t *ed; // vm edict state - sv_edict_t *sv; // sv edict state cl_edict_t *cl; // cl edict state vm_edict_t *ui; // ui edict state } priv; @@ -55,7 +53,6 @@ struct edict_s union { void *vp; // generic entvars - sv_entvars_t *sv; // server entvars cl_entvars_t *cl; // client entvars ui_entvars_t *ui; // uimenu entvars } progs; @@ -107,7 +104,6 @@ typedef struct prvm_prog_s union { float *gp; - sv_globalvars_t *sv; cl_globalvars_t *cl; ui_globalvars_t *ui; } globals; @@ -138,7 +134,7 @@ typedef struct prvm_prog_s int max_edicts; int limit_edicts; int reserved_edicts; - edict_t *edicts; + pr_edict_t *edicts; void *edictsfields; void *edictprivate; int edictprivate_size; @@ -154,12 +150,12 @@ typedef struct prvm_prog_s // function pointers void (*begin_increase_edicts)(void); void (*end_increase_edicts)(void); - void (*init_edict)(edict_t *edict); - void (*free_edict)(edict_t *ed); + void (*init_edict)(pr_edict_t *edict); + void (*free_edict)(pr_edict_t *ed); void (*count_edicts)(void); - bool (*load_edict)(edict_t *ent); // initialize edict for first loading - void (*restore_edict)(edict_t *ent); // restore edict from savegame or changelevel - void (*keyvalue_edict)(edict_t *ent, const char *key, const char *value ); // KeyValueData + bool (*load_edict)(pr_edict_t *ent); // initialize edict for first loading + void (*restore_edict)(pr_edict_t *ent); // restore edict from savegame or changelevel + void (*keyvalue_edict)(pr_edict_t *ent, const char *key, const char *value ); void (*init_cmd)(void); void (*reset_cmd)(void); void (*error_cmd)(const char *format, ...); @@ -180,14 +176,14 @@ typedef struct vprogs_exp_s void ( *Update )( dword time ); // refreshing compile, exec some programs e.t.c // edict operations - edict_t *(*AllocEdict)( void ); - void (*FreeEdict)( edict_t *ed ); - void (*PrintEdict)( edict_t *ed ); + pr_edict_t *(*AllocEdict)( void ); + void (*FreeEdict)( pr_edict_t *ed ); + void (*PrintEdict)( pr_edict_t *ed ); // savegame stuff void (*WriteGlobals)( void *buffer, void *ptr, setpair_t callback ); void (*ReadGlobals)( int s_table, dkeyvalue_t *globals, int count ); - void (*WriteEdict)( edict_t *ed, void *buffer, void *ptr, setpair_t callback ); + void (*WriteEdict)( pr_edict_t *ed, void *buffer, void *ptr, setpair_t callback ); void (*ReadEdict)( int s_table, int ednum, dkeyvalue_t *fields, int numpairs ); // load ents description diff --git a/public/vsound_api.h b/public/vsound_api.h index bde187f9..523bc0a0 100644 --- a/public/vsound_api.h +++ b/public/vsound_api.h @@ -5,33 +5,9 @@ #ifndef VSOUND_API_H #define VSOUND_API_H -// sound channels -typedef enum -{ - CHAN_AUTO = 0, - CHAN_WEAPON, - CHAN_VOICE, - CHAN_ITEM, - CHAN_BODY, - CHAN_ANNOUNCER, // announcer - - // snd flags - CHAN_NO_PHS_ADD = 8, // send to all clients, not just ones in PHS (ATTN 0 will also do this) - CHAN_RELIABLE = 16, // send by reliable message, not datagram -} snd_channel_t; - -// sound attenuation values -typedef enum -{ - ATTN_NONE = 0, // full volume the entire level - ATTN_NORM, - ATTN_IDLE, - ATTN_STATIC, // diminish very rapidly with distance -} snd_attenuation_t; - -#define PITCH_LOW 95 // other values are possible - 0-255, where 255 is very high -#define PITCH_NORM 100 // non-pitch shifted -#define PITCH_HIGH 120 +// snd internal flags (lower bits are used for snd channels) +#define CHAN_NO_PHS_ADD (1<<3) // send to all clients, not just ones in PHS (ATTN 0 will also do this) +#define CHAN_RELIABLE (1<<4) // send by reliable message, not datagram /* ============================================================================== diff --git a/render/r_image.c b/render/r_image.c index 3635b416..ba032f85 100644 --- a/render/r_image.c +++ b/render/r_image.c @@ -5,7 +5,7 @@ #include "r_local.h" #include "byteorder.h" -#include "vector_lib.h" +#include "mathlib.h" #include "const.h" static rgbdata_t *R_LoadImage( script_t *script, const char *name, const byte *buf, size_t size, int *samples, texFlags_t *flags ); diff --git a/render/render.dsp b/render/render.dsp index 55ddd977..55f3b459 100644 --- a/render/render.dsp +++ b/render/render.dsp @@ -91,7 +91,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 -# ADD LINK32 msvcrtd.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept /libpath:"../public/libs/" +# ADD LINK32 msvcrtd.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /pdbtype:sept # SUBTRACT LINK32 /profile /incremental:no /map # Begin Custom Build TargetDir=\Xash3D\src_main\temp\render\!debug diff --git a/sv_dll/cbase.h b/sv_dll/cbase.h new file mode 100644 index 00000000..69b9129f --- /dev/null +++ b/sv_dll/cbase.h @@ -0,0 +1,38 @@ +//======================================================================= +// Copyright (C) XashXT Group 2006 +// stdafx.h +//======================================================================= +#ifndef CBASE_H +#define CBASE_H + +class CBaseEntity; +class CBaseLogic; +class CBaseBrush; +class CBaseAnimating; +class CBaseMonster; +class CBasePlayerWeapon; +class CSquadMonster; +class CBaseMonster; +class CCineMonster; +class CBasePlayer; +class CSound; + +#include "hierarchy.h" +#include "globals.h" +#include "utils.h" +#include "saverestore.h" +#include "schedule.h" +#include "qfiles_ref.h" +#include "defaults.h" +#include "monsterevent.h" +#include "baseentity.h" +#include "baselogic.h" +#include "basesprite.h" +#include "baseinfo.h" +#include "baseanimating.h" +#include "baseitem.h" +#include "basebrush.h" +#include "basemonster.h" +#include "baseworld.h" + +#endif //CBASE_H \ No newline at end of file diff --git a/sv_dll/legacy.cpp b/sv_dll/legacy.cpp new file mode 100644 index 00000000..e69de29b diff --git a/sv_dll/server.def b/sv_dll/server.def new file mode 100644 index 00000000..a2eccc63 --- /dev/null +++ b/sv_dll/server.def @@ -0,0 +1,5 @@ +LIBRARY server +EXPORTS + GiveFnptrsToDll @1 +SECTIONS + .data READ WRITE diff --git a/sv_dll/server.dsp b/sv_dll/server.dsp new file mode 100644 index 00000000..f49f7a2b --- /dev/null +++ b/sv_dll/server.dsp @@ -0,0 +1,572 @@ +# Microsoft Developer Studio Project File - Name="server" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=server - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "server.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "server.mak" CFG="server - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "server - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "server - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/GoldSrc/server", ELEBAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "server - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\temp\server\!release" +# PROP Intermediate_Dir "..\temp\server\!release" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /c +# ADD CPP /nologo /GB /MD /W3 /O2 /I "./" /I "./ents" /I "./game" /I "./global" /I "./monsters" /I "../public" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# SUBTRACT CPP /Fr /YX +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 +# ADD LINK32 msvcrt.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\server.def" /libpath:"..\common\libs" +# SUBTRACT LINK32 /profile /map /debug /nodefaultlib +# Begin Custom Build - Performing Custom Build Step on $(InputPath) +TargetDir=\Xash3D\src_main\temp\server\!release +InputPath=\Xash3D\src_main\temp\server\!release\server.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\xash\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\server.dll "D:\Xash3D\xash\bin\server.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "server - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "server___Win32_Debug" +# PROP BASE Intermediate_Dir "server___Win32_Debug" +# PROP BASE Ignore_Export_Lib 1 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\temp\server\!debug" +# PROP Intermediate_Dir "..\temp\server\!debug" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MT /W3 /O2 /I "..\server" /I "..\common\engine" /I "..\common" /I "..\server\ents" /I "..\server\global" /I "..\server\weapons" /I "..\server\game" /I "..\server\monsters" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /GB /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "./ents" /I "./game" /I "./global" /I "./monsters" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c +# SUBTRACT CPP /u /YX +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /incremental:yes /machine:I386 /nodefaultlib:"libc" /def:".\server.def" /libpath:"..\common\libs" +# SUBTRACT BASE LINK32 /profile /map /debug +# ADD LINK32 msvcrtd.lib /nologo /subsystem:windows /dll /incremental:yes /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\server.def" /pdbtype:sept +# SUBTRACT LINK32 /profile /map +# Begin Custom Build - Performing Custom Build Step on $(InputPath) +TargetDir=\Xash3D\src_main\temp\server\!debug +InputPath=\Xash3D\src_main\temp\server\!debug\server.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\xash\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\server.dll "D:\Xash3D\xash\bin\server.dll" + +# End Custom Build + +!ENDIF + +# Begin Target + +# Name "server - Win32 Release" +# Name "server - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=.\monsters\ai_sound.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\animating.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\animation.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\apache.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\barnacle.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\barney.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basebrush.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseentity.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basefunc.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basefx.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseinfo.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseitem.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baselogic.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\basemonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basemover.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseother.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basepath.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baserockets.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basetank.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\basetrigger.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseutil.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseweapon.cpp +# End Source File +# Begin Source File + +SOURCE=.\ents\baseworld.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\client.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\combat.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\decals.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\defaultai.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\dll_int.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\flyingmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\game.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\generic.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\globals.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\gman.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\hassassin.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\headcrab.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\hgrunt.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\leech.cpp +# End Source File +# Begin Source File + +SOURCE=.\legacy.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\lights.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\multiplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\nodes.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\osprey.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\parent.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\player.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\rat.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\roach.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\saverestore.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\scientist.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\scripted.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\sfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\singleplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\sound.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\squadmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\talkmonster.cpp +# End Source File +# Begin Source File + +SOURCE=.\game\teamplay_gamerules.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\turret.cpp +# End Source File +# Begin Source File + +SOURCE=.\global\utils.cpp +# End Source File +# Begin Source File + +SOURCE=.\weapon_generic.cpp +# End Source File +# Begin Source File + +SOURCE=.\monsters\zombie.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\monsters\activity.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\activitymap.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\animation.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\baseanimating.h +# End Source File +# Begin Source File + +SOURCE=.\ents\basebeams.h +# End Source File +# Begin Source File + +SOURCE=.\ents\basebrush.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baseentity.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baseinfo.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baseitem.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baselogic.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\basemonster.h +# End Source File +# Begin Source File + +SOURCE=.\ents\basemover.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baserockets.h +# End Source File +# Begin Source File + +SOURCE=.\ents\basesprite.h +# End Source File +# Begin Source File + +SOURCE=.\ents\basetank.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baseweapon.h +# End Source File +# Begin Source File + +SOURCE=.\ents\baseworld.h +# End Source File +# Begin Source File + +SOURCE=.\global\bullets.h +# End Source File +# Begin Source File + +SOURCE=.\cbase.h +# End Source File +# Begin Source File + +SOURCE=.\global\cdll_dll.h +# End Source File +# Begin Source File + +SOURCE=.\global\client.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\damage.h +# End Source File +# Begin Source File + +SOURCE=.\global\decals.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\defaultai.h +# End Source File +# Begin Source File + +SOURCE=.\global\defaults.h +# End Source File +# Begin Source File + +SOURCE=.\global\enginecallback.h +# End Source File +# Begin Source File + +SOURCE=.\global\extdll.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\flyingmonster.h +# End Source File +# Begin Source File + +SOURCE=.\game\game.h +# End Source File +# Begin Source File + +SOURCE=.\game\gamerules.h +# End Source File +# Begin Source File + +SOURCE=.\global\globals.h +# End Source File +# Begin Source File + +SOURCE=.\global\hierarchy.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\monsterevent.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\monsters.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\nodes.h +# End Source File +# Begin Source File + +SOURCE=.\global\plane.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\player.h +# End Source File +# Begin Source File + +SOURCE=.\global\saverestore.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\schedule.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\scripted.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\scriptevent.h +# End Source File +# Begin Source File + +SOURCE=.\global\sfx.h +# End Source File +# Begin Source File + +SOURCE=.\global\shake.h +# End Source File +# Begin Source File + +SOURCE=.\global\soundent.h +# End Source File +# Begin Source File + +SOURCE=.\game\spectator.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\squad.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\squadmonster.h +# End Source File +# Begin Source File + +SOURCE=.\monsters\talkmonster.h +# End Source File +# Begin Source File + +SOURCE=.\global\te_temp.h +# End Source File +# Begin Source File + +SOURCE=.\game\teamplay_gamerules.h +# End Source File +# Begin Source File + +SOURCE=.\global\utils.h +# End Source File +# Begin Source File + +SOURCE=.\global\vector.h +# End Source File +# End Group +# End Target +# End Project diff --git a/sv_dll/server.plg b/sv_dll/server.plg new file mode 100644 index 00000000..35b71426 --- /dev/null +++ b/sv_dll/server.plg @@ -0,0 +1,16 @@ + + +
+

Build Log

+

+--------------------Configuration: server - Win32 Debug-------------------- +

+

Command Lines

+ + + +

Results

+server.dll - 0 error(s), 0 warning(s) +
+ + diff --git a/sv_dll/weapon_generic.cpp b/sv_dll/weapon_generic.cpp new file mode 100644 index 00000000..cfaaf386 --- /dev/null +++ b/sv_dll/weapon_generic.cpp @@ -0,0 +1,68 @@ +//======================================================================= +// Copyright (C) Shambler Team 2006 +// weapons.cpp - player weapon baseclass +//======================================================================= + +#include "extdll.h" +#include "utils.h" +#include "cbase.h" +#include "baseweapon.h" + +LINK_ENTITY_TO_CLASS( weapon_m249, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_crossbow, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_crowbar, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_redeemer, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_eagle, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_glock, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_mp5, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_shotgun, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_m40a1, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_handgrenade, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_debug, CBasePlayerWeapon ); +LINK_ENTITY_TO_CLASS( weapon_rpg, CBasePlayerWeapon ); + +//*********************************************************** +// world_items +//*********************************************************** +class CWorldItem : public CBaseEntity +{ +public: + void KeyValue(KeyValueData *pkvd ); + void Spawn( void ); +}; + +LINK_ENTITY_TO_CLASS(world_items, CWorldItem); + +void CWorldItem::KeyValue(KeyValueData *pkvd) +{ + if (FStrEq(pkvd->szKeyName, "type")) + { + pev->impulse = atoi(pkvd->szValue); + pkvd->fHandled = TRUE; + } + else CBaseEntity::KeyValue( pkvd ); +} + +void CWorldItem::Spawn( void ) +{ + CBaseEntity *pEntity = NULL; + + switch (pev->impulse) + { + case 44: //ITEM_BATTERY: + pEntity = CBaseEntity::Create( "item_battery", pev->origin, pev->angles ); + break; + case 45: //ITEM_SUIT: + pEntity = CBaseEntity::Create( "item_suit", pev->origin, pev->angles ); + break; + } + + if (!pEntity) Msg( "unable to create world_item %d\n", pev->impulse ); + else + { + pEntity->pev->target = pev->target; + pEntity->pev->targetname = pev->targetname; + pEntity->pev->spawnflags = pev->spawnflags; + } + REMOVE_ENTITY(edict()); +} diff --git a/todo.log b/todo.log index 8cc73598..c1622b4a 100644 --- a/todo.log +++ b/todo.log @@ -18,7 +18,11 @@ fopen Beta 13.12.08 -0. имплементация server.dll, client.dll +0. подключить sv_dll к проекту + +entity_state_t невидима для пользователя + +edict_t - существует только на сервере diff --git a/vprogs/pr_edict.c b/vprogs/pr_edict.c index 5e1d7385..cd21c143 100644 --- a/vprogs/pr_edict.c +++ b/vprogs/pr_edict.c @@ -11,7 +11,7 @@ sizebuf_t vm_tempstringsbuf; int prvm_type_size[8] = {1, sizeof(string_t)/4,1,3,1,1, sizeof(func_t)/4, sizeof(void *)/4}; ddef_t *PRVM_ED_FieldAtOfs(int ofs); -bool PRVM_ED_ParseEpair(edict_t *ent, ddef_t *key, const char *s); +bool PRVM_ED_ParseEpair(pr_edict_t *ent, ddef_t *key, const char *s); //============================================================================ // mempool handling @@ -34,7 +34,7 @@ void PRVM_MEM_Alloc(void) vm.prog->edictprivate_size = max(vm.prog->edictprivate_size, (int)sizeof(vm_edict_t)); // alloc edicts - vm.prog->edicts = (edict_t *)Mem_Alloc(vm.prog->progs_mempool, vm.prog->limit_edicts * sizeof(edict_t)); + vm.prog->edicts = (pr_edict_t *)Mem_Alloc(vm.prog->progs_mempool, vm.prog->limit_edicts * sizeof(pr_edict_t)); // alloc edict private space vm.prog->edictprivate = Mem_Alloc(vm.prog->progs_mempool, vm.prog->max_edicts * vm.prog->edictprivate_size); @@ -177,7 +177,7 @@ PRVM_ED_ClearEdict Sets everything to NULL ================= */ -void PRVM_ED_ClearEdict (edict_t *e) +void PRVM_ED_ClearEdict (pr_edict_t *e) { Mem_Set (e->progs.vp, 0, vm.prog->progs->entityfields * 4); e->priv.ed->free = false; @@ -197,10 +197,10 @@ instead of being removed and recreated, which can cause interpolated angles and bad trails. ================= */ -edict_t *PRVM_ED_Alloc (void) +pr_edict_t *PRVM_ED_Alloc (void) { int i; - edict_t *e; + pr_edict_t *e; // the client qc dont need maxclients // thus it doesnt need to use svs.maxclients @@ -240,7 +240,7 @@ Marks the edict as free FIXME: walk all entities and NULL out references to this entity ================= */ -void PRVM_ED_Free (edict_t *ed) +void PRVM_ED_Free (pr_edict_t *ed) { // dont delete the null entity (world) or reserved edicts if(PRVM_NUM_FOR_EDICT(ed) <= vm.prog->reserved_edicts ) @@ -546,7 +546,7 @@ For debugging */ // LordHavoc: optimized this to print out much more quickly (tempstring) // LordHavoc: changed to print out every 4096 characters (incase there are a lot of fields to print) -void PRVM_ED_Print(edict_t *ed) +void PRVM_ED_Print(pr_edict_t *ed) { size_t l; ddef_t *d; @@ -620,7 +620,7 @@ PRVM_ED_Write For savegames ============= */ -void PRVM_ED_Write( edict_t *ed, void *buffer, void *numpairs, setpair_t callback ) +void PRVM_ED_Write( pr_edict_t *ed, void *buffer, void *numpairs, setpair_t callback ) { ddef_t *d; int *v; @@ -666,7 +666,7 @@ void PRVM_ED_Read( int s_table, int entnum, dkeyvalue_t *fields, int numpairs ) { const char *keyname, *value; ddef_t *key; - edict_t *ent; + pr_edict_t *ent; int i; if( entnum >= vm.prog->limit_edicts ) Host_Error( "PRVM_ED_Read: too many edicts in save file\n" ); @@ -777,7 +777,7 @@ For debugging void PRVM_ED_Count_f( void ) { int i; - edict_t *ent; + pr_edict_t *ent; int active; if(Cmd_Argc() != 2) @@ -883,7 +883,7 @@ Can parse either fields or globals returns false if error ============= */ -bool PRVM_ED_ParseEpair( edict_t *ent, ddef_t *key, const char *s ) +bool PRVM_ED_ParseEpair( pr_edict_t *ent, ddef_t *key, const char *s ) { int i, l; char *new_p; @@ -976,7 +976,7 @@ Console command to set a field of a specified edict */ void PRVM_ED_EdictSet_f(void) { - edict_t *ed; + pr_edict_t *ed; ddef_t *key; if(Cmd_Argc() != 5) @@ -1010,7 +1010,7 @@ ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ -const char *PRVM_ED_ParseEdict( const char *data, edict_t *ent ) +const char *PRVM_ED_ParseEdict( const char *data, pr_edict_t *ent ) { ddef_t *key; bool init, newline, anglehack; @@ -1113,7 +1113,7 @@ to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves. */ void PRVM_ED_LoadFromFile( const char *data ) { - edict_t *ent; + pr_edict_t *ent; int parsed, inhibited, spawned, died; mfunction_t *func; @@ -1421,7 +1421,7 @@ void PRVM_LoadProgs( const char *filename ) ((int *)vm.prog->globals.gp)[i] = LittleLong (((int *)vm.prog->globals.gp)[i]); // moved edict_size calculation down here, below field adding code - // LordHavoc: this no longer includes the edict_t header + // LordHavoc: this no longer includes the pr_edict_t header vm.prog->edict_size = vm.prog->progs->entityfields * 4; vm.prog->edictareasize = vm.prog->edict_size * vm.prog->limit_edicts; @@ -1602,7 +1602,7 @@ void PRVM_Fields_f (void) int *counts; char tempstring[MAX_MSGLEN], tempstring2[260]; const char *name; - edict_t *ed; + pr_edict_t *ed; ddef_t *d; int *v; @@ -1876,7 +1876,7 @@ void _PRVM_FreeAll(const char *filename, int fileline) } // LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons -edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline) +pr_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline) { PRVM_ERROR ("PRVM_EDICT_NUM: %s: bad number %i (called at %s:%i)", PRVM_NAME, n, filename, fileline); return NULL; diff --git a/vprogs/pr_exec.c b/vprogs/pr_exec.c index 46093f05..0ed00385 100644 --- a/vprogs/pr_exec.c +++ b/vprogs/pr_exec.c @@ -539,7 +539,7 @@ void PRVM_ExecuteProgram( func_t fnum, const char *name, const char *file, const { dstatement_t *st, *startst; mfunction_t *f, *newf; - edict_t *ed; + pr_edict_t *ed; prvm_eval_t *ptr, *_switch; int switchtype, exitdepth; int i, jumpcount, cachedpr_trace; diff --git a/vprogs/vprogs.dsp b/vprogs/vprogs.dsp index 843f117c..58c60f90 100644 --- a/vprogs/vprogs.dsp +++ b/vprogs/vprogs.dsp @@ -54,7 +54,8 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 -# ADD LINK32 msvcrt.lib /nologo /dll /profile /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# SUBTRACT LINK32 /profile # Begin Custom Build TargetDir=\Xash3D\src_main\temp\vprogs\!release InputPath=\Xash3D\src_main\temp\vprogs\!release\vprogs.dll @@ -79,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 diff --git a/vprogs/vprogs.h b/vprogs/vprogs.h index 89e0aa4b..ba762ac8 100644 --- a/vprogs/vprogs.h +++ b/vprogs/vprogs.h @@ -359,25 +359,25 @@ func_t PRVM_ED_FindFunctionOffset(const char *function); void PRVM_MEM_IncreaseEdicts(void); -edict_t *PRVM_ED_Alloc (void); -void PRVM_ED_Free (edict_t *ed); -void PRVM_ED_ClearEdict (edict_t *e); +pr_edict_t *PRVM_ED_Alloc (void); +void PRVM_ED_Free (pr_edict_t *ed); +void PRVM_ED_ClearEdict (pr_edict_t *e); ddef_t *PRVM_ED_GlobalAtOfs( int ofs ); void PRVM_PrintFunctionStatements (const char *name); -void PRVM_ED_Print(edict_t *ed); -void PRVM_ED_Write( edict_t *ed, void *buffer, void *ptr, setpair_t callback ); +void PRVM_ED_Print(pr_edict_t *ed); +void PRVM_ED_Write( pr_edict_t *ed, void *buffer, void *ptr, setpair_t callback ); void PRVM_ED_Read( int s_table, int ednum, dkeyvalue_t *fields, int numpairs ); -const char *PRVM_ED_ParseEdict (const char *data, edict_t *ent); +const char *PRVM_ED_ParseEdict (const char *data, pr_edict_t *ent); char *PRVM_ValueString( etype_t type, prvm_eval_t *val ); void PRVM_ED_WriteGlobals( void *buffer, void *ptr, setpair_t callback ); void PRVM_ED_ReadGlobals( int s_table, dkeyvalue_t *globals, int numpairs ); void PRVM_ED_LoadFromFile( const char *data ); -edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline); +pr_edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline); #define PRVM_EDICT_NUM(n) (((n) >= 0 && (n) < vm.prog->max_edicts) ? vm.prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) #define PRVM_EDICT_NUM_UNSIGNED(n) (((n) < vm.prog->max_edicts) ? vm.prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) -#define PRVM_NUM_FOR_EDICT(e) ((int)((edict_t *)(e) - vm.prog->edicts)) +#define PRVM_NUM_FOR_EDICT(e) ((int)((pr_edict_t *)(e) - vm.prog->edicts)) #define PRVM_NEXT_EDICT(e) ((e) + 1) #define PRVM_EDICT_TO_PROG(e) (PRVM_NUM_FOR_EDICT(e)) #define PRVM_PROG_TO_EDICT(n) (PRVM_EDICT_NUM(n)) diff --git a/vsound/vsound.dsp b/vsound/vsound.dsp index 4f6bb10c..e0568def 100644 --- a/vsound/vsound.dsp +++ b/vsound/vsound.dsp @@ -54,7 +54,8 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 -# ADD LINK32 libogg.lib vorbis.lib /nologo /dll /profile /machine:I386 /nodefaultlib:"libcmt.lib" /opt:nowin98 +# ADD LINK32 libogg.lib vorbis.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libcmt.lib" /opt:nowin98 +# SUBTRACT LINK32 /profile # Begin Custom Build TargetDir=\Xash3D\src_main\temp\vsound\!release InputPath=\Xash3D\src_main\temp\vsound\!release\vsound.dll @@ -79,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -113,6 +114,10 @@ SOURCE="$(InputPath)" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File +SOURCE=.\s_export.c +# End Source File +# Begin Source File + SOURCE=.\s_load.c # End Source File # Begin Source File @@ -127,10 +132,6 @@ SOURCE=.\s_openal.c SOURCE=.\s_stream.c # End Source File -# Begin Source File - -SOURCE=.\s_export.c -# End Source File # End Group # Begin Group "Header Files" diff --git a/xash.dsw b/xash.dsw index 71c10fd6..4a00813c 100644 --- a/xash.dsw +++ b/xash.dsw @@ -63,6 +63,18 @@ Package=<4> ############################################################################### +Project: "server"=".\sv_dll\server.dsp" - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + Project: "render"=".\render\render.dsp" - Package Owner=<4> Package=<5>