From 704e653af67b5e78aab70f9639301130dbcfd57c Mon Sep 17 00:00:00 2001 From: g-cont Date: Mon, 17 Sep 2007 00:00:00 +0400 Subject: [PATCH] 17 Sep 2007 --- changelog.log | 14 +- common/bsplib/map.c | 1 - common/bsplib/qbsp3.c | 2 +- common/bsplib/textures.c | 30 +- common/common.dsp | 36 +- common/common/utils.c | 29 +- engine/client/cl_parse.c | 4 +- engine/client/cl_pred.c | 9 +- engine/common.h | 8 +- engine/common/cmd.c | 10 +- engine/common/common.c | 2 +- engine/common/cvar.c | 63 +- engine/common/cvar.h | 12 +- engine/common/keys.h | 2 + engine/common/menu.c | 2 +- engine/common/progsvm.h | 387 +++ engine/common/vm_cmds.c | 3150 +++++++++++++++++++ engine/common/vm_cmds.h | 343 ++ engine/common/vm_edict.c | 1944 ++++++++++++ engine/common/vm_exec.c | 1121 +++++++ engine/engine.dsp | 24 + engine/engine.h | 11 +- engine/host.c | 1 + engine/progdefs.h | 183 ++ engine/server/ref_server.h | 191 -- engine/server/server.h | 190 +- engine/server/sv_ccmds.c | 24 +- engine/server/sv_edict.h | 77 + engine/server/sv_ents.c | 68 +- engine/server/sv_game.c | 1616 +++++++++- engine/server/sv_init.c | 325 +- engine/server/sv_main.c | 19 +- engine/server/sv_phys.c | 1197 ++++--- engine/server/sv_send.c | 14 +- engine/server/sv_spawn.c | 792 ++--- engine/server/sv_user.c | 4 +- engine/server/sv_world.c | 174 +- engine/server/tstent.c | 55 + engine/snd_dma.c | 6 +- engine/sound.h | 6 +- launch/console.c | 16 +- launch/utils.c | 12 + public/basetypes.h | 4 +- public/const.h | 26 +- release.bat | 3 +- render/gl_model.c | 5 +- render/gl_rsurf.c | 82 +- vprogs/client.c | 48 +- vprogs/compile.log | 75 + vprogs/damage.c | 58 +- vprogs/defs.c | 313 +- vprogs/dummys.c | 168 +- vprogs/ents/ambient.c | 2 +- vprogs/ents/ccam.c | 46 +- vprogs/ents/funcs/func_button.c | 2 +- vprogs/ents/funcs/func_door.c | 2 +- vprogs/ents/funcs/func_mover.c | 126 +- vprogs/ents/funcs/func_path_corner.c | 6 +- vprogs/ents/funcs/func_train.c | 62 +- vprogs/ents/funcs/funcs.c | 18 +- vprogs/ents/internal.c | 40 +- vprogs/ents/items/items.c | 33 +- vprogs/ents/lights.c | 20 +- vprogs/ents/triggers/trigger_changelevel.c | 6 +- vprogs/ents/triggers/trigger_counter.c | 52 +- vprogs/ents/triggers/trigger_generic.c | 44 +- vprogs/ents/triggers/trigger_hurt.c | 26 +- vprogs/ents/triggers/trigger_message.c | 64 +- vprogs/ents/triggers/trigger_once.c | 40 +- vprogs/ents/triggers/trigger_push.c | 30 +- vprogs/ents/triggers/trigger_secret.c | 24 +- vprogs/ents/triggers/trigger_sequence.c | 162 +- vprogs/ents/triggers/trigger_setskill.c | 10 +- vprogs/ents/triggers/trigger_setviewpoint.c | 88 +- vprogs/ents/triggers/trigger_teleport.c | 74 +- vprogs/ents/triggers/triggers.c | 16 +- vprogs/impulses.c | 22 +- vprogs/main.c | 12 +- vprogs/player.c | 134 +- vprogs/progdefs.h | 390 +-- vprogs/run.bat | 1 + 81 files changed, 11435 insertions(+), 3073 deletions(-) create mode 100644 engine/common/progsvm.h create mode 100644 engine/common/vm_cmds.c create mode 100644 engine/common/vm_cmds.h create mode 100644 engine/common/vm_edict.c create mode 100644 engine/common/vm_exec.c create mode 100644 engine/progdefs.h delete mode 100644 engine/server/ref_server.h create mode 100644 engine/server/sv_edict.h create mode 100644 engine/server/tstent.c create mode 100644 vprogs/compile.log create mode 100644 vprogs/run.bat diff --git a/changelog.log b/changelog.log index dc11685a..d5a68dcc 100644 --- a/changelog.log +++ b/changelog.log @@ -1,5 +1,5 @@ Разработать концепцию языка VirtualC\VirtualC++ (базируется на QuakeC) -Придумать новые имена (6 символов) для launcher.dll +представить func_t как структуру(возвращаемые значения и аргументы) Quake1 Quake2 SV_MoveBounds SV_TraceBounds @@ -21,14 +21,22 @@ SV_ClipToLinks SV_ClipMoveToEntities 12. Подключить advapi динамически OK 13. Переименовать platform.dll в common.dll OK 14. Переименовать renderer.dll в render.dll OK -15. Упорядочить файлы и код в common.dll Ok +15. Упорядочить файлы и код в common.dll OK 16. Пофиксить вылет при загрузке модели игрока в меню - +17. Переписать bsplib для работы в цикле +18. Полная имплементация PRVM +{ + перенести параметры из sv_edict_t в sv_fields_t + упорядочить FL_ флаги OK + упорядочить entvars_t +} //================================================== // то, что уже готово //================================================== ++исправлен баг с загрузкой анимированных текстур +-удален формат моделей md2 +исправлен баг с флагом RF_FULLBRIGHT для studio models в режиме RDF_NOWORLDMODEL +существенно уменьшен размер всех лаунчеров +новая система загрузки дллок (поддержка нативных библиотек) diff --git a/common/bsplib/map.c b/common/bsplib/map.c index 1376f520..f12bc3bc 100644 --- a/common/bsplib/map.c +++ b/common/bsplib/map.c @@ -740,7 +740,6 @@ void ParseBrush (bsp_entity_t *mapent) side = b->original_sides + b->numsides; side->planenum = planenum; side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], &td, vec3_origin); - // save the td off in case there is an origin brush and we // have to recalculate the texinfo side_brushtextures[nummapbrushsides] = td; diff --git a/common/bsplib/qbsp3.c b/common/bsplib/qbsp3.c index 94146b7c..06e3aad4 100644 --- a/common/bsplib/qbsp3.c +++ b/common/bsplib/qbsp3.c @@ -323,7 +323,7 @@ bool PrepareBSPModel ( const char *dir, const char *name, byte params ) bool CompileBSPModel ( void ) { - //must be first! + // must be first! if( onlyents ) WbspMain( true ); else if( onlyvis && !onlyrad ) WvisMain ( full_compile ); else if( onlyrad && !onlyvis ) WradMain( full_compile ); diff --git a/common/bsplib/textures.c b/common/bsplib/textures.c index 99083f07..1c79f850 100644 --- a/common/bsplib/textures.c +++ b/common/bsplib/textures.c @@ -15,7 +15,7 @@ int FindMiptex (char *name) for (i = 0; i < nummiptex; i++ ) { - if (!strcmp (name, textureref[i].name)) + if (!stricmp(name, textureref[i].name)) return i; } if (nummiptex == MAX_MAP_TEXTURES) Sys_Error ("MAX_MAP_TEXTURES"); @@ -33,11 +33,11 @@ int FindMiptex (char *name) } nummiptex++; - if (textureref[i].animname[0]) + if (textureref[i].animname[0]) { - Msg("animname %s\n", textureref[i].animname ); - FindMiptex(textureref[i].animname); - } + MsgDev(D_INFO, "FindMiptex: animation chain \"%s->%s\"\n", textureref[i].name, textureref[i].animname ); + FindMiptex(textureref[i].name); + } return i; } @@ -189,17 +189,15 @@ int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin) // find the texinfo tc = texinfo; - for (i=0 ; iflags != tx.flags) - continue; - if (tc->value != tx.value) - continue; - for (j=0 ; j<2 ; j++) + if (tc->flags != tx.flags) continue; + if (tc->value != tx.value) continue; + for (j = 0; j < 2; j++) { - if (strcmp (tc->texture, tx.texture)) + if (stricmp (tc->texture, tx.texture)) goto skip; - for (k=0 ; k<4 ; k++) + for (k = 0; k < 4; k++) { if (tc->vecs[j][k] != tx.vecs[j][k]) goto skip; @@ -214,15 +212,13 @@ skip:; // load the next animation mt = FindMiptex (bt->name); - if (textureref[mt].animname) + if (textureref[mt].animname[0]) { anim = *bt; strcpy (anim.name, textureref[mt].animname); tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); } - else - tc->nexttexinfo = -1; - + else tc->nexttexinfo = -1; return i; } diff --git a/common/common.dsp b/common/common.dsp index 070081e1..87f90e17 100644 --- a/common/common.dsp +++ b/common/common.dsp @@ -54,7 +54,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 /machine:I386 /opt:nowin98 -# ADD LINK32 msvcrt.lib winmm.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 +# ADD LINK32 msvcrt.lib winmm.lib user32.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 # Begin Custom Build TargetDir=\XASH3D\src_main\!source\temp\common\!release InputPath=\XASH3D\src_main\!source\temp\common\!release\common.dll @@ -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 msvcrt.lib winmm.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrtd.lib" /pdbtype:sept +# ADD LINK32 msvcrt.lib winmm.lib user32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrtd.lib" /pdbtype:sept # SUBTRACT LINK32 /incremental:no /nodefaultlib # Begin Custom Build TargetDir=\XASH3D\src_main\!source\temp\common\!debug @@ -113,14 +113,6 @@ SOURCE="$(InputPath)" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File -SOURCE=.\common\memory.c -# End Source File -# Begin Source File - -SOURCE=.\common\utils.c -# End Source File -# Begin Source File - SOURCE=.\bsplib\brushbsp.c # End Source File # Begin Source File @@ -161,6 +153,10 @@ SOURCE=.\bsplib\map.c # End Source File # Begin Source File +SOURCE=.\common\memory.c +# End Source File +# Begin Source File + SOURCE=.\bsplib\patches.c # End Source File # Begin Source File @@ -233,6 +229,10 @@ SOURCE=.\bsplib\tree.c # End Source File # Begin Source File +SOURCE=.\common\utils.c +# End Source File +# Begin Source File + SOURCE=.\bsplib\winding.c # End Source File # Begin Source File @@ -249,14 +249,6 @@ SOURCE=.\common\ziplib.c # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File -SOURCE=.\common\memory.h -# End Source File -# Begin Source File - -SOURCE=.\common\utils.h -# End Source File -# Begin Source File - SOURCE=.\common\blankframe.h # End Source File # Begin Source File @@ -273,6 +265,10 @@ SOURCE=.\common\mdllib.h # End Source File # Begin Source File +SOURCE=.\common\memory.h +# End Source File +# Begin Source File + SOURCE=.\platform.h # End Source File # Begin Source File @@ -285,6 +281,10 @@ SOURCE=..\public\ref_system.h # End Source File # Begin Source File +SOURCE=.\common\utils.h +# End Source File +# Begin Source File + SOURCE=.\common\zip32.h # End Source File # End Group diff --git a/common/common/utils.c b/common/common/utils.c index 7a251221..9300a4ce 100644 --- a/common/common/utils.c +++ b/common/common/utils.c @@ -1333,31 +1333,22 @@ static int enter; void ThreadLock (void) { if (!threaded) return; - if (enter) - { - MsgWarn("ThreadLock: recursive call\n"); - return; - } EnterCriticalSection (&crit); + if (enter) Sys_Error ("Recursive ThreadLock\n"); enter = 1; } void ThreadUnlock (void) { if (!threaded) return; - if (!enter) - { - MsgWarn("ThreadUnlock: must call ThreadLock first\n"); - return; - } + if (!enter) Sys_Error ("ThreadUnlock without lock\n"); enter = 0; LeaveCriticalSection (&crit); } int GetThreadWork (void) { - int r; - int f; + int r, f; ThreadLock (); @@ -1367,7 +1358,7 @@ int GetThreadWork (void) return -1; } - f = 10*dispatch / workcount; + f = 10 * dispatch / workcount; if (f != oldf) { oldf = f; @@ -1397,7 +1388,7 @@ void ThreadSetDefault (void) { if (numthreads == -1) // not set manually { - //NOTE: we must init Plat_InitCPU() first + // NOTE: we must init Plat_InitCPU() first numthreads = GI.cpunum; if (numthreads < 1 || numthreads > MAX_THREADS) numthreads = 1; @@ -1418,9 +1409,8 @@ RunThreadsOn */ void RunThreadsOn (int workcnt, bool showpacifier, void(*func)(int)) { - int threadid[MAX_THREADS]; + int i, threadid[MAX_THREADS]; HANDLE threadhandle[MAX_THREADS]; - int i; double start, end; start = Plat_DoubleTime(); @@ -1433,16 +1423,17 @@ void RunThreadsOn (int workcnt, bool showpacifier, void(*func)(int)) // run threads in parallel InitializeCriticalSection (&crit); - if (numthreads == 1) func (0); // use same thread + if (numthreads == 1) func(0); // use same thread else { - for (i = 0;i < numthreads; i++) + for (i = 0; i < numthreads; i++) { threadhandle[i] = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)func, (LPVOID)i, 0, &threadid[i]); } - for (i = 0; i < numthreads; i++) + { WaitForSingleObject (threadhandle[i], INFINITE); + } } DeleteCriticalSection (&crit); diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index 389fecb6..d610699d 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -389,7 +389,7 @@ void CL_LoadClientinfo (clientinfo_t *ci, char *s) { sprintf (model_filename, "models/players/gordon/player.mdl"); sprintf (weapon_filename, "models/weapons/w_glock.mdl"); - strcpy (ci->iconname, "textures/base_menu/i_fixme.pcx"); + strcpy (ci->iconname, "i_fixme.pcx"); ci->model = re->RegisterModel (model_filename); memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel)); ci->weaponmodel[0] = re->RegisterModel (weapon_filename); @@ -436,7 +436,7 @@ void CL_LoadClientinfo (clientinfo_t *ci, char *s) } // icon file - strcpy (ci->iconname, "textures/base_menu/i_fixme.pcx"); + strcpy (ci->iconname, "i_fixme.pcx"); ci->icon = re->RegisterPic (ci->iconname); } diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index 777361e8..3955854b 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -125,7 +125,7 @@ void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, if (trace.allsolid || trace.startsolid || trace.fraction < tr->fraction) { - trace.ent = (struct edict_s *)ent; + trace.ent = (edict_t *)ent; if (tr->startsolid) { *tr = trace; @@ -145,14 +145,13 @@ void CL_ClipMoveToEntities ( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, CL_PMTrace ================ */ -trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) +trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) { trace_t t; // check against world t = CM_BoxTrace (start, end, mins, maxs, 0, MASK_PLAYERSOLID); - if (t.fraction < 1.0) - t.ent = (struct edict_s *)1; + if (t.fraction < 1.0) t.ent = (edict_t *)1; // check all other solid models CL_ClipMoveToEntities (start, mins, maxs, end, &t); @@ -160,7 +159,7 @@ trace_t CL_PMTrace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) return t; } -int CL_PMpointcontents (vec3_t point) +int CL_PMpointcontents (vec3_t point) { int i; entity_state_t *ent; diff --git a/engine/common.h b/engine/common.h index 660efb00..875f8815 100644 --- a/engine/common.h +++ b/engine/common.h @@ -131,7 +131,7 @@ int COM_CheckParm (char *parm); void COM_Init (void); void COM_InitArgv (int argc, char **argv); -char *CopyString (char *in); +char *CopyString (const char *in); //============================================================================ @@ -406,7 +406,7 @@ void Cmd_AddCommand (char *cmd_name, xcommand_t function); // as a clc_stringcmd instead of executed locally void Cmd_RemoveCommand (char *cmd_name); -bool Cmd_Exists (char *cmd_name); +bool Cmd_Exists (const char *cmd_name); // used by the cvar code to check for cvar / command name overlap char *Cmd_CompleteCommand (char *partial); @@ -420,11 +420,11 @@ char *Cmd_Args (void); // functions. Cmd_Argv () will return an empty string, not a NULL // if arg > argc, so string operations are always safe. -void Cmd_TokenizeString (char *text, bool macroExpand); +void Cmd_TokenizeString (const char *text, bool macroExpand); // Takes a null terminated string. Does not need to be /n terminated. // breaks the string up into arg tokens. -void Cmd_ExecuteString (char *text); +void Cmd_ExecuteString (const char *text); // Parses a single line of text into arguments and tries to execute it // as if it was typed at the console diff --git a/engine/common/cmd.c b/engine/common/cmd.c index 41191e78..bf0ebdca 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -538,7 +538,7 @@ char *Cmd_Args (void) Cmd_MacroExpandString ====================== */ -char *Cmd_MacroExpandString (char *text) +char *Cmd_MacroExpandString (const char *text) { int i, j, count, len; bool inquote; @@ -548,7 +548,7 @@ char *Cmd_MacroExpandString (char *text) char *token, *start; inquote = false; - scan = text; + scan = (char *)text; len = strlen (scan); if (len >= MAX_STRING_CHARS) @@ -613,7 +613,7 @@ Parses the given string into command line tokens. $Cvars will be expanded unless they are in a quoted token ============ */ -void Cmd_TokenizeString (char *text, bool macroExpand) +void Cmd_TokenizeString (const char *text, bool macroExpand) { int i; char *token; @@ -741,7 +741,7 @@ void Cmd_RemoveCommand (char *cmd_name) Cmd_Exists ============ */ -bool Cmd_Exists (char *cmd_name) +bool Cmd_Exists (const char *cmd_name) { cmd_function_t *cmd; @@ -800,7 +800,7 @@ A complete command line has been parsed, so try to execute it FIXME: lookupnoadd the token to speed search? ============ */ -void Cmd_ExecuteString (char *text) +void Cmd_ExecuteString (const char *text) { cmd_function_t *cmd; cmdalias_t *a; diff --git a/engine/common/common.c b/engine/common/common.c index 66eef918..43ef05e1 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -148,7 +148,7 @@ void COM_InitArgv (int argc, char **argv) srand(time(NULL)); // init random generator } -char *CopyString (char *in) +char *CopyString (const char *in) { char *out; diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 3c439cee..03872344 100644 --- a/engine/common/cvar.c +++ b/engine/common/cvar.c @@ -28,7 +28,7 @@ cvar_t *cvar_vars; Cvar_InfoValidate ============ */ -static bool Cvar_InfoValidate (char *s) +static bool Cvar_InfoValidate (const char *s) { if (strstr (s, "\\")) return false; @@ -44,11 +44,11 @@ static bool Cvar_InfoValidate (char *s) Cvar_FindVar ============ */ -cvar_t *Cvar_FindVar (char *var_name) +cvar_t *Cvar_FindVar (const char *var_name) { cvar_t *var; - for (var=cvar_vars ; var ; var=var->next) + for (var = cvar_vars; var; var = var->next) if (!strcmp (var_name, var->name)) return var; @@ -60,13 +60,12 @@ cvar_t *Cvar_FindVar (char *var_name) Cvar_VariableValue ============ */ -float Cvar_VariableValue (char *var_name) +float Cvar_VariableValue (const char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); - if (!var) - return 0; + if (!var) return 0; return atof (var->string); } @@ -76,13 +75,12 @@ float Cvar_VariableValue (char *var_name) Cvar_VariableString ============ */ -char *Cvar_VariableString (char *var_name) +char *Cvar_VariableString (const char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); - if (!var) - return ""; + if (!var) return ""; return var->string; } @@ -95,7 +93,7 @@ Cvar_CompleteVariable char *Cvar_CompleteVariable (char *partial) { cvar_t *cvar; - int len; + int len; len = strlen(partial); @@ -124,7 +122,7 @@ If the variable already exists, the value will not be set The flags will be or'ed in if the variable exists. ============ */ -cvar_t *Cvar_Get (char *var_name, char *var_value, int flags) +cvar_t *Cvar_Get (const char *var_name, const char *var_value, int flags) { cvar_t *var; @@ -176,15 +174,12 @@ cvar_t *Cvar_Get (char *var_name, char *var_value, int flags) Cvar_Set2 ============ */ -cvar_t *Cvar_Set2 (char *var_name, char *value, bool force) +cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) { cvar_t *var; var = Cvar_FindVar (var_name); - if (!var) - { // create it - return Cvar_Get (var_name, value, 0); - } + if (!var) return Cvar_Get (var_name, value, 0); // create it if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO)) { @@ -244,13 +239,13 @@ cvar_t *Cvar_Set2 (char *var_name, char *value, bool force) var->modified = true; - if (var->flags & CVAR_USERINFO) - userinfo_modified = true; // transmit at next oportunity + // transmit at next oportunity + if (var->flags & CVAR_USERINFO) userinfo_modified = true; - Z_Free (var->string); // free the old value string + Z_Free (var->string); // free the old value string var->string = CopyString(value); - var->value = atof (var->string); + var->value = atof(var->string); return var; } @@ -260,7 +255,7 @@ cvar_t *Cvar_Set2 (char *var_name, char *value, bool force) Cvar_ForceSet ============ */ -cvar_t *Cvar_ForceSet (char *var_name, char *value) +cvar_t *Cvar_ForceSet (const char *var_name, const char *value) { return Cvar_Set2 (var_name, value, true); } @@ -270,7 +265,7 @@ cvar_t *Cvar_ForceSet (char *var_name, char *value) Cvar_Set ============ */ -cvar_t *Cvar_Set (char *var_name, char *value) +cvar_t *Cvar_Set (const char *var_name, const char *value) { return Cvar_Set2 (var_name, value, false); } @@ -352,14 +347,13 @@ Handles variable inspection and changing from the console */ bool Cvar_Command (void) { - cvar_t *v; + cvar_t *v; -// check variables + // check variables v = Cvar_FindVar (Cmd_Argv(0)); - if (!v) - return false; + if (!v) return false; -// perform a variable print or set + // perform a variable print or set if (Cmd_Argc() == 1) { Msg ("\"%s\" is \"%s\"\n", v->name, v->string); @@ -392,10 +386,8 @@ void Cvar_Set_f (void) if (c == 4) { - if (!strcmp(Cmd_Argv(3), "u")) - flags = CVAR_USERINFO; - else if (!strcmp(Cmd_Argv(3), "s")) - flags = CVAR_SERVERINFO; + if (!strcmp(Cmd_Argv(3), "u")) flags = CVAR_USERINFO; + else if (!strcmp(Cmd_Argv(3), "s")) flags = CVAR_SERVERINFO; else { Msg ("flags can only be 'u' or 's'\n"); @@ -403,8 +395,7 @@ void Cvar_Set_f (void) } Cvar_FullSet (Cmd_Argv(1), Cmd_Argv(2), flags); } - else - Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); + else Cvar_Set (Cmd_Argv(1), Cmd_Argv(2)); } @@ -475,7 +466,7 @@ void Cvar_List_f (void) bool userinfo_modified; -char *Cvar_BitInfo (int bit) +char *Cvar_BitInfo (int bit) { static char info[MAX_INFO_STRING]; cvar_t *var; @@ -491,13 +482,13 @@ char *Cvar_BitInfo (int bit) } // returns an info string containing all the CVAR_USERINFO cvars -char *Cvar_Userinfo (void) +char *Cvar_Userinfo (void) { return Cvar_BitInfo (CVAR_USERINFO); } // returns an info string containing all the CVAR_SERVERINFO cvars -char *Cvar_Serverinfo (void) +char *Cvar_Serverinfo (void) { return Cvar_BitInfo (CVAR_SERVERINFO); } diff --git a/engine/common/cvar.h b/engine/common/cvar.h index 1e4423a4..53255327 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -6,17 +6,17 @@ #define CVAR_H extern cvar_t *cvar_vars; -cvar_t *Cvar_FindVar (char *var_name); +cvar_t *Cvar_FindVar (const char *var_name); -cvar_t *Cvar_Get (char *var_name, char *value, int flags); +cvar_t *Cvar_Get (const char *var_name, const char *value, int flags); // creates the variable if it doesn't exist, or returns the existing one // if it exists, the value will not be changed, but flags will be ORed in // that allows variables to be unarchived without needing bitflags -cvar_t *Cvar_Set (char *var_name, char *value); +cvar_t *Cvar_Set (const char *var_name, const char *value); // will create the variable if it doesn't exist -cvar_t *Cvar_ForceSet (char *var_name, char *value); +cvar_t *Cvar_ForceSet (const char *var_name, const char *value); // will set the variable even if NOSET or LATCH cvar_t *Cvar_FullSet (char *var_name, char *value, int flags); @@ -24,10 +24,10 @@ cvar_t *Cvar_FullSet (char *var_name, char *value, int flags); void Cvar_SetValue (char *var_name, float value); // expands value to a string and calls Cvar_Set -float Cvar_VariableValue (char *var_name); +float Cvar_VariableValue (const char *var_name); // returns 0 if not defined or non numeric -char *Cvar_VariableString (char *var_name); +char *Cvar_VariableString (const char *var_name); // returns an empty string if not defined char *Cvar_CompleteVariable (char *partial); diff --git a/engine/common/keys.h b/engine/common/keys.h index f81b22e3..1a048d25 100644 --- a/engine/common/keys.h +++ b/engine/common/keys.h @@ -142,5 +142,7 @@ void Key_Init (void); void Key_WriteBindings (file_t *f); void Key_SetBinding (int keynum, char *binding); void Key_ClearStates (void); +char *Key_KeynumToString (int keynum); +int Key_StringToKeynum (char *str); int Key_GetKey (void); diff --git a/engine/common/menu.c b/engine/common/menu.c index 96faa28f..d154708f 100644 --- a/engine/common/menu.c +++ b/engine/common/menu.c @@ -3275,7 +3275,7 @@ void PlayerConfig_MenuDraw( void ) re->RenderFrame( &refdef ); - strcpy( scratch, "textures/base_menu/i_fixme.pcx" ); + strcpy( scratch, "i_fixme.pcx" ); re->DrawPic( s_player_config_menu.x - 40, refdef.y, scratch ); } } diff --git a/engine/common/progsvm.h b/engine/common/progsvm.h new file mode 100644 index 00000000..ce2e37b9 --- /dev/null +++ b/engine/common/progsvm.h @@ -0,0 +1,387 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +/* +This is a try to make the vm more generic, it is mainly based on the progs.h file. +For the license refer to progs.h. + +Generic means, less as possible hard-coded links with the other parts of the engine. +This means no edict_engineprivate struct usage, etc. +The code uses void pointers instead. +*/ + +#ifndef PROGSVM_H +#define PROGSVM_H + +#include "vprogs.h" // defs shared with qcc +#include "progdefs.h" // generated by program cdefs +#include "sv_edict.h" + +typedef struct prvm_stack_s +{ + int s; + mfunction_t *f; + +} prvm_stack_t; + +// virtual typedef +typedef union prvm_eval_s +{ + int edict; + int _int; + float _float; + float vector[3]; + int ivector[3]; + func_t function; + string_t string; +} prvm_eval_t; + +//with this the crc isn't needed for fields. +typedef struct prvm_fieldvars_s +{ + int ofs; + int type; + const char *name; +} prvm_fieldvars_t; + +typedef struct edict_state_s +{ + bool free; + float freetime; + +} vm_edict_t; + +struct edict_s +{ + // engine-private fields (stored in dynamically resized array) + union + { + vm_edict_t *ed; // vm edict state + void *vp; // generic edict + sv_edict_t *sv; // sv edict state + } priv; + + // QuakeC prog fields (stored in dynamically resized array) + union + { + void *vp; // generic entvars + entvars_t *sv; // server entvars + } progs; + +}; + +#define PRVM_GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)ed->progs.vp + fieldoffset) : NULL) +#define PRVM_GETGLOBALFIELDVALUE(fieldoffset) (fieldoffset ? (prvm_eval_t *)((unsigned char *)prog->globals.generic + fieldoffset) : NULL) + +#define PRVM_FE_CLASSNAME 8 +#define PRVM_FE_CHAIN 4 +#define PRVM_OP_STATE 1 + +#define PRVM_MAX_STACK_DEPTH 1024 +#define PRVM_LOCALSTACK_SIZE 16384 + +#define PRVM_MAX_OPENFILES 256 +#define PRVM_MAX_OPENSEARCHES 128 + +typedef void (*prvm_builtin_t) (void); + +// [INIT] variables flagged with this token can be initialized by 'you' +// NOTE: external code has to create and free the mempools but everything else is done by prvm ! +typedef struct prvm_prog_s +{ + dprograms_t *progs; + mfunction_t *functions; + char *strings; + int stringssize; + ddef_t *fielddefs; + ddef_t *globaldefs; + dstatement_t *statements; + int edict_size; // in bytes + int edictareasize; // in bytes (for bound checking) + int pev_save; // used by PRVM_PUSH_GLOBALS\PRVM_POP_GLOBALS + int other_save; // used by PRVM_PUSH_GLOBALS\PRVM_POP_GLOBALS + + int *statement_linenums;// NULL if not available + double *statement_profile; // only incremented if prvm_statementprofiling is on + + union + { + float *generic; + globalvars_t *server; + } globals; + + int maxknownstrings; + int numknownstrings; + + // this is updated whenever a string is removed or added + // (simple optimization of the free string search) + int firstfreeknownstring; + const char **knownstrings; + byte *knownstrings_freeable; + const char ***stringshash; + + // all memory allocations related to this vm_prog (code, edicts, strings) + byte *progs_mempool; // [INIT] + + prvm_builtin_t *builtins; // [INIT] + int numbuiltins; // [INIT] + + int argc; + + int trace; + mfunction_t *xfunction; + int xstatement; + + // stacktrace writes into stack[MAX_STACK_DEPTH] + // thus increase the array, so depth wont be overwritten + prvm_stack_t stack[PRVM_MAX_STACK_DEPTH + 1]; + int depth; + + int localstack[PRVM_LOCALSTACK_SIZE]; + int localstack_used; + + word filecrc; + + //============================================================================ + // until this point everything also exists (with the pr_ prefix) in the old vm + + file_t *openfiles[PRVM_MAX_OPENFILES]; + search_t *opensearches[PRVM_MAX_OPENSEARCHES]; + + // copies of some vars that were former read from sv + int num_edicts; + // number of edicts for which space has been (should be) allocated + int max_edicts; // [INIT] + // used instead of the constant MAX_EDICTS + int limit_edicts; // [INIT] + + // number of reserved edicts (allocated from 1) + int reserved_edicts; // [INIT] + + edict_t *edicts; + void *edictsfields; + void *edictprivate; + + // size of the engine private struct + int edictprivate_size; // [INIT] + + // has to be updated every frame - so the vm time is up-to-date + // AK changed so time will point to the time field (if there is one) else it points to _time + // actually should be double, but qc doesnt support it + float *time; + float _time; + + // allow writing to world entity fields, this is set by server init and + // cleared before first server frame + bool protect_world; + + // name of the prog, e.g. "Server", "Client" or "Menu" (used for text output) + char *name; // [INIT] + + // flag - used to store general flags like PRVM_GE_SELF, etc. + int flag; + + char *extensionstring; // [INIT] + + bool loadintoworld; // [INIT] + + // used to indicate whether a prog is loaded + bool loaded; + + //============================================================================ + + ddef_t *self; // if self != 0 then there is a global self + + //============================================================================ + // function pointers + + void (*begin_increase_edicts)(void); // [INIT] used by PRVM_MEM_Increase_Edicts + void (*end_increase_edicts)(void); // [INIT] + + void (*init_edict)(edict_t *edict); // [INIT] used by PRVM_ED_ClearEdict + void (*free_edict)(edict_t *ed); // [INIT] used by PRVM_ED_Free + + void (*count_edicts)(void); // [INIT] used by PRVM_ED_Count_f + + bool (*load_edict)(edict_t *ent); // [INIT] used by PRVM_ED_LoadFromFile + + void (*init_cmd)(void); // [INIT] used by PRVM_InitProg + void (*reset_cmd)(void); // [INIT] used by PRVM_ResetProg + + void (*error_cmd)(const char *format, ...); // [INIT] + +} prvm_prog_t; + +extern prvm_prog_t *prog; + +enum +{ + PRVM_SERVERPROG = 0, + PRVM_CLIENTPROG, + PRVM_MENUPROG, + PRVM_MAXPROGS, // must be last +}; + +extern prvm_prog_t prvm_prog_list[PRVM_MAXPROGS]; + +//============================================================================ +// prvm_cmds part + +extern prvm_builtin_t vm_sv_builtins[]; +extern prvm_builtin_t vm_cl_builtins[]; +extern prvm_builtin_t vm_m_builtins[]; + +extern const int vm_sv_numbuiltins; +extern const int vm_cl_numbuiltins; +extern const int vm_m_numbuiltins; + +extern char * vm_sv_extensions; +extern char * vm_cl_extensions; +extern char * vm_m_extensions; + +void VM_SV_Cmd_Init(void); +void VM_SV_Cmd_Reset(void); + +void VM_CL_Cmd_Init(void); +void VM_CL_Cmd_Reset(void); + +void VM_M_Cmd_Init(void); +void VM_M_Cmd_Reset(void); + +void VM_Cmd_Init(void); +void VM_Cmd_Reset(void); +//============================================================================ + +void PRVM_Init (void); + +void PRVM_ExecuteProgram (func_t fnum, const char *errormessage); + +#define PRVM_Alloc(buffersize) _PRVM_Alloc(buffersize, __FILE__, __LINE__) +#define PRVM_Free(buffer) _PRVM_Free(buffer, __FILE__, __LINE__) +#define PRVM_FreeAll() _PRVM_FreeAll(__FILE__, __LINE__) +void *_PRVM_Alloc (size_t buffersize, const char *filename, int fileline); +void _PRVM_Free (void *buffer, const char *filename, int fileline); +void _PRVM_FreeAll (const char *filename, int fileline); + +void PRVM_Profile (int maxfunctions, int mininstructions); +void PRVM_Profile_f (void); +void PRVM_PrintFunction_f (void); + +void PRVM_PrintState(void); +void PRVM_CrashAll (void); +void PRVM_Crash (void); + +int PRVM_ED_FindFieldOffset(const char *field); +int PRVM_ED_FindGlobalOffset(const char *global); +ddef_t *PRVM_ED_FindField (const char *name); +ddef_t *PRVM_ED_FindGlobal (const char *name); +mfunction_t *PRVM_ED_FindFunction (const char *name); +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); + +void PRVM_PrintFunctionStatements (const char *name); +void PRVM_ED_Print(edict_t *ed); +void PRVM_ED_Write (file_t *f, edict_t *ed); +const char *PRVM_ED_ParseEdict (const char *data, edict_t *ent); + +void PRVM_ED_WriteGlobals (file_t *f); +void PRVM_ED_ParseGlobals (const char *data); + +void PRVM_ED_LoadFromFile (const char *data); + +edict_t *PRVM_EDICT_NUM_ERROR(int n, char *filename, int fileline); +#define PRVM_EDICT_NUM(n) (((n) >= 0 && (n) < prog->max_edicts) ? prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) +#define PRVM_EDICT_NUM_UNSIGNED(n) (((n) < prog->max_edicts) ? prog->edicts + (n) : PRVM_EDICT_NUM_ERROR(n, __FILE__, __LINE__)) +#define PRVM_NUM_FOR_EDICT(e) ((int)((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)) +#define PRVM_PUSH_GLOBALS prog->pev_save = prog->globals.server->pev, prog->other_save = prog->globals.server->other +#define PRVM_POP_GLOBALS prog->globals.server->pev = prog->pev_save, prog->globals.server->other = prog->other_save + +//============================================================================ + +#define PRVM_G_FLOAT(o) (prog->globals.generic[o]) +#define PRVM_G_INT(o) (*(int *)&prog->globals.generic[o]) +#define PRVM_G_EDICT(o) (PRVM_PROG_TO_EDICT(*(int *)&prog->globals.generic[o])) +#define PRVM_G_EDICTNUM(o) PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(o)) +#define PRVM_G_VECTOR(o) (&prog->globals.generic[o]) +#define PRVM_G_STRING(o) (PRVM_GetString(*(string_t *)&prog->globals.generic[o])) +//#define PRVM_G_FUNCTION(o) (*(func_t *)&prog->globals.generic[o]) + +// FIXME: make these go away? +#define PRVM_E_FLOAT(e,o) (((float*)e->progs.vp)[o]) +#define PRVM_E_INT(e,o) (((int*)e->progs.vp)[o]) +//#define PRVM_E_VECTOR(e,o) (&((float*)e->progs.vp)[o]) +#define PRVM_E_STRING(e,o) (PRVM_GetString(*(string_t *)&((float*)e->progs.vp)[o])) + +extern int prvm_type_size[8]; // for consistency : I think a goal of this sub-project is to +// make the new vm mostly independent from the old one, thus if it's necessary, I copy everything + +void PRVM_Init_Exec(void); + +void PRVM_ED_PrintEdicts_f (void); +void PRVM_ED_PrintNum (int ent); + +const char *PRVM_GetString(int num); +int PRVM_SetEngineString(const char *s); +int PRVM_AllocString(size_t bufferlength, char **pointer); +void PRVM_FreeString(int num); + +//============================================================================ + +#define PRVM_Begin +#define PRVM_End prog = 0 +#define PRVM_NAME (prog->name ? prog->name : "unnamed.dat") + +// helper macro to make function pointer calls easier +#define PRVM_GCALL(func) if(prog->func) prog->func +#define PRVM_ERROR prog->error_cmd + +// other prog handling functions +bool PRVM_SetProgFromString(const char *str); +void PRVM_SetProg(int prognr); + +/* +Initializing a vm: +Call InitProg with the num +Set up the fields marked with [INIT] in the prog struct +Load a program with LoadProgs +*/ +void PRVM_InitProg(int prognr); +// LoadProgs expects to be called right after InitProg +void PRVM_LoadProgs (const char *filename, int numrequiredfunc, char **required_func, int numrequiredfields, prvm_fieldvars_t *required_field); +void PRVM_ResetProg(void); + +bool PRVM_ProgLoaded(int prognr); + +int PRVM_GetProgNr(void); + +void VM_Warning(const char *fmt, ...); +void VM_Error(const char *fmt, ...); + +// TODO: fill in the params +//void PRVM_Create(); + +#endif diff --git a/engine/common/vm_cmds.c b/engine/common/vm_cmds.c new file mode 100644 index 00000000..59034067 --- /dev/null +++ b/engine/common/vm_cmds.c @@ -0,0 +1,3150 @@ +// AK +// Basically every vm builtin cmd should be in here. +// All 3 builtin and extension lists can be found here +// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds +// also applies here + +#include "engine.h" +#include "vm_cmds.h" +#include "sound.h" +#include "screen.h" +#include "keys.h" + +//============================================================================ +// Common + +// temp string handling +// LordHavoc: added this to semi-fix the problem of using many ftos calls in a print +static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH]; +static int vm_string_tempindex = 0; +extern render_exp_t *re; + +// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct) +// TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black] +char *VM_GetTempString(void) +{ + char *s; + s = vm_string_temp[vm_string_tempindex]; + vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS; + return s; +} + +void VM_CheckEmptyString (const char *s) +{ + if (s[0] <= ' ') + PRVM_ERROR ("%s: Bad string", PRVM_NAME); +} + +//============================================================================ +//BUILT-IN FUNCTIONS + +void VM_VarString(int first, char *out, int outlength) +{ + int i; + const char *s; + char *outend; + + outend = out + outlength - 1; + for (i = first;i < prog->argc && out < outend;i++) + { + s = PRVM_G_STRING((OFS_PARM0+i*3)); + while (out < outend && *s) + *out++ = *s++; + } + *out++ = 0; +} + +/* +================= +VM_checkextension + +returns true if the extension is supported by the server + +checkextension(extensionname) +================= +*/ + +// kind of helper function +static bool checkextension(const char *name) +{ + int len; + char *e, *start; + len = (int)strlen(name); + + for (e = prog->extensionstring;*e;e++) + { + while (*e == ' ') + e++; + if (!*e) + break; + start = e; + while (*e && *e != ' ') + e++; + if ((e - start) == len && !strncasecmp(start, name, len)) + return true; + } + return false; +} + +void VM_checkextension (void) +{ + VM_SAFEPARMCOUNT(1,VM_checkextension); + + PRVM_G_FLOAT(OFS_RETURN) = checkextension(PRVM_G_STRING(OFS_PARM0)); +} + +/* +================= +VM_error + +This is a TERMINAL error, which will kill off the entire prog. +Dumps self. + +error(value) +================= +*/ +void VM_error (void) +{ + edict_t *ed; + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(0, string, sizeof(string)); + Msg("======%s ERROR in %s:\n%s\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); + if(prog->self) + { + ed = PRVM_G_EDICT(prog->self->ofs); + PRVM_ED_Print(ed); + } + + PRVM_ERROR ("%s: Program error in function %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); +} + +/* +================= +VM_objerror + +Dumps out self, then an error message. The program is aborted and self is +removed, but the level can continue. + +objerror(value) +================= +*/ +void VM_objerror (void) +{ + edict_t *ed; + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(0, string, sizeof(string)); + Msg("======OBJECT ERROR======\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); + if(prog->self) + { + ed = PRVM_G_EDICT (prog->self->ofs); + PRVM_ED_Print(ed); + + PRVM_ED_Free (ed); + } + else + // objerror has to display the object progs -> else call + PRVM_ERROR ("VM_objecterror: self not defined !"); + Msg("%s OBJECT ERROR in %s:\n%s\nTip: read above for entity information\n", PRVM_NAME, PRVM_GetString(prog->xfunction->s_name), string); +} + +/* +================= +VM_print (actually used only by client and menu) + +print to console + +print(string) +================= +*/ +void VM_print (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(0, string, sizeof(string)); + Con_Print(string); +} + +/* +================= +VM_bprint + +broadcast print to everyone on server + +bprint(...[string]) +================= +*/ +void VM_bprint (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(0, string, sizeof(string)); + + if(sv.state != ss_game) + { + Con_Print( string ); +//VM_Warning("VM_bprint: game is not server(%s) !\n", PRVM_NAME); + return; + } + + SV_BroadcastPrintf(PRINT_HIGH, string); +} + +/* +================= +VM_sprint (menu & client but only if server.active == true) + +single print to a specific client + +sprint(float clientnum,...[string]) +================= +*/ +void VM_sprint( void ) +{ + int num; + char string[VM_STRINGTEMP_LENGTH]; + + //find client for this entity + num = (int)PRVM_G_FLOAT(OFS_PARM0); + if (sv.state != ss_game || num < 0 || num >= host.maxclients || !svs.clients[num].state != cs_spawned) + { + VM_Warning("VM_sprint: %s: invalid client or server is not active !\n", PRVM_NAME); + return; + } + + VM_VarString(1, string, sizeof(string)); + SV_ClientPrintf (svs.clients+(num - 1), PRINT_HIGH, "%s", string ); +} + +/* +================= +VM_centerprint + +single print to the screen + +centerprint(clientent, value) +================= +*/ +void VM_centerprint (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + + VM_VarString(0, string, sizeof(string)); + + SCR_CenterPrint(string); +} + +/* +================= +VM_normalize + +vector normalize(vector) +================= +*/ +void VM_normalize (void) +{ + float *value1; + vec3_t newvalue; + double f; + + VM_SAFEPARMCOUNT(1,VM_normalize); + + value1 = PRVM_G_VECTOR(OFS_PARM0); + + f = DotProduct(value1, value1); + if (f) + { + f = 1.0 / sqrt(f); + VectorScale(value1, f, newvalue); + } + else VectorClear(newvalue); + + VectorCopy (newvalue, PRVM_G_VECTOR(OFS_RETURN)); +} + +/* +================= +VM_vlen + +scalar vlen(vector) +================= +*/ +void VM_vlen (void) +{ + VM_SAFEPARMCOUNT(1,VM_vlen); + PRVM_G_FLOAT(OFS_RETURN) = VectorLength(PRVM_G_VECTOR(OFS_PARM0)); +} + +/* +================= +VM_vectoyaw + +float vectoyaw(vector) +================= +*/ +void VM_vectoyaw (void) +{ + float *value1; + float yaw; + + VM_SAFEPARMCOUNT(1,VM_vectoyaw); + + 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) +================= +*/ +void VM_vectoangles (void) +{ + float *value1; + float forward; + float yaw, pitch; + + VM_SAFEPARMCOUNT(1,VM_vectoangles); + + 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 + { + // LordHavoc: optimized a bit + 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; + } + + PRVM_G_FLOAT(OFS_RETURN+0) = pitch; + PRVM_G_FLOAT(OFS_RETURN+1) = yaw; + PRVM_G_FLOAT(OFS_RETURN+2) = 0; +} + +/* +================= +VM_random + +Returns a number from 0<= num < 1 + +float random() +================= +*/ +void VM_random (void) +{ + VM_SAFEPARMCOUNT(0,VM_random); + + PRVM_G_FLOAT(OFS_RETURN) = RANDOM_LONG(0, 1); +} + +/* +================= +PF_sound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +already running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. + +================= +*/ +/* +void PF_sound (void) +{ + char *sample; + int channel; + edict_t *entity; + int volume; + float attenuation; + + entity = PRVM_G_EDICT(OFS_PARM0); + channel = PRVM_G_FLOAT(OFS_PARM1); + sample = PRVM_G_STRING(OFS_PARM2); + volume = PRVM_G_FLOAT(OFS_PARM3) * 255; + attenuation = PRVM_G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 255) + Host_Error ("SV_StartSound: volume = %i", volume); + + if (attenuation < 0 || attenuation > 4) + Host_Error ("SV_StartSound: attenuation = %f", attenuation); + + if (channel < 0 || channel > 7) + Host_Error ("SV_StartSound: channel = %i", channel); + + SV_StartSound (entity, channel, sample, volume, attenuation); +} +*/ + +/* +========= +VM_localsound + +localsound(string sample) +========= +*/ +void VM_localsound(void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_localsound); + + s = PRVM_G_STRING(OFS_PARM0); + + if(!S_StartLocalSound(s)) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning("VM_localsound: Failed to play %s for %s !\n", s, PRVM_NAME); + return; + } + + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +================= +VM_break + +break() +================= +*/ +void VM_break (void) +{ + PRVM_ERROR ("%s: break statement", PRVM_NAME); +} + +//============================================================================ + +/* +================= +VM_localcmd + +Sends text over to the client's execution buffer + +[localcmd (string, ...) or] +cmd (string, ...) +================= +*/ +void VM_localcmd (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_VarString(0, string, sizeof(string)); + Cbuf_AddText(string); +} + +/* +================= +VM_cvar + +float cvar (string) +================= +*/ +void VM_cvar (void) +{ + VM_SAFEPARMCOUNT(1,VM_cvar); + + PRVM_G_FLOAT(OFS_RETURN) = Cvar_VariableValue(PRVM_G_STRING(OFS_PARM0)); +} + +/* +================= +VM_cvar_string + +const string VM_cvar_string (string) +================= +*/ +void VM_cvar_string(void) +{ + char *out; + const char *name; + const char *cvar_string; + VM_SAFEPARMCOUNT(1,VM_cvar_string); + + name = PRVM_G_STRING(OFS_PARM0); + + if(!name) + PRVM_ERROR("VM_cvar_string: %s: null string", PRVM_NAME); + + VM_CheckEmptyString(name); + + out = VM_GetTempString(); + + cvar_string = Cvar_VariableString(name); + + strncpy(out, cvar_string, VM_STRINGTEMP_LENGTH); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out); +} + +/* +================= +VM_cvar_set + +void cvar_set (string,string) +================= +*/ +void VM_cvar_set (void) +{ + VM_SAFEPARMCOUNT(2,VM_cvar_set); + + Cvar_Set(PRVM_G_STRING(OFS_PARM0), PRVM_G_STRING(OFS_PARM1)); +} + +/* +========= +VM_dprint + +dprint(...[string]) +========= +*/ +void VM_dprint (void) +{ + char string[VM_STRINGTEMP_LENGTH]; + if (host.debug) + { + VM_VarString(0, string, sizeof(string)); + Msg("%s", string); + } +} + +/* +========= +VM_ftos + +string ftos(float) +========= +*/ + +void VM_ftos (void) +{ + float v; + char *s; + + VM_SAFEPARMCOUNT(1, VM_ftos); + + v = PRVM_G_FLOAT(OFS_PARM0); + + s = VM_GetTempString(); + if ((float)((int)v) == v) + sprintf(s, "%i", (int)v); + else + sprintf(s, "%f", v); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); +} + +/* +========= +VM_fabs + +float fabs(float) +========= +*/ + +void VM_fabs (void) +{ + float v; + + VM_SAFEPARMCOUNT(1,VM_fabs); + + v = PRVM_G_FLOAT(OFS_PARM0); + PRVM_G_FLOAT(OFS_RETURN) = fabs(v); +} + +/* +========= +VM_vtos + +string vtos(vector) +========= +*/ + +void VM_vtos (void) +{ + char *s; + + VM_SAFEPARMCOUNT(1,VM_vtos); + + s = VM_GetTempString(); + sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); +} + +/* +========= +VM_etos + +string etos(entity) +========= +*/ + +void VM_etos (void) +{ + char *s; + + VM_SAFEPARMCOUNT(1, VM_etos); + + s = VM_GetTempString(); + sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); +} + +/* +========= +VM_stof + +float stof(...[string]) +========= +*/ +void VM_stof(void) +{ + char string[VM_STRINGTEMP_LENGTH]; + VM_VarString(0, string, sizeof(string)); + PRVM_G_FLOAT(OFS_RETURN) = atof(string); +} + +/* +======================== +VM_itof + +float itof(intt ent) +======================== +*/ +void VM_itof(void) +{ + VM_SAFEPARMCOUNT(1, VM_itof); + PRVM_G_FLOAT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +/* +======================== +VM_ftoe + +entity ftoe(float num) +======================== +*/ +void VM_ftoe(void) +{ + int ent; + VM_SAFEPARMCOUNT(1, VM_ftoe); + + ent = (int)PRVM_G_FLOAT(OFS_PARM0); + if (ent < 0 || ent >= MAX_EDICTS || PRVM_PROG_TO_EDICT(ent)->priv.ed->free) + ent = 0; // return world instead of a free or invalid entity + + PRVM_G_INT(OFS_RETURN) = ent; +} + +/* +========= +VM_spawn + +entity spawn() +========= +*/ + +void VM_spawn (void) +{ + edict_t *ed; + prog->xfunction->builtinsprofile += 20; + ed = PRVM_ED_Alloc(); + VM_RETURN_EDICT(ed); +} + +/* +========= +VM_remove + +remove(entity e) +========= +*/ + +void VM_remove (void) +{ + edict_t *ed; + prog->xfunction->builtinsprofile += 20; + + VM_SAFEPARMCOUNT(1, VM_remove); + + ed = PRVM_G_EDICT(OFS_PARM0); + if( PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts ) + { + if (host.developer >= D_INFO) + VM_Warning( "VM_remove: tried to remove the null entity or a reserved entity!\n" ); + } + else if( ed->priv.ed->free ) + { + if (host.developer >= D_INFO) + VM_Warning( "VM_remove: tried to remove an already freed entity!\n" ); + } + else PRVM_ED_Free (ed); +} + +/* +========= +VM_find + +entity find(entity start, .string field, string match) +========= +*/ + +void VM_find (void) +{ + int e; + int f; + const char *s, *t; + edict_t *ed; + + VM_SAFEPARMCOUNT(3,VM_find); + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = PRVM_G_STRING(OFS_PARM2); + + // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and + // expects it to find all the monsters, so we must be careful to support + // searching for "" + if (!s) + s = ""; + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.ed->free) + continue; + t = PRVM_E_STRING(ed,f); + if (!t) + t = ""; + if (!strcmp(t,s)) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +========= +VM_findfloat + + entity findfloat(entity start, .float field, float match) + entity findentity(entity start, .entity field, entity match) +========= +*/ +// LordHavoc: added this for searching float, int, and entity reference fields +void VM_findfloat (void) +{ + int e; + int f; + float s; + edict_t *ed; + + VM_SAFEPARMCOUNT(3,VM_findfloat); + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = PRVM_G_FLOAT(OFS_PARM2); + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.ed->free) + continue; + if (PRVM_E_FLOAT(ed,f) == s) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +========= +VM_findchain + +entity findchain(.string field, string match) +========= +*/ +// chained search for strings in entity fields +// entity(.string field, string match) findchain = #402; +void VM_findchain (void) +{ + int i; + int f; + int chain_of; + const char *s, *t; + edict_t *ent, *chain; + + VM_SAFEPARMCOUNT(2,VM_findchain); + + // is the same like !(prog->flag & PRVM_FE_CHAIN) - even if the operator precedence is another + if(!prog->flag & PRVM_FE_CHAIN) + PRVM_ERROR("VM_findchain: %s doesnt have a chain field !", PRVM_NAME); + + chain_of = PRVM_ED_FindField("chain")->ofs; + + chain = prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = PRVM_G_STRING(OFS_PARM1); + + // LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and + // expects it to find all the monsters, so we must be careful to support + // searching for "" + if (!s) + s = ""; + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.ed->free) + continue; + t = PRVM_E_STRING(ent,f); + if (!t) + t = ""; + if (strcmp(t,s)) + continue; + + PRVM_E_INT(ent,chain_of) = PRVM_NUM_FOR_EDICT(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +========= +VM_findchainfloat + +entity findchainfloat(.string field, float match) +entity findchainentity(.string field, entity match) +========= +*/ +// LordHavoc: chained search for float, int, and entity reference fields +// entity(.string field, float match) findchainfloat = #403; +void VM_findchainfloat (void) +{ + int i; + int f; + int chain_of; + float s; + edict_t *ent, *chain; + + VM_SAFEPARMCOUNT(2, VM_findchainfloat); + + if(!prog->flag & PRVM_FE_CHAIN) + PRVM_ERROR("VM_findchainfloat: %s doesnt have a chain field !", PRVM_NAME); + + chain_of = PRVM_ED_FindField("chain")->ofs; + + chain = (edict_t *)prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = PRVM_G_FLOAT(OFS_PARM1); + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.ed->free) + continue; + if (PRVM_E_FLOAT(ent,f) != s) + continue; + + PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +======================== +VM_findflags + +entity findflags(entity start, .float field, float match) +======================== +*/ +// LordHavoc: search for flags in float fields +void VM_findflags (void) +{ + int e; + int f; + int s; + edict_t *ed; + + VM_SAFEPARMCOUNT(3, VM_findflags); + + + e = PRVM_G_EDICTNUM(OFS_PARM0); + f = PRVM_G_INT(OFS_PARM1); + s = (int)PRVM_G_FLOAT(OFS_PARM2); + + for (e++ ; e < prog->num_edicts ; e++) + { + prog->xfunction->builtinsprofile++; + ed = PRVM_EDICT_NUM(e); + if (ed->priv.ed->free) + continue; + if (!PRVM_E_FLOAT(ed,f)) + continue; + if ((int)PRVM_E_FLOAT(ed,f) & s) + { + VM_RETURN_EDICT(ed); + return; + } + } + + VM_RETURN_EDICT(prog->edicts); +} + +/* +======================== +VM_findchainflags + +entity findchainflags(.float field, float match) +======================== +*/ +// LordHavoc: chained search for flags in float fields +void VM_findchainflags (void) +{ + int i; + int f; + int s; + int chain_of; + edict_t *ent, *chain; + + VM_SAFEPARMCOUNT(2, VM_findchainflags); + + if(!prog->flag & PRVM_FE_CHAIN) + PRVM_ERROR("VM_findchainflags: %s doesnt have a chain field !", PRVM_NAME); + + chain_of = PRVM_ED_FindField("chain")->ofs; + + chain = (edict_t *)prog->edicts; + + f = PRVM_G_INT(OFS_PARM0); + s = (int)PRVM_G_FLOAT(OFS_PARM1); + + ent = PRVM_NEXT_EDICT(prog->edicts); + for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + { + prog->xfunction->builtinsprofile++; + if (ent->priv.ed->free) + continue; + if (!PRVM_E_FLOAT(ent,f)) + continue; + if (!((int)PRVM_E_FLOAT(ent,f) & s)) + continue; + + PRVM_E_INT(ent,chain_of) = PRVM_EDICT_TO_PROG(chain); + chain = ent; + } + + VM_RETURN_EDICT(chain); +} + +/* +========= +VM_coredump + +coredump() +========= +*/ +void VM_coredump (void) +{ + VM_SAFEPARMCOUNT(0,VM_coredump); + + Cbuf_AddText("prvm_edicts "); + Cbuf_AddText(PRVM_NAME); + Cbuf_AddText("\n"); +} + +/* +========= +VM_stackdump + +stackdump() +========= +*/ +void PRVM_StackTrace(void); +void VM_stackdump (void) +{ + VM_SAFEPARMCOUNT(0, VM_stackdump); + + PRVM_StackTrace(); +} + +/* +========= +VM_crash + +crash() +========= +*/ + +void VM_crash(void) +{ + VM_SAFEPARMCOUNT(0, VM_crash); + + PRVM_ERROR("Crash called by %s",PRVM_NAME); +} + +/* +========= +VM_traceon + +traceon() +========= +*/ +void VM_traceon (void) +{ + VM_SAFEPARMCOUNT(0,VM_traceon); + + prog->trace = true; +} + +/* +========= +VM_traceoff + +traceoff() +========= +*/ +void VM_traceoff (void) +{ + VM_SAFEPARMCOUNT(0,VM_traceoff); + + prog->trace = false; +} + +/* +========= +VM_eprint + +eprint(entity e) +========= +*/ +void VM_eprint (void) +{ + VM_SAFEPARMCOUNT(1,VM_eprint); + + PRVM_ED_PrintNum (PRVM_G_EDICTNUM(OFS_PARM0)); +} + +/* +========= +VM_rint + +float rint(float) +========= +*/ +void VM_rint (void) +{ + float f; + VM_SAFEPARMCOUNT(1,VM_rint); + + f = PRVM_G_FLOAT(OFS_PARM0); + if (f > 0) + PRVM_G_FLOAT(OFS_RETURN) = floor(f + 0.5); + else + PRVM_G_FLOAT(OFS_RETURN) = ceil(f - 0.5); +} + +/* +========= +VM_floor + +float floor(float) +========= +*/ +void VM_floor (void) +{ + VM_SAFEPARMCOUNT(1,VM_floor); + + PRVM_G_FLOAT(OFS_RETURN) = floor(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_ceil + +float ceil(float) +========= +*/ +void VM_ceil (void) +{ + VM_SAFEPARMCOUNT(1,VM_ceil); + + PRVM_G_FLOAT(OFS_RETURN) = ceil(PRVM_G_FLOAT(OFS_PARM0)); +} + + +/* +============= +VM_nextent + +entity nextent(entity) +============= +*/ +void VM_nextent (void) +{ + int i; + edict_t *ent; + + i = PRVM_G_EDICTNUM(OFS_PARM0); + while (1) + { + prog->xfunction->builtinsprofile++; + i++; + if (i == prog->num_edicts) + { + VM_RETURN_EDICT(prog->edicts); + return; + } + ent = PRVM_EDICT_NUM(i); + if (!ent->priv.ed->free) + { + VM_RETURN_EDICT(ent); + return; + } + } +} + +//============================================================================= + +/* +============== +VM_changelevel +server and menu + +changelevel(string map) +============== +*/ +void VM_changelevel (void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_changelevel); + + if(sv.state != ss_game) + { + VM_Warning("VM_changelevel: game is not server (%s)\n", PRVM_NAME); + return; + } + + s = PRVM_G_STRING(OFS_PARM0); + Cbuf_AddText (va("changelevel %s\n",s)); +} + +/* +========= +VM_sin + +float sin(float) +========= +*/ +void VM_sin (void) +{ + VM_SAFEPARMCOUNT(1,VM_sin); + PRVM_G_FLOAT(OFS_RETURN) = sin(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_cos +float cos(float) +========= +*/ +void VM_cos (void) +{ + VM_SAFEPARMCOUNT(1,VM_cos); + PRVM_G_FLOAT(OFS_RETURN) = cos(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +========= +VM_sqrt + +float sqrt(float) +========= +*/ +void VM_sqrt (void) +{ + VM_SAFEPARMCOUNT(1,VM_sqrt); + PRVM_G_FLOAT(OFS_RETURN) = sqrt(PRVM_G_FLOAT(OFS_PARM0)); +} + +/* +================= +VM_randomvec + +Returns a vector of length < 1 and > 0 + +vector randomvec() +================= +*/ +void VM_randomvec (void) +{ + vec3_t temp; + //float length; + + VM_SAFEPARMCOUNT(0, VM_randomvec); + + //// WTF ?? + do + { + temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + } + while (DotProduct(temp, temp) >= 1); + VectorCopy (temp, PRVM_G_VECTOR(OFS_RETURN)); + + /* + temp[0] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + temp[1] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + temp[2] = (rand()&32767) * (2.0 / 32767.0) - 1.0; + // length returned always > 0 + length = (rand()&32766 + 1) * (1.0 / 32767.0) / VectorLength(temp); + VectorScale(temp,length, temp);*/ + //VectorCopy(temp, PRVM_G_VECTOR(OFS_RETURN)); +} + +//============================================================================= + +/* +========= +VM_registercvar + +float registercvar (string name, string value, float flags) +========= +*/ +void VM_registercvar (void) +{ + const char *name, *value; + int flags; + + VM_SAFEPARMCOUNT(3,VM_registercvar); + + name = PRVM_G_STRING(OFS_PARM0); + value = PRVM_G_STRING(OFS_PARM1); + flags = (int)PRVM_G_FLOAT(OFS_PARM2); + PRVM_G_FLOAT(OFS_RETURN) = 0; + + if(flags > CVAR_MAXFLAGSVAL) + return; + +// first check to see if it has already been defined + if (Cvar_FindVar (name)) + return; + +// check for overlap with a command + if (Cmd_Exists (name)) + { + VM_Warning("VM_registercvar: %s is a command\n", name); + return; + } + + Cvar_Get(name, value, flags); + + PRVM_G_FLOAT(OFS_RETURN) = 1; // success +} + +/* +================= +VM_min + +returns the minimum of two supplied floats + +float min(float a, float b, ...[float]) +================= +*/ +void VM_min (void) +{ + // LordHavoc: 3+ argument enhancement suggested by FrikaC + if (prog->argc == 2) + PRVM_G_FLOAT(OFS_RETURN) = min(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); + else if (prog->argc >= 3) + { + int i; + float f = PRVM_G_FLOAT(OFS_PARM0); + for (i = 1;i < prog->argc;i++) + if (PRVM_G_FLOAT((OFS_PARM0+i*3)) < f) + f = PRVM_G_FLOAT((OFS_PARM0+i*3)); + PRVM_G_FLOAT(OFS_RETURN) = f; + } + else + PRVM_ERROR("VM_min: %s must supply at least 2 floats", PRVM_NAME); +} + +/* +================= +VM_max + +returns the maximum of two supplied floats + +float max(float a, float b, ...[float]) +================= +*/ +void VM_max (void) +{ + // LordHavoc: 3+ argument enhancement suggested by FrikaC + if (prog->argc == 2) + PRVM_G_FLOAT(OFS_RETURN) = max(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); + else if (prog->argc >= 3) + { + int i; + float f = PRVM_G_FLOAT(OFS_PARM0); + for (i = 1;i < prog->argc;i++) + if (PRVM_G_FLOAT((OFS_PARM0+i*3)) > f) + f = PRVM_G_FLOAT((OFS_PARM0+i*3)); + PRVM_G_FLOAT(OFS_RETURN) = f; + } + else + PRVM_ERROR("VM_max: %s must supply at least 2 floats", PRVM_NAME); +} + +/* +================= +VM_bound + +returns number bounded by supplied range + +float bound(float min, float value, float max) +================= +*/ +void VM_bound (void) +{ + VM_SAFEPARMCOUNT(3,VM_bound); + PRVM_G_FLOAT(OFS_RETURN) = bound(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1), PRVM_G_FLOAT(OFS_PARM2)); +} + +/* +================= +VM_pow + +returns a raised to power b + +float pow(float a, float b) +================= +*/ +void VM_pow (void) +{ + VM_SAFEPARMCOUNT(2,VM_pow); + PRVM_G_FLOAT(OFS_RETURN) = pow(PRVM_G_FLOAT(OFS_PARM0), PRVM_G_FLOAT(OFS_PARM1)); +} + +/* +================= +VM_copyentity + +copies data from one entity to another + +copyentity(entity src, entity dst) +================= +*/ +void VM_copyentity (void) +{ + edict_t *in, *out; + VM_SAFEPARMCOUNT(2,VM_copyentity); + in = PRVM_G_EDICT(OFS_PARM0); + out = PRVM_G_EDICT(OFS_PARM1); + memcpy(out->progs.vp, in->progs.vp, prog->progs->entityfields * 4); +} + +void VM_Files_Init(void) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENFILES;i++) + prog->openfiles[i] = NULL; +} + +void VM_Files_CloseAll(void) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENFILES;i++) + { + if (prog->openfiles[i]) + FS_Close(prog->openfiles[i]); + prog->openfiles[i] = NULL; + } +} + +file_t *VM_GetFileHandle( int index ) +{ + if (index < 0 || index >= PRVM_MAX_OPENFILES) + { + Msg("VM_GetFileHandle: invalid file handle %i used in %s\n", index, PRVM_NAME); + return NULL; + } + if (prog->openfiles[index] == NULL) + { + Msg("VM_GetFileHandle: no such file handle %i (or file has been closed) in %s\n", index, PRVM_NAME); + return NULL; + } + return prog->openfiles[index]; +} + +/* +========= +VM_fopen + +float fopen(string filename, float mode) +========= +*/ +// float(string filename, float mode) fopen = #110; +// opens a file inside quake/gamedir/data/ (mode is FILE_READ, FILE_APPEND, or FILE_WRITE), +// returns fhandle >= 0 if successful, or fhandle < 0 if unable to open file for any reason +void VM_fopen(void) +{ + int filenum, mode; + const char *modestring, *filename; + + VM_SAFEPARMCOUNT(2,VM_fopen); + + for (filenum = 0;filenum < PRVM_MAX_OPENFILES;filenum++) + if (prog->openfiles[filenum] == NULL) + break; + if (filenum >= PRVM_MAX_OPENFILES) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning("VM_fopen: %s ran out of file handles (%i)\n", PRVM_NAME, PRVM_MAX_OPENFILES); + return; + } + mode = (int)PRVM_G_FLOAT(OFS_PARM1); + switch(mode) + { + case 0: // FILE_READ + modestring = "rb"; + break; + case 1: // FILE_APPEND + modestring = "ab"; + break; + case 2: // FILE_WRITE + modestring = "wb"; + break; + default: + PRVM_G_FLOAT(OFS_RETURN) = -3; + VM_Warning("VM_fopen: %s: no such mode %i (valid: 0 = read, 1 = append, 2 = write)\n", PRVM_NAME, mode); + return; + } + filename = PRVM_G_STRING(OFS_PARM0); + + prog->openfiles[filenum] = FS_Open(va("data/%s", filename), modestring ); + if (prog->openfiles[filenum] == NULL && mode == 0) + prog->openfiles[filenum] = FS_Open(va("%s", filename), modestring ); + + if (prog->openfiles[filenum] == NULL) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + if (host.developer >= D_WARN) + VM_Warning("VM_fopen: %s: %s mode %s failed\n", PRVM_NAME, filename, modestring); + } + else + { + PRVM_G_FLOAT(OFS_RETURN) = filenum; + if (host.developer >= D_WARN) + Msg("VM_fopen: %s: %s mode %s opened as #%i\n", PRVM_NAME, filename, modestring, filenum); + } +} + +/* +========= +VM_fclose + +fclose(float fhandle) +========= +*/ +//void(float fhandle) fclose = #111; // closes a file +void VM_fclose(void) +{ + int filenum; + + VM_SAFEPARMCOUNT(1,VM_fclose); + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning("VM_fclose: invalid file handle %i used in %s\n", filenum, PRVM_NAME); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning("VM_fclose: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME); + return; + } + FS_Close(prog->openfiles[filenum]); + prog->openfiles[filenum] = NULL; + if (host.developer >= D_WARN) + Msg("VM_fclose: %s: #%i closed\n", PRVM_NAME, filenum); +} + +/* +========= +VM_fgets + +string fgets(float fhandle) +========= +*/ +//string(float fhandle) fgets = #112; // reads a line of text from the file and returns as a tempstring +void VM_fgets(void) +{ + int c; + static char string[VM_STRINGTEMP_LENGTH]; + int filenum; + + VM_SAFEPARMCOUNT(1, VM_fgets); + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning("VM_fgets: invalid file handle %i used in %s\n", filenum, PRVM_NAME); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning("VM_fgets: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME); + return; + } + + c = FS_Gets (prog->openfiles[filenum], string, VM_STRINGTEMP_LENGTH ); + + if (host.developer >= D_WARN) Msg("fgets: %s: %s\n", PRVM_NAME, string); + + if (c >= 0) PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); + else PRVM_G_INT(OFS_RETURN) = 0; +} + +/* +========= +VM_fputs + +fputs(float fhandle, string s) +========= +*/ +//void(float fhandle, string s) fputs = #113; // writes a line of text to the end of the file +void VM_fputs(void) +{ + int stringlength; + char string[VM_STRINGTEMP_LENGTH]; + int filenum; + + VM_SAFEPARMCOUNT(2,VM_fputs); + + filenum = (int)PRVM_G_FLOAT(OFS_PARM0); + if (filenum < 0 || filenum >= PRVM_MAX_OPENFILES) + { + VM_Warning("VM_fputs: invalid file handle %i used in %s\n", filenum, PRVM_NAME); + return; + } + if (prog->openfiles[filenum] == NULL) + { + VM_Warning("VM_fputs: no such file handle %i (or file has been closed) in %s\n", filenum, PRVM_NAME); + return; + } + VM_VarString(1, string, sizeof(string)); + if ((stringlength = (int)strlen(string))) + FS_Write(prog->openfiles[filenum], string, stringlength); + if (host.developer >= D_WARN) + Msg("fputs: %s: %s\n", PRVM_NAME, string); +} + +/* +========= +VM_strlen + +float strlen(string s) +========= +*/ +//float(string s) strlen = #114; // returns how many characters are in a string +void VM_strlen(void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1,VM_strlen); + + s = PRVM_G_STRING(OFS_PARM0); + if (s) + PRVM_G_FLOAT(OFS_RETURN) = strlen(s); + else + PRVM_G_FLOAT(OFS_RETURN) = 0; +} + +/* +========= +VM_strcat + +string strcat(string,string,...[string]) +========= +*/ +//string(string s1, string s2) strcat = #115; +// concatenates two strings (for example "abc", "def" would return "abcdef") +// and returns as a tempstring +void VM_strcat(void) +{ + char *s; + + if(prog->argc < 1) + PRVM_ERROR("VM_strcat wrong parameter count (min. 1 expected ) !"); + + s = VM_GetTempString(); + VM_VarString(0, s, VM_STRINGTEMP_LENGTH); + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s); +} + +/* +========= +VM_substring + +string substring(string s, float start, float length) +========= +*/ +// string(string s, float start, float length) substring = #116; +// returns a section of a string as a tempstring +void VM_substring(void) +{ + int i, start, length; + const char *s; + char *string; + + VM_SAFEPARMCOUNT(3,VM_substring); + + string = VM_GetTempString(); + s = PRVM_G_STRING(OFS_PARM0); + start = (int)PRVM_G_FLOAT(OFS_PARM1); + length = (int)PRVM_G_FLOAT(OFS_PARM2); + if (!s) + s = ""; + for (i = 0;i < start && *s;i++, s++); + for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++) + string[i] = *s; + string[i] = 0; + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string); +} + +/* +========= +VM_stov + +vector stov(string s) +========= +*/ +//vector(string s) stov = #117; // returns vector value from a string +void VM_stov(void) +{ + char string[VM_STRINGTEMP_LENGTH]; + vec3_t out; + const char *s; + int i; + + VM_SAFEPARMCOUNT(1,VM_stov); + + VM_VarString(0, string, sizeof(string)); + + s = string; + VectorClear( out ); + + if (*s == '\'') s++; + for (i = 0;i < 3;i++) + { + while (*s == ' ' || *s == '\t') s++; + out[i] = atof(s); + if (out[i] == 0 && *s != '-' && *s != '+' && (*s < '0' || *s > '9')) + break; // not a number + while (*s && *s != ' ' && *s !='\t' && *s != '\'') s++; + if (*s == '\'') break; + } + VectorCopy(out, PRVM_G_VECTOR(OFS_RETURN)); +} + +/* +========= +VM_strzone + +string strzone(string s) +========= +*/ +//string(string s, ...) strzone = #118; // makes a copy of a string into the string zone and returns it, this is often used to keep around a tempstring for longer periods of time (tempstrings are replaced often) +void VM_strzone(void) +{ + char *out; + char string[VM_STRINGTEMP_LENGTH]; + size_t alloclen; + + VM_SAFEPARMCOUNT(1,VM_strzone); + + VM_VarString(0, string, sizeof(string)); + alloclen = strlen(string) + 1; + PRVM_G_INT(OFS_RETURN) = PRVM_AllocString(alloclen, &out); + memcpy(out, string, alloclen); +} + +/* +========= +VM_strunzone + +strunzone(string s) +========= +*/ +//void(string s) strunzone = #119; // removes a copy of a string from the string zone (you can not use that string again or it may crash!!!) +void VM_strunzone(void) +{ + VM_SAFEPARMCOUNT(1,VM_strunzone); + PRVM_FreeString(PRVM_G_INT(OFS_PARM0)); +} + +/* +========= +VM_command (used by client and menu) + +clientcommand(float client, string s) (for client and menu) +========= +*/ +//void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client +//this function originally written by KrimZon, made shorter by LordHavoc +void VM_clcommand (void) +{ + client_t *temp_client; + int i; + + VM_SAFEPARMCOUNT(2, VM_clcommand); + + i = (int)PRVM_G_FLOAT(OFS_PARM0); + if (sv.state != ss_game || i < 0 || i >= host.maxclients || svs.clients[i].state != cs_spawned) + { + VM_Warning("VM_clientcommand: %s: invalid client/server is not active !\n", PRVM_NAME); + return; + } + + temp_client = sv_client; + sv_client = svs.clients + i; + Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1)); + sv_client = temp_client; +} + + +/* +========= +VM_tokenize + +float tokenize(string s) +========= +*/ +//float(string s) tokenize = #441; // takes apart a string into individal words (access them with argv), returns how many +//this function originally written by KrimZon, made shorter by LordHavoc +//20040203: rewritten by LordHavoc (no longer uses allocations) +int num_tokens = 0; +char *tokens[256], tokenbuf[MAX_INPUTLINE]; +void VM_tokenize (void) +{ + size_t pos; + const char *p; + + VM_SAFEPARMCOUNT(1, VM_tokenize); + + p = PRVM_G_STRING(OFS_PARM0); + + num_tokens = 0; + pos = 0; + + while(COM_Parse(&p)) + { + size_t tokenlen; + if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0]))) + break; + tokenlen = strlen(COM_Token()) + 1; + if (pos + tokenlen > sizeof(tokenbuf)) + break; + tokens[num_tokens++] = tokenbuf + pos; + Mem_Copy(tokenbuf + pos, COM_Token(), tokenlen); + pos += tokenlen; + } + + PRVM_G_FLOAT(OFS_RETURN) = num_tokens; +} + +//string(float n) argv = #442; // returns a word from the tokenized string (returns nothing for an invalid index) +//this function originally written by KrimZon, made shorter by LordHavoc +void VM_argv (void) +{ + int token_num; + + VM_SAFEPARMCOUNT(1,VM_argv); + + token_num = (int)PRVM_G_FLOAT(OFS_PARM0); + + if (token_num >= 0 && token_num < num_tokens) + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tokens[token_num]); + else + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL); +} + +/* +//void(entity e, entity tagentity, string tagname) setattachment = #443; // attachs e to a tag on tagentity (note: use "" to attach to entity origin/angles instead of a tag) +void PF_setattachment (void) +{ + edict_t *e = PRVM_G_EDICT(OFS_PARM0); + edict_t *tagentity = PRVM_G_EDICT(OFS_PARM1); + char *tagname = PRVM_G_STRING(OFS_PARM2); + prvm_eval_t *v; + int i, modelindex; + model_t *model; + + if (tagentity == NULL) + tagentity = prog->edicts; + + v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_entity); + if (v) + fields.server->edict = PRVM_EDICT_TO_PROG(tagentity); + + v = PRVM_GETEDICTFIELDVALUE(e, eval_tag_index); + if (v) + fields.server->_float = 0; + if (tagentity != NULL && tagentity != prog->edicts && tagname && tagname[0]) + { + modelindex = (int)tagentity->progs.server->modelindex; + if (modelindex >= 0 && modelindex < MAX_MODELS) + { + model = sv.models[modelindex]; + if (model->data_overridetagnamesforskin && (unsigned int)tagentity->progs.server->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->progs.server->skin].num_overridetagnames) + for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->progs.server->skin].num_overridetagnames;i++) + if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->progs.server->skin].data_overridetagnames[i].name)) + fields.server->_float = i + 1; + // FIXME: use a model function to get tag info (need to handle skeletal) + if (fields.server->_float == 0 && model->num_tags) + for (i = 0;i < model->num_tags;i++) + if (!strcmp(tagname, model->data_tags[i].name)) + fields.server->_float = i + 1; + if (fields.server->_float == 0) + MsgDev("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i (model \"%s\") but could not find it\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity), model->name); + } + else + MsgDev("setattachment(edict %i, edict %i, string \"%s\"): tried to find tag named \"%s\" on entity %i but it has no model\n", PRVM_NUM_FOR_EDICT(e), PRVM_NUM_FOR_EDICT(tagentity), tagname, tagname, PRVM_NUM_FOR_EDICT(tagentity)); + } +}*/ + +/* +========= +VM_isserver + +float isserver() +========= +*/ +void VM_isserver(void) +{ + VM_SAFEPARMCOUNT(0,VM_serverstate); + + PRVM_G_FLOAT(OFS_RETURN) = (sv.state == ss_game) ? true : false; +} + +/* +========= +VM_clientcount + +float clientcount() +========= +*/ +void VM_clientcount(void) +{ + VM_SAFEPARMCOUNT(0,VM_clientcount); + + PRVM_G_FLOAT(OFS_RETURN) = host.maxclients; +} + +/* +========= +VM_getmousepos + +vector getmousepos() +========= +*/ +void VM_getmousepos(void) +{ + + VM_SAFEPARMCOUNT(0,VM_getmousepos); + + PRVM_G_VECTOR(OFS_RETURN)[0] = mouse_x; + PRVM_G_VECTOR(OFS_RETURN)[1] = mouse_y; + PRVM_G_VECTOR(OFS_RETURN)[2] = 0; +} + +/* +========= +VM_gettime + +float gettime(void) +========= +*/ +void VM_gettime(void) +{ + VM_SAFEPARMCOUNT(0,VM_gettime); + + PRVM_G_FLOAT(OFS_RETURN) = (float) *prog->time; +} + +/* +========= +VM_loadfromdata + +loadfromdata(string data) +========= +*/ +void VM_loadfromdata(void) +{ + VM_SAFEPARMCOUNT(1,VM_loadentsfromfile); + + PRVM_ED_LoadFromFile(PRVM_G_STRING(OFS_PARM0)); +} + +/* +======================== +VM_parseentitydata + +parseentitydata(entity ent, string data) +======================== +*/ +void VM_parseentitydata(void) +{ + edict_t *ent; + const char *data; + + VM_SAFEPARMCOUNT(2, VM_parseentitydata); + + // get edict and test it + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent->priv.ed->free) + PRVM_ERROR ("VM_parseentitydata: %s: Can only set already spawned entities (entity %i is free)!", PRVM_NAME, PRVM_NUM_FOR_EDICT(ent)); + + data = PRVM_G_STRING(OFS_PARM1); + + // parse the opening brace + if (!COM_Parse(&data) || COM_Token()[0] != '{' ) + PRVM_ERROR ("VM_parseentitydata: %s: Couldn't parse entity data:\n%s", PRVM_NAME, data ); + + PRVM_ED_ParseEdict (data, ent); +} + +/* +========= +VM_loadfromfile + +loadfromfile(string file) +========= +*/ +void VM_loadfromfile(void) +{ + const char *filename; + char *data; + + VM_SAFEPARMCOUNT(1,VM_loadfromfile); + + filename = PRVM_G_STRING(OFS_PARM0); + // .. is parent directory on many platforms + // / is parent directory on Amiga + // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea) + // \ is a windows-ism (so it's naughty to use it, / works on all platforms) + if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\')) + { + PRVM_G_FLOAT(OFS_RETURN) = -4; + VM_Warning("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename); + return; + } + + // not conform with VM_fopen + data = (char *)FS_LoadFile(filename, NULL); + if (data == NULL) PRVM_G_FLOAT(OFS_RETURN) = -1; + PRVM_ED_LoadFromFile(data); +} + + +/* +========= +VM_modulo + +float mod(float val, float m) +========= +*/ +void VM_modulo(void) +{ + int val, m; + VM_SAFEPARMCOUNT(2,VM_module); + + val = (int) PRVM_G_FLOAT(OFS_PARM0); + m = (int) PRVM_G_FLOAT(OFS_PARM1); + + PRVM_G_FLOAT(OFS_RETURN) = (float) (val % m); +} + +void VM_Search_Init(void) +{ + int i; + for (i = 0;i < PRVM_MAX_OPENSEARCHES;i++) + prog->opensearches[i] = NULL; +} + +void VM_Search_Reset(void) +{ + int i; + // reset the fssearch list + for(i = 0; i < PRVM_MAX_OPENSEARCHES; i++) + { + if(prog->opensearches[i]) + Mem_Free(prog->opensearches[i]); + prog->opensearches[i] = NULL; + } +} + +/* +========= +VM_search_begin + +float search_begin(string pattern, float caseinsensitive, float quiet) +========= +*/ +void VM_search_begin(void) +{ + int handle; + const char *pattern; + int caseinsens, quiet; + + VM_SAFEPARMCOUNT(3, VM_search_begin); + + pattern = PRVM_G_STRING(OFS_PARM0); + + VM_CheckEmptyString(pattern); + + caseinsens = (int)PRVM_G_FLOAT(OFS_PARM1); + quiet = (int)PRVM_G_FLOAT(OFS_PARM2); + + for(handle = 0; handle < PRVM_MAX_OPENSEARCHES; handle++) + if(!prog->opensearches[handle]) + break; + + if(handle >= PRVM_MAX_OPENSEARCHES) + { + PRVM_G_FLOAT(OFS_RETURN) = -2; + VM_Warning("VM_search_begin: %s ran out of search handles (%i)\n", PRVM_NAME, PRVM_MAX_OPENSEARCHES); + return; + } + + if(!(prog->opensearches[handle] = FS_Search(pattern))) + PRVM_G_FLOAT(OFS_RETURN) = -1; + else + PRVM_G_FLOAT(OFS_RETURN) = handle; +} + +/* +========= +VM_search_end + +void search_end(float handle) +========= +*/ +void VM_search_end(void) +{ + int handle; + VM_SAFEPARMCOUNT(1, VM_search_end); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning("VM_search_end: invalid handle %i used in %s\n", handle, PRVM_NAME); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning("VM_search_end: no such handle %i in %s\n", handle, PRVM_NAME); + return; + } + + Mem_Free(prog->opensearches[handle]); + prog->opensearches[handle] = NULL; +} + +/* +========= +VM_search_getsize + +float search_getsize(float handle) +========= +*/ +void VM_search_getsize(void) +{ + int handle; + VM_SAFEPARMCOUNT(1, VM_M_search_getsize); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning("VM_search_getsize: invalid handle %i used in %s\n", handle, PRVM_NAME); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning("VM_search_getsize: no such handle %i in %s\n", handle, PRVM_NAME); + return; + } + + PRVM_G_FLOAT(OFS_RETURN) = prog->opensearches[handle]->numfilenames; +} + +/* +========= +VM_search_getfilename + +string search_getfilename(float handle, float num) +========= +*/ +void VM_search_getfilename(void) +{ + int handle, filenum; + char *tmp; + VM_SAFEPARMCOUNT(2, VM_search_getfilename); + + handle = (int)PRVM_G_FLOAT(OFS_PARM0); + filenum = (int)PRVM_G_FLOAT(OFS_PARM1); + + if(handle < 0 || handle >= PRVM_MAX_OPENSEARCHES) + { + VM_Warning("VM_search_getfilename: invalid handle %i used in %s\n", handle, PRVM_NAME); + return; + } + if(prog->opensearches[handle] == NULL) + { + VM_Warning("VM_search_getfilename: no such handle %i in %s\n", handle, PRVM_NAME); + return; + } + if(filenum < 0 || filenum >= prog->opensearches[handle]->numfilenames) + { + VM_Warning("VM_search_getfilename: invalid filenum %i in %s\n", filenum, PRVM_NAME); + return; + } + + tmp = VM_GetTempString(); + strncpy(tmp, prog->opensearches[handle]->filenames[filenum], VM_STRINGTEMP_LENGTH); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); +} + +/* +========= +VM_chr + +string chr(float ascii) +========= +*/ +void VM_chr(void) +{ + char *tmp; + VM_SAFEPARMCOUNT(1, VM_chr); + + tmp = VM_GetTempString(); + tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0); + tmp[1] = 0; + + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); +} + +//============================================================================= +// Draw builtins (client & menu) + +/* +========= +VM_iscachedpic + +float iscachedpic(string pic) +========= +*/ +void VM_iscachedpic(void) +{ + VM_SAFEPARMCOUNT(1,VM_iscachedpic); + + // drawq hasnt such a function, thus always return true + PRVM_G_FLOAT(OFS_RETURN) = false; +} + +/* +========= +VM_precache_pic + +string precache_pic(string pic) +========= +*/ +void VM_precache_pic(void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1, VM_precache_pic); + + s = PRVM_G_STRING(OFS_PARM0); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); + + if(!s) PRVM_ERROR ("VM_precache_pic: %s: NULL", PRVM_NAME); + + VM_CheckEmptyString (s); + + re->RegisterPic((char *)s); //may return empty frame +} + +/* +========= +VM_freepic + +freepic(string s) +========= +*/ +void VM_freepic(void) +{ + const char *s; + + VM_SAFEPARMCOUNT(1,VM_freepic); + + s = PRVM_G_STRING(OFS_PARM0); + + if(!s) + PRVM_ERROR ("VM_freepic: %s: NULL"); + + VM_CheckEmptyString (s); + + // this does nothing +} + +/* +========= +VM_drawcharacter + +float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawcharacter(void) +{ + float *pos, *scale, *rgb; + char character; + int flag; + VM_SAFEPARMCOUNT(6,VM_drawcharacter); + + character = (char) PRVM_G_FLOAT(OFS_PARM1); + if(character == 0) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning("VM_drawcharacter: %s passed null character !\n",PRVM_NAME); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + scale = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + flag = (int)PRVM_G_FLOAT(OFS_PARM5); + + re->DrawChar( pos[0], pos[1], character ); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawstring + +float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawstring(void) +{ + float *pos,*scale,*rgb; + const char *string; + int flag; + VM_SAFEPARMCOUNT(6,VM_drawstring); + + string = PRVM_G_STRING(OFS_PARM1); + if(!string) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning("VM_drawstring: %s passed null string !\n",PRVM_NAME); + return; + } + + pos = PRVM_G_VECTOR(OFS_PARM0); + scale = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + flag = (int)PRVM_G_FLOAT(OFS_PARM5); + + re->DrawString( pos[0], pos[1], (char *)string ); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} +/* +========= +VM_drawpic + +float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawpic(void) +{ + const char *picname; + float *size, *pos, *rgb; + int flag; + + VM_SAFEPARMCOUNT(6,VM_drawpic); + + picname = PRVM_G_STRING(OFS_PARM1); + + if(!picname) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning("VM_drawpic: %s passed null picture name !\n", PRVM_NAME); + return; + } + + VM_CheckEmptyString (picname); + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM2); + rgb = PRVM_G_VECTOR(OFS_PARM3); + flag = (int) PRVM_G_FLOAT(OFS_PARM5); + + re->DrawPic( pos[0], pos[1], (char *)picname ); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_drawfill + +float drawfill(vector position, vector size, vector rgb, float alpha, float flag) +========= +*/ +void VM_drawfill(void) +{ + float *size, *pos, *rgb; + int flag, color; + + VM_SAFEPARMCOUNT(5,VM_drawfill); + + + pos = PRVM_G_VECTOR(OFS_PARM0); + size = PRVM_G_VECTOR(OFS_PARM1); + rgb = PRVM_G_VECTOR(OFS_PARM2); + flag = (int) PRVM_G_FLOAT(OFS_PARM4); + + color = VectorLength( rgb ); //stupid hack + + re->DrawFill( pos[0], pos[1], size[0], size[1], color ); + PRVM_G_FLOAT(OFS_RETURN) = 1; +} + +/* +========= +VM_keynumtostring + +string keynumtostring(float keynum) +========= +*/ +void VM_keynumtostring (void) +{ + int keynum; + char *tmp; + VM_SAFEPARMCOUNT(1, VM_keynumtostring); + + keynum = (int)PRVM_G_FLOAT(OFS_PARM0); + + tmp = VM_GetTempString(); + + strncpy(tmp, Key_KeynumToString(keynum), VM_STRINGTEMP_LENGTH); + + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp); +} + +/* +========= +VM_stringtokeynum + +float stringtokeynum(string key) +========= +*/ +void VM_stringtokeynum (void) +{ + const char *str; + VM_SAFEPARMCOUNT( 1, VM_keynumtostring ); + + str = PRVM_G_STRING( OFS_PARM0 ); + + PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum( (char *)str ); +} + +/* +============== +VM_vectorvectors + +Writes new values for v_forward, v_up, and v_right based on the given forward vector +vectorvectors(vector, vector) +============== +*/ +void VM_vectorvectors (void) +{ + DotProduct(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward); + VectorVectors(prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); +} + +// float(float number, float quantity) bitshift (EXT_BITSHIFT) +void VM_bitshift (void) +{ + int n1, n2; + VM_SAFEPARMCOUNT(2, VM_bitshift); + + n1 = (int)fabs((int)PRVM_G_FLOAT(OFS_PARM0)); + n2 = (int)PRVM_G_FLOAT(OFS_PARM1); + if(!n1) + PRVM_G_FLOAT(OFS_RETURN) = n1; + else + if(n2 < 0) + PRVM_G_FLOAT(OFS_RETURN) = (n1 >> -n2); + else + PRVM_G_FLOAT(OFS_RETURN) = (n1 << n2); +} + +//////////////////////////////////////// +// AltString functions +//////////////////////////////////////// + +/* +======================== +VM_altstr_count + +float altstr_count(string) +======================== +*/ +void VM_altstr_count( void ) +{ + const char *altstr, *pos; + int count; + + VM_SAFEPARMCOUNT( 1, VM_altstr_count ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + //VM_CheckEmptyString( altstr ); + + for( count = 0, pos = altstr ; *pos ; pos++ ) { + if( *pos == '\\' ) { + if( !*++pos ) { + break; + } + } else if( *pos == '\'' ) { + count++; + } + } + + PRVM_G_FLOAT( OFS_RETURN ) = (float) (count / 2); +} + +/* +======================== +VM_altstr_prepare + +string altstr_prepare(string) +======================== +*/ +void VM_altstr_prepare( void ) +{ + char *outstr, *out; + const char *instr, *in; + int size; + + VM_SAFEPARMCOUNT( 1, VM_altstr_prepare ); + + instr = PRVM_G_STRING( OFS_PARM0 ); + //VM_CheckEmptyString( instr ); + outstr = VM_GetTempString(); + + for( out = outstr, in = instr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *in ; size--, in++, out++ ) + if( *in == '\'' ) { + *out++ = '\\'; + *out = '\''; + size--; + } else + *out = *in; + *out = 0; + + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); +} + +/* +======================== +VM_altstr_get + +string altstr_get(string, float) +======================== +*/ +void VM_altstr_get( void ) +{ + const char *altstr, *pos; + char *outstr, *out; + int count, size; + + VM_SAFEPARMCOUNT( 2, VM_altstr_get ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + //VM_CheckEmptyString( altstr ); + + count = (int)PRVM_G_FLOAT( OFS_PARM1 ); + count = count * 2 + 1; + + for( pos = altstr ; *pos && count ; pos++ ) + if( *pos == '\\' ) { + if( !*++pos ) + break; + } else if( *pos == '\'' ) + count--; + + if( !*pos ) { + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); + return; + } + + outstr = VM_GetTempString(); + for( out = outstr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *pos ; size--, pos++, out++ ) + if( *pos == '\\' ) { + if( !*++pos ) + break; + *out = *pos; + size--; + } else if( *pos == '\'' ) + break; + else + *out = *pos; + + *out = 0; + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); +} + +/* +======================== +VM_altstr_set + +string altstr_set(string altstr, float num, string set) +======================== +*/ +void VM_altstr_set( void ) +{ + int num; + const char *altstr, *str; + const char *in; + char *outstr, *out; + + VM_SAFEPARMCOUNT( 3, VM_altstr_set ); + + altstr = PRVM_G_STRING( OFS_PARM0 ); + //VM_CheckEmptyString( altstr ); + + num = (int)PRVM_G_FLOAT( OFS_PARM1 ); + + str = PRVM_G_STRING( OFS_PARM2 ); + //VM_CheckEmptyString( str ); + + outstr = out = VM_GetTempString(); + for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ ) + if( *in == '\\' ) { + if( !*++in ) { + break; + } + } else if( *in == '\'' ) { + num--; + } + + if( !in ) { + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( altstr ); + return; + } + // copy set in + for( ; *str; *out++ = *str++ ); + // now jump over the old content + for( ; *in ; in++ ) + if( *in == '\'' || (*in == '\\' && !*++in) ) + break; + + if( !in ) { + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL ); + return; + } + + strncpy(out, in, VM_STRINGTEMP_LENGTH); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); +} + +/* +======================== +VM_altstr_ins +insert after num +string altstr_ins(string altstr, float num, string set) +======================== +*/ +void VM_altstr_ins(void) +{ + int num; + const char *setstr; + const char *set; + const char *instr; + const char *in; + char *outstr; + char *out; + + in = instr = PRVM_G_STRING( OFS_PARM0 ); + num = (int)PRVM_G_FLOAT( OFS_PARM1 ); + set = setstr = PRVM_G_STRING( OFS_PARM2 ); + + out = outstr = VM_GetTempString(); + for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ ) + if( *in == '\\' ) { + if( !*++in ) { + break; + } + } else if( *in == '\'' ) { + num--; + } + + *out++ = '\''; + for( ; *set ; *out++ = *set++ ); + *out++ = '\''; + + strncpy(out, in, VM_STRINGTEMP_LENGTH); + PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr ); +} + + +//////////////////////////////////////// +// BufString functions +//////////////////////////////////////// +//[515]: string buffers support +#define MAX_QCSTR_BUFFERS 128 +#define MAX_QCSTR_STRINGS 1024 + +typedef struct +{ + int num_strings; + char *strings[MAX_QCSTR_STRINGS]; +}qcstrbuffer_t; + +static qcstrbuffer_t *qcstringbuffers[MAX_QCSTR_BUFFERS]; +static int num_qcstringbuffers; +static int buf_sortpower; + +#define BUFSTR_BUFFER(a) (a>=MAX_QCSTR_BUFFERS) ? NULL : (qcstringbuffers[a]) +#define BUFSTR_ISFREE(a) (anum_strings<=0) ? 1 : 0 + +static int BufStr_FindFreeBuffer (void) +{ + int i; + if(num_qcstringbuffers == MAX_QCSTR_BUFFERS) + return -1; + for(i=0;inum_strings > 0) + { + for(i=0;inum_strings;i++) + if(b->strings[i]) + Z_Free(b->strings[i]); + num_qcstringbuffers--; + } + Z_Free(qcstringbuffers[index]); + qcstringbuffers[index] = NULL; + } +} + +static int BufStr_FindFreeString (qcstrbuffer_t *b) +{ + int i; + for(i=0;inum_strings;i++) + if(!b->strings[i] || !b->strings[i][0]) + return i; + if(i == MAX_QCSTR_STRINGS) return -1; + else return i; +} + +static int BufStr_SortStringsUP (const void *in1, const void *in2) +{ + const char *a, *b; + a = *((const char **) in1); + b = *((const char **) in2); + if(!a[0]) return 1; + if(!b[0]) return -1; + return strncmp(a, b, buf_sortpower); +} + +static int BufStr_SortStringsDOWN (const void *in1, const void *in2) +{ + const char *a, *b; + a = *((const char **) in1); + b = *((const char **) in2); + if(!a[0]) return 1; + if(!b[0]) return -1; + return strncmp(b, a, buf_sortpower); +} + +#ifdef REMOVETHIS +static void VM_BufStr_Init (void) +{ + memset(qcstringbuffers, 0, sizeof(qcstringbuffers)); + num_qcstringbuffers = 0; +} + +static void VM_BufStr_ShutDown (void) +{ + int i; + for(i=0;i= 0) + num_qcstringbuffers++; + //else + //Msg("VM_buf_create: buffers overflow in %s\n", PRVM_NAME); + PRVM_G_FLOAT(OFS_RETURN) = i; +} + +/* +======================== +VM_buf_del +deletes buffer and all strings in it +void buf_del(float bufhandle) = #461; +======================== +*/ +void VM_buf_del (void) +{ + VM_SAFEPARMCOUNT(1, VM_buf_del); + if(BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0))) + BufStr_ClearBuffer((int)PRVM_G_FLOAT(OFS_PARM0)); + else + { + VM_Warning("VM_buf_del: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } +} + +/* +======================== +VM_buf_getsize +how many strings are stored in buffer +float buf_getsize(float bufhandle) = #462; +======================== +*/ +void VM_buf_getsize (void) +{ + qcstrbuffer_t *b; + VM_SAFEPARMCOUNT(1, VM_buf_getsize); + + b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + if(!b) + { + PRVM_G_FLOAT(OFS_RETURN) = -1; + VM_Warning("VM_buf_getsize: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + else + PRVM_G_FLOAT(OFS_RETURN) = b->num_strings; +} + +/* +======================== +VM_buf_copy +copy all content from one buffer to another, make sure it exists +void buf_copy(float bufhandle_from, float bufhandle_to) = #463; +======================== +*/ +void VM_buf_copy (void) +{ + qcstrbuffer_t *b1, *b2; + int i; + VM_SAFEPARMCOUNT(2, VM_buf_copy); + + b1 = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + if(!b1) + { + VM_Warning("VM_buf_copy: invalid source buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + i = (int)PRVM_G_FLOAT(OFS_PARM1); + if(i == (int)PRVM_G_FLOAT(OFS_PARM0)) + { + VM_Warning("VM_buf_copy: source == destination (%i) in %s\n", i, PRVM_NAME); + return; + } + b2 = BUFSTR_BUFFER(i); + if(!b2) + { + VM_Warning("VM_buf_copy: invalid destination buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), PRVM_NAME); + return; + } + + BufStr_ClearBuffer(i); + qcstringbuffers[i] = (qcstrbuffer_t *)Z_Malloc(sizeof(qcstrbuffer_t)); + memset(qcstringbuffers[i], 0, sizeof(qcstrbuffer_t)); + b2->num_strings = b1->num_strings; + + for(i=0;inum_strings;i++) + if(b1->strings[i] && b1->strings[i][0]) + { + size_t stringlen; + stringlen = strlen(b1->strings[i]) + 1; + b2->strings[i] = (char *)Z_Malloc(stringlen); + if(!b2->strings[i]) + { + VM_Warning("VM_buf_copy: not enough memory for buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM1), PRVM_NAME); + break; + } + memcpy(b2->strings[i], b1->strings[i], stringlen); + } +} + +/* +======================== +VM_buf_sort +sort buffer by beginnings of strings (sortpower defaults it's lenght) +"backward == TRUE" means that sorting goes upside-down +void buf_sort(float bufhandle, float sortpower, float backward) = #464; +======================== +*/ +void VM_buf_sort (void) +{ + qcstrbuffer_t *b; + int i; + VM_SAFEPARMCOUNT(3, VM_buf_sort); + + b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + if(!b) + { + VM_Warning("VM_buf_sort: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + if(b->num_strings <= 0) + { + VM_Warning("VM_buf_sort: tried to sort empty buffer %i in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + buf_sortpower = (int)PRVM_G_FLOAT(OFS_PARM1); + if(buf_sortpower <= 0) + buf_sortpower = 99999999; + + if(!PRVM_G_FLOAT(OFS_PARM2)) + qsort(b->strings, b->num_strings, sizeof(char*), BufStr_SortStringsUP); + else + qsort(b->strings, b->num_strings, sizeof(char*), BufStr_SortStringsDOWN); + + for(i=b->num_strings-1;i>=0;i--) //[515]: delete empty lines + if(b->strings) + { + if(b->strings[i][0]) + break; + else + { + Z_Free(b->strings[i]); + --b->num_strings; + b->strings[i] = NULL; + } + } + else + --b->num_strings; +} + +/* +======================== +VM_buf_implode +concantenates all buffer string into one with "glue" separator and returns it as tempstring +string buf_implode(float bufhandle, string glue) = #465; +======================== +*/ +void VM_buf_implode (void) +{ + qcstrbuffer_t *b; + char *k; + const char *sep; + int i; + size_t l; + VM_SAFEPARMCOUNT(2, VM_buf_implode); + + b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = 0; + if(!b) + { + VM_Warning("VM_buf_implode: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + if(!b->num_strings) + return; + sep = PRVM_G_STRING(OFS_PARM1); + k = VM_GetTempString(); + k[0] = 0; + for(l=i=0;inum_strings;i++) + if(b->strings[i]) + { + l += strlen(b->strings[i]); + if(l>=4095) + break; + strncat(k, b->strings[i], VM_STRINGTEMP_LENGTH); + if(sep && (i != b->num_strings-1)) + { + l += strlen(sep); + if(l>=4095) + break; + strncat(k, sep, VM_STRINGTEMP_LENGTH); + } + } + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(k); +} + +/* +======================== +VM_bufstr_get +get a string from buffer, returns direct pointer, dont str_unzone it! +string bufstr_get(float bufhandle, float string_index) = #465; +======================== +*/ +void VM_bufstr_get (void) +{ + qcstrbuffer_t *b; + int strindex; + VM_SAFEPARMCOUNT(2, VM_bufstr_get); + + b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + if(!b) + { + VM_Warning("VM_bufstr_get: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + strindex = (int)PRVM_G_FLOAT(OFS_PARM1); + if(strindex < 0 || strindex > MAX_QCSTR_STRINGS) + { + VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME); + return; + } + PRVM_G_INT(OFS_RETURN) = 0; + if(b->num_strings <= strindex) + return; + if(b->strings[strindex]) + PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(b->strings[strindex]); +} + +/* +======================== +VM_bufstr_set +copies a string into selected slot of buffer +void bufstr_set(float bufhandle, float string_index, string str) = #466; +======================== +*/ +void VM_bufstr_set (void) +{ + int bufindex, strindex; + qcstrbuffer_t *b; + const char *news; + size_t alloclen; + + VM_SAFEPARMCOUNT(3, VM_bufstr_set); + + bufindex = (int)PRVM_G_FLOAT(OFS_PARM0); + b = BUFSTR_BUFFER(bufindex); + if(!b) + { + VM_Warning("VM_bufstr_set: invalid buffer %i used in %s\n", bufindex, PRVM_NAME); + return; + } + strindex = (int)PRVM_G_FLOAT(OFS_PARM1); + if(strindex < 0 || strindex > MAX_QCSTR_STRINGS) + { + VM_Warning("VM_bufstr_set: invalid string index %i used in %s\n", strindex, PRVM_NAME); + return; + } + news = PRVM_G_STRING(OFS_PARM2); + if(!news) + { + VM_Warning("VM_bufstr_set: null string used in %s\n", PRVM_NAME); + return; + } + if(b->strings[strindex]) + Z_Free(b->strings[strindex]); + alloclen = strlen(news) + 1; + b->strings[strindex] = (char *)Z_Malloc(alloclen); + memcpy(b->strings[strindex], news, alloclen); +} + +/* +======================== +VM_bufstr_add +adds string to buffer in nearest free slot and returns it +"order == TRUE" means that string will be added after last "full" slot +float bufstr_add(float bufhandle, string str, float order) = #467; +======================== +*/ +void VM_bufstr_add (void) +{ + int bufindex, order, strindex; + qcstrbuffer_t *b; + const char *string; + size_t alloclen; + + VM_SAFEPARMCOUNT(3, VM_bufstr_add); + + bufindex = (int)PRVM_G_FLOAT(OFS_PARM0); + b = BUFSTR_BUFFER(bufindex); + PRVM_G_FLOAT(OFS_RETURN) = -1; + if(!b) + { + VM_Warning("VM_bufstr_add: invalid buffer %i used in %s\n", bufindex, PRVM_NAME); + return; + } + string = PRVM_G_STRING(OFS_PARM1); + if(!string) + { + VM_Warning("VM_bufstr_add: null string used in %s\n", PRVM_NAME); + return; + } + + order = (int)PRVM_G_FLOAT(OFS_PARM2); + if(order) + strindex = b->num_strings; + else + { + strindex = BufStr_FindFreeString(b); + if(strindex < 0) + { + VM_Warning("VM_bufstr_add: buffer %i has no free string slots in %s\n", bufindex, PRVM_NAME); + return; + } + } + + while(b->num_strings <= strindex) + { + if(b->num_strings == MAX_QCSTR_STRINGS) + { + VM_Warning("VM_bufstr_add: buffer %i has no free string slots in %s\n", bufindex, PRVM_NAME); + return; + } + b->strings[b->num_strings] = NULL; + b->num_strings++; + } + if(b->strings[strindex]) + Z_Free(b->strings[strindex]); + alloclen = strlen(string) + 1; + b->strings[strindex] = (char *)Z_Malloc(alloclen); + memcpy(b->strings[strindex], string, alloclen); + PRVM_G_FLOAT(OFS_RETURN) = strindex; +} + +/* +======================== +VM_bufstr_free +delete string from buffer +void bufstr_free(float bufhandle, float string_index) = #468; +======================== +*/ +void VM_bufstr_free (void) +{ + int i; + qcstrbuffer_t *b; + VM_SAFEPARMCOUNT(2, VM_bufstr_free); + + b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0)); + if(!b) + { + VM_Warning("VM_bufstr_free: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME); + return; + } + i = (int)PRVM_G_FLOAT(OFS_PARM1); + if(i < 0 || i > MAX_QCSTR_STRINGS) + { + VM_Warning("VM_bufstr_free: invalid string index %i used in %s\n", i, PRVM_NAME); + return; + } + if(b->strings[i]) + Z_Free(b->strings[i]); + b->strings[i] = NULL; + if(i+1 == b->num_strings) + --b->num_strings; +} + +//============= + +void VM_Cmd_Init(void) +{ + // only init the stuff for the current prog + VM_Files_Init(); + VM_Search_Init(); +} + +void VM_Cmd_Reset(void) +{ + VM_Search_Reset(); + VM_Files_CloseAll(); +} + diff --git a/engine/common/vm_cmds.h b/engine/common/vm_cmds.h new file mode 100644 index 00000000..1d74e23a --- /dev/null +++ b/engine/common/vm_cmds.h @@ -0,0 +1,343 @@ +// AK +// Basically every vm builtin cmd should be in here. +// All 3 builtin and extension lists can be found here +// cause large (I think they will) parts are from pr_cmds the same copyright like in pr_cmds +// also applies here + + +/* +============================================================================ +common cmd list: +================= + + checkextension(string) + error(...[string]) + objerror(...[string) + print(...[strings]) + bprint(...[string]) + sprint(float clientnum,...[string]) + centerprint(...[string]) +vector normalize(vector) +float vlen(vector) +float vectoyaw(vector) +vector vectoangles(vector) +float random() + cmd(string) + float cvar (string) + cvar_set (string,string) + dprint(...[string]) +string ftos(float) +float fabs(float) +string vtos(vector) +string etos(entity) +float stof(...[string]) +entity spawn() + remove(entity e) +entity find(entity start, .string field, string match) + +entity findfloat(entity start, .float field, float match) +entity findentity(entity start, .entity field, entity match) + +entity findchain(.string field, string match) + +entity findchainfloat(.string field, float match) +entity findchainentity(.string field, entity match) + +string precache_file(string) +string precache_sound (string sample) + coredump() + traceon() + traceoff() + eprint(entity e) +float rint(float) +float floor(float) +float ceil(float) +entity nextent(entity) +float sin(float) +float cos(float) +float sqrt(float) +vector randomvec() +float registercvar (string name, string value, float flags) +float min(float a, float b, ...[float]) +float max(float a, float b, ...[float]) +float bound(float min, float value, float max) +float pow(float a, float b) + copyentity(entity src, entity dst) +float fopen(string filename, float mode) + fclose(float fhandle) +string fgets(float fhandle) + fputs(float fhandle, string s) +float strlen(string s) +string strcat(string,string,...[string]) +string substring(string s, float start, float length) +vector stov(string s) +string strzone(string s) + strunzone(string s) +float tokenize(string s) +string argv(float n) +float isserver() +float clientcount() +float clientstate() + clientcommand(float client, string s) (for client and menu) + changelevel(string map) + localsound(string sample) +vector getmousepos() +float gettime() + loadfromdata(string data) + loadfromfile(string file) + parseentitydata(entity ent, string data) +float mod(float val, float m) +const string cvar_string (string) + crash() + stackdump() + +float search_begin(string pattern, float caseinsensitive, float quiet) +void search_end(float handle) +float search_getsize(float handle) +string search_getfilename(float handle, float num) + +string chr(float ascii) + +float itof(intt ent) +entity ftoe(float num) + +-------will be removed soon---------- +float altstr_count(string) +string altstr_prepare(string) +string altstr_get(string,float) +string altstr_set(string altstr, float num, string set) +string altstr_ins(string altstr, float num, string set) +-------------------------------------- + +entity findflags(entity start, .float field, float match) +entity findchainflags(.float field, float match) + +perhaps only : Menu : WriteMsg +=============================== + + WriteByte(float data, float dest, float desto) + WriteChar(float data, float dest, float desto) + WriteShort(float data, float dest, float desto) + WriteLong(float data, float dest, float desto) + WriteAngle(float data, float dest, float desto) + WriteCoord(float data, float dest, float desto) + WriteString(string data, float dest, float desto) + WriteEntity(entity data, float dest, float desto) + +Client & Menu : draw functions & video functions +=================================================== + +float iscachedpic(string pic) +string precache_pic(string pic) + freepic(string s) +float drawcharacter(vector position, float character, vector scale, vector rgb, float alpha, float flag) +float drawstring(vector position, string text, vector scale, vector rgb, float alpha, float flag) +float drawpic(vector position, string pic, vector size, vector rgb, float alpha, float flag) +float drawfill(vector position, vector size, vector rgb, float alpha, float flag) + +============================================================================== +menu cmd list: +=============== + + setkeydest(float dest) +float getkeydest() + setmousetarget(float target) +float getmousetarget() + + callfunction(...,string function_name) + writetofile(float fhandle, entity ent) +float isfunction(string function_name) +vector getresolution(float number) +string keynumtostring(float keynum) +string findkeysforcommand(string command) +float getserverliststat(float type) +string getserverliststring(float fld, float hostnr) + +float stringtokeynum(string key) + + resetserverlistmasks() + setserverlistmaskstring(float mask, float fld, string str) + setserverlistmasknumber(float mask, float fld, float num, float op) + resortserverlist() + setserverlistsort(float field, float descending) + refreshserverlist() +float getserverlistnumber(float fld, float hostnr) +float getserverlistindexforkey(string key) + addwantedserverlistkey(string key) +*/ + +#include "engine.h" +#include "server.h" +#include "progdefs.h" +#include "progsvm.h" + +//============================================================================ +// nice helper macros + +#ifndef VM_NOPARMCHECK +#define VM_SAFEPARMCOUNT(p,f) if(prog->argc != p) PRVM_ERROR(#f " wrong parameter count (" #p " expected ) !") +#else +#define VM_SAFEPARMCOUNT(p,f) +#endif + +#define VM_RETURN_EDICT(e) (((int *)prog->globals.generic)[OFS_RETURN] = PRVM_EDICT_TO_PROG(e)) + +#define e10 NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL +#define e100 e10,e10,e10,e10,e10,e10,e10,e10,e10,e10 +#define e1000 e100,e100,e100,e100,e100,e100,e100,e100,e100,e100 + +#define VM_STRINGTEMP_BUFFERS 16 +#define VM_STRINGTEMP_LENGTH MAX_INPUTLINE + +// builtins and other general functions + +char *VM_GetTempString(void); +void VM_CheckEmptyString (const char *s); +void VM_VarString(int first, char *out, int outlength); + +void VM_checkextension (void); +void VM_error (void); +void VM_objerror (void); +void VM_print (void); +void VM_bprint (void); +void VM_sprint (void); +void VM_centerprint (void); +void VM_normalize (void); +void VM_vlen (void); +void VM_vectoyaw (void); +void VM_vectoangles (void); +void VM_random (void); +void VM_localsound(void); +void VM_break (void); +void VM_localcmd (void); +void VM_cvar (void); +void VM_cvar_string(void); +void VM_cvar_set (void); +void VM_dprint (void); +void VM_ftos (void); +void VM_fabs (void); +void VM_vtos (void); +void VM_etos (void); +void VM_stof(void); +void VM_itof(void); +void VM_ftoe(void); +void VM_spawn (void); +void VM_remove (void); +void VM_find (void); +void VM_findfloat (void); +void VM_findchain (void); +void VM_findchainfloat (void); +void VM_findflags (void); +void VM_findchainflags (void); +void VM_precache_file (void); +void VM_precache_error (void); +void VM_precache_sound (void); +void VM_coredump (void); + +void VM_stackdump (void); +void VM_crash(void); // REMOVE IT +void VM_traceon (void); +void VM_traceoff (void); +void VM_eprint (void); +void VM_rint (void); +void VM_floor (void); +void VM_ceil (void); +void VM_nextent (void); + +void VM_changelevel (void); +void VM_sin (void); +void VM_cos (void); +void VM_sqrt (void); +void VM_randomvec (void); +void VM_registercvar (void); +void VM_min (void); +void VM_max (void); +void VM_bound (void); +void VM_pow (void); +void VM_copyentity (void); + +void VM_Files_Init(void); +void VM_Files_CloseAll(void); + +void VM_fopen(void); +void VM_fclose(void); +void VM_fgets(void); +void VM_fputs(void); +// used by M_WriteToFile +// should be only called from a builtin +file_t *VM_GetFileHandle( int index ); + +void VM_strlen(void); +void VM_strcat(void); +void VM_substring(void); +void VM_stov(void); +void VM_strzone(void); +void VM_strunzone(void); + +void VM_clcommand (void); + +void VM_tokenize (void); +void VM_argv (void); + +void VM_isserver(void); +void VM_clientcount(void); +void VM_getmousepos(void); +void VM_gettime(void); +void VM_loadfromdata(void); +void VM_parseentitydata(void); +void VM_loadfromfile(void); +void VM_modulo(void); + +void VM_search_begin(void); +void VM_search_end(void); +void VM_search_getsize(void); +void VM_search_getfilename(void); +void VM_chr(void); +void VM_iscachedpic(void); +void VM_precache_pic(void); +void VM_freepic(void); +void VM_drawcharacter(void); +void VM_drawstring(void); +void VM_drawpic(void); +void VM_drawfill(void); +void VM_drawsetcliparea(void); +void VM_drawresetcliparea(void); +void VM_getimagesize(void); + +void VM_vectorvectors (void); + +void VM_keynumtostring (void); +void VM_stringtokeynum (void); + +void VM_cin_open( void ); +void VM_cin_close( void ); +void VM_cin_setstate( void ); +void VM_cin_getstate( void ); +void VM_cin_restart( void ); + +void VM_drawline (void); +void VM_R_PolygonBegin (void); +void VM_R_PolygonVertex (void); +void VM_R_PolygonEnd (void); + +void VM_bitshift (void); + +void VM_altstr_count( void ); +void VM_altstr_prepare( void ); +void VM_altstr_get( void ); +void VM_altstr_set( void ); +void VM_altstr_ins(void); + +void VM_buf_create(void); +void VM_buf_del (void); +void VM_buf_getsize (void); +void VM_buf_copy (void); +void VM_buf_sort (void); +void VM_buf_implode (void); +void VM_bufstr_get (void); +void VM_bufstr_set (void); +void VM_bufstr_add (void); +void VM_bufstr_free (void); + +void VM_Cmd_Init(void); +void VM_Cmd_Reset(void); diff --git a/engine/common/vm_edict.c b/engine/common/vm_edict.c new file mode 100644 index 00000000..d903b8b1 --- /dev/null +++ b/engine/common/vm_edict.c @@ -0,0 +1,1944 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ +// AK new vm + +#include "engine.h" +#include "progsvm.h" + +prvm_prog_t *prog; + +static prvm_prog_t prog_list[PRVM_MAXPROGS]; + +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); + +// LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others)) +cvar_t *prvm_boundscheck; +// LordHavoc: prints every opcode as it executes - warning: this is significant spew +cvar_t *prvm_traceqc; +// LordHavoc: counts usage of each QuakeC statement +cvar_t *prvm_statementprofiling; +//============================================================================ +// mempool handling + +/* +=============== +PRVM_MEM_Alloc +=============== +*/ +void PRVM_MEM_Alloc(void) +{ + int i; + + // reserve space for the null entity aka world + // check bound of max_edicts + prog->max_edicts = bound(1 + prog->reserved_edicts, prog->max_edicts, prog->limit_edicts); + prog->num_edicts = bound(1 + prog->reserved_edicts, prog->num_edicts, prog->max_edicts); + + // edictprivate_size has to be min as big prvm_edict_private_t + prog->edictprivate_size = max(prog->edictprivate_size, (int)sizeof(vm_edict_t)); + + // alloc edicts + prog->edicts = (edict_t *)Mem_Alloc(prog->progs_mempool, prog->limit_edicts * sizeof(edict_t)); + + // alloc edict private space + prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size); + + // alloc edict fields + prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size); + + // set edict pointers + for(i = 0; i < prog->max_edicts; i++) + { + prog->edicts[i].priv.ed = (vm_edict_t *)((byte *)prog->edictprivate + i * prog->edictprivate_size); + prog->edicts[i].progs.vp = (void*)((byte *)prog->edictsfields + i * prog->edict_size); + } +} + +/* +=============== +PRVM_MEM_IncreaseEdicts +=============== +*/ +void PRVM_MEM_IncreaseEdicts(void) +{ + int i; + int oldmaxedicts = prog->max_edicts; + void *oldedictsfields = prog->edictsfields; + void *oldedictprivate = prog->edictprivate; + + if(prog->max_edicts >= prog->limit_edicts) + return; + + PRVM_GCALL(begin_increase_edicts)(); + + // increase edicts + prog->max_edicts = min(prog->max_edicts + 256, prog->limit_edicts); + + prog->edictsfields = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edict_size); + prog->edictprivate = Mem_Alloc(prog->progs_mempool, prog->max_edicts * prog->edictprivate_size); + + memcpy(prog->edictsfields, oldedictsfields, oldmaxedicts * prog->edict_size); + memcpy(prog->edictprivate, oldedictprivate, oldmaxedicts * prog->edictprivate_size); + + //set e and v pointers + for(i = 0; i < prog->max_edicts; i++) + { + prog->edicts[i].priv.ed = (vm_edict_t *)((byte *)prog->edictprivate + i * prog->edictprivate_size); + prog->edicts[i].progs.vp = (void*)((byte *)prog->edictsfields + i * prog->edict_size); + } + + PRVM_GCALL(end_increase_edicts)(); + + Mem_Free(oldedictsfields); + Mem_Free(oldedictprivate); +} + +//============================================================================ +// normal prvm + +int PRVM_ED_FindFieldOffset(const char *field) +{ + ddef_t *d; + d = PRVM_ED_FindField(field); + if (!d) return 0; + return d->ofs * 4; +} + +int PRVM_ED_FindGlobalOffset(const char *global) +{ + ddef_t *d; + d = PRVM_ED_FindGlobal(global); + if (!d) return 0; + return d->ofs * 4; +} + +func_t PRVM_ED_FindFunctionOffset(const char *function) +{ + mfunction_t *f; + f = PRVM_ED_FindFunction(function); + if (!f) + return 0; + return (func_t)(f - prog->functions); +} + +bool PRVM_ProgLoaded(int prognr) +{ + if(prognr < 0 || prognr >= PRVM_MAXPROGS) + return false; + + return (prog_list[prognr].loaded ? true : false); +} + +/* +================= +PRVM_SetProgFromString +================= +*/ +// perhaps add a return value when the str doesnt exist +bool PRVM_SetProgFromString(const char *str) +{ + int i = 0; + for(; i < PRVM_MAXPROGS ; i++) + if(prog_list[i].name && !strcmp(prog_list[i].name,str)) + { + if(prog_list[i].loaded) + { + prog = &prog_list[i]; + return true; + } + else + { + Msg("%s not loaded !\n", PRVM_NAME); + return false; + } + } + + Msg("Invalid program name %s !\n", str); + return false; +} + +/* +================= +PRVM_SetProg +================= +*/ +void PRVM_SetProg(int prognr) +{ + if(0 <= prognr && prognr < PRVM_MAXPROGS) + { + if(prog_list[prognr].loaded) + prog = &prog_list[prognr]; + else + PRVM_ERROR("%i not loaded !", prognr); + return; + } + PRVM_ERROR("Invalid program number %i", prognr); +} + +/* +================= +PRVM_ED_ClearEdict + +Sets everything to NULL +================= +*/ +void PRVM_ED_ClearEdict (edict_t *e) +{ + memset (e->progs.vp, 0, prog->progs->entityfields * 4); + e->priv.ed->free = false; + + // AK: Let the init_edict function determine if something needs to be initialized + PRVM_GCALL(init_edict)(e); +} + +/* +================= +PRVM_ED_Alloc + +Either finds a free edict, or allocates a new one. +Try to avoid reusing an entity that was recently freed, because it +can cause the client to think the entity morphed into something else +instead of being removed and recreated, which can cause interpolated +angles and bad trails. +================= +*/ +edict_t *PRVM_ED_Alloc (void) +{ + int i; + edict_t *e; + + // the client qc dont need maxclients + // thus it doesnt need to use svs.maxclients + // AK: changed i=svs.maxclients+1 + // AK: changed so the edict 0 wont spawn -> used as reserved/world entity + // although the menu/client has no world + for (i = prog->reserved_edicts + 1; i < prog->num_edicts; i++) + { + e = PRVM_EDICT_NUM(i); + // the first couple seconds of server time can involve a lot of + // freeing and allocating, so relax the replacement policy + if (e->priv.ed->free && ( e->priv.ed->freetime < 2 || (*prog->time - e->priv.ed->freetime) > 0.5 ) ) + { + PRVM_ED_ClearEdict (e); + return e; + } + } + + if (i == prog->limit_edicts) + PRVM_ERROR ("%s: PRVM_ED_Alloc: no free edicts",PRVM_NAME); + + prog->num_edicts++; + if (prog->num_edicts >= prog->max_edicts) + PRVM_MEM_IncreaseEdicts(); + + e = PRVM_EDICT_NUM(i); + PRVM_ED_ClearEdict (e); + + return e; +} + +/* +================= +PRVM_ED_Free + +Marks the edict as free +FIXME: walk all entities and NULL out references to this entity +================= +*/ +void PRVM_ED_Free (edict_t *ed) +{ + // dont delete the null entity (world) or reserved edicts + if(PRVM_NUM_FOR_EDICT(ed) <= prog->reserved_edicts ) + return; + + PRVM_GCALL(free_edict)(ed); + + ed->priv.ed->free = true; + ed->priv.ed->freetime = *prog->time; +} + +//=========================================================================== + +/* +============ +PRVM_ED_GlobalAtOfs +============ +*/ +ddef_t *PRVM_ED_GlobalAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; iprogs->numglobaldefs ; i++) + { + def = &prog->globaldefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FieldAtOfs +============ +*/ +ddef_t *PRVM_ED_FieldAtOfs (int ofs) +{ + ddef_t *def; + int i; + + for (i=0 ; iprogs->numfielddefs ; i++) + { + def = &prog->fielddefs[i]; + if (def->ofs == ofs) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FindField +============ +*/ +ddef_t *PRVM_ED_FindField (const char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; iprogs->numfielddefs ; i++) + { + def = &prog->fielddefs[i]; + if (!strcmp(PRVM_GetString(def->s_name), name)) + return def; + } + return NULL; +} + +/* +============ +PRVM_ED_FindGlobal +============ +*/ +ddef_t *PRVM_ED_FindGlobal (const char *name) +{ + ddef_t *def; + int i; + + for (i=0 ; iprogs->numglobaldefs ; i++) + { + def = &prog->globaldefs[i]; + if (!strcmp(PRVM_GetString(def->s_name), name)) + return def; + } + return NULL; +} + + +/* +============ +PRVM_ED_FindFunction +============ +*/ +mfunction_t *PRVM_ED_FindFunction (const char *name) +{ + mfunction_t *func; + int i; + + for (i=0 ; iprogs->numfunctions ; i++) + { + func = &prog->functions[i]; + if (!strcmp(PRVM_GetString(func->s_name), name)) + return func; + } + return NULL; +} + + +/* +============ +PRVM_ValueString + +Returns a string describing *data in a type specific manner +============= +*/ +char *PRVM_ValueString (etype_t type, prvm_eval_t *val) +{ + static char line[MAX_INPUTLINE]; + ddef_t *def; + mfunction_t *f; + int n; + + type = (etype_t)((int) type & ~DEF_SAVEGLOBAL); + + switch (type) + { + case ev_string: + strncpy (line, PRVM_GetString (val->string), sizeof (line)); + break; + case ev_entity: + n = val->edict; + if (n < 0 || n >= prog->limit_edicts) + sprintf (line, "entity %i (invalid!)", n); + else + sprintf (line, "entity %i", n); + break; + case ev_function: + f = prog->functions + val->function; + sprintf (line, "%s()", PRVM_GetString(f->s_name)); + break; + case ev_field: + def = PRVM_ED_FieldAtOfs ( val->_int ); + sprintf (line, ".%s", PRVM_GetString(def->s_name)); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + // LordHavoc: changed from %5.1f to %10.4f + sprintf (line, "%10.4f", val->_float); + break; + case ev_vector: + // LordHavoc: changed from %5.1f to %10.4f + sprintf (line, "'%10.4f %10.4f %10.4f'", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + sprintf (line, "pointer"); + break; + default: + sprintf (line, "bad type %i", (int) type); + break; + } + + return line; +} + +/* +============ +PRVM_UglyValueString + +Returns a string describing *data in a type specific manner +Easier to parse than PR_ValueString +============= +*/ +char *PRVM_UglyValueString (etype_t type, prvm_eval_t *val) +{ + static char line[MAX_INPUTLINE]; + int i; + const char *s; + ddef_t *def; + mfunction_t *f; + + type = (etype_t)((int)type & ~DEF_SAVEGLOBAL); + + switch (type) + { + case ev_string: + // Parse the string a bit to turn special characters + // (like newline, specifically) into escape codes, + // this fixes saving games from various mods + s = PRVM_GetString (val->string); + for (i = 0;i < (int)sizeof(line) - 2 && *s;) + { + if (*s == '\n') + { + line[i++] = '\\'; + line[i++] = 'n'; + } + else if (*s == '\r') + { + line[i++] = '\\'; + line[i++] = 'r'; + } + else + line[i++] = *s; + s++; + } + line[i] = '\0'; + break; + case ev_entity: + sprintf (line, "%i", PRVM_NUM_FOR_EDICT(PRVM_PROG_TO_EDICT(val->edict))); + break; + case ev_function: + f = prog->functions + val->function; + strncpy (line, PRVM_GetString (f->s_name), sizeof (line)); + break; + case ev_field: + def = PRVM_ED_FieldAtOfs ( val->_int ); + sprintf (line, ".%s", PRVM_GetString(def->s_name)); + break; + case ev_void: + sprintf (line, "void"); + break; + case ev_float: + sprintf (line, "%f", val->_float); + break; + case ev_vector: + sprintf (line, "%f %f %f", val->vector[0], val->vector[1], val->vector[2]); + break; + case ev_pointer: + case ev_integer: + case ev_variant: + case ev_struct: + case ev_union: + sprintf (line, "skip new type %i", type); + break; + default: + sprintf (line, "bad type %i", type); + break; + } + + return line; +} + +/* +============ +PRVM_GlobalString + +Returns a string with a description and the contents of a global, +padded to 20 field width +============ +*/ +char *PRVM_GlobalString (int ofs) +{ + char *s; + //size_t i; + ddef_t *def; + void *val; + static char line[128]; + + val = (void *)&prog->globals.generic[ofs]; + def = PRVM_ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"GLOBAL%i", ofs); + else + { + s = PRVM_ValueString ((etype_t)def->type, (prvm_eval_t *)val); + sprintf (line,"%s (=%s)", PRVM_GetString(def->s_name), s); + } + + //i = strlen(line); + //for ( ; i<20 ; i++) + // strcat (line," "); + //strcat (line," "); + + return line; +} + +char *PRVM_GlobalStringNoContents (int ofs) +{ + //size_t i; + ddef_t *def; + static char line[128]; + + def = PRVM_ED_GlobalAtOfs(ofs); + if (!def) + sprintf (line,"GLOBAL%i", ofs); + else + sprintf (line,"%s", PRVM_GetString(def->s_name)); + + //i = strlen(line); + //for ( ; i<20 ; i++) + // strcat (line," "); + //strcat (line," "); + + return line; +} + + +/* +============= +PRVM_ED_Print + +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) +{ + size_t l; + ddef_t *d; + int *v; + int i, j; + const char *name; + int type; + char tempstring[MAX_INPUTLINE], tempstring2[260]; // temporary string buffers + + if (ed->priv.ed->free) + { + Msg("%s: FREE\n",PRVM_NAME); + return; + } + + tempstring[0] = 0; + sprintf(tempstring, "\n%s EDICT %i:\n", PRVM_NAME, PRVM_NUM_FOR_EDICT(ed)); + for (i=1 ; iprogs->numfielddefs ; i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)ed->progs.vp + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + + for (j=0 ; j sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strncat(tempstring, name, sizeof(tempstring)); + for (l = strlen(name);l < 14;l++) + strncat(tempstring, " ", sizeof(tempstring)); + strncat(tempstring, " ", sizeof(tempstring)); + + name = PRVM_ValueString((etype_t)d->type, (prvm_eval_t *)v); + if (strlen(name) > sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strncat(tempstring, name, sizeof(tempstring)); + strncat(tempstring, "\n", sizeof(tempstring)); + if (strlen(tempstring) >= sizeof(tempstring)/2) + { + Con_Print(tempstring); + tempstring[0] = 0; + } + } + if (tempstring[0]) + Con_Print(tempstring); +} + +/* +============= +PRVM_ED_Write + +For savegames +============= +*/ +void PRVM_ED_Write (file_t *f, edict_t *ed) +{ + ddef_t *d; + int *v; + int i, j; + const char *name; + int type; + + FS_Print(f, "{\n"); + + if (ed->priv.ed->free) + { + FS_Print(f, "}\n"); + return; + } + + for (i=1 ; iprogs->numfielddefs ; i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + + v = (int *)((char *)ed->progs.vp + d->ofs*4); + + // if the value is still all 0, skip the field + type = d->type & ~DEF_SAVEGLOBAL; + for (j=0 ; jtype, (prvm_eval_t *)v)); + } + + FS_Print(f, "}\n"); +} + +void PRVM_ED_PrintNum (int ent) +{ + PRVM_ED_Print(PRVM_EDICT_NUM(ent)); +} + +/* +============= +PRVM_ED_PrintEdicts_f + +For debugging, prints all the entities in the current server +============= +*/ +void PRVM_ED_PrintEdicts_f (void) +{ + int i; + + if(Cmd_Argc() != 2) + { + Con_Print("prvm_edicts \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + Msg("%s: %i entities\n", PRVM_NAME, prog->num_edicts); + for (i=0 ; inum_edicts ; i++) + PRVM_ED_PrintNum (i); + + PRVM_End; +} + +/* +============= +PRVM_ED_PrintEdict_f + +For debugging, prints a single edict +============= +*/ +void PRVM_ED_PrintEdict_f (void) +{ + int i; + + if(Cmd_Argc() != 3) + { + Msg("prvm_edict \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) return; + + i = atoi (Cmd_Argv(2)); + if (i >= prog->num_edicts) + { + Msg("Bad edict number\n"); + PRVM_End; + return; + } + PRVM_ED_PrintNum (i); + + PRVM_End; +} + +/* +============= +PRVM_ED_Count + +For debugging +============= +*/ +// 2 possibilities : 1. just displaying the active edict count +// 2. making a function pointer [x] +void PRVM_ED_Count_f (void) +{ + int i; + edict_t *ent; + int active; + + if(Cmd_Argc() != 2) + { + Con_Print("prvm_count \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + if(prog->count_edicts) + prog->count_edicts(); + else + { + active = 0; + for (i=0 ; inum_edicts ; i++) + { + ent = PRVM_EDICT_NUM(i); + if (ent->priv.ed->free) + continue; + active++; + } + + Msg("num_edicts:%3i\n", prog->num_edicts); + Msg("active :%3i\n", active); + } + + PRVM_End; +} + +/* +============================================================================== + + ARCHIVING GLOBALS + +FIXME: need to tag constants, doesn't really work +============================================================================== +*/ + +/* +============= +PRVM_ED_WriteGlobals +============= +*/ +void PRVM_ED_WriteGlobals (file_t *f) +{ + ddef_t *def; + int i; + const char *name; + int type; + + FS_Print(f,"{\n"); + for (i=0 ; iprogs->numglobaldefs ; i++) + { + def = &prog->globaldefs[i]; + type = def->type; + if ( !(def->type & DEF_SAVEGLOBAL) ) + continue; + type &= ~DEF_SAVEGLOBAL; + + if (type != ev_string && type != ev_float && type != ev_entity) + continue; + + name = PRVM_GetString(def->s_name); + FS_Printf(f,"\"%s\" ", name); + FS_Printf(f,"\"%s\"\n", PRVM_UglyValueString((etype_t)type, (prvm_eval_t *)&prog->globals.generic[def->ofs])); + } + FS_Print(f,"}\n"); +} + +/* +============= +PRVM_ED_ParseGlobals +============= +*/ +void PRVM_ED_ParseGlobals (const char *data) +{ + char keyname[MAX_INPUTLINE]; + ddef_t *key; + + while (1) + { + // parse key + if (!COM_Parse(&data)) + PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace"); + if (COM_Token()[0] == '}') + break; + + strncpy (keyname, COM_Token(), sizeof(keyname)); + + // parse value + if (!COM_Parse(&data)) + PRVM_ERROR ("PRVM_ED_ParseGlobals: EOF without closing brace"); + + if (COM_Token()[0] == '}') + PRVM_ERROR ("PRVM_ED_ParseGlobals: closing brace without data"); + + key = PRVM_ED_FindGlobal (keyname); + if (!key) + { + MsgDev(D_INFO, "'%s' is not a global on %s\n", keyname, PRVM_NAME); + continue; + } + + if (!PRVM_ED_ParseEpair(NULL, key, COM_Token())) + PRVM_ERROR ("PRVM_ED_ParseGlobals: parse error"); + } +} + +//============================================================================ + + +/* +============= +PRVM_ED_ParseEval + +Can parse either fields or globals +returns false if error +============= +*/ +bool PRVM_ED_ParseEpair(edict_t *ent, ddef_t *key, const char *s) +{ + int i, l; + char *new_p; + ddef_t *def; + prvm_eval_t *val; + mfunction_t *func; + + if (ent) + val = (prvm_eval_t *)((int *)ent->progs.vp + key->ofs); + else + val = (prvm_eval_t *)((int *)prog->globals.generic + key->ofs); + switch (key->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + l = (int)strlen(s) + 1; + val->string = PRVM_AllocString(l, &new_p); + for (i = 0;i < l;i++) + { + if (s[i] == '\\' && i < l-1) + { + i++; + if (s[i] == 'n') + *new_p++ = '\n'; + else if (s[i] == 'r') + *new_p++ = '\r'; + else + *new_p++ = s[i]; + } + else + *new_p++ = s[i]; + } + break; + + case ev_float: + while (*s && *s <= ' ') + s++; + val->_float = atof(s); + break; + + case ev_vector: + for (i = 0;i < 3;i++) + { + while (*s && *s <= ' ') + s++; + if (!*s) + break; + val->vector[i] = atof(s); + while (*s > ' ') + s++; + if (!*s) + break; + } + break; + + case ev_entity: + while (*s && *s <= ' ') + s++; + i = atoi(s); + if (i >= prog->limit_edicts) + MsgDev(D_WARN, "PRVM_ED_ParseEpair: ev_entity reference too large (edict %u >= MAX_EDICTS %u) on %s\n", (uint)i, (uint)MAX_EDICTS, PRVM_NAME); + while (i >= prog->max_edicts) + PRVM_MEM_IncreaseEdicts(); + // if IncreaseEdicts was called the base pointer needs to be updated + if (ent) val = (prvm_eval_t *)((int *)ent->progs.vp + key->ofs); + val->edict = PRVM_EDICT_TO_PROG(PRVM_EDICT_NUM((int)i)); + break; + + case ev_field: + def = PRVM_ED_FindField(s); + if (!def) + { + MsgDev(D_WARN, "PRVM_ED_ParseEpair: Can't find field %s in %s\n", s, PRVM_NAME); + return false; + } + val->_int = def->ofs; + break; + + case ev_function: + func = PRVM_ED_FindFunction(s); + if (!func) + { + MsgDev(D_WARN, "PRVM_ED_ParseEpair: Can't find function %s in %s\n", s, PRVM_NAME); + return false; + } + val->function = func - prog->functions; + break; + + default: + MsgDev(D_WARN, "PRVM_ED_ParseEpair: Unknown key->type %i for key \"%s\" on %s\n", key->type, PRVM_GetString(key->s_name), PRVM_NAME); + return false; + } + return true; +} + +/* +============= +PRVM_ED_EdictSet_f + +Console command to set a field of a specified edict +============= +*/ +void PRVM_ED_EdictSet_f(void) +{ + edict_t *ed; + ddef_t *key; + + if(Cmd_Argc() != 5) + { + Con_Print("prvm_edictset \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + { + Msg("Wrong program name %s !\n", Cmd_Argv(1)); + return; + } + + ed = PRVM_EDICT_NUM(atoi(Cmd_Argv(2))); + + if((key = PRVM_ED_FindField(Cmd_Argv(3))) == 0) + MsgWarn("Key %s not found !\n", Cmd_Argv(3)); + else PRVM_ED_ParseEpair(ed, key, Cmd_Argv(4)); + + PRVM_End; +} + +/* +==================== +PRVM_ED_ParseEdict + +Parses an edict out of the given string, returning the new position +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) +{ + ddef_t *key; + bool init, newline; + char keyname[256]; + size_t n; + + init = false; + + // go through all the dictionary pairs + while (1) + { + // parse key + if (!COM_Parse(&data)) + PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace"); + + newline = (COM_Token()[0] == '}') ? true : false; + if(!newline) MsgDev(D_INFO, "Key: \"%s\"", COM_Token()); + else break; + + strncpy (keyname, COM_Token(), sizeof(keyname)); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + if (!COM_Parse(&data)) + PRVM_ERROR ("PRVM_ED_ParseEdict: EOF without closing brace"); + MsgDev(D_INFO, " \"%s\"\n", COM_Token()); + + if (COM_Token()[0] == '}') + PRVM_ERROR ("PRVM_ED_ParseEdict: closing brace without data"); + + init = true; + + // ignore attempts to set key "" (this problem occurs in nehahra neh1m8.bsp) + if (!keyname[0]) + continue; + + // keynames with a leading underscore are used for utility comments, + // and are immediately discarded by quake + if (keyname[0] == '_') continue; + + key = PRVM_ED_FindField (keyname); + if (!key) + { + MsgDev(D_INFO, "%s: '%s' is not a field\n", PRVM_NAME, keyname); + continue; + } + + if (!PRVM_ED_ParseEpair(ent, key, COM_Token())) + PRVM_ERROR ("PRVM_ED_ParseEdict: parse error"); + } + + if (!init) ent->priv.ed->free = true; + + return data; +} + + +/* +================ +PRVM_ED_LoadFromFile + +The entities are directly placed in the array, rather than allocated with +PRVM_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. + +Used for both fresh maps and savegame loads. A fresh map would also need +to call PRVM_ED_CallSpawnFunctions () to let the objects initialize themselves. +================ +*/ +void PRVM_ED_LoadFromFile (const char *data) +{ + edict_t *ent; + int parsed, inhibited, spawned, died; + mfunction_t *func; + + parsed = 0; + inhibited = 0; + spawned = 0; + died = 0; + + + // parse ents + while (1) + { + // parse the opening brace + if (!COM_Parse(&data)) break; + if (COM_Token()[0] != '{') + PRVM_ERROR ("PRVM_ED_LoadFromFile: %s: found %s when expecting {", PRVM_NAME, COM_Token()); + + // CHANGED: this is not conform to PR_LoadFromFile + if(prog->loadintoworld) + { + prog->loadintoworld = false; + ent = PRVM_EDICT_NUM(0); + } + else ent = PRVM_ED_Alloc(); + + // clear it + if (ent != prog->edicts) // hack + memset (ent->progs.vp, 0, prog->progs->entityfields * 4); + + data = PRVM_ED_ParseEdict (data, ent); + parsed++; + + // remove the entity ? + if(prog->load_edict && !prog->load_edict(ent)) + { + PRVM_ED_Free(ent); + inhibited++; + continue; + } + + // immediately call spawn function, but only if there is a self global and a classname + if(prog->self && prog->flag & PRVM_FE_CLASSNAME) + { + string_t handle = *(string_t*)&((byte*)ent->progs.vp)[PRVM_ED_FindFieldOffset("classname")]; + if (!handle) + { + if(host.debug) + { + MsgWarn("No classname for:\n"); + PRVM_ED_Print(ent); + } + PRVM_ED_Free (ent); + continue; + } + + // look for the spawn function + func = PRVM_ED_FindFunction (PRVM_GetString(handle)); + + if (!func) + { + if(host.debug) + { + MsgWarn("No spawn function for:\n"); + PRVM_ED_Print(ent); + } + PRVM_ED_Free (ent); + continue; + } + + // self = ent + PRVM_G_INT(prog->self->ofs) = PRVM_EDICT_TO_PROG(ent); + PRVM_ExecuteProgram (func - prog->functions, "" ); + } + + spawned++; + if (ent->priv.ed->free) + died++; + } + + MsgDev(D_INFO, "%s: %i new entities parsed, %i new inhibited, %i (%i new) spawned (whereas %i removed self, %i stayed)\n", PRVM_NAME, parsed, inhibited, prog->num_edicts, spawned, died, spawned - died); +} + +/* +=============== +PRVM_ResetProg +=============== +*/ + +void PRVM_ResetProg() +{ + PRVM_GCALL(reset_cmd)(); + Mem_FreePool(&prog->progs_mempool); + memset(prog,0,sizeof(prvm_prog_t)); +} + +/* +=============== +PRVM_LoadLNO +=============== +*/ +void PRVM_LoadLNO( const char *progname ) +{ + fs_offset_t filesize; + unsigned char *lno; + unsigned int *header; + char filename[512]; + + strcpy( filename, progname ); + FS_StripExtension( filename ); + FS_DefaultExtension( filename, ".lno" ); + + lno = FS_LoadFile( filename, &filesize ); + if( !lno ) return; + +/* + FS_Write (h, &lnotype, sizeof(int)); + FS_Write (h, &version, sizeof(int)); + FS_Write (h, &numglobaldefs, sizeof(int)); + FS_Write (h, &numpr_globals, sizeof(int)); + FS_Write (h, &numfielddefs, sizeof(int)); + FS_Write (h, &numstatements, sizeof(int)); + FS_Write (h, statement_linenums, numstatements * sizeof(int)); +*/ + if( (uint) filesize < (6 + prog->progs->numstatements) * sizeof( int ) ) + { + Mem_Free(lno); + return; + } + + header = (uint *) lno; + if( header[ 0 ] == *(unsigned int *) "LNOF" && + LittleLong( header[ 1 ] ) == 1 && + (unsigned int)LittleLong( header[ 2 ] ) == (unsigned int)prog->progs->numglobaldefs && + (unsigned int)LittleLong( header[ 3 ] ) == (unsigned int)prog->progs->numglobals && + (unsigned int)LittleLong( header[ 4 ] ) == (unsigned int)prog->progs->numfielddefs && + (unsigned int)LittleLong( header[ 5 ] ) == (unsigned int)prog->progs->numstatements ) + { + prog->statement_linenums = (int *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof( int ) ); + memcpy( prog->statement_linenums, (int *) lno + 6, prog->progs->numstatements * sizeof( int ) ); + } + Mem_Free( lno ); +} + +/* +=============== +PRVM_LoadProgs +=============== +*/ +void PRVM_LoadProgs (const char *filename, int numedfunc, char **ed_func, int numedfields, prvm_fieldvars_t *ed_field) +{ + int i; + dstatement_t *st; + ddef_t *infielddefs; + dfunction_t *dfunctions; + fs_offset_t filesize; + + if( prog->loaded ) + { + PRVM_ERROR ("PRVM_LoadProgs: there is already a %s program loaded!", PRVM_NAME ); + } + + prog->progs = (dprograms_t *)FS_LoadFile (filename, &filesize); + if (prog->progs == NULL || filesize < (fs_offset_t)sizeof(dprograms_t)) + PRVM_ERROR ("PRVM_LoadProgs: couldn't load %s for %s", filename, PRVM_NAME); + + MsgDev(D_INFO, "%s programs occupy %iK.\n", PRVM_NAME, filesize/1024); + + prog->filecrc = CRC_Block((unsigned char *)prog->progs, filesize); + + // byte swap the header + for (i = 0;i < (int) sizeof(*prog->progs) / 4;i++) + ((int *)prog->progs)[i] = LittleLong ( ((int *)prog->progs)[i] ); + + if (prog->progs->version != VPROGS_VERSION) + PRVM_ERROR ("%s: %s has wrong version number (%i should be %i)", PRVM_NAME, filename, prog->progs->version, VPROGS_VERSION); + + //try to recognize progs.dat by crc + switch(prog->progs->crc) + { + case PROG_CRC_SERVER: + Msg("Loading ^3server.dat\n"); + break; + default: + PRVM_ERROR ("%s: %s system vars have been modified, progdefs.h is out of date", PRVM_NAME, filename); + break; + } + + //prog->functions = (dfunction_t *)((unsigned char *)progs + progs->ofs_functions); + dfunctions = (dfunction_t *)((unsigned char *)prog->progs + prog->progs->ofs_functions); + + prog->strings = (char *)prog->progs + prog->progs->ofs_strings; + prog->stringssize = 0; + for (i = 0;i < prog->progs->numstrings;i++) + { + if (prog->progs->ofs_strings + prog->stringssize >= (int)filesize) + PRVM_ERROR ("%s: %s strings go past end of file", PRVM_NAME, filename); + prog->stringssize += (int)strlen (prog->strings + prog->stringssize) + 1; + } + prog->numknownstrings = 0; + prog->maxknownstrings = 0; + prog->knownstrings = NULL; + prog->knownstrings_freeable = NULL; + + prog->globaldefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_globaldefs); + + // we need to expand the fielddefs list to include all the engine fields, + // so allocate a new place for it + infielddefs = (ddef_t *)((unsigned char *)prog->progs + prog->progs->ofs_fielddefs); + // ( + DPFIELDS ) + prog->fielddefs = (ddef_t *)Mem_Alloc(prog->progs_mempool, (prog->progs->numfielddefs + numedfields) * sizeof(ddef_t)); + + prog->statements = (dstatement_t *)((unsigned char *)prog->progs + prog->progs->ofs_statements); + + prog->statement_profile = (double *)Mem_Alloc(prog->progs_mempool, prog->progs->numstatements * sizeof(*prog->statement_profile)); + + // moved edict_size calculation down below field adding code + + //pr_global_struct = (globalvars_t *)((unsigned char *)progs + progs->ofs_globals); + prog->globals.generic = (float *)((unsigned char *)prog->progs + prog->progs->ofs_globals); + + // byte swap the lumps + for (i=0 ; iprogs->numstatements ; i++) + { + prog->statements[i].op = LittleShort(prog->statements[i].op); + prog->statements[i].a = LittleShort(prog->statements[i].a); + prog->statements[i].b = LittleShort(prog->statements[i].b); + prog->statements[i].c = LittleShort(prog->statements[i].c); + } + + prog->functions = (mfunction_t *)Mem_Alloc(prog->progs_mempool, sizeof(mfunction_t) * prog->progs->numfunctions); + for (i = 0; i < prog->progs->numfunctions; i++) + { + prog->functions[i].first_statement = LittleLong (dfunctions[i].first_statement); + prog->functions[i].parm_start = LittleLong (dfunctions[i].parm_start); + prog->functions[i].s_name = LittleLong (dfunctions[i].s_name); + prog->functions[i].s_file = LittleLong (dfunctions[i].s_file); + prog->functions[i].numparms = LittleLong (dfunctions[i].numparms); + prog->functions[i].locals = LittleLong (dfunctions[i].locals); + memcpy(prog->functions[i].parm_size, dfunctions[i].parm_size, sizeof(dfunctions[i].parm_size)); + } + + for (i = 0; i < prog->progs->numglobaldefs; i++) + { + prog->globaldefs[i].type = LittleShort (prog->globaldefs[i].type); + prog->globaldefs[i].ofs = LittleShort (prog->globaldefs[i].ofs); + prog->globaldefs[i].s_name = LittleLong (prog->globaldefs[i].s_name); + } + + // copy the progs fields to the new fields list + for (i = 0; i < prog->progs->numfielddefs; i++) + { + prog->fielddefs[i].type = LittleShort (infielddefs[i].type); + if (prog->fielddefs[i].type & DEF_SAVEGLOBAL) + PRVM_ERROR ("PRVM_LoadProgs: prog->fielddefs[i].type & DEF_SAVEGLOBAL in %s", PRVM_NAME); + prog->fielddefs[i].ofs = LittleShort (infielddefs[i].ofs); + prog->fielddefs[i].s_name = LittleLong (infielddefs[i].s_name); + } + + // append the ed fields + for (i = 0; i < (int)numedfields; i++) + { + prog->fielddefs[prog->progs->numfielddefs].type = ed_field[i].type; + prog->fielddefs[prog->progs->numfielddefs].ofs = ed_field[i].ofs; + prog->fielddefs[prog->progs->numfielddefs].s_name = PRVM_SetEngineString(ed_field[i].name); + } + + // check ed functions + for(i=0 ; i < numedfunc ; i++) + if(PRVM_ED_FindFunction(ed_func[i]) == 0) + PRVM_ERROR("%s: %s not found in %s",PRVM_NAME, ed_func[i], filename); + + for (i=0 ; iprogs->numglobals ; i++) + ((int *)prog->globals.generic)[i] = LittleLong (((int *)prog->globals.generic)[i]); + + // moved edict_size calculation down here, below field adding code + // LordHavoc: this no longer includes the edict_t header + prog->edict_size = prog->progs->entityfields * 4; + prog->edictareasize = prog->edict_size * prog->limit_edicts; + + // LordHavoc: bounds check anything static + for (i = 0, st = prog->statements; i < prog->progs->numstatements; i++, st++) + { + switch (st->op) + { + case OP_IF: + case OP_IFNOT: + if ((word) st->a >= prog->progs->numglobals || (word)st->b + i < 0 || (word)st->b + i >= prog->progs->numstatements) + PRVM_ERROR("PRVM_LoadProgs: out of bounds IF/IFNOT (statement %d) in %s", i, PRVM_NAME); + break; + case OP_GOTO: + if (st->a + i < 0 || st->a + i >= prog->progs->numstatements) + PRVM_ERROR("PRVM_LoadProgs: out of bounds GOTO (statement %d) in %s", i, PRVM_NAME); + break; + // global global global + case OP_ADD_F: + case OP_ADD_V: + case OP_SUB_F: + case OP_SUB_V: + case OP_MUL_F: + case OP_MUL_V: + case OP_MUL_FV: + case OP_MUL_VF: + case OP_DIV_F: + case OP_BITAND: + case OP_BITOR: + case OP_GE: + case OP_LE: + case OP_GT: + case OP_LT: + case OP_AND: + case OP_OR: + case OP_EQ_F: + case OP_EQ_V: + case OP_EQ_S: + case OP_EQ_E: + case OP_EQ_FNC: + case OP_NE_F: + case OP_NE_V: + case OP_NE_S: + case OP_NE_E: + case OP_NE_FNC: + case OP_ADDRESS: + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + case OP_LOAD_V: + if ((word) st->a >= prog->progs->numglobals || (word) st->b >= prog->progs->numglobals || (word)st->c >= prog->progs->numglobals) + PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d)", i); + break; + // global none global + case OP_NOT_F: + case OP_NOT_V: + case OP_NOT_S: + case OP_NOT_FNC: + case OP_NOT_ENT: + if ((word) st->a >= prog->progs->numglobals || (word) st->c >= prog->progs->numglobals) + PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME); + break; + // 2 globals + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: + case OP_STOREP_S: + case OP_STOREP_FNC: + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: + case OP_STORE_S: + case OP_STORE_FNC: + case OP_STATE: + case OP_STOREP_V: + case OP_STORE_V: + if ((word) st->a >= prog->progs->numglobals || (word) st->b >= prog->progs->numglobals) + PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME); + break; + // 1 global + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + case OP_DONE: + case OP_RETURN: + if ((word) st->a >= prog->progs->numglobals) + PRVM_ERROR("PRVM_LoadProgs: out of bounds global index (statement %d) in %s", i, PRVM_NAME); + break; + default: + MsgDev(D_WARN, "PRVM_LoadProgs: unknown opcode %d at statement %d in %s\n", st->op, i, PRVM_NAME); + break; + } + } + + PRVM_LoadLNO(filename); + + PRVM_Init_Exec(); + + prog->loaded = true; + + // set flags & ddef_ts in prog + + prog->flag = 0; + + prog->self = PRVM_ED_FindGlobal("self"); + + if( PRVM_ED_FindGlobal("time") && PRVM_ED_FindGlobal("time")->type & ev_float ) + prog->time = &PRVM_G_FLOAT(PRVM_ED_FindGlobal("time")->ofs); + + if(PRVM_ED_FindField ("chain")) + prog->flag |= PRVM_FE_CHAIN; + + if(PRVM_ED_FindField ("classname")) + prog->flag |= PRVM_FE_CLASSNAME; + + if(PRVM_ED_FindField ("nextthink") && PRVM_ED_FindField ("frame") && PRVM_ED_FindField ("think") && prog->flag && prog->self) + prog->flag |= PRVM_OP_STATE; + + PRVM_GCALL(init_cmd)(); + + // init mempools + PRVM_MEM_Alloc(); +} + + +void PRVM_Fields_f (void) +{ + int i, j, ednum, used, usedamount; + int *counts; + char tempstring[MAX_INPUTLINE], tempstring2[260]; + const char *name; + edict_t *ed; + ddef_t *d; + int *v; + + // TODO + /* + if (!sv.active) + { + Con_Print("no progs loaded\n"); + return; + } + */ + + if(Cmd_Argc() != 2) + { + Con_Print("prvm_fields \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + counts = (int *)Z_Malloc(prog->progs->numfielddefs * sizeof(int)); + for (ednum = 0; ednum < prog->max_edicts; ednum++) + { + ed = PRVM_EDICT_NUM(ednum); + if (ed->priv.ed->free) + continue; + for (i = 1;i < prog->progs->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + v = (int *)((char *)ed->progs.vp + d->ofs*4); + // if the value is still all 0, skip the field + for (j = 0;j < prvm_type_size[d->type & ~DEF_SAVEGLOBAL];j++) + { + if (v[j]) + { + counts[i]++; + break; + } + } + } + } + used = 0; + usedamount = 0; + tempstring[0] = 0; + for (i = 0;i < prog->progs->numfielddefs;i++) + { + d = &prog->fielddefs[i]; + name = PRVM_GetString(d->s_name); + if (name[strlen(name)-2] == '_') + continue; // skip _x, _y, _z vars + switch(d->type & ~DEF_SAVEGLOBAL) + { + case ev_string: + strncat(tempstring, "string ", sizeof(tempstring)); + break; + case ev_entity: + strncat(tempstring, "entity ", sizeof(tempstring)); + break; + case ev_function: + strncat(tempstring, "function ", sizeof(tempstring)); + break; + case ev_field: + strncat(tempstring, "field ", sizeof(tempstring)); + break; + case ev_void: + strncat(tempstring, "void ", sizeof(tempstring)); + break; + case ev_float: + strncat(tempstring, "float ", sizeof(tempstring)); + break; + case ev_vector: + strncat(tempstring, "vector ", sizeof(tempstring)); + break; + case ev_pointer: + strncat(tempstring, "pointer ", sizeof(tempstring)); + break; + default: + sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL); + strncat(tempstring, tempstring2, sizeof(tempstring)); + break; + } + if (strlen(name) > sizeof(tempstring2)-4) + { + memcpy (tempstring2, name, sizeof(tempstring2)-4); + tempstring2[sizeof(tempstring2)-4] = tempstring2[sizeof(tempstring2)-3] = tempstring2[sizeof(tempstring2)-2] = '.'; + tempstring2[sizeof(tempstring2)-1] = 0; + name = tempstring2; + } + strncat(tempstring, name, sizeof(tempstring)); + for (j = (int)strlen(name);j < 25;j++) + strncat(tempstring, " ", sizeof(tempstring)); + sprintf(tempstring2, "%5d", counts[i]); + strncat(tempstring, tempstring2, sizeof(tempstring)); + strncat(tempstring, "\n", sizeof(tempstring)); + if (strlen(tempstring) >= sizeof(tempstring)/2) + { + Con_Print(tempstring); + tempstring[0] = 0; + } + if (counts[i]) + { + used++; + usedamount += prvm_type_size[d->type & ~DEF_SAVEGLOBAL]; + } + } + Mem_Free(counts); + Msg("%s: %i entity fields (%i in use), totalling %i bytes per edict (%i in use), %i edicts allocated, %i bytes total spent on edict fields (%i needed)\n", PRVM_NAME, prog->progs->entityfields, used, prog->progs->entityfields * 4, usedamount * 4, prog->max_edicts, prog->progs->entityfields * 4 * prog->max_edicts, usedamount * 4 * prog->max_edicts); + + PRVM_End; +} + +void PRVM_Globals_f (void) +{ + int i; + // TODO + /*if (!sv.active) + { + Con_Print("no progs loaded\n"); + return; + }*/ + if(Cmd_Argc () != 2) + { + Con_Print("prvm_globals \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString (Cmd_Argv (1))) + return; + + Msg("%s :", PRVM_NAME); + + for (i = 0;i < prog->progs->numglobaldefs;i++) + Msg("%s\n", PRVM_GetString(prog->globaldefs[i].s_name)); + Msg("%i global variables, totalling %i bytes\n", prog->progs->numglobals, prog->progs->numglobals * 4); + + PRVM_End; +} + +/* +=============== +PRVM_Global +=============== +*/ +void PRVM_Global_f(void) +{ + ddef_t *global; + if( Cmd_Argc() != 3 ) { + Msg( "prvm_global \n" ); + return; + } + + PRVM_Begin; + if( !PRVM_SetProgFromString( Cmd_Argv(1) ) ) + return; + + global = PRVM_ED_FindGlobal( Cmd_Argv(2) ); + if( !global ) + Msg( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) ); + else + Msg( "%s: %s\n", Cmd_Argv(2), PRVM_ValueString( (etype_t)global->type, (prvm_eval_t *) &prog->globals.generic[ global->ofs ] ) ); + PRVM_End; +} + +/* +=============== +PRVM_GlobalSet +=============== +*/ +void PRVM_GlobalSet_f(void) +{ + ddef_t *global; + if( Cmd_Argc() != 4 ) { + Msg( "prvm_globalset \n" ); + return; + } + + PRVM_Begin; + if( !PRVM_SetProgFromString( Cmd_Argv(1) ) ) + return; + + global = PRVM_ED_FindGlobal( Cmd_Argv(2) ); + if( !global ) + Msg( "No global '%s' in %s!\n", Cmd_Argv(2), Cmd_Argv(1) ); + else + PRVM_ED_ParseEpair( NULL, global, Cmd_Argv(3) ); + PRVM_End; +} + +/* +=============== +PRVM_Init +=============== +*/ +void PRVM_Init (void) +{ + Cmd_AddCommand ("prvm_edict", PRVM_ED_PrintEdict_f); + Cmd_AddCommand ("prvm_edicts", PRVM_ED_PrintEdicts_f); + Cmd_AddCommand ("prvm_edictcount", PRVM_ED_Count_f); + Cmd_AddCommand ("prvm_profile", PRVM_Profile_f); + Cmd_AddCommand ("prvm_fields", PRVM_Fields_f); + Cmd_AddCommand ("prvm_globals", PRVM_Globals_f); + Cmd_AddCommand ("prvm_global", PRVM_Global_f); + Cmd_AddCommand ("prvm_globalset", PRVM_GlobalSet_f); + Cmd_AddCommand ("prvm_edictset", PRVM_ED_EdictSet_f); + Cmd_AddCommand ("prvm_printfunction", PRVM_PrintFunction_f); + + // LordHavoc: optional runtime bounds checking (speed drain, but worth it for security, on by default - breaks most QCCX features (used by CRMod and others)) + prvm_boundscheck = Cvar_Get ("prvm_boundscheck", "0", 0); + prvm_traceqc = Cvar_Get ("prvm_traceqc", "0", 0); + prvm_statementprofiling = Cvar_Get ("prvm_statementprofiling", "0", 0); + + //VM_Cmd_Init(); +} + +// LordHavoc: changed this to NOT use a return statement, so that it can be used in functions that must return a value +void VM_Warning(const char *fmt, ...) +{ + va_list argptr; + char msg[MAX_INPUTLINE]; + + va_start(argptr, fmt); + sprintf(msg, fmt, argptr); + va_end(argptr); + + Msg(msg); + // TODO: either add a cvar/cmd to control the state dumping or replace some of the calls with Con_Printf [9/13/2006 Black] + //PRVM_PrintState(); +} + +/* +=============== +VM_error + +Abort the server with a game error +=============== +*/ +void VM_Error (const char *fmt, ...) +{ + char msg[1024]; + va_list argptr; + + va_start (argptr,fmt); + vsprintf (msg, fmt, argptr); + va_end (argptr); + + Host_Error ("Prvm error: %s", msg); +} + +/* +=============== +PRVM_InitProg +=============== +*/ +void PRVM_InitProg(int prognr) +{ + if(prognr < 0 || prognr >= PRVM_MAXPROGS) + Sys_Error("PRVM_InitProg: Invalid program number %i",prognr); + + prog = &prog_list[prognr]; + + if(prog->loaded) PRVM_ResetProg(); + + memset(prog, 0, sizeof(prvm_prog_t)); + + prog->time = &prog->_time; + prog->error_cmd = VM_Error; +} + +int PRVM_GetProgNr() +{ + return prog - prog_list; +} + +void *_PRVM_Alloc(size_t buffersize, const char *filename, int fileline) +{ + return Com->Mem.Alloc(prog->progs_mempool, buffersize, filename, fileline); +} + +void _PRVM_Free(void *buffer, const char *filename, int fileline) +{ + Com->Mem.Free(buffer, filename, fileline); +} + +void _PRVM_FreeAll(const char *filename, int fileline) +{ + prog->progs = NULL; + prog->fielddefs = NULL; + prog->functions = NULL; + Com->Mem.EmptyPool(prog->progs_mempool, filename, fileline); +} + +// LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons +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; +} + +const char *PRVM_GetString(int num) +{ + if (num >= 0 && num < prog->stringssize) + return prog->strings + num; + else if (num < 0 && num >= -prog->numknownstrings) + { + num = -1 - num; + if (!prog->knownstrings[num]) + PRVM_ERROR("PRVM_GetString: attempt to get string that is already freed"); + return prog->knownstrings[num]; + } + else + { + PRVM_ERROR("PRVM_GetString: invalid string offset %i", num); + return ""; + } +} + +int PRVM_SetEngineString(const char *s) +{ + int i; + if (!s) + return 0; + if (s >= prog->strings && s <= prog->strings + prog->stringssize) + PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area"); + for (i = 0;i < prog->numknownstrings;i++) + if (prog->knownstrings[i] == s) + return -1 - i; + // new unknown engine string + MsgDev(D_WARN, "new engine string %p\n", s ); + for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + const unsigned char *oldstrings_freeable = prog->knownstrings_freeable; + prog->maxknownstrings += 128; + prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char)); + if (prog->numknownstrings) + { + memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char)); + } + } + prog->numknownstrings++; + } + prog->firstfreeknownstring = i + 1; + prog->knownstrings[i] = s; + return -1 - i; +} + +int PRVM_AllocString(size_t bufferlength, char **pointer) +{ + int i; + if (!bufferlength) + return 0; + for (i = prog->firstfreeknownstring;i < prog->numknownstrings;i++) + if (!prog->knownstrings[i]) + break; + if (i >= prog->numknownstrings) + { + if (i >= prog->maxknownstrings) + { + const char **oldstrings = prog->knownstrings; + const unsigned char *oldstrings_freeable = prog->knownstrings_freeable; + prog->maxknownstrings += 128; + prog->knownstrings = (const char **)PRVM_Alloc(prog->maxknownstrings * sizeof(char *)); + prog->knownstrings_freeable = (unsigned char *)PRVM_Alloc(prog->maxknownstrings * sizeof(unsigned char)); + if (prog->numknownstrings) + { + memcpy((char **)prog->knownstrings, oldstrings, prog->numknownstrings * sizeof(char *)); + memcpy((char **)prog->knownstrings_freeable, oldstrings_freeable, prog->numknownstrings * sizeof(unsigned char)); + } + } + prog->numknownstrings++; + } + prog->firstfreeknownstring = i + 1; + prog->knownstrings[i] = (char *)PRVM_Alloc(bufferlength); + prog->knownstrings_freeable[i] = true; + if (pointer) + *pointer = (char *)(prog->knownstrings[i]); + return -1 - i; +} + +void PRVM_FreeString(int num) +{ + if (num == 0) + PRVM_ERROR("PRVM_FreeString: attempt to free a NULL string"); + else if (num >= 0 && num < prog->stringssize) + PRVM_ERROR("PRVM_FreeString: attempt to free a constant string"); + else if (num < 0 && num >= -prog->numknownstrings) + { + num = -1 - num; + if (!prog->knownstrings[num]) + PRVM_ERROR("PRVM_FreeString: attempt to free a non-existent or already freed string"); + if (!prog->knownstrings[num]) + PRVM_ERROR("PRVM_FreeString: attempt to free a string owned by the engine"); + PRVM_Free((char *)prog->knownstrings[num]); + prog->knownstrings[num] = NULL; + prog->knownstrings_freeable[num] = false; + prog->firstfreeknownstring = min(prog->firstfreeknownstring, num); + } + else + PRVM_ERROR("PRVM_FreeString: invalid string offset %i", num); +} + diff --git a/engine/common/vm_exec.c b/engine/common/vm_exec.c new file mode 100644 index 00000000..85647b1b --- /dev/null +++ b/engine/common/vm_exec.c @@ -0,0 +1,1121 @@ +/* +Copyright (C) 1996-1997 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "engine.h" +#include "progsvm.h" + +char *prvm_opnames[] = +{ +"^5DONE", + +"MUL_F", +"MUL_V", +"MUL_FV", +"MUL_VF", + +"DIV", + +"ADD_F", +"ADD_V", + +"SUB_F", +"SUB_V", + +"^2EQ_F", +"^2EQ_V", +"^2EQ_S", +"^2EQ_E", +"^2EQ_FNC", + +"^2NE_F", +"^2NE_V", +"^2NE_S", +"^2NE_E", +"^2NE_FNC", + +"^2LE", +"^2GE", +"^2LT", +"^2GT", + +"^6FIELD_F", +"^6FIELD_V", +"^6FIELD_S", +"^6FIELD_ENT", +"^6FIELD_FLD", +"^6FIELD_FNC", + +"^1ADDRESS", + +"STORE_F", +"STORE_V", +"STORE_S", +"STORE_ENT", +"STORE_FLD", +"STORE_FNC", + +"^1STOREP_F", +"^1STOREP_V", +"^1STOREP_S", +"^1STOREP_ENT", +"^1STOREP_FLD", +"^1STOREP_FNC", + +"^5RETURN", + +"^2NOT_F", +"^2NOT_V", +"^2NOT_S", +"^2NOT_ENT", +"^2NOT_FNC", + +"^5IF", +"^5IFNOT", + +"^3CALL0", +"^3CALL1", +"^3CALL2", +"^3CALL3", +"^3CALL4", +"^3CALL5", +"^3CALL6", +"^3CALL7", +"^3CALL8", + +"^1STATE", + +"^5GOTO", + +"^2AND", +"^2OR", + +"BITAND", +"BITOR" +}; + +char *PRVM_GlobalString (int ofs); +char *PRVM_GlobalStringNoContents (int ofs); + + +//============================================================================= + +/* +================= +PRVM_PrintStatement +================= +*/ +extern cvar_t *prvm_statementprofiling; +void PRVM_PrintStatement (dstatement_t *s) +{ + size_t i; + int opnum = (int)(s - prog->statements); + + Msg("s%i: ", opnum); + if( prog->statement_linenums ) + Msg( "%s:%i: ", PRVM_GetString( prog->xfunction->s_file ), prog->statement_linenums[ opnum ] ); + + if (prvm_statementprofiling->value) + Msg("%7.0f ", prog->statement_profile[s - prog->statements]); + + if ( (unsigned)s->op < sizeof(prvm_opnames)/sizeof(prvm_opnames[0])) + { + Msg("%s ", prvm_opnames[s->op]); + i = strlen(prvm_opnames[s->op]); + // don't count a preceding color tag when padding the name + if (prvm_opnames[s->op][0] == STRING_COLOR_TAG) + i -= 2; + for ( ; i<10 ; i++) + Con_Print(" "); + } + if (s->op == OP_IF || s->op == OP_IFNOT) + Msg("%s, s%i",PRVM_GlobalString((unsigned short) s->a),(signed short)s->b + opnum); + else if (s->op == OP_GOTO) + Msg("s%i",(signed short)s->a + opnum); + else if ( (unsigned)(s->op - OP_STORE_F) < 6) + { + Con_Print(PRVM_GlobalString((unsigned short) s->a)); + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b)); + } + else if (s->op == OP_ADDRESS || (unsigned)(s->op - OP_LOAD_F) < 6) + { + if (s->a) + Con_Print(PRVM_GlobalString((unsigned short) s->a)); + if (s->b) + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->b)); + } + if (s->c) + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c)); + } + } + else + { + if (s->a) + Con_Print(PRVM_GlobalString((unsigned short) s->a)); + if (s->b) + { + Con_Print(", "); + Con_Print(PRVM_GlobalString((unsigned short) s->b)); + } + if (s->c) + { + Con_Print(", "); + Con_Print(PRVM_GlobalStringNoContents((unsigned short) s->c)); + } + } + Con_Print("\n"); +} + +void PRVM_PrintFunctionStatements (const char *name) +{ + int i, firststatement, endstatement; + mfunction_t *func; + func = PRVM_ED_FindFunction (name); + if (!func) + { + Msg("%s progs: no function named %s\n", PRVM_NAME, name); + return; + } + firststatement = func->first_statement; + if (firststatement < 0) + { + Msg("%s progs: function %s is builtin #%i\n", PRVM_NAME, name, -firststatement); + return; + } + + // find the end statement + endstatement = prog->progs->numstatements; + for (i = 0;i < prog->progs->numfunctions;i++) + if (endstatement > prog->functions[i].first_statement && firststatement < prog->functions[i].first_statement) + endstatement = prog->functions[i].first_statement; + + // now print the range of statements + Msg("%s progs: disassembly of function %s (statements %i-%i):\n", PRVM_NAME, name, firststatement, endstatement); + for (i = firststatement;i < endstatement;i++) + { + PRVM_PrintStatement(prog->statements + i); + prog->statement_profile[i] = 0; + } +} + +/* +============ +PRVM_PrintFunction_f + +============ +*/ +void PRVM_PrintFunction_f (void) +{ + if (Cmd_Argc() != 3) + { + Msg("usage: prvm_printfunction \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_PrintFunctionStatements(Cmd_Argv(2)); + + PRVM_End; +} + +/* +============ +PRVM_StackTrace +============ +*/ +void PRVM_StackTrace (void) +{ + mfunction_t *f; + int i; + + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + for (i = prog->depth;i > 0;i--) + { + f = prog->stack[i].f; + + if (!f) + Con_Print("\n"); + else + Msg("%12s : %s : statement %i\n", PRVM_GetString(f->s_file), PRVM_GetString(f->s_name), prog->stack[i].s - f->first_statement); + } +} + + +void PRVM_Profile (int maxfunctions, int mininstructions) +{ + mfunction_t *f, *best; + int i, num; + double max; + + Msg( "%s Profile:\n[CallCount] [Statements] [BuiltinCost]\n", PRVM_NAME ); + + num = 0; + do + { + max = 0; + best = NULL; + for (i=0 ; iprogs->numfunctions ; i++) + { + f = &prog->functions[i]; + if (max < f->profile + f->builtinsprofile + f->callcount) + { + max = f->profile + f->builtinsprofile + f->callcount; + best = f; + } + } + if (best) + { + if (num < maxfunctions && max >= mininstructions) + { + if (best->first_statement < 0) + Msg("%9.0f ----- builtin ----- %s\n", best->callcount, PRVM_GetString(best->s_name)); + else + Msg("%9.0f %9.0f %9.0f %s\n", best->callcount, best->profile, best->builtinsprofile, PRVM_GetString(best->s_name)); + } + num++; + best->profile = 0; + best->builtinsprofile = 0; + best->callcount = 0; + } + } while (best); +} + +/* +============ +PRVM_Profile_f + +============ +*/ +void PRVM_Profile_f (void) +{ + int howmany; + + howmany = 1<<30; + if (Cmd_Argc() == 3) + howmany = atoi(Cmd_Argv(2)); + else if (Cmd_Argc() != 2) + { + Con_Print("prvm_profile \n"); + return; + } + + PRVM_Begin; + if(!PRVM_SetProgFromString(Cmd_Argv(1))) + return; + + PRVM_Profile(howmany, 1); + + PRVM_End; +} + +void PRVM_CrashAll() +{ + int i; + prvm_prog_t *oldprog = prog; + + for(i = 0; i < PRVM_MAXPROGS; i++) + { + if(!PRVM_ProgLoaded(i)) + continue; + PRVM_SetProg(i); + PRVM_Crash(); + } + + prog = oldprog; +} + +void PRVM_PrintState(void) +{ + int i; + if (prog->xfunction) + { + for (i = -7; i <= 0;i++) + if (prog->xstatement + i >= prog->xfunction->first_statement) + PRVM_PrintStatement (prog->statements + prog->xstatement + i); + } + else + Con_Print("null function executing??\n"); + PRVM_StackTrace (); +} + +void PRVM_Crash() +{ + if (prog == NULL) + return; + + if( prog->depth > 0 ) + { + Msg("QuakeC crash report for %s:\n", PRVM_NAME); + PRVM_PrintState(); + } + + // dump the stack so host_error can shutdown functions + prog->depth = 0; + prog->localstack_used = 0; + + // reset the prog pointer + prog = NULL; +} + +/* +============================================================================ +PRVM_ExecuteProgram + +The interpretation main loop +============================================================================ +*/ + +/* +==================== +PRVM_EnterFunction + +Returns the new program statement counter +==================== +*/ +int PRVM_EnterFunction (mfunction_t *f) +{ + int i, j, c, o; + + if (!f) + PRVM_ERROR ("PRVM_EnterFunction: NULL function in %s", PRVM_NAME); + + prog->stack[prog->depth].s = prog->xstatement; + prog->stack[prog->depth].f = prog->xfunction; + prog->depth++; + if (prog->depth >=PRVM_MAX_STACK_DEPTH) + PRVM_ERROR ("stack overflow"); + +// save off any locals that the new function steps on + c = f->locals; + if (prog->localstack_used + c > PRVM_LOCALSTACK_SIZE) + PRVM_ERROR ("PRVM_ExecuteProgram: locals stack overflow in %s", PRVM_NAME); + + for (i=0 ; i < c ; i++) + prog->localstack[prog->localstack_used+i] = ((int *)prog->globals.generic)[f->parm_start + i]; + prog->localstack_used += c; + +// copy parameters + o = f->parm_start; + for (i=0 ; inumparms ; i++) + { + for (j=0 ; jparm_size[i] ; j++) + { + ((int *)prog->globals.generic)[o] = ((int *)prog->globals.generic)[OFS_PARM0+i*3+j]; + o++; + } + } + + prog->xfunction = f; + return f->first_statement - 1; // offset the s++ +} + +/* +==================== +PRVM_LeaveFunction +==================== +*/ +int PRVM_LeaveFunction (void) +{ + int i, c; + + if (prog->depth <= 0) + PRVM_ERROR ("prog stack underflow in %s", PRVM_NAME); + + if (!prog->xfunction) + PRVM_ERROR ("PR_LeaveFunction: NULL function in %s", PRVM_NAME); +// restore locals from the stack + c = prog->xfunction->locals; + prog->localstack_used -= c; + if (prog->localstack_used < 0) + PRVM_ERROR ("PRVM_ExecuteProgram: locals stack underflow in %s", PRVM_NAME); + + for (i=0 ; i < c ; i++) + ((int *)prog->globals.generic)[prog->xfunction->parm_start + i] = prog->localstack[prog->localstack_used+i]; + +// up stack + prog->depth--; + prog->xfunction = prog->stack[prog->depth].f; + return prog->stack[prog->depth].s; +} + +void PRVM_Init_Exec(void) +{ + // dump the stack + prog->depth = 0; + prog->localstack_used = 0; + // reset the string table + // nothing here yet +} + +/* +==================== +PRVM_ExecuteProgram +==================== +*/ +// LordHavoc: optimized +#define OPA ((prvm_eval_t *)&prog->globals.generic[(word) st->a]) +#define OPB ((prvm_eval_t *)&prog->globals.generic[(word) st->b]) +#define OPC ((prvm_eval_t *)&prog->globals.generic[(word) st->c]) +extern cvar_t *prvm_boundscheck; +extern cvar_t *prvm_traceqc; +extern cvar_t *prvm_statementprofiling; +extern int PRVM_ED_FindFieldOffset (const char *field); +extern ddef_t* PRVM_ED_FindGlobal(const char *name); + +void PRVM_ExecuteProgram (func_t fnum, const char *errormessage) +{ + dstatement_t *st, *startst; + mfunction_t *f, *newf; + edict_t *ed; + prvm_eval_t *ptr; + int jumpcount, cachedpr_trace, exitdepth; + + if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions) + { + if (prog->self && PRVM_G_INT(prog->self->ofs)) + PRVM_ED_Print(PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs))); + PRVM_ERROR ("PRVM_ExecuteProgram: %s", errormessage); + return; + } + + f = &prog->functions[fnum]; + + prog->trace = prvm_traceqc->value; + + // we know we're done when pr_depth drops to this + exitdepth = prog->depth; + + // make a stack frame + st = &prog->statements[PRVM_EnterFunction (f)]; + // save the starting statement pointer for profiling + // (when the function exits or jumps, the (st - startst) integer value is + // added to the function's profile counter) + startst = st; + // instead of counting instructions, we count jumps + jumpcount = 0; + // add one to the callcount of this function because otherwise engine-called functions aren't counted + prog->xfunction->callcount++; + +chooseexecprogram: + cachedpr_trace = prog->trace; + + while (1) + { + st++; + + if (prog->trace) PRVM_PrintStatement(st); + if (prvm_statementprofiling->value) prog->statement_profile[st - prog->statements]++; + + switch (st->op) + { + case OP_ADD_F: + OPC->_float = OPA->_float + OPB->_float; + break; + case OP_ADD_V: + OPC->vector[0] = OPA->vector[0] + OPB->vector[0]; + OPC->vector[1] = OPA->vector[1] + OPB->vector[1]; + OPC->vector[2] = OPA->vector[2] + OPB->vector[2]; + break; + case OP_SUB_F: + OPC->_float = OPA->_float - OPB->_float; + break; + case OP_SUB_V: + OPC->vector[0] = OPA->vector[0] - OPB->vector[0]; + OPC->vector[1] = OPA->vector[1] - OPB->vector[1]; + OPC->vector[2] = OPA->vector[2] - OPB->vector[2]; + break; + case OP_MUL_F: + OPC->_float = OPA->_float * OPB->_float; + break; + case OP_MUL_V: + OPC->_float = OPA->vector[0]*OPB->vector[0] + OPA->vector[1]*OPB->vector[1] + OPA->vector[2]*OPB->vector[2]; + break; + case OP_MUL_FV: + OPC->vector[0] = OPA->_float * OPB->vector[0]; + OPC->vector[1] = OPA->_float * OPB->vector[1]; + OPC->vector[2] = OPA->_float * OPB->vector[2]; + break; + case OP_MUL_VF: + OPC->vector[0] = OPB->_float * OPA->vector[0]; + OPC->vector[1] = OPB->_float * OPA->vector[1]; + OPC->vector[2] = OPB->_float * OPA->vector[2]; + break; + case OP_DIV_F: + if( OPB->_float != 0.0f ) + { + OPC->_float = OPA->_float / OPB->_float; + } + else + { + if( host.developer >= D_WARN ) + { + prog->xfunction->profile += (st - startst); + startst = st; + prog->xstatement = st - prog->statements; + VM_Warning( "Attempted division by zero in %s\n", PRVM_NAME ); + } + OPC->_float = 0.0f; + } + break; + case OP_BITAND: + OPC->_float = (int)OPA->_float & (int)OPB->_float; + break; + case OP_BITOR: + OPC->_float = (int)OPA->_float | (int)OPB->_float; + break; + case OP_GE: + OPC->_float = OPA->_float >= OPB->_float; + break; + case OP_LE: + OPC->_float = OPA->_float <= OPB->_float; + break; + case OP_GT: + OPC->_float = OPA->_float > OPB->_float; + break; + case OP_LT: + OPC->_float = OPA->_float < OPB->_float; + break; + case OP_AND: + OPC->_float = OPA->_float && OPB->_float; + break; + case OP_OR: + OPC->_float = OPA->_float || OPB->_float; + break; + case OP_NOT_F: + OPC->_float = !OPA->_float; + break; + case OP_NOT_V: + OPC->_float = !OPA->vector[0] && !OPA->vector[1] && !OPA->vector[2]; + break; + case OP_NOT_S: + OPC->_float = !OPA->string || !*PRVM_GetString(OPA->string); + break; + case OP_NOT_FNC: + OPC->_float = !OPA->function; + break; + case OP_NOT_ENT: + OPC->_float = (OPA->edict == 0); + break; + case OP_EQ_F: + OPC->_float = OPA->_float == OPB->_float; + break; + case OP_EQ_V: + OPC->_float = (OPA->vector[0] == OPB->vector[0]) && (OPA->vector[1] == OPB->vector[1]) && (OPA->vector[2] == OPB->vector[2]); + break; + case OP_EQ_S: + OPC->_float = !strcmp(PRVM_GetString(OPA->string),PRVM_GetString(OPB->string)); + break; + case OP_EQ_E: + OPC->_float = OPA->_int == OPB->_int; + break; + case OP_EQ_FNC: + OPC->_float = OPA->function == OPB->function; + break; + case OP_NE_F: + OPC->_float = OPA->_float != OPB->_float; + break; + case OP_NE_V: + OPC->_float = (OPA->vector[0] != OPB->vector[0]) || (OPA->vector[1] != OPB->vector[1]) || (OPA->vector[2] != OPB->vector[2]); + break; + case OP_NE_S: + OPC->_float = strcmp(PRVM_GetString(OPA->string),PRVM_GetString(OPB->string)); + break; + case OP_NE_E: + OPC->_float = OPA->_int != OPB->_int; + break; + case OP_NE_FNC: + OPC->_float = OPA->function != OPB->function; + break; + + case OP_STORE_F: + case OP_STORE_ENT: + case OP_STORE_FLD: // integers + case OP_STORE_S: + case OP_STORE_FNC: // pointers + OPB->_int = OPA->_int; + break; + case OP_STORE_V: + OPB->ivector[0] = OPA->ivector[0]; + OPB->ivector[1] = OPA->ivector[1]; + OPB->ivector[2] = OPA->ivector[2]; + break; + + case OP_STOREP_F: + case OP_STOREP_ENT: + case OP_STOREP_FLD: // integers + case OP_STOREP_S: + case OP_STOREP_FNC: // pointers + if(prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int + 4 > prog->edictareasize)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int); + return; + } + ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int); + ptr->_int = OPA->_int; + break; + + case OP_STOREP_V: + if (prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int + 12 > prog->edictareasize)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int); + return; + } + ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int); + ptr->vector[0] = OPA->vector[0]; + ptr->vector[1] = OPA->vector[1]; + ptr->vector[2] = OPA->vector[2]; + break; + + case OP_ADDRESS: + if (prvm_boundscheck->value && ((uint)(OPB->_int) >= (uint)(prog->progs->entityfields))) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int); + return; + } + if (OPA->edict == 0 && prog->protect_world) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME); + return; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->_int = (byte *)((int *)ed->progs.vp + OPB->_int) - (unsigned char *)prog->edictsfields; + break; + + case OP_LOAD_F: + case OP_LOAD_FLD: + case OP_LOAD_ENT: + case OP_LOAD_S: + case OP_LOAD_FNC: + if (prvm_boundscheck->value && ((uint)(OPB->_int) >= (uint)(prog->progs->entityfields))) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int); + return; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->_int = ((prvm_eval_t *)((int *)ed->progs.vp + OPB->_int))->_int; + break; + + case OP_LOAD_V: + if (prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int + 2 >= prog->progs->entityfields)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int); + return; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->vector[0] = ((prvm_eval_t *)((int *)ed->progs.vp + OPB->_int))->vector[0]; + OPC->vector[1] = ((prvm_eval_t *)((int *)ed->progs.vp + OPB->_int))->vector[1]; + OPC->vector[2] = ((prvm_eval_t *)((int *)ed->progs.vp + OPB->_int))->vector[2]; + break; + + case OP_IFNOT: + if (!OPA->_int) + { + prog->xfunction->profile += (st - startst); + st += st->b - 1; // offset the s++ + startst = st; + if (++jumpcount == 10000000) + { + prog->xstatement = st - prog->statements; + PRVM_Profile(1<<30, 1000000); + PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", jumpcount, PRVM_NAME); + } + } + break; + + case OP_IF: + if (OPA->_int) + { + prog->xfunction->profile += (st - startst); + st += st->b - 1; // offset the s++ + startst = st; + if (++jumpcount == 10000000) + { + prog->xstatement = st - prog->statements; + PRVM_Profile(1<<30, 1000000); + PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", jumpcount, PRVM_NAME); + } + } + break; + + case OP_GOTO: + prog->xfunction->profile += (st - startst); + st += st->a - 1; // offset the s++ + startst = st; + if (++jumpcount == 10000000) + { + prog->xstatement = st - prog->statements; + PRVM_Profile(1<<30, 1000000); + PRVM_ERROR("runaway loop counter hit limit of %d jumps\ntip: read above for list of most-executed functions", jumpcount, PRVM_NAME); + } + break; + case OP_CALL0: + case OP_CALL1: + case OP_CALL2: + case OP_CALL3: + case OP_CALL4: + case OP_CALL5: + case OP_CALL6: + case OP_CALL7: + case OP_CALL8: + prog->xfunction->profile += (st - startst); + startst = st; + prog->xstatement = st - prog->statements; + prog->argc = st->op - OP_CALL0; + if (!OPA->function) PRVM_ERROR("NULL function in %s", PRVM_NAME); + + newf = &prog->functions[OPA->function]; + newf->callcount++; + + if (newf->first_statement < 0) + { + // negative statements are built in functions + int builtinnumber = -newf->first_statement; + prog->xfunction->builtinsprofile++; + if (builtinnumber < prog->numbuiltins && prog->builtins[builtinnumber]) + prog->builtins[builtinnumber](); + else PRVM_ERROR("No such builtin #%i in %s", builtinnumber, PRVM_NAME); + } + else st = prog->statements + PRVM_EnterFunction(newf); + startst = st; + break; + + case OP_DONE: + case OP_RETURN: + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + + prog->globals.generic[OFS_RETURN+0] = prog->globals.generic[(word) st->a+0]; + prog->globals.generic[OFS_RETURN+1] = prog->globals.generic[(word) st->a+1]; + prog->globals.generic[OFS_RETURN+2] = prog->globals.generic[(word) st->a+2]; + + st = prog->statements + PRVM_LeaveFunction(); + startst = st; + if (prog->depth <= exitdepth) + return; // all done + if (prog->trace != cachedpr_trace) + goto chooseexecprogram; + break; + + case OP_STATE: + if(prog->flag & PRVM_OP_STATE) + { + ed = PRVM_PROG_TO_EDICT(PRVM_G_INT(prog->self->ofs)); + PRVM_E_FLOAT(ed, PRVM_ED_FindField ("nextthink")->ofs) = *prog->time + 0.1; + PRVM_E_FLOAT(ed, PRVM_ED_FindField ("frame")->ofs) = OPA->_float; + *(func_t *)((float*)ed->progs.vp + PRVM_ED_FindField ("think")->ofs) = OPB->function; + } + else + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR("OP_STATE not supported by %s", PRVM_NAME); + } + break; + +// LordHavoc: to be enabled when Progs version 7 (or whatever it will be numbered) is finalized +#if 0 + case OP_ADD_I: + OPC->_int = OPA->_int + OPB->_int; + break; + case OP_ADD_IF: + OPC->_int = OPA->_int + (int) OPB->_float; + break; + case OP_ADD_FI: + OPC->_float = OPA->_float + (float) OPB->_int; + break; + case OP_SUB_I: + OPC->_int = OPA->_int - OPB->_int; + break; + case OP_SUB_IF: + OPC->_int = OPA->_int - (int) OPB->_float; + break; + case OP_SUB_FI: + OPC->_float = OPA->_float - (float) OPB->_int; + break; + case OP_MUL_I: + OPC->_int = OPA->_int * OPB->_int; + break; + case OP_MUL_IF: + OPC->_int = OPA->_int * (int) OPB->_float; + break; + case OP_MUL_FI: + OPC->_float = OPA->_float * (float) OPB->_int; + break; + case OP_MUL_VI: + OPC->vector[0] = (float) OPB->_int * OPA->vector[0]; + OPC->vector[1] = (float) OPB->_int * OPA->vector[1]; + OPC->vector[2] = (float) OPB->_int * OPA->vector[2]; + break; + case OP_DIV_VF: + { + float temp = 1.0f / OPB->_float; + OPC->vector[0] = temp * OPA->vector[0]; + OPC->vector[1] = temp * OPA->vector[1]; + OPC->vector[2] = temp * OPA->vector[2]; + } + break; + case OP_DIV_I: + OPC->_int = OPA->_int / OPB->_int; + break; + case OP_DIV_IF: + OPC->_int = OPA->_int / (int) OPB->_float; + break; + case OP_DIV_FI: + OPC->_float = OPA->_float / (float) OPB->_int; + break; + case OP_CONV_ITOF: + OPC->_float = OPA->_int; + break; + case OP_CONV_FTOI: + OPC->_int = OPA->_float; + break; + case OP_BITAND_I: + OPC->_int = OPA->_int & OPB->_int; + break; + case OP_BITOR_I: + OPC->_int = OPA->_int | OPB->_int; + break; + case OP_BITAND_IF: + OPC->_int = OPA->_int & (int)OPB->_float; + break; + case OP_BITOR_IF: + OPC->_int = OPA->_int | (int)OPB->_float; + break; + case OP_BITAND_FI: + OPC->_float = (int)OPA->_float & OPB->_int; + break; + case OP_BITOR_FI: + OPC->_float = (int)OPA->_float | OPB->_int; + break; + case OP_GE_I: + OPC->_float = OPA->_int >= OPB->_int; + break; + case OP_LE_I: + OPC->_float = OPA->_int <= OPB->_int; + break; + case OP_GT_I: + OPC->_float = OPA->_int > OPB->_int; + break; + case OP_LT_I: + OPC->_float = OPA->_int < OPB->_int; + break; + case OP_AND_I: + OPC->_float = OPA->_int && OPB->_int; + break; + case OP_OR_I: + OPC->_float = OPA->_int || OPB->_int; + break; + case OP_GE_IF: + OPC->_float = (float)OPA->_int >= OPB->_float; + break; + case OP_LE_IF: + OPC->_float = (float)OPA->_int <= OPB->_float; + break; + case OP_GT_IF: + OPC->_float = (float)OPA->_int > OPB->_float; + break; + case OP_LT_IF: + OPC->_float = (float)OPA->_int < OPB->_float; + break; + case OP_AND_IF: + OPC->_float = (float)OPA->_int && OPB->_float; + break; + case OP_OR_IF: + OPC->_float = (float)OPA->_int || OPB->_float; + break; + case OP_GE_FI: + OPC->_float = OPA->_float >= (float)OPB->_int; + break; + case OP_LE_FI: + OPC->_float = OPA->_float <= (float)OPB->_int; + break; + case OP_GT_FI: + OPC->_float = OPA->_float > (float)OPB->_int; + break; + case OP_LT_FI: + OPC->_float = OPA->_float < (float)OPB->_int; + break; + case OP_AND_FI: + OPC->_float = OPA->_float && (float)OPB->_int; + break; + case OP_OR_FI: + OPC->_float = OPA->_float || (float)OPB->_int; + break; + case OP_NOT_I: + OPC->_float = !OPA->_int; + break; + case OP_EQ_I: + OPC->_float = OPA->_int == OPB->_int; + break; + case OP_EQ_IF: + OPC->_float = (float)OPA->_int == OPB->_float; + break; + case OP_EQ_FI: + OPC->_float = OPA->_float == (float)OPB->_int; + break; + case OP_NE_I: + OPC->_float = OPA->_int != OPB->_int; + break; + case OP_NE_IF: + OPC->_float = (float)OPA->_int != OPB->_float; + break; + case OP_NE_FI: + OPC->_float = OPA->_float != (float)OPB->_int; + break; + case OP_STORE_I: + OPB->_int = OPA->_int; + break; + case OP_STOREP_I: + if (prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int + 4 > prog->edictareasize)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to write to an out of bounds edict", PRVM_NAME); + return; + } + ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int); + ptr->_int = OPA->_int; + break; + case OP_LOAD_I: + if (prvm_boundscheck->value && (OPA->edict < 0 || OPA->edict >= prog->edictareasize)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME); + return; + } + if (OPB->_int < 0 || OPB->_int >= prog->progs->entityfields) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME); + return; + } + ed = PRVM_PROG_TO_EDICT(OPA->edict); + OPC->_int = ((prvm_eval_t *)((int *)ed->progs.vp + OPB->_int))->_int; + break; + + case OP_GSTOREP_I: + case OP_GSTOREP_F: + case OP_GSTOREP_ENT: + case OP_GSTOREP_FLD: // integers + case OP_GSTOREP_S: + case OP_GSTOREP_FNC: // pointers + if (prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int >= (uint)prog->progs->numglobaldefs)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME); + return; + } + prog->globals.generic[OPB->_int] = OPA->_float; + break; + + case OP_GSTOREP_V: + if (prvm_boundscheck->value && (OPB->_int < 0 || OPB->_int + 2 >= (uint)prog->progs->numglobaldefs)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME); + return; + } + prog->globals.generic[OPB->_int+0] = OPA->vector[0]; + prog->globals.generic[OPB->_int+1] = OPA->vector[1]; + prog->globals.generic[OPB->_int+2] = OPA->vector[2]; + break; + + case OP_GLOBALADDRESS: + i = OPA->_int + (int)OPB->_float; + if (prvm_boundscheck->value && (i < 0 || i >= (uint)prog->progs->numglobaldefs)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to address an out of bounds global", PRVM_NAME); + return; + } + OPC->_float = prog->globals.generic[i]; + break; + + case OP_LOADA_I: + case OP_LOADA_F: + case OP_LOADA_FLD: + case OP_LOADA_ENT: + case OP_LOADA_S: + case OP_LOADA_FNC: + if (prvm_boundscheck->value && (OPA->_int < 0 || OPA->_int >= (uint)prog->progs->numglobaldefs)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME); + return; + } + OPC->_float = prog->globals.generic[OPA->_int]; + break; + + case OP_LOADA_V: + if (prvm_boundscheck->value && (OPA->_int < 0 || OPA->_int + 2 >= (uint)prog->progs->numglobaldefs)) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME); + return; + } + OPC->vector[0] = prog->globals.generic[OPA->_int+0]; + OPC->vector[1] = prog->globals.generic[OPA->_int+1]; + OPC->vector[2] = prog->globals.generic[OPA->_int+2]; + break; + + case OP_BOUNDCHECK: + if (OPA->_int < 0 || OPA->_int >= st->b) + { + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c); + return; + } + break; +#endif + default: + prog->xfunction->profile += (st - startst); + prog->xstatement = st - prog->statements; + PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME); + } + } +} diff --git a/engine/engine.dsp b/engine/engine.dsp index ccd7f80a..dfd85a78 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -300,6 +300,18 @@ SOURCE=.\vid_dll.c SOURCE=.\vid_menu.c # End Source File +# Begin Source File + +SOURCE=.\common\vm_cmds.c +# End Source File +# Begin Source File + +SOURCE=.\common\vm_edict.c +# End Source File +# Begin Source File + +SOURCE=.\common\vm_exec.c +# End Source File # End Group # Begin Group "Header Files" @@ -350,6 +362,14 @@ SOURCE=..\public\platform.h # End Source File # Begin Source File +SOURCE=.\progdefs.h +# End Source File +# Begin Source File + +SOURCE=.\common\progsvm.h +# End Source File +# Begin Source File + SOURCE=.\common\qmenu.h # End Source File # Begin Source File @@ -372,6 +392,10 @@ SOURCE=.\sound.h SOURCE=.\common\vid.h # End Source File +# Begin Source File + +SOURCE=.\common\vm_cmds.h +# End Source File # End Group # End Target # End Project diff --git a/engine/engine.h b/engine/engine.h index de776f53..ed5ec14d 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -23,7 +23,7 @@ #include "sprite.h" #include "bspmodel.h" #include -#include "bspmodel.h" +#include "vprogs.h" #include "const.h" #include "common.h" #include "cvar.h" @@ -127,6 +127,7 @@ filesystem manager #define FS_FileBase( x, y ) Com->Fs.FileBase( x, y ) #define FS_Find( x ) Com->Fs.Search( x, false ) #define FS_Printf Com->Fs.Printf +#define FS_Print Com->Fs.Print #define FS_Seek Com->Fs.Seek #define FS_Tell Com->Fs.Tell #define FS_Gets Com->Fs.Gets @@ -199,4 +200,12 @@ System utilites */ void Sys_Error( const char *msg, ... ); +// +// in_win.c +// +extern int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +// vm_exec.c +void PRVM_Init (void); + #endif//ENGINE_H \ No newline at end of file diff --git a/engine/host.c b/engine/host.c index 4a6ba0a4..d13efe25 100644 --- a/engine/host.c +++ b/engine/host.c @@ -106,6 +106,7 @@ void Host_Init (char *funcname, int argc, char **argv) Cmd_Init (); Cvar_Init (); Key_Init (); + PRVM_Init(); // we need to add the early commands twice, because // a basedir or cddir needs to be set before execing diff --git a/engine/progdefs.h b/engine/progdefs.h new file mode 100644 index 00000000..36f09c05 --- /dev/null +++ b/engine/progdefs.h @@ -0,0 +1,183 @@ +#ifndef PROGDEFS_H +#define PROGDEFS_H + +typedef struct globalvars_s +{ + int pad[28]; // parms offsets + + // pointers to ents + int pev; // Pointer EntVars (same as self) + int other; + int world; + + // timer + float time; + float frametime; + + // map global info + string_t mapname; // map name + string_t startspot; // landmark name (new map position - get by name) + vec3_t spotoffset; // landmark offset (old map position) + + // gameplay modes + float deathmatch; + float coop; + float teamplay; + + float serverflags; //server flags + + // game info + float total_secrets; + float total_monsters; + float found_secrets; + float killed_monsters; + + // AngleVectors result + vec3_t v_forward; + vec3_t v_right; + vec3_t v_up; + + // SV_trace result + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vec3_t trace_endpos; + vec3_t trace_plane_normal; + float trace_plane_dist; + float trace_hitgroup; // studio model hitgroup number + float trace_contents; + int trace_ent; + float trace_flags; // misc info + + // game_export_s + func_t main; // Init + func_t StartFrame; // RunFrame + func_t EndFrame; // EndFrame + func_t PlayerPreThink; // ClientThink + func_t PlayerPostThink; // ClientThink + func_t ClientKill; // ??? + func_t ClientConnect; // ClientConnect + func_t PutClientInServer; // ClientBegin + func_t ClientDisconnect; // ClientDisconnect + func_t SetNewParms; // ??? + func_t SetChangeParms; // ??? + +} globalvars_t; + +typedef struct entvars_s +{ + // base entity info + string_t classname; + string_t globalname; + float modelindex; + + // physics description + vec3_t origin; + vec3_t angles; + vec3_t velocity; + vec3_t avelocity; + vec3_t post_origin; + vec3_t post_angles; + vec3_t post_velocity; + vec3_t post_avelocity; + vec3_t origin_offset; + vec3_t angles_offset; + + float bouncetype; + float movetype; + float solid; + vec3_t absmin, absmax; + vec3_t mins, maxs; + vec3_t size; + + // entity base description + int chain; // dynamic list of all ents + string_t model; + float frame; + float sequence; + float renderfx; + float effects; + float skin; + float body; + string_t weaponmodel; + float weaponframe; + + // base generic funcs + func_t use; + func_t touch; + func_t think; + func_t blocked; + func_t activate; + + // npc generic funcs + func_t walk; + func_t jump; + func_t duck; + + // flags + float flags; + float aiflags; + float spawnflags; + + // other variables + int groundentity; + float nextthink; + float takedamage; + float health; + + float frags; + float weapon; + float items; + string_t target; + string_t parent; + string_t targetname; + int aiment; // attachment edict + int goalentity; + vec3_t punchangle; + float deadflag; + vec3_t view_ofs; //int viewheight; + float button0; + float button1; + float button2; + float impulse; + float fixangle; + vec3_t v_angle; + float idealpitch; + string_t netname; + int enemy; + float colormap; + float team; + float max_health; + float teleport_time; + float armortype; + float armorvalue; + float waterlevel; + float watertype; + float ideal_yaw; + float yaw_speed; + float dmg_take; + float dmg_save; + int dmg_inflictor; + int owner; + vec3_t movedir; + string_t message; + float sounds; + string_t noise; + string_t noise1; + string_t noise2; + string_t noise3; + float jumpup; + float jumpdn; + int movetarget; + float mass; + float density; + float gravity; + float dmg; + float dmgtime; + float speed; + +} entvars_t; + +#define PROG_CRC_SERVER 63599 + +#endif//PROGDEFS_H \ No newline at end of file diff --git a/engine/server/ref_server.h b/engine/server/ref_server.h deleted file mode 100644 index f0064f5f..00000000 --- a/engine/server/ref_server.h +++ /dev/null @@ -1,191 +0,0 @@ - -// game.h -- game dll information visible to server -#include "savefile.h" - -#define GAME_API_VERSION 3 - -#define FL_TRACKTRAIN 0x00008000 - -// edict->svflags - -#define SVF_NOCLIENT 0x00000001 // don't send entity to clients, even if it has effects -#define SVF_DEADMONSTER 0x00000002 // treat as CONTENTS_DEADMONSTER for collision -#define SVF_MONSTER 0x00000004 // treat as CONTENTS_MONSTER for collision - -#define AI_NOSTEP 0x00000400 -#define AI_DUCKED 0x00000800 - - -#define AI_ACTOR 0x00040000 - -// edict->solid values -typedef enum -{ -SOLID_NOT, // 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_t; - -typedef enum { - F_INT, - F_FLOAT, - F_LSTRING, // string on disk, pointer in memory, TAG_LEVEL - F_GSTRING, // string on disk, pointer in memory, TAG_GAME - F_VECTOR, - F_ANGLEHACK, - F_EDICT, // index on disk, pointer in memory - F_ITEM, // index on disk, pointer in memory - F_CLIENT, // index on disk, pointer in memory - F_FUNCTION, - F_MMOVE, - F_IGNORE -} fieldtype_t; - -typedef struct -{ - char *name; - int ofs; - fieldtype_t type; - int flags; -} field_t; - -typedef struct -{ - char *name; - void (*spawn)(edict_t *ent); -} spawn_t; - -//=============================================================== - -// link_t is only used for entity area links now -typedef struct link_s -{ - struct link_s *prev, *next; -} link_t; - -#define MAX_ENT_CLUSTERS 16 - -struct gclient_s -{ - player_state_t ps; // communicated by server to clients - int ping; - - pmove_state_t old_pmove; // for detecting out-of-pmove changes - vec3_t v_angle; // aiming direction - - vec3_t oldviewangles; - vec3_t oldvelocity; - - float bobtime; // so off-ground doesn't change it - - // the game dll can add anything it wants after - // this point in the structure -}; - -typedef struct monsterinfo_s -{ - int aiflags; - - float jumpup; - float jumpdn; - - void (*jump)(edict_t *self); - -} monsterinfo_t; - -struct edict_s -{ - entity_state_t s; - struct gclient_s *client; - bool inuse; - int linkcount; - - // FIXME: move these fields to a server private sv_entity_t - link_t area; // linked to a division node or leaf - - int num_clusters; // if -1, use headnode instead - int clusternums[MAX_ENT_CLUSTERS]; - int headnode; // unused if num_clusters != -1 - int areanum, areanum2; - - //================================ - - int svflags; // SVF_NOCLIENT, SVF_DEADMONSTER, SVF_MONSTER, etc - vec3_t mins, maxs; - vec3_t absmin, absmax, size; - solid_t solid; - int clipmask; - edict_t *owner; - - // added for engine - char *classname; - int spawnflags; - - int movetype; - int flags; - - char *model; - float freetime; // sv.time when the object was freed - - vec3_t velocity; - vec3_t avelocity; - vec3_t origin_offset; - - int health; - - float nextthink; - void (*prethink) (edict_t *ent); - void (*think)(edict_t *self); - void (*blocked)(edict_t *self, edict_t *other); //move to moveinfo? - void (*touch)(edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf); - void (*use)(edict_t *self, edict_t *other, edict_t *activator); - - edict_t *enemy; - edict_t *goalentity; - edict_t *movetarget; - - float teleport_time; - - int watertype; - int waterlevel; - int viewheight; - - monsterinfo_t monsterinfo; - - vec3_t movedir; - edict_t *groundentity; - int groundentity_linkcount; - int mass; - - float gravity_debounce_time; - float gravity; - - int takedamage; - int dmg; - - vec3_t move_origin; - vec3_t move_angles; - - vec3_t oldvelocity; - - float speed; - float density; - float volume; // precalculated size scale - float bob; // bobbing in water amplitude - float duration; - int bobframe; - int bouncetype; -}; - -typedef struct game_export_s -{ - edict_t *edicts; - int edict_size; - int client_size; - int num_edicts; // current number, <= max_edicts - int max_edicts; - -} game_export_t; - -//dll handle diff --git a/engine/server/server.h b/engine/server/server.h index 52b5dd62..d651fe11 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -18,102 +18,95 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // server.h +#ifndef SERVER_H +#define SERVER_H - -//define PARANOID // speed sapping error checking - -#include "ref_server.h" - +#include "progsvm.h" +#include "vm_cmds.h" //============================================================================= -typedef struct +#define MAX_MASTERS 8 // max recipients for heartbeat packets +#define LATENCY_COUNTS 16 +#define RATE_MESSAGES 10 + +typedef enum { - gclient_t *clients; // [maxclients] - - int maxclients; - int maxentities; - - bool autosaved; -} game_locals_t; - -#define MAX_MASTERS 8 // max recipients for heartbeat packets - -typedef enum { - ss_dead, // no map loaded - ss_loading, // spawning level edicts - ss_game, // actively running + ss_dead, // no map loaded + ss_loading, // spawning level edicts + ss_game, // actively running ss_cinematic, ss_demo, ss_pic + } server_state_t; -// some qc commands are only valid before the server has finished -// initializing (precache commands, static sounds / objects, etc) + +typedef enum +{ + cs_free, // can be reused for a new connection + cs_zombie, // client has been disconnected, but don't reuse connection for a couple seconds + cs_connected, // has been assigned to a client_t, but not in game yet + cs_spawned // client is fully in game + +} client_state_t; typedef struct { - server_state_t state; // precache commands are only valid during load + server_state_t state; // precache commands are only valid during load - bool attractloop; // running cinematics and demos for the local system only - bool loadgame; // client begins should reuse existing entity + bool attractloop; // running cinematics and demos for the local system only + bool loadgame; // client begins should reuse existing entity - float time; // always sv.framenum * 100 msec + float time; // always sv.framenum * 100 msec int framenum; float frametime; - char name[MAX_QPATH]; // map name, or cinematic name - struct cmodel_s *models[MAX_MODELS]; + char name[MAX_QPATH]; // map name, or cinematic name + struct cmodel_s *models[MAX_MODELS]; char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; entity_state_t baselines[MAX_EDICTS]; // the multicast buffer is used to send a message to a set of clients // it is only used to marshall data until SV_Message is called - sizebuf_t multicast; + sizebuf_t multicast; byte multicast_buf[MAX_MSGLEN]; // demo server information file_t *demofile; bool timedemo; // don't time sync - byte *mempool; + float lastchecktime; + int lastcheck; + + // global + edict_t **edicts; // [max_edicts] + gclient_t *clients; // [maxclients] + + bool autosaved; } server_t; -#define EDICT_NUM(n) ((edict_t *)((byte *)ge->edicts + ge->edict_size * (n) )) -#define NUM_FOR_EDICT(e) ( ((byte *)(e) - (byte *)ge->edicts ) / ge->edict_size) - -typedef enum -{ - cs_free, // can be reused for a new connection - cs_zombie, // client has been disconnected, but don't reuse - // connection for a couple seconds - cs_connected, // has been assigned to a client_t, but not in game yet - cs_spawned // client is fully in game -} client_state_t; - typedef struct { - int areabytes; - byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits - player_state_t ps; - int num_entities; - int first_entity; // into the circular sv_packet_entities[] - float senttime; // for ping calculations -} client_frame_t; + int areabytes; + byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits + player_state_t ps; + int num_entities; + int first_entity; // into the circular sv_packet_entities[] + float senttime; // for ping calculations -#define LATENCY_COUNTS 16 -#define RATE_MESSAGES 10 +} client_frame_t; typedef struct client_s { client_state_t state; - char userinfo[MAX_INFO_STRING]; // name, etc + char userinfo[MAX_INFO_STRING]; // name, etc - int lastframe; // for delta compression + int lastframe; // for delta compression usercmd_t lastcmd; // for filling in big drops int commandMsec; // every seconds this is reset, if user - // commands exhaust it, assume time cheating + // commands exhaust it, assume time cheating int frame_latency[LATENCY_COUNTS]; int ping; @@ -122,7 +115,7 @@ typedef struct client_s int rate; int surpressCount; // number of messages rate supressed - edict_t *edict; // EDICT_NUM(clientnum+1) + edict_t *edict; // EDICT_NUM(clientnum+1) char name[32]; // extracted from userinfo, high bits masked int messagelevel; // for filtering printed messages @@ -133,25 +126,27 @@ typedef struct client_s client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here - byte *download; // file being downloaded + byte *download; // file being downloaded int downloadsize; // total bytes (can't use EOF because of paks) int downloadcount; // bytes sent float lastmessage; // sv.framenum when packet was last received float lastconnect; - int challenge; // challenge of this user, randomly generated + int challenge; // challenge of this user, randomly generated netchan_t netchan; } client_t; -// a client can leave the server in one of four ways: -// dropping properly by quiting or disconnecting -// timing out if no valid messages are received for timeout.value seconds -// getting kicked off by the server operator -// a program error, like an overflowed reliable buffer - -//============================================================================= +/* +============================================================================= + a client can leave the server in one of four ways: + dropping properly by quiting or disconnecting + timing out if no valid messages are received for timeout.value seconds + getting kicked off by the server operator + a program error, like an overflowed reliable buffer +============================================================================= +*/ // MAX_CHALLENGES is made large to prevent a denial // of service attack that could cycle all of them @@ -163,21 +158,21 @@ typedef struct netadr_t adr; int challenge; float time; -} challenge_t; +} challenge_t; typedef struct { - bool initialized; // sv_init has completed - float realtime; // always increasing, no clamping, etc + bool initialized; // sv_init has completed + float realtime; // always increasing, no clamping, etc char mapcmd[MAX_TOKEN_CHARS]; // ie: *intro.cin+base char comment[MAX_TOKEN_CHARS]; // map name, e.t.c. - int spawncount; // incremented each server start - // used to check late spawns + int spawncount; // incremented each server start + // used to check late spawns - client_t *clients; // [maxclients->value]; + client_t *clients; // [maxclients->value]; int num_client_entities; // maxclients->value*UPDATE_BACKUP*MAX_PACKET_ENTITIES int next_client_entities; // next client_entity to use entity_state_t *client_entities; // [num_client_entities] @@ -197,45 +192,40 @@ typedef struct extern netadr_t net_from; extern sizebuf_t net_message; -extern netadr_t master_adr[MAX_MASTERS]; // address of the master server +extern netadr_t master_adr[MAX_MASTERS]; // address of the master server -extern server_static_t svs; // persistant server info -extern server_t sv; // local server +extern server_static_t svs; // persistant server info +extern server_t sv; // local server extern cvar_t *sv_paused; extern cvar_t *maxclients; -extern cvar_t *sv_noreload; // don't reload level state when reentering +extern cvar_t *sv_noreload; // don't reload level state when reentering extern cvar_t *sv_airaccelerate; // don't reload level state when reentering extern cvar_t *sv_maxvelocity; extern cvar_t *sv_gravity; - // development tool + // development tool extern cvar_t *sv_enforcetime; extern client_t *sv_client; extern edict_t *sv_player; -extern game_locals_t game; + //=========================================================== - // // sv_main.c // void SV_FinalMessage (char *message, bool reconnect); void SV_DropClient (client_t *drop); -int SV_ModelIndex (char *name); -int SV_SoundIndex (char *name); -int SV_ImageIndex (char *name); +int SV_ModelIndex (const char *name); +int SV_SoundIndex (const char *name); +int SV_ImageIndex (const char *name); void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); - void SV_ExecuteUserCommand (char *s); void SV_InitOperatorCommands (void); - void SV_SendServerinfo (client_t *client); void SV_UserinfoChanged (client_t *cl); - - void Master_Heartbeat (void); void Master_Packet (void); @@ -244,7 +234,9 @@ void Master_Packet (void); // void SV_InitGame (void); void SV_Map (bool attractloop, char *levelstring, char *savename, bool loadgame); - +void SV_VM_Setup(void); +void SV_VM_Begin(void); +void SV_VM_End(void); // // sv_phys.c @@ -260,15 +252,13 @@ void SV_CheckGround (edict_t *ent); typedef enum {RD_NONE, RD_CLIENT, RD_PACKET} redirect_t; #define SV_OUTPUTBUF_LENGTH (MAX_MSGLEN - 16) -extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; +extern char sv_outputbuf[SV_OUTPUTBUF_LENGTH]; void SV_FlushRedirect (int sv_redirected, char *outputbuf); void SV_DemoCompleted (void); void SV_SendClientMessages (void); -void SV_StartSound (vec3_t origin, edict_t *entity, int channel, - int soundindex, float volume, - float attenuation, float timeofs); +void SV_StartSound (vec3_t origin, edict_t *entity, int channel, int index, float vol, float attn, float timeofs); void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...); void SV_BroadcastPrintf (int level, char *fmt, ...); void SV_BroadcastCommand (char *fmt, ...); @@ -290,38 +280,29 @@ void SV_Status_f (void); void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg); void SV_RecordDemoMessage (void); void SV_BuildClientFrame (client_t *client); - +void SV_FatPVS ( vec3_t org ); void SV_Error (char *error, ...); // // sv_game.c // -extern game_export_t *ge; - void SV_InitGameProgs (void); void SV_ShutdownGameProgs (void); void SV_InitEdict (edict_t *e); - -// misc game funcs -void PF_error (char *fmt, ...); -void PF_Configstring (int index, char *val); -void PF_setmodel (edict_t *ent, char *name); -void PF_cprintf (edict_t *ent, int level, char *fmt, ...); -bool PF_inPVS (vec3_t p1, vec3_t p2); -void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume, float attenuation, float timeofs); +void SV_ConfigString (int index, const char *val); +void SV_SetModel (edict_t *ent, const char *name); +bool PF_inpvs (vec3_t p1, vec3_t p2); // // sv_studio.c // - byte *SV_GetModelPtr(edict_t *ent); int SV_StudioExtractBbox( studiohdr_t *phdr, int sequence, float *mins, float *maxs ); // // sv_spawn.c // - void SV_SpawnEntities (char *mapname, char *entities, char *spawnpoint); void SV_FreeEdict (edict_t *ed); void SV_InitEdict (edict_t *e); @@ -338,7 +319,6 @@ void SV_TouchTriggers (edict_t *ent); // // sv_save.c // - void SV_WriteSaveFile( char *name ); void SV_ReadSaveFile( char *name ); void SV_ReadLevelFile( char *name ); @@ -347,7 +327,6 @@ void SV_ReadLevelFile( char *name ); // // high level object sorting to reduce interaction tests // - void SV_ClearWorld (void); // called after the world model has been loaded, before linking any entities @@ -389,4 +368,5 @@ trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *p // if the starting point is in a solid, it will be allowed to move out // to an open area -// passedict is explicitly excluded from clipping checks (normally NULL) \ No newline at end of file +// passedict is explicitly excluded from clipping checks (normally NULL) +#endif//SERVER_H \ No newline at end of file diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index b4f9efae..5a009355 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -174,7 +174,7 @@ void SV_GameMap_f (void) char *map; int i; client_t *cl; - bool *savedInuse; + bool *savedFree; if (Cmd_Argc() != 2) { @@ -189,22 +189,22 @@ void SV_GameMap_f (void) // save the map just exited if (sv.state == ss_game) { - // clear all the client inuse flags before saving so that + // clear all the client free flags before saving so that // when the level is re-entered, the clients will spawn // at spawn points instead of occupying body shells - savedInuse = Z_Malloc(maxclients->value * sizeof(bool)); + savedFree = Z_Malloc(maxclients->value * sizeof(bool)); for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { - savedInuse[i] = cl->edict->inuse; - cl->edict->inuse = false; + savedFree[i] = cl->edict->priv.sv->free; + cl->edict->priv.sv->free = true; } SV_WriteSaveFile( "save0" ); //autosave // we must restore these for clients to transfer over correctly for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) - cl->edict->inuse = savedInuse[i]; - Z_Free (savedInuse); + cl->edict->priv.sv->free = savedFree[i]; + Z_Free (savedFree); } } @@ -309,7 +309,7 @@ void SV_Savegame_f (void) return; } - if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0) + if (maxclients->value == 1 && svs.clients[0].edict->priv.sv->client->ps.stats[STAT_HEALTH] <= 0) { Msg ("\nCan't savegame while dead!\n"); return; @@ -381,7 +381,7 @@ void SV_Status_f (void) { if (!cl->state) continue; Msg ("%3i ", i); - Msg ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]); + Msg ("%5i ", cl->edict->priv.sv->client->ps.stats[STAT_FRAGS]); if (cl->state == cs_connected) Msg ("CNCT "); @@ -626,11 +626,7 @@ Let the game dll handle a command */ void SV_ServerCommand_f (void) { - if (!ge) - { - Msg ("No game loaded.\n"); - return; - } + Msg ("No game loaded.\n"); } //=========================================================== diff --git a/engine/server/sv_edict.h b/engine/server/sv_edict.h new file mode 100644 index 00000000..1a5f81e2 --- /dev/null +++ b/engine/server/sv_edict.h @@ -0,0 +1,77 @@ +//======================================================================= +// Copyright XashXT Group 2007 © +// sv_edict.h - server prvm edict +//======================================================================= +#ifndef SV_EDICT_H +#define SV_EDICT_H + +// game.h -- game dll information visible to server +#include "savefile.h" + +#define MAX_ENT_CLUSTERS 16 + +#define AI_FLY (1<<0) // monster is flying +#define AI_SWIM (1<<1) // swimming monster +#define AI_ONGROUND (1<<2) // monster is onground +#define AI_PARTIALONGROUND (1<<3) // monster is partially onground +#define AI_GODMODE (1<<4) // monster don't give damage at all +#define AI_NOTARGET (1<<5) // monster will no searching enemy's +#define AI_NOSTEP (1<<6) // Lazarus stuff +#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 +#define AI_ACTOR (1<<10) // disable ai for actor +#define AI_DRIVER (1<<11) // npc or player driving vehcicle or train +#define AI_SPECTATOR (1<<12) // spectator mode for clients + +// edict->solid values +typedef enum +{ +SOLID_NOT, // 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_t; + +// link_t is only used for entity area links now +typedef struct link_s +{ + struct link_s *prev; + struct link_s *next; + int entnum; // get edict by number +} link_t; + +struct gclient_s +{ + player_state_t ps; // communicated by server to clients + int ping; + + pmove_state_t old_pmove; // for detecting out-of-pmove changes + vec3_t v_angle; // aiming direction + + vec3_t oldviewangles; + vec3_t oldvelocity; + + float bobtime; // so off-ground doesn't change it +}; + +struct sv_edict_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 + int clipmask; // trace info + int headnode; // unused if num_clusters != -1 + int linkcount; + int num_clusters; // if -1, use headnode instead + int clusternums[MAX_ENT_CLUSTERS]; + int areanum, areanum2; + + // baselines + entity_state_t s; + struct gclient_s *client; //get rid of this +}; +#endif//SV_EDICT_H \ No newline at end of file diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index 8b1fffc0..ce317e66 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -550,7 +550,7 @@ void SV_BuildClientFrame (client_t *client) byte *bitvector; clent = client->edict; - if (!clent->client) return;// not in game yet + if (!clent->priv.sv->client) return;// not in game yet // this is the frame we are creating frame = &client->frames[sv.framenum & UPDATE_MASK]; @@ -559,7 +559,7 @@ void SV_BuildClientFrame (client_t *client) // find the client's PVS for (i=0 ; i<3 ; i++) - org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i]; + org[i] = clent->priv.sv->client->ps.pmove.origin[i]*0.125 + clent->priv.sv->client->ps.viewoffset[i]; leafnum = CM_PointLeafnum (org); clientarea = CM_LeafArea (leafnum); @@ -569,7 +569,7 @@ void SV_BuildClientFrame (client_t *client) frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea); // grab the current player_state_t - frame->ps = clent->client->ps; + frame->ps = clent->priv.sv->client->ps; SV_FatPVS (org); @@ -581,34 +581,29 @@ void SV_BuildClientFrame (client_t *client) c_fullsend = 0; - for (e = 1; e < ge->num_edicts ; e++) + for (e = 1; e < prog->num_edicts; e++) { - ent = EDICT_NUM(e); - - // ignore ents without visible models - if (ent->svflags & SVF_NOCLIENT) - continue; + ent = PRVM_EDICT_NUM(e); // ignore ents without visible models unless they have an effect - if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound && !ent->s.event) + if (!ent->priv.sv->s.modelindex && !ent->priv.sv->s.effects && !ent->priv.sv->s.sound && !ent->priv.sv->s.event) continue; // ignore if not touching a PV leaf if (ent != clent) { // check area - if (!CM_AreasConnected (clientarea, ent->areanum)) + if (!CM_AreasConnected (clientarea, ent->priv.sv->areanum)) { // doors can legally straddle two areas, so // we may need to check another one - if (!ent->areanum2 - || !CM_AreasConnected (clientarea, ent->areanum2)) + if (!ent->priv.sv->areanum2 || !CM_AreasConnected (clientarea, ent->priv.sv->areanum2)) continue; // blocked by a door } // beams just check one point for PHS - if (ent->s.renderfx & RF_BEAM) + if (ent->priv.sv->s.renderfx & RF_BEAM) { - l = ent->clusternums[0]; + l = ent->priv.sv->clusternums[0]; if ( !(clientphs[l >> 3] & (1 << (l&7) )) ) continue; } @@ -616,37 +611,38 @@ void SV_BuildClientFrame (client_t *client) { // FIXME: if an ent has a model and a sound, but isn't // in the PVS, only the PHS, clear the model - if (ent->s.sound) + if (ent->priv.sv->s.sound) { bitvector = fatpvs; //clientphs; } else bitvector = fatpvs; - if (ent->num_clusters == -1) - { // too many leafs for individual check, go by headnode - if (!CM_HeadnodeVisible (ent->headnode, bitvector)) + if (ent->priv.sv->num_clusters == -1) + { + // too many leafs for individual check, go by headnode + if (!CM_HeadnodeVisible (ent->priv.sv->headnode, bitvector)) continue; c_fullsend++; } else { // check individual leafs - for (i=0 ; i < ent->num_clusters ; i++) + for (i=0 ; i < ent->priv.sv->num_clusters ; i++) { - l = ent->clusternums[i]; + l = ent->priv.sv->clusternums[i]; if (bitvector[l >> 3] & (1 << (l&7) )) break; } - if (i == ent->num_clusters) + if (i == ent->priv.sv->num_clusters) continue; // not visible } - if (!ent->s.modelindex) + if (!ent->priv.sv->s.modelindex) { // don't send sounds if they will be attenuated away vec3_t delta; float len; - VectorSubtract (org, ent->s.origin, delta); + VectorSubtract (org, ent->priv.sv->s.origin, delta); len = VectorLength (delta); if (len > 400) continue; @@ -656,15 +652,15 @@ void SV_BuildClientFrame (client_t *client) // add it to the circular client_entities array state = &svs.client_entities[svs.next_client_entities % svs.num_client_entities]; - if (ent->s.number != e) + if (ent->priv.sv->s.number != e) { - MsgWarn ("SV_BuildClientFrame: invalid ent->s.number %d\n", ent->s.number ); - ent->s.number = e; // ptr to current entity such as entnumber + MsgWarn ("SV_BuildClientFrame: invalid ent->priv.sv->s.number %d\n", ent->priv.sv->s.number ); + ent->priv.sv->s.number = e; // ptr to current entity such as entnumber } - *state = ent->s; + *state = ent->priv.sv->s; // don't mark players missiles as solid - if (ent->owner == client->edict) state->solid = 0; + if (PRVM_PROG_TO_EDICT(ent->progs.sv->owner) == client->edict) state->solid = 0; svs.next_client_entities++; frame->num_entities++; @@ -702,18 +698,16 @@ void SV_RecordDemoMessage (void) MSG_WriteByte (&buf, svc_packetentities); e = 1; - ent = EDICT_NUM(e); - while (e < ge->num_edicts) + ent = PRVM_EDICT_NUM(e); + while (e < prog->num_edicts) { // ignore ents without visible models unless they have an effect - if (ent->inuse && - ent->s.number && - (ent->s.modelindex || ent->s.effects || ent->s.sound || ent->s.event) && - !(ent->svflags & SVF_NOCLIENT)) - MSG_WriteDeltaEntity (&nostate, &ent->s, &buf, false, true); + if (!ent->priv.sv->free && ent->priv.sv->s.number && + (ent->priv.sv->s.modelindex || ent->priv.sv->s.effects || ent->priv.sv->s.sound || ent->priv.sv->s.event)) + MSG_WriteDeltaEntity (&nostate, &ent->priv.sv->s, &buf, false, true); e++; - ent = EDICT_NUM(e); + ent = PRVM_EDICT_NUM(e); } MSG_WriteShort (&buf, 0); // end of packetentities diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index a73c7243..79fc6f2a 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -19,174 +19,488 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // sv_game.c -- interface to the game dll -#include #include "engine.h" #include "server.h" -game_export_t *ge; -HINSTANCE sv_library; -game_locals_t game; - /* -=============== -PF_dprintf +============== +PF_makevectors -Debug print to server console -=============== +Writes new values for v_forward, v_up, and v_right based on angles +makevectors(vector) +============== */ -void PF_dprintf (char *fmt, ...) +void PF_makevectors (void) { - char msg[1024]; - va_list argptr; - - va_start (argptr,fmt); - vsprintf (msg, fmt, argptr); - va_end (argptr); - - Msg ("%s", msg); + AngleVectors(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); } +void PF_makevectors2 (void) +{ + AngleVectorsFLU(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); +} /* -=============== -PF_cprintf +================= +PF_setorigin -Print to a single client -=============== +This is the only valid way to move an object without using the physics of the world (setting velocity and waiting). Directly changing origin will not set internal links correctly, so clipping would be messed up. This should be called when an object is spawned, and then only if it is teleported. + +setorigin (entity, origin) +================= */ -void PF_cprintf (edict_t *ent, int level, char *fmt, ...) +void PF_setorigin (void) { - char msg[1024]; - va_list argptr; - int n; + edict_t *e; + float *org; - if (ent) + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) { - n = NUM_FOR_EDICT(ent); - if (n < 1 || n > maxclients->value) - Host_Error("cprintf to a non-client\n"); - } - - va_start (argptr,fmt); - vsprintf (msg, fmt, argptr); - va_end (argptr); - - if (ent) - SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg); - else - Msg ("%s", msg); -} - - -/* -=============== -PF_centerprintf - -centerprint to a single client -=============== -*/ -void PF_centerprintf (edict_t *ent, char *fmt, ...) -{ - char msg[1024]; - va_list argptr; - int n; - - n = NUM_FOR_EDICT(ent); - if (n < 1 || n > maxclients->value) + VM_Warning("setorigin: can not modify world entity\n"); return; - - va_start (argptr,fmt); - vsprintf (msg, fmt, argptr); - va_end (argptr); - - MSG_Begin( svc_centerprint ); - MSG_WriteString (&sv.multicast, msg); - MSG_Send(MSG_ONE_R, NULL, ent ); + } + if (e->priv.sv->free) + { + VM_Warning("setorigin: can not modify free entity\n"); + return; + } + org = PRVM_G_VECTOR(OFS_PARM1); + VectorCopy (org, e->progs.sv->origin); + SV_LinkEdict (e); } +void 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("SetMinMaxSize: backwards mins/maxs"); + + // set derived values + VectorCopy (min, e->progs.sv->mins); + VectorCopy (max, e->progs.sv->maxs); + VectorSubtract (max, min, e->progs.sv->size); + + SV_LinkEdict (e); +} + + +//test for stats +void PF_SetStats( void ) +{ + edict_t *e; + int stat_num; + const char *string; + short value; + + e = PRVM_G_EDICT(OFS_PARM0); + + if(!e->priv.sv->client) return; + + stat_num = (int)PRVM_G_FLOAT(OFS_PARM1); + + if(stat_num < 0 || stat_num > MAX_STATS) return; + + string = PRVM_G_STRING(OFS_PARM2); + + switch(stat_num) + { + case STAT_HEALTH_ICON: + value = SV_ImageIndex( string ); + break; + case STAT_HEALTH: + value = atoi( string ); + break; + case STAT_HELPICON: + value = SV_ImageIndex( string ); + break; + default: + MsgWarn("unknown stat type %d\n", stat_num ); + return; + } + e->priv.sv->client->ps.stats[stat_num] = value; +} + /* -=============== -PF_error +================= +PF_setsize -Abort the server with a game error -=============== +the size box is rotated by the current angle +LordHavoc: no it isn't... + +setsize (entity, minvector, maxvector) +================= */ -void PF_error (char *fmt, ...) +void PF_setsize (void) { - char msg[1024]; - va_list argptr; - - va_start (argptr,fmt); - vsprintf (msg, fmt, argptr); - va_end (argptr); + edict_t *e; + float *min, *max; - Host_Error("Game Error: %s\n", msg); + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning("setsize: can not modify world entity\n"); + return; + } + if (e->priv.sv->free) + { + VM_Warning("setsize: can not modify free entity\n"); + return; + } + min = PRVM_G_VECTOR(OFS_PARM1); + max = PRVM_G_VECTOR(OFS_PARM2); + SetMinMaxSize (e, min, max, false); } +void SV_SetModel (edict_t *ent, const char *name) +{ + int i; + cmodel_t *mod; + + i = SV_ModelIndex( name ); + ent->progs.sv->model = PRVM_SetEngineString(sv.configstrings[CS_MODELS+i]); + ent->progs.sv->modelindex = ent->priv.sv->s.modelindex = i; + + mod = CM_LoadModel(sv.configstrings[CS_MODELS+i]); + if(mod) SetMinMaxSize( ent, mod->mins, mod->maxs, false ); +} /* ================= PF_setmodel -Also sets mins and maxs for inline bmodels +setmodel(entity, model) ================= */ -void PF_setmodel (edict_t *ent, char *name) +void PF_setmodel( void ) +{ + edict_t *e; + + e = PRVM_G_EDICT(OFS_PARM0); + if (e == prog->edicts) + { + VM_Warning("setmodel: can not modify world entity\n"); + return; + } + if (e->priv.sv->free) + { + VM_Warning("setmodel: can not modify free entity\n"); + return; + } + SV_SetModel( e, PRVM_G_STRING(OFS_PARM1) ); +} + +/* +================= +PF_sprint + +single print to a specific client + +sprint(clientent, value) +================= +*/ +void PF_sprint (void) +{ + client_t *client; + int num; + char string[VM_STRINGTEMP_LENGTH]; + + num = PRVM_G_EDICTNUM(OFS_PARM0); + + if (num < 1 || num > host.maxclients || svs.clients[num - 1].state != cs_spawned) + { + VM_Warning("tried to centerprint to a non-client\n"); + return; + } + + client = svs.clients + num-1; + + VM_VarString(1, string, sizeof(string)); + SV_ClientPrintf (client, PRINT_HIGH, "%s", string ); +} + + +/* +================= +PF_centerprint + +single print to a specific client + +centerprint(clientent, value) +================= +*/ +void PF_centerprint (void) +{ + client_t *client; + int num; + char string[VM_STRINGTEMP_LENGTH]; + + num = PRVM_G_EDICTNUM(OFS_PARM0); + + if(num < 1 || num > host.maxclients || svs.clients[num-1].state != cs_spawned) + { + VM_Warning("tried to centerprint to a non-client\n"); + return; + } + + client = svs.clients + num - 1; + + VM_VarString(1, string, sizeof(string)); + MSG_Begin( svc_centerprint ); + MSG_WriteString (&sv.multicast, string ); + MSG_Send(MSG_ONE_R, NULL, client->edict ); +} + +/* +================= +PF_particle + +particle(origin, color, count) +================= +*/ +void PF_particle (void) +{ + float *org, *dir; + float color; + float count; + + 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_ambientsound + +================= +*/ +void PF_ambientsound (void) +{ + const char *samp; + float *pos; + float vol, attenuation; + int soundnum, large; + + pos = PRVM_G_VECTOR (OFS_PARM0); + samp = PRVM_G_STRING(OFS_PARM1); + vol = PRVM_G_FLOAT(OFS_PARM2); + attenuation = PRVM_G_FLOAT(OFS_PARM3); + + // check to see if samp was properly precached + soundnum = SV_SoundIndex(samp); + if (!soundnum) return; + + large = false; + if (soundnum >= 256) large = true; + + // unsupported +} + +/* +================= +PF_sound + +Each entity can have eight independant sound sources, like voice, +weapon, feet, etc. + +Channel 0 is an auto-allocate channel, the others override anything +already running on that entity/channel pair. + +An attenuation of 0 will play full volume everywhere in the level. +Larger attenuations will drop off. + +================= +*/ +void PF_sound (void) +{ + const char *sample; + int channel, sound_idx; + edict_t *entity; + int volume; + float attenuation; + + entity = PRVM_G_EDICT(OFS_PARM0); + channel = (int)PRVM_G_FLOAT(OFS_PARM1); + sample = PRVM_G_STRING(OFS_PARM2); + volume = (int)(PRVM_G_FLOAT(OFS_PARM3) * 255); + attenuation = PRVM_G_FLOAT(OFS_PARM4); + + if (volume < 0 || volume > 255) + { + VM_Warning("SV_StartSound: volume must be in range 0-1\n"); + return; + } + + if (attenuation < 0 || attenuation > 4) + { + VM_Warning("SV_StartSound: attenuation must be in range 0-4\n"); + return; + } + + if (channel < 0 || channel > 7) + { + VM_Warning("SV_StartSound: channel must be in range 0-7\n"); + return; + } + + sound_idx = SV_SoundIndex( sample ); + SV_StartSound (NULL, entity, channel, sound_idx, volume, attenuation, 0 ); +} + +/* +================= +PF_traceline + +Used for use tracing and shot targeting +Traces are blocked by bbox and exact bsp entityes, and also slide box entities +if the tryents flag is set. + +traceline (vector1, vector2, tryents) +================= +*/ +void PF_traceline (void) +{ + float *v1, *v2; + trace_t trace; + int move; + edict_t *ent; + + 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, ent, MASK_ALL ); + + prog->globals.server->trace_allsolid = trace.allsolid; + prog->globals.server->trace_startsolid = trace.startsolid; + prog->globals.server->trace_fraction = trace.fraction; + prog->globals.server->trace_contents = trace.contents; + + VectorCopy (trace.endpos, prog->globals.server->trace_endpos); + VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal); + prog->globals.server->trace_plane_dist = trace.plane.dist; + if (trace.ent) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); + else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); +} + + +/* +================= +PF_tracebox + +Used for use tracing and shot targeting +Traces are blocked by bbox and exact bsp entityes, and also slide box entities +if the tryents flag is set. + +tracebox (vector1, vector mins, vector maxs, vector2, tryents) +================= +*/ +// LordHavoc: added this for my own use, VERY useful, similar to traceline +void PF_tracebox (void) +{ + float *v1, *v2, *m1, *m2; + trace_t trace; + int move; + edict_t *ent; + + 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, ent, MASK_ALL ); + + prog->globals.server->trace_allsolid = trace.allsolid; + prog->globals.server->trace_startsolid = trace.startsolid; + prog->globals.server->trace_fraction = trace.fraction; + prog->globals.server->trace_contents = trace.contents; + + VectorCopy (trace.endpos, prog->globals.server->trace_endpos); + VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal); + prog->globals.server->trace_plane_dist = trace.plane.dist; + + if (trace.ent) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); + else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); +} + +/* +================= +PF_checkpos + +Returns true if the given entity can move to the given position from it's +current position by walking or rolling. +FIXME: make work... +scalar checkpos (entity, vector) +================= +*/ +void PF_checkpos (void) +{ +} + +//============================================================================ +int PF_newcheckclient (int check) { int i; - cmodel_t *mod; - - if (!name) Host_Error("PF_setmodel: NULL\n"); + edict_t *ent; + vec3_t org; - i = SV_ModelIndex (name); - - ent->s.modelindex = i; - mod = CM_LoadModel (name); + // cycle to the next one + check = bound(1, check, host.maxclients); + if (check == host.maxclients) i = 1; + else i = check + 1; - if(mod) // hull setup + for (;; i++) { - VectorCopy (mod->mins, ent->mins); - VectorCopy (mod->maxs, ent->maxs); - SV_LinkEdict (ent); + // count the cost + prog->xfunction->builtinsprofile++; + // wrap around + if (i == host.maxclients + 1) i = 1; + // look up the client's edict + ent = PRVM_EDICT_NUM(i); + // check if it is to be ignored, but never ignore the one we started on (prevent infinite loop) + if (i != check && (ent->priv.sv->free || ent->progs.sv->health <= 0 || ((int)ent->progs.sv->aiflags & AI_NOTARGET))) + continue; + // found a valid client (possibly the same one again) + break; } -} -/* -=============== -PF_Configstring + // get the PVS for the entity + VectorAdd(ent->progs.sv->origin, ent->progs.sv->view_ofs, org); -=============== -*/ -void PF_Configstring (int index, char *val) -{ - if (index < 0 || index >= MAX_CONFIGSTRINGS) - Host_Error("PF_Configstring: bad index %i value %s\n", index, val); + SV_FatPVS( org ); // fat pvs manually - if (!val) val = ""; - - // change the string in sv - strcpy (sv.configstrings[index], val); - - if (sv.state != ss_loading) - { - // send the update to everyone - SZ_Clear (&sv.multicast); - MSG_Begin(svc_configstring); - MSG_WriteShort (&sv.multicast, index); - MSG_WriteString (&sv.multicast, val); - MSG_Send(MSG_ALL_R, vec3_origin, NULL ); - } + return i; } /* ================= -PF_inPVS +PF_inphs Also checks portalareas so that doors block sight ================= */ -bool PF_inPVS (vec3_t p1, vec3_t p2) +bool PF_inpvs (vec3_t p1, vec3_t p2) { int leafnum; int cluster; @@ -208,15 +522,14 @@ bool PF_inPVS (vec3_t p1, vec3_t p2) return true; } - /* ================= -PF_inPHS +PF_inphs Also checks portalareas so that doors block sound ================= */ -bool PF_inPHS (vec3_t p1, vec3_t p2) +bool PF_inphs (vec3_t p1, vec3_t p2) { int leafnum; int cluster; @@ -239,13 +552,1039 @@ bool PF_inPHS (vec3_t p1, vec3_t p2) return true; } -void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume, float attenuation, float timeofs) +/* +================= +PF_checkclient + +Returns a client (or object that has a client enemy) that would be a +valid target. + +If there is more than one valid option, they are cycled each frame + +If (self.origin + self.viewofs) is not in the PVS of the current target, +it is not returned at all. + +name checkclient () +================= +*/ +int c_invis, c_notvis; +void PF_checkclient (void) { - if (!entity) return; - SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs); + edict_t *ent, *self; + vec3_t view; + + // find a new check if on a new frame + if (sv.time - sv.lastchecktime >= 0.1) + { + sv.lastcheck = PF_newcheckclient (sv.lastcheck); + sv.lastchecktime = sv.time; + } + + // return check if it might be visible + ent = PRVM_EDICT_NUM(sv.lastcheck); + if (ent->priv.sv->free || ent->progs.sv->health <= 0) + { + VM_RETURN_EDICT(prog->edicts); + return; + } + + // if current entity can't possibly see the check entity, return 0 + self = PRVM_PROG_TO_EDICT(prog->globals.server->pev); + VectorAdd(self->progs.sv->origin, self->progs.sv->view_ofs, view); + + if (!PF_inpvs(view, view)) + { + c_notvis++; + VM_RETURN_EDICT(prog->edicts); + return; + } + + // might be able to see it + c_invis++; + VM_RETURN_EDICT(ent); } -//============================================== +//============================================================================ +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 + strcpy (sv.configstrings[index], val); + + if (sv.state != ss_loading) + { + // send the update to everyone + SZ_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 ); + } +} + +/* +=============== +PF_Configstring + +=============== +*/ +void PF_Configstring( void ) +{ + SV_ConfigString((int)PRVM_G_FLOAT(OFS_PARM0), PRVM_G_STRING(OFS_PARM1)); +} + +/* +================= +PF_stuffcmd + +Sends text over to the client's execution buffer + +stuffcmd (clientent, value, ...) +================= +*/ +void PF_stuffcmd (void) +{ + int entnum; + client_t *old; + char string[VM_STRINGTEMP_LENGTH]; + + entnum = PRVM_G_EDICTNUM(OFS_PARM0); + if (entnum < 1 || entnum > host.maxclients || svs.clients[entnum-1].state != cs_spawned) + { + VM_Warning("Can't stuffcmd to a non-client\n"); + return; + } + + VM_VarString(1, string, sizeof(string)); + + old = sv_client; + sv_client = svs.clients + entnum - 1; + SV_BroadcastCommand("%s", string); + sv_client = old; +} + +/* +================= +PF_findradius + +Returns a chain of entities that have origins within a spherical area + +findradius (origin, radius) +================= +*/ +void PF_findradius (void) +{ + edict_t *ent, *chain; + vec_t radius, radius2; + vec3_t org, eorg, mins, maxs; + int i; + int numtouchedicts; + edict_t *touchedicts[MAX_EDICTS]; + + chain = (edict_t *)prog->edicts; + + VectorCopy(PRVM_G_VECTOR(OFS_PARM0), org); + radius = PRVM_G_FLOAT(OFS_PARM1); + radius2 = radius * radius; + + mins[0] = org[0] - (radius + 1); + mins[1] = org[1] - (radius + 1); + mins[2] = org[2] - (radius + 1); + maxs[0] = org[0] + (radius + 1); + maxs[1] = org[1] + (radius + 1); + maxs[2] = org[2] + (radius + 1); + + numtouchedicts = 0;//SV_EntitiesInBox(mins, maxs, MAX_EDICTS, touchedicts); + + if (numtouchedicts > MAX_EDICTS) + { + // this never happens + MsgWarn("SV_EntitiesInBox returned %i edicts, max was %i\n", numtouchedicts, MAX_EDICTS); + numtouchedicts = MAX_EDICTS; + } + for (i = 0; i < numtouchedicts; i++) + { + ent = touchedicts[i]; + prog->xfunction->builtinsprofile++; + + 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); +} + +void PF_precache_file (void) +{ + // precache_file is only used to copy files with qcc, it does nothing + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + + +void PF_precache_sound (void) +{ + SV_SoundIndex(PRVM_G_STRING(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +void PF_precache_model (void) +{ + SV_ModelIndex(PRVM_G_STRING(OFS_PARM0)); + PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0); +} + +/* +=============== +PF_walkmove + +float(float yaw, float dist) walkmove +=============== +*/ +void PF_walkmove (void) +{ + edict_t *ent; + float yaw, dist; + vec3_t move; + mfunction_t *oldf; + int oldself; + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(prog->globals.server->pev); + if (ent == prog->edicts) + { + VM_Warning("walkmove: can not modify world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("walkmove: can not modify free entity\n"); + return; + } + + yaw = PRVM_G_FLOAT(OFS_PARM0); + dist = PRVM_G_FLOAT(OFS_PARM1); + + if (!((int)ent->progs.sv->aiflags & (AI_ONGROUND|AI_FLY|AI_SWIM))) + return; + + yaw = yaw * M_PI * 2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + // save program state, because SV_movestep may call other progs + oldf = prog->xfunction; + oldself = prog->globals.server->pev; + + PRVM_G_FLOAT(OFS_RETURN) = 0;//SV_movestep(ent, move, true); + + // restore program state + prog->xfunction = oldf; + prog->globals.server->pev = oldself; +} + +/* +=============== +PF_droptofloor + +void() droptofloor +=============== +*/ +void PF_droptofloor (void) +{ + edict_t *ent; + vec3_t end; + trace_t trace; + + // assume failure if it returns early + PRVM_G_FLOAT(OFS_RETURN) = 0; + + ent = PRVM_PROG_TO_EDICT(prog->globals.server->pev); + if (ent == prog->edicts) + { + VM_Warning("droptofloor: can not modify world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("droptofloor: can not modify free entity\n"); + return; + } + + VectorCopy (ent->progs.sv->origin, end); + end[2] -= 256; + + trace = SV_Trace(ent->progs.sv->origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_ALL ); + + if (trace.fraction != 1) + { + VectorCopy (trace.endpos, ent->progs.sv->origin); + SV_LinkEdict (ent); + ent->progs.sv->flags = (int)ent->progs.sv->aiflags | AI_ONGROUND; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + PRVM_G_FLOAT(OFS_RETURN) = 1; + } +} + +/* +=============== +PF_lightstyle + +void(float style, string value) lightstyle +=============== +*/ +void PF_lightstyle (void) +{ + int style; + const char *val; + + style = (int)PRVM_G_FLOAT(OFS_PARM0); + val = PRVM_G_STRING(OFS_PARM1); + + if( (uint) style >= MAX_LIGHTSTYLES ) + { + PRVM_ERROR( "PF_lightstyle: style: %i >= 64", style ); + } + + SV_ConfigString (CS_LIGHTS + style, val ); +} + +/* +============= +PF_checkbottom +============= +*/ +void PF_checkbottom (void) +{ + PRVM_G_FLOAT(OFS_RETURN) = 0;//SV_CheckBottom (PRVM_G_EDICT(OFS_PARM0)); +} + +/* +============= +PF_pointcontents +============= +*/ +void PF_pointcontents (void) +{ + PRVM_G_FLOAT(OFS_RETURN) = SV_PointContents(PRVM_G_VECTOR(OFS_PARM0)); +} + +/* +============= +PF_aim + +Pick a vector for the player to shoot along +vector aim(entity, missilespeed) +============= +*/ +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" ); + + // assume failure if it returns early + VectorCopy(prog->globals.server->v_forward, PRVM_G_VECTOR(OFS_RETURN)); + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning("aim: can not use world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("aim: can not 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.server->v_forward, dir); + VectorMA (start, 2048, dir, end); + tr = SV_Trace (start, vec3_origin, vec3_origin, end, ent, MASK_ALL ); + + if (tr.ent && ((edict_t *)tr.ent)->progs.sv->takedamage == DAMAGE_AIM && (flags & DF_NO_FRIENDLY_FIRE || ent->progs.sv->team <=0 || ent->progs.sv->team != ((edict_t *)tr.ent)->progs.sv->team)) + { + VectorCopy (prog->globals.server->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 != 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.server->v_forward); + if (dist < bestdist) continue; // to far to turn + tr = SV_Trace (start, vec3_origin, vec3_origin, end, ent, MASK_ALL ); + 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.server->v_forward); + VectorScale (prog->globals.server->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_changeyaw + +This was a major timewaster in progs, so it was converted to C +============== +*/ +void PF_changeyaw (void) +{ + edict_t *ent; + float ideal, current, move, speed; + + ent = PRVM_PROG_TO_EDICT(prog->globals.server->pev); + if (ent == prog->edicts) + { + VM_Warning("changeyaw: can not modify world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("changeyaw: can not modify free entity\n"); + return; + } + current = anglemod(ent->progs.sv->angles[1]); + ideal = ent->progs.sv->ideal_yaw; + speed = ent->progs.sv->yaw_speed; + + if (current == ideal) return; + 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; + } + + ent->progs.sv->angles[1] = anglemod(current + move); +} + +/* +============== +PF_changepitch +============== +*/ +void PF_changepitch (void) +{ + edict_t *ent; + float ideal = 30, current, move, speed = 30; + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning("changepitch: can not modify world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("changepitch: can not modify free entity\n"); + return; + } + current = anglemod( ent->progs.sv->angles[0] ); + + if (current == ideal) return; + 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; + } + + ent->progs.sv->angles[0] = anglemod(current + move); +} + +/* +=============================================================================== + +MESSAGE WRITING + +=============================================================================== +*/ +void PF_BeginMessage(void) +{ + MSG_Begin((int)PRVM_G_FLOAT(OFS_PARM0)); +} + +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_WriteWord (void) +{ + MSG_WriteWord(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +void PF_WriteLong (void) +{ + MSG_WriteLong(&sv.multicast, (int)PRVM_G_FLOAT(OFS_PARM0)); +} + +void PF_WriteFloat (void) +{ + MSG_WriteFloat(&sv.multicast, PRVM_G_FLOAT(OFS_PARM0)); +} + +void PF_WriteAngle (void) +{ + MSG_WriteAngle (&sv.multicast, PRVM_G_FLOAT(OFS_PARM0)); +} + +void PF_WriteCoord (void) +{ + MSG_WritePos (&sv.multicast, PRVM_G_VECTOR(OFS_PARM0)); +} + +void PF_WriteString (void) +{ + MSG_WriteString (&sv.multicast, (char *)PRVM_G_STRING(OFS_PARM0)); +} + +void PF_WriteUnterminatedString (void) +{ + MSG_WriteUnterminatedString (&sv.multicast, PRVM_G_STRING(OFS_PARM0)); +} + +void PF_WriteEntity (void) +{ + MSG_WriteShort (&sv.multicast, PRVM_G_EDICTNUM(OFS_PARM1)); +} + +void PF_EndMessage (void) +{ + MSG_Send((int)PRVM_G_FLOAT(OFS_PARM0), PRVM_G_VECTOR(OFS_PARM1), PRVM_G_EDICT(OFS_PARM2)); +} + +////////////////////////////////////////////////////////// + +void PF_makestatic (void) +{ + edict_t *ent; + + ent = PRVM_G_EDICT(OFS_PARM0); + if (ent == prog->edicts) + { + VM_Warning("makestatic: can not modify world entity\n"); + return; + } + if (ent->priv.sv->free) + { + VM_Warning("makestatic: can not modify free entity\n"); + return; + } + + // just throw the entity away now + PRVM_ED_Free (ent); +} + +//============================================================================= + +/* +============== +PF_setspawnparms +============== +*/ +void PF_setspawnparms (void) +{ + edict_t *ent; + int i; + client_t *client; + + ent = PRVM_G_EDICT(OFS_PARM0); + i = PRVM_NUM_FOR_EDICT(ent); + if (i < 1 || i > host.maxclients || svs.clients[i-1].state != cs_spawned) + { + Msg("tried to setspawnparms on a non-client\n"); + return; + } + + // copy spawn parms out of the client_t + client = svs.clients + i - 1; +} + +void PF_registercvar (void) +{ + const char *name, *value; + name = PRVM_G_STRING(OFS_PARM0); + value = PRVM_G_STRING(OFS_PARM1); + PRVM_G_FLOAT(OFS_RETURN) = 0; + + // first check to see if it has already been defined + if (Cvar_FindVar (name)) + return; + + // check for overlap with a command + if (Cmd_Exists (name)) + { + VM_Warning("PF_registercvar: %s is a command\n", name); + return; + } + + Cvar_Get(name, value, 0); + PRVM_G_FLOAT(OFS_RETURN) = 1; // success +} + +/* +================= +PF_copyentity + +copies data from one entity to another + +copyentity(src, dst) +================= +*/ +void PF_copyentity (void) +{ + edict_t *in, *out; + + in = PRVM_G_EDICT(OFS_PARM0); + if (in == prog->edicts) + { + VM_Warning("copyentity: can not read world entity\n"); + return; + } + if (in->priv.sv->free) + { + VM_Warning("copyentity: can not read free entity\n"); + return; + } + out = PRVM_G_EDICT(OFS_PARM1); + if (out == prog->edicts) + { + VM_Warning("copyentity: can not modify world entity\n"); + return; + } + if (out->priv.sv->free) + { + VM_Warning("copyentity: can not modify free entity\n"); + return; + } + Mem_Copy(out->progs.sv, in->progs.sv, prog->progs->entityfields * 4); +} + +static cmodel_t *getmodel(edict_t *ed) +{ + int modelindex; + if (!ed || ed->priv.sv->free) + return NULL; + + modelindex = (int)ed->progs.sv->modelindex; + if (modelindex < 1 || modelindex >= MAX_MODELS) + return NULL; + + return sv.models[modelindex]; +} + +//void(entity e, string s) clientcommand = #440; // executes a command string as if it came from the specified client +//this function originally written by KrimZon, made shorter by LordHavoc +void PF_clientcommand (void) +{ + client_t *temp_client; + int i; + + //find client for this entity + i = (PRVM_NUM_FOR_EDICT(PRVM_G_EDICT(OFS_PARM0)) - 1); + if (i < 0 || i >= host.maxclients || svs.clients[i].state != cs_spawned) + { + Msg("PF_clientcommand: entity is not a client\n"); + return; + } + + temp_client = sv_client; + sv_client = svs.clients + i; + Cmd_ExecuteString (PRVM_G_STRING(OFS_PARM1)); + sv_client = temp_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); +} + +void PF_spawnclient (void) +{ + int i; + edict_t *ed; + prog->xfunction->builtinsprofile += 2; + ed = prog->edicts; + + for (i = 0;i < host.maxclients; i++) + { + if (svs.clients[i].state != cs_spawned) + { + prog->xfunction->builtinsprofile += 100; +//SV_ConnectClient (i, NULL); + svs.clients[i].state = cs_connected; + ed = PRVM_EDICT_NUM(i + 1); + break; + } + } + VM_RETURN_EDICT(ed); +} + +//float(entity clent) clienttype (DP_SV_BOTCLIENT) +void PF_clienttype (void) +{ + int clientnum = PRVM_G_EDICTNUM(OFS_PARM0) - 1; + + if (clientnum < 0 || clientnum >= host.maxclients) + PRVM_G_FLOAT(OFS_RETURN) = 3; + else if (svs.clients[clientnum].state == cs_spawned) + PRVM_G_FLOAT(OFS_RETURN) = 0; + else if (svs.clients[clientnum].state == cs_connected) + PRVM_G_FLOAT(OFS_RETURN) = 1; + else + PRVM_G_FLOAT(OFS_RETURN) = 2; +} + +void PF_edict_num (void) +{ + VM_RETURN_EDICT(PRVM_EDICT_NUM((int)PRVM_G_FLOAT(OFS_PARM0))); +} + +prvm_builtin_t vm_sv_builtins[] = +{ +NULL, // #0 +PF_makevectors, // #1 void(vector ang) makevectors +PF_setorigin, // #2 void(entity e, vector o) setorigin +PF_setmodel, // #3 void(entity e, string m) setmodel +PF_setsize, // #4 void(entity e, vector min, vector max) setsize +NULL, // #5 void(entity e, vector min, vector max) setabssize +VM_break, // #6 void() break +VM_random, // #7 float() random +PF_sound, // #8 void(entity e, float chan, string samp) sound +VM_normalize, // #9 vector(vector v) normalize +VM_error, // #10 void(string e) error +VM_objerror, // #11 void(string e) objerror +VM_vlen, // #12 float(vector v) vlen +VM_vectoyaw, // #13 float(vector v) vectoyaw +VM_spawn, // #14 entity() spawn +VM_remove, // #15 void(entity e) remove +PF_traceline, // #16 float(vector v1, vector v2, float tryents) traceline +PF_checkclient, // #17 entity() clientlist +VM_find, // #18 entity(entity start, .string fld, string match) find +PF_precache_sound, // #19 void(string s) precache_sound +PF_precache_model, // #20 void(string s) precache_model +PF_stuffcmd, // #21 void(entity client, string s)stuffcmd +PF_findradius, // #22 entity(vector org, float rad) findradius +VM_bprint, // #23 void(string s) bprint +PF_sprint, // #24 void(entity client, string s) sprint +VM_dprint, // #25 void(string s) dprint +VM_ftos, // #26 void(string s) ftos +VM_vtos, // #27 void(string s) vtos +VM_coredump, // #28 void() coredump +VM_traceon, // #29 void() traceon +VM_traceoff, // #30 void() traceoff +VM_eprint, // #31 void(entity e) eprint +PF_walkmove, // #32 float(float yaw, float dist) walkmove +NULL, // #33 +PF_droptofloor, // #34 float() droptofloor +PF_lightstyle, // #35 void(float style, string value) lightstyle +VM_rint, // #36 float(float v) rint +VM_floor, // #37 float(float v) floor +VM_ceil, // #38 float(float v) ceil +PF_SetStats, // #39 void(entity e, float f, string stats) setstats +PF_checkbottom, // #40 float(entity e) checkbottom +PF_pointcontents, // #41 float(vector v) pointcontents +NULL, // #42 +VM_fabs, // #43 float(float f) fabs +PF_aim, // #44 vector(entity e, float speed) aim +VM_cvar, // #45 float(string s) cvar +VM_localcmd, // #46 void(string s) localcmd +VM_nextent, // #47 entity(entity e) nextent +PF_particle, // #48 void(vector o, vector d, float color, float count) particle +PF_changeyaw, // #49 void() ChangeYaw +NULL, // #50 +VM_vectoangles, // #51 vector(vector v) vectoangles +PF_WriteByte, // #52 void(float f) WriteByte +PF_WriteChar, // #53 void(float f) WriteChar +PF_WriteShort, // #54 void(float f) WriteShort +PF_WriteWord, // #55 void(float f) WriteWord +PF_WriteLong, // #56 void(float f) WriteLong +PF_WriteCoord, // #57 void(vector v) WriteCoord +PF_WriteAngle, // #58 void(float f) WriteAngle +PF_WriteString, // #59 void(string s) WriteString +PF_WriteEntity, // #60 void(entity e) WriteEntity +PF_WriteFloat, // #61 void(entity e) WriteFloat +NULL, // #62 +PF_BeginMessage, // #63 void(float to) MSG_Begin +PF_EndMessage, // #64 void(float to, vector v, entity e) MSG_End +PF_Configstring, // #65 void(float num, string s) configstring +NULL, // #66 +NULL, // #67 void(float step) movetogoal +PF_precache_file, // #68 string(string s) precache_file +PF_makestatic, // #69 void(entity e) makestatic +VM_changelevel, // #70 void(string s) changelevel +NULL, // #71 +VM_cvar_set, // #72 void(string var, string val) cvar_set +PF_centerprint, // #73 void(entity client, strings) centerprint +PF_ambientsound, // #74 void(vector pos, string samp, float vol, float atten) ambientsound +PF_precache_model, // #75 string(string s) precache_model2 +PF_precache_sound, // #76 string(string s) precache_sound2 +PF_precache_file, // #77 string(string s) precache_file2 +PF_setspawnparms, // #78 void(entity e) setspawnparms +NULL, // #79 +PF_changepitch, // #80 void(entity ent) changepitch (DP_QC_CHANGEPITCH) +VM_stof, // #81 float(string s) stof (FRIK_FILE) +VM_sin, // #82 float(float f) sin (DP_QC_SINCOSSQRTPOW) +VM_cos, // #83 float(float f) cos (DP_QC_SINCOSSQRTPOW) +VM_sqrt, // #84 float(float f) sqrt (DP_QC_SINCOSSQRTPOW) +VM_etos, // #85 string(entity ent) etos (DP_QC_ETOS) +NULL, // #86 +NULL, // #87 +NULL, // #88 +NULL, // #89 +PF_tracebox, // #90 void(vector v1, vector min, vector max, vector v2, float nomonsters, entity forent) tracebox (DP_QC_TRACEBOX) +VM_randomvec, // #91 vector() randomvec (DP_QC_RANDOMVEC) +NULL, // #92 +PF_registercvar, // #93 float(string name, string value) registercvar (DP_REGISTERCVAR) +VM_min, // #94 float(float a, floats) min (DP_QC_MINMAXBOUND) +VM_max, // #95 float(float a, floats) max (DP_QC_MINMAXBOUND) +VM_bound, // #96 float(float minimum, float val, float maximum) bound (DP_QC_MINMAXBOUND) +VM_pow, // #97 float(float f, float f) pow (DP_QC_SINCOSSQRTPOW) +VM_findfloat, // #98 entity(entity start, .float fld, float match) findfloat (DP_QC_FINDFLOAT) +VM_checkextension, // #99 float(string s) checkextension (the basis of the extension system) +NULL, // #100 +NULL, // #101 +NULL, // #102 +NULL, // #103 +NULL, // #104 +NULL, // #105 +NULL, // #106 +NULL, // #107 +NULL, // #108 +NULL, // #109 +VM_fopen, // #110 float(string filename, float mode) fopen (FRIK_FILE) +VM_fclose, // #111 void(float fhandle) fclose (FRIK_FILE) +VM_fgets, // #112 string(float fhandle) fgets (FRIK_FILE) +VM_fputs, // #113 void(float fhandle, string s) fputs (FRIK_FILE) +VM_strlen, // #114 float(string s) strlen (FRIK_FILE) +VM_strcat, // #115 string(string s1, string s2) strcat (FRIK_FILE) +VM_substring, // #116 string(string s, float start, float length) substring (FRIK_FILE) +VM_stov, // #117 vector(string) stov (FRIK_FILE) +VM_strzone, // #118 string(string s) strzone (FRIK_FILE) +VM_strunzone, // #119 void(string s) strunzone (FRIK_FILE) +e10, e10, e10, e10, e10, e10, e10, e10, // #120-199 +NULL, // #200 FTEQW range #200-#299 +NULL, // #201 +NULL, // #202 +NULL, // #203 +NULL, // #204 +NULL, // #205 +NULL, // #206 +NULL, // #207 +NULL, // #208 +NULL, // #209 +NULL, // #210 +NULL, // #211 +NULL, // #212 +NULL, // #213 +NULL, // #214 +NULL, // #215 +NULL, // #216 +NULL, // #217 +VM_bitshift, // #218 float(float number, float quantity) bitshift (EXT_BITSHIFT) +NULL, // #219 +e10, // #220-#229 +e10, // #230-#239 +e10, // #240-#249 +e10, // #250-#259 +e10, // #260-#269 +e10, // #270-#279 +e10, // #280-#289 +e10, // #290-#299 +e10, e10, e10, e10, e10, e10, e10, e10, e10, e10, // #300-399 +VM_copyentity, // #400 void(entity from, entity to) copyentity (DP_QC_COPYENTITY) +NULL, // #401 +VM_findchain, // #402 entity(.string fld, string match) findchain (DP_QC_FINDCHAIN) +VM_findchainfloat, // #403 entity(.float fld, float match) findchainfloat (DP_QC_FINDCHAINFLOAT) +NULL, // #404 void(vector org, string modelname, float startframe, float endframe, float framerate) effect (DP_SV_EFFECT) +NULL, // #405 void(vector org, vector velocity, float howmany) te_blood (DP_TE_BLOOD) +NULL, // #406 void(vector mincorner, vector maxcorner, float explosionspeed, float howmany) te_bloodshower (DP_TE_BLOODSHOWER) +NULL, // #407 void(vector org, vector color) te_explosionrgb (DP_TE_EXPLOSIONRGB) +NULL, // #408 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color, float gravityflag, float randomveljitter) te_particlecube (DP_TE_PARTICLECUBE) +NULL, // #409 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlerain (DP_TE_PARTICLERAIN) +NULL, // #410 void(vector mincorner, vector maxcorner, vector vel, float howmany, float color) te_particlesnow (DP_TE_PARTICLESNOW) +NULL, // #411 void(vector org, vector vel, float howmany) te_spark (DP_TE_SPARK) +NULL, // #412 void(vector org) te_gunshotquad (DP_QUADEFFECTS1) +NULL, // #413 void(vector org) te_spikequad (DP_QUADEFFECTS1) +NULL, // #414 void(vector org) te_superspikequad (DP_QUADEFFECTS1) +NULL, // #415 void(vector org) te_explosionquad (DP_QUADEFFECTS1) +NULL, // #416 void(vector org) te_smallflash (DP_TE_SMALLFLASH) +NULL, // #417 void(vector org, float radius, float lifetime, vector color) te_customflash (DP_TE_CUSTOMFLASH) +NULL, // #418 void(vector org) te_gunshot (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #419 void(vector org) te_spike (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #420 void(vector org) te_superspike (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #421 void(vector org) te_explosion (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #422 void(vector org) te_tarexplosion (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #423 void(vector org) te_wizspike (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #424 void(vector org) te_knightspike (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #425 void(vector org) te_lavasplash (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #426 void(vector org) te_teleport (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #427 void(vector org, float colorstart, float colorlength) te_explosion2 (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #428 void(entity own, vector start, vector end) te_lightning1 (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #429 void(entity own, vector start, vector end) te_lightning2 (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #430 void(entity own, vector start, vector end) te_lightning3 (DP_TE_STANDARDEFFECTBUILTINS) +NULL, // #431 void(entity own, vector start, vector end) te_beam (DP_TE_STANDARDEFFECTBUILTINS) +VM_vectorvectors, // #432 void(vector dir) vectorvectors (DP_QC_VECTORVECTORS) +NULL, // #433 void(vector org) te_plasmaburn (DP_TE_PLASMABURN) +NULL, // #434 float(entity e, float s) getsurfacenumpoints (DP_QC_GETSURFACE) +NULL, // #435 vector(entity e, float s, float n) getsurfacepoint (DP_QC_GETSURFACE) +NULL, // #436 vector(entity e, float s) getsurfacenormal (DP_QC_GETSURFACE) +NULL, // #437 string(entity e, float s) getsurfacetexture (DP_QC_GETSURFACE) +NULL, // #438 float(entity e, vector p) getsurfacenearpoint (DP_QC_GETSURFACE) +NULL, // #439 vector(entity e, float s, vector p) getsurfaceclippedpoint (DP_QC_GETSURFACE) +PF_clientcommand, // #440 void(entity e, string s) clientcommand (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_tokenize, // #441 float(string s) tokenize (KRIMZON_SV_PARSECLIENTCOMMAND) +VM_argv, // #442 string(float n) argv (KRIMZON_SV_PARSECLIENTCOMMAND) +NULL, // #443 void(entity e, entity tagentity, string tagname) setattachment (DP_GFX_QUAKE3MODELTAGS) +VM_search_begin, // #444 float(string pattern, float caseinsensitive, float quiet) search_begin (DP_FS_SEARCH) +VM_search_end, // #445 void(float handle) search_end (DP_FS_SEARCH) +VM_search_getsize, // #446 float(float handle) search_getsize (DP_FS_SEARCH) +VM_search_getfilename, // #447 string(float handle, float num) search_getfilename (DP_FS_SEARCH) +VM_cvar_string, // #448 string(string s) cvar_string (DP_QC_CVAR_STRING) +VM_findflags, // #449 entity(entity start, .float fld, float match) findflags (DP_QC_FINDFLAGS) +VM_findchainflags, // #450 entity(.float fld, float match) findchainflags (DP_QC_FINDCHAINFLAGS) +NULL, // #451 float(entity ent, string tagname) gettagindex (DP_QC_GETTAGINFO) +NULL, // #452 vector(entity ent, float tagindex) gettaginfo (DP_QC_GETTAGINFO) +PF_dropclient, // #453 void(entity clent) dropclient (DP_SV_DROPCLIENT) +PF_spawnclient, // #454 entity() spawnclient (DP_SV_BOTCLIENT) +PF_clienttype, // #455 float(entity clent) clienttype (DP_SV_BOTCLIENT) +PF_WriteUnterminatedString, // #456 void(float to, string s) WriteUnterminatedString (DP_SV_WRITEUNTERMINATEDSTRING) +NULL, // #457 void(vector org, vector vel, float howmany) te_flamejet = #457 (DP_TE_FLAMEJET) +NULL, // #458 +PF_edict_num, // #459 entity(float num) (??) +VM_buf_create, // #460 float() buf_create (DP_QC_STRINGBUFFERS) +VM_buf_del, // #461 void(float bufhandle) buf_del (DP_QC_STRINGBUFFERS) +VM_buf_getsize, // #462 float(float bufhandle) buf_getsize (DP_QC_STRINGBUFFERS) +VM_buf_copy, // #463 void(float bufhandle_from, float bufhandle_to) buf_copy (DP_QC_STRINGBUFFERS) +VM_buf_sort, // #464 void(float bufhandle, float sortpower, float backward) buf_sort (DP_QC_STRINGBUFFERS) +VM_buf_implode, // #465 string(float bufhandle, string glue) buf_implode (DP_QC_STRINGBUFFERS) +VM_bufstr_get, // #466 string(float bufhandle, float string_index) bufstr_get (DP_QC_STRINGBUFFERS) +VM_bufstr_set, // #467 void(float bufhandle, float string_index, string str) bufstr_set (DP_QC_STRINGBUFFERS) +VM_bufstr_add, // #468 float(float bufhandle, string str, float order) bufstr_add (DP_QC_STRINGBUFFERS) +VM_bufstr_free, // #469 void(float bufhandle, float string_index) bufstr_free (DP_QC_STRINGBUFFERS) +NULL, // #470 +NULL, // #471 +NULL, // #472 +NULL, // #473 +NULL, // #474 +NULL, // #475 +NULL, // #476 +NULL, // #477 +NULL, // #478 +NULL, // #479 +e10, e10 // #480-499 (LordHavoc) +}; + +const int vm_sv_numbuiltins = sizeof(vm_sv_builtins) / sizeof(prvm_builtin_t); /* =============== @@ -257,15 +1596,7 @@ it is changing to a different game directory. */ void SV_ShutdownGameProgs (void) { - if (!ge) return; - Msg("==== ShutdownGame ====\n"); - - //free main memory pools - Mem_FreePool(&sv.mempool); - - Mem_Free( ge ); - ge = NULL; } /* @@ -275,26 +1606,9 @@ SV_InitGameProgs Init the game subsystem for a new map =============== */ -void SCR_DebugGraph (float value, int color); - void SV_InitGameProgs (void) { - // unload anything we have now - if (ge) SV_ShutdownGameProgs (); - - sv.mempool = Mem_AllocPool("Zone Game"); - ge = Mem_Alloc(sv.mempool, sizeof(game_export_t)); - - // initialize all entities for this game - game.maxentities = 1024; - - ge->edict_size = sizeof(edict_t); - ge->edicts = (edict_t *)Mem_Alloc(sv.mempool, game.maxentities * ge->edict_size); - ge->max_edicts = game.maxentities; - - // initialize all clients for this game - game.maxclients = maxclients->value; - game.clients = (gclient_t *)Mem_Alloc(sv.mempool, game.maxclients * sizeof(gclient_t)); - ge->num_edicts = game.maxclients + 1; //reserve for world + Msg("==== InitGame ====\n"); + SV_VM_Setup(); } diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 094809a8..ac1e153f 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -24,28 +24,132 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. server_static_t svs; // persistant server info server_t sv; // local server +#define REQFIELDS (sizeof(reqfields) / sizeof(prvm_fieldvars_t)) + +prvm_fieldvars_t reqfields[] = +{ + {0, 1, "classname"}, + {1, 1, "globalname"}, + {2, 2, "modelindex"}, + {3, 3, "origin"}, + {6, 3, "angles"}, + {9, 3, "velocity"}, + {12, 3, "avelocity"}, + {15, 3, "post_origin"}, + {18, 3, "post_angles"}, + {21, 3, "post_velocity"}, + {24, 3, "post_avelocity"}, + {27, 3, "origin_offset"}, + {30, 3, "angles_offset"}, + {33, 2, "bouncetype"}, + {34, 2, "movetype"}, + {35, 2, "solid"}, + {36, 3, "absmin"}, + {39, 3, "absmax"}, + {42, 3, "mins"}, + {45, 3, "maxs"}, + {48, 3, "size"}, + {51, 4, "chain"}, + {52, 1, "model"}, + {53, 2, "frame"}, + {54, 2, "sequence"}, + {55, 2, "renderfx"}, + {56, 2, "effects"}, + {57, 2, "skin"}, + {58, 2, "body"}, + {59, 1, "weaponmodel"}, + {60, 2, "weaponframe"}, + {61, 6, "use"}, + {62, 6, "touch"}, + {63, 6, "think"}, + {64, 6, "blocked"}, + {65, 6, "activate"}, + {66, 6, "walk"}, + {67, 6, "jump"}, + {68, 6, "duck"}, + {69, 2, "flags"}, + {70, 2, "aiflags"}, + {71, 2, "spawnflags"}, + {72, 4, "groundentity"}, + {73, 2, "nextthink"}, + {74, 2, "takedamage"}, + {75, 2, "health"}, + {76, 2, "frags"}, + {77, 2, "weapon"}, + {78, 2, "items"}, + {79, 1, "target"}, + {80, 1, "parent"}, + {81, 1, "targetname"}, + {82, 4, "aiment"}, + {83, 4, "goalentity"}, + {84, 3, "punchangle"}, + {87, 2, "deadflag"}, + {88, 3, "view_ofs"}, + {91, 2, "button0"}, + {92, 2, "button1"}, + {93, 2, "button2"}, + {94, 2, "impulse"}, + {95, 2, "fixangle"}, + {96, 3, "v_angle"}, + {99, 2, "idealpitch"}, + {100, 1, "netname"}, + {101, 4, "enemy"}, + {102, 2, "colormap"}, + {103, 2, "team"}, + {104, 2, "max_health"}, + {105, 2, "teleport_time"}, + {106, 2, "armortype"}, + {107, 2, "armorvalue"}, + {108, 2, "waterlevel"}, + {109, 2, "watertype"}, + {110, 2, "ideal_yaw"}, + {111, 2, "yaw_speed"}, + {112, 2, "dmg_take"}, + {113, 2, "dmg_save"}, + {114, 4, "dmg_inflictor"}, + {115, 4, "owner"}, + {116, 3, "movedir"}, + {119, 1, "message"}, + {120, 2, "sounds"}, + {121, 1, "noise"}, + {122, 1, "noise1"}, + {123, 1, "noise2"}, + {124, 1, "noise3"}, + {125, 2, "jumpup"}, + {126, 2, "jumpdn"}, + {127, 4, "movetarget"}, + {128, 2, "mass"}, + {129, 2, "density"}, + {130, 2, "gravity"}, + {131, 2, "dmg"}, + {132, 2, "dmgtime"}, + {133, 2, "speed"} +}; + /* ================ SV_FindIndex ================ */ -int SV_FindIndex (char *name, int start, int max, bool create) +int SV_FindIndex (const char *name, int start, int end, bool create) { int i; - if (!name || !name[0]) - return 0; + if (!name || !name[0]) return 0; - for (i=1 ; inum_edicts ; entnum++) + for (entnum = 1; entnum < prog->num_edicts ; entnum++) { - svent = EDICT_NUM(entnum); - if (!svent->inuse) + svent = PRVM_EDICT_NUM(entnum); + if (svent->priv.sv->free) continue; + if (!svent->priv.sv->s.modelindex && !svent->priv.sv->s.sound && !svent->priv.sv->s.effects) continue; - if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects) - continue; - svent->s.number = entnum; + svent->priv.sv->s.number = entnum; // // take current state as baseline // - VectorCopy (svent->s.origin, svent->s.old_origin); - sv.baselines[entnum] = svent->s; + VectorCopy (svent->priv.sv->s.origin, svent->priv.sv->s.old_origin); + sv.baselines[entnum] = svent->priv.sv->s; } } @@ -166,6 +269,7 @@ clients along with it. void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_state_t serverstate, bool attractloop, bool loadgame) { uint i, checksum; + edict_t *ent; if (attractloop) Cvar_Set ("paused", "0"); @@ -199,8 +303,10 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); strcpy (sv.name, server); + SV_VM_Begin(); + // leave slots at start for clients only - for (i=0 ; ivalue ; i++) + for (i = 0; ivalue ; i++) { // needs to reconnect if (svs.clients[i].state > cs_connected) @@ -242,6 +348,39 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat sv.state = ss_loading; Com_SetServerState (sv.state); + ent = PRVM_EDICT_NUM(0); + prog->protect_world = false; + 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; + + prog->globals.server->mapname = PRVM_SetEngineString(sv.name); + + // spawn the rest of the entities on the map + sv.edicts = (edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(edict_t *)); + sv.clients = (gclient_t *)PRVM_Alloc(maxclients->value * sizeof(gclient_t)); + *prog->time = sv.time = 1.0; + + // serverflags are for cross level information (sigils) +//prog->globals.server->serverflags = svs.serverflags; + + // we need to reset the spawned flag on all connected clients here so that + // their thinks don't run during startup (before PutClientInServer) + // we also need to set up the client entities now + // and we need to set the ->edict pointers to point into the progs edicts + for (i = 0, sv_client = svs.clients; i < maxclients->value; i++, sv_client++) + { + sv_client->state = cs_connected; + sv_client->edict = PRVM_EDICT_NUM(i + 1); + sv_client->edict->priv.sv->client = sv.clients + i; + ent->priv.sv->s.number = i + 1; + memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); + PRVM_ED_ClearEdict(sv_client->edict); + } + // load and spawn all other entities SV_SpawnEntities ( sv.name, CM_EntityString(), spawnpoint ); @@ -263,6 +402,7 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); Msg ("-------------------------------------\n"); + SV_VM_End(); } /* @@ -274,9 +414,7 @@ A brand new game has been started */ void SV_InitGame (void) { - int i; - edict_t *ent; - char idmaster[32]; + char idmaster[32]; if (svs.initialized) { @@ -342,14 +480,6 @@ void SV_InitGame (void) // init game SV_InitGameProgs (); - - for (i = 0; i < maxclients->value; i++) - { - ent = EDICT_NUM(i + 1); - ent->s.number = i + 1; - svs.clients[i].edict = ent; - memset (&svs.clients[i].lastcmd, 0, sizeof(svs.clients[i].lastcmd)); - } } @@ -438,3 +568,132 @@ void SV_Map (bool attractloop, char *levelstring, char *savename, bool loadgame) SV_BroadcastCommand ("reconnect\n"); } + +void SV_VM_BeginIncreaseEdicts(void) +{ + int i; + edict_t *ent; + + if(sv.edicts) PRVM_Free( sv.edicts ); + + sv.edicts = (edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *)); + // links don't survive the transition, so unlink everything + for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++) + { + if (!ent->priv.sv->free) SV_UnlinkEdict(prog->edicts + i); //free old entity + memset(&ent->priv.sv->clusternums, 0, sizeof(ent->priv.sv->clusternums)); + } + SV_ClearWorld(); +} + +void SV_VM_EndIncreaseEdicts(void) +{ + int i; + edict_t *ent; + + for (i = 0, ent = prog->edicts; i < prog->max_edicts; i++, ent++) + { + // link every entity except world + if (!ent->priv.sv->free) SV_LinkEdict(ent); + } +} + +void SV_VM_InitEdict(edict_t *e) +{ + SV_InitEdict( e ); +} + +void SV_VM_FreeEdict(edict_t *e) +{ + SV_UnlinkEdict(e); // unlink from world bsp + SV_FreeEdict( e ); +} + +void SV_VM_CountEdicts( void ) +{ + int i; + edict_t *ent; + int 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_VM_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 )) || (current_skill == 1 && ((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->progs.sv->spawnflags & SPAWNFLAG_NOT_HARD ))) + { + return false; + } + return true; +} + +void SV_VM_Setup( void ) +{ + PRVM_Begin; + PRVM_InitProg( PRVM_SERVERPROG ); + + // allocate the mempools + // TODO: move the magic numbers/constants into #defines [9/13/2006 Black] + prog->progs_mempool = Mem_AllocPool("Server Progs" ); + prog->builtins = vm_sv_builtins; + prog->numbuiltins = vm_sv_numbuiltins; + prog->max_edicts = 512; + prog->limit_edicts = MAX_EDICTS; + prog->reserved_edicts = maxclients->value; + prog->edictprivate_size = sizeof(sv_edict_t); + prog->name = "server"; + prog->extensionstring = ""; + prog->loadintoworld = true; + + prog->begin_increase_edicts = SV_VM_BeginIncreaseEdicts; + prog->end_increase_edicts = SV_VM_EndIncreaseEdicts; + prog->init_edict = SV_VM_InitEdict; + prog->free_edict = SV_VM_FreeEdict; + prog->count_edicts = SV_VM_CountEdicts; + prog->load_edict = SV_VM_LoadEdict; + prog->init_cmd = VM_Cmd_Init; + prog->reset_cmd = VM_Cmd_Reset; + prog->error_cmd = VM_Error; + + // TODO: add a requiredfuncs list (ask LH if this is necessary at all) + PRVM_LoadProgs( "server.dat", 0, NULL, REQFIELDS, reqfields ); + PRVM_End; +} + +void SV_VM_Begin(void) +{ + PRVM_Begin; + PRVM_SetProg( PRVM_SERVERPROG ); + + *prog->time = sv.time; +} + +void SV_VM_End(void) +{ + PRVM_End; +} \ No newline at end of file diff --git a/engine/server/sv_main.c b/engine/server/sv_main.c index 47865acb..bb4d47fe 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -151,7 +151,7 @@ char *SV_StatusString (void) cl = &svs.clients[i]; if (cl->state == cs_connected || cl->state == cs_spawned ) { - sprintf (player, "%i %i \"%s\"\n", cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name); + sprintf (player, "%i %i \"%s\"\n", cl->edict->priv.sv->client->ps.stats[STAT_FRAGS], cl->ping, cl->name); playerLength = strlen(player); if (statusLength + playerLength >= sizeof(status) ) break; // can't hold any more @@ -396,7 +396,7 @@ gotnewcl: sv_client = newcl; edictnum = (newcl - svs.clients) + 1; - ent = EDICT_NUM(edictnum); + ent = PRVM_EDICT_NUM( edictnum ); newcl->edict = ent; newcl->challenge = challenge; // save challenge for checksumming @@ -556,7 +556,7 @@ void SV_CalcPings (void) #endif // let the game dll know about the ping - cl->edict->client->ping = cl->ping; + cl->edict->priv.sv->client->ping = cl->ping; } } @@ -700,14 +700,14 @@ player processing happens outside RunWorldFrame */ void SV_PrepWorldFrame (void) { - edict_t *ent; + edict_t *ent; int i; - for (i=0 ; inum_edicts ; i++, ent++) + for (i = 0; i < prog->num_edicts ; i++, ent++) { - ent = EDICT_NUM(i); + ent = PRVM_EDICT_NUM(i); // events only last for a single message - ent->s.event = 0; + ent->priv.sv->s.event = 0; } } @@ -768,6 +768,9 @@ void SV_Frame (float time) // keep the random time dependent rand (); + // setup the VM frame + SV_VM_Begin(); + // check timeouts SV_CheckTimeouts (); @@ -809,6 +812,8 @@ void SV_Frame (float time) // clear teleport flags, etc for next frame SV_PrepWorldFrame (); + // end the server VM frame + SV_VM_End(); } //============================================================================ diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 2f5d01f2..1d612eab 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -43,8 +43,8 @@ bool SV_CheckBottom (edict_t *ent) int x, y; float mid, bottom; - VectorAdd (ent->s.origin, ent->mins, mins); - VectorAdd (ent->s.origin, ent->maxs, maxs); + VectorAdd (ent->priv.sv->s.origin, ent->progs.sv->mins, mins); + VectorAdd (ent->priv.sv->s.origin, ent->progs.sv->maxs, maxs); // if all of the points under the corners are solid world, don't bother // with the tougher checks @@ -113,37 +113,37 @@ void SV_DropToFloor (edict_t *ent) vec3_t v, dest; VectorSet(v, -15,-15,-15); - VectorCopy (v, ent->mins); + VectorCopy (v, ent->progs.sv->mins); VectorSet(v, 15, 15, 15); - VectorCopy (v, ent->maxs); + VectorCopy (v, ent->progs.sv->maxs); - if (ent->model) PF_setmodel (ent, ent->model); + if (ent->progs.sv->model) SV_SetModel (ent, PRVM_G_STRING(ent->progs.sv->model)); // Lazarus: // origin_offset is wrong - absmin and absmax weren't set soon enough. // Fortunately we KNOW what the "offset" is - nada. - VectorClear(ent->origin_offset); + VectorClear(ent->progs.sv->origin_offset); - ent->solid = SOLID_BBOX; - ent->clipmask |= MASK_MONSTERSOLID; - if(!ent->health) ent->health = 20; - ent->takedamage = DAMAGE_YES; + ent->progs.sv->solid = SOLID_BBOX; + ent->priv.sv->clipmask |= MASK_MONSTERSOLID; + if(!ent->progs.sv->health) ent->progs.sv->health = 20; + ent->progs.sv->takedamage = DAMAGE_YES; - ent->movetype = MOVETYPE_TOSS; + ent->progs.sv->movetype = MOVETYPE_TOSS; VectorSet(v, 0, 0, -128); - VectorAdd (ent->s.origin, v, dest); + VectorAdd (ent->priv.sv->s.origin, v, dest); - tr = SV_Trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID); + tr = SV_Trace (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, dest, ent, MASK_SOLID); if (tr.startsolid) { - Msg("SV_DropToFloor: %s startsolid at %s\n", ent->classname, ent->s.origin[0], ent->s.origin[1], ent->s.origin[2]); + Msg("SV_DropToFloor: %s startsolid at %s\n", PRVM_G_STRING(ent->progs.sv->classname), ent->priv.sv->s.origin[0], ent->priv.sv->s.origin[1], ent->priv.sv->s.origin[2]); SV_FreeEdict (ent); return; } tr.endpos[2] += 1; - ent->mins[2] -= 1; - VectorCopy (tr.endpos, ent->s.origin); + ent->progs.sv->mins[2] -= 1; + VectorCopy (tr.endpos, ent->priv.sv->s.origin); SV_LinkEdict (ent); } @@ -153,28 +153,24 @@ void SV_CheckGround (edict_t *ent) vec3_t point; trace_t trace; - if(sv.time < ent->gravity_debounce_time) - return; - - if (ent->flags & (FL_SWIM|FL_FLY)) return; - - if (ent->velocity[2] > 100) + if ((int)ent->progs.sv->aiflags & (AI_SWIM|AI_FLY)) return; + if (ent->progs.sv->velocity[2] > 100) { - ent->groundentity = NULL; + ent->progs.sv->groundentity = 0; return; } // if the hull point one-quarter unit down is solid the entity is on ground - point[0] = ent->s.origin[0]; - point[1] = ent->s.origin[1]; - point[2] = ent->s.origin[2] - 0.25; + point[0] = ent->priv.sv->s.origin[0]; + point[1] = ent->priv.sv->s.origin[1]; + point[2] = ent->priv.sv->s.origin[2] - 0.25; - trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID); + trace = SV_Trace (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, point, ent, MASK_MONSTERSOLID); // check steepness if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) { - ent->groundentity = NULL; + ent->progs.sv->groundentity = 0; return; } @@ -184,14 +180,12 @@ void SV_CheckGround (edict_t *ent) // dead monster to drop through the brush model. This change *may* // have other consequences, though, so watch out for this. - ent->groundentity = trace.ent; - ent->groundentity_linkcount = trace.ent->linkcount; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); if (!trace.startsolid && !trace.allsolid) { - VectorCopy (trace.endpos, ent->s.origin); - ent->groundentity = trace.ent; - ent->groundentity_linkcount = trace.ent->linkcount; - ent->velocity[2] = trace.ent->velocity[2]; + VectorCopy (trace.endpos, ent->priv.sv->s.origin); + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + ent->progs.sv->velocity[2] = trace.ent->progs.sv->velocity[2]; } } @@ -208,31 +202,31 @@ void SV_FallingDamage (edict_t *ent) int damage; vec3_t dir; - if (ent->movetype == MOVETYPE_NOCLIP) + if (ent->progs.sv->movetype == MOVETYPE_NOCLIP) return; - if ((ent->oldvelocity[2] < 0) && (ent->velocity[2] > ent->oldvelocity[2]) && (!ent->groundentity)) + if ((ent->progs.sv->post_velocity[2] < 0) && (ent->progs.sv->velocity[2] > ent->progs.sv->post_velocity[2]) && (!ent->progs.sv->groundentity)) { - delta = ent->oldvelocity[2]; + delta = ent->progs.sv->post_velocity[2]; } else { - if (!ent->groundentity) + if (!ent->progs.sv->groundentity) return; - delta = ent->velocity[2] - ent->oldvelocity[2]; + delta = ent->progs.sv->velocity[2] - ent->progs.sv->post_velocity[2]; } delta = delta*delta * 0.0001; // never take falling damage if completely underwater - if (ent->waterlevel == 3) return; - if (ent->waterlevel == 2) delta *= 0.25; - if (ent->waterlevel == 1) delta *= 0.5; + if (ent->progs.sv->waterlevel == 3) return; + if (ent->progs.sv->waterlevel == 2) delta *= 0.25; + if (ent->progs.sv->waterlevel == 1) delta *= 0.5; if (delta < 1) return; if (delta < 15) { - ent->s.event = EV_FOOTSTEP; + ent->priv.sv->s.event = EV_FOOTSTEP; return; } @@ -246,7 +240,7 @@ void SV_FallingDamage (edict_t *ent) if (damage < 1) damage = 1; VectorSet (dir, 0, 0, 1); - T_Damage (ent, ge->edicts, ge->edicts, dir, ent->s.origin, vec3_origin, damage, 0, 0, DMG_FALL); + T_Damage (ent, prog->edicts, prog->edicts, dir, ent->priv.sv->s.origin, vec3_origin, damage, 0, 0, DMG_FALL); } } @@ -282,33 +276,33 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) edict_t *target; // try the move - VectorCopy (ent->s.origin, oldorg); - VectorAdd (ent->s.origin, move, neworg); + VectorCopy (ent->priv.sv->s.origin, oldorg); + VectorAdd (ent->priv.sv->s.origin, move, neworg); - AngleVectors(ent->s.angles,forward,NULL,up); - if(ent->enemy) - target = ent->enemy; - else if(ent->movetarget) - target = ent->movetarget; + AngleVectors(ent->priv.sv->s.angles,forward,NULL,up); + if(ent->progs.sv->enemy) + target = PRVM_PROG_TO_EDICT(ent->progs.sv->enemy); + else if(ent->progs.sv->movetarget) + target = PRVM_PROG_TO_EDICT(ent->progs.sv->movetarget); else target = NULL; // flying monsters don't step up - if ( ent->flags & (FL_SWIM | FL_FLY) ) + if ((int)ent->progs.sv->aiflags & (AI_SWIM | AI_FLY) ) { // try one move with vertical motion, then one without for (i = 0; i < 2; i++) { - VectorAdd (ent->s.origin, move, neworg); - if (i == 0 && ent->enemy) + VectorAdd (ent->priv.sv->s.origin, move, neworg); + if (i == 0 && ent->progs.sv->enemy) { - if (!ent->goalentity) - ent->goalentity = ent->enemy; - dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; - if (ent->goalentity->client) + if (!ent->progs.sv->goalentity) + ent->progs.sv->goalentity = ent->progs.sv->enemy; + dz = ent->priv.sv->s.origin[2] - PRVM_PROG_TO_EDICT(ent->progs.sv->goalentity)->priv.sv->s.origin[2]; + if (PRVM_PROG_TO_EDICT(ent->progs.sv->goalentity)->priv.sv->client) { if (dz > 40) neworg[2] -= 8; - if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) + if (!(((int)ent->progs.sv->aiflags & AI_SWIM) && (ent->progs.sv->waterlevel < 2))) if (dz < 30) neworg[2] += 8; } else @@ -319,16 +313,16 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) else neworg[2] += dz; } } - trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); + trace = SV_Trace (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, neworg, ent, MASK_MONSTERSOLID); // fly monsters don't enter water voluntarily - if (ent->flags & FL_FLY) + if ((int)ent->progs.sv->aiflags & AI_FLY) { - if (!ent->waterlevel) + if (!ent->progs.sv->waterlevel) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent->mins[2] + 1; + test[2] = trace.endpos[2] + ent->progs.sv->mins[2] + 1; contents = SV_PointContents(test); if (contents & MASK_WATER) return false; @@ -336,13 +330,13 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) } // swim monsters don't exit water voluntarily - if (ent->flags & FL_SWIM) + if ((int)ent->progs.sv->aiflags & AI_SWIM) { - if (ent->waterlevel < 2) + if (ent->progs.sv->waterlevel < 2) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent->mins[2] + 1; + test[2] = trace.endpos[2] + ent->progs.sv->mins[2] + 1; contents = SV_PointContents(test); if (!(contents & MASK_WATER)) return false; @@ -351,7 +345,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) if (trace.fraction == 1) { - VectorCopy (trace.endpos, ent->s.origin); + VectorCopy (trace.endpos, ent->priv.sv->s.origin); if (relink) { SV_LinkEdict(ent); @@ -360,7 +354,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) return true; } - if (!ent->enemy) + if (!ent->progs.sv->enemy) break; } @@ -368,7 +362,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) } // push down from a step height above the wished position - if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) + if (!((int)ent->progs.sv->aiflags & AI_NOSTEP)) stepsize = STEPSIZE; else stepsize = 1; @@ -376,25 +370,25 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) VectorCopy (neworg, end); end[2] -= stepsize*2; - trace = SV_Trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); + trace = SV_Trace (neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_MONSTERSOLID); // Determine whether monster is capable of and/or should jump jump = 0; - if((ent->monsterinfo.jump) && !(ent->monsterinfo.aiflags & AI_DUCKED)) + if((ent->progs.sv->jump) && !((int)ent->progs.sv->aiflags & AI_DUCKED)) { // Don't jump if path is blocked by monster or player. Otherwise, // monster might attempt to jump OVER the monster/player, which // ends up looking a bit goofy. Also don't jump if the monster's // movement isn't deliberate (target=NULL) - if(trace.ent && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER))) + if(trace.ent && (trace.ent->priv.sv->client || ((int)trace.ent->progs.sv->flags & FL_MONSTER))) canjump = false; else if(target) { // Never jump unless it places monster closer to his goal vec3_t dir; - VectorSubtract(target->s.origin, oldorg, dir); + VectorSubtract(target->priv.sv->s.origin, oldorg, dir); d1 = VectorLength(dir); - VectorSubtract(target->s.origin, trace.endpos, dir); + VectorSubtract(target->priv.sv->s.origin, trace.endpos, dir); d2 = VectorLength(dir); if(d2 < d1) canjump = true; @@ -407,25 +401,25 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) if (trace.allsolid) { - if(canjump && (ent->monsterinfo.jumpup > 0)) + if(canjump && (ent->progs.sv->jumpup > 0)) { - neworg[2] += ent->monsterinfo.jumpup - stepsize; - trace = SV_Trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); + neworg[2] += ent->progs.sv->jumpup - stepsize; + trace = SV_Trace (neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_MONSTERSOLID); if (!trace.allsolid && !trace.startsolid && trace.fraction > 0 && (trace.plane.normal[2] > 0.9)) { - if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER))) + if(!trace.ent || (!trace.ent->priv.sv->client && !((int)trace.ent->progs.sv->flags & FL_MONSTER) && !((int)trace.ent->progs.sv->flags & FL_DEADMONSTER))) { // Good plane to jump on. Make sure monster is more or less facing // the obstacle to avoid cutting-corners jumps trace_t tr; vec3_t p2; - VectorMA(ent->s.origin,1024,forward,p2); - tr = SV_Trace(ent->s.origin,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID); + VectorMA(ent->priv.sv->s.origin,1024,forward,p2); + tr = SV_Trace(ent->priv.sv->s.origin,ent->progs.sv->mins,ent->progs.sv->maxs,p2,ent,MASK_MONSTERSOLID); if(DotProduct(tr.plane.normal,forward) < -0.95) { jump = 1; - jumpheight = trace.endpos[2] - ent->s.origin[2]; + jumpheight = trace.endpos[2] - ent->priv.sv->s.origin[2]; } else return false; } @@ -438,7 +432,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) if (trace.startsolid) { neworg[2] -= stepsize; - trace = SV_Trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); + trace = SV_Trace (neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_MONSTERSOLID); if (trace.allsolid || trace.startsolid) return false; } @@ -446,29 +440,29 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) // don't go in to water // Lazarus: misc_actors don't go swimming, but wading is fine - if (ent->monsterinfo.aiflags & AI_ACTOR) + if ((int)ent->progs.sv->aiflags & AI_ACTOR) { // First check for lava/slime under feet - but only if we're not already in // a liquid test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; - if (ent->waterlevel == 0) + if (ent->progs.sv->waterlevel == 0) { - test[2] = trace.endpos[2] + ent->mins[2] + 1; + test[2] = trace.endpos[2] + ent->progs.sv->mins[2] + 1; contents = SV_PointContents(test); if (contents & (CONTENTS_LAVA | CONTENTS_SLIME)) return false; } - test[2] = trace.endpos[2] + ent->viewheight - 1; + test[2] = trace.endpos[2] + ent->progs.sv->view_ofs[2] - 1; //FIXME contents = SV_PointContents(test); if (contents & MASK_WATER) return false; } - else if (ent->waterlevel == 0) + else if (ent->progs.sv->waterlevel == 0) { test[0] = trace.endpos[0]; test[1] = trace.endpos[1]; - test[2] = trace.endpos[2] + ent->mins[2] + 1; + test[2] = trace.endpos[2] + ent->progs.sv->mins[2] + 1; contents = SV_PointContents(test); if (contents & MASK_WATER) @@ -486,34 +480,33 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) vec3_t laser_start, laser_end; vec3_t monster_mins, monster_maxs; - for(i = maxclients->value + 1; i < ge->num_edicts; i++) + for(i = maxclients->value + 1; i < prog->num_edicts; i++) { - e = EDICT_NUM(i); - if(!e->inuse) continue; - if(!e->classname) continue; - if(strcmp(e->classname, "env_laser")) continue; - if(e->svflags & SVF_NOCLIENT) continue; - if(!PF_inPVS(ent->s.origin,e->s.origin)) + e = PRVM_EDICT_NUM(i); + if(e->priv.sv->free) continue; + if(!PRVM_G_STRING(e->progs.sv->classname)) continue; + if(strcmp(PRVM_G_STRING(e->progs.sv->classname), "env_laser")) continue; + if(!PF_inpvs(ent->priv.sv->s.origin,e->priv.sv->s.origin)) continue; // Check to see if monster is ALREADY in the path of this laser. // If so, allow the move so he can get out. - VectorMA(e->s.origin, 2048, e->movedir, laser_end); - laser_trace = SV_Trace(e->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER); + VectorMA(e->priv.sv->s.origin, 2048, e->progs.sv->movedir, laser_end); + laser_trace = SV_Trace(e->priv.sv->s.origin,NULL,NULL,laser_end,NULL,CONTENTS_SOLID|CONTENTS_MONSTER); if(laser_trace.ent == ent) continue; VectorCopy(laser_trace.endpos,laser_end); - laser_mins[0] = min(e->s.origin[0],laser_end[0]); - laser_mins[1] = min(e->s.origin[1],laser_end[1]); - laser_mins[2] = min(e->s.origin[2],laser_end[2]); - laser_maxs[0] = max(e->s.origin[0],laser_end[0]); - laser_maxs[1] = max(e->s.origin[1],laser_end[1]); - laser_maxs[2] = max(e->s.origin[2],laser_end[2]); - monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->mins[0]; - monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->mins[1]; - monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->mins[2]; - monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->maxs[0]; - monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->maxs[1]; - monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->maxs[2]; + laser_mins[0] = min(e->priv.sv->s.origin[0],laser_end[0]); + laser_mins[1] = min(e->priv.sv->s.origin[1],laser_end[1]); + laser_mins[2] = min(e->priv.sv->s.origin[2],laser_end[2]); + laser_maxs[0] = max(e->priv.sv->s.origin[0],laser_end[0]); + laser_maxs[1] = max(e->priv.sv->s.origin[1],laser_end[1]); + laser_maxs[2] = max(e->priv.sv->s.origin[2],laser_end[2]); + monster_mins[0] = min(oldorg[0],trace.endpos[0]) + ent->progs.sv->mins[0]; + monster_mins[1] = min(oldorg[1],trace.endpos[1]) + ent->progs.sv->mins[1]; + monster_mins[2] = min(oldorg[2],trace.endpos[2]) + ent->progs.sv->mins[2]; + monster_maxs[0] = max(oldorg[0],trace.endpos[0]) + ent->progs.sv->maxs[0]; + monster_maxs[1] = max(oldorg[1],trace.endpos[1]) + ent->progs.sv->maxs[1]; + monster_maxs[2] = max(oldorg[2],trace.endpos[2]) + ent->progs.sv->maxs[2]; if( monster_maxs[0] < laser_mins[0] ) continue; if( monster_maxs[1] < laser_mins[1] ) continue; if( monster_maxs[2] < laser_mins[2] ) continue; @@ -524,7 +517,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) // monster's total movement intersects laser bounding box. // If laser is parallel to x, y, or z, we definitely // know this move will put monster in path of laser - if ( (e->movedir[0] == 1.) || (e->movedir[1] == 1.) || (e->movedir[2] == 1.)) + if ( (e->progs.sv->movedir[0] == 1.) || (e->progs.sv->movedir[1] == 1.) || (e->progs.sv->movedir[2] == 1.)) return false; // Shift psuedo laser towards monster's current position up to // the total distance he's proposing moving. @@ -534,22 +527,22 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) while(delta < dist+15.875) { if(delta > dist) delta = dist; - VectorMA(e->s.origin, -delta,dir,laser_start); - VectorMA(e->s.old_origin,-delta,dir,laser_end); - laser_trace = SV_Trace(laser_start,NULL,NULL,laser_end,ge->edicts,CONTENTS_SOLID|CONTENTS_MONSTER); + VectorMA(e->priv.sv->s.origin, -delta,dir,laser_start); + VectorMA(e->priv.sv->s.old_origin,-delta,dir,laser_end); + laser_trace = SV_Trace(laser_start,NULL,NULL,laser_end,prog->edicts,CONTENTS_SOLID|CONTENTS_MONSTER); if(laser_trace.ent == ent) return false; delta += 16; } } } - if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.jumpdn > 0)) + if ((trace.fraction == 1) && !jump && canjump && (ent->progs.sv->jumpdn > 0)) { - end[2] = oldorg[2] + move[2] - ent->monsterinfo.jumpdn; - trace = SV_Trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER); + end[2] = oldorg[2] + move[2] - ent->progs.sv->jumpdn; + trace = SV_Trace (neworg, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_MONSTERSOLID | MASK_WATER); if(trace.fraction < 1 && (trace.plane.normal[2] > 0.9) && (trace.contents & MASK_SOLID) && (neworg[2] - 16 > trace.endpos[2])) { - if(!trace.ent || (!trace.ent->client && !(trace.ent->svflags & SVF_MONSTER) && !(trace.ent->svflags & SVF_DEADMONSTER))) + if(!trace.ent || (!trace.ent->priv.sv->client && !((int)trace.ent->progs.sv->flags & FL_MONSTER) && !((int)trace.ent->progs.sv->flags & FL_DEADMONSTER))) jump = -1; } } @@ -558,46 +551,46 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) if ((trace.fraction == 1) && !jump) { // if monster had the ground pulled out, go ahead and fall - if ( ent->flags & FL_PARTIALGROUND ) + if ((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) { - VectorAdd (ent->s.origin, move, ent->s.origin); + VectorAdd (ent->priv.sv->s.origin, move, ent->priv.sv->s.origin); if (relink) { SV_LinkEdict(ent); SV_TouchTriggers (ent); } - ent->groundentity = NULL; + ent->progs.sv->groundentity = 0; return true; } return false; // walked off an edge } // check point traces down for dangling corners - VectorCopy (trace.endpos, ent->s.origin); + VectorCopy (trace.endpos, ent->priv.sv->s.origin); if(!jump) { bool skip = false; // if monster CAN jump down, and a position just a bit forward would be // a good jump-down spot, allow (briefly) !M_CheckBottom - if (canjump && target && (target->s.origin[2] < ent->s.origin[2]) && (ent->monsterinfo.jumpdn > 0)) + if (canjump && target && (target->priv.sv->s.origin[2] < ent->priv.sv->s.origin[2]) && (ent->progs.sv->jumpdn > 0)) { vec3_t p1, p2; trace_t tr; VectorMA(oldorg,48,forward,p1); - tr = SV_Trace(ent->s.origin, ent->mins, ent->maxs, p1, ent, MASK_MONSTERSOLID); + tr = SV_Trace(ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, p1, ent, MASK_MONSTERSOLID); if(tr.fraction == 1) { p2[0] = p1[0]; p2[1] = p1[1]; - p2[2] = p1[2] - ent->monsterinfo.jumpdn; - tr = SV_Trace(p1,ent->mins,ent->maxs,p2,ent,MASK_MONSTERSOLID | MASK_WATER); + p2[2] = p1[2] - ent->progs.sv->jumpdn; + tr = SV_Trace(p1,ent->progs.sv->mins,ent->progs.sv->maxs,p2,ent,MASK_MONSTERSOLID | MASK_WATER); if(tr.fraction < 1 && (tr.plane.normal[2] > 0.9) && (tr.contents & MASK_SOLID) && (p1[2] - 16 > tr.endpos[2])) { - if(!tr.ent || (!tr.ent->client && !(tr.ent->svflags & SVF_MONSTER) && !(tr.ent->svflags & SVF_DEADMONSTER))) + if(!tr.ent || (!tr.ent->priv.sv->client && !((int)tr.ent->progs.sv->flags & FL_MONSTER) && !((int)tr.ent->progs.sv->flags & FL_DEADMONSTER))) { - VectorSubtract(target->s.origin, tr.endpos, dir); + VectorSubtract(target->priv.sv->s.origin, tr.endpos, dir); d2 = VectorLength(dir); if(d2 < d1) skip = true; @@ -610,7 +603,7 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) { if (!SV_CheckBottom (ent)) { - if ( ent->flags & FL_PARTIALGROUND ) + if ( (int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) { // entity had floor mostly pulled out from underneath it // and is trying to correct if (relink) @@ -620,33 +613,32 @@ bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) } return true; } - VectorCopy (oldorg, ent->s.origin); + VectorCopy (oldorg, ent->priv.sv->s.origin); return false; } } } - if ( ent->flags & FL_PARTIALGROUND ) + if ((int)ent->progs.sv->aiflags & AI_PARTIALONGROUND ) { - ent->flags &= ~FL_PARTIALGROUND; + (int)ent->progs.sv->aiflags &= ~AI_PARTIALONGROUND; } - ent->groundentity = trace.ent; - if(trace.ent) ent->groundentity_linkcount = trace.ent->linkcount; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); // the move is ok if(jump) { - VectorScale(move, 10, ent->velocity); + VectorScale(move, 10, ent->progs.sv->velocity); if(jump > 0) { - ent->monsterinfo.jump(ent); - ent->velocity[2] = 2.5*jumpheight + 80; +//ent->progs.sv->jump(ent); + ent->progs.sv->velocity[2] = 2.5*jumpheight + 80; } else { - ent->velocity[2] = max(ent->velocity[2],100); - if(oldorg[2] - ent->s.origin[2] > 48) - ent->s.origin[2] = oldorg[2] + ent->velocity[2]*0.1f; + ent->progs.sv->velocity[2] = max(ent->progs.sv->velocity[2],100); + if(oldorg[2] - ent->priv.sv->s.origin[2] > 48) + ent->priv.sv->s.origin[2] = oldorg[2] + ent->progs.sv->velocity[2]*0.1f; } if(relink) { @@ -671,7 +663,7 @@ bool SV_WalkMove (edict_t *ent, float yaw, float dist) { vec3_t move; - if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) + if (!ent->progs.sv->groundentity && !((int)ent->progs.sv->aiflags & (AI_FLY|AI_SWIM))) return false; yaw = yaw * M_PI*2 / 360; @@ -694,29 +686,29 @@ edict_t *SV_TestEntityPosition (edict_t *ent) trace_t trace; int mask; - if (ent->clipmask) mask = ent->clipmask; + if (ent->priv.sv->clipmask) mask = ent->priv.sv->clipmask; else mask = MASK_SOLID; - if(ent->solid == SOLID_BSP) + if(ent->progs.sv->solid == SOLID_BSP) { vec3_t org, mins, maxs; - VectorAdd(ent->s.origin, ent->origin_offset, org); - VectorSubtract(ent->mins, ent->origin_offset, mins); - VectorSubtract(ent->maxs, ent->origin_offset, maxs); + VectorAdd(ent->priv.sv->s.origin, ent->progs.sv->origin_offset, org); + VectorSubtract(ent->progs.sv->mins, ent->progs.sv->origin_offset, mins); + VectorSubtract(ent->progs.sv->maxs, ent->progs.sv->origin_offset, maxs); trace = SV_Trace (org, mins, maxs, org, ent, mask); } - else trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask); + else trace = SV_Trace (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, ent->priv.sv->s.origin, ent, mask); if (trace.startsolid) { // Lazarus - work around for players/monsters standing on dead monsters causing // those monsters to gib when rotating brush models are in the vicinity - if ( (ent->svflags & SVF_DEADMONSTER) && (trace.ent->client || (trace.ent->svflags & SVF_MONSTER))) + if ( ((int)ent->progs.sv->flags & FL_DEADMONSTER) && (trace.ent->priv.sv->client || ((int)trace.ent->progs.sv->flags & FL_MONSTER))) return NULL; // Lazarus - return a bit more useful info than simply "g_edicts" if(trace.ent) return trace.ent; - else return ge->edicts; + else return prog->edicts; } return NULL; @@ -729,10 +721,10 @@ SV_CheckVelocity */ void SV_CheckVelocity (edict_t *ent) { - if(VectorLength(ent->velocity) > sv_maxvelocity->value) + if(VectorLength(ent->progs.sv->velocity) > sv_maxvelocity->value) { - VectorNormalize(ent->velocity); - VectorScale(ent->velocity, sv_maxvelocity->value, ent->velocity); + VectorNormalize(ent->progs.sv->velocity); + VectorScale(ent->progs.sv->velocity, sv_maxvelocity->value, ent->progs.sv->velocity); } } @@ -745,20 +737,23 @@ Runs thinking code for this frame if necessary */ bool SV_RunThink (edict_t *ent) { - float thinktime; + float thinktime; - thinktime = ent->nextthink; - if(thinktime <= 0) return true; - - if(thinktime > sv.time + 0.001) + thinktime = ent->progs.sv->nextthink; + if (thinktime <= 0 || thinktime > sv.time + sv.frametime) return true; - - ent->nextthink = 0; - if (!ent->think) - PF_error ("NULL ent->think for %s",ent->classname); - ent->think (ent); - return false; + // don't let things stay in the past. + // it is possible to start that way by a trigger with a local time. + if (thinktime < sv.time) thinktime = sv.time; + + ent->progs.sv->nextthink = 0; //reset thinktime + prog->globals.server->time = thinktime; + prog->globals.server->pev = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_ExecuteProgram (ent->progs.sv->think, "QC function self.think is missing"); + + return !ent->priv.sv->free; } /* @@ -770,15 +765,44 @@ Two entities have touched, so run their touch functions */ void SV_Impact (edict_t *e1, trace_t *trace) { - edict_t *e2; + edict_t *e2 = (edict_t *)trace->ent; - e2 = trace->ent; + PRVM_PUSH_GLOBALS; - if (e1->touch && e1->solid != SOLID_NOT) - e1->touch (e1, e2, &trace->plane, trace->surface); - - if (e2->touch && e2->solid != SOLID_NOT) - e2->touch (e2, e1, NULL, NULL); + prog->globals.server->time = sv.time; + if (!e1->priv.sv->free && !e2->priv.sv->free && e1->progs.sv->touch && e1->progs.sv->solid != SOLID_NOT) + { + prog->globals.server->pev = PRVM_EDICT_TO_PROG(e1); + prog->globals.server->other = PRVM_EDICT_TO_PROG(e2); + prog->globals.server->time = sv.time; + prog->globals.server->trace_allsolid = trace->allsolid; + prog->globals.server->trace_startsolid = trace->startsolid; + prog->globals.server->trace_fraction = trace->fraction; + prog->globals.server->trace_contents = trace->contents; + VectorCopy (trace->endpos, prog->globals.server->trace_endpos); + VectorCopy (trace->plane.normal, prog->globals.server->trace_plane_normal); + prog->globals.server->trace_plane_dist = trace->plane.dist; + if (trace->ent) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace->ent); + else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_ExecuteProgram (e1->progs.sv->touch, "QC function pev->touch is missing"); + } + if (!e1->priv.sv->free && !e2->priv.sv->free && e2->progs.sv->touch && e2->progs.sv->solid != SOLID_NOT) + { + prog->globals.server->pev = PRVM_EDICT_TO_PROG(e2); + prog->globals.server->other = PRVM_EDICT_TO_PROG(e1); + prog->globals.server->time = sv.time; + prog->globals.server->trace_allsolid = false; + prog->globals.server->trace_startsolid = false; + prog->globals.server->trace_fraction = 1; + prog->globals.server->trace_contents = trace->contents; + VectorCopy (e2->progs.sv->origin, prog->globals.server->trace_endpos); + VectorSet (prog->globals.server->trace_plane_normal, 0, 0, 1); + prog->globals.server->trace_plane_dist = 0; + prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(e1); + PRVM_ExecuteProgram (e2->progs.sv->touch, "QC function pev->touch is missing"); + } + + PRVM_POP_GLOBALS; } @@ -845,31 +869,31 @@ retry: numbumps = 4; blocked = 0; - VectorCopy (ent->velocity, original_velocity); - VectorCopy (ent->velocity, primal_velocity); + VectorCopy (ent->progs.sv->velocity, original_velocity); + VectorCopy (ent->progs.sv->velocity, primal_velocity); numplanes = 0; time_left = time; - ent->groundentity = NULL; + ent->progs.sv->groundentity = 0; for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { - for (i = 0; i < 3; i++) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; + for (i = 0; i < 3; i++) end[i] = ent->priv.sv->s.origin[i] + time_left * ent->progs.sv->velocity[i]; - trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); + trace = SV_Trace (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); return 3; } if (trace.fraction > 0) { // actually covered some distance - VectorCopy (trace.endpos, ent->s.origin); - VectorCopy (ent->velocity, original_velocity); + VectorCopy (trace.endpos, ent->priv.sv->s.origin); + VectorCopy (ent->progs.sv->velocity, original_velocity); numplanes = 0; } @@ -882,35 +906,35 @@ retry: // try again if (!num_retries && wasonground) { - if ((hit->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7)) + if ((hit->progs.sv->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7)) { vec3_t above; VectorCopy(end,above); above[2] += 32; - trace = SV_Trace (above, ent->mins, ent->maxs, end, ent, mask); + trace = SV_Trace (above, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, mask); VectorCopy (trace.endpos,end); end[2] += 1; - VectorSubtract (end,ent->s.origin,ent->velocity); - VectorScale (ent->velocity,1.0/time_left,ent->velocity); + VectorSubtract (end,ent->priv.sv->s.origin,ent->progs.sv->velocity); + VectorScale (ent->progs.sv->velocity,1.0/time_left,ent->progs.sv->velocity); num_retries++; goto retry; } } // if blocked by player AND on a conveyor - if (hit && hit->client && onconveyor) + if (hit && hit->priv.sv->client && onconveyor) { vec3_t player_dest; trace_t ptrace; - if(ent->mass > hit->mass) + if(ent->progs.sv->mass > hit->progs.sv->mass) { - VectorMA (hit->s.origin,time_left,ent->velocity,player_dest); - ptrace = SV_Trace(hit->s.origin,hit->mins,hit->maxs,player_dest,hit,hit->clipmask); + VectorMA (hit->priv.sv->s.origin,time_left,ent->progs.sv->velocity,player_dest); + ptrace = SV_Trace(hit->priv.sv->s.origin,hit->progs.sv->mins,hit->progs.sv->maxs,player_dest,hit,hit->priv.sv->clipmask); if(ptrace.fraction == 1.0) { - VectorCopy(player_dest,hit->s.origin); + VectorCopy(player_dest,hit->priv.sv->s.origin); SV_LinkEdict(hit); goto retry; } @@ -921,10 +945,9 @@ retry: if (trace.plane.normal[2] > 0.7) { blocked |= 1; // floor - if ( hit->solid == SOLID_BSP) + if ( hit->progs.sv->solid == SOLID_BSP) { - ent->groundentity = hit; - ent->groundentity_linkcount = hit->linkcount; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(hit); } } if (!trace.plane.normal[2]) @@ -934,8 +957,7 @@ retry: // run the impact function SV_Impact (ent, &trace); - if (!ent->inuse) - break; // removed by the impact function + if (ent->priv.sv->free) break; // removed by the impact function time_left -= time_left * trace.fraction; @@ -944,7 +966,7 @@ retry: if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); blocked |= 3; return blocked; } @@ -969,27 +991,27 @@ retry: if (i != numplanes) { // go along this plane - VectorCopy (new_velocity, ent->velocity); + VectorCopy (new_velocity, ent->progs.sv->velocity); } else { // go along the crease if (numplanes != 2) { // gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); blocked |= 7; return blocked; } CrossProduct (planes[0], planes[1], dir); - d = DotProduct (dir, ent->velocity); - VectorScale (dir, d, ent->velocity); + d = DotProduct (dir, ent->progs.sv->velocity); + VectorScale (dir, d, ent->progs.sv->velocity); } // if original velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners - if (DotProduct (ent->velocity, primal_velocity) <= 0) + if (DotProduct (ent->progs.sv->velocity, primal_velocity) <= 0) { - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); return blocked; } } @@ -1032,32 +1054,32 @@ int SV_PushableMove (edict_t *ent, float time, int mask) retry: numbumps = 4; - ent->bouncetype = 0; + ent->progs.sv->bouncetype = 0; blocked = 0; - VectorCopy (ent->velocity, original_velocity); - VectorCopy (ent->velocity, primal_velocity); + VectorCopy (ent->progs.sv->velocity, original_velocity); + VectorCopy (ent->progs.sv->velocity, primal_velocity); numplanes = 0; time_left = time; - VectorAdd(ent->s.origin,ent->origin_offset,origin); - VectorCopy(ent->size,maxs); + VectorAdd(ent->priv.sv->s.origin,ent->progs.sv->origin_offset,origin); + VectorCopy(ent->progs.sv->size,maxs); VectorScale(maxs,0.5,maxs); VectorNegate(maxs,mins); - ent->groundentity = NULL; + ent->progs.sv->groundentity = 0; for (bumpcount=0 ; bumpcountvelocity[i]; + for (i = 0; i < 3; i++) end[i] = origin[i] + time_left * ent->progs.sv->velocity[i]; trace = SV_Trace (origin, mins, maxs, end, ent, mask); if (trace.allsolid) { // entity is trapped in another solid - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); return 3; } @@ -1065,8 +1087,8 @@ retry: { // actually covered some distance VectorCopy (trace.endpos, origin); - VectorSubtract (origin, ent->origin_offset, ent->s.origin); - VectorCopy (ent->velocity, original_velocity); + VectorSubtract (origin, ent->progs.sv->origin_offset, ent->priv.sv->s.origin); + VectorCopy (ent->progs.sv->velocity, original_velocity); numplanes = 0; } @@ -1079,7 +1101,7 @@ retry: // try again if (!num_retries && wasonground) { - if ((hit->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7)) + if ((hit->progs.sv->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7)) { vec3_t above; @@ -1087,26 +1109,26 @@ retry: above[2] += 32; trace = SV_Trace (above, mins, maxs, end, ent, mask); VectorCopy (trace.endpos,end); - VectorSubtract (end,origin,ent->velocity); - VectorScale (ent->velocity,1.0/time_left,ent->velocity); + VectorSubtract (end,origin,ent->progs.sv->velocity); + VectorScale (ent->progs.sv->velocity,1.0/time_left,ent->progs.sv->velocity); num_retries++; goto retry; } } // if blocked by player AND on a conveyor - if (hit->client && onconveyor) + if (hit->priv.sv->client && onconveyor) { vec3_t player_dest; trace_t ptrace; - if(ent->mass > hit->mass) + if(ent->progs.sv->mass > hit->progs.sv->mass) { - VectorMA (hit->s.origin,time_left,ent->velocity,player_dest); - ptrace = SV_Trace(hit->s.origin,hit->mins,hit->maxs,player_dest,hit,hit->clipmask); + VectorMA (hit->priv.sv->s.origin,time_left,ent->progs.sv->velocity,player_dest); + ptrace = SV_Trace(hit->priv.sv->s.origin,hit->progs.sv->mins,hit->progs.sv->maxs,player_dest,hit,hit->priv.sv->clipmask); if(ptrace.fraction == 1.0) { - VectorCopy(player_dest,hit->s.origin); + VectorCopy(player_dest,hit->priv.sv->s.origin); SV_LinkEdict(hit); goto retry; } @@ -1118,13 +1140,12 @@ retry: { // Lazarus: special case - if this ent or the impact ent is // in water, motion is NOT blocked. - if((hit->movetype != MOVETYPE_PUSHABLE) || ((ent->waterlevel==0) && (hit->waterlevel==0))) + if((hit->progs.sv->movetype != MOVETYPE_PUSHABLE) || ((ent->progs.sv->waterlevel==0) && (hit->progs.sv->waterlevel==0))) { blocked |= 1; // floor - if ( hit->solid == SOLID_BSP) + if ( hit->progs.sv->solid == SOLID_BSP) { - ent->groundentity = hit; - ent->groundentity_linkcount = hit->linkcount; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(hit); } } } @@ -1135,7 +1156,7 @@ retry: // run the impact function SV_Impact (ent, &trace); - if (!ent->inuse) break; // removed by the impact function + if (ent->priv.sv->free) break; // removed by the impact function time_left -= time_left * trace.fraction; @@ -1143,7 +1164,7 @@ retry: if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); blocked |= 3; return blocked; } @@ -1156,14 +1177,13 @@ retry: { // DH: experimenting here. 1 is no bounce, // 1.5 bounces like a grenade, 2 is a superball - if(ent->bouncetype == 1) + if(ent->progs.sv->bouncetype == 1) { ClipVelocity (original_velocity, planes[i], new_velocity, 1.4); // stop small oscillations if (new_velocity[2] < 60) { - ent->groundentity = trace.ent; - ent->groundentity_linkcount = trace.ent->linkcount; + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); VectorCopy (vec3_origin, new_velocity); } else @@ -1173,9 +1193,9 @@ retry: if(!new_velocity[1]) new_velocity[1] = crandom() * new_velocity[2]/4; } } - else if(ent->bouncetype == 2) + else if(ent->progs.sv->bouncetype == 2) { - VectorCopy(ent->velocity, new_velocity); + VectorCopy(ent->progs.sv->velocity, new_velocity); } else { @@ -1195,28 +1215,28 @@ retry: if (i != numplanes) { // go along this plane - VectorCopy (new_velocity, ent->velocity); + VectorCopy (new_velocity, ent->progs.sv->velocity); } else { // go along the crease if (numplanes != 2) { - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); blocked |= 7; return blocked; } CrossProduct (planes[0], planes[1], dir); - d = DotProduct (dir, ent->velocity); - VectorScale (dir, d, ent->velocity); + d = DotProduct (dir, ent->progs.sv->velocity); + VectorScale (dir, d, ent->progs.sv->velocity); } // if velocity is against the original velocity, stop dead // to avoid tiny occilations in sloping corners - if( !ent->bouncetype ) + if( !ent->progs.sv->bouncetype ) { - if (DotProduct (ent->velocity, primal_velocity) <= 0) + if (DotProduct (ent->progs.sv->velocity, primal_velocity) <= 0) { - VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->progs.sv->velocity); return blocked; } } @@ -1232,8 +1252,7 @@ SV_AddGravity */ void SV_AddGravity (edict_t *ent) { - if(sv.time > ent->gravity_debounce_time) - ent->velocity[2] -= ent->gravity * sv_gravity->value * 0.1; + ent->progs.sv->velocity[2] -= ent->progs.sv->gravity * sv_gravity->value * 0.1; } /* @@ -1263,18 +1282,18 @@ trace_t SV_PushEntity (edict_t *ent, vec3_t push) int mask; int num_retries=0; - VectorCopy (ent->s.origin, start); + VectorCopy (ent->priv.sv->s.origin, start); VectorAdd (start, push, end); - if (ent->clipmask) - mask = ent->clipmask; + if (ent->priv.sv->clipmask) + mask = ent->priv.sv->clipmask; else mask = MASK_SOLID; retry: - trace = SV_Trace (start, ent->mins, ent->maxs, end, ent, mask); + trace = SV_Trace (start, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, mask); - VectorCopy (trace.endpos, ent->s.origin); + VectorCopy (trace.endpos, ent->priv.sv->s.origin); SV_LinkEdict (ent); if (trace.fraction != 1.0) @@ -1282,10 +1301,10 @@ retry: SV_Impact (ent, &trace); // if the pushed entity went away and the pusher is still there - if (!trace.ent->inuse && ent->inuse) + if (trace.ent->priv.sv->free && !ent->priv.sv->free) { // move the pusher back and try again - VectorCopy (start, ent->s.origin); + VectorCopy (start, ent->priv.sv->s.origin); SV_LinkEdict (ent); goto retry; } @@ -1294,29 +1313,29 @@ retry: // try again if (!num_retries && wasonground) { - if ((trace.ent->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7) && !trace.startsolid) + if ((trace.ent->progs.sv->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7) && !trace.startsolid) { vec3_t above; VectorCopy(end,above); above[2] += 32; - trace = SV_Trace (above, ent->mins, ent->maxs, end, ent, mask); + trace = SV_Trace (above, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, mask); VectorCopy (trace.endpos, end); - VectorCopy (start, ent->s.origin); + VectorCopy (start, ent->priv.sv->s.origin); SV_LinkEdict(ent); num_retries++; goto retry; } } - if(onconveyor && !trace.ent->client) + if(onconveyor && !trace.ent->priv.sv->client) { // If blocker can be damaged, destroy it. Otherwise destroy blockee. - if(trace.ent->takedamage == DAMAGE_YES) - T_Damage(trace.ent, ent, ent, vec3_origin, trace.ent->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); - else T_Damage(ent, trace.ent, trace.ent, vec3_origin, ent->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); + if(trace.ent->progs.sv->takedamage == DAMAGE_YES) + T_Damage(trace.ent, ent, ent, vec3_origin, trace.ent->priv.sv->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); + else T_Damage(ent, trace.ent, trace.ent, vec3_origin, ent->priv.sv->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); } } - if (ent->inuse) SV_TouchTriggers (ent); + if (!ent->priv.sv->free) SV_TouchTriggers (ent); return trace; } @@ -1338,20 +1357,20 @@ void MoveRiders_r(edict_t *platform, edict_t *ignore, vec3_t move, vec3_t amove, int i; edict_t *rider; - for(i = 1, rider = EDICT_NUM(i); i <= ge->num_edicts; i++, rider = EDICT_NUM(i)) + for(i = 1, rider = PRVM_EDICT_NUM(i); i <= prog->num_edicts; i++, rider = PRVM_EDICT_NUM(i)) { - if((rider->groundentity == platform) && (rider != ignore)) + if((rider->progs.sv->groundentity == PRVM_EDICT_TO_PROG(platform)) && (rider != ignore)) { - VectorAdd(rider->s.origin, move, rider->s.origin); + VectorAdd(rider->priv.sv->s.origin, move, rider->priv.sv->s.origin); if (turn && (amove[YAW] != 0.)) { - if(!rider->client) rider->s.angles[YAW] += amove[YAW]; + if(!rider->priv.sv->client) rider->priv.sv->s.angles[YAW] += amove[YAW]; else { - rider->s.angles[YAW] += amove[YAW]; - rider->client->ps.pmove.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]); - rider->client->ps.pmove.pm_type = PM_FREEZE; - rider->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; + rider->priv.sv->s.angles[YAW] += amove[YAW]; + rider->priv.sv->client->ps.pmove.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]); + rider->priv.sv->client->ps.pmove.pm_type = PM_FREEZE; + rider->priv.sv->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; } } SV_LinkEdict(rider); @@ -1360,14 +1379,14 @@ void MoveRiders_r(edict_t *platform, edict_t *ignore, vec3_t move, vec3_t amove, { // Move is blocked. Since this is for riders, not pushees, // it should be ok to just back the move for this rider off - VectorSubtract(rider->s.origin,move,rider->s.origin); + VectorSubtract(rider->priv.sv->s.origin,move,rider->priv.sv->s.origin); if(turn && (amove[YAW] != 0.)) { - rider->s.angles[YAW] -= amove[YAW]; - if(rider->client) + rider->priv.sv->s.angles[YAW] -= amove[YAW]; + if(rider->priv.sv->client) { - rider->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); - rider->client->ps.viewangles[YAW] -= amove[YAW]; + rider->priv.sv->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); + rider->priv.sv->client->ps.viewangles[YAW] -= amove[YAW]; } } SV_LinkEdict(rider); @@ -1401,8 +1420,8 @@ void RealBoundingBox(edict_t *ent, vec3_t mins, vec3_t maxs) for(k = 0; k < 2; k++) { k4 = k * 4; - if(k) p[k4][2] = ent->maxs[2]; - else p[k4][2] = ent->mins[2]; + if(k) p[k4][2] = ent->progs.sv->maxs[2]; + else p[k4][2] = ent->progs.sv->mins[2]; p[k4 + 1][2] = p[k4][2]; p[k4 + 2][2] = p[k4][2]; @@ -1411,26 +1430,26 @@ void RealBoundingBox(edict_t *ent, vec3_t mins, vec3_t maxs) for(j = 0; j < 2; j++) { j2 = j * 2; - if(j) p[j2+k4][1] = ent->maxs[1]; - else p[j2+k4][1] = ent->mins[1]; + if(j) p[j2+k4][1] = ent->progs.sv->maxs[1]; + else p[j2+k4][1] = ent->progs.sv->mins[1]; p[j2 + k4 + 1][1] = p[j2 + k4][1]; for(i = 0; i < 2; i++) { - if(i) p[i + j2 + k4][0] = ent->maxs[0]; - else p[i + j2 + k4][0] = ent->mins[0]; + if(i) p[i + j2 + k4][0] = ent->progs.sv->maxs[0]; + else p[i + j2 + k4][0] = ent->progs.sv->mins[0]; } } } - AngleVectors(ent->s.angles, forward, left, up); + AngleVectors(ent->priv.sv->s.angles, forward, left, up); for(i = 0; i < 8; i++) { VectorScale(forward, p[i][0], f1); VectorScale(left, -p[i][1], l1); VectorScale(up, p[i][2], u1); - VectorAdd(ent->s.origin, f1, p[i]); + VectorAdd(ent->priv.sv->s.origin, f1, p[i]); VectorAdd(p[i], l1, p[i]); VectorAdd(p[i], u1, p[i]); } @@ -1484,8 +1503,8 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) // find the bounding box for (i = 0; i < 3; i++) { - mins[i] = pusher->absmin[i] + move[i]; - maxs[i] = pusher->absmax[i] + move[i]; + mins[i] = pusher->progs.sv->absmin[i] + move[i]; + maxs[i] = pusher->progs.sv->absmax[i] + move[i]; } // we need this for pushing things later @@ -1494,14 +1513,14 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) // save the pusher's original position pushed_p->ent = pusher; - VectorCopy (pusher->s.origin, pushed_p->origin); - VectorCopy (pusher->s.angles, pushed_p->angles); - if (pusher->client) pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW]; + VectorCopy (pusher->priv.sv->s.origin, pushed_p->origin); + VectorCopy (pusher->priv.sv->s.angles, pushed_p->angles); + if (pusher->priv.sv->client) pushed_p->deltayaw = pusher->priv.sv->client->ps.pmove.delta_angles[YAW]; pushed_p++; // move the pusher to it's final position - VectorAdd (pusher->s.origin, move, pusher->s.origin); - VectorAdd (pusher->s.angles, amove, pusher->s.angles); + VectorAdd (pusher->priv.sv->s.origin, move, pusher->priv.sv->s.origin); + VectorAdd (pusher->priv.sv->s.angles, amove, pusher->priv.sv->s.angles); SV_LinkEdict (pusher); // Lazarus: Standard Q2 takes a horrible shortcut @@ -1517,28 +1536,28 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) RealBoundingBox(pusher,realmins,realmaxs); // see if any solid entities are inside the final position - check = EDICT_NUM( 1 ); + check = PRVM_EDICT_NUM( 1 ); - for (e = 1; e < ge->num_edicts; e++, check = EDICT_NUM(e)) + for (e = 1; e < prog->num_edicts; e++, check = PRVM_EDICT_NUM(e)) { - if (!check->inuse) continue; - if (check == pusher->owner) continue; - if (check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_NONE || check->movetype == MOVETYPE_NOCLIP) + if (check->priv.sv->free) continue; + if (check == PRVM_PROG_TO_EDICT(pusher->progs.sv->owner)) continue; + if (check->progs.sv->movetype == MOVETYPE_PUSH || check->progs.sv->movetype == MOVETYPE_NONE || check->progs.sv->movetype == MOVETYPE_NOCLIP) continue; - if (!check->area.prev) + if (!check->priv.sv->area.prev) continue; // not linked in anywhere // if the entity is standing on the pusher, it will definitely be moved - if (check->groundentity != pusher) + if (check->progs.sv->groundentity != PRVM_EDICT_TO_PROG(pusher)) { // see if the ent needs to be tested - if ( check->absmin[0] >= realmaxs[0] - || check->absmin[1] >= realmaxs[1] - || check->absmin[2] >= realmaxs[2] - || check->absmax[0] <= realmins[0] - || check->absmax[1] <= realmins[1] - || check->absmax[2] <= realmins[2] ) + if ( check->progs.sv->absmin[0] >= realmaxs[0] + || check->progs.sv->absmin[1] >= realmaxs[1] + || check->progs.sv->absmin[2] >= realmaxs[2] + || check->progs.sv->absmax[0] <= realmins[0] + || check->progs.sv->absmax[1] <= realmins[1] + || check->progs.sv->absmax[2] <= realmins[2] ) continue; // see if the ent's bbox is inside the pusher's final position @@ -1549,112 +1568,112 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) // Lazarus: func_tracktrain-specific stuff // If train is *driven*, then hurt monsters/players it touches NOW // rather than waiting to be blocked. - if ((pusher->flags & FL_TRACKTRAIN) && pusher->owner && ((check->svflags & SVF_MONSTER) || check->client) && (check->groundentity != pusher)) + if (((int)pusher->progs.sv->flags & FL_TRACKTRAIN) && pusher->progs.sv->owner && (((int)check->progs.sv->flags & FL_MONSTER) || check->priv.sv->client) && (check->progs.sv->groundentity != PRVM_EDICT_TO_PROG(pusher))) { vec3_t dir; - VectorSubtract(check->s.origin,pusher->s.origin,dir); + VectorSubtract(check->priv.sv->s.origin,pusher->priv.sv->s.origin,dir); dir[2] += 16; VectorNormalize(dir); - T_Damage (check, pusher, pusher, dir, check->s.origin, vec3_origin, pusher->dmg, 1, 0, DMG_CRUSH); + T_Damage (check, pusher, pusher, dir, check->priv.sv->s.origin, vec3_origin, pusher->progs.sv->dmg, 1, 0, DMG_CRUSH); } - if ((pusher->movetype == MOVETYPE_PUSH) || (pusher->movetype == MOVETYPE_PENDULUM) || (check->groundentity == pusher)) + if ((pusher->progs.sv->movetype == MOVETYPE_PUSH) || (pusher->progs.sv->movetype == MOVETYPE_PENDULUM) || (check->progs.sv->groundentity == PRVM_EDICT_TO_PROG(pusher))) { // move this entity pushed_p->ent = check; - VectorCopy (check->s.origin, pushed_p->origin); - VectorCopy (check->s.angles, pushed_p->angles); + VectorCopy (check->priv.sv->s.origin, pushed_p->origin); + VectorCopy (check->priv.sv->s.angles, pushed_p->angles); pushed_p++; // try moving the contacted entity - VectorAdd (check->s.origin, move, check->s.origin); + VectorAdd (check->priv.sv->s.origin, move, check->priv.sv->s.origin); // Lazarus: if turn_rider is set, do it. We don't do this by default // 'cause it can be a fairly drastic change in gameplay - if (turn && (check->groundentity == pusher)) + if (turn && (check->progs.sv->groundentity == PRVM_EDICT_TO_PROG(pusher))) { - if(!check->client) + if(!check->priv.sv->client) { - check->s.angles[YAW] += amove[YAW]; + check->priv.sv->s.angles[YAW] += amove[YAW]; } else { if(amove[YAW] != 0.) { - check->client->ps.pmove.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]); - check->client->ps.viewangles[YAW] += amove[YAW]; + check->priv.sv->client->ps.pmove.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]); + check->priv.sv->client->ps.viewangles[YAW] += amove[YAW]; // PM_FREEZE makes the turn smooth, even though it will // be turned off by ClientThink in the very next video frame - check->client->ps.pmove.pm_type = PM_FREEZE; + check->priv.sv->client->ps.pmove.pm_type = PM_FREEZE; // PMF_NO_PREDICTION overrides .exe's client physics, which // really doesn't like for us to change player angles. Note // that this isn't strictly necessary, since Lazarus 1.7 and // later automatically turn prediction off (in ClientThink) when // player is riding a MOVETYPE_PUSH - check->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; + check->priv.sv->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; } if(amove[PITCH] != 0.) { float delta_yaw; float pitch = amove[PITCH]; - delta_yaw = check->s.angles[YAW] - pusher->s.angles[YAW]; + delta_yaw = check->priv.sv->s.angles[YAW] - pusher->priv.sv->s.angles[YAW]; delta_yaw *= M_PI / 180.; pitch *= cos(delta_yaw); - check->client->ps.pmove.delta_angles[PITCH] += ANGLE2SHORT(pitch); - check->client->ps.viewangles[PITCH] += pitch; - check->client->ps.pmove.pm_type = PM_FREEZE; - check->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; + check->priv.sv->client->ps.pmove.delta_angles[PITCH] += ANGLE2SHORT(pitch); + check->priv.sv->client->ps.viewangles[PITCH] += pitch; + check->priv.sv->client->ps.pmove.pm_type = PM_FREEZE; + check->priv.sv->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION; } } } // Lazarus: This is where we attempt to move check due to a rotation, WITHOUT embedding // check in pusher (or anything else) - if(check->groundentity == pusher) + if(check->progs.sv->groundentity == PRVM_EDICT_TO_PROG(pusher)) { if((amove[PITCH] != 0) || (amove[YAW] != 0) || (amove[ROLL] != 0)) { // figure movement due to the pusher's amove - VectorAdd(check->s.origin,check->origin_offset,org_check); - VectorSubtract (org_check, pusher->s.origin, org); + VectorAdd(check->priv.sv->s.origin,check->progs.sv->origin_offset,org_check); + VectorSubtract (org_check, pusher->priv.sv->s.origin, org); org2[0] = DotProduct (org, forward); org2[1] = -DotProduct (org, right); org2[2] = DotProduct (org, up); VectorSubtract (org2, org, move2); - VectorAdd (check->s.origin, move2, check->s.origin); + VectorAdd (check->priv.sv->s.origin, move2, check->priv.sv->s.origin); if((amove[PITCH] != 0) || (amove[ROLL] != 0)) { - VectorCopy(check->s.origin,org); - org[2] += 2*check->mins[2]; - tr = SV_Trace(check->s.origin,vec3_origin,vec3_origin,org,check,MASK_SOLID); + VectorCopy(check->priv.sv->s.origin,org); + org[2] += 2*check->progs.sv->mins[2]; + tr = SV_Trace(check->priv.sv->s.origin,vec3_origin,vec3_origin,org,check,MASK_SOLID); if(!tr.startsolid && tr.fraction < 1) - check->s.origin[2] = tr.endpos[2] - check->mins[2] + fabs(tr.plane.normal[0])*check->size[0]/2 + fabs(tr.plane.normal[1])*check->size[1]/2; + check->priv.sv->s.origin[2] = tr.endpos[2] - check->progs.sv->mins[2] + fabs(tr.plane.normal[0])*check->progs.sv->size[0]/2 + fabs(tr.plane.normal[1])*check->progs.sv->size[1]/2; // Lazarus: func_tracktrain is a special case. Since we KNOW (if the map was - // constructed properly) that "move_origin" is a safe position, we + // constructed properly) that "post_origin" is a safe position, we // can infer that there should be a safe (not embedded) position - // somewhere between move_origin and the proposed new location. - if((pusher->flags & FL_TRACKTRAIN) && (check->client || (check->svflags & SVF_MONSTER))) + // somewhere between post_origin and the proposed new location. + if(((int)pusher->progs.sv->flags & FL_TRACKTRAIN) && (check->priv.sv->client || ((int)check->progs.sv->flags & FL_MONSTER))) { vec3_t f,l,u; - AngleVectors(pusher->s.angles, f, l, u); - VectorScale(f,pusher->move_origin[0],f); - VectorScale(l,-pusher->move_origin[1],l); - VectorAdd(pusher->s.origin,f,org); + AngleVectors(pusher->priv.sv->s.angles, f, l, u); + VectorScale(f,pusher->progs.sv->post_origin[0],f); + VectorScale(l,-pusher->progs.sv->post_origin[1],l); + VectorAdd(pusher->priv.sv->s.origin,f,org); VectorAdd(org,l,org); - org[2] += pusher->move_origin[2] + 1; + org[2] += pusher->progs.sv->post_origin[2] + 1; org[2] += 16 * ( fabs(u[0]) + fabs(u[1]) ); - tr = SV_Trace(org,check->mins,check->maxs,check->s.origin,check,MASK_SOLID); + tr = SV_Trace(org,check->progs.sv->mins,check->progs.sv->maxs,check->priv.sv->s.origin,check,MASK_SOLID); if(!tr.startsolid) { - VectorCopy(tr.endpos,check->s.origin); - VectorCopy(check->s.origin,org); + VectorCopy(tr.endpos,check->priv.sv->s.origin); + VectorCopy(check->priv.sv->s.origin,org); org[2] -= 128; - tr = SV_Trace(check->s.origin,check->mins,check->maxs,org,check,MASK_SOLID); + tr = SV_Trace(check->priv.sv->s.origin,check->progs.sv->mins,check->progs.sv->maxs,org,check,MASK_SOLID); if(tr.fraction > 0) - VectorCopy(tr.endpos,check->s.origin); + VectorCopy(tr.endpos,check->priv.sv->s.origin); } } } @@ -1662,32 +1681,32 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) } // may have pushed them off an edge - if (check->groundentity != pusher) check->groundentity = NULL; + if (check->progs.sv->groundentity != PRVM_EDICT_TO_PROG(pusher)) check->progs.sv->groundentity = 0; block = SV_TestEntityPosition (check); - if (block && (pusher->flags & FL_TRACKTRAIN) && (check->client || (check->svflags & SVF_MONSTER)) && (check->groundentity == pusher) ) + if (block && ((int)pusher->progs.sv->flags & FL_TRACKTRAIN) && (check->priv.sv->client || ((int)check->progs.sv->flags & FL_MONSTER)) && (check->progs.sv->groundentity == PRVM_EDICT_TO_PROG(pusher))) { // Lazarus: Last hope. If this doesn't get rider out of the way he's // gonna be stuck. vec3_t f,l,u; - AngleVectors(pusher->s.angles, f, l, u); - VectorScale(f,pusher->move_origin[0],f); - VectorScale(l,-pusher->move_origin[1],l); - VectorAdd(pusher->s.origin,f,org); + AngleVectors(pusher->priv.sv->s.angles, f, l, u); + VectorScale(f,pusher->progs.sv->post_origin[0],f); + VectorScale(l,-pusher->progs.sv->post_origin[1],l); + VectorAdd(pusher->priv.sv->s.origin,f,org); VectorAdd(org,l,org); - org[2] += pusher->move_origin[2] + 1; + org[2] += pusher->progs.sv->post_origin[2] + 1; org[2] += 16 * ( fabs(u[0]) + fabs(u[1]) ); - tr = SV_Trace(org,check->mins,check->maxs,check->s.origin,check,MASK_SOLID); + tr = SV_Trace(org,check->progs.sv->mins,check->progs.sv->maxs,check->priv.sv->s.origin,check,MASK_SOLID); if(!tr.startsolid) { - VectorCopy(tr.endpos,check->s.origin); - VectorCopy(check->s.origin,org); + VectorCopy(tr.endpos,check->priv.sv->s.origin); + VectorCopy(check->priv.sv->s.origin,org); org[2] -= 128; - tr = SV_Trace(check->s.origin,check->mins,check->maxs,org,check,MASK_SOLID); + tr = SV_Trace(check->priv.sv->s.origin,check->progs.sv->mins,check->progs.sv->maxs,org,check,MASK_SOLID); if(tr.fraction > 0) - VectorCopy(tr.endpos,check->s.origin); + VectorCopy(tr.endpos,check->priv.sv->s.origin); block = SV_TestEntityPosition (check); } } @@ -1703,16 +1722,16 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) // if it is ok to leave in the old position, do it // this is only relevent for riding entities, not pushed - VectorSubtract (check->s.origin, move, check->s.origin); - VectorSubtract (check->s.origin, move2, check->s.origin); + VectorSubtract (check->priv.sv->s.origin, move, check->priv.sv->s.origin); + VectorSubtract (check->priv.sv->s.origin, move2, check->priv.sv->s.origin); if(turn) { // Argh! - angle - check->s.angles[YAW] -= amove[YAW]; - if(check->client) + check->priv.sv->s.angles[YAW] -= amove[YAW]; + if(check->priv.sv->client) { - check->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); - check->client->ps.viewangles[YAW] -= amove[YAW]; + check->priv.sv->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); + check->priv.sv->client->ps.viewangles[YAW] -= amove[YAW]; } } @@ -1732,11 +1751,11 @@ bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) // twice, it goes back to the original position for (p=pushed_p-1 ; p>=pushed ; p--) { - VectorCopy (p->origin, p->ent->s.origin); - VectorCopy (p->angles, p->ent->s.angles); - if (p->ent->client) + VectorCopy (p->origin, p->ent->priv.sv->s.origin); + VectorCopy (p->angles, p->ent->priv.sv->s.angles); + if (p->ent->priv.sv->client) { - p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; + p->ent->priv.sv->client->ps.pmove.delta_angles[YAW] = p->deltayaw; } SV_LinkEdict (p->ent); } @@ -1768,17 +1787,17 @@ void SV_Physics_Pusher (edict_t *ent) // if the move is blocked, all moved objects will be backed out pushed_p = pushed; - if (part->velocity[0] || part->velocity[1] || part->velocity[2] || part->avelocity[0] || part->avelocity[1] || part->avelocity[2]) + if (part->progs.sv->velocity[0] || part->progs.sv->velocity[1] || part->progs.sv->velocity[2] || part->progs.sv->avelocity[0] || part->progs.sv->avelocity[1] || part->progs.sv->avelocity[2]) { // object is moving - VectorScale (part->velocity, 0.1f, move); - VectorScale (part->avelocity, 0.1f, amove); + VectorScale (part->progs.sv->velocity, 0.1f, move); + VectorScale (part->progs.sv->avelocity, 0.1f, amove); SV_Push(part, move, amove); // move was blocked } if (pushed_p > &pushed[MAX_EDICTS]) - PF_error("pushed_p > &pushed[MAX_EDICTS], memory corrupted"); + PRVM_ERROR("pushed_p > &pushed[MAX_EDICTS], memory corrupted"); SV_RunThink (part); } @@ -1810,8 +1829,8 @@ void SV_Physics_Noclip (edict_t *ent) // regular thinking if (!SV_RunThink (ent)) return; - VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); - VectorMA (ent->s.origin, 0.1f, ent->velocity, ent->s.origin); + VectorMA (ent->priv.sv->s.angles, 0.1f, ent->progs.sv->avelocity, ent->priv.sv->s.angles); + VectorMA (ent->priv.sv->s.origin, 0.1f, ent->progs.sv->velocity, ent->priv.sv->s.origin); SV_LinkEdict(ent); } @@ -1843,106 +1862,104 @@ void SV_Physics_Toss (edict_t *ent) // regular thinking SV_RunThink (ent); - if (ent->groundentity) wasonground = true; + if (ent->progs.sv->groundentity) wasonground = true; - if (ent->velocity[2] > 0) ent->groundentity = NULL; + if (ent->progs.sv->velocity[2] > 0) ent->progs.sv->groundentity = 0; // check for the groundentity going away - if (ent->groundentity) - if (!ent->groundentity->inuse) - ent->groundentity = NULL; + if (ent->progs.sv->groundentity) + if (PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity)->priv.sv->free) + ent->progs.sv->groundentity = 0; // Lazarus: conveyor - if (ent->groundentity && (ent->groundentity->movetype == MOVETYPE_CONVEYOR)) + if (ent->progs.sv->groundentity && (PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity)->progs.sv->movetype == MOVETYPE_CONVEYOR)) { vec3_t point, end; trace_t tr; - edict_t *ground = ent->groundentity; + edict_t *ground = PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity); - VectorCopy(ent->s.origin,point); + VectorCopy(ent->priv.sv->s.origin,point); point[2] += 1; VectorCopy(point,end); end[2] -= 256; - tr = SV_Trace (point, ent->mins, ent->maxs, end, ent, MASK_SOLID); + tr = SV_Trace (point, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_SOLID); // tr.ent HAS to be ground, but just in case we screwed something up: if(tr.ent == ground) { onconveyor = true; - ent->velocity[0] = ground->movedir[0] * ground->speed; - ent->velocity[1] = ground->movedir[1] * ground->speed; + ent->progs.sv->velocity[0] = ground->progs.sv->movedir[0] * ground->progs.sv->speed; + ent->progs.sv->velocity[1] = ground->progs.sv->movedir[1] * ground->progs.sv->speed; if(tr.plane.normal[2] > 0) { - ent->velocity[2] = ground->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; - if(DotProduct(ground->movedir,tr.plane.normal) > 0) + ent->progs.sv->velocity[2] = ground->progs.sv->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; + if(DotProduct(ground->progs.sv->movedir,tr.plane.normal) > 0) { // then we're moving down - ent->velocity[2] = -ent->velocity[2]; + ent->progs.sv->velocity[2] = -ent->progs.sv->velocity[2]; } } - VectorScale (ent->velocity, 0.1f, move); + VectorScale (ent->progs.sv->velocity, 0.1f, move); trace = SV_PushEntity (ent, move); - if (!ent->inuse) return; + if (ent->priv.sv->free) return; SV_CheckGround(ent); } } // if onground, return without moving - if ( ent->groundentity ) + if ( ent->progs.sv->groundentity ) return; - VectorCopy (ent->s.origin, old_origin); + VectorCopy (ent->priv.sv->s.origin, old_origin); SV_CheckVelocity (ent); // add gravity - if (ent->movetype != MOVETYPE_FLY) + if (ent->progs.sv->movetype != MOVETYPE_FLY) SV_AddGravity (ent); // move angles - VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); + VectorMA (ent->priv.sv->s.angles, 0.1f, ent->progs.sv->avelocity, ent->priv.sv->s.angles); // move origin - VectorScale (ent->velocity, 0.1f, move); + VectorScale (ent->progs.sv->velocity, 0.1f, move); trace = SV_PushEntity (ent, move); - if (!ent->inuse) - return; + if (ent->priv.sv->free) return; if (trace.fraction < 1 ) { - if (ent->movetype == MOVETYPE_BOUNCE) + if (ent->progs.sv->movetype == MOVETYPE_BOUNCE) backoff = 1.0 + 0.5f; else if(trace.plane.normal[2] <= 0.7) // Lazarus - don't stop on steep incline backoff = 1.5; else backoff = 1; - ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); + ClipVelocity (ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.7) { - if (ent->velocity[2] < 60.0f || (ent->movetype != MOVETYPE_BOUNCE) ) + if (ent->progs.sv->velocity[2] < 60.0f || (ent->progs.sv->movetype != MOVETYPE_BOUNCE) ) { - ent->groundentity = trace.ent; - ent->groundentity_linkcount = trace.ent->linkcount; - VectorCopy (vec3_origin, ent->velocity); - VectorCopy (vec3_origin, ent->avelocity); + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + VectorCopy (vec3_origin, ent->progs.sv->velocity); + VectorCopy (vec3_origin, ent->progs.sv->avelocity); } } } // check for water transition - wasinwater = (ent->watertype & MASK_WATER); - ent->watertype = SV_PointContents (ent->s.origin); - isinwater = ent->watertype & MASK_WATER; + wasinwater = ((int)ent->progs.sv->watertype & MASK_WATER); + ent->progs.sv->watertype = SV_PointContents (ent->priv.sv->s.origin); + isinwater = (int)ent->progs.sv->watertype & MASK_WATER; - if (isinwater) ent->waterlevel = 1; - else ent->waterlevel = 0; + if (isinwater) ent->progs.sv->waterlevel = 1; + else ent->progs.sv->waterlevel = 0; if (!wasinwater && isinwater) - SV_StartSound(old_origin, ge->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); + SV_StartSound(old_origin, prog->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); else if (wasinwater && !isinwater) - SV_StartSound(ent->s.origin, ge->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); + SV_StartSound(ent->priv.sv->s.origin, prog->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); } /* @@ -1975,22 +1992,22 @@ void SV_AddRotationalFriction (edict_t *ent) int n; float adjustment; - VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); + VectorMA (ent->priv.sv->s.angles, 0.1f, ent->progs.sv->avelocity, ent->priv.sv->s.angles); adjustment = 0.1f * sv_stopspeed * sv_friction; for (n = 0; n < 3; n++) { - if (ent->avelocity[n] > 0) + if (ent->progs.sv->avelocity[n] > 0) { - ent->avelocity[n] -= adjustment; - if (ent->avelocity[n] < 0) - ent->avelocity[n] = 0; + ent->progs.sv->avelocity[n] -= adjustment; + if (ent->progs.sv->avelocity[n] < 0) + ent->progs.sv->avelocity[n] = 0; } else { - ent->avelocity[n] += adjustment; - if (ent->avelocity[n] > 0) - ent->avelocity[n] = 0; + ent->progs.sv->avelocity[n] += adjustment; + if (ent->progs.sv->avelocity[n] > 0) + ent->progs.sv->avelocity[n] = 0; } } } @@ -2005,31 +2022,31 @@ float RiderMass(edict_t *platform) trace_t trace; vec3_t point; - for(i = 1, rider = EDICT_NUM(i); i <= ge->num_edicts; i++, rider = EDICT_NUM(i)) + for(i = 1, rider = PRVM_EDICT_NUM(i); i <= prog->num_edicts; i++, rider = PRVM_EDICT_NUM(i)) { if(rider == platform) continue; - if(!rider->inuse) continue; - if(rider->groundentity == platform) + if(rider->priv.sv->free) continue; + if(rider->progs.sv->groundentity == PRVM_EDICT_TO_PROG(platform)) { - mass += rider->mass; + mass += rider->progs.sv->mass; mass += RiderMass(rider); } - else if (rider->movetype == MOVETYPE_PUSHABLE ) + else if (rider->progs.sv->movetype == MOVETYPE_PUSHABLE ) { // Bah - special case for func_pushable riders. Swimming // func_pushables don't really have a groundentity, even // though they may be sitting on another swimming // func_pushable, which is what we need to know. - VectorCopy(rider->s.origin,point); + VectorCopy(rider->priv.sv->s.origin,point); point[2] -= 0.25; - trace = SV_Trace (rider->s.origin, rider->mins, rider->maxs, point, rider, MASK_MONSTERSOLID); + trace = SV_Trace (rider->priv.sv->s.origin, rider->progs.sv->mins, rider->progs.sv->maxs, point, rider, MASK_MONSTERSOLID); if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) continue; if (!trace.startsolid && !trace.allsolid) { if(trace.ent == platform) { - mass += rider->mass; + mass += rider->progs.sv->mass; mass += RiderMass(rider); } } @@ -2043,7 +2060,7 @@ void SV_Physics_Step (edict_t *ent) bool hitsound = false; float *vel; float speed, newspeed, control; - float friction; + float friction, volume; edict_t *ground; edict_t *e; int cont; @@ -2054,74 +2071,54 @@ void SV_Physics_Step (edict_t *ent) vec3_t old_origin, move; // airborne monsters should always check for ground - if (!ent->groundentity) SV_CheckGround (ent); + if (!ent->progs.sv->groundentity) SV_CheckGround (ent); - oldwaterlevel = ent->waterlevel; + oldwaterlevel = ent->progs.sv->waterlevel; - VectorCopy(ent->s.origin, old_origin); + VectorCopy(ent->priv.sv->s.origin, old_origin); // Lazarus: If density hasn't been calculated yet, do so now - if (ent->mass > 0 && ent->density == 0.) + if (ent->progs.sv->mass > 0 && ent->progs.sv->density == 0.) { - ent->volume = ent->size[0] * ent->size[1] * ent->size[2]; - ent->density = ent->mass/ent->volume; - - if(ent->movetype == MOVETYPE_PUSHABLE) - { - // This stuff doesn't apply to anything else, and... heh... - // caused monster_flipper to sink - - ent->bob = min(2.0,300.0/ent->mass); - ent->duration = max(2.0,1.0 + ent->mass/100); - - // Figure out neutral bouyancy line for this entity - // This isn't entirely realistic, but helps gameplay: - // Arbitrary mass limit for func_pushable that can be pushed on - // land is 500. So make a mass=500+, 64x64x64 crate sink. - // (Otherwise, player might cause a 501 crate to leave - // water and expect to be able to push it.) - // Max floating density is then 0.0019073486328125 - if(ent->density > WATER_DENSITY) - ent->flags &= ~FL_SWIM; // sinks like a rock - } + volume = ent->progs.sv->size[0] * ent->progs.sv->size[1] * ent->progs.sv->size[2]; + ent->progs.sv->density = ent->progs.sv->mass/volume; } // If not a monster, then determine whether we're in water. // (monsters take care of this in g_monster.c) - if (!(ent->svflags & SVF_MONSTER) && (ent->flags && FL_SWIM) ) + if (!((int)ent->progs.sv->flags & FL_MONSTER) && ((int)ent->progs.sv->aiflags && AI_SWIM) ) { - point[0] = (ent->absmax[0] + ent->absmin[0])/2; - point[1] = (ent->absmax[1] + ent->absmin[1])/2; - point[2] = ent->absmin[2] + 1; + point[0] = (ent->progs.sv->absmax[0] + ent->progs.sv->absmin[0])/2; + point[1] = (ent->progs.sv->absmax[1] + ent->progs.sv->absmin[1])/2; + point[2] = ent->progs.sv->absmin[2] + 1; cont = SV_PointContents (point); if (!(cont & MASK_WATER)) { - ent->waterlevel = 0; - ent->watertype = 0; + ent->progs.sv->waterlevel = 0; + ent->progs.sv->watertype = 0; } else { - ent->watertype = cont; - ent->waterlevel = 1; - point[2] = ent->absmin[2] + ent->size[2]/2; + ent->progs.sv->watertype = cont; + ent->progs.sv->waterlevel = 1; + point[2] = ent->progs.sv->absmin[2] + ent->progs.sv->size[2]/2; cont = SV_PointContents (point); if (cont & MASK_WATER) { - ent->waterlevel = 2; - point[2] = ent->absmax[2]; + ent->progs.sv->waterlevel = 2; + point[2] = ent->progs.sv->absmax[2]; cont = SV_PointContents (point); - if (cont & MASK_WATER) - ent->waterlevel = 3; + if (cont & MASK_WATER) ent->progs.sv->waterlevel = 3; } } } - ground = ent->groundentity; + ground = PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity); SV_CheckVelocity (ent); if (ground) wasonground = true; - if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) + if (ent->progs.sv->avelocity[0] || ent->progs.sv->avelocity[1] || ent->progs.sv->avelocity[2]) SV_AddRotationalFriction (ent); // add gravity except: @@ -2129,48 +2126,48 @@ void SV_Physics_Step (edict_t *ent) // swimming monsters who are in the water if (!wasonground) { - if (!(ent->flags & FL_FLY)) + if (!((int)ent->progs.sv->aiflags & AI_FLY)) { - if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) + if (!(((int)ent->progs.sv->aiflags & AI_SWIM) && (ent->progs.sv->waterlevel > 2))) { - if (ent->velocity[2] < sv_gravity->value*-0.1) + if (ent->progs.sv->velocity[2] < sv_gravity->value*-0.1) hitsound = true; - if (ent->waterlevel == 0) + if (ent->progs.sv->waterlevel == 0) SV_AddGravity (ent); } } } // friction for flying monsters that have been given vertical velocity - if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) + if (((int)ent->progs.sv->aiflags & AI_FLY) && (ent->progs.sv->velocity[2] != 0)) { - speed = fabs(ent->velocity[2]); + speed = fabs(ent->progs.sv->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; friction = sv_friction/3; newspeed = speed - (0.1f * control * friction); if (newspeed < 0) newspeed = 0; newspeed /= speed; - ent->velocity[2] *= newspeed; + ent->progs.sv->velocity[2] *= newspeed; } // friction for swimming monsters that have been given vertical velocity - if (ent->movetype != MOVETYPE_PUSHABLE) + if (ent->progs.sv->movetype != MOVETYPE_PUSHABLE) { // Lazarus: This is id's swag at drag. It works mostly, but for submerged // crates we can do better. - if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0)) + if (((int)ent->progs.sv->aiflags & AI_SWIM) && (ent->progs.sv->velocity[2] != 0)) { - speed = fabs(ent->velocity[2]); + speed = fabs(ent->progs.sv->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; - newspeed = speed - (0.1f * control * sv_waterfriction * ent->waterlevel); + newspeed = speed - (0.1f * control * sv_waterfriction * ent->progs.sv->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; - ent->velocity[2] *= newspeed; + ent->progs.sv->velocity[2] *= newspeed; } } // Lazarus: Floating stuff - if ((ent->movetype == MOVETYPE_PUSHABLE) && (ent->flags && FL_SWIM) && (ent->waterlevel)) + if ((ent->progs.sv->movetype == MOVETYPE_PUSHABLE) && ((int)ent->progs.sv->aiflags && AI_SWIM) && (ent->progs.sv->waterlevel)) { float waterlevel; float rider_mass, total_mass; @@ -2178,61 +2175,50 @@ void SV_Physics_Step (edict_t *ent) float Accel, Area, Drag, Force; VectorCopy(point,end); - if(ent->waterlevel < 3) + if(ent->progs.sv->waterlevel < 3) { - point[2] = ent->absmax[2]; - end[2] = ent->absmin[2]; + point[2] = ent->progs.sv->absmax[2]; + end[2] = ent->progs.sv->absmin[2]; tr = SV_Trace(point,NULL,NULL,end,ent,MASK_WATER); waterlevel = tr.endpos[2]; } else { // Not right, but really all we need to know - waterlevel = ent->absmax[2] + 1; + waterlevel = ent->progs.sv->absmax[2] + 1; } rider_mass = RiderMass(ent); - total_mass = rider_mass + ent->mass; - Area = ent->size[0] * ent->size[1]; - if(waterlevel < ent->absmax[2]) + total_mass = rider_mass + ent->progs.sv->mass; + Area = ent->progs.sv->size[0] * ent->progs.sv->size[1]; + if(waterlevel < ent->progs.sv->absmax[2]) { // A portion of crate is above water - int time; - float t0, t1, z0, z1; - // For partially submerged crates, use same psuedo-friction thing used // on other entities. This isn't really correct, but then neither is // our drag calculation used for fully submerged crates good for this // situation - if (ent->velocity[2] != 0) + if (ent->progs.sv->velocity[2] != 0) { - speed = fabs(ent->velocity[2]); + speed = fabs(ent->progs.sv->velocity[2]); control = speed < sv_stopspeed ? sv_stopspeed : speed; - newspeed = speed - (0.1f * control * sv_waterfriction * ent->waterlevel); + newspeed = speed - (0.1f * control * sv_waterfriction * ent->progs.sv->waterlevel); if (newspeed < 0) newspeed = 0; newspeed /= speed; - ent->velocity[2] *= newspeed; + ent->progs.sv->velocity[2] *= newspeed; } // Apply physics and bob AFTER friction, or the damn thing will never move. - Force = -total_mass + ((waterlevel-ent->absmin[2]) * Area * WATER_DENSITY); + Force = -total_mass + ((waterlevel-ent->progs.sv->absmin[2]) * Area * WATER_DENSITY); Accel = Force * sv_gravity->value/total_mass; - ent->velocity[2] += Accel*0.1f; - - time = ent->duration*10; - t0 = ent->bobframe%time; - t1 = (ent->bobframe+1)%time; - z0 = sin(2*M_PI*t0/time); - z1 = sin(2*M_PI*t1/time); - ent->velocity[2] += ent->bob * (z1-z0) * 10; - ent->bobframe = (ent->bobframe+1)%time; + ent->progs.sv->velocity[2] += Accel*0.1f; } else { // Crate is fully submerged - Force = -total_mass + ent->volume * WATER_DENSITY; + Force = -total_mass + volume * WATER_DENSITY; if(sv_gravity->value) { - Drag = 0.00190735 * 1.05 * Area * (ent->velocity[2]*ent->velocity[2])/sv_gravity->value; + Drag = 0.00190735 * 1.05 * Area * (ent->progs.sv->velocity[2]*ent->progs.sv->velocity[2])/sv_gravity->value; if(Drag > fabs(Force)) { // Drag actually CAN be > total weight, but if we do this we tend to @@ -2240,77 +2226,77 @@ void SV_Physics_Step (edict_t *ent) // height Drag = fabs(Force); } - if(ent->velocity[2] > 0) + if(ent->progs.sv->velocity[2] > 0) Drag = -Drag; Force += Drag; } Accel = Force * sv_gravity->value/total_mass; - ent->velocity[2] += Accel*0.1f; + ent->progs.sv->velocity[2] += Accel*0.1f; } - if(ent->watertype & MASK_CURRENT) + if((int)ent->progs.sv->watertype & MASK_CURRENT) { // Move with current, relative to mass. Mass=400 or less // will move at 50 units/sec. float v; int current; - if(ent->mass > 400) v = 0.125 * ent->mass; + if(ent->progs.sv->mass > 400) v = 0.125 * ent->progs.sv->mass; else v = 50.; - current = ent->watertype & MASK_CURRENT; + current = (int)ent->progs.sv->watertype & MASK_CURRENT; switch (current) { - case CONTENTS_CURRENT_0: ent->velocity[0] = v; break; - case CONTENTS_CURRENT_90: ent->velocity[1] = v; break; - case CONTENTS_CURRENT_180: ent->velocity[0] = -v; break; - case CONTENTS_CURRENT_270: ent->velocity[1] = -v; break; - case CONTENTS_CURRENT_UP : ent->velocity[2] = max(v, ent->velocity[2]); - case CONTENTS_CURRENT_DOWN: ent->velocity[2] = min(-v, ent->velocity[2]); + case CONTENTS_CURRENT_0: ent->progs.sv->velocity[0] = v; break; + case CONTENTS_CURRENT_90: ent->progs.sv->velocity[1] = v; break; + case CONTENTS_CURRENT_180: ent->progs.sv->velocity[0] = -v; break; + case CONTENTS_CURRENT_270: ent->progs.sv->velocity[1] = -v; break; + case CONTENTS_CURRENT_UP : ent->progs.sv->velocity[2] = max(v, ent->progs.sv->velocity[2]); + case CONTENTS_CURRENT_DOWN: ent->progs.sv->velocity[2] = min(-v, ent->progs.sv->velocity[2]); } } } // Conveyor - if (wasonground && (ground->movetype == MOVETYPE_CONVEYOR)) + if (wasonground && (ground->progs.sv->movetype == MOVETYPE_CONVEYOR)) { trace_t tr; - VectorCopy(ent->s.origin,point); + VectorCopy(ent->priv.sv->s.origin,point); point[2] += 1; VectorCopy(point,end); end[2] -= 256; - tr = SV_Trace (point, ent->mins, ent->maxs, end, ent, MASK_SOLID); + tr = SV_Trace (point, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, MASK_SOLID); // tr.ent HAS to be ground, but just in case we screwed something up: if(tr.ent == ground) { onconveyor = true; - ent->velocity[0] = ground->movedir[0] * ground->speed; - ent->velocity[1] = ground->movedir[1] * ground->speed; + ent->progs.sv->velocity[0] = ground->progs.sv->movedir[0] * ground->progs.sv->speed; + ent->progs.sv->velocity[1] = ground->progs.sv->movedir[1] * ground->progs.sv->speed; if(tr.plane.normal[2] > 0) { - ent->velocity[2] = ground->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; - if(DotProduct(ground->movedir,tr.plane.normal) > 0) + ent->progs.sv->velocity[2] = ground->progs.sv->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; + if(DotProduct(ground->progs.sv->movedir,tr.plane.normal) > 0) { // Then we're moving down. - ent->velocity[2] = -ent->velocity[2] + 2; + ent->progs.sv->velocity[2] = -ent->progs.sv->velocity[2] + 2; } } } } - if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) + if (ent->progs.sv->velocity[2] || ent->progs.sv->velocity[1] || ent->progs.sv->velocity[0]) { int block; // apply friction // let dead monsters who aren't completely onground slide - if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) + if ((wasonground) || ((int)ent->progs.sv->aiflags & (AI_SWIM|AI_FLY))) if (!onconveyor) { - if (!(ent->health <= 0.0 && !SV_CheckBottom(ent))) + if (!(ent->progs.sv->health <= 0.0 && !SV_CheckBottom(ent))) { - vel = ent->velocity; + vel = ent->progs.sv->velocity; speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); if (speed) { @@ -2328,18 +2314,18 @@ void SV_Physics_Step (edict_t *ent) } } - if (ent->svflags & SVF_MONSTER) mask = MASK_MONSTERSOLID; - else if(ent->movetype == MOVETYPE_PUSHABLE) mask = MASK_MONSTERSOLID | MASK_PLAYERSOLID; - else if(ent->clipmask) mask = ent->clipmask; // Lazarus edition + if ((int)ent->progs.sv->flags & FL_MONSTER) mask = MASK_MONSTERSOLID; + else if(ent->progs.sv->movetype == MOVETYPE_PUSHABLE) mask = MASK_MONSTERSOLID | MASK_PLAYERSOLID; + else if(ent->priv.sv->clipmask) mask = ent->priv.sv->clipmask; // Lazarus edition else mask = MASK_SOLID; - if (ent->movetype == MOVETYPE_PUSHABLE) + if (ent->progs.sv->movetype == MOVETYPE_PUSHABLE) { block = SV_PushableMove (ent, 0.1f, mask); if(block && !(block & 8) && onconveyor) { - T_Damage(ent, ge->edicts, ge->edicts, vec3_origin, ent->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); - if(!ent->inuse) return; + T_Damage(ent, prog->edicts, prog->edicts, vec3_origin, ent->priv.sv->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); + if(ent->priv.sv->free) return; } } else @@ -2347,66 +2333,66 @@ void SV_Physics_Step (edict_t *ent) block = SV_FlyMove (ent, 0.1f, mask); if(block && !(block & 8) && onconveyor) { - T_Damage (ent, ge->edicts, ge->edicts, vec3_origin, ent->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); - if(!ent->inuse) return; + T_Damage (ent, prog->edicts, prog->edicts, vec3_origin, ent->priv.sv->s.origin, vec3_origin, 100000, 1, 0, DMG_CRUSH); + if(ent->priv.sv->free) return; } } SV_LinkEdict (ent); SV_TouchTriggers (ent); - if (!ent->inuse) return; + if (ent->priv.sv->free) return; - if (ent->groundentity && !wasonground && hitsound) + if (ent->progs.sv->groundentity && !wasonground && hitsound) { - PF_StartSound (ent, 0, SV_SoundIndex("world/land.wav"), 1, 1, 0); + SV_StartSound (NULL, ent, 0, SV_SoundIndex("world/land.wav"), 1, 1, 0); } // Move func_pushable riders - if(ent->movetype == MOVETYPE_PUSHABLE) + if(ent->progs.sv->movetype == MOVETYPE_PUSHABLE) { trace_t tr; - if(ent->bouncetype == 2) VectorMA(old_origin,0.1f,ent->velocity,ent->s.origin); - VectorSubtract(ent->s.origin,old_origin,move); - for(i = 1, e = EDICT_NUM(i); i < ge->num_edicts; i++, e = EDICT_NUM(i)) + if(ent->progs.sv->bouncetype == 2) VectorMA(old_origin,0.1f,ent->progs.sv->velocity,ent->priv.sv->s.origin); + VectorSubtract(ent->priv.sv->s.origin,old_origin,move); + for(i = 1, e = PRVM_EDICT_NUM(i); i < prog->num_edicts; i++, e = PRVM_EDICT_NUM(i)) { if(e==ent) continue; - if(e->groundentity == ent) + if(e->progs.sv->groundentity == PRVM_EDICT_TO_PROG(ent)) { - VectorAdd(e->s.origin,move,end); - tr = SV_Trace(e->s.origin, e->mins, e->maxs, end, ent, MASK_SOLID); - VectorCopy(tr.endpos,e->s.origin); + VectorAdd(e->priv.sv->s.origin,move,end); + tr = SV_Trace(e->priv.sv->s.origin, e->progs.sv->mins, e->progs.sv->maxs, end, ent, MASK_SOLID); + VectorCopy(tr.endpos,e->priv.sv->s.origin); SV_LinkEdict(e); } } } } - else if(ent->movetype == MOVETYPE_PUSHABLE) + else if(ent->progs.sv->movetype == MOVETYPE_PUSHABLE) { // We run touch function for non-moving func_pushables every frame // to see if they are touching, for example, a trigger_mass SV_TouchTriggers(ent); - if(!ent->inuse) return; + if(ent->priv.sv->free) return; } // Lazarus: Add falling damage for entities that can be damaged - if( ent->takedamage ) + if( ent->progs.sv->takedamage ) { SV_FallingDamage(ent); - VectorCopy(ent->velocity,ent->oldvelocity); + VectorCopy(ent->progs.sv->velocity,ent->progs.sv->post_velocity); } - if ((!oldwaterlevel && ent->waterlevel) && !ent->groundentity) + if ((!oldwaterlevel && ent->progs.sv->waterlevel) && !ent->progs.sv->groundentity) { - if( (ent->watertype & CONTENTS_SLIME) || (ent->watertype & CONTENTS_WATER) ) - PF_StartSound (ent, CHAN_BODY, SV_SoundIndex("player/watr_in.wav"), 1, ATTN_NORM, 0); - else if(ent->watertype & CONTENTS_MUD) - PF_StartSound (ent, CHAN_BODY, SV_SoundIndex("mud/mud_in2.wav"), 1, ATTN_NORM, 0); + if( ((int)ent->progs.sv->watertype & CONTENTS_SLIME) || ((int)ent->progs.sv->watertype & CONTENTS_WATER) ) + SV_StartSound (NULL, ent, CHAN_BODY, SV_SoundIndex("player/watr_in.wav"), 1, ATTN_NORM, 0); + else if((int)ent->progs.sv->watertype & CONTENTS_MUD) + SV_StartSound (NULL, ent, CHAN_BODY, SV_SoundIndex("mud/mud_in2.wav"), 1, ATTN_NORM, 0); } // regular thinking SV_RunThink (ent); - VectorCopy(ent->velocity,ent->oldvelocity); + VectorCopy(ent->progs.sv->velocity,ent->progs.sv->post_velocity); } //============================================================================ @@ -2428,13 +2414,13 @@ trace_t SV_DebrisEntity (edict_t *ent, vec3_t push) int damage; int mask; - VectorCopy (ent->s.origin, start); + VectorCopy (ent->priv.sv->s.origin, start); VectorAdd (start, push, end); - if(ent->clipmask) mask = ent->clipmask; + if(ent->priv.sv->clipmask) mask = ent->priv.sv->clipmask; else mask = MASK_SHOT; - trace = SV_Trace (start, ent->mins, ent->maxs, end, ent, mask); - VectorCopy (trace.endpos, ent->s.origin); + trace = SV_Trace (start, ent->progs.sv->mins, ent->progs.sv->maxs, end, ent, mask); + VectorCopy (trace.endpos, ent->priv.sv->s.origin); SV_LinkEdict (ent); if (trace.fraction != 1.0) @@ -2444,31 +2430,47 @@ trace_t SV_DebrisEntity (edict_t *ent, vec3_t push) SV_FreeEdict(ent); return trace; } - if(trace.ent->client || (trace.ent->svflags & SVF_MONSTER) ) + if(trace.ent->priv.sv->client || ((int)trace.ent->progs.sv->flags & FL_MONSTER) ) { // touching a player or monster // if rock has no mass we really don't care who it hits - if(!ent->mass) return trace; - speed1 = VectorLength(ent->velocity); + if(!ent->progs.sv->mass) return trace; + speed1 = VectorLength(ent->progs.sv->velocity); if(!speed1) return trace; - speed2 = VectorLength(trace.ent->velocity); - VectorCopy(ent->velocity,v1); + speed2 = VectorLength(trace.ent->progs.sv->velocity); + VectorCopy(ent->progs.sv->velocity,v1); VectorNormalize(v1); - VectorCopy(trace.ent->velocity,v2); + VectorCopy(trace.ent->progs.sv->velocity,v2); VectorNormalize(v2); dot = -DotProduct(v1,v2); speed1 += speed2 * dot; if(speed1 <= 0) return trace; - scale = (float)ent->mass/200.*speed1; - VectorMA(trace.ent->velocity,scale,v1,trace.ent->velocity); + scale = (float)ent->progs.sv->mass/200.*speed1; + VectorMA(trace.ent->progs.sv->velocity,scale,v1,trace.ent->progs.sv->velocity); // Take a swag at it... if(speed1 > 100) { - damage = (int)(ent->mass * speed1 / 5000.); - if(damage) T_Damage(trace.ent, ge->edicts, ge->edicts, v1, trace.ent->s.origin, vec3_origin, damage, 0, 0, DMG_CRUSH); + damage = (int)(ent->progs.sv->mass * speed1 / 5000.); + if(damage) T_Damage(trace.ent, prog->edicts, prog->edicts, v1, trace.ent->priv.sv->s.origin, vec3_origin, damage, 0, 0, DMG_CRUSH); } - if(ent->touch) ent->touch (ent, trace.ent, &trace.plane, trace.surface); + + PRVM_PUSH_GLOBALS; + + prog->globals.server->pev = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->other = PRVM_EDICT_TO_PROG(trace.ent); //correct ? + prog->globals.server->time = sv.time; + prog->globals.server->trace_allsolid = trace.allsolid; + prog->globals.server->trace_startsolid = trace.startsolid; + prog->globals.server->trace_fraction = trace.fraction; + prog->globals.server->trace_contents = trace.contents; + VectorCopy (trace.endpos, prog->globals.server->trace_endpos); + VectorCopy (trace.plane.normal, prog->globals.server->trace_plane_normal); + prog->globals.server->trace_plane_dist = trace.plane.dist; + if (trace.ent) prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(trace.ent); + else prog->globals.server->trace_ent = PRVM_EDICT_TO_PROG(prog->edicts); + PRVM_ExecuteProgram (ent->progs.sv->touch, "QC function pev->touch is missing"); + PRVM_POP_GLOBALS; SV_LinkEdict(trace.ent); } @@ -2499,59 +2501,57 @@ void SV_Physics_Debris (edict_t *ent) // regular thinking SV_RunThink (ent); - if (ent->velocity[2] > 0) - ent->groundentity = NULL; + if (ent->progs.sv->velocity[2] > 0) + ent->progs.sv->groundentity = 0; // check for the groundentity going away - if (ent->groundentity) - if (!ent->groundentity->inuse) - ent->groundentity = NULL; + if (ent->progs.sv->groundentity) + if (PRVM_PROG_TO_EDICT(ent->progs.sv->groundentity)->priv.sv->free) + ent->progs.sv->groundentity = 0; // if onground, return without moving - if ( ent->groundentity ) + if ( ent->progs.sv->groundentity ) return; - VectorCopy (ent->s.origin, old_origin); + VectorCopy (ent->priv.sv->s.origin, old_origin); SV_CheckVelocity (ent); SV_AddGravity (ent); // move angles - VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); + VectorMA (ent->priv.sv->s.angles, 0.1f, ent->progs.sv->avelocity, ent->priv.sv->s.angles); // move origin - VectorScale (ent->velocity, 0.1f, move); + VectorScale (ent->progs.sv->velocity, 0.1f, move); trace = SV_DebrisEntity (ent, move); - if (!ent->inuse) - return; + if (ent->priv.sv->free) return; if (trace.fraction < 1) { backoff = 1.0; - ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); + ClipVelocity (ent->progs.sv->velocity, trace.plane.normal, ent->progs.sv->velocity, backoff); // stop if on ground if (trace.plane.normal[2] > 0.3) { - if (ent->velocity[2] < 60) + if (ent->progs.sv->velocity[2] < 60) { - ent->groundentity = trace.ent; - ent->groundentity_linkcount = trace.ent->linkcount; - VectorCopy (vec3_origin, ent->velocity); - VectorCopy (vec3_origin, ent->avelocity); + ent->progs.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + VectorCopy (vec3_origin, ent->progs.sv->velocity); + VectorCopy (vec3_origin, ent->progs.sv->avelocity); } } } // check for water transition - wasinwater = (ent->watertype & MASK_WATER); - ent->watertype = SV_PointContents (ent->s.origin); - isinwater = ent->watertype & MASK_WATER; + wasinwater = ((int)ent->progs.sv->watertype & MASK_WATER); + ent->progs.sv->watertype = SV_PointContents (ent->priv.sv->s.origin); + isinwater = (int)ent->progs.sv->watertype & MASK_WATER; - if (isinwater) ent->waterlevel = 1; - else ent->waterlevel = 0; + if (isinwater) ent->progs.sv->waterlevel = 1; + else ent->progs.sv->waterlevel = 0; - if (!wasinwater && isinwater) SV_StartSound (old_origin, ge->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); - else if (wasinwater && !isinwater) SV_StartSound (ent->s.origin, ge->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); + if (!wasinwater && isinwater) SV_StartSound (old_origin, prog->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); + else if (wasinwater && !isinwater) SV_StartSound (ent->priv.sv->s.origin, prog->edicts, CHAN_AUTO, SV_SoundIndex("misc/h2ohit1.wav"), 1, 1, 0); } @@ -2573,39 +2573,39 @@ void SV_Physics_Conveyor(edict_t *ent) vec3_t v, move; vec3_t point, end; - VectorScale(ent->movedir,ent->speed,v); + VectorScale(ent->progs.sv->movedir,ent->progs.sv->speed,v); VectorScale(v, 0.1f, move); for(i = 0; i < maxclients->value; i++) { - player = EDICT_NUM(i) + 1; - if(!player->inuse) continue; - if(!player->groundentity) continue; - if(player->groundentity != ent) continue; + 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)) continue; // Look below player; make sure he's on a conveyor - VectorCopy(player->s.origin,point); + VectorCopy(player->priv.sv->s.origin,point); point[2] += 1; VectorCopy(point,end); end[2] -= 256; - tr = SV_Trace (point, player->mins, player->maxs, end, player, MASK_SOLID); + tr = SV_Trace (point, player->progs.sv->mins, player->progs.sv->maxs, end, 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->speed * sqrt(1.0 - tr.plane.normal[2]*tr.plane.normal[2]) / tr.plane.normal[2]; - if(DotProduct(ent->movedir,tr.plane.normal) > 0) + v[2] = ent->progs.sv->speed * 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) { // then we're moving down v[2] = -v[2]; } move[2] = v[2] * 0.1f; } - VectorAdd(player->s.origin,move,end); - tr = SV_Trace(player->s.origin,player->mins,player->maxs,end,player,player->clipmask); - VectorCopy(tr.endpos,player->s.origin); + VectorAdd(player->priv.sv->s.origin,move,end); + tr = SV_Trace(player->priv.sv->s.origin,player->progs.sv->mins,player->progs.sv->maxs,end,player,player->priv.sv->clipmask); + VectorCopy(tr.endpos,player->priv.sv->s.origin); SV_LinkEdict(player); } } @@ -2613,11 +2613,10 @@ void SV_Physics_Conveyor(edict_t *ent) void SV_Physics(edict_t *ent) { - if (ent->prethink) ent->prethink (ent); wasonground = false; onconveyor = false; - switch ( (int)ent->movetype) + switch ( (int)ent->progs.sv->movetype) { case MOVETYPE_PUSH: SV_Physics_Pusher (ent); @@ -2646,6 +2645,6 @@ void SV_Physics(edict_t *ent) SV_Physics_Conveyor(ent); break; default: - PF_error ("SV_Physics: bad movetype %i", (int)ent->movetype); + PRVM_ERROR ("SV_Physics: bad movetype %i", (int)ent->progs.sv->movetype); } } \ No newline at end of file diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 7726ec14..9a9e5575 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -208,7 +208,7 @@ void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename, reliable = true; // intentional fallthrough case MSG_ONE: if(ent == NULL) return; - j = NUM_FOR_EDICT(ent); + j = PRVM_NUM_FOR_EDICT(ent); if (j < 1 || j > numclients) return; current = svs.clients + (j - 1); numclients = 1; // send to one @@ -228,7 +228,7 @@ void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename, { area2 = CM_LeafArea (leafnum); cluster = CM_LeafCluster (leafnum); - leafnum = CM_PointLeafnum (client->edict->s.origin); + leafnum = CM_PointLeafnum (client->edict->priv.sv->s.origin); if (!CM_AreasConnected (area1, area2)) continue; if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7))))) continue; } @@ -299,7 +299,7 @@ void SV_StartSound (vec3_t origin, edict_t *entity, int channel, int soundindex, MsgWarn("SV_StartSound: timeofs = %f\n", timeofs); timeofs = bound(0, timeofs, 0.255 ); } - ent = NUM_FOR_EDICT(entity); + ent = PRVM_NUM_FOR_EDICT(entity); if (channel & 8) // no PHS flag { @@ -315,7 +315,7 @@ void SV_StartSound (vec3_t origin, edict_t *entity, int channel, int soundindex, // the client doesn't know that bmodels have weird origins // the origin can also be explicitly set - if ( (entity->svflags & SVF_NOCLIENT) || (entity->solid == SOLID_BSP) || origin ) + if (entity->progs.sv->solid == SOLID_BSP || !VectorIsNull(origin)) flags |= SND_POS; // always send the entity number for channel overrides @@ -327,16 +327,16 @@ void SV_StartSound (vec3_t origin, edict_t *entity, int channel, int soundindex, if (!origin) { origin = origin_v; - if (entity->solid == SOLID_BSP) + if (entity->progs.sv->solid == SOLID_BSP) { for (i = 0; i < 3; i++) { - origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]); + origin_v[i] = entity->priv.sv->s.origin[i]+0.5*(entity->progs.sv->mins[i]+entity->progs.sv->maxs[i]); } } else { - VectorCopy (entity->s.origin, origin_v); + VectorCopy (entity->priv.sv->s.origin, origin_v); } } diff --git a/engine/server/sv_spawn.c b/engine/server/sv_spawn.c index 51e1e78c..5576eb40 100644 --- a/engine/server/sv_spawn.c +++ b/engine/server/sv_spawn.c @@ -1,211 +1,16 @@ #include "engine.h" #include "server.h" -#define FOFS(x) (int)&(((edict_t *)0)->x) -#define FFL_NOSPAWN 2 - edict_t *pm_passent; -char *single_statusbar = -"yb -24 " - -// health -"xv 0 " -"hnum " -"xv 50 " -"pic 0 " - -// ammo -"if 2 " -"{ xv 100 " -"anum " -"xv 150 " -"pic 2 " -"} " - -// armor -"if 4 " -"{ xv 200 " -"rnum " -"xv 250 " -"pic 4 " -"} " - -// selected item -"if 6 " -"{ xv 296 " -"pic 6 " -"} " - -"yb -50 " - -// picked up item -"if 7 " -"{ xv 0 " -"pic 7 " -"xv 26 " -"yb -42 " -"stat_string 8 " -"yb -50 " -"} " - -// timer (was xv 262) -"if 9 " -"{ xv 230 " -"num 4 10 " -"xv 296 " -"pic 9 " -"} " - -// help / weapon icon -"if 11 " -"{ xv 148 " -"pic 11 " -"} " - -// vehicle speed -"if 22 " -"{ yb -90 " -"xv 128 " -"pic 22 " -"} " - -// zoom -"if 23 " -"{ yv 0 " -"xv 0 " -"pic 23 " -"} " -; - - -void SP_info_player_start (edict_t *ent){} -void SP_info_player_deathmatch (edict_t *ent){} -void SP_worldspawn (edict_t *ent) -{ - vec3_t skyaxis; - - ent->movetype = MOVETYPE_PUSH; - ent->solid = SOLID_BSP; - ent->inuse = true; // since the world doesn't use G_Spawn() - ent->s.modelindex = 1; // world model is always index 1 - - //--------------- - - VectorSet( skyaxis, 32, 180, 20 ); - - PF_Configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value))); - PF_Configstring (CS_STATUSBAR, single_statusbar); - PF_Configstring (CS_SKY, "sky" ); - PF_Configstring (CS_SKYROTATE, va("%f", 0.0f )); - PF_Configstring (CS_SKYAXIS, va("%f %f %f", skyaxis[0], skyaxis[1], skyaxis[2]) ); - PF_Configstring (CS_CDTRACK, va("%i", 0 )); - - //--------------- - - // help icon for statusbar - SV_ImageIndex ("i_help"); - SV_ImageIndex ("help"); - SV_ImageIndex ("field_3"); -} - -void SP_misc_explobox (edict_t *self) -{ - self->solid = SOLID_BBOX; - self->movetype = MOVETYPE_STEP; - - self->model = "models/barrel.mdl"; - self->s.modelindex = SV_ModelIndex (self->model); - VectorSet (self->mins, -16, -16, 0); - VectorSet (self->maxs, 16, 16, 40); - - if (!self->health) self->health = 10; - self->monsterinfo.aiflags = AI_NOSTEP; - - self->think = SV_DropToFloor; - self->nextthink = sv.time + 0.5; - - PF_setmodel (self, self->model); -} - - -spawn_t spawns[] = -{ - {"info_player_start", SP_info_player_start}, - {"info_player_deathmatch", SP_info_player_deathmatch}, - - - {"misc_explobox", SP_misc_explobox}, - {"worldspawn", SP_worldspawn}, - {NULL, NULL} -}; - -field_t fields[] = -{ - {"classname", FOFS(classname), F_LSTRING}, - {"model", FOFS(model), F_LSTRING}, - {"spawnflags", FOFS(spawnflags), F_INT}, - {"health", FOFS(health), F_INT}, - {"origin", FOFS(s.origin), F_VECTOR}, - {"angles", FOFS(s.angles), F_VECTOR}, - {"angle", FOFS(s.angles), F_ANGLEHACK}, - - {"owner", FOFS(owner), F_EDICT, FFL_NOSPAWN}, - - {"prethink", FOFS(prethink), F_FUNCTION, FFL_NOSPAWN}, - {"think", FOFS(think), F_FUNCTION, FFL_NOSPAWN}, - {"blocked", FOFS(blocked), F_FUNCTION, FFL_NOSPAWN}, - {"touch", FOFS(touch), F_FUNCTION, FFL_NOSPAWN}, - {"use", FOFS(use), F_FUNCTION, FFL_NOSPAWN}, - - {"skin", FOFS(s.skin), F_INT}, - {"body", FOFS(s.body), F_INT}, - - {0, 0, F_INT, 0} - -}; - // pmove doesn't need to know about passent and contentmask trace_t PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) { - if (pm_passent->health > 0) + if (pm_passent->progs.sv->health > 0) return SV_Trace (start, mins, maxs, end, pm_passent, MASK_PLAYERSOLID); return SV_Trace (start, mins, maxs, end, pm_passent, MASK_DEADSOLID); } -/* -=============== -ED_CallSpawn - -Finds the spawn function for the entity and calls it -=============== -*/ -void ED_CallSpawn (edict_t *ent) -{ - spawn_t *s; - - if (!ent->classname) - { - Msg("ED_CallSpawn: NULL classname\n"); - SV_FreeEdict(ent); - return; - } - - // check normal spawn functions - for (s = spawns; s->name; s++) - { - if (!strcmp(s->name, ent->classname)) - { - // found it - s->spawn (ent); - return; - } - } - - Msg("%s doesn't have a spawn function\n", ent->classname); - SV_FreeEdict(ent); -} - /* ============= ED_NewString @@ -237,107 +42,79 @@ char *ED_NewString (const char *string) } /* -=============== -ED_ParseField +=========== +PutClientInServer -Takes a key/value pair and sets the binary values -in an edict -=============== +Called when a player connects to a server or respawns in +a deathmatch. +============ */ -void ED_ParseField (char *key, const char *value, edict_t *ent) +void SV_PutClientInServer (edict_t *ent) { - field_t *f; - byte *b; - float v; - vec3_t vec; + vec3_t mins = {-16, -16, -24}; + vec3_t maxs = {16, 16, 32}; + int index; + vec3_t spawn_origin = {-128, -32, -72 }, spawn_angles; + gclient_t *client; + int i; - for (f = fields; f->name; f++) + index = PRVM_NUM_FOR_EDICT(ent) - 1; + + client = ent->priv.sv->client; + + ent->priv.sv->client = &sv.clients[index]; + ent->progs.sv->movetype = MOVETYPE_WALK; + ent->priv.sv->free = false; + ent->progs.sv->classname = PRVM_SetEngineString("player"); + ent->progs.sv->solid = SOLID_BBOX; + ent->progs.sv->model = PRVM_SetEngineString("models/player.mdl"); + (int)ent->progs.sv->flags &= ~FL_DEADMONSTER; + + VectorCopy (mins, ent->progs.sv->mins); + VectorCopy (maxs, ent->progs.sv->maxs); + VectorClear (ent->progs.sv->velocity); + + // clear playerstate values + memset (&ent->priv.sv->client->ps, 0, sizeof(client->ps)); + + // info_player_start + client->ps.pmove.origin[0] = spawn_origin[0] * 8; + client->ps.pmove.origin[1] = spawn_origin[1] * 8; + client->ps.pmove.origin[2] = spawn_origin[2] * 8; + + client->ps.fov = 90; + + client->ps.fov = bound(1, client->ps.fov, 160); + client->ps.gunindex = SV_ModelIndex("models/weapons/v_eagle.mdl"); + + // clear entity state values + ent->priv.sv->s.effects = 0; + ent->priv.sv->s.modelindex = MAX_MODELS - 1; // will use the skin specified model + ent->priv.sv->s.weaponmodel = MAX_MODELS - 1; // custom gun model + + // sknum is player num and weapon number + // weapon number will be added in changeweapon + ent->priv.sv->s.skin = PRVM_NUM_FOR_EDICT(ent) - 1; + + ent->priv.sv->s.frame = 0; + VectorCopy (spawn_origin, ent->priv.sv->s.origin); + ent->priv.sv->s.origin[2] += 1; // make sure off ground + VectorCopy (ent->priv.sv->s.origin, ent->priv.sv->s.old_origin); + + // set the delta angle + for (i = 0; i < 3; i++) { - if (!(f->flags & FFL_NOSPAWN) && !strcasecmp(f->name, key)) - { - // found it - b = (byte *)ent; - - switch (f->type) - { - case F_LSTRING: - *(char **)(b+f->ofs) = ED_NewString (value); - break; - case F_VECTOR: - sscanf (value, "%f %f %f", &vec[0], &vec[1], &vec[2]); - ((float *)(b+f->ofs))[0] = vec[0]; - ((float *)(b+f->ofs))[1] = vec[1]; - ((float *)(b+f->ofs))[2] = vec[2]; - break; - case F_INT: - *(int *)(b+f->ofs) = atoi(value); - break; - case F_FLOAT: - *(float *)(b+f->ofs) = atof(value); - break; - case F_ANGLEHACK: - v = atof(value); - ((float *)(b+f->ofs))[0] = 0; - ((float *)(b+f->ofs))[1] = v; - ((float *)(b+f->ofs))[2] = 0; - break; - case F_IGNORE: - break; - } - return; - } - } - Msg("%s is not a field\n", key); -} - -/* -==================== -ED_ParseEdict - -Parses an edict out of the given string, returning the new position -ed should be a properly initialized empty edict. -==================== -*/ -char *ED_ParseEdict (char *data, edict_t *ent) -{ - bool init; - char keyname[256]; - char *com_token; - - init = false; - - // go through all the dictionary pairs - while (1) - { - // parse key - com_token = COM_Parse (&data); - if (com_token[0] == '}') break; - if (!data) PF_error ("ED_ParseEntity: EOF without closing brace"); - - strncpy (keyname, com_token, sizeof(keyname)-1); - - // parse value - com_token = COM_Parse (&data); - if (!data) PF_error ("ED_ParseEntity: EOF without closing brace"); - - if (com_token[0] == '}') - PF_error ("ED_ParseEntity: closing brace without data"); - - init = true; - - // keynames with a leading underscore are used for utility comments, - // and are immediately discarded by quake - if (keyname[0] == '_') continue; - - ED_ParseField (keyname, com_token, ent); + client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i]); } - if (!init) memset (ent, 0, sizeof(*ent)); + ent->priv.sv->s.angles[PITCH] = ent->priv.sv->s.angles[ROLL] = 0; + ent->priv.sv->s.angles[YAW] = spawn_angles[YAW]; + VectorCopy(ent->priv.sv->s.angles, client->ps.viewangles); + VectorCopy (client->ps.viewangles, client->v_angle); - return (char *)data; + SV_LinkEdict(ent); } - /* ============== SpawnEntities @@ -348,83 +125,16 @@ parsing textual entity definitions out of an ent file. */ void SV_SpawnEntities (char *mapname, char *entities, char *spawnpoint) { - edict_t *ent; - int inhibit; - char *com_token; - int i; - Msg("====== SpawnEntities ========\n"); - - memset (ge->edicts, 0, game.maxentities * sizeof(edict_t)); - - // set client fields on player ents - for (i = 0; i < game.maxclients; i++) - ge->edicts[i+1].client = game.clients + i; - - ent = NULL; - inhibit = 0; - - // parse ents - while (1) - { - // parse the opening brace - com_token = COM_Parse (&entities); - if (!entities) break; - if (com_token[0] != '{') - PF_error("ED_LoadFromFile: found %s when expecting {",com_token); - - if (!ent) ent = ge->edicts; - else ent = SV_Spawn (); - entities = ED_ParseEdict (entities, ent); - - ED_CallSpawn (ent); - ent->s.renderfx |= RF_IR_VISIBLE; //PGM - } - - Msg("%i entities inhibited\n", inhibit); -} - -/* -================= -SV_Spawn - -Either finds a free edict, or allocates a new one. -Try to avoid reusing an entity that was recently freed, because it -can cause the client to think the entity morphed into something else -instead of being removed and recreated, which can cause interpolated -angles and bad trails. -================= -*/ -edict_t *SV_Spawn (void) -{ - int i; - edict_t *e; - - e = EDICT_NUM((int)maxclients->value + 1); - for ( i = maxclients->value + 1; i < ge->num_edicts; i++, e++) - { - // the first couple seconds of server time can involve a lot of - // freeing and allocating, so relax the replacement policy - if (!e->inuse) - { - SV_InitEdict (e); - return e; - } - } - - if (i == game.maxentities) PF_error ("ED_Alloc: no free edicts"); - - ge->num_edicts++; - - SV_InitEdict (e); - return e; + PRVM_ED_LoadFromFile ( entities ); } void SV_InitEdict (edict_t *e) { - e->inuse = true; - e->classname = "noclass"; - e->s.number = NUM_FOR_EDICT(e); + e->priv.sv->free = false; + e->progs.sv->classname = PRVM_SetEngineString("noclass"); + e->priv.sv->s.number = PRVM_NUM_FOR_EDICT(e); + e->priv.sv->s.renderfx |= RF_IR_VISIBLE; //evil stuff... } @@ -439,13 +149,24 @@ void SV_FreeEdict (edict_t *ed) { SV_UnlinkEdict(ed); // unlink from world - if (NUM_FOR_EDICT(ed) <= maxclients->value) + // don't free players! + if (PRVM_NUM_FOR_EDICT(ed) <= maxclients->value) return; memset (ed, 0, sizeof(*ed)); - ed->classname = "freed"; - ed->freetime = sv.time; - ed->inuse = false; + ed->progs.sv->classname = PRVM_SetEngineString("freed"); + ed->priv.sv->freetime = sv.time; + ed->priv.sv->free = true; + + ed->progs.sv->model = 0; + ed->progs.sv->takedamage = 0; + ed->progs.sv->modelindex = 0; + ed->progs.sv->skin = 0; + ed->progs.sv->frame = 0; + ed->progs.sv->solid = 0; + VectorClear(ed->progs.sv->origin); + VectorClear(ed->progs.sv->angles); + ed->progs.sv->nextthink = -1; } /* @@ -460,154 +181,28 @@ void SV_TouchTriggers (edict_t *ent) edict_t *touch[MAX_EDICTS], *hit; // dead things don't activate triggers! - if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) + if ((ent->priv.sv->client || ((int)ent->progs.sv->flags & FL_MONSTER)) && (ent->progs.sv->health <= 0)) return; - num = SV_AreaEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + num = SV_AreaEdicts(ent->progs.sv->absmin, ent->progs.sv->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + + PRVM_PUSH_GLOBALS; // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) for (i = 0; i < num; i++) { hit = touch[i]; - if (!hit->inuse) continue; - if (!hit->touch) continue; - hit->touch (hit, ent, NULL, NULL); - } -} + if (hit->priv.sv->free) continue; -/* -============= -SV_Find - -Searches all active entities for the next one that holds -the matching string at fieldofs (use the FOFS() macro) in the structure. - -Searches beginning at the edict after from, or the beginning if NULL -NULL will be returned if the end of the list is reached. - -============= -*/ -edict_t *SV_Find (edict_t *from, int fieldofs, char *match) -{ - char *s; - int i; - edict_t *ent; - - if (!from) i = NUM_FOR_EDICT(ge->edicts); - else i = NUM_FOR_EDICT(from); - - for (; i < ge->num_edicts; i++) - { - ent = EDICT_NUM(i); - - if(!ent->inuse) continue; - - s = *(char **)((byte *)ent + fieldofs); - if (!s) continue; - if (!strcasecmp (s, match)) - return ent; - } - return NULL; -} - - -/* -=========== -SelectSpawnPoint - -Chooses a player start, deathmatch start, coop start, etc -============ -*/ -void SV_SelectSpawnPoint (edict_t *ent, vec3_t origin, vec3_t angles) -{ - edict_t *spot = NULL; - - spot = SV_Find (spot, FOFS(classname), "info_player_start"); - if (!spot) PF_error ("Couldn't find spawn point\n"); - - VectorCopy (spot->s.origin, origin); - origin[2] += 9; - VectorCopy (spot->s.angles, angles); -} - - -/* -=========== -PutClientInServer - -Called when a player connects to a server or respawns in -a deathmatch. -============ -*/ -void SV_PutClientInServer (edict_t *ent) -{ - vec3_t mins = {-16, -16, -24}; - vec3_t maxs = {16, 16, 32}; - int index; - vec3_t spawn_origin, spawn_angles; - gclient_t *client; - int i; - - // find a spawn point - // do it before setting health back up, so farthest - // ranging doesn't count this client - SV_SelectSpawnPoint (ent, spawn_origin, spawn_angles); - - index = NUM_FOR_EDICT(ent) - 1; - - client = ent->client; - - ent->client = &game.clients[index]; - ent->movetype = MOVETYPE_WALK; - ent->inuse = true; - ent->classname = "player"; - ent->solid = SOLID_BBOX; - ent->model = "models/player.mdl"; - ent->svflags &= ~SVF_DEADMONSTER; - - VectorCopy (mins, ent->mins); - VectorCopy (maxs, ent->maxs); - VectorClear (ent->velocity); - - // clear playerstate values - memset (&ent->client->ps, 0, sizeof(client->ps)); - - client->ps.pmove.origin[0] = spawn_origin[0] * 8; - client->ps.pmove.origin[1] = spawn_origin[1] * 8; - client->ps.pmove.origin[2] = spawn_origin[2] * 8; - - client->ps.fov = 90; - - client->ps.fov = bound(1, client->ps.fov, 160); - client->ps.gunindex = SV_ModelIndex("models/weapons/v_eagle.mdl"); - - // clear entity state values - ent->s.effects = 0; - ent->s.modelindex = MAX_MODELS - 1; // will use the skin specified model - ent->s.weaponmodel = MAX_MODELS - 1; // custom gun model - - // sknum is player num and weapon number - // weapon number will be added in changeweapon - ent->s.skin = NUM_FOR_EDICT(ent) - 1; - - ent->s.frame = 0; - VectorCopy (spawn_origin, ent->s.origin); - ent->s.origin[2] += 1; // make sure off ground - VectorCopy (ent->s.origin, ent->s.old_origin); - - // set the delta angle - for (i = 0; i < 3; i++) - { - client->ps.pmove.delta_angles[i] = ANGLE2SHORT(spawn_angles[i]); + prog->globals.server->pev = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->other = PRVM_EDICT_TO_PROG(hit); + prog->globals.server->time = sv.time; + PRVM_ExecuteProgram (ent->progs.sv->touch, "QC function pev->touch is missing"); } - ent->s.angles[PITCH] = ent->s.angles[ROLL] = 0; - ent->s.angles[YAW] = spawn_angles[YAW]; - VectorCopy(ent->s.angles, client->ps.viewangles); - VectorCopy (client->ps.viewangles, client->v_angle); - - SV_LinkEdict(ent); + // restore state + PRVM_POP_GLOBALS; } static edict_t *current_player; @@ -653,38 +248,38 @@ void SV_CalcGunOffset (edict_t *ent) float delta; // gun angles from bobbing - ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005; - ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01; + ent->priv.sv->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005; + ent->priv.sv->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01; if (bobcycle & 1) { - ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL]; - ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW]; + ent->priv.sv->client->ps.gunangles[ROLL] = -ent->priv.sv->client->ps.gunangles[ROLL]; + ent->priv.sv->client->ps.gunangles[YAW] = -ent->priv.sv->client->ps.gunangles[YAW]; } - ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005; - ent->client->ps.viewoffset[2] = 22; + ent->priv.sv->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005; + ent->priv.sv->client->ps.viewoffset[2] = 22; // gun angles from delta movement for (i = 0; i < 3; i++) { - delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i]; + delta = ent->priv.sv->client->oldviewangles[i] - ent->priv.sv->client->ps.viewangles[i]; if (delta > 180) delta -= 360; if (delta < -180) delta += 360; if (delta > 45) delta = 45; if (delta < -45) delta = -45; - if (i == YAW) ent->client->ps.gunangles[ROLL] += 0.1*delta; - ent->client->ps.gunangles[i] += 0.2 * delta; + if (i == YAW) ent->priv.sv->client->ps.gunangles[ROLL] += 0.1*delta; + ent->priv.sv->client->ps.gunangles[i] += 0.2 * delta; } // gun height - VectorClear (ent->client->ps.gunoffset); + VectorClear (ent->priv.sv->client->ps.gunoffset); // gun_x / gun_y / gun_z are development tools for (i = 0; i < 3; i++) { - ent->client->ps.gunoffset[i] += forward[i]; - ent->client->ps.gunoffset[i] += right[i]; - ent->client->ps.gunoffset[i] += up[i]; + ent->priv.sv->client->ps.gunoffset[i] += forward[i]; + ent->priv.sv->client->ps.gunoffset[i] += right[i]; + ent->priv.sv->client->ps.gunoffset[i] += up[i]; } } @@ -697,24 +292,24 @@ void SV_CalcViewOffset (edict_t *ent) vec3_t v; // base angles - angles = ent->client->ps.kick_angles; + angles = ent->priv.sv->client->ps.kick_angles; // add angles based on velocity - delta = DotProduct (ent->velocity, forward); + delta = DotProduct (ent->progs.sv->velocity, forward); angles[PITCH] += delta * 0.002; - delta = DotProduct (ent->velocity, right); + delta = DotProduct (ent->progs.sv->velocity, right); angles[ROLL] += delta * 0.005; // add angles based on bob delta = bobfracsin * 0.002 * xyspeed; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) + if (ent->priv.sv->client->ps.pmove.pm_flags & PMF_DUCKED) delta *= 6; // crouching angles[PITCH] += delta; delta = bobfracsin * 0.002 * xyspeed; - if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) + if (ent->priv.sv->client->ps.pmove.pm_flags & PMF_DUCKED) delta *= 6; // crouching if (bobcycle & 1) delta = -delta; angles[ROLL] += delta; @@ -736,13 +331,13 @@ void SV_CalcViewOffset (edict_t *ent) v[1] = bound(-14, v[1], 14); v[2] = bound(-22, v[0], 30); - VectorCopy (v, ent->client->ps.viewoffset); + VectorCopy (v, ent->priv.sv->client->ps.viewoffset); } void SV_SetStats (edict_t *ent) { - ent->client->ps.stats[STAT_HEALTH_ICON] = SV_ImageIndex("i_health"); - ent->client->ps.stats[STAT_HEALTH] = ent->health; + ent->priv.sv->client->ps.stats[STAT_HEALTH_ICON] = SV_ImageIndex("i_health"); + ent->priv.sv->client->ps.stats[STAT_HEALTH] = ent->progs.sv->health; } void ClientEndServerFrame (edict_t *ent) @@ -751,7 +346,7 @@ void ClientEndServerFrame (edict_t *ent) int i; current_player = ent; - current_client = ent->client; + current_client = ent->priv.sv->client; // // If the origin or velocity have changed since ClientThink(), @@ -763,28 +358,28 @@ void ClientEndServerFrame (edict_t *ent) // for (i = 0; i < 3; i++) { - current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0; - current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0; + current_client->ps.pmove.origin[i] = ent->priv.sv->s.origin[i]*8.0; + current_client->ps.pmove.velocity[i] = ent->progs.sv->velocity[i]*8.0; } - AngleVectors (ent->client->v_angle, forward, right, up); + AngleVectors (ent->priv.sv->client->v_angle, forward, right, up); // // set model angles from view angles so other things in // the world can tell which direction you are looking // - if (ent->client->v_angle[PITCH] > 180) ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3; - else ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3; + if (ent->priv.sv->client->v_angle[PITCH] > 180) ent->priv.sv->s.angles[PITCH] = (-360 + ent->priv.sv->client->v_angle[PITCH])/3; + else ent->priv.sv->s.angles[PITCH] = ent->priv.sv->client->v_angle[PITCH]/3; - ent->s.angles[YAW] = ent->client->v_angle[YAW]; - ent->s.angles[ROLL] = 0; - ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4; + ent->priv.sv->s.angles[YAW] = ent->priv.sv->client->v_angle[YAW]; + ent->priv.sv->s.angles[ROLL] = 0; + ent->priv.sv->s.angles[ROLL] = SV_CalcRoll (ent->priv.sv->s.angles, ent->progs.sv->velocity)*4; // // calculate speed and cycle to be used for // all cyclic walking effects // - xyspeed = sqrt(ent->velocity[0] * ent->velocity[0] + ent->velocity[1] * ent->velocity[1]); + xyspeed = sqrt(ent->progs.sv->velocity[0] * ent->progs.sv->velocity[0] + ent->progs.sv->velocity[1] * ent->progs.sv->velocity[1]); if (xyspeed < 5) { @@ -824,14 +419,14 @@ ClientEndServerFrames void ClientEndServerFrames (void) { int i; - edict_t *ent; + edict_t *ent; // calc the player views now that all pushing // and damage has been added - for (i = 1; i < maxclients->value; i++) + for (i = 0; i < maxclients->value; i++) { - ent = EDICT_NUM(i); - if (!ent->inuse || !ent->client) + ent = PRVM_EDICT_NUM(i); + if (ent->priv.sv->free || !ent->priv.sv->client) continue; ClientEndServerFrame (ent); } @@ -854,12 +449,12 @@ void SV_RunFrame (void) // even the world gets a chance to think // - ent = EDICT_NUM(0); - for (i = 0; i < ge->num_edicts; i++, ent++) + ent = PRVM_EDICT_NUM(0); + for (i = 0; i < prog->num_edicts; i++, ent++) { - if (!ent->inuse) continue; + if (ent->priv.sv->free) continue; - VectorCopy (ent->s.origin, ent->s.old_origin); + VectorCopy (ent->priv.sv->s.origin, ent->priv.sv->s.old_origin); if (i > 0 && i <= maxclients->value) continue; //don't apply phys on clients @@ -873,9 +468,9 @@ void SV_RunFrame (void) bool SV_ClientConnect (edict_t *ent, char *userinfo) { // they can connect - ent->client = game.clients + NUM_FOR_EDICT(ent) - 1; - ent->svflags = 0; // make sure we start with known default - ent->health = 100; + ent->priv.sv->client = sv.clients + PRVM_NUM_FOR_EDICT(ent) - 1; + ent->progs.sv->flags = 0; // make sure we start with known default + ent->progs.sv->health = 100; return true; } @@ -884,7 +479,7 @@ void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo) { char *s; int playernum; - + // check for malformed or illegal info strings if (!Info_Validate(userinfo)) { @@ -894,12 +489,12 @@ void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo) // set skin s = Info_ValueForKey (userinfo, "skin"); - playernum = NUM_FOR_EDICT(ent) - 1; + playernum = PRVM_NUM_FOR_EDICT(ent); // combine name and skin into a configstring - PF_Configstring (CS_PLAYERSKINS + playernum, va("%s\\%s", Info_ValueForKey (userinfo, "name"), Info_ValueForKey (userinfo, "skin"))); + SV_ConfigString (CS_PLAYERSKINS + playernum, va("%s\\%s", Info_ValueForKey (userinfo, "name"), Info_ValueForKey (userinfo, "skin"))); - ent->client->ps.fov = bound(1, atoi(Info_ValueForKey(userinfo, "fov")), 160); + ent->priv.sv->client->ps.fov = bound(1, atoi(Info_ValueForKey(userinfo, "fov")), 160); } /* @@ -914,18 +509,18 @@ void SV_ClientBegin (edict_t *ent) { int i; - ent->client = game.clients + NUM_FOR_EDICT(ent) - 1; + ent->priv.sv->client = sv.clients + PRVM_NUM_FOR_EDICT(ent) - 1; // if there is already a body waiting for us (a loadgame), just // take it, otherwise spawn one from scratch - if (ent->inuse == true) + if (ent->priv.sv->free) { // the client has cleared the client side viewangles upon // connecting to the server, which is different than the // state when the game is saved, so we need to compensate // with deltaangles for (i = 0; i < 3; i++) - ent->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->client->ps.viewangles[i]); + ent->priv.sv->client->ps.pmove.delta_angles[i] = ANGLE2SHORT(ent->priv.sv->client->ps.viewangles[i]); } else { @@ -933,7 +528,6 @@ void SV_ClientBegin (edict_t *ent) // except for the persistant data that was initialized at // ClientConnect() time SV_InitEdict (ent); - ent->classname = "player"; SV_PutClientInServer (ent); } @@ -958,22 +552,22 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) vec3_t oldorigin, oldvelocity; int i, j; - client = ent->client; + client = ent->priv.sv->client; - VectorCopy(ent->s.origin, oldorigin); - VectorCopy(ent->velocity, oldvelocity); + VectorCopy(ent->priv.sv->s.origin, oldorigin); + VectorCopy(ent->progs.sv->velocity, oldvelocity); - ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; + ent->priv.sv->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; - VectorCopy(ent->s.origin, view); + VectorCopy(ent->priv.sv->s.origin, view); pm_passent = ent; // set up for pmove memset (&pm, 0, sizeof(pm)); - if (ent->movetype == MOVETYPE_NOCLIP) client->ps.pmove.pm_type = PM_SPECTATOR; - else if (ent->s.modelindex != MAX_MODELS - 1) client->ps.pmove.pm_type = PM_GIB; + if (ent->progs.sv->movetype == MOVETYPE_NOCLIP) client->ps.pmove.pm_type = PM_SPECTATOR; + else if (ent->priv.sv->s.modelindex != MAX_MODELS - 1) client->ps.pmove.pm_type = PM_GIB; else client->ps.pmove.pm_type = PM_NORMAL; client->ps.pmove.gravity = sv_gravity->value; @@ -981,8 +575,8 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) for (i = 0; i < 3; i++) { - pm.s.origin[i] = ent->s.origin[i]*8; - pm.s.velocity[i] = ent->velocity[i]*8; + pm.s.origin[i] = ent->priv.sv->s.origin[i]*8; + pm.s.velocity[i] = ent->progs.sv->velocity[i]*8; } if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) @@ -1002,17 +596,19 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) for (i = 0; i < 3; i++) { - ent->s.origin[i] = pm.s.origin[i]*0.125; - ent->velocity[i] = pm.s.velocity[i]*0.125; + ent->priv.sv->s.origin[i] = pm.s.origin[i]*0.125; + ent->progs.sv->velocity[i] = pm.s.velocity[i]*0.125; } - VectorCopy (pm.mins, ent->mins); - VectorCopy (pm.maxs, ent->maxs); + VectorCopy (pm.mins, ent->progs.sv->mins); + VectorCopy (pm.maxs, ent->progs.sv->maxs); SV_LinkEdict(ent); - if (ent->movetype != MOVETYPE_NOCLIP) + if (ent->progs.sv->movetype != MOVETYPE_NOCLIP) SV_TouchTriggers (ent); + PRVM_PUSH_GLOBALS; + for (i = 0; i < pm.numtouch; i++) { other = pm.touchents[i]; @@ -1022,9 +618,14 @@ void ClientThink (edict_t *ent, usercmd_t *ucmd) break; } if (j != i) continue; // duplicated - if (!other->touch) continue; - other->touch (other, ent, NULL, NULL); + + prog->globals.server->pev = PRVM_EDICT_TO_PROG(other); + prog->globals.server->other = PRVM_EDICT_TO_PROG(ent); + prog->globals.server->time = sv.time; +//PRVM_ExecuteProgram (ent->progs.sv->touch, "QC function pev->touch is missing"); } + + PRVM_POP_GLOBALS; } /* @@ -1039,27 +640,56 @@ void SV_ClientDisconnect (edict_t *ent) { int playernum; - if (!ent->client) return; + if (!ent->priv.sv->client) return; Msg("player disconnected\n"); // send effect MSG_Begin( svc_muzzleflash ); - MSG_WriteShort( &sv.multicast, NUM_FOR_EDICT(ent) ); + MSG_WriteShort( &sv.multicast, PRVM_NUM_FOR_EDICT(ent)); MSG_WriteByte( &sv.multicast, MZ_LOGOUT ); - MSG_Send(MSG_PVS, ent->s.origin, NULL); + MSG_Send(MSG_PVS, ent->priv.sv->s.origin, NULL); SV_UnlinkEdict(ent); - ent->s.modelindex = 0; - ent->solid = SOLID_NOT; - ent->inuse = false; - ent->classname = "disconnected"; + ent->priv.sv->s.modelindex = 0; + ent->progs.sv->solid = SOLID_NOT; + ent->priv.sv->free = true; + ent->progs.sv->classname = PRVM_SetEngineString("disconnected"); - playernum = NUM_FOR_EDICT(ent) - 1; - PF_Configstring (CS_PLAYERSKINS + playernum, ""); + playernum = PRVM_NUM_FOR_EDICT(ent) - 1; + SV_ConfigString (CS_PLAYERSKINS + playernum, ""); } +/* +=============== +PF_cprintf + +Print to a single client +=============== +*/ +void PF_cprintf (edict_t *ent, int level, char *fmt, ...) +{ + char msg[1024]; + va_list argptr; + int n; + + if (ent) + { + n = PRVM_NUM_FOR_EDICT(ent); + if (n < 1 || n > maxclients->value) + Host_Error("cprintf to a non-client\n"); + } + + va_start (argptr,fmt); + vsprintf (msg, fmt, argptr); + va_end (argptr); + + if (ent) SV_ClientPrintf (svs.clients+(n-1), level, "%s", msg); + else Msg ("%s", msg); +} + + /* ================== Cmd_Say_f @@ -1099,14 +729,14 @@ void Cmd_Say_f (edict_t *ent, bool team, bool arg0) strcat(text, "\n"); - if (dedicated->value) + if (dedicated->value) PF_cprintf(NULL, PRINT_CHAT, "%s", text); - for (j = 1; j <= game.maxclients; j++) + for (j = 1; j <= maxclients->value; j++) { - other = EDICT_NUM(j); - if (!other->inuse) continue; - if (!other->client) continue; + other = PRVM_EDICT_NUM(j); + if (other->priv.sv->free) continue; + if (!other->priv.sv->client) continue; PF_cprintf(other, PRINT_CHAT, "%s", text); } } @@ -1165,7 +795,7 @@ void SV_ClientCommand (edict_t *ent) char *cmd; char *parm; - if (!ent->client) return; // not fully in game yet + if (!ent->priv.sv->client) return; // not fully in game yet cmd = Cmd_Argv(0); diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 26e67ec3..fd162651 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -97,8 +97,8 @@ void SV_New_f (void) if (sv.state == ss_game) { // set up the entity for the client - ent = EDICT_NUM(playernum+1); - ent->s.number = playernum+1; + ent = PRVM_EDICT_NUM(playernum+1); + ent->priv.sv->s.number = playernum+1; sv_client->edict = ent; memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index dac9e951..21da2882 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -30,13 +30,7 @@ ENTITY AREA CHECKING FIXME: this use of "area" is different from the bsp file use =============================================================================== */ - -// (type *)STRUCT_FROM_LINK(link_t *link, type, member) -// ent = STRUCT_FROM_LINK(link,entity_t,order) -// FIXME: remove this mess! -#define STRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m))) - -#define EDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area) +#define EDICT_FROM_AREA(l) PRVM_EDICT_NUM(l->entnum) typedef struct areanode_s { @@ -73,12 +67,13 @@ void RemoveLink (link_t *l) l->prev->next = l->next; } -void InsertLinkBefore (link_t *l, link_t *before) +void InsertLinkBefore (link_t *l, link_t *before, edict_t *ent) { l->next = before; l->prev = before->prev; l->prev->next = l; l->next->prev = l; + l->entnum = PRVM_NUM_FOR_EDICT(ent); } /* @@ -108,10 +103,8 @@ areanode_t *SV_CreateAreaNode (int depth, vec3_t mins, vec3_t maxs) } VectorSubtract (maxs, mins, size); - if (size[0] > size[1]) - anode->axis = 0; - else - anode->axis = 1; + if (size[0] > size[1]) anode->axis = 0; + else anode->axis = 1; anode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]); VectorCopy (mins, mins1); @@ -149,10 +142,9 @@ SV_UnlinkEdict */ void SV_UnlinkEdict (edict_t *ent) { - if (!ent->area.prev) - return; // not linked in anywhere - RemoveLink (&ent->area); - ent->area.prev = ent->area.next = NULL; + if (!ent->priv.sv->area.prev) return; // not linked in anywhere + RemoveLink (&ent->priv.sv->area); + ent->priv.sv->area.prev = ent->priv.sv->area.next = NULL; } @@ -166,47 +158,47 @@ SV_LinkEdict void SV_LinkEdict (edict_t *ent) { areanode_t *node; - int leafs[MAX_TOTAL_ENT_LEAFS]; - int clusters[MAX_TOTAL_ENT_LEAFS]; - int num_leafs; - int i, j, k; - int area; - int topnode; + int leafs[MAX_TOTAL_ENT_LEAFS]; + int clusters[MAX_TOTAL_ENT_LEAFS]; + int num_leafs; + int i, j, k; + int area; + int topnode; - if (ent->area.prev) SV_UnlinkEdict (ent); // unlink from old position - if (ent == ge->edicts) return; // don't add the world - if (!ent->inuse) return; + if (ent->priv.sv->area.prev) SV_UnlinkEdict (ent); // unlink from old position + if (ent == prog->edicts) return; // don't add the world + if (ent->priv.sv->free) return; // set the size - VectorSubtract (ent->maxs, ent->mins, ent->size); + VectorSubtract (ent->progs.sv->maxs, ent->progs.sv->mins, ent->progs.sv->size); // encode the size into the entity_state for client prediction - if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER)) + if (ent->progs.sv->solid == SOLID_BBOX && !((int)ent->progs.sv->flags & FL_DEADMONSTER)) { // assume that x/y are equal and symetric - i = ent->maxs[0]/8; + i = ent->progs.sv->maxs[0]/8; if (i<1) i = 1; if (i>31) i = 31; // z is not symetric - j = (-ent->mins[2])/8; + j = (-ent->progs.sv->mins[2])/8; if (j < 1) j = 1; if (j > 31) j = 31; // and z maxs can be negative... - k = (ent->maxs[2]+32)/8; + k = (ent->progs.sv->maxs[2]+32)/8; if (k<1) k = 1; if (k>63) k = 63; - ent->s.solid = (k<<10) | (j<<5) | i; + ent->priv.sv->s.solid = (k<<10) | (j<<5) | i; } - else if (ent->solid == SOLID_BSP) + else if (ent->progs.sv->solid == SOLID_BSP) { - ent->s.solid = 31; // a solid_bbox will never create this value + ent->priv.sv->s.solid = 31; // a solid_bbox will never create this value } - else ent->s.solid = 0; + else ent->priv.sv->s.solid = 0; // set the abs box - if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) ) + if (ent->progs.sv->solid == SOLID_BSP && (ent->priv.sv->s.angles[0] || ent->priv.sv->s.angles[1] || ent->priv.sv->s.angles[2]) ) { // expand for rotation float max = 0, v; @@ -214,39 +206,39 @@ void SV_LinkEdict (edict_t *ent) for (i=0 ; i<3 ; i++) { - v =fabs( ent->mins[i]); + v =fabs( ent->progs.sv->mins[i]); if (v > max) max = v; - v =fabs( ent->maxs[i]); + v =fabs( ent->progs.sv->maxs[i]); if (v > max) max = v; } for (i=0 ; i<3 ; i++) { - ent->absmin[i] = ent->s.origin[i] - max; - ent->absmax[i] = ent->s.origin[i] + max; + ent->progs.sv->absmin[i] = ent->priv.sv->s.origin[i] - max; + ent->progs.sv->absmax[i] = ent->priv.sv->s.origin[i] + max; } } else { // normal - VectorAdd (ent->s.origin, ent->mins, ent->absmin); - VectorAdd (ent->s.origin, ent->maxs, ent->absmax); + VectorAdd (ent->priv.sv->s.origin, ent->progs.sv->mins, ent->progs.sv->absmin); + VectorAdd (ent->priv.sv->s.origin, ent->progs.sv->maxs, ent->progs.sv->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->absmin[0] -= 1; - ent->absmin[1] -= 1; - ent->absmin[2] -= 1; - ent->absmax[0] += 1; - ent->absmax[1] += 1; - ent->absmax[2] += 1; + 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; // link to PVS leafs - ent->num_clusters = 0; - ent->areanum = 0; - ent->areanum2 = 0; + ent->priv.sv->num_clusters = 0; + ent->priv.sv->areanum = 0; + ent->priv.sv->areanum2 = 0; //get all leafs, including solids - num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); + num_leafs = CM_BoxLeafnums (ent->progs.sv->absmin, ent->progs.sv->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); // set areas for (i = 0; i < num_leafs; i++) @@ -256,25 +248,25 @@ void SV_LinkEdict (edict_t *ent) if (area) { // doors may legally straggle two areas, // but nothing should evern need more than that - if (ent->areanum && ent->areanum != area) + if (ent->priv.sv->areanum && ent->priv.sv->areanum != area) { - if (ent->areanum2 && ent->areanum2 != area && sv.state == ss_loading) - MsgWarn("SV_LinkEdict: object touching 3 areas at %f %f %f\n", ent->absmin[0], ent->absmin[1], ent->absmin[2]); - ent->areanum2 = area; + if (ent->priv.sv->areanum2 && ent->priv.sv->areanum2 != area && sv.state == ss_loading) + MsgWarn("SV_LinkEdict: object touching 3 areas at %f %f %f\n", ent->progs.sv->absmin[0], ent->progs.sv->absmin[1], ent->progs.sv->absmin[2]); + ent->priv.sv->areanum2 = area; } - else ent->areanum = area; + else ent->priv.sv->areanum = area; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode - ent->num_clusters = -1; - ent->headnode = topnode; + ent->priv.sv->num_clusters = -1; + ent->priv.sv->headnode = topnode; } else { - ent->num_clusters = 0; + ent->priv.sv->num_clusters = 0; for (i = 0; i < num_leafs; i++) { if (clusters[i] == -1) continue; // not a visible leaf @@ -284,42 +276,42 @@ void SV_LinkEdict (edict_t *ent) } if (j == i) { - if (ent->num_clusters == MAX_ENT_CLUSTERS) + if (ent->priv.sv->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode - ent->num_clusters = -1; - ent->headnode = topnode; + ent->priv.sv->num_clusters = -1; + ent->priv.sv->headnode = topnode; break; } - ent->clusternums[ent->num_clusters++] = clusters[i]; + ent->priv.sv->clusternums[ent->priv.sv->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid - if (!ent->linkcount) + if (!ent->priv.sv->linkcount) { - VectorCopy (ent->s.origin, ent->s.old_origin); + VectorCopy (ent->priv.sv->s.origin, ent->priv.sv->s.old_origin); } - ent->linkcount++; + ent->priv.sv->linkcount++; - if (ent->solid == SOLID_NOT) return; + if (ent->progs.sv->solid == SOLID_NOT) return; // find the first node that the ent's box crosses node = sv_areanodes; while (1) { if (node->axis == -1) break; - if (ent->absmin[node->axis] > node->dist) + if (ent->progs.sv->absmin[node->axis] > node->dist) node = node->children[0]; - else if (ent->absmax[node->axis] < node->dist) + else if (ent->progs.sv->absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in - if (ent->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); - else InsertLinkBefore (&ent->area, &node->solid_edicts); + if (ent->progs.sv->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->priv.sv->area, &node->trigger_edicts, ent ); + else InsertLinkBefore (&ent->priv.sv->area, &node->solid_edicts, ent ); } @@ -346,9 +338,9 @@ void SV_AreaEdicts_r (areanode_t *node) next = l->next; check = EDICT_FROM_AREA(l); - if (check->solid == SOLID_NOT) continue; // deactivated - if (check->absmin[0] > area_maxs[0] || check->absmin[1] > area_maxs[1] || check->absmin[2] > area_maxs[2] - || check->absmax[0] < area_mins[0] || check->absmax[1] < area_mins[1] || check->absmax[2] < area_mins[2]) + if (check->progs.sv->solid == SOLID_NOT) continue; // deactivated + if (check->progs.sv->absmin[0] > area_maxs[0] || check->progs.sv->absmin[1] > area_maxs[1] || check->progs.sv->absmin[2] > area_maxs[2] + || check->progs.sv->absmax[0] < area_mins[0] || check->progs.sv->absmax[1] < area_mins[1] || check->progs.sv->absmax[2] < area_mins[2]) continue; // not touching if (area_count == area_maxcount) @@ -417,9 +409,9 @@ int SV_PointContents (vec3_t p) // might intersect, so do an exact clip headnode = SV_HullForEntity (hit); - angles = hit->s.angles; - if (hit->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - c2 = CM_TransformedPointContents (p, headnode, hit->s.origin, hit->s.angles); + angles = hit->priv.sv->s.angles; + if (hit->progs.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate + c2 = CM_TransformedPointContents (p, headnode, hit->priv.sv->s.origin, hit->priv.sv->s.angles); contents |= c2; } return contents; @@ -456,10 +448,10 @@ int SV_HullForEntity (edict_t *ent) cmodel_t *model; // decide which clipping hull to use, based on the size - if (ent->solid == SOLID_BSP) + if (ent->progs.sv->solid == SOLID_BSP) { // explicit hulls in the BSP model - model = sv.models[ ent->s.modelindex ]; + model = sv.models[ ent->priv.sv->s.modelindex ]; if (!model) { @@ -470,7 +462,7 @@ int SV_HullForEntity (edict_t *ent) } // create a temp hull from bounding box sizes - return CM_HeadnodeForBox (ent->mins, ent->maxs); + return CM_HeadnodeForBox (ent->progs.sv->mins, ent->progs.sv->maxs); } /* @@ -494,30 +486,32 @@ void SV_ClipMoveToEntities ( moveclip_t *clip ) for (i = 0; i < num; i++) { touch = touchlist[i]; - if (touch->solid == SOLID_NOT) continue; + if (touch->progs.sv->solid == SOLID_NOT) continue; if (touch == clip->passedict) continue; if (clip->trace.allsolid) return; if (clip->passedict) { - if (touch->owner == clip->passedict) continue; // don't clip against own missiles - if (clip->passedict->owner == touch) continue; // don't clip against owner + if (PRVM_PROG_TO_EDICT(touch->progs.sv->owner) == clip->passedict) + continue; // don't clip against own missiles + if (PRVM_PROG_TO_EDICT(clip->passedict->progs.sv->owner) == touch) + continue; // don't clip against owner } - if ( !(clip->contentmask & CONTENTS_DEADMONSTER) && (touch->svflags & SVF_DEADMONSTER) ) + if ( !(clip->contentmask & CONTENTS_DEADMONSTER) && ((int)touch->progs.sv->flags & FL_DEADMONSTER)) continue; // might intersect, so do an exact clip headnode = SV_HullForEntity (touch); - angles = touch->s.angles; - if (touch->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate + angles = touch->priv.sv->s.angles; + if (touch->progs.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - if (touch->svflags & SVF_MONSTER) + if ((int)touch->progs.sv->flags & FL_MONSTER) { - trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins2, clip->maxs2, headnode, clip->contentmask, touch->s.origin, angles); + trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins2, clip->maxs2, headnode, clip->contentmask, touch->priv.sv->s.origin, angles); } else { - trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins, clip->maxs, headnode, clip->contentmask, touch->s.origin, angles); + trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins, clip->maxs, headnode, clip->contentmask, touch->priv.sv->s.origin, angles); } if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { @@ -579,7 +573,7 @@ trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *p // clip to world clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask); - clip.trace.ent = ge->edicts; + clip.trace.ent = prog->edicts; if (clip.trace.fraction == 0) return clip.trace; // blocked by the world clip.contentmask = contentmask; diff --git a/engine/server/tstent.c b/engine/server/tstent.c new file mode 100644 index 00000000..f5b91e02 --- /dev/null +++ b/engine/server/tstent.c @@ -0,0 +1,55 @@ +void SP_info_player_start (edict_t *ent){} +void SP_info_player_deathmatch (edict_t *ent){} +void SP_worldspawn (edict_t *ent) +{ + vec3_t skyaxis; + + ent->priv.sv->movetype = MOVETYPE_PUSH; + ent->priv.sv->solid = SOLID_BSP; + ent->priv.sv->free = false; // since the world doesn't use G_Spawn() + ent->priv.sv->s.modelindex = 1; // world model is always index 1 + + //--------------- + + VectorSet( skyaxis, 32, 180, 20 ); + + PF_Configstring (CS_MAXCLIENTS, va("%i", (int)(maxclients->value))); + PF_Configstring (CS_STATUSBAR, single_statusbar); + PF_Configstring (CS_SKY, "sky" ); + PF_Configstring (CS_SKYROTATE, va("%f", 0.0f )); + PF_Configstring (CS_SKYAXIS, va("%f %f %f", skyaxis[0], skyaxis[1], skyaxis[2]) ); + PF_Configstring (CS_CDTRACK, va("%i", 0 )); + + //--------------- + + // help icon for statusbar + SV_ImageIndex ("i_help"); + SV_ImageIndex ("help"); + SV_ImageIndex ("field_3"); +} + +void SP_misc_explobox (edict_t *self) +{ + self->priv.sv->solid = SOLID_BBOX; + self->priv.sv->movetype = MOVETYPE_STEP; + + self->priv.sv->model = "models/barrel.mdl"; + self->priv.sv->s.modelindex = SV_ModelIndex (self->priv.sv->model); + VectorSet (self->priv.sv->mins, -16, -16, 0); + VectorSet (self->priv.sv->maxs, 16, 16, 40); + + if (!self->priv.sv->health) self->priv.sv->health = 10; + self->priv.sv->monsterinfo.aiflags = AI_NOSTEP; + + self->priv.sv->think = SV_DropToFloor; + self->priv.sv->nextthink = sv.time + 0.5; + + PF_setmodel (self, self->priv.sv->model); +} + +void SP_func_wall(edict_t *self) +{ + self->priv.sv->solid = SOLID_BSP; + PF_setmodel (self, self->priv.sv->model); + SV_LinkEdict(self); +} \ No newline at end of file diff --git a/engine/snd_dma.c b/engine/snd_dma.c index ac952e25..df5b487e 100644 --- a/engine/snd_dma.c +++ b/engine/snd_dma.c @@ -202,7 +202,7 @@ S_FindName ================== */ -sfx_t *S_FindName (char *name, bool create) +sfx_t *S_FindName (const char *name, bool create) { int i; sfx_t *sfx; @@ -302,7 +302,7 @@ S_RegisterSound ================== */ -sfx_t *S_RegisterSound (char *name) +sfx_t *S_RegisterSound (const char *name) { sfx_t *sfx; @@ -731,7 +731,7 @@ void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float f S_StartLocalSound ================== */ -int S_StartLocalSound (char *sound) +int S_StartLocalSound (const char *sound) { sfx_t *sfx; diff --git a/engine/sound.h b/engine/sound.h index 8b557ae4..c651f172 100644 --- a/engine/sound.h +++ b/engine/sound.h @@ -25,7 +25,7 @@ void S_Shutdown (void); // if origin is NULL, the sound will be dynamically sourced from the entity void S_StartSound (vec3_t origin, int entnum, int entchannel, struct sfx_s *sfx, float fvol, float attenuation, float timeofs); -int S_StartLocalSound (char *s); +int S_StartLocalSound (const char *s); void S_RawSamples (int samples, int rate, int width, int channels, byte *data); @@ -35,10 +35,10 @@ void S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up); void S_Activate (bool active); void S_BeginRegistration (void); -struct sfx_s *S_RegisterSound (char *sample); +struct sfx_s *S_RegisterSound (const char *sample); void S_EndRegistration (void); -struct sfx_s *S_FindName (char *name, bool create); +struct sfx_s *S_FindName (const char *name, bool create); // the sound code makes callbacks to the client for entitiy position // information, so entities can be dynamically re-spatialized diff --git a/launch/console.c b/launch/console.c index 2fde8041..9a0d7cae 100644 --- a/launch/console.c +++ b/launch/console.c @@ -89,13 +89,20 @@ void Sys_ShowConsoleW( bool show ) static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { - static bool s_timePolarity; + static bool s_timePolarity; + PAINTSTRUCT ps; + HDC hdc; switch (uMsg) { case WM_ACTIVATE: if ( LOWORD( wParam ) != WA_INACTIVE ) SetFocus( s_wcd.hwndInputLine ); break; + case WM_PAINT: + hdc = BeginPaint(hWnd, (LPPAINTSTRUCT)&ps); + EndPaint(hWnd,(LPPAINTSTRUCT)&ps); + return TRUE; + break; case WM_CLOSE: if(sys_error) { @@ -129,7 +136,7 @@ static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPara case WM_COMMAND: if ( wParam == SUBMIT_ID ) { - SendMessage(s_wcd.hwndInputLine,WM_CHAR, 13, 0L); + SendMessage(s_wcd.hwndInputLine, WM_CHAR, 13, 0L); SetFocus( s_wcd.hwndInputLine ); } break; @@ -197,11 +204,10 @@ print into window console void Sys_PrintW(const char *pMsg) { char buffer[MAX_INPUTLINE*2]; + static dword s_totalChars; char *b = buffer; const char *msg; - int bufLen; - int i = 0; - static unsigned long s_totalChars; + int bufLen, i = 0; // if the message is REALLY long, use just the last portion of it if ( strlen( pMsg ) > MAX_INPUTLINE - 1 ) diff --git a/launch/utils.c b/launch/utils.c index b95db103..3646ab80 100644 --- a/launch/utils.c +++ b/launch/utils.c @@ -12,6 +12,18 @@ bool debug_mode = false; bool console_read_only = true; int dev_mode = 0; +void Sys_SendKeyEvents( void ) +{ + MSG wmsg; + + while (PeekMessage (&wmsg, NULL, 0, 0, PM_NOREMOVE)) + { + if (!GetMessage (&wmsg, NULL, 0, 0)) break; + TranslateMessage (&wmsg); + DispatchMessage (&wmsg); + } +} + /* ==================== Log_Timestamp diff --git a/public/basetypes.h b/public/basetypes.h index 8f747e04..02ab423d 100644 --- a/public/basetypes.h +++ b/public/basetypes.h @@ -45,8 +45,10 @@ typedef struct image_s image_t; typedef struct model_s model_t; typedef int func_t; typedef struct edict_s edict_t; -typedef struct gclient_s gclient_t; typedef int string_t; +typedef struct gclient_s gclient_t; +typedef struct sv_edict_s sv_edict_t; +typedef struct cl_edict_s cl_edict_t; typedef int progsnum_t; typedef struct progfuncs_s progfuncs_t; typedef float vec_t; diff --git a/public/const.h b/public/const.h index 100675cc..45fe7174 100644 --- a/public/const.h +++ b/public/const.h @@ -121,17 +121,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // edict->movetype values // edict->flags -#define FL_FLY 0x00000001 -#define FL_SWIM 0x00000002 // implied immunity to drowining -#define FL_IMMUNE_LASER 0x00000004 -#define FL_INWATER 0x00000008 -#define FL_GODMODE 0x00000010 -#define FL_NOTARGET 0x00000020 -#define FL_IMMUNE_SLIME 0x00000040 -#define FL_IMMUNE_LAVA 0x00000080 -#define FL_PARTIALGROUND 0x00000100 // not all corners are valid -#define FL_WATERJUMP 0x00000200 // player jumping out of water -#define FL_ONGROUND 0x00000400 +#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 connection +#define FL_FLOAT (1<<7) // this entity can be floating. FIXME: remove this ? +#define FL_TRACKTRAIN (1<<8) // old stuff... typedef enum { @@ -260,7 +258,7 @@ typedef struct cplane_t plane; // surface normal at impact csurface_t *surface; // surface hit int contents; // contents on other side of surface hit - struct edict_s *ent; // not set by CM_*() functions + edict_t *ent; // not set by CM_*() functions } trace_t; @@ -343,14 +341,14 @@ typedef struct // results (out) int numtouch; - struct edict_s *touchents[MAXTOUCH]; + edict_t *touchents[MAXTOUCH]; vec3_t viewangles; // clamped float viewheight; vec3_t mins, maxs; // bounding box size - struct edict_s *groundentity; + edict_t *groundentity; int watertype; int waterlevel; diff --git a/release.bat b/release.bat index cf8267a6..7d27403a 100644 --- a/release.bat +++ b/release.bat @@ -56,5 +56,6 @@ if exist vprogs\server.dat move vprogs\server.dat D:\Xash3D\xash\server.dat echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -xash.exe -game valve +map skytest -debug -log +xash.exe -game valve +map lighttest -debug -log +rem bin\bsplib -game xash +map dm_qstyle -vis -rad -full -log :done \ No newline at end of file diff --git a/render/gl_model.c b/render/gl_model.c index 83e04303..62787557 100644 --- a/render/gl_model.c +++ b/render/gl_model.c @@ -444,7 +444,7 @@ void Mod_LoadTexinfo (lump_t *l) loadmodel->texinfo = out; loadmodel->numtexinfo = count; - for ( i=0 ; ivecs[0][j] = LittleFloat(in->vecs[0][j]); @@ -461,13 +461,12 @@ void Mod_LoadTexinfo (lump_t *l) out->image = r_notexture; } } - // count animation frames for (i = 0; i < count; i++) { out = &loadmodel->texinfo[i]; out->numframes = 1; - for (step = out->next ; step && step != out ; step=step->next) + for (step = out->next; step && step != out; step = step->next) out->numframes++; } } diff --git a/render/gl_rsurf.c b/render/gl_rsurf.c index 569e1a86..85d1f95f 100644 --- a/render/gl_rsurf.c +++ b/render/gl_rsurf.c @@ -83,10 +83,9 @@ image_t *R_TextureAnimation (mtexinfo_t *tex) { int c; - if (!tex->next) - return tex->image; + if (!tex->next) return tex->image; - c = fmod(currententity->frame, tex->numframes); + c = (int)currententity->frame % tex->numframes; while (c) { tex = tex->next; @@ -96,81 +95,6 @@ image_t *R_TextureAnimation (mtexinfo_t *tex) return tex->image; } -#if 0 -/* -================= -WaterWarpPolyVerts - -Mangles the x and y coordinates in a copy of the poly -so that any drawing routine can be water warped -================= -*/ -glpoly_t *WaterWarpPolyVerts (glpoly_t *p) -{ - int i; - float *v, *nv; - static byte buffer[1024]; - glpoly_t *out; - - out = (glpoly_t *)buffer; - - out->numverts = p->numverts; - v = p->verts[0]; - nv = out->verts[0]; - for (i = 0; i < p->numverts; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE) - { - nv[0] = v[0] + 4*sin(v[1] * 0.05 + r_newrefdef.time) * sin(v[2] * 0.05 + r_newrefdef.time); - nv[1] = v[1] + 4*sin(v[0] * 0.05 + r_newrefdef.time) * sin(v[2] * 0.05 + r_newrefdef.time); - - nv[2] = v[2]; - nv[3] = v[3]; - nv[4] = v[4]; - nv[5] = v[5]; - nv[6] = v[6]; - } - - return out; -} - -/* -================ -DrawGLWaterPoly - -Warp the vertex coordinates -================ -*/ -void DrawGLWaterPoly (glpoly_t *p) -{ - int i; - float *v; - - p = WaterWarpPolyVerts (p); - qglBegin (GL_TRIANGLE_FAN); - v = p->verts[0]; - for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) - { - qglTexCoord2f (v[3], v[4]); - qglVertex3fv (v); - } - qglEnd (); -} -void DrawGLWaterPolyLightmap (glpoly_t *p) -{ - int i; - float *v; - - p = WaterWarpPolyVerts (p); - qglBegin (GL_TRIANGLE_FAN); - v = p->verts[0]; - for (i=0 ; inumverts ; i++, v+= VERTEXSIZE) - { - qglTexCoord2f (v[5], v[6]); - qglVertex3fv (v); - } - qglEnd (); -} -#endif - /* ================ DrawGLPoly @@ -1191,7 +1115,7 @@ void R_DrawWorld (void) // auto cycle the world frame for texture animation memset (&ent, 0, sizeof(ent)); - ent.frame = (int)(r_newrefdef.time * 0.5); + ent.frame = (int)(r_newrefdef.time * 0.01); currententity = &ent; gl_state.currenttextures[0] = gl_state.currenttextures[1] = -1; diff --git a/vprogs/client.c b/vprogs/client.c index d3b719ec..5385f9bd 100644 --- a/vprogs/client.c +++ b/vprogs/client.c @@ -166,8 +166,8 @@ This function is called when the player enters the 'kill' command in the console void() ClientKill = { - //pprint(self, " has", " killed themselves."); - T_Damage(self, self, self, self.health); + //pprint(pev, " has", " killed themselves."); + T_Damage(pev, pev, pev, pev->health); ClientRespawn(); }; @@ -182,7 +182,7 @@ This function is called when the player connects to the server. void() ClientConnect = { - pprint(self, " has", " joined the game."); + pprint(pev, " has", " joined the game."); configstring (2, "sky"); //CS_SKY }; @@ -197,7 +197,7 @@ This function is called when the player disconnects from the server. void() ClientDisconnect = { - pprint(self, " has", " left the game."); + pprint(pev, " has", " left the game."); }; /* @@ -261,37 +261,37 @@ void() PutClientInServer = local entity spawn_spot; // This holds where we want to spawn spawn_spot = find_spawnspot(); //find (world, classname, "info_player_start"); // Find it :) - self.classname = "player"; // I'm a player! - self.health = self.max_health = 100; // My health (and my max) is 100 - self.takedamage = DAMAGE_AIM; // I can be fired at - self.solid = SOLID_BBOX; // Things sort of 'slide' past me - self.movetype = MOVETYPE_WALK; // Yep, I want to walk. - self.flags = FL_CLIENT; // Yes, I'm a client. + pev->classname = "player"; // I'm a player! + pev->health = pev->max_health = 100; // My health (and my max) is 100 + pev->takedamage = DAMAGE_AIM; // I can be fired at + pev->solid = SOLID_BBOX; // Things sort of 'slide' past me + pev->movetype = MOVETYPE_WALK; // Yep, I want to walk. + pev->flags = FL_CLIENT; // Yes, I'm a client. - self.origin = spawn_spot.origin + '0 0 1'; // Move to the spawnspot location - self.angles = spawn_spot.angles; // Face the angle the spawnspot indicates - self.fixangle = TRUE; // Turn this way immediately + pev->origin = spawn_spot.origin + '0 0 1'; // Move to the spawnspot location + pev->angles = spawn_spot.angles; // Face the angle the spawnspot indicates + pev->fixangle = TRUE; // Turn this way immediately dprint("PutClientInServer()\n"); - setmodel (self, "models/player.mdl"); // Set my player to the player model - setsize (self, VEC_HULL_MIN, VEC_HULL_MAX); // Set my size + setmodel (pev, "models/player.mdl"); // Set my player to the player model + setsize (pev, VEC_HULL_MIN, VEC_HULL_MAX); // Set my size - self.view_ofs = '0 0 22'; // Center my view + pev->view_ofs = '0 0 22'; // Center my view - setsize(self, '-16 -16 -32', '16 16 32' ); + setsize(pev, '-16 -16 -32', '16 16 32' ); - if (self.aflag) + if (pev->aflag) CCamChasePlayer (); - self.velocity = '0 0 0'; // Stop any old movement + pev->velocity = '0 0 0'; // Stop any old movement - self.th_pain = PlayerPain; - self.th_die = PlayerDie; + pev->th_pain = PlayerPain; + pev->th_die = PlayerDie; - setstats( self, STAT_HEALTH_ICON, "i_health"); - setstats( self, STAT_HEALTH, ftos(self.health)); - //setstats( self, STAT_HELPICON, "i_help"); + setstats( pev, STAT_HEALTH_ICON, "i_health"); + setstats( pev, STAT_HEALTH, ftos(pev->health)); + //setstats( pev, STAT_HELPICON, "i_help"); GetLevelParms(); }; diff --git a/vprogs/compile.log b/vprogs/compile.log new file mode 100644 index 00000000..01658196 --- /dev/null +++ b/vprogs/compile.log @@ -0,0 +1,75 @@ +======================================================================= + Xash3D started at Sep16 2007 [20:19:23] +======================================================================= +------- Loading bin/launch.dll [0.6] ------- +Sys_LoadLibrary: Loading common.dll [2] - ok +------- Loading bin/common.dll [1.3] ------- +CPU: AuthenticAMD [1 core]. Frequency: 1.8 Ghz +CPU Features: MMX 3DNow SSE SSE2 RDTSC CMOV FCMOV +Current search path: +./ +--------------------Configuration: server - Vm16 Debug-------------------- +Compiling... +defs.c +main.c +damage.c +player.c +client.c +dummys.c +ents/internal.c +ents/lights.c +ents/ambient.c +ents/ccam.c +ents/triggers/triggers.c +ents/triggers/trigger_generic.c +ents/triggers/trigger_once.c +ents/triggers/trigger_sequence.c +ents/triggers/trigger_message.c +ents/triggers/trigger_counter.c +ents/triggers/trigger_setviewpoint.c +ents/triggers/trigger_teleport.c +ents/triggers/trigger_hurt.c +ents/triggers/trigger_push.c +ents/triggers/trigger_changelevel.c +ents/triggers/trigger_setskill.c +ents/triggers/trigger_secret.c +ents/funcs/funcs.c +ents/funcs/func_mover.c +ents/funcs/func_door.c +ents/funcs/func_button.c +ents/funcs/func_path_corner.c +ents/funcs/func_train.c +ents/items/items.c +impulses.c +writing progdefs.h +Progs should run on any Quake executor +client.c(75) : warning C2: 'who' : unreferenced local variable +client.c(76) : warning C2: 'fragnum' : unreferenced local variable +dummys.c(131) : warning C2: 'f' : unreferenced local variable +dummys.c(131) : warning C2: 'g' : unreferenced local variable +ents/triggers/trigger_setviewpoint.c(26) : warning C2: 'oldpev' : unreferenced local variable +ents/triggers/trigger_setviewpoint.c(26) : warning C2: 'oldtrig' : unreferenced local variable + 18752 strofs (of 1000000) + 2805 numstatements (of 524288) + 263 numfunctions (of 16384) + 893 numglobaldefs (of 32768) + 234 numfielddefs (209 unique) (of 2048) + 903 numpr_globals (of 65536) +Writing server.dat + 63476 TOTAL SIZE + 17 unique precache_sounds + 5 unique precache_models +optres_shortenifnots 30 +optres_overlaptemps 1282 +optres_nonvec_parms 457 +optres_assignments 58 +optres_unreferenced 92 +optres_dupconstdefs 84 +‘Є®ЇЁа®ў ­® д ©«®ў: 1. + +server.dat - 0 error(s), 6 warning(s) +Sys_FreeLibrary: Unloading common.dll + +======================================================================= + Xash3D stopped at Sep16 2007 [20:19:24] +======================================================================= \ No newline at end of file diff --git a/vprogs/damage.c b/vprogs/damage.c index d60bb248..d5b90d40 100644 --- a/vprogs/damage.c +++ b/vprogs/damage.c @@ -18,7 +18,7 @@ void(entity who_died, entity who_killed) ClientObiturary; void(entity targ, entity attacker) Killed = { - local entity oself; + local entity oldpev; if (targ.health < -99) targ.health = -99; // don't let sbar look bad if a player @@ -26,10 +26,10 @@ void(entity targ, entity attacker) Killed = targ.takedamage = DAMAGE_NO; targ.touch = SUB_Null; - oself = self; - self = targ; // self must be targ for th_die - self.th_die (); - self = oself; + oldpev = pev; + pev = targ; // pev must be targ for th_die + pev->th_die (); + pev = oldpev; ClientObiturary(targ, attacker); }; @@ -69,7 +69,7 @@ This should be the only function that ever reduces health. void(entity targ, entity inflictor, entity attacker, float damage) T_Damage= { local vector dir; - local entity oldself; + local entity oldpev; if (!targ.takedamage) return; @@ -86,7 +86,7 @@ void(entity targ, entity inflictor, entity attacker, float damage) T_Damage= } // check for godmode - if (targ.flags & FL_GODMODE) + if (targ.aiflags & AI_GODMODE) return; // add to the damage total for clients, which will be sent as a single @@ -112,13 +112,13 @@ void(entity targ, entity inflictor, entity attacker, float damage) T_Damage= } // react to the damage - oldself = self; - self = targ; + oldpev = pev; + pev = targ; - if (self.th_pain) - self.th_pain (attacker, damage); + if (pev->th_pain) + pev->th_pain (attacker, damage); - self = oldself; + pev = oldpev; }; @@ -131,33 +131,33 @@ Can be used for clients or monsters */ void() WaterMove = { - if (self.movetype == MOVETYPE_NOCLIP) + if (pev->movetype == MOVETYPE_NOCLIP) return; - if (self.health < 0) + if (pev->health < 0) return; - if (self.waterlevel != 3) + if (pev->waterlevel != 3) { - self.air_finished = time + 12; - self.dmg = 2; + pev->air_finished = time + 12; + pev->dmg = 2; } - else if (self.air_finished < time && self.pain_finished < time) + else if (pev->air_finished < time && pev->pain_finished < time) { // drown! - self.dmg = self.dmg + 2; - if (self.dmg > 15) - self.dmg = 10; - T_Damage (self, world, world, self.dmg); - self.pain_finished = time + 1; + pev->dmg = pev->dmg + 2; + if (pev->dmg > 15) + pev->dmg = 10; + T_Damage (pev, world, world, pev->dmg); + pev->pain_finished = time + 1; } - if (self.watertype == CONTENT_LAVA && self.dmgtime < time) + if (pev->watertype == CONTENT_LAVA && pev->dmgtime < time) { // do damage - self.dmgtime = time + 0.2; - T_Damage (self, world, world, 6*self.waterlevel); + pev->dmgtime = time + 0.2; + T_Damage (pev, world, world, 6*pev->waterlevel); } - else if (self.watertype == CONTENT_SLIME && self.dmgtime < time) + else if (pev->watertype == CONTENT_SLIME && pev->dmgtime < time) { // do damage - self.dmgtime = time + 1; - T_Damage (self, world, world, 4*self.waterlevel); + pev->dmgtime = time + 1; + T_Damage (pev, world, world, 4*pev->waterlevel); } }; \ No newline at end of file diff --git a/vprogs/defs.c b/vprogs/defs.c index 39fd7411..4a928694 100644 --- a/vprogs/defs.c +++ b/vprogs/defs.c @@ -14,120 +14,173 @@ */ // These lines CANNOT be altered/moved -entity self; -entity other; -entity world; -float time; -float frametime; -float force_retouch; // force all entities to touch triggers -string mapname; -float deathmatch; -float coop; -float teamplay; -float serverflags; // propagated from level to level, used to -float total_secrets; -float total_monsters; -float found_secrets; // number of secrets found -float killed_monsters; // number of monsters killed -float parm1, parm2, parm3, parm4, parm5, parm6, parm7, parm8, parm9, parm10, parm11, parm12, parm13, parm14, parm15, parm16; -vector v_forward, v_up, v_right; // set by makevectors() -float trace_allsolid; -float trace_startsolid; -float trace_fraction; -vector trace_endpos; -vector trace_plane_normal; -float trace_plane_dist; -entity trace_ent; -float trace_inopen; -float trace_inwater; + // pointers to ents + entity pev; // Pointer EntVars (same as self) + entity other; + entity world; -entity msg_entity; // destination of single entity writes -void() main; // only for testing -void() StartFrame; -void() EndFrame; -void() PlayerPreThink; -void() PlayerPostThink; -void() ClientKill; -void() ClientConnect; -void() PutClientInServer; // call after setting the parm1... parms -void() ClientDisconnect; -void() SetNewParms; // called when a client first connects to -void() SetChangeParms; // call to set parms for self so they can -void end_sys_globals; // flag for structure dumping + // timer + float time; + float frametime; -.float modelindex; // *** model index in the precached list -.vector absmin, absmax; // *** origin + mins / maxs -.float ltime; // local time for entity -.float movetype; -.float solid; -.vector origin; // *** -.vector oldorigin; // *** -.vector velocity; -.vector angles; -.vector avelocity; -.vector punchangle; // temp angle adjust from damage or recoil -.string classname; // spawn function -.string model; -.float frame; -.float skin; -.float body; -.float effects; -.float sequence; -.float renderfx; -.vector mins, maxs; // bounding box extents reletive to origin -.vector size; // maxs - mins -.void() touch; -.void() use; -.void() think; -.void() blocked; // for doors or plats, called when can't push other -.float nextthink; -.entity groundentity; -.float health; -.float frags; -.float weapon; // one of the IT_SHOTGUN, etc flags -.string weaponmodel; -.float weaponframe; -.float currentammo; -.float ammo_shells, ammo_nails, ammo_rockets, ammo_cells; -.float items; // bit flags -.float takedamage; -.entity chain; -.float deadflag; -.vector view_ofs; // add to origin to get eye point -.float button0; // fire -.float button1; // use -.float button2; // jump -.float impulse; // weapon changes -.float fixangle; -.vector v_angle; // view / targeting angle for players -.float idealpitch; // calculated pitch angle for lookup up slopes -.string netname; -.entity enemy; -.float flags; -.float colormap; -.float team; -.float max_health; // players maximum health is stored here -.float teleport_time; // don't back up -.float armortype; // save this fraction of incoming damage -.float armorvalue; -.float waterlevel; // 0 = not in, 1 = feet, 2 = wast, 3 = eyes -.float watertype; // a contents value -.float ideal_yaw; -.float yaw_speed; -.entity aiment; -.entity goalentity; // a movetarget or an enemy -.float spawnflags; -.string target; -.string targetname; -.float dmg_take; -.float dmg_save; -.entity dmg_inflictor; -.entity owner; // who launched a missile -.vector movedir; // mostly for doors, but also used for waterjump -.string message; // trigger messages -.float sounds; // either a cd track number or sound number -.string noise, noise1, noise2, noise3; // contains names of wavs to play + // map global info + string mapname; + string startspot; + vector spotoffset; + // gameplay modes + float deathmatch; + float coop; + float teamplay; + + float serverflags; // propagated from level to level, used to + + // game info + float total_secrets; + float total_monsters; + float found_secrets; // number of secrets found + float killed_monsters; // number of monsters killed + + // MakeVectors result + vector v_forward; + vector v_right; + vector v_up; + + // SV_trace result + float trace_allsolid; + float trace_startsolid; + float trace_fraction; + vector trace_endpos; + vector trace_plane_normal; + float trace_plane_dist; + float trace_hitgroup; + float trace_contents; + entity trace_ent; + float trace_flags; + + void() main; // only for testing + void() StartFrame; + void() EndFrame; + void() PlayerPreThink; + void() PlayerPostThink; + void() ClientKill; + void() ClientConnect; + void() PutClientInServer; // call after setting the parm1... parms + void() ClientDisconnect; + void() SetNewParms; // called when a client first connects to + void() SetChangeParms; // call to set parms for self so they can + +void end_sys_globals; // flag for structure dumping + + // base entity info + .string classname; + .string globalname; + .float modelindex; + + // physics description + .vector origin; + .vector angles; + .vector velocity; + .vector avelocity; + .vector post_origin; + .vector post_angles; + .vector post_velocity; + .vector post_avelocity; + .vector origin_offset; + .vector angles_offset; + + .float bouncetype; + .float movetype; + .float solid; + .vector absmin, absmax; + .vector mins, maxs; + .vector size; + + // entity base description + .entity chain; // dynamic list of all ents + .string model; + .float frame; + .float sequence; + .float renderfx; + .float effects; + .float skin; + .float body; + .string weaponmodel; + .float weaponframe; + + // base generic funcs + .void() use; + .void() touch; + .void() think; + .void() blocked; + .void() activate; + + // npc generic funcs + .void() walk; + .void() jump; + .void() duck; + + // flags + .float flags; + .float aiflags; + .float spawnflags; + + // other variables + .entity groundentity; + .float nextthink; + .float takedamage; + .float health; + + .float frags; + .float weapon; + .float items; + .string target; + .string parent; + .string targetname; + .entity aiment; // attachment edict + .entity goalentity; + .vector punchangle; + .float deadflag; + .vector view_ofs; //.entity viewheight; + .float button0; + .float button1; + .float button2; + .float impulse; + .float fixangle; + .vector v_angle; + .float idealpitch; + .string netname; + .entity enemy; + .float colormap; + .float team; + .float max_health; + .float teleport_time; + .float armortype; + .float armorvalue; + .float waterlevel; + .float watertype; + .float ideal_yaw; + .float yaw_speed; + .float dmg_take; + .float dmg_save; + .entity dmg_inflictor; + .entity owner; + .vector movedir; + .string message; + .float sounds; + .string noise; + .string noise1; + .string noise2; + .string noise3; + .float jumpup; + .float jumpdn; + .entity movetarget; + .float mass; + .float density; + .float gravity; + .float dmg; + .float dmgtime; + .float speed; void end_sys_fields; // flag for structure dumping // End. Lines below this MAY be altered, to some extent @@ -240,19 +293,31 @@ float TRUE = 1; #define STAT_ZOOM 23 #define MAX_STATS 32 +// edict.aiflags +#define AI_FLY 1 // monster is flying +#define AI_SWIM 2 // swimming monster +#define AI_ONGROUND 4 // monster is onground +#define AI_PARTIALONGROUND 8 // monster is partially onground +#define AI_GODMODE 16 // monster don't give damage at all +#define AI_NOTARGET 32 // monster will no searching enemy's +#define AI_NOSTEP 64 // Lazarus stuff +#define AI_DUCKED 128 // monster (or player) is ducked +#define AI_JUMPING 256 // monster (or player) is jumping +#define AI_FROZEN 512 // stop moving, but continue thinking +#define AI_ACTOR 1024 // disable ai for actor +#define AI_DRIVER 2048 // npc or player driving vehcicle or train +#define AI_SPECTATOR 4096 // spectator mode for clients + // edict.flags -float FL_FLY = 1; -float FL_SWIM = 2; -float FL_CLIENT = 8; // set for all client edicts -float FL_INWATER = 16; // for enter / leave water splash -float FL_MONSTER = 32; -float FL_GODMODE = 64; // player cheat -float FL_NOTARGET = 128; // player cheat -float FL_ITEM = 256; // extra wide size for bonus items -float FL_ONGROUND = 512; // standing on something -float FL_PARTIALGROUND = 1024; // not all corners are valid -float FL_WATERJUMP = 2048; // player jumping out of water -float FL_JUMPRELEASED = 4096; // for jump debouncing +#define FL_CLIENT 1 // this is client +#define FL_MONSTER 2 // this is npc +#define FL_DEADMONSTER 4 +#define FL_WORLDBRUSH 8 // Not moveable/removeable brush entity +#define FL_DORMANT 16 // Entity is dormant, no updates to client +#define FL_FRAMETHINK 32 // entity will be thinking every frame +#define FL_GRAPHED 64 // ainode list member +#define FL_FLOAT 128 // this entity can be floating. FIXME: remove this ? +#define FL_TRACKTRAIN 256 // this is tracktrain entity // edict.movetype values float MOVETYPE_NONE = 0; // never moves @@ -424,7 +489,7 @@ string string_null; // null string, nothing should be held here void(vector o, vector d, float color, float count) particle = #48;// start a particle effect void(string s) bprint = #23; void(entity client, string s) sprint = #24; -void() SUB_Remove = {remove(self);}; +void() SUB_Remove = {remove(pev);}; // End // Damage.qc diff --git a/vprogs/dummys.c b/vprogs/dummys.c index 0e582e5f..c7b90852 100644 --- a/vprogs/dummys.c +++ b/vprogs/dummys.c @@ -4,44 +4,44 @@ +------+-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+ | Scratch Http://www.admdev.com/scratch | +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+ -| This file contains remove(self); statements for entities not yet coded. | +| This file contains remove(pev); statements for entities not yet coded. | | This avoids Quake spewing out pages and pages of error messages when | | loading maps. | +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+ */ // General Junk -void() event_lightning = {remove(self);}; -void() misc_fireball = {remove(self);}; -void() misc_explobox2 = {remove(self);}; -void() trap_spikeshooter = {remove(self);}; -void() trap_shooter = {remove(self);}; -void() func_bossgate = {remove(self);}; -void() func_episodegate = {remove(self);}; -//void() func_illusionary = {remove(self);}; -//void() func_train = {remove(self);}; -//void() func_button = {remove(self);}; -//void() func_door = {remove(self);}; -void() func_door_secret = {remove(self);}; -void() func_plat = {remove(self);}; -void() func_wall = {remove(self);}; -void() info_intermission = {remove(self);}; -void() info_null = {remove(self);}; -//void() info_teleport_destination= {remove(self);}; -//void() path_corner = {remove(self);}; +void() event_lightning = {remove(pev);}; +void() misc_fireball = {remove(pev);}; +void() misc_explobox2 = {remove(pev);}; +void() trap_spikeshooter = {remove(pev);}; +void() trap_shooter = {remove(pev);}; +void() func_bossgate = {remove(pev);}; +void() func_episodegate = {remove(pev);}; +//void() func_illusionary = {remove(pev);}; +//void() func_train = {remove(pev);}; +//void() func_button = {remove(pev);}; +//void() func_door = {remove(pev);}; +void() func_door_secret = {remove(pev);}; +void() func_plat = {remove(pev);}; +void() func_wall = {remove(pev);}; +void() info_intermission = {remove(pev);}; +void() info_null = {remove(pev);}; +//void() info_teleport_destination= {remove(pev);}; +//void() path_corner = {remove(pev);}; // Triggers -//void() trigger_relay = {remove(self);}; -//void() trigger_multiple = {remove(self);}; -//void() trigger_once = {remove(self);}; -//void() trigger_changelevel = {remove(self);}; -//void() trigger_counter = {remove(self);}; -//void() trigger_teleport = {remove(self);}; -//void() trigger_secret = {remove(self);}; -//void() trigger_setskill = {remove(self);}; -void() trigger_monsterjump = {remove(self);}; -void() trigger_onlyregistered = {remove(self);}; -//void() trigger_push = {remove(self);}; -//void() trigger_hurt = {remove(self);}; +//void() trigger_relay = {remove(pev);}; +//void() trigger_multiple = {remove(pev);}; +//void() trigger_once = {remove(pev);}; +//void() trigger_changelevel = {remove(pev);}; +//void() trigger_counter = {remove(pev);}; +//void() trigger_teleport = {remove(pev);}; +//void() trigger_secret = {remove(pev);}; +//void() trigger_setskill = {remove(pev);}; +void() trigger_monsterjump = {remove(pev);}; +void() trigger_onlyregistered = {remove(pev);}; +//void() trigger_push = {remove(pev);}; +//void() trigger_hurt = {remove(pev);}; // Player Starts void() info_player_start = {}; @@ -50,45 +50,45 @@ void() info_player_deathmatch = {}; void() info_player_coop = {}; // Weapons -void() weapon_supershotgun = {remove(self);}; -void() weapon_nailgun = {remove(self);}; -void() weapon_supernailgun = {remove(self);}; -void() weapon_grenadelauncher = {remove(self);}; -void() weapon_rocketlauncher = {remove(self);}; -void() weapon_lightning = {remove(self);}; +void() weapon_supershotgun = {remove(pev);}; +void() weapon_nailgun = {remove(pev);}; +void() weapon_supernailgun = {remove(pev);}; +void() weapon_grenadelauncher = {remove(pev);}; +void() weapon_rocketlauncher = {remove(pev);}; +void() weapon_lightning = {remove(pev);}; // Monsters -void() monster_enforcer = {remove(self);}; -void() monster_ogre = {remove(self);}; -void() monster_demon1 = {remove(self);}; -void() monster_shambler = {remove(self);}; -void() monster_knight = {remove(self);}; -void() monster_army = {remove(self);}; -void() monster_wizard = {remove(self);}; -void() monster_dog = {remove(self);}; -void() monster_zombie = {remove(self);}; -void() monster_boss = {remove(self);}; -void() monster_tarbaby = {remove(self);}; -void() monster_hell_knight = {remove(self);}; -void() monster_fish = {remove(self);}; -void() monster_shalrath = {remove(self);}; -void() monster_oldone = {remove(self);}; +void() monster_enforcer = {remove(pev);}; +void() monster_ogre = {remove(pev);}; +void() monster_demon1 = {remove(pev);}; +void() monster_shambler = {remove(pev);}; +void() monster_knight = {remove(pev);}; +void() monster_army = {remove(pev);}; +void() monster_wizard = {remove(pev);}; +void() monster_dog = {remove(pev);}; +void() monster_zombie = {remove(pev);}; +void() monster_boss = {remove(pev);}; +void() monster_tarbaby = {remove(pev);}; +void() monster_hell_knight = {remove(pev);}; +void() monster_fish = {remove(pev);}; +void() monster_shalrath = {remove(pev);}; +void() monster_oldone = {remove(pev);}; -void() item_health = {remove(self);}; -void() item_megahealth_rot = {remove(self);}; -void() item_armor1 = {remove(self);}; -void() item_armor2 = {remove(self);}; -void() item_armorInv = {remove(self);}; -void() item_shells = {remove(self);}; -void() item_spikes = {remove(self);}; -void() item_rockets = {remove(self);}; -void() item_cells = {remove(self);}; -void() item_key1 = {remove(self);}; -void() item_key2 = {remove(self);}; -void() item_artifact_invulnerability = {remove(self);}; -void() item_artifact_envirosuit = {remove(self);}; -void() item_artifact_invisibility = {remove(self);}; -void() item_artifact_super_damage = {remove(self);}; +void() item_health = {remove(pev);}; +void() item_megahealth_rot = {remove(pev);}; +void() item_armor1 = {remove(pev);}; +void() item_armor2 = {remove(pev);}; +void() item_armorInv = {remove(pev);}; +void() item_shells = {remove(pev);}; +void() item_spikes = {remove(pev);}; +void() item_rockets = {remove(pev);}; +void() item_cells = {remove(pev);}; +void() item_key1 = {remove(pev);}; +void() item_key2 = {remove(pev);}; +void() item_artifact_invulnerability = {remove(pev);}; +void() item_artifact_envirosuit = {remove(pev);}; +void() item_artifact_invisibility = {remove(pev);}; +void() item_artifact_super_damage = {remove(pev);}; void barrel_spawn(string netname1, string model1, string deathmessage, float damage) { @@ -98,31 +98,31 @@ void barrel_spawn(string netname1, string model1, string deathmessage, float dam precache_model (model1); precache_sound ("weapons/r_exp3.wav"); - if (!self.dmg) self.dmg = damage; - self.netname = netname1; + if (!pev->dmg) pev->dmg = damage; + pev->netname = netname1; - self.owner = self; - self.solid = SOLID_BBOX; - self.movetype = MOVETYPE_NONE; - setmodel (self, model1); - self.health = 20; - self.th_die = SUB_Null; - self.takedamage = DAMAGE_AIM; - self.think = SUB_Null; - self.nextthink = -1; - self.flags = 0; + pev->owner = pev; + pev->solid = SOLID_BBOX; + pev->movetype = MOVETYPE_NONE; + setmodel (pev, model1); + pev->health = 20; + pev->th_die = SUB_Null; + pev->takedamage = DAMAGE_AIM; + pev->think = SUB_Null; + pev->nextthink = -1; + pev->flags = 0; - self.origin_z = self.origin_z + 2; - oldz = self.origin_z; + pev->origin_z = pev->origin_z + 2; + oldz = pev->origin_z; droptofloor(); - if (oldz - self.origin_z > 250) + if (oldz - pev->origin_z > 250) { dprint ("explosive box fell out of level at "); - dprint (vtos(self.origin)); + dprint (vtos(pev->origin)); dprint ("\n"); - remove(self); + remove(pev); } } diff --git a/vprogs/ents/ambient.c b/vprogs/ents/ambient.c index 080ac498..09595d9c 100644 --- a/vprogs/ents/ambient.c +++ b/vprogs/ents/ambient.c @@ -23,6 +23,6 @@ void() ambient_swamp2 = {doambient("ambience/swamp2.wav", 0.5);}; void(string soundfile, float volume) doambient = { precache_sound (soundfile); - ambientsound (self.origin, soundfile, volume, ATTN_STATIC); + ambientsound (pev->origin, soundfile, volume, ATTN_STATIC); }; diff --git a/vprogs/ents/ccam.c b/vprogs/ents/ccam.c index 9a1be864..f42cd3a2 100644 --- a/vprogs/ents/ccam.c +++ b/vprogs/ents/ccam.c @@ -8,13 +8,13 @@ void () CCam; void () CCamChasePlayer = { - makevectors (self.v_angle); - traceline ((self.origin + self.view_ofs),((((self.origin + self.view_ofs) + (v_forward * self.camview_z)) + (v_up * self.camview_x)) + (v_right * self.camview_y)),FALSE,self); - setorigin (self.trigger_field,trace_endpos); + makevectors (pev->v_angle); + traceline ((pev->origin + pev->view_ofs),((((pev->origin + pev->view_ofs) + (v_forward * pev->camview_z)) + (v_up * pev->camview_x)) + (v_right * pev->camview_y)),FALSE,pev); + setorigin (pev->trigger_field,trace_endpos); MsgBegin( 5 ); - WriteEntity (self.trigger_field); - MsgEnd( MSG_ONE, '0 0 0', self ); - self.weaponmodel = ""; + WriteEntity (pev->trigger_field); + MsgEnd( MSG_ONE, '0 0 0', pev ); + pev->weaponmodel = ""; }; void () CCam = @@ -22,25 +22,24 @@ void () CCam = local entity camera; local entity spot; - if (self.aflag == FALSE) + if (pev->aflag == FALSE) { - self.aflag = TRUE; + pev->aflag = TRUE; camera = spawn (); spot = spawn (); - self.trigger_field = camera; + pev->trigger_field = camera; camera.classname = "camera"; camera.movetype = MOVETYPE_FLY; camera.solid = SOLID_NOT; setmodel (camera,"progs/eyes.mdl"); setsize (camera,'0 0 0','0 0 0'); - makevectors (self.v_angle); - traceline ((self.origin + self.view_ofs),(((self.origin + self.view_ofs) - + (v_forward * -64.000))),FALSE,self); - self.camview = '0 0 -64'; // added + makevectors (pev->v_angle); + traceline ((pev->origin + pev->view_ofs),(((pev->origin + pev->view_ofs) + + (v_forward * -64.000))),FALSE,pev); + pev->camview = '0 0 -64'; // added setorigin (camera,trace_endpos); - camera.angles = self.angles; - self.weaponmodel = ""; - msg_entity = self; + camera.angles = pev->angles; + pev->weaponmodel = ""; MsgBegin( 5 ); WriteEntity (camera); @@ -48,22 +47,21 @@ void () CCam = WriteAngle (camera.angles_x); WriteAngle (camera.angles_y); WriteAngle (camera.angles_z); - MsgEnd( MSG_ONE, '0 0 0', self ); - sprint (self,"Chase Cam On\n"); + MsgEnd( MSG_ONE, '0 0 0', pev ); + sprint (pev,"Chase Cam On\n"); } else { - self.aflag = FALSE; - msg_entity = self; + pev->aflag = FALSE; MsgBegin( 5 ); - WriteEntity (self); + WriteEntity (pev); WriteByte (10); WriteAngle (camera.angles_x); WriteAngle (camera.angles_y); WriteAngle (camera.angles_z); - MsgEnd( MSG_ONE, '0 0 0', self ); - remove (self.trigger_field); - sprint (self,"Chase Cam Off\n"); + MsgEnd( MSG_ONE, '0 0 0', pev ); + remove (pev->trigger_field); + sprint (pev,"Chase Cam Off\n"); //W_SetCurrentAmmo (); } }; \ No newline at end of file diff --git a/vprogs/ents/funcs/func_button.c b/vprogs/ents/funcs/func_button.c index 265562c2..02f348be 100644 --- a/vprogs/ents/funcs/func_button.c +++ b/vprogs/ents/funcs/func_button.c @@ -8,6 +8,6 @@ Points func_button to the unified func_mover(); code. void() func_button = { func_mover(); - self.classname = "button"; + pev->classname = "button"; }; diff --git a/vprogs/ents/funcs/func_door.c b/vprogs/ents/funcs/func_door.c index c5652790..39225366 100644 --- a/vprogs/ents/funcs/func_door.c +++ b/vprogs/ents/funcs/func_door.c @@ -8,6 +8,6 @@ Points func_door to the unified func_mover(); code. void() func_door = { func_mover(); - self.classname = "door"; + pev->classname = "door"; bprint("func_door_spawn\n"); }; \ No newline at end of file diff --git a/vprogs/ents/funcs/func_mover.c b/vprogs/ents/funcs/func_mover.c index 7dffd37e..5d47027f 100644 --- a/vprogs/ents/funcs/func_mover.c +++ b/vprogs/ents/funcs/func_mover.c @@ -64,20 +64,20 @@ float MOVER_TOGGLE = 32; void() func_mover_stop_general = { - self.velocity = '0 0 0'; //Stop me! - self.touched = FALSE; //Touch me! - sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); //make a sound! - setorigin(self, self.dest); //set my origin exactly to dest. + pev->velocity = '0 0 0'; //Stop me! + pev->touched = FALSE; //Touch me! + sound (pev, CHAN_VOICE, pev->noise1, 1, ATTN_NORM); //make a sound! + setorigin(pev, pev->dest); //set my origin exactly to dest. }; void() func_mover_stop = { func_mover_stop_general(); - if(self.wait >= 0) //Return upon wait over! + if(pev->wait >= 0) //Return upon wait over! { - self.think = func_mover_think; - self.nextthink = self.ltime + self.wait; + pev->think = func_mover_think; + pev->nextthink = time + pev->wait; } }; @@ -88,7 +88,7 @@ void() func_mover_stop_dead = void() func_mover_blocked = { - T_Damage (other, self, self, self.dmg); //Do my damage; + T_Damage (other, pev, pev, pev->dmg); //Do my damage; func_mover_think(); //Return; }; @@ -99,7 +99,7 @@ void(vector destination, float movespeed, void() dest_func) func_mover_move = local float pathlength, traveltime; //Calculate movement vector - path = destination - self.origin; + path = destination - pev->origin; //Calculate length of movement vector; pathlength = vlen(path); @@ -108,20 +108,20 @@ void(vector destination, float movespeed, void() dest_func) func_mover_move = traveltime = (pathlength) / (movespeed); // scale the destdelta vector by the time spent traveling to get velocity - self.velocity = path * (1/traveltime); + pev->velocity = path * (1/traveltime); - if(traveltime < 0.1 || self.origin == destination) + if(traveltime < 0.1 || pev->origin == destination) { - self.think = dest_func; - self.nextthink = self.ltime + 0.1; - self.dest = destination; + pev->think = dest_func; + pev->nextthink = time + 0.1; + pev->dest = destination; return; } - self.think = dest_func; - self.nextthink = self.ltime + traveltime; + pev->think = dest_func; + pev->nextthink = time + traveltime; - self.dest = destination; + pev->dest = destination; }; void() func_mover_think = @@ -129,26 +129,26 @@ void() func_mover_think = local vector a; local void() b; - if(self.state == STATE_OPEN) //Am i open? + if(pev->state == STATE_OPEN) //Am i open? { - self.state = STATE_CLOSED; //Now im closing! - a = self.pos1; //My first position! + pev->state = STATE_CLOSED; //Now im closing! + a = pev->pos1; //My first position! b = func_mover_stop_dead; //Stopping func to use! } - else if (self.state == STATE_CLOSED) + else if (pev->state == STATE_CLOSED) { - self.state = STATE_OPEN; - a = self.pos2; + pev->state = STATE_OPEN; + a = pev->pos2; - if(self.spawnflags & MOVER_TOGGLE) //Am i toggable? + if(pev->spawnflags & MOVER_TOGGLE) //Am i toggable? b = func_mover_stop_dead; //if yes.. stop me dead. else b = func_mover_stop; //if no.. return me; } - func_mover_move(a, self.speed, b); //Loaded move function; + func_mover_move(a, pev->speed, b); //Loaded move function; - sound (self, CHAN_VOICE, self.noise2, 1, ATTN_NORM); + sound (pev, CHAN_VOICE, pev->noise2, 1, ATTN_NORM); }; void() func_mover_fire = @@ -165,76 +165,76 @@ void() func_mover_touch = if(other == world) //Are you the world? return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.triggerer = other; + pev->triggerer = other; - self.touched = TRUE; //stop touching me! - self.think = func_mover_fire; //set me next think - self.nextthink = self.ltime + self.delay; //set it so it happens in 0.1 secs from now. + pev->touched = TRUE; //stop touching me! + pev->think = func_mover_fire; //set me next think + pev->nextthink = time + pev->delay; //set it so it happens in 0.1 secs from now. } }; void() func_mover_use = { - if(self.message) - centerprint(self.triggerer, self.message); + if(pev->message) + centerprint(pev->triggerer, pev->message); - self.touched = TRUE; //Fake touch! + pev->touched = TRUE; //Fake touch! - self.think = func_mover_fire; //set me next think! - self.nextthink = self.ltime + self.delay; //in delay + pev->think = func_mover_fire; //set me next think! + pev->nextthink = time + pev->delay; //in delay }; void() func_mover_die = { - self.health = self.max_health; //reset health on death; + pev->health = pev->max_health; //reset health on death; - self.takedamage = DAMAGE_YES; //These two are set to no and null in killed function; - self.touch = func_mover_touch; //[Damage.QC] + pev->takedamage = DAMAGE_YES; //These two are set to no and null in killed function; + pev->touch = func_mover_touch; //[Damage.QC] }; void() func_mover = { func_setup(); //Sets up some basic func properties;[funcs.qc] - self.classname = "mover"; + pev->classname = "mover"; - if(self.health) + if(pev->health) { - self.max_health = self.health; - self.takedamage = DAMAGE_YES; + pev->max_health = pev->health; + pev->takedamage = DAMAGE_YES; } - self.blocked = func_mover_blocked; - self.use = func_mover_use; - self.touch = func_mover_touch; - self.th_die = func_mover_die; + pev->blocked = func_mover_blocked; + pev->use = func_mover_use; + pev->touch = func_mover_touch; + pev->th_die = func_mover_die; //func_mover; DEFAULTS; - if (!self.speed) - self.speed = 100; - if (!self.wait) - self.wait = 3; - if (!self.lip) - self.lip = 8; - if (!self.dmg) - self.dmg = 2; + if (!pev->speed) + pev->speed = 100; + if (!pev->wait) + pev->wait = 3; + if (!pev->lip) + pev->lip = 8; + if (!pev->dmg) + pev->dmg = 2; - if(!self.delay) - self.delay = 0.1; //stuff with 0 delay dont move! (or work ;) ) + if(!pev->delay) + pev->delay = 0.1; //stuff with 0 delay dont move! (or work ;) ) //func_mover; positions; .pos1 == closed; .pos2 == open; - self.pos1 = self.origin; - self.pos2 = self.pos1 + self.movedir*(fabs(self.movedir*self.size) - self.lip); + pev->pos1 = pev->origin; + pev->pos2 = pev->pos1 + pev->movedir*(fabs(pev->movedir*pev->size) - pev->lip); - if(self.spawnflags & MOVER_START_OPEN) + if(pev->spawnflags & MOVER_START_OPEN) { - self.state = STATE_OPEN; - setorigin(self, self.pos2); + pev->state = STATE_OPEN; + setorigin(pev, pev->pos2); } else - self.state = STATE_CLOSED; + pev->state = STATE_CLOSED; }; diff --git a/vprogs/ents/funcs/func_path_corner.c b/vprogs/ents/funcs/func_path_corner.c index 98a3ff5b..47fce00e 100644 --- a/vprogs/ents/funcs/func_path_corner.c +++ b/vprogs/ents/funcs/func_path_corner.c @@ -8,9 +8,9 @@ Currently only trains use this to tell their next stop position; void() func_path_corner = { - if (!self.targetname) + if (!pev->targetname) objerror ("monster_movetarget: no targetname"); - self.solid = SOLID_TRIGGER; - setsize (self, '-8 -8 -8', '8 8 8'); + pev->solid = SOLID_TRIGGER; + setsize (pev, '-8 -8 -8', '8 8 8'); }; \ No newline at end of file diff --git a/vprogs/ents/funcs/func_train.c b/vprogs/ents/funcs/func_train.c index 6edd9fce..521fdf21 100644 --- a/vprogs/ents/funcs/func_train.c +++ b/vprogs/ents/funcs/func_train.c @@ -21,15 +21,15 @@ If the train has the 'wait' field set on its spawn it waits the alloted time the void() func_train_wait = { - if (self.wait) + if (pev->wait) { - self.nextthink = self.ltime + self.wait; - //sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + pev->nextthink = time + pev->wait; + //sound (pev, CHAN_VOICE, pev->noise, 1, ATTN_NORM); } else - self.nextthink = self.ltime + 0.1; + pev->nextthink = time + 0.1; - self.think = func_train_next; + pev->think = func_train_next; }; /* @@ -44,21 +44,21 @@ void() func_train_next = { local entity targ; - targ = find (world, targetname, self.target); + targ = find (world, targetname, pev->target); - self.target = targ.target; + pev->target = targ.target; - if (!self.target) + if (!pev->target) objerror ("train_next: no next target"); if (targ.wait) - self.wait = targ.wait; + pev->wait = targ.wait; else - self.wait = 0; + pev->wait = 0; - //sound (self, CHAN_VOICE, self.noise1, 1, ATTN_NORM); + //sound (pev, CHAN_VOICE, pev->noise1, 1, ATTN_NORM); - func_mover_move (targ.origin - self.mins, self.speed, func_train_wait); + func_mover_move (targ.origin - pev->mins, pev->speed, func_train_wait); }; /* @@ -72,16 +72,16 @@ void() func_train_find = { local entity targ; - targ = find (world, targetname, self.target); + targ = find (world, targetname, pev->target); - self.target = targ.target; + pev->target = targ.target; - setorigin (self, targ.origin - self.mins); + setorigin (pev, targ.origin - pev->mins); - if (!self.targetname) // not triggered, so start immediately + if (!pev->targetname) // not triggered, so start immediately { - self.nextthink = self.ltime + 0.1; - self.think = func_train_next; + pev->nextthink = time + 0.1; + pev->think = func_train_next; } }; @@ -95,11 +95,11 @@ If targeted the train starts moving then cannot be used/targetted again; void() func_train_use = { - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.touched = TRUE; - self.nextthink = self.ltime + 0.1; - self.think = func_train_next; + pev->touched = TRUE; + pev->nextthink = time + 0.1; + pev->think = func_train_next; } }; @@ -114,19 +114,19 @@ void() func_train = { func_setup(); - setsize (self, self.mins , self.maxs); + setsize (pev, pev->mins , pev->maxs); - self.classname = "train"; + pev->classname = "train"; //func_train defaults; - if (!self.speed) - self.speed = 100; - if (!self.target) + if (!pev->speed) + pev->speed = 100; + if (!pev->target) objerror ("func_train without a target"); - if (!self.dmg) - self.dmg = 2; + if (!pev->dmg) + pev->dmg = 2; - self.nextthink = self.ltime + 0.1; - self.think = func_train_find; + pev->nextthink = time + 0.1; + pev->think = func_train_find; }; diff --git a/vprogs/ents/funcs/funcs.c b/vprogs/ents/funcs/funcs.c index 64bdc228..38fdfd9d 100644 --- a/vprogs/ents/funcs/funcs.c +++ b/vprogs/ents/funcs/funcs.c @@ -20,7 +20,7 @@ FUNC_SETUP(); Description; This function is used by ALL our map func_'s. It sets up the func_'s basic and most common properties; -With the only exception being 'self.movetype = MOVETYPE_PUSH;' which usually gets set to something else +With the only exception being 'pev->movetype = MOVETYPE_PUSH;' which usually gets set to something else in the func_'s spawning function after this has been called. It's included because out of the func_'s we have so far more require this field to be set to that than any other. */ @@ -28,12 +28,12 @@ void() func_setup = { SetMovedir (); - self.solid = SOLID_BSP; - self.movetype = MOVETYPE_PUSH; + pev->solid = SOLID_BSP; + pev->movetype = MOVETYPE_PUSH; - setorigin (self, self.origin); - setmodel (self, self.model); - setsize (self, self.mins , self.maxs); + setorigin (pev, pev->origin); + setmodel (pev, pev->model); + setsize (pev, pev->mins , pev->maxs); }; /* @@ -48,7 +48,7 @@ void() func_illusionary = { func_setup(); - self.solid = SOLID_TRIGGER; + pev->solid = SOLID_TRIGGER; }; /* @@ -64,10 +64,10 @@ Jon Eriksson - For the idea and base code! void() func_place_model = { - precache_model (self.model); + precache_model (pev->model); func_setup(); - self.movetype = MOVETYPE_NONE; + pev->movetype = MOVETYPE_NONE; }; diff --git a/vprogs/ents/internal.c b/vprogs/ents/internal.c index eed5ef15..0e80c739 100644 --- a/vprogs/ents/internal.c +++ b/vprogs/ents/internal.c @@ -11,16 +11,14 @@ .string name; // .entity triggerer; -void(string modelname) Precache_Set = // Precache model, and set myself to it +void(string modelname) Precache_Set = // Precache model, and set mypev to it { precache_model(modelname); - setmodel(self, modelname); + setmodel(pev, modelname); }; void(entity ent) SetViewPoint = // Alter the Viewpoint Entity { - msg_entity = self; // This message is to myself. - MsgBegin(SVC_SETVIEW); // Network Protocol: Set Viewpoint Entity WriteEntity(ent); // Write entity to clients. MsgEnd( MSG_ONE, '0 0 0', ent ); @@ -32,44 +30,44 @@ just constant angles. */ void() SetMovedir = { - if (self.angles == '0 -1 0') - self.movedir = '0 0 1'; - else if (self.angles == '0 -2 0') - self.movedir = '0 0 -1'; + if (pev->angles == '0 -1 0') + pev->movedir = '0 0 1'; + else if (pev->angles == '0 -2 0') + pev->movedir = '0 0 -1'; else { - makevectors (self.angles); - self.movedir = v_forward; + makevectors (pev->angles); + pev->movedir = v_forward; } - self.angles = '0 0 0'; + pev->angles = '0 0 0'; }; void() IEM_usetarget = { - local entity t, oldself, oldother; + local entity t, oldpev, oldother; - if(self.target) + if(pev->target) { - t = find(world, targetname, self.target); + t = find(world, targetname, pev->target); while(t) { - if(self.triggerer) - t.triggerer = self.triggerer; + if(pev->triggerer) + t.triggerer = pev->triggerer; - oldself = self; + oldpev = pev; oldother = other; - self = t; + pev = t; if(t.use) t.use(); - self = oldself; + pev = oldpev; other = oldother; - t = find(t, targetname, self.target); + t = find(t, targetname, pev->target); } } @@ -80,5 +78,5 @@ void(float effect_type, vector effect_org) IEM_effects = MsgBegin(SVC_TEMPENTITY); WriteByte(effect_type); WriteCoord(effect_org); - MsgEnd( MSG_BROADCAST, effect_org, self ); + MsgEnd( MSG_BROADCAST, effect_org, pev ); }; \ No newline at end of file diff --git a/vprogs/ents/items/items.c b/vprogs/ents/items/items.c index 79daeed0..bf7a3f88 100644 --- a/vprogs/ents/items/items.c +++ b/vprogs/ents/items/items.c @@ -23,20 +23,19 @@ It sets up all the required and most basic item parimeters. void() item_setup = { - if(!self.think) //Items should start after other solids.... + if(!pev->think) //Items should start after other solids.... { - self.think = item_setup; - self.nextthink = time + 0.2; + pev->think = item_setup; + pev->nextthink = time + 0.2; return; } - self.oldmodel = self.model; // so it can be restored on respawn + pev->oldmodel = pev->model; // so it can be restored on respawn - self.flags = FL_ITEM; // make extra wide - self.solid = SOLID_TRIGGER; //Im a TRIGGER! - self.movetype = MOVETYPE_TOSS; //Toss me baby!... erm.. - self.velocity = '0 0 0'; //Stop me moving! - self.origin_z = self.origin_z + 6; //Raise me a bit off the floor + pev->solid = SOLID_TRIGGER; //Im a TRIGGER! + pev->movetype = MOVETYPE_TOSS; //Toss me baby!... erm.. + pev->velocity = '0 0 0'; //Stop me moving! + pev->origin_z = pev->origin_z + 6; //Raise me a bit off the floor }; /* @@ -63,9 +62,9 @@ Makes the item pickupable again. void() item_respawn = { - setorigin(self, self.origin); - self.solid = SOLID_TRIGGER; - self.model = self.oldmodel; + setorigin(pev, pev->origin); + pev->solid = SOLID_TRIGGER; + pev->model = pev->oldmodel; }; /* @@ -80,18 +79,18 @@ Stops the item getting picked up for a while, nextthink at bottom of code. void() item_pickup = { - self.solid = SOLID_NOT; - self.model = string_null; + pev->solid = SOLID_NOT; + pev->model = string_null; IEM_usetarget(); - if(self.spawnflags & ITEM_PICKUP_ONCE) + if(pev->spawnflags & ITEM_PICKUP_ONCE) return; - self.think = item_respawn; + pev->think = item_respawn; if(deathmatch) - self.nextthink = time + 20; //This ideally would be a CVAR + pev->nextthink = time + 20; //This ideally would be a CVAR }; diff --git a/vprogs/ents/lights.c b/vprogs/ents/lights.c index ab0c84dd..3d5eadaa 100644 --- a/vprogs/ents/lights.c +++ b/vprogs/ents/lights.c @@ -32,46 +32,46 @@ void() light_fluorospark = // Light with buzz ambient void() light_globe = // Light with visible globe { Precache_Set("progs/s_light.spr"); // Set model - makestatic(self); // Static entity. Never changes. + makestatic(pev); // Static entity. Never changes. }; void() light_torch_small_walltorch = // Light with visible wall torch { Precache_Set("progs/flame.mdl"); // Set model - makestatic(self); // Static entity. Never changes. + makestatic(pev); // Static entity. Never changes. doambient("ambience/fire1.wav", 0.5); // Spawn fire ambient sound }; void() light_flame_small_yellow = // Light with small flame & fire sound { Precache_Set("progs/flame2.mdl"); // Set model - makestatic(self); // Static entity. Never changes. + makestatic(pev); // Static entity. Never changes. doambient("ambience/fire1.wav", 0.5); // Spawn fire ambient sound }; void() light_flame_large_yellow = // Light with larger flame & fire sound { Precache_Set("progs/flame2.mdl"); // Set model - self.frame = 1; // Switch to second frame (large) - makestatic(self); // Static entity. Never changes. + pev->frame = 1; // Switch to second frame (large) + makestatic(pev); // Static entity. Never changes. doambient("ambience/fire1.wav", 0.5); // Spawn fire ambient sound }; void() light_flame_small_white = // Light with small flame & fire sound { Precache_Set("progs/flame2.mdl"); // Set model - makestatic(self); // Static entity. Never changes. + makestatic(pev); // Static entity. Never changes. doambient("ambience/fire1.wav", 0.5); // Spawn fire ambient sound }; void() Light_setup = // Set light on or off, as per spawnflags { - if (self.style < 32) {return;} // Dont switch other styles. + if (pev->style < 32) {return;} // Dont switch other styles. - if (self.spawnflags & START_OFF) - lightstyle(self.style, "a"); // If light starts off, set it off. + if (pev->spawnflags & START_OFF) + lightstyle(pev->style, "a"); // If light starts off, set it off. else - lightstyle(self.style, "m"); // If light starts ON, turn in ON. Simple :) + lightstyle(pev->style, "m"); // If light starts ON, turn in ON. Simple :) }; void() LightStyles_setup = diff --git a/vprogs/ents/triggers/trigger_changelevel.c b/vprogs/ents/triggers/trigger_changelevel.c index 4240232d..7f0d514c 100644 --- a/vprogs/ents/triggers/trigger_changelevel.c +++ b/vprogs/ents/triggers/trigger_changelevel.c @@ -7,17 +7,17 @@ */ void() trigger_changelevel_touch = { - changelevel(self.map); + changelevel(pev->map); }; void() trigger_changelevel = { - if (!self.map) + if (!pev->map) objerror ("chagnelevel trigger doesn't have map"); trigger_setup(); - self.touch = trigger_changelevel_touch; + pev->touch = trigger_changelevel_touch; }; diff --git a/vprogs/ents/triggers/trigger_counter.c b/vprogs/ents/triggers/trigger_counter.c index a75cc3fc..28bc2316 100644 --- a/vprogs/ents/triggers/trigger_counter.c +++ b/vprogs/ents/triggers/trigger_counter.c @@ -11,48 +11,48 @@ Counts the number of times it gets fired.. then fires its targets.. void() trigger_counter_use = { - self.count = self.count - 1; //subtract my count by one; 'ive been triggered' + pev->count = pev->count - 1; //subtract my count by one; 'ive been triggered' - if(self.count < 0) + if(pev->count < 0) return; - if(self.count != 0) + if(pev->count != 0) { - if (self.count >= 4) - centerprint (self.triggerer, self.targ1); - else if (self.count == 3) - centerprint (self.triggerer, self.targ2); - else if (self.count == 2) - centerprint (self.triggerer, self.targ3); + if (pev->count >= 4) + centerprint (pev->triggerer, pev->targ1); + else if (pev->count == 3) + centerprint (pev->triggerer, pev->targ2); + else if (pev->count == 2) + centerprint (pev->triggerer, pev->targ3); else - centerprint (self.triggerer, self.targ4); + centerprint (pev->triggerer, pev->targ4); } IEM_usetarget(); - if(!(self.spawnflags & TRIGGER_ONCE)) //if im a trigger_once, remove me; - remove(self); + if(!(pev->spawnflags & TRIGGER_ONCE)) //if im a trigger_once, remove me; + remove(pev); else - self.count = self.wait1; //restore old count + pev->count = pev->wait1; //restore old count }; void() trigger_counter = { - if(!self.count) //If my count not set in map default it to 1; - self.count = 1; + if(!pev->count) //If my count not set in map default it to 1; + pev->count = 1; - self.wait1 = self.count; //store count levels; + pev->wait1 = pev->count; //store count levels; - self.use = trigger_counter_use; //my use function; + pev->use = trigger_counter_use; //my use function; - if(!self.targ1) //if a custom message is not set use the standard ones instead; - self.targ1 = "There are more to go..."; - if(!self.targ2) - self.targ2 = "Only 3 more to go..."; - if(!self.targ3) - self.targ3 = "Only 2 more to go..."; - if(!self.targ4) - self.targ4 = "Only 1 more to go..."; + if(!pev->targ1) //if a custom message is not set use the standard ones instead; + pev->targ1 = "There are more to go..."; + if(!pev->targ2) + pev->targ2 = "Only 3 more to go..."; + if(!pev->targ3) + pev->targ3 = "Only 2 more to go..."; + if(!pev->targ4) + pev->targ4 = "Only 1 more to go..."; - self.classname = "t_counter"; + pev->classname = "t_counter"; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_generic.c b/vprogs/ents/triggers/trigger_generic.c index 8b8ff864..f020abe8 100644 --- a/vprogs/ents/triggers/trigger_generic.c +++ b/vprogs/ents/triggers/trigger_generic.c @@ -6,16 +6,16 @@ void() trigger_generic_think = { - self.touched = FALSE; + pev->touched = FALSE; - if(self.message) - centerprint(self.triggerer , self.message); + if(pev->message) + centerprint(pev->triggerer , pev->message); - if(self.target) + if(pev->target) IEM_usetarget(); - if(self.spawnflags & TRIGGER_ONCE) - remove(self); + if(pev->spawnflags & TRIGGER_ONCE) + remove(pev); }; void() trigger_generic_touch = @@ -23,39 +23,39 @@ void() trigger_generic_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.triggerer = other; + pev->triggerer = other; - self.touched = TRUE; - self.think = trigger_generic_think; - self.nextthink = time + self.delay; + pev->touched = TRUE; + pev->think = trigger_generic_think; + pev->nextthink = time + pev->delay; } }; void() trigger_generic_use = { - if(self.touched == TRUE) + if(pev->touched == TRUE) return; - self.touched = TRUE; + pev->touched = TRUE; - if(self.message) - centerprint(self.triggerer, self.message); + if(pev->message) + centerprint(pev->triggerer, pev->message); - self.think = trigger_generic_think; - self.nextthink = time + self.delay; + pev->think = trigger_generic_think; + pev->nextthink = time + pev->delay; }; void() trigger_generic = { trigger_setup(); - self.touch = trigger_generic_touch; - self.use = trigger_generic_use; + pev->touch = trigger_generic_touch; + pev->use = trigger_generic_use; - self.classname = "generic"; + pev->classname = "generic"; - if(!self.delay) - self.delay = 0.1; + if(!pev->delay) + pev->delay = 0.1; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_hurt.c b/vprogs/ents/triggers/trigger_hurt.c index 73fb55ad..925495b6 100644 --- a/vprogs/ents/triggers/trigger_hurt.c +++ b/vprogs/ents/triggers/trigger_hurt.c @@ -3,28 +3,28 @@ |TRIGGER_HURT| +============+==============+ |Description; | -|Hurt player for self.dmg. | +|Hurt player for pev->dmg. | +===========================+ */ void() trigger_hurt_think = { - self.solid = SOLID_TRIGGER; - self.touched = FALSE; + pev->solid = SOLID_TRIGGER; + pev->touched = FALSE; }; void() trigger_hurt_touch = { if(other.takedamage) { - if(self.touched == FALSE) + if(pev->touched == FALSE) { - T_Damage (other, self, self, self.dmg); + T_Damage (other, pev, pev, pev->dmg); - self.touched = TRUE; - self.solid = SOLID_NOT; - self.think = trigger_hurt_think; - self.nextthink = time + 1; + pev->touched = TRUE; + pev->solid = SOLID_NOT; + pev->think = trigger_hurt_think; + pev->nextthink = time + 1; } } }; @@ -33,10 +33,10 @@ void() trigger_hurt = { trigger_setup(); - self.touch = trigger_hurt_touch; + pev->touch = trigger_hurt_touch; - if(!self.dmg) - self.dmg = 5; + if(!pev->dmg) + pev->dmg = 5; - self.classname = "t_hurt"; + pev->classname = "t_hurt"; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_message.c b/vprogs/ents/triggers/trigger_message.c index 85257d9d..2e710dc6 100644 --- a/vprogs/ents/triggers/trigger_message.c +++ b/vprogs/ents/triggers/trigger_message.c @@ -10,26 +10,26 @@ void() trigger_message_think = { - self.touched = FALSE; + pev->touched = FALSE; - if(self.message) - centerprint(self.triggerer, self.message); - if(self.message1) + if(pev->message) + centerprint(pev->triggerer, pev->message); + if(pev->message1) { - sprint(self.triggerer, self.message1); - sprint(self.triggerer, "\n"); + sprint(pev->triggerer, pev->message1); + sprint(pev->triggerer, "\n"); } - if(self.message2) + if(pev->message2) { - dprint(self.message2); + dprint(pev->message2); dprint("\n"); } - if(self.target) + if(pev->target) IEM_usetarget(); - if(self.spawnflags & TRIGGER_ONCE) - remove(self); + if(pev->spawnflags & TRIGGER_ONCE) + remove(pev); }; void() trigger_message_touch = @@ -37,50 +37,50 @@ void() trigger_message_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.touched = TRUE; + pev->touched = TRUE; - self.triggerer = other; + pev->triggerer = other; - self.think = trigger_message_think; - self.nextthink = time + self.delay; + pev->think = trigger_message_think; + pev->nextthink = time + pev->delay; } }; void() trigger_message_use = { - if(self.touched == TRUE) + if(pev->touched == TRUE) return; - self.touched = TRUE; + pev->touched = TRUE; - if(self.message) - centerprint(self.triggerer, self.message); - if(self.message1) + if(pev->message) + centerprint(pev->triggerer, pev->message); + if(pev->message1) { - sprint(self.triggerer, self.message1); - sprint(self.triggerer, "\n"); + sprint(pev->triggerer, pev->message1); + sprint(pev->triggerer, "\n"); } - if(self.message2) + if(pev->message2) { - dprint(self.message2); + dprint(pev->message2); dprint("\n"); } - self.think = trigger_message_think; - self.nextthink = time + self.delay; + pev->think = trigger_message_think; + pev->nextthink = time + pev->delay; }; void() trigger_message = { trigger_setup(); - if(!self.delay) - self.delay = 1; + if(!pev->delay) + pev->delay = 1; - self.touch = trigger_message_touch; - self.use = trigger_message_use; + pev->touch = trigger_message_touch; + pev->use = trigger_message_use; - self.classname = "t_message"; + pev->classname = "t_message"; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_once.c b/vprogs/ents/triggers/trigger_once.c index 66c0468d..17f0bdb9 100644 --- a/vprogs/ents/triggers/trigger_once.c +++ b/vprogs/ents/triggers/trigger_once.c @@ -6,10 +6,10 @@ void() trigger_once_think = { - if(self.target) + if(pev->target) IEM_usetarget(); - remove(self); + remove(pev); }; void() trigger_once_touch = @@ -17,45 +17,45 @@ void() trigger_once_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - if(self.message) - centerprint(other, self.message); + if(pev->message) + centerprint(other, pev->message); - self.think = trigger_once_think; - self.nextthink = time + self.delay; + pev->think = trigger_once_think; + pev->nextthink = time + pev->delay; } }; void() trigger_once_use = { - if(self.touched == TRUE) + if(pev->touched == TRUE) return; - self.touched = TRUE; + pev->touched = TRUE; - if(self.message) + if(pev->message) { - bprint(self.message); + bprint(pev->message); dprint("\n"); } - self.think = trigger_once_think; - self.nextthink = time + self.delay; + pev->think = trigger_once_think; + pev->nextthink = time + pev->delay; } void() trigger_once = { trigger_setup(); - self.touch = trigger_once_touch; - self.use = trigger_once_use; + pev->touch = trigger_once_touch; + pev->use = trigger_once_use; - self.classname = "once"; + pev->classname = "once"; - if(!self.delay) - self.delay = 0.1; + if(!pev->delay) + pev->delay = 0.1; - if(!self.target) - remove(self); + if(!pev->target) + remove(pev); }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_push.c b/vprogs/ents/triggers/trigger_push.c index a80be789..3b5f310c 100644 --- a/vprogs/ents/triggers/trigger_push.c +++ b/vprogs/ents/triggers/trigger_push.c @@ -3,31 +3,31 @@ |TRIGGER_PUSH| +============+==============+ |Description; | -|Push player for self speed.| +|Push player for pev speed.| +===========================+ */ void() trigger_push_think = { - self.touched = FALSE; + pev->touched = FALSE; }; void() trigger_push_touch = { if(other.flags & FL_CLIENT) - other.velocity = self.speed * self.movedir * 10; + other.velocity = pev->speed * pev->movedir * 10; - if (self.spawnflags & TRIGGER_ONCE) - remove(self); + if (pev->spawnflags & TRIGGER_ONCE) + remove(pev); - if(self.dmg) + if(pev->dmg) { - if(self.touched == FALSE) + if(pev->touched == FALSE) { - T_Damage (other, self, self, self.dmg); - self.touched = TRUE; + T_Damage (other, pev, pev, pev->dmg); + pev->touched = TRUE; - self.think = trigger_push_think; - self.nextthink = time + 0.1; + pev->think = trigger_push_think; + pev->nextthink = time + 0.1; } } }; @@ -36,12 +36,12 @@ void() trigger_push = { trigger_setup(); - self.touch = trigger_push_touch; + pev->touch = trigger_push_touch; - if (!self.speed) - self.speed = 1000; + if (!pev->speed) + pev->speed = 1000; - self.classname = "t_push"; + pev->classname = "t_push"; }; diff --git a/vprogs/ents/triggers/trigger_secret.c b/vprogs/ents/triggers/trigger_secret.c index c75053c6..893b84a2 100644 --- a/vprogs/ents/triggers/trigger_secret.c +++ b/vprogs/ents/triggers/trigger_secret.c @@ -8,7 +8,7 @@ void() trigger_secret_think = { total_secrets++; - if(self.target) + if(pev->target) IEM_usetarget(); }; @@ -18,20 +18,20 @@ void() trigger_secret_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - if (!self.message) - self.message = "You found a secret area!"; + if (!pev->message) + pev->message = "You found a secret area!"; else - centerprint(other, self.message); + centerprint(other, pev->message); - if(self.delay) + if(pev->delay) { - self.think = trigger_secret_think; - self.nextthink = time + self.delay; + pev->think = trigger_secret_think; + pev->nextthink = time + pev->delay; } - self.touched = TRUE; + pev->touched = TRUE; } }; @@ -39,8 +39,8 @@ void() trigger_secret = { trigger_setup(); - self.touch = trigger_secret_touch; + pev->touch = trigger_secret_touch; - if(!self.delay) - self.delay = 0.1; + if(!pev->delay) + pev->delay = 0.1; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_sequence.c b/vprogs/ents/triggers/trigger_sequence.c index ca65cfed..e90e1c2f 100644 --- a/vprogs/ents/triggers/trigger_sequence.c +++ b/vprogs/ents/triggers/trigger_sequence.c @@ -36,16 +36,16 @@ void() trigger_sequence_think; void(string seq_a, float seq_b) trigger_sequence_think1 = { - self.target = seq_a; - self.delay = seq_b; + pev->target = seq_a; + pev->delay = seq_b; - if(self.target) + if(pev->target) IEM_usetarget(); else - self.touched = FALSE; + pev->touched = FALSE; - self.think = trigger_sequence_think; - self.nextthink = time + self.delay; + pev->think = trigger_sequence_think; + pev->nextthink = time + pev->delay; }; void() trigger_sequence_think = @@ -53,99 +53,99 @@ void() trigger_sequence_think = local string a; local float b; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.oldtarg1 = self.targ1; - self.oldtarg2 = self.targ2; - self.oldtarg3 = self.targ3; - self.oldtarg4 = self.targ4; - self.oldtarg5 = self.targ5; - self.oldtarg6 = self.targ6; - self.oldtarg7 = self.targ7; - self.oldtarg8 = self.targ8; - self.delay = self.olddelay; + pev->oldtarg1 = pev->targ1; + pev->oldtarg2 = pev->targ2; + pev->oldtarg3 = pev->targ3; + pev->oldtarg4 = pev->targ4; + pev->oldtarg5 = pev->targ5; + pev->oldtarg6 = pev->targ6; + pev->oldtarg7 = pev->targ7; + pev->oldtarg8 = pev->targ8; + pev->delay = pev->olddelay; return; } - if(self.targ1) + if(pev->targ1) { - a = self.targ1; - b = self.wait1; + a = pev->targ1; + b = pev->wait1; - self.targ1 = self.oldtarg1; + pev->targ1 = pev->oldtarg1; trigger_sequence_think1(a,b); return; } - else if(self.targ2) + else if(pev->targ2) { - a = self.targ2; - b = self.wait2; + a = pev->targ2; + b = pev->wait2; - self.targ2 = self.oldtarg2; + pev->targ2 = pev->oldtarg2; trigger_sequence_think1(a,b); return; } - else if(self.targ3) + else if(pev->targ3) { - a = self.targ3; - b = self.wait3; + a = pev->targ3; + b = pev->wait3; - self.targ3 = self.oldtarg3; + pev->targ3 = pev->oldtarg3; trigger_sequence_think1(a,b); return; } - else if(self.targ4) + else if(pev->targ4) { - a = self.targ4; - b = self.wait4; + a = pev->targ4; + b = pev->wait4; - self.targ4 = self.oldtarg4; + pev->targ4 = pev->oldtarg4; trigger_sequence_think1(a,b); return; } - else if(self.targ5) + else if(pev->targ5) { - a = self.targ5; - b = self.wait5; + a = pev->targ5; + b = pev->wait5; - self.targ5 = self.oldtarg5; + pev->targ5 = pev->oldtarg5; trigger_sequence_think1(a,b); return; } - else if(self.targ6) + else if(pev->targ6) { - a = self.targ6; - b = self.wait6; + a = pev->targ6; + b = pev->wait6; - self.targ6 = self.oldtarg6; + pev->targ6 = pev->oldtarg6; trigger_sequence_think1(a,b); return; } - else if(self.targ7) + else if(pev->targ7) { - a = self.targ7; - b = self.wait7; + a = pev->targ7; + b = pev->wait7; - self.targ7 = self.oldtarg7; + pev->targ7 = pev->oldtarg7; trigger_sequence_think1(a,b); return; } - else if(self.targ8) + else if(pev->targ8) { - a = self.targ8; - b = self.wait8; + a = pev->targ8; + b = pev->wait8; - self.targ8 = self.oldtarg8; + pev->targ8 = pev->oldtarg8; trigger_sequence_think1(a,b); return; } - self.touched = FALSE; + pev->touched = FALSE; - if(self.spawnflags & TRIGGER_ONCE) - remove(self); + if(pev->spawnflags & TRIGGER_ONCE) + remove(pev); }; void() trigger_sequence_touch = @@ -153,74 +153,74 @@ void() trigger_sequence_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.spawnflags & TRIGGER_INTTERUPTABLE) + if(pev->spawnflags & TRIGGER_INTTERUPTABLE) { - if(self.touched == TRUE) + if(pev->touched == TRUE) { - self.touched = FALSE; + pev->touched = FALSE; - self.delay = self.olddelay; + pev->delay = pev->olddelay; - self.triggerer = other; + pev->triggerer = other; - self.think = trigger_sequence_think; - self.nextthink = time + self.delay; + pev->think = trigger_sequence_think; + pev->nextthink = time + pev->delay; return; } } - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.touched = TRUE; + pev->touched = TRUE; - if(self.message) - centerprint(other, self.message); + if(pev->message) + centerprint(other, pev->message); - self.triggerer = other; + pev->triggerer = other; - self.think = trigger_sequence_think; - self.nextthink = time + self.delay; + pev->think = trigger_sequence_think; + pev->nextthink = time + pev->delay; } }; void() trigger_sequence_use = { - if(self.spawnflags & TRIGGER_INTTERUPTABLE) + if(pev->spawnflags & TRIGGER_INTTERUPTABLE) { - if(self.touched == TRUE) + if(pev->touched == TRUE) { - self.touched = FALSE; + pev->touched = FALSE; - self.delay = self.olddelay; + pev->delay = pev->olddelay; - self.think = trigger_sequence_think; - self.nextthink = time + self.delay; + pev->think = trigger_sequence_think; + pev->nextthink = time + pev->delay; return; } } - if(self.touched == TRUE) + if(pev->touched == TRUE) return; - self.touched = TRUE; + pev->touched = TRUE; - self.think = trigger_sequence_think; - self.nextthink = time + self.delay; + pev->think = trigger_sequence_think; + pev->nextthink = time + pev->delay; }; void() trigger_sequence = { trigger_setup(); - if(!self.delay) - self.delay = 0.1; + if(!pev->delay) + pev->delay = 0.1; - self.delay = self.olddelay; + pev->delay = pev->olddelay; - self.classname = "t_sequence"; + pev->classname = "t_sequence"; - self.touch = trigger_sequence_touch; - self.use = trigger_sequence_use; + pev->touch = trigger_sequence_touch; + pev->use = trigger_sequence_use; }; \ No newline at end of file diff --git a/vprogs/ents/triggers/trigger_setskill.c b/vprogs/ents/triggers/trigger_setskill.c index b95e6b67..7fda6dc9 100644 --- a/vprogs/ents/triggers/trigger_setskill.c +++ b/vprogs/ents/triggers/trigger_setskill.c @@ -3,7 +3,7 @@ |TRIGGER_SETSKILL| +================+====================+ |Description; | -|Set skill to value of self.message. | +|Set skill to value of pev->message. | +=====================================+ */ @@ -12,9 +12,9 @@ void() trigger_setskill_touch = if (other.classname != "player") return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - cvar_set ("skill", self.message); + cvar_set ("skill", pev->message); } }; @@ -22,8 +22,8 @@ void() trigger_setskill = { trigger_setup(); - self.classname = "setskill"; + pev->classname = "setskill"; - self.touch = trigger_setskill_touch; + pev->touch = trigger_setskill_touch; }; diff --git a/vprogs/ents/triggers/trigger_setviewpoint.c b/vprogs/ents/triggers/trigger_setviewpoint.c index ef9f6a9b..c798af84 100644 --- a/vprogs/ents/triggers/trigger_setviewpoint.c +++ b/vprogs/ents/triggers/trigger_setviewpoint.c @@ -7,64 +7,62 @@ void() info_viewpoint_destination = { trigger_setup(); - setorigin(self, self.origin); + setorigin(pev, pev->origin); - setmodel (self, "progs/eyes.mdl"); - self.modelindex = 0; + setmodel (pev, "progs/eyes.mdl"); + pev->modelindex = 0; }; void() trigger_change_viewpoint_touch; void() trigger_change_viewpoint_think1 = { - self.touched = FALSE; - self.touch = trigger_change_viewpoint_touch; + pev->touched = FALSE; + pev->touch = trigger_change_viewpoint_touch; }; void() trigger_change_viewpoint_think = { - local entity e, oldself, oldtrig; + local entity e, oldpev, oldtrig; - if(self.touched == TRUE) + if(pev->touched == TRUE) { - e = find(world, targetname, self.target); - //e = self.triggerer.triggerer.triggerer; - self.triggerer.triggerer = self.triggerer; + e = find(world, targetname, pev->target); + //e = pev->triggerer.triggerer.triggerer; + pev->triggerer.triggerer = pev->triggerer; - msg_entity = self.triggerer; MsgBegin(SVC_SETVIEW); // Network Protocol: Set Viewpoint Entity WriteEntity( e); // Write entity to clients. - MsgEnd(MSG_ONE, '0 0 0', self ); + MsgEnd(MSG_ONE, '0 0 0', pev ); - //self.angles = e.mangles; - //self.fixangle = 1; + //pev->angles = e.mangles; + //pev->fixangle = 1; - //self.triggerer.movetype = MOVETYPE_NONE; + //pev->triggerer.movetype = MOVETYPE_NONE; - self.think = trigger_change_viewpoint_think; - self.nextthink = time + self.wait1; + pev->think = trigger_change_viewpoint_think; + pev->nextthink = time + pev->wait1; - self.touched = FALSE; + pev->touched = FALSE; bprint("working\n"); } - else if(self.touched == FALSE) + else if(pev->touched == FALSE) { - //self.triggerer = self.triggerer.triggerer; + //pev->triggerer = pev->triggerer.triggerer; - msg_entity = self.triggerer; MsgBegin(SVC_SETVIEW); // Network Protocol: Set Viewpoint Entity - WriteEntity(self.triggerer.triggerer); - MsgEnd(MSG_ONE, '0 0 0', self ); + WriteEntity(pev->triggerer.triggerer); + MsgEnd(MSG_ONE, '0 0 0', pev ); - self.triggerer.movetype = MOVETYPE_WALK; + pev->triggerer.movetype = MOVETYPE_WALK; - self.triggerer = world; + pev->triggerer = world; - self.touched = TRUE; + pev->touched = TRUE; - self.think = trigger_change_viewpoint_think1; - self.nextthink = time + 2; + pev->think = trigger_change_viewpoint_think1; + pev->nextthink = time + 2; } }; @@ -73,14 +71,14 @@ void() trigger_change_viewpoint_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.touched = TRUE; - self.touch = SUB_Null; - self.triggerer = other; + pev->touched = TRUE; + pev->touch = SUB_Null; + pev->triggerer = other; - self.think = trigger_change_viewpoint_think; - self.nextthink = time + self.delay; + pev->think = trigger_change_viewpoint_think; + pev->nextthink = time + pev->delay; bprint("touched"); } @@ -88,28 +86,28 @@ void() trigger_change_viewpoint_touch = void() trigger_change_viewpoint_use = { - if(self.touched == TRUE) + if(pev->touched == TRUE) return; - self.think = trigger_change_viewpoint_think; - self.nextthink = time + self.delay; + pev->think = trigger_change_viewpoint_think; + pev->nextthink = time + pev->delay; }; void() trigger_change_viewpoint = { trigger_setup(); - if(!self.delay) - self.delay = 1; - if(!self.wait) - self.wait = 1; + if(!pev->delay) + pev->delay = 1; + if(!pev->wait) + pev->wait = 1; - self.touch = trigger_change_viewpoint_touch; - self.use = trigger_change_viewpoint_use ; + pev->touch = trigger_change_viewpoint_touch; + pev->use = trigger_change_viewpoint_use ; - if(!self.target) + if(!pev->target) { objerror("trigger_change_viewpoint: NO TARGET"); - self.solid = SOLID_NOT; + pev->solid = SOLID_NOT; } }; diff --git a/vprogs/ents/triggers/trigger_teleport.c b/vprogs/ents/triggers/trigger_teleport.c index 450c3252..a151fa39 100644 --- a/vprogs/ents/triggers/trigger_teleport.c +++ b/vprogs/ents/triggers/trigger_teleport.c @@ -11,15 +11,15 @@ void(entity ono, entity duo)setangles = void() spawn_tdeath_touch = { - if (other == self.owner) + if (other == pev->owner) return; // frag anyone who teleports in on top of an invincible player if (other.classname == "player") { - if (self.owner.classname != "player") + if (pev->owner.classname != "player") { - T_Damage (self.owner, self, self, 50000); + T_Damage (pev->owner, pev, pev, 50000); return; } @@ -27,7 +27,7 @@ void() spawn_tdeath_touch = if (other.health) { - T_Damage (other, self, self, 50000); + T_Damage (other, pev, pev, 50000); } }; @@ -56,24 +56,24 @@ void() trigger_teleport_think = { local entity t; - t = find (world, targetname, self.target); + t = find (world, targetname, pev->target); if (!t) objerror ("couldn't find target"); - IEM_effects(TE_TELEPORT, self.triggerer.origin); + IEM_effects(TE_TELEPORT, pev->triggerer.origin); - spawn_tdeath(t.origin, self.triggerer); + spawn_tdeath(t.origin, pev->triggerer); - setorigin(self.triggerer, t.origin); - setangles(self.triggerer, t); + setorigin(pev->triggerer, t.origin); + setangles(pev->triggerer, t); IEM_effects(TE_TELEPORT, t.origin); - if(self.message) - centerprint(self.triggerer, self.message); + if(pev->message) + centerprint(pev->triggerer, pev->message); - self.touched = FALSE; + pev->touched = FALSE; }; void() trigger_teleport_touch = @@ -81,25 +81,25 @@ void() trigger_teleport_touch = if(!(other.flags & FL_CLIENT)) return; - if(self.touched == FALSE) + if(pev->touched == FALSE) { - self.touched = TRUE; + pev->touched = TRUE; - self.triggerer = other; + pev->triggerer = other; - self.think = trigger_teleport_think; - self.nextthink = time + self.delay; + pev->think = trigger_teleport_think; + pev->nextthink = time + pev->delay; } }; void() trigger_teleport_use = { - //if(self.touched == TRUE) + //if(pev->touched == TRUE) // return; - if(self.touched == TRUE) - self.touched = FALSE; - //self.think = trigger_teleport_think; - //self.nextthink = time + self.delay; + if(pev->touched == TRUE) + pev->touched = FALSE; + //pev->think = trigger_teleport_think; + //pev->nextthink = time + pev->delay; }; @@ -107,25 +107,25 @@ void() trigger_teleport = { trigger_setup(); - self.touch = trigger_teleport_touch; - self.use = trigger_teleport_use; + pev->touch = trigger_teleport_touch; + pev->use = trigger_teleport_use; - if (!self.target) + if (!pev->target) objerror ("no target"); - if(self.spawnflags & TRIGGER_START_OFF) - self.touched = TRUE; + if(pev->spawnflags & TRIGGER_START_OFF) + pev->touched = TRUE; - if(!self.delay) - self.delay = 0.1; + if(!pev->delay) + pev->delay = 0.1; - self.classname = "t_teleport"; + pev->classname = "t_teleport"; /* - if (!(self.spawnflags & SILENT)) + if (!(pev->spawnflags & SILENT)) { //precache_sound ("ambience/hum1.wav"); - //o = (self.mins + self.maxs)*0.5; + //o = (pev->mins + pev->maxs)*0.5; //ambientsound (o, "ambience/hum1.wav",0.5 , ATTN_STATIC); } */ @@ -134,11 +134,11 @@ void() trigger_teleport = void() info_teleport_destination = { // this does nothing, just serves as a target spot - self.mangle = self.angles; - self.angles = '0 0 0'; - self.model = ""; - self.origin = self.origin + '0 0 27'; - if (!self.targetname) + pev->mangle = pev->angles; + pev->angles = '0 0 0'; + pev->model = ""; + pev->origin = pev->origin + '0 0 27'; + if (!pev->targetname) objerror ("no targetname"); }; diff --git a/vprogs/ents/triggers/triggers.c b/vprogs/ents/triggers/triggers.c index 29f46d2b..eabeb7b1 100644 --- a/vprogs/ents/triggers/triggers.c +++ b/vprogs/ents/triggers/triggers.c @@ -17,20 +17,20 @@ void() trigger_setup = { // trigger angles are used for one-way touches. An angle of 0 is assumed // to mean no restrictions, so use a yaw of 360 instead. - //if (self.angles != '0 0 0') + //if (pev->angles != '0 0 0') // SetMovedir (); //not at the moment they are not.... - self.solid = SOLID_TRIGGER; - self.movetype = MOVETYPE_NONE; + pev->solid = SOLID_TRIGGER; + pev->movetype = MOVETYPE_NONE; - setmodel (self, self.model); - setorigin(self, self.origin); + setmodel (pev, pev->model); + setorigin(pev, pev->origin); - if(self.spawnflags & TRIGGER_NO_MODEL) + if(pev->spawnflags & TRIGGER_NO_MODEL) { - self.modelindex = 0; - self.model = ""; + pev->modelindex = 0; + pev->model = ""; } }; diff --git a/vprogs/impulses.c b/vprogs/impulses.c index efbfb67d..eae8fac9 100644 --- a/vprogs/impulses.c +++ b/vprogs/impulses.c @@ -10,26 +10,26 @@ void() CheckImpulses = { - if (self.impulse == 15) + if (pev->impulse == 15) CCam (); - if(self.impulse == 10) + if(pev->impulse == 10) { local string a; - a = ftos(self.items); - sprint(self, a); - sprint(self, "Items Printed\n"); + a = ftos(pev->items); + sprint(pev, a); + sprint(pev, "Items Printed\n"); } - if(self.impulse == 11) + if(pev->impulse == 11) { - self.items = self.items + 8; - sprint(self, "Items added to\{136}\n"); + pev->items = pev->items + 8; + sprint(pev, "Items added to\{136}\n"); } - if(self.impulse == 150) + if(pev->impulse == 150) { - IEM_effects(TE_TELEPORT, self.origin); + IEM_effects(TE_TELEPORT, pev->origin); } - self.impulse = 0; // Clear impulse list. + pev->impulse = 0; // Clear impulse list. }; \ No newline at end of file diff --git a/vprogs/main.c b/vprogs/main.c index 3a260aac..ae6f8cfb 100644 --- a/vprogs/main.c +++ b/vprogs/main.c @@ -29,8 +29,8 @@ This function is called to set up new player info. void() SetNewParms = //Sets up start game parms { - parm1 = 10; - parm2 = 100; + pev->items = 10; + pev->health = 100; }; /* @@ -46,14 +46,11 @@ loading upon next level. void() SetChangeParms = //called on changelevel; command { - if (self.health <= 0) + if (pev->health <= 0) { SetNewParms(); return; } - - parm1 = self.items; - parm2 = self.health; }; /* @@ -74,9 +71,6 @@ void() GetLevelParms = { if (world.model == "maps/start.bsp") SetNewParms (); // take away all stuff on starting new episode - - self.items = parm1; - self.health = parm2; }; diff --git a/vprogs/player.c b/vprogs/player.c index 392ec7e4..7523ce77 100644 --- a/vprogs/player.c +++ b/vprogs/player.c @@ -61,13 +61,13 @@ $frame axattd1 axattd2 axattd3 axattd4 axattd5 axattd6 void () SetClientFrame = { // note: call whenever weapon frames are called! - if (self.anim_time > time) + if (pev->anim_time > time) return; //don't call every frame, if it is the animations will play too fast - self.anim_time = time + 0.1; + pev->anim_time = time + 0.1; local float anim_change, run; - if (self.velocity_x || self.velocity_y) + if (pev->velocity_x || pev->velocity_y) run = TRUE; else run = FALSE; @@ -75,40 +75,40 @@ void () SetClientFrame = anim_change = FALSE; // check for stop/go and animation transitions - if (run != self.anim_run && self.anim_priority == ANIM_BASIC) + if (run != pev->anim_run && pev->anim_priority == ANIM_BASIC) anim_change = TRUE; if (anim_change != TRUE) { - if (self.frame < self.anim_end) + if (pev->frame < pev->anim_end) { // continue an animation - self.frame = self.frame + 1; + pev->frame = pev->frame + 1; return; } - if (self.anim_priority == ANIM_DEATH) + if (pev->anim_priority == ANIM_DEATH) { - if (self.deadflag == DEAD_DYING) + if (pev->deadflag == DEAD_DYING) { - self.nextthink = -1; - self.deadflag = DEAD_DEAD; + pev->nextthink = -1; + pev->deadflag = DEAD_DEAD; } return; // stay there } } // return to either a running or standing frame - self.anim_priority = ANIM_BASIC; - self.anim_run = run; + pev->anim_priority = ANIM_BASIC; + pev->anim_run = run; - if (self.velocity_x || self.velocity_y) + if (pev->velocity_x || pev->velocity_y) { // running - self.frame = $rockrun1; - self.anim_end = $rockrun6; + pev->frame = $rockrun1; + pev->anim_end = $rockrun6; } else { // standing - self.frame = $stand1; - self.anim_end = $stand5; + pev->frame = $stand1; + pev->anim_end = $stand5; } }; @@ -119,61 +119,61 @@ void () SetClientFrame = */ void() PainSound = { - if (self.health < 0) + if (pev->health < 0) return; - self.noise = ""; + pev->noise = ""; - if (self.watertype == CONTENT_WATER && self.waterlevel == 3) + if (pev->watertype == CONTENT_WATER && pev->waterlevel == 3) { // water pain sounds if (random() <= 0.5) - self.noise = "player/drown1.wav"; + pev->noise = "player/drown1.wav"; else - self.noise = "player/drown2.wav"; + pev->noise = "player/drown2.wav"; } - else if (self.watertype == CONTENT_SLIME || self.watertype == CONTENT_LAVA) + else if (pev->watertype == CONTENT_SLIME || pev->watertype == CONTENT_LAVA) { // slime/lava pain sounds if (random() <= 0.5) - self.noise = "player/lburn1.wav"; + pev->noise = "player/lburn1.wav"; else - self.noise = "player/lburn2.wav"; + pev->noise = "player/lburn2.wav"; } - if (self.noise) + if (pev->noise) { - sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + sound (pev, CHAN_VOICE, pev->noise, 1, ATTN_NORM); return; } //don't make multiple pain sounds right after each other - if (self.pain_finished > time) + if (pev->pain_finished > time) return; - self.pain_finished = time + 0.5; + pev->pain_finished = time + 0.5; local float rs; rs = rint((random() * 5) + 1); // rs = 1-6 if (rs == 1) - self.noise = "player/pain1.wav"; + pev->noise = "player/pain1.wav"; else if (rs == 2) - self.noise = "player/pain2.wav"; + pev->noise = "player/pain2.wav"; else if (rs == 3) - self.noise = "player/pain3.wav"; + pev->noise = "player/pain3.wav"; else if (rs == 4) - self.noise = "player/pain4.wav"; + pev->noise = "player/pain4.wav"; else if (rs == 5) - self.noise = "player/pain5.wav"; + pev->noise = "player/pain5.wav"; else - self.noise = "player/pain6.wav"; + pev->noise = "player/pain6.wav"; - sound (self, CHAN_VOICE, self.noise, 1, ATTN_NORM); + sound (pev, CHAN_VOICE, pev->noise, 1, ATTN_NORM); }; void () PlayerPain = { - if (self.anim_priority < ANIM_PAIN) // call only if not attacking and not already in pain + if (pev->anim_priority < ANIM_PAIN) // call only if not attacking and not already in pain { - self.anim_priority = ANIM_PAIN; - self.frame = $pain1; - self.anim_end = $pain6; + pev->anim_priority = ANIM_PAIN; + pev->frame = $pain1; + pev->anim_end = $pain6; } PainSound (); }; @@ -188,61 +188,61 @@ void() DeathSound = local float rs; rs = rint ((random() * 4) + 1); // rs = 1-5 - if (self.waterlevel == 3) // water death sound - self.noise = "player/h2odeath.wav"; + if (pev->waterlevel == 3) // water death sound + pev->noise = "player/h2odeath.wav"; else if (rs == 1) - self.noise = "player/death1.wav"; + pev->noise = "player/death1.wav"; else if (rs == 2) - self.noise = "player/death2.wav"; + pev->noise = "player/death2.wav"; else if (rs == 3) - self.noise = "player/death3.wav"; + pev->noise = "player/death3.wav"; else if (rs == 4) - self.noise = "player/death4.wav"; + pev->noise = "player/death4.wav"; else if (rs == 5) - self.noise = "player/death5.wav"; + pev->noise = "player/death5.wav"; - sound (self, CHAN_VOICE, self.noise, 1, ATTN_NONE); + sound (pev, CHAN_VOICE, pev->noise, 1, ATTN_NONE); }; void () PlayerDie = { - self.view_ofs = '0 0 -8'; - self.angles_x = self.angles_z = 0; - self.deadflag = DEAD_DYING; - self.solid = SOLID_NOT; - self.movetype = MOVETYPE_TOSS; - self.flags = self.flags - (self.flags & FL_ONGROUND); - if (self.velocity_z < 10) - self.velocity_z = self.velocity_z + random()*300; + pev->view_ofs = '0 0 -8'; + pev->angles_x = pev->angles_z = 0; + pev->deadflag = DEAD_DYING; + pev->solid = SOLID_NOT; + pev->movetype = MOVETYPE_TOSS; + pev->aiflags = pev->aiflags - (pev->aiflags & AI_ONGROUND); + if (pev->velocity_z < 10) + pev->velocity_z = pev->velocity_z + random()*300; local float rand; rand = rint ((random() * 4) + 1); // rand = 1-5 - self.anim_priority = ANIM_DEATH; + pev->anim_priority = ANIM_DEATH; if (rand == 1) { - self.frame = $deatha1; - self.anim_end = $deatha11; + pev->frame = $deatha1; + pev->anim_end = $deatha11; } else if (rand == 2) { - self.frame = $deathb1; - self.anim_end = $deathb9; + pev->frame = $deathb1; + pev->anim_end = $deathb9; } else if (rand == 3) { - self.frame = $deathc1; - self.anim_end = $deathc15; + pev->frame = $deathc1; + pev->anim_end = $deathc15; } else if (rand == 4) { - self.frame = $deathd1; - self.anim_end = $deathd9; + pev->frame = $deathd1; + pev->anim_end = $deathd9; } else { - self.frame = $deathe1; - self.anim_end = $deathe9; + pev->frame = $deathe1; + pev->anim_end = $deathe9; } DeathSound(); }; diff --git a/vprogs/progdefs.h b/vprogs/progdefs.h index 180e98bc..5d8560de 100644 --- a/vprogs/progdefs.h +++ b/vprogs/progdefs.h @@ -12,13 +12,14 @@ typedef struct globalvars_s int ofs_parm5[3]; int ofs_parm6[3]; int ofs_parm7[3]; - int self; + int pev; int other; int world; float time; float frametime; - float force_retouch; string_t mapname; + string_t startspot; + vec3_t spotoffset; float deathmatch; float coop; float teamplay; @@ -27,35 +28,19 @@ typedef struct globalvars_s float total_monsters; float found_secrets; float killed_monsters; - float parm1; - float parm2; - float parm3; - float parm4; - float parm5; - float parm6; - float parm7; - float parm8; - float parm9; - float parm10; - float parm11; - float parm12; - float parm13; - float parm14; - float parm15; - float parm16; vec3_t v_forward; - vec3_t v_up; vec3_t v_right; + vec3_t v_up; float trace_allsolid; float trace_startsolid; float trace_fraction; vec3_t trace_endpos; vec3_t trace_plane_normal; float trace_plane_dist; + float trace_hitgroup; + float trace_contents; int trace_ent; - float trace_inopen; - float trace_inwater; - int msg_entity; + float trace_flags; func_t main; func_t StartFrame; func_t EndFrame; @@ -71,48 +56,61 @@ typedef struct globalvars_s typedef struct entvars_s { + string_t classname; + string_t globalname; float modelindex; - vec3_t absmin; - vec3_t absmax; - float ltime; + vec3_t origin; + vec3_t angles; + vec3_t velocity; + vec3_t avelocity; + vec3_t post_origin; + vec3_t post_angles; + vec3_t post_velocity; + vec3_t post_avelocity; + vec3_t origin_offset; + vec3_t angles_offset; + float bouncetype; float movetype; float solid; - vec3_t origin; - vec3_t oldorigin; - vec3_t velocity; - vec3_t angles; - vec3_t avelocity; - vec3_t punchangle; - string_t classname; - string_t model; - float frame; - float skin; - float body; - float effects; - float sequence; - float renderfx; + vec3_t absmin; + vec3_t absmax; vec3_t mins; vec3_t maxs; vec3_t size; - func_t touch; + int chain; + string_t model; + float frame; + float sequence; + float renderfx; + float effects; + float skin; + float body; + string_t weaponmodel; + float weaponframe; func_t use; + func_t touch; func_t think; func_t blocked; - float nextthink; + func_t activate; + func_t walk; + func_t jump; + func_t duck; + float flags; + float aiflags; + float spawnflags; int groundentity; + float nextthink; + float takedamage; float health; float frags; float weapon; - string_t weaponmodel; - float weaponframe; - float currentammo; - float ammo_shells; - float ammo_nails; - float ammo_rockets; - float ammo_cells; float items; - float takedamage; - int chain; + string_t target; + string_t parent; + string_t targetname; + int aiment; + int goalentity; + vec3_t punchangle; float deadflag; vec3_t view_ofs; float button0; @@ -124,7 +122,6 @@ typedef struct entvars_s float idealpitch; string_t netname; int enemy; - float flags; float colormap; float team; float max_health; @@ -135,11 +132,6 @@ typedef struct entvars_s float watertype; float ideal_yaw; float yaw_speed; - int aiment; - int goalentity; - float spawnflags; - string_t target; - string_t targetname; float dmg_take; float dmg_save; int dmg_inflictor; @@ -151,6 +143,15 @@ typedef struct entvars_s string_t noise1; string_t noise2; string_t noise3; + float jumpup; + float jumpdn; + int movetarget; + float mass; + float density; + float gravity; + float dmg; + float dmgtime; + float speed; } entvars_t; //with this the crc isn't needed for fields. @@ -160,128 +161,159 @@ struct fieldvars_s int type; char *name; } fieldvars[] = { - {0, 2, "modelindex"}, - {1, 3, "absmin"}, - {1, 2, "absmin_x"}, - {2, 2, "absmin_y"}, - {3, 2, "absmin_z"}, - {4, 3, "absmax"}, - {4, 2, "absmax_x"}, - {5, 2, "absmax_y"}, - {6, 2, "absmax_z"}, - {7, 2, "ltime"}, - {8, 2, "movetype"}, - {9, 2, "solid"}, - {10, 3, "origin"}, - {10, 2, "origin_x"}, - {11, 2, "origin_y"}, - {12, 2, "origin_z"}, - {13, 3, "oldorigin"}, - {13, 2, "oldorigin_x"}, - {14, 2, "oldorigin_y"}, - {15, 2, "oldorigin_z"}, - {16, 3, "velocity"}, - {16, 2, "velocity_x"}, - {17, 2, "velocity_y"}, - {18, 2, "velocity_z"}, - {19, 3, "angles"}, - {19, 2, "angles_x"}, - {20, 2, "angles_y"}, - {21, 2, "angles_z"}, - {22, 3, "avelocity"}, - {22, 2, "avelocity_x"}, - {23, 2, "avelocity_y"}, - {24, 2, "avelocity_z"}, - {25, 3, "punchangle"}, - {25, 2, "punchangle_x"}, - {26, 2, "punchangle_y"}, - {27, 2, "punchangle_z"}, - {28, 1, "classname"}, - {29, 1, "model"}, - {30, 2, "frame"}, - {31, 2, "skin"}, - {32, 2, "body"}, - {33, 2, "effects"}, - {34, 2, "sequence"}, - {35, 2, "renderfx"}, - {36, 3, "mins"}, - {36, 2, "mins_x"}, - {37, 2, "mins_y"}, - {38, 2, "mins_z"}, - {39, 3, "maxs"}, - {39, 2, "maxs_x"}, - {40, 2, "maxs_y"}, - {41, 2, "maxs_z"}, - {42, 3, "size"}, - {42, 2, "size_x"}, - {43, 2, "size_y"}, - {44, 2, "size_z"}, - {45, 6, "touch"}, - {46, 6, "use"}, - {47, 6, "think"}, - {48, 6, "blocked"}, - {49, 2, "nextthink"}, - {50, 4, "groundentity"}, - {51, 2, "health"}, - {52, 2, "frags"}, - {53, 2, "weapon"}, - {54, 1, "weaponmodel"}, - {55, 2, "weaponframe"}, - {56, 2, "currentammo"}, - {57, 2, "ammo_shells"}, - {58, 2, "ammo_nails"}, - {59, 2, "ammo_rockets"}, - {60, 2, "ammo_cells"}, - {61, 2, "items"}, - {62, 2, "takedamage"}, - {63, 4, "chain"}, - {64, 2, "deadflag"}, - {65, 3, "view_ofs"}, - {65, 2, "view_ofs_x"}, - {66, 2, "view_ofs_y"}, - {67, 2, "view_ofs_z"}, - {68, 2, "button0"}, - {69, 2, "button1"}, - {70, 2, "button2"}, - {71, 2, "impulse"}, - {72, 2, "fixangle"}, - {73, 3, "v_angle"}, - {73, 2, "v_angle_x"}, - {74, 2, "v_angle_y"}, - {75, 2, "v_angle_z"}, - {76, 2, "idealpitch"}, - {77, 1, "netname"}, - {78, 4, "enemy"}, - {79, 2, "flags"}, - {80, 2, "colormap"}, - {81, 2, "team"}, - {82, 2, "max_health"}, - {83, 2, "teleport_time"}, - {84, 2, "armortype"}, - {85, 2, "armorvalue"}, - {86, 2, "waterlevel"}, - {87, 2, "watertype"}, - {88, 2, "ideal_yaw"}, - {89, 2, "yaw_speed"}, - {90, 4, "aiment"}, - {91, 4, "goalentity"}, - {92, 2, "spawnflags"}, - {93, 1, "target"}, - {94, 1, "targetname"}, - {95, 2, "dmg_take"}, - {96, 2, "dmg_save"}, - {97, 4, "dmg_inflictor"}, - {98, 4, "owner"}, - {99, 3, "movedir"}, - {99, 2, "movedir_x"}, - {100, 2, "movedir_y"}, - {101, 2, "movedir_z"}, - {102, 1, "message"}, - {103, 2, "sounds"}, - {104, 1, "noise"}, - {105, 1, "noise1"}, - {106, 1, "noise2"}, - {107, 1, "noise3"} + {0, 1, "classname"}, + {1, 1, "globalname"}, + {2, 2, "modelindex"}, + {3, 3, "origin"}, + {3, 2, "origin_x"}, + {4, 2, "origin_y"}, + {5, 2, "origin_z"}, + {6, 3, "angles"}, + {6, 2, "angles_x"}, + {7, 2, "angles_y"}, + {8, 2, "angles_z"}, + {9, 3, "velocity"}, + {9, 2, "velocity_x"}, + {10, 2, "velocity_y"}, + {11, 2, "velocity_z"}, + {12, 3, "avelocity"}, + {12, 2, "avelocity_x"}, + {13, 2, "avelocity_y"}, + {14, 2, "avelocity_z"}, + {15, 3, "post_origin"}, + {15, 2, "post_origin_x"}, + {16, 2, "post_origin_y"}, + {17, 2, "post_origin_z"}, + {18, 3, "post_angles"}, + {18, 2, "post_angles_x"}, + {19, 2, "post_angles_y"}, + {20, 2, "post_angles_z"}, + {21, 3, "post_velocity"}, + {21, 2, "post_velocity_x"}, + {22, 2, "post_velocity_y"}, + {23, 2, "post_velocity_z"}, + {24, 3, "post_avelocity"}, + {24, 2, "post_avelocity_x"}, + {25, 2, "post_avelocity_y"}, + {26, 2, "post_avelocity_z"}, + {27, 3, "origin_offset"}, + {27, 2, "origin_offset_x"}, + {28, 2, "origin_offset_y"}, + {29, 2, "origin_offset_z"}, + {30, 3, "angles_offset"}, + {30, 2, "angles_offset_x"}, + {31, 2, "angles_offset_y"}, + {32, 2, "angles_offset_z"}, + {33, 2, "bouncetype"}, + {34, 2, "movetype"}, + {35, 2, "solid"}, + {36, 3, "absmin"}, + {36, 2, "absmin_x"}, + {37, 2, "absmin_y"}, + {38, 2, "absmin_z"}, + {39, 3, "absmax"}, + {39, 2, "absmax_x"}, + {40, 2, "absmax_y"}, + {41, 2, "absmax_z"}, + {42, 3, "mins"}, + {42, 2, "mins_x"}, + {43, 2, "mins_y"}, + {44, 2, "mins_z"}, + {45, 3, "maxs"}, + {45, 2, "maxs_x"}, + {46, 2, "maxs_y"}, + {47, 2, "maxs_z"}, + {48, 3, "size"}, + {48, 2, "size_x"}, + {49, 2, "size_y"}, + {50, 2, "size_z"}, + {51, 4, "chain"}, + {52, 1, "model"}, + {53, 2, "frame"}, + {54, 2, "sequence"}, + {55, 2, "renderfx"}, + {56, 2, "effects"}, + {57, 2, "skin"}, + {58, 2, "body"}, + {59, 1, "weaponmodel"}, + {60, 2, "weaponframe"}, + {61, 6, "use"}, + {62, 6, "touch"}, + {63, 6, "think"}, + {64, 6, "blocked"}, + {65, 6, "activate"}, + {66, 6, "walk"}, + {67, 6, "jump"}, + {68, 6, "duck"}, + {69, 2, "flags"}, + {70, 2, "aiflags"}, + {71, 2, "spawnflags"}, + {72, 4, "groundentity"}, + {73, 2, "nextthink"}, + {74, 2, "takedamage"}, + {75, 2, "health"}, + {76, 2, "frags"}, + {77, 2, "weapon"}, + {78, 2, "items"}, + {79, 1, "target"}, + {80, 1, "parent"}, + {81, 1, "targetname"}, + {82, 4, "aiment"}, + {83, 4, "goalentity"}, + {84, 3, "punchangle"}, + {84, 2, "punchangle_x"}, + {85, 2, "punchangle_y"}, + {86, 2, "punchangle_z"}, + {87, 2, "deadflag"}, + {88, 3, "view_ofs"}, + {88, 2, "view_ofs_x"}, + {89, 2, "view_ofs_y"}, + {90, 2, "view_ofs_z"}, + {91, 2, "button0"}, + {92, 2, "button1"}, + {93, 2, "button2"}, + {94, 2, "impulse"}, + {95, 2, "fixangle"}, + {96, 3, "v_angle"}, + {96, 2, "v_angle_x"}, + {97, 2, "v_angle_y"}, + {98, 2, "v_angle_z"}, + {99, 2, "idealpitch"}, + {100, 1, "netname"}, + {101, 4, "enemy"}, + {102, 2, "colormap"}, + {103, 2, "team"}, + {104, 2, "max_health"}, + {105, 2, "teleport_time"}, + {106, 2, "armortype"}, + {107, 2, "armorvalue"}, + {108, 2, "waterlevel"}, + {109, 2, "watertype"}, + {110, 2, "ideal_yaw"}, + {111, 2, "yaw_speed"}, + {112, 2, "dmg_take"}, + {113, 2, "dmg_save"}, + {114, 4, "dmg_inflictor"}, + {115, 4, "owner"}, + {116, 3, "movedir"}, + {116, 2, "movedir_x"}, + {117, 2, "movedir_y"}, + {118, 2, "movedir_z"}, + {119, 1, "message"}, + {120, 2, "sounds"}, + {121, 1, "noise"}, + {122, 1, "noise1"}, + {123, 1, "noise2"}, + {124, 1, "noise3"}, + {125, 2, "jumpup"}, + {126, 2, "jumpdn"}, + {127, 4, "movetarget"}, + {128, 2, "mass"}, + {129, 2, "density"}, + {130, 2, "gravity"}, + {131, 2, "dmg"}, + {132, 2, "dmgtime"}, + {133, 2, "speed"} }; -#define PROGHEADER_CRC 21645 +#define PROGHEADER_CRC 63599 diff --git a/vprogs/run.bat b/vprogs/run.bat new file mode 100644 index 00000000..46b4a12e --- /dev/null +++ b/vprogs/run.bat @@ -0,0 +1 @@ +qcclib -log -dev 4 -progdefs -debug \ No newline at end of file