diff --git a/changelog.log b/changelog.log index 83ec4b60..8cf00ba5 100644 --- a/changelog.log +++ b/changelog.log @@ -6,10 +6,12 @@ SV_Move SV_Trace SV_ClipMoveToEntity CM_BoxTrace SV_ClipToLinks SV_ClipMoveToEntities -//================================================== -// FIXME -//================================================== -1. Пофиксить движение игрока (сл. большая скорость) +1. Перенести основные части gamed.dll в движок OK +2. Попытка полностью отказаться от gamed.dll OK +3. Перенести физику в движок OK +4. Восстановить изменения кода до 06.09.07 (кроме PRVM) + + //================================================== // то, что уже готово diff --git a/debug.bat b/debug.bat index 8f9cabfd..79712401 100644 --- a/debug.bat +++ b/debug.bat @@ -55,5 +55,5 @@ if exist progs\server.dat copy progs\server.dat D:\Xash3D\xash\server.dat echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -xash.exe +map qctest -debug +xash.exe +map qctest -log :done \ No newline at end of file diff --git a/engine/client/cl_cin.c b/engine/client/cl_cin.c index 7dd84d45..3145637d 100644 --- a/engine/client/cl_cin.c +++ b/engine/client/cl_cin.c @@ -402,17 +402,17 @@ void SCR_RunCinematic (void) if (cls.key_dest != key_game) { // pause if menu or console is up - cl.cinematictime = cls.realtime - cl.cinematicframe/14; + cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; return; } - frame = (cls.realtime - cl.cinematictime)*14.0; + frame = (cls.realtime - cl.cinematictime)*14.0/1000; if (frame <= cl.cinematicframe) return; if (frame > cl.cinematicframe+1) { Msg ("Dropped frame: %i > %i\n", frame, cl.cinematicframe+1); - cl.cinematictime = cls.realtime - cl.cinematicframe/14; + cl.cinematictime = cls.realtime - cl.cinematicframe*1000/14; } if (cin.pic) Z_Free (cin.pic); @@ -546,5 +546,5 @@ void SCR_PlayCinematic (char *arg) cl.cinematicframe = 0; cin.pic = SCR_ReadNextFrame (); - cl.cinematictime = cls.realtime; + cl.cinematictime = Sys_Milliseconds (); } diff --git a/engine/client/cl_ents.c b/engine/client/cl_ents.c index e6cee883..f0c22ed8 100644 --- a/engine/client/cl_ents.c +++ b/engine/client/cl_ents.c @@ -323,8 +323,7 @@ void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits) } if (ent->serverframe != cl.frame.serverframe - 1) - { - // wasn't in last update, so initialize some things + { // wasn't in last update, so initialize some things ent->trailcount = 1024; // for diminishing rocket / grenade trails // duplicate the current state so lerping doesn't hurt anything ent->prev = *state; @@ -657,7 +656,7 @@ void CL_ParseFrame (void) cl.frame.serverframe = MSG_ReadLong (&net_message); cl.frame.deltaframe = MSG_ReadLong (&net_message); - cl.frame.servertime = cl.frame.serverframe * 0.1; + cl.frame.servertime = cl.frame.serverframe*100; // BIG HACK to let old demos continue to work if (cls.serverProtocol != 26) @@ -700,8 +699,8 @@ void CL_ParseFrame (void) // clamp time if (cl.time > cl.frame.servertime) cl.time = cl.frame.servertime; - else if (cl.time < cl.frame.servertime - 0.1) - cl.time = cl.frame.servertime - 0.1; + else if (cl.time < cl.frame.servertime - 100) + cl.time = cl.frame.servertime - 100; // read areabits len = MSG_ReadByte (&net_message); @@ -739,8 +738,9 @@ void CL_ParseFrame (void) cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125; cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125; VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles); - if (cls.disable_servercount != cl.servercount && cl.refresh_prepped) - SCR_EndLoadingPlaque (); // get rid of loading plaque + if (cls.disable_servercount != cl.servercount + && cl.refresh_prepped) + SCR_EndLoadingPlaque (); // get rid of loading plaque } cl.sound_prepped = true; // can start mixing ambient sounds @@ -829,7 +829,7 @@ void CL_AddPacketEntities (frame_t *frame) autorotate = anglemod(cl.time/10); // brush models can auto animate their frames - autoanim = 2 * cl.time; + autoanim = 2*cl.time/1000; memset (&ent, 0, sizeof(ent)); @@ -850,7 +850,7 @@ void CL_AddPacketEntities (frame_t *frame) else if (effects & EF_ANIM_ALL) ent.frame = autoanim; else if (effects & EF_ANIM_ALLFAST) - ent.frame = cl.time * 0.1; + ent.frame = cl.time / 100; else ent.frame = s1->frame; @@ -974,7 +974,7 @@ void CL_AddPacketEntities (frame_t *frame) vec3_t forward; vec3_t start; - AngleVectorsRight(ent.angles, forward, NULL, NULL); + AngleVectors (ent.angles, forward, NULL, NULL); VectorMA (ent.origin, 64, forward, start); V_AddLight (start, 100, 1, 0, 0); } @@ -1231,7 +1231,8 @@ void CL_CalcViewValues (void) // smooth out stair climbing delta = cls.realtime - cl.predicted_step_time; - if (delta < 0.1) cl.refdef.vieworg[2] -= cl.predicted_step * (0.1 - delta) * 100; + if (delta < 100) + cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01; } else { // just use interpolated values @@ -1256,7 +1257,7 @@ void CL_CalcViewValues (void) for (i=0 ; i<3 ; i++) cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp); - AngleVectorsRight(cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up); + AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up); // interpolate field of view cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov); @@ -1288,14 +1289,15 @@ void CL_AddEntities (void) cl.time = cl.frame.servertime; cl.lerpfrac = 1.0; } - else if (cl.time < cl.frame.servertime - 0.1) + else if (cl.time < cl.frame.servertime - 100) { if (cl_showclamp->value) - Msg ("low clamp %i\n", cl.frame.servertime - 0.1 - cl.time); - cl.time = cl.frame.servertime - 0.1; + Msg ("low clamp %i\n", cl.frame.servertime-100 - cl.time); + cl.time = cl.frame.servertime - 100; cl.lerpfrac = 0; } - else cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 100; + else + cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01; if (cl_timedemo->value) cl.lerpfrac = 1.0; diff --git a/engine/client/cl_fx.c b/engine/client/cl_fx.c index e41650fa..055749ce 100644 --- a/engine/client/cl_fx.c +++ b/engine/client/cl_fx.c @@ -69,7 +69,7 @@ void CL_RunLightStyles (void) int i; clightstyle_t *ls; - ofs = cl.time * 0.1; + ofs = cl.time / 100; if (ofs == lastofs) return; lastofs = ofs; @@ -257,7 +257,7 @@ void CL_ParseMuzzleFlash (void) dl = CL_AllocDlight (i); VectorCopy (pl->current.origin, dl->origin); - AngleVectorsRight(pl->current.angles, fv, rv, NULL); + AngleVectors (pl->current.angles, fv, rv, NULL); VectorMA (dl->origin, 18, fv, dl->origin); VectorMA (dl->origin, 16, rv, dl->origin); if (silenced) @@ -398,7 +398,7 @@ void CL_ParseMuzzleFlash2 (void) flash_number = MSG_ReadByte (&net_message); // locate the origin - AngleVectorsRight(cl_entities[ent].current.angles, forward, right, NULL); + AngleVectors (cl_entities[ent].current.angles, forward, right, NULL); origin[0] = cl_entities[ent].current.origin[0] + forward[0] + right[0]; origin[1] = cl_entities[ent].current.origin[1] + forward[1] + right[1]; origin[2] = cl_entities[ent].current.origin[2] + forward[2] + right[2]; @@ -1607,7 +1607,7 @@ void CL_FlyParticles (vec3_t origin, int count) } - ltime = cl.time; + ltime = (float)cl.time / 1000.0; for (i=0 ; i -#include "client.h" - -HINSTANCE cl_library; - -void CL_InitGameProgs (void) -{ - void *cl; - - //find client.dll - cl = Sys_LoadGame("ClientAPI", cl_library, NULL); - - if(cl) Msg("client.dll found and loaded\n"); - else Msg("client.dll not loaded\n"); -} \ No newline at end of file diff --git a/engine/client/cl_input.c b/engine/client/cl_input.c index bac9ae8f..713b00df 100644 --- a/engine/client/cl_input.c +++ b/engine/client/cl_input.c @@ -23,8 +23,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. cvar_t *cl_nodelta; -uint frame_msec; -uint old_sys_frame_time; +extern unsigned sys_frame_time; +unsigned frame_msec; +unsigned old_sys_frame_time; /* =============================================================================== @@ -93,7 +94,7 @@ void KeyDown (kbutton_t *b) c = Cmd_Argv(2); b->downtime = atoi(c); if (!b->downtime) - b->downtime = host.cl_timer - 100; + b->downtime = sys_frame_time - 100; b->state |= 1 + 2; // down + impulse down } @@ -193,8 +194,8 @@ float CL_KeyState (kbutton_t *key) if (key->state) { // still down - msec += host.cl_timer - key->downtime; - key->downtime = host.cl_timer; + msec += sys_frame_time - key->downtime; + key->downtime = sys_frame_time; } #if 0 @@ -205,8 +206,10 @@ float CL_KeyState (kbutton_t *key) #endif val = (float)msec / frame_msec; - if (val < 0) val = 0; - if (val > 1) val = 1; + if (val < 0) + val = 0; + if (val > 1) + val = 1; return val; } @@ -295,7 +298,9 @@ void CL_BaseMove (usercmd_t *cmd) cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back); } - // adjust for speed key / running +// +// adjust for speed key / running +// if ( (in_speed.state & 1) ^ (int)(cl_run->value) ) { cmd->forwardmove *= 2; @@ -333,27 +338,34 @@ void CL_FinishMove (usercmd_t *cmd) int ms; int i; - // figure button bits - if ( in_attack.state & 3 ) cmd->buttons |= BUTTON_ATTACK; +// +// figure button bits +// + if ( in_attack.state & 3 ) + cmd->buttons |= BUTTON_ATTACK; in_attack.state &= ~2; - if (in_use.state & 3) cmd->buttons |= BUTTON_USE; + if (in_use.state & 3) + cmd->buttons |= BUTTON_USE; in_use.state &= ~2; - if (anykeydown && cls.key_dest == key_game) cmd->buttons |= BUTTON_ANY; + if (anykeydown && cls.key_dest == key_game) + cmd->buttons |= BUTTON_ANY; // send milliseconds of time to apply the move ms = cls.frametime * 1000; - if (ms > 250) ms = 100; // time was unreasonable + if (ms > 250) + ms = 100; // time was unreasonable cmd->msec = ms; CL_ClampPitch (); - for (i = 0; i < 3; i++) cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); + for (i=0 ; i<3 ; i++) + cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); cmd->impulse = in_impulse; in_impulse = 0; - // send the ambient light level at the player's current position +// send the ambient light level at the player's current position cmd->lightlevel = (byte)cl_lightlevel->value; } @@ -366,8 +378,11 @@ usercmd_t CL_CreateCmd (void) { usercmd_t cmd; - frame_msec = host.cl_timer - old_sys_frame_time; - frame_msec = bound(1, frame_msec, 200); + frame_msec = sys_frame_time - old_sys_frame_time; + if (frame_msec < 1) + frame_msec = 1; + if (frame_msec > 200) + frame_msec = 200; // get basic movement from keyboard CL_BaseMove (&cmd); @@ -377,9 +392,9 @@ usercmd_t CL_CreateCmd (void) CL_FinishMove (&cmd); - old_sys_frame_time = host.cl_timer; + old_sys_frame_time = sys_frame_time; - //cmd.impulse = cls.framecount; +//cmd.impulse = cls.framecount; return cmd; } @@ -468,7 +483,7 @@ void CL_SendCmd (void) if ( cls.state == ca_connected) { - if (cls.netchan.message.cursize || host.realtime - cls.netchan.last_sent > 1.0f ) + if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 ) Netchan_Transmit (&cls.netchan, 0, buf.data); return; } @@ -483,7 +498,7 @@ void CL_SendCmd (void) } if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop - && cls.realtime - cl.cinematictime > 1.0f) + && cls.realtime - cl.cinematictime > 1000) { // skip the rest of the cinematic SCR_FinishCinematic (); } diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 2a04596d..c289914f 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -364,7 +364,7 @@ CL_Pause_f void CL_Pause_f (void) { // never pause in multiplayer - if (host.maxclients > 1 || !Com_ServerState ()) + if (Cvar_VariableValue ("maxclients") > 1 || !Com_ServerState ()) { Cvar_SetValue ("paused", 0); return; @@ -462,7 +462,7 @@ void CL_CheckForResend (void) if (cls.state != ca_connecting) return; - if (cls.realtime - cls.connect_time < 3.0f) + if (cls.realtime - cls.connect_time < 3000) return; if (!NET_StringToAdr (cls.servername, &adr)) @@ -616,6 +616,16 @@ void CL_Disconnect (void) if (cls.state == ca_disconnected) return; + if (cl_timedemo && cl_timedemo->value) + { + int time; + + time = Sys_Milliseconds () - cl.timedemo_start; + if (time > 0) + Msg ("%i frames, %3.1f seconds: %3.1f fps\n", cl.timedemo_frames, + time/1000.0, cl.timedemo_frames*1000.0 / time); + } + VectorClear (cl.refdef.blend); re->CinematicSetPalette(NULL); @@ -717,7 +727,8 @@ void CL_Changing_f (void) { //ZOID //if we are downloading, we don't change! This so we don't suddenly stop downloading a map - if (cls.download) return; + if (cls.download) + return; SCR_BeginLoadingPlaque (); cls.state = ca_connected; // not active anymore, but not disconnected @@ -751,7 +762,7 @@ void CL_Reconnect_f (void) if (*cls.servername) { if (cls.state >= ca_connected) { CL_Disconnect(); - cls.connect_time = cls.realtime - 1.5f; + cls.connect_time = cls.realtime - 1500; } else cls.connect_time = -99999; // fire immediately @@ -1010,7 +1021,8 @@ void CL_ReadPackets (void) // // check timeout // - if (cls.state >= ca_connected && cls.realtime - cls.netchan.last_received > cl_timeout->value) + if (cls.state >= ca_connected + && cls.realtime - cls.netchan.last_received > cl_timeout->value*1000) { if (++cl.timeoutcount > 5) // timeoutcount saves debugger { @@ -1401,8 +1413,7 @@ CL_InitLocal void CL_InitLocal (void) { cls.state = ca_disconnected; - cls.realtime = Sys_DoubleTime(); - + cls.realtime = Sys_Milliseconds (); CL_InitInput (); adr0 = Cvar_Get( "adr0", "", CVAR_ARCHIVE ); @@ -1415,9 +1426,9 @@ void CL_InitLocal (void) adr7 = Cvar_Get( "adr7", "", CVAR_ARCHIVE ); adr8 = Cvar_Get( "adr8", "", CVAR_ARCHIVE ); - // - // register our variables - // +// +// register our variables +// cl_stereo_separation = Cvar_Get( "cl_stereo_separation", "0.4", CVAR_ARCHIVE ); cl_stereo = Cvar_Get( "cl_stereo", "0", 0 ); @@ -1606,8 +1617,9 @@ void CL_FixCvarCheats (void) int i; cheatvar_t *var; - if(!strcmp(cl.configstrings[CS_MAXCLIENTS], "1") || !cl.configstrings[CS_MAXCLIENTS][0] ) - return; // single player can cheat + if ( !strcmp(cl.configstrings[CS_MAXCLIENTS], "1") + || !cl.configstrings[CS_MAXCLIENTS][0] ) + return; // single player can cheat // find all the cvars if we haven't done it yet if (!numcheatvars) @@ -1666,36 +1678,44 @@ CL_Frame ================== */ -void CL_Frame (float time) +void CL_Frame (int msec) { - static float extratime; - static float lasttimecalled; + static int extratime; + static int lasttimecalled; - if (host.type == HOST_DEDICATED) return; + if (dedicated->value) + return; - extratime += time; + extratime += msec; if (!cl_timedemo->value) { - if (cls.state == ca_connected && extratime < 0.1f) - return; // don't flood packets out while connecting - if (extratime < 1.0f / cl_maxfps->value) - return; // framerate is too high + if (cls.state == ca_connected && extratime < 100) + return; // don't flood packets out while connecting + if (extratime < 1000/cl_maxfps->value) + return; // framerate is too high } // let the mouse activate or deactivate IN_Frame (); // decide the simulation time - cls.frametime = extratime; + cls.frametime = extratime/1000.0; cl.time += extratime; - cls.realtime = Sys_DoubleTime(); + cls.realtime = curtime; extratime = 0; - if (cls.frametime > (1.0 / 5)) cls.frametime = (1.0 / 5); +#if 0 + if (cls.frametime > (1.0 / cl_minfps->value)) + cls.frametime = (1.0 / cl_minfps->value); +#else + if (cls.frametime > (1.0 / 5)) + cls.frametime = (1.0 / 5); +#endif // if in the debugger last frame, don't timeout - if (time > 1.0f) cls.netchan.last_received = Sys_DoubleTime(); + if (msec > 5000) + cls.netchan.last_received = Sys_Milliseconds (); // fetch results from server CL_ReadPackets (); @@ -1712,7 +1732,11 @@ void CL_Frame (float time) CL_PrepRefresh (); // update the screen + if (host_speeds->value) + time_before_ref = Sys_Milliseconds (); SCR_UpdateScreen (); + if (host_speeds->value) + time_after_ref = Sys_Milliseconds (); // update audio S_Update (cl.refdef.vieworg, cl.v_forward, cl.v_right, cl.v_up); @@ -1724,6 +1748,27 @@ void CL_Frame (float time) SCR_RunConsole (); cls.framecount++; + + if ( log_stats->value ) + { + if ( cls.state == ca_active ) + { + if ( !lasttimecalled ) + { + lasttimecalled = Sys_Milliseconds(); + if ( log_stats_file ) + FS_Printf( log_stats_file, "0\n" ); + } + else + { + int now = Sys_Milliseconds(); + + if ( log_stats_file ) + FS_Printf( log_stats_file, "%d\n", now - lasttimecalled ); + lasttimecalled = now; + } + } + } } @@ -1736,8 +1781,8 @@ CL_Init */ void CL_Init (void) { - // nothing running on the client - if (host.type == HOST_DEDICATED) return; + if (dedicated->value) + return; // nothing running on the client // all archived variables will now be loaded @@ -1754,7 +1799,6 @@ void CL_Init (void) SCR_Init (); cls.disable_screen = true; // don't draw yet - CL_InitGameProgs(); CL_InitLocal (); IN_Init (); diff --git a/engine/client/cl_newfx.c b/engine/client/cl_newfx.c index b67c9b37..b3572dd4 100644 --- a/engine/client/cl_newfx.c +++ b/engine/client/cl_newfx.c @@ -81,7 +81,7 @@ void CL_Flashlight (int ent, vec3_t pos) VectorCopy (pos, dl->origin); dl->radius = 400; dl->minlight = 250; - dl->die = cl.time + 0.1; + dl->die = cl.time + 100; dl->color[0] = 1; dl->color[1] = 1; dl->color[2] = 1; @@ -100,7 +100,7 @@ void CL_ColorFlash (vec3_t pos, int ent, int intensity, float r, float g, float VectorCopy (pos, dl->origin); dl->radius = intensity; dl->minlight = 250; - dl->die = cl.time + 0.1; + dl->die = cl.time + 100; dl->color[0] = r; dl->color[1] = g; dl->color[2] = b; @@ -453,7 +453,7 @@ void CL_Heatbeam (vec3_t start, vec3_t end) VectorMA (move, -1, up, move); VectorScale (vec, step, vec); - ltime = cl.time; + ltime = (float) cl.time/1000.0; // for (i=0 ; ifraction) { - trace.ent = (prvm_edict_t *)ent; + trace.ent = (struct edict_s *)ent; if (tr->startsolid) { *tr = trace; @@ -145,14 +145,14 @@ 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 = (prvm_edict_t *)1; + t.ent = (struct edict_s *)1; // check all other solid models CL_ClipMoveToEntities (start, mins, maxs, end, &t); @@ -214,9 +214,8 @@ void CL_PredictMovement (void) return; if (!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) - { - // just set angles - for (i = 0; i < 3; i++) + { // just set angles + for (i=0 ; i<3 ; i++) { cl.predicted_angles[i] = cl.viewangles[i] + SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[i]); } diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 5b13214a..5f94fb92 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -439,7 +439,8 @@ SCR_DrawNet */ void SCR_DrawNet (void) { - if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged < CMD_BACKUP-1) + if (cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged + < CMD_BACKUP-1) return; re->DrawPic (scr_vrect.x+64, scr_vrect.y, "net"); @@ -504,7 +505,7 @@ Scroll it up or down */ void SCR_RunConsole (void) { - // decide on the height of the console +// decide on the height of the console if (cls.key_dest == key_console) scr_conlines = 0.5; // half screen else @@ -512,14 +513,14 @@ void SCR_RunConsole (void) if (scr_conlines < scr_con_current) { - scr_con_current -= scr_conspeed->value * cls.frametime * 1000; + scr_con_current -= scr_conspeed->value*cls.frametime; if (scr_conlines > scr_con_current) scr_con_current = scr_conlines; } else if (scr_conlines > scr_con_current) { - scr_con_current += scr_conspeed->value * cls.frametime * 1000; + scr_con_current += scr_conspeed->value*cls.frametime; if (scr_conlines < scr_con_current) scr_con_current = scr_conlines; } @@ -569,19 +570,20 @@ SCR_BeginLoadingPlaque void SCR_BeginLoadingPlaque (void) { S_StopAllSounds (); - cl.sound_prepped = false; // don't play ambients + cl.sound_prepped = false; // don't play ambients if (cls.disable_screen) return; - if (host.developer) return; - - if (cls.state == ca_disconnected) return; // if at console, don't bring up the plaque + if (developer->value) + return; + if (cls.state == ca_disconnected) + return; // if at console, don't bring up the plaque if (cls.key_dest == key_console) return; if (cl.cinematictime > 0) - scr_draw_loading = 2; // clear to black first - else scr_draw_loading = 1; - SCR_UpdateScreen(); - - cls.disable_screen = cls.realtime; + scr_draw_loading = 2; // clear to black first + else + scr_draw_loading = 1; + SCR_UpdateScreen (); + cls.disable_screen = Sys_Milliseconds (); cls.disable_servercount = cl.servercount; } @@ -629,19 +631,18 @@ int entitycmpfnc( const entity_t *a, const entity_t *b ) void SCR_TimeRefresh_f (void) { int i; - float start, stop; - float time; + int start, stop; + float time; if ( cls.state != ca_active ) return; - start = Sys_DoubleTime(); + start = Sys_Milliseconds (); if (Cmd_Argc() == 2) - { - // run without page flipping + { // run without page flipping re->BeginFrame( 0 ); - for (i = 0; i < 128; i++) + for (i=0 ; i<128 ; i++) { cl.refdef.viewangles[1] = i/128.0*360.0; re->RenderFrame (&cl.refdef); @@ -660,8 +661,8 @@ void SCR_TimeRefresh_f (void) } } - stop = Sys_DoubleTime(); - time = (stop-start); + stop = Sys_Milliseconds (); + time = (stop-start)/1000.0; Msg ("%f seconds (%f fps)\n", time, 128/time); } @@ -1267,7 +1268,7 @@ void SCR_UpdateScreen (void) // do nothing at all if (cls.disable_screen) { - if (cls.realtime - cls.disable_screen > 120.0f) + if (Sys_Milliseconds() - cls.disable_screen > 120000) { cls.disable_screen = 0; Msg ("Loading plaque timed out.\n"); diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 377b475c..23c98866 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -360,10 +360,16 @@ float CalcFov (float fov_x, float width, float height) float a; float x; - fov_x = bound(1, fov_x, 180); - x = width / tan(fov_x / 360 * M_PI); - a = atan (height / x); - a = a * 360/M_PI; + if (fov_x < 1 || fov_x > 179) + { + Com_Error (ERR_DROP, "Bad fov: %f", fov_x); + } + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; return a; } @@ -439,6 +445,13 @@ void V_RenderView( float stereo_separation ) if (!cl.refresh_prepped) return; // still loading + if (cl_timedemo->value) + { + if (!cl.timedemo_start) + cl.timedemo_start = Sys_DoubleTime(); + cl.timedemo_frames++; + } + // an invalid frame will just use the exact previous refdef // we can't use the old frame if the video mode has changed, though... if ( cl.frame.valid && (cl.force_refdef || !cl_paused->value) ) @@ -487,7 +500,7 @@ void V_RenderView( float stereo_separation ) cl.refdef.width = scr_vrect.width; cl.refdef.height = scr_vrect.height; cl.refdef.fov_y = CalcFov (cl.refdef.fov_x, cl.refdef.width, cl.refdef.height); - cl.refdef.time = cl.time; + cl.refdef.time = (cl.time * 0.001); // render use realtime now cl.refdef.areabits = cl.frame.areabits; @@ -520,6 +533,9 @@ void V_RenderView( float stereo_separation ) re->RenderFrame (&cl.refdef); if (cl_stats->value) Msg ("ent:%i lt:%i part:%i\n", r_numentities, r_numdlights, r_numparticles); + if ( log_stats->value && ( log_stats_file != 0 ) ) + FS_Printf( log_stats_file, "%i,%i,%i,",r_numentities, r_numdlights, r_numparticles); + SCR_AddDirtyPoint (scr_vrect.x, scr_vrect.y); SCR_AddDirtyPoint (scr_vrect.x+scr_vrect.width-1, diff --git a/engine/client/client.h b/engine/client/client.h index a0c06f37..7e57d4d8 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -34,27 +34,27 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. typedef struct { bool valid; // cleared if delta parsing was invalid - int serverframe; - float servertime; // server time the message is valid for (in msec) - int deltaframe; - byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits + int serverframe; + int servertime; // server time the message is valid for (in msec) + int deltaframe; + byte areabits[MAX_MAP_AREAS/8]; // portalarea visibility bits player_state_t playerstate; - int num_entities; - int parse_entities; // non-masked index into cl_parse_entities array + int num_entities; + int parse_entities; // non-masked index into cl_parse_entities array } frame_t; typedef struct { - entity_state_t baseline; // delta from this if not from a previous frame + entity_state_t baseline; // delta from this if not from a previous frame entity_state_t current; entity_state_t prev; // will always be valid, but might just be a copy of current int serverframe; // if not current, this ent isn't in the frame - int trailcount; // for diminishing grenade trails + int trailcount; // for diminishing grenade trails vec3_t lerp_origin; // for trails (variable hz) - float fly_stoptime; + int fly_stoptime; } centity_t; #define MAX_CLIENTWEAPONMODELS 20 // PGM -- upped from 16 to fit the chainfist vwep @@ -81,24 +81,24 @@ extern int num_cl_weaponmodels; // typedef struct { - int timeoutcount; + int timeoutcount; - int timedemo_frames; - float timedemo_start; + int timedemo_frames; + int timedemo_start; - bool refresh_prepped; // false if on new level or new ref dll - bool sound_prepped; // ambient sounds can start - bool force_refdef; // vid has changed, so we can't use a paused refdef + bool refresh_prepped; // false if on new level or new ref dll + bool sound_prepped; // ambient sounds can start + bool force_refdef; // vid has changed, so we can't use a paused refdef - int parse_entities; // index (not anded off) into cl_parse_entities[] + int parse_entities; // index (not anded off) into cl_parse_entities[] - usercmd_t cmd; - usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds - int cmd_time[CMD_BACKUP]; // time sent, for calculating pings + usercmd_t cmd; + usercmd_t cmds[CMD_BACKUP]; // each mesage will send several old cmds + int cmd_time[CMD_BACKUP]; // time sent, for calculating pings short predicted_origins[CMD_BACKUP][3]; // for debug comparing against server float predicted_step; // for stair up smoothing - float predicted_step_time; + unsigned predicted_step_time; vec3_t predicted_origin; // generated by CL_PredictMovement vec3_t predicted_angles; @@ -115,11 +115,11 @@ typedef struct // and teleport direction changes vec3_t viewangles; - float time; // this is the time value that the client - // is rendering at. always <= cls.realtime + int time; // this is the time value that the client + // is rendering at. always <= cls.realtime float lerpfrac; // between oldframe and frame - refdef_t refdef; + refdef_t refdef; vec3_t v_forward, v_right, v_up; // set when refdef.angles is set @@ -133,10 +133,10 @@ typedef struct // non-gameserver infornamtion // FIXME: move this cinematic stuff into the cin_t structure file_t *cinematic_file; - float cinematictime; // cls.realtime for first cinematic frame - int cinematicframe; + int cinematictime; // cls.realtime for first cinematic frame + int cinematicframe; char cinematicpalette[768]; - bool cinematicpalette_active; + bool cinematicpalette_active; // // server state information @@ -196,11 +196,11 @@ typedef struct keydest_t key_dest; int framecount; - double realtime; // always increasing, no clamping, etc - float frametime; // seconds since last frame + int realtime; // always increasing, no clamping, etc + float frametime; // seconds since last frame // screen rendering information - float disable_screen; // showing loading plaque between levels + float disable_screen; // showing loading plaque between levels // or changing rendering dlls // if time gets > 30 seconds ahead, break it int disable_servercount; // when we receive a frame and cl.servercount @@ -433,11 +433,6 @@ void CL_PingServers_f (void); void CL_Snd_Restart_f (void); void CL_RequestNextDownload (void); -// -// cl_game -// -void CL_InitGameProgs (void); - // // cl_input // diff --git a/engine/common.h b/engine/common.h index 6127c0d8..1049632d 100644 --- a/engine/common.h +++ b/engine/common.h @@ -59,17 +59,12 @@ typedef struct sizebuf_s int errorcount; // cause by errors } sizebuf_t; -void _SZ_Init (sizebuf_t *buf, byte *data, int length, const char *filename, int fileline); -void _SZ_Write (sizebuf_t *buf, void *data, int length, const char *filename, int fileline); -void *_SZ_GetSpace (sizebuf_t *buf, int length, const char *filename, int fileline); -void _SZ_Print (sizebuf_t *buf, char *data, const char *filename, int fileline); -void _SZ_Clear (sizebuf_t *buf, const char *filename, int fileline); +void SZ_Init (sizebuf_t *buf, byte *data, int length); +void SZ_Clear (sizebuf_t *buf); +void *SZ_GetSpace (sizebuf_t *buf, int length); +void SZ_Write (sizebuf_t *buf, void *data, int length); +void SZ_Print (sizebuf_t *buf, char *data); // strcats onto the sizebuf -#define SZ_Init(buf, data, length) _SZ_Init( buf, data, length, __FILE__, __LINE__) -#define SZ_Write(buf, data, length) _SZ_Write( buf, data, length, __FILE__, __LINE__) -#define SZ_Print(buf, data ) _SZ_Print( buf, data, __FILE__, __LINE__) -#define SZ_GetSpace(buf, length) _SZ_GetSpace( buf, length, __FILE__, __LINE__) -#define SZ_Clear(buf) _SZ_Clear( buf, __FILE__, __LINE__) //============================================================================ struct usercmd_s; @@ -92,26 +87,26 @@ void _MSG_WriteDeltaUsercmd (sizebuf_t *sb, struct usercmd_s *from, struct userc void _MSG_WriteDeltaEntity (struct entity_state_s *from, struct entity_state_s *to, sizebuf_t *msg, bool force, bool newentity, const char *filename, int fileline); void _MSG_WriteDir (sizebuf_t *sb, vec3_t vector, const char *filename, int fileline); void _MSG_WriteVector (sizebuf_t *sb, float *v, const char *filename, int fileline); -void _MSG_Send (msgtype_t to, vec3_t origin, prvm_edict_t *ent, const char *filename, int fileline); +void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename, int fileline); -#define MSG_Begin( x ) _MSG_Begin( x, __FILE__, __LINE__) -#define MSG_WriteChar(x,y) _MSG_WriteChar (x, y, __FILE__, __LINE__) -#define MSG_WriteByte(x,y) _MSG_WriteByte (x, y, __FILE__, __LINE__) -#define MSG_WriteShort(x,y) _MSG_WriteShort (x, y, __FILE__, __LINE__) -#define MSG_WriteWord(x,y) _MSG_WriteWord (x, y, __FILE__, __LINE__) -#define MSG_WriteLong(x,y) _MSG_WriteLong (x, y, __FILE__, __LINE__) -#define MSG_WriteFloat(x, y) _MSG_WriteFloat (x, y, __FILE__, __LINE__) -#define MSG_WriteString(x,y) _MSG_WriteString (x, y, __FILE__, __LINE__) -#define MSG_WriteCoord(x, y) _MSG_WriteCoord (x, y, __FILE__, __LINE__) -#define MSG_WritePos(x, y) _MSG_WritePos (x, y, __FILE__, __LINE__) -#define MSG_WriteAngle(x, y) _MSG_WriteAngle (x, y, __FILE__, __LINE__) -#define MSG_WriteAngle16(x, y) _MSG_WriteAngle16 (x, y, __FILE__, __LINE__) -#define MSG_WriteUnterminatedString(x, y) _MSG_WriteUnterminatedString (x, y, __FILE__, __LINE__) -#define MSG_WriteDeltaUsercmd(x, y, z) _MSG_WriteDeltaUsercmd (x, y, z, __FILE__, __LINE__) -#define MSG_WriteDeltaEntity(x, y, z, t, m) _MSG_WriteDeltaEntity (x, y, z, t, m, __FILE__, __LINE__) -#define MSG_WriteDir(x, y) _MSG_WriteDir (x, y, __FILE__, __LINE__) -#define MSG_WriteVector(x, y) _MSG_WriteVector (x, y, __FILE__, __LINE__) -#define MSG_Send(x, y, z) _MSG_Send(x, y, z, __FILE__, __LINE__) +#define MSG_Begin( x ) _MSG_Begin( x, __FILE__, __LINE__); +#define MSG_WriteChar(x,y) _MSG_WriteChar (x, y, __FILE__, __LINE__); +#define MSG_WriteByte(x,y) _MSG_WriteByte (x, y, __FILE__, __LINE__); +#define MSG_WriteShort(x,y) _MSG_WriteShort (x, y, __FILE__, __LINE__); +#define MSG_WriteWord(x,y) _MSG_WriteWord (x, y, __FILE__, __LINE__); +#define MSG_WriteLong(x,y) _MSG_WriteLong (x, y, __FILE__, __LINE__); +#define MSG_WriteFloat(x, y) _MSG_WriteFloat (x, y, __FILE__, __LINE__); +#define MSG_WriteString(x,y) _MSG_WriteString (x, y, __FILE__, __LINE__); +#define MSG_WriteCoord(x, y) _MSG_WriteCoord (x, y, __FILE__, __LINE__); +#define MSG_WritePos(x, y) _MSG_WritePos (x, y, __FILE__, __LINE__); +#define MSG_WriteAngle(x, y) _MSG_WriteAngle (x, y, __FILE__, __LINE__); +#define MSG_WriteAngle16(x, y) _MSG_WriteAngle16 (x, y, __FILE__, __LINE__); +#define MSG_WriteUnterminatedString(x, y) _MSG_WriteUnterminatedString (x, y, __FILE__, __LINE__); +#define MSG_WriteDeltaUsercmd(x, y, z) _MSG_WriteDeltaUsercmd (x, y, z, __FILE__, __LINE__); +#define MSG_WriteDeltaEntity(x, y, z, t, m) _MSG_WriteDeltaEntity (x, y, z, t, m, __FILE__, __LINE__); +#define MSG_WriteDir(x, y) _MSG_WriteDir (x, y, __FILE__, __LINE__); +#define MSG_WriteVector(x, y) _MSG_WriteVector (x, y, __FILE__, __LINE__); +#define MSG_Send(x, y, z) _MSG_Send(x, y, z, __FILE__, __LINE__); void MSG_BeginReading (sizebuf_t *sb); @@ -136,14 +131,15 @@ void MSG_ReadData (sizebuf_t *sb, void *buffer, int size); //============================================================================ -int COM_Argc (void); +int COM_Argc (void); char *COM_Argv (int arg); // range and null checked void COM_ClearArgv (int arg); +int COM_CheckParm (char *parm); void COM_Init (void); void COM_InitArgv (int argc, char **argv); -char *CopyString (const char *in); +char *CopyString (char *in); //============================================================================ @@ -418,7 +414,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 (const char *cmd_name); +bool Cmd_Exists (char *cmd_name); // used by the cvar code to check for cvar / command name overlap char *Cmd_CompleteCommand (char *partial); @@ -432,11 +428,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 (const char *text, bool macroExpand); +void Cmd_TokenizeString (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 (const char *text); +void Cmd_ExecuteString (char *text); // Parses a single line of text into arguments and tries to execute it // as if it was typed at the console @@ -461,32 +457,33 @@ NET #define PACKET_HEADER 10 // two ints and a short typedef enum {NA_LOOPBACK, NA_BROADCAST, NA_IP, NA_IPX, NA_BROADCAST_IPX} netadrtype_t; + typedef enum {NS_CLIENT, NS_SERVER} netsrc_t; typedef struct { netadrtype_t type; - byte ip[4]; - byte ipx[10]; + byte ip[4]; + byte ipx[10]; - word port; + unsigned short port; } netadr_t; -void NET_Init (void); -void NET_Shutdown (void); +void NET_Init (void); +void NET_Shutdown (void); -void NET_Config (bool multiplayer); +void NET_Config (bool multiplayer); bool NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message); -void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to); +void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to); bool NET_CompareAdr (netadr_t a, netadr_t b); bool NET_CompareBaseAdr (netadr_t a, netadr_t b); bool NET_IsLocalAddress (netadr_t adr); -char *NET_AdrToString (netadr_t a); +char *NET_AdrToString (netadr_t a); bool NET_StringToAdr (char *s, netadr_t *a); -void NET_Sleep(int msec); +void NET_Sleep(int msec); //============================================================================ @@ -503,12 +500,12 @@ typedef struct int dropped; // between last packet and previous int last_received; // for timeouts - int last_sent; // for retransmits + int last_sent; // for retransmits netadr_t remote_address; int qport; // qport value to write when transmitting - // sequencing variables +// sequencing variables int incoming_sequence; int incoming_acknowledged; int incoming_reliable_acknowledged; // single bit @@ -520,16 +517,16 @@ typedef struct int last_reliable_sequence; // sequence number of last send // reliable staging and holding areas - sizebuf_t message; // writing buffer to send to server - byte message_buf[MAX_MSGLEN - 16]; // leave space for header + sizebuf_t message; // writing buffer to send to server + byte message_buf[MAX_MSGLEN-16]; // leave space for header // message is copied to this buffer when it is first transfered int reliable_length; - byte reliable_buf[MAX_MSGLEN - 16]; // unacked reliable message + byte reliable_buf[MAX_MSGLEN-16]; // unacked reliable message } netchan_t; -extern netadr_t net_from; -extern sizebuf_t net_message; +extern netadr_t net_from; +extern sizebuf_t net_message; extern byte net_message_buffer[MAX_MSGLEN]; @@ -627,25 +624,39 @@ MISC #define EXEC_INSERT 1 // insert at current position, but don't run yet #define EXEC_APPEND 2 // add to end of the command buffer -void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush)); -void Com_EndRedirect (void); -void Com_Printf (char *fmt, ...); -void Com_DPrintf (int level, char *fmt, ...); -void Com_DWarnf (char *fmt, ...); -void Com_Error (int code, char *fmt, ...); -void Com_Error_f ( void ); -void Com_Quit (void); +#define PRINT_ALL 0 +#define PRINT_DEVELOPER 1 // only print when "developer 1" -int Com_ServerState (void); // this should have just been a cvar... -void Com_SetServerState (int state); +void Com_BeginRedirect (int target, char *buffer, int buffersize, void (*flush)); +void Com_EndRedirect (void); +void Com_Printf (char *fmt, ...); +void Com_DPrintf (int level, char *fmt, ...); +void Com_DWarnf (char *fmt, ...); +void Com_Error (int code, char *fmt, ...); +void Com_Error_f ( void ); +void Com_Quit (void); + +int Com_ServerState (void); // this should have just been a cvar... +void Com_SetServerState (int state); unsigned Com_BlockChecksum (void *buffer, int length); -byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence); +byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence); float frand(void); // 0 to 1 float crand(void); // -1 to 1 +extern cvar_t *developer; +extern cvar_t *dedicated; extern cvar_t *host_speeds; +extern cvar_t *log_stats; + +extern file_t *log_stats_file; + +// host_speeds times +extern int time_before_game; +extern int time_after_game; +extern int time_before_ref; +extern int time_after_ref; #define NUMVERTEXNORMALS 162 extern vec3_t bytedirs[NUMVERTEXNORMALS]; @@ -686,12 +697,12 @@ CLIENT / SERVER SYSTEMS void CL_Init (void); void CL_Drop (void); void CL_Shutdown (void); -void CL_Frame (float time); +void CL_Frame (int msec); void Con_Print (char *text); void SCR_BeginLoadingPlaque (void); void SV_Init (void); void SV_Shutdown (char *finalmsg, bool reconnect); -void SV_Frame (float time); +void SV_Frame (int msec); #endif//COMMON_H \ No newline at end of file diff --git a/engine/common/cmd.c b/engine/common/cmd.c index ed1da89a..41191e78 100644 --- a/engine/common/cmd.c +++ b/engine/common/cmd.c @@ -234,7 +234,7 @@ void Cbuf_Execute (void) memmove (text, text+i, cmd_text.cursize); } - // execute the command line +// execute the command line Cmd_ExecuteString (line); if (cmd_wait) @@ -301,7 +301,7 @@ bool Cbuf_AddLateCommands (void) int argc; bool ret; - // build the combined string to parse from +// build the combined string to parse from s = 0; argc = COM_Argc(); for (i=1 ; i= MAX_STRING_CHARS) @@ -612,10 +613,10 @@ Parses the given string into command line tokens. $Cvars will be expanded unless they are in a quoted token ============ */ -void Cmd_TokenizeString (const char *text, bool macroExpand) +void Cmd_TokenizeString (char *text, bool macroExpand) { int i; - char *token; + char *token; // clear the args from the last string for (i = 0; i < cmd_argc; i++) Z_Free (cmd_argv[i]); @@ -740,15 +741,16 @@ void Cmd_RemoveCommand (char *cmd_name) Cmd_Exists ============ */ -bool Cmd_Exists (const char *cmd_name) +bool Cmd_Exists (char *cmd_name) { cmd_function_t *cmd; - for (cmd = cmd_functions; cmd; cmd = cmd->next) + for (cmd=cmd_functions ; cmd ; cmd=cmd->next) { if (!strcmp (cmd_name,cmd->name)) return true; } + return false; } @@ -798,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 (const char *text) +void Cmd_ExecuteString (char *text) { cmd_function_t *cmd; cmdalias_t *a; diff --git a/engine/common/cmodel.c b/engine/common/cmodel.c index f48fcac6..083910f1 100644 --- a/engine/common/cmodel.c +++ b/engine/common/cmodel.c @@ -36,19 +36,19 @@ typedef struct typedef struct { - int contents; - int cluster; - int area; - word firstleafbrush; - word numleafbrushes; + int contents; + int cluster; + int area; + unsigned short firstleafbrush; + unsigned short numleafbrushes; } cleaf_t; typedef struct { - int contents; - int numsides; - int firstbrushside; - int checkcount; // to avoid repeated testings + int contents; + int numsides; + int firstbrushside; + int checkcount; // to avoid repeated testings } cbrush_t; typedef struct @@ -926,7 +926,7 @@ Handles offseting and rotation of the end points for moving and rotating entities ================== */ -int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles) +int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t angles) { vec3_t p_l; vec3_t temp; @@ -940,7 +940,7 @@ int CM_TransformedPointContents (vec3_t p, int headnode, vec3_t origin, vec3_t a if (headnode != box_headnode && (angles[0] || angles[1] || angles[2]) ) { - AngleVectorsRight (angles, forward, right, up); + AngleVectors (angles, forward, right, up); VectorCopy (p_l, temp); p_l[0] = DotProduct (temp, forward); @@ -978,15 +978,16 @@ bool trace_ispoint; // optimized case CM_ClipBoxToBrush ================ */ -void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t *trace, cbrush_t *brush) +void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, + trace_t *trace, cbrush_t *brush) { - int i, j; - cplane_t *plane, *clipplane; + int i, j; + cplane_t *plane, *clipplane; float dist; float enterfrac, leavefrac; vec3_t ofs; float d1, d2; - bool getout, startout; + bool getout, startout; float f; cbrushside_t *side, *leadside; @@ -994,7 +995,8 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t leavefrac = 1; clipplane = NULL; - if (!brush->numsides) return; + if (!brush->numsides) + return; c_brush_traces++; @@ -1002,7 +1004,7 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t startout = false; leadside = NULL; - for (i = 0; i < brush->numsides; i++) + for (i=0 ; inumsides ; i++) { side = &map_brushsides[brush->firstbrushside+i]; plane = side->plane; @@ -1010,17 +1012,17 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t // FIXME: special case for axial if (!trace_ispoint) - { - // general box case + { // general box case // push the plane out apropriately for mins/maxs // FIXME: use signbits into 8 way lookup for each mins/maxs - for (j = 0; j < 3; j++) + for (j=0 ; j<3 ; j++) { if (plane->normal[j] < 0) ofs[j] = maxs[j]; - else ofs[j] = mins[j]; + else + ofs[j] = mins[j]; } dist = DotProduct (ofs, plane->normal); dist = plane->dist - dist; @@ -1033,13 +1035,17 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t d1 = DotProduct (p1, plane->normal) - dist; d2 = DotProduct (p2, plane->normal) - dist; - if (d2 > 0) getout = true; // endpoint is not in solid - if (d1 > 0) startout = true; + if (d2 > 0) + getout = true; // endpoint is not in solid + if (d1 > 0) + startout = true; // if completely in front of face, no intersection - if (d1 > 0 && d2 >= d1) return; + if (d1 > 0 && d2 >= d1) + return; - if (d1 <= 0 && d2 <= 0) continue; + if (d1 <= 0 && d2 <= 0) + continue; // crosses face if (d1 > d2) @@ -1054,23 +1060,25 @@ void CM_ClipBoxToBrush (vec3_t mins, vec3_t maxs, vec3_t p1, vec3_t p2, trace_t } else { // leave - f = (d1 + DIST_EPSILON) / (d1-d2); - if (f < leavefrac) leavefrac = f; + f = (d1+DIST_EPSILON) / (d1-d2); + if (f < leavefrac) + leavefrac = f; } } if (!startout) - { - // original point was inside brush + { // original point was inside brush trace->startsolid = true; - if (!getout) trace->allsolid = true; + if (!getout) + trace->allsolid = true; return; } if (enterfrac < leavefrac) { if (enterfrac > -1 && enterfrac < trace->fraction) { - if (enterfrac < 0) enterfrac = 0; + if (enterfrac < 0) + enterfrac = 0; trace->fraction = enterfrac; trace->plane = *clipplane; trace->surface = &(leadside->surface->c); @@ -1184,7 +1192,7 @@ void CM_TestInLeaf (int leafnum) if ( !(leaf->contents & trace_contents)) return; // trace line against all brushes in the leaf - for (k = 0; k < leaf->numleafbrushes; k++) + for (k=0 ; knumleafbrushes ; k++) { brushnum = map_leafbrushes[leaf->firstleafbrush+k]; b = &map_brushes[brushnum]; @@ -1192,7 +1200,7 @@ void CM_TestInLeaf (int leafnum) continue; // already checked this brush in another leaf b->checkcount = checkcount; - if (!(b->contents & trace_contents)) + if ( !(b->contents & trace_contents)) continue; CM_TestBoxInBrush (trace_mins, trace_maxs, trace_start, &trace_trace, b); if (!trace_trace.fraction) @@ -1331,12 +1339,15 @@ return; CM_BoxTrace ================== */ -trace_t CM_BoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int headnode, int brushmask) +trace_t CM_BoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask) { int i; - checkcount++; // for multi-check avoidance - c_traces++; // for statistics, may be zeroed + checkcount++; // for multi-check avoidance + + c_traces++; // for statistics, may be zeroed // fill in a default trace memset (&trace_trace, 0, sizeof(trace_trace)); @@ -1352,24 +1363,26 @@ trace_t CM_BoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int hea VectorCopy (mins, trace_mins); VectorCopy (maxs, trace_maxs); + // // check for position test special case + // if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2]) { int leafs[1024]; int i, numleafs; - vec3_t c1, c2; + vec3_t c1, c2; int topnode; VectorAdd (start, mins, c1); VectorAdd (start, maxs, c2); - for (i = 0; i < 3; i++) + for (i=0 ; i<3 ; i++) { c1[i] -= 1; c2[i] += 1; } numleafs = CM_BoxLeafnums_headnode (c1, c2, leafs, 1024, headnode, &topnode); - for (i = 0; i < numleafs; i++) + for (i=0 ; i maxs[2] ? -mins[2] : maxs[2]; } + // // general sweeping through world + // CM_RecursiveHullCheck (headnode, 0, 1, start, end); if (trace_trace.fraction == 1) @@ -1403,7 +1420,7 @@ trace_t CM_BoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int hea } else { - for (i = 0; i < 3; i++) + for (i=0 ; i<3 ; i++) trace_trace.endpos[i] = start[i] + trace_trace.fraction * (end[i] - start[i]); } return trace_trace; @@ -1423,7 +1440,10 @@ rotating entities #endif -trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t maxs, int headnode, int brushmask, vec3_t origin, vec3_t angles) +trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, + vec3_t mins, vec3_t maxs, + int headnode, int brushmask, + vec3_t origin, vec3_t angles) { trace_t trace; vec3_t start_l, end_l; @@ -1437,14 +1457,15 @@ trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t ma VectorSubtract (end, origin, end_l); // rotate start and end into the models frame of reference - if (headnode != box_headnode && !VectorIsNull(angles)) + if (headnode != box_headnode && + (angles[0] || angles[1] || angles[2]) ) rotated = true; else rotated = false; if (rotated) { - AngleVectorsRight (angles, forward, right, up); + AngleVectors (angles, forward, right, up); VectorCopy (start_l, temp); start_l[0] = DotProduct (temp, forward); @@ -1465,7 +1486,7 @@ trace_t CM_TransformedBoxTrace (vec3_t start, vec3_t end, vec3_t mins, vec3_t ma // FIXME: figure out how to do this with existing angles VectorCopy( angles, a ); VectorNegate ( a, a ); - AngleVectorsRight (a, forward, right, up); + AngleVectors (a, forward, right, up); VectorCopy (trace.plane.normal, temp); trace.plane.normal[0] = DotProduct (temp, forward); @@ -1720,15 +1741,15 @@ STUDIO SHARED CMODELS =============================================================================== */ -#define HULL_PRECISION 4 // precision factor +#define NUM_HULL_ROUNDS 22 +#define HULL_PRECISION 4 -word hull_table[] = { 0, 4, 8, 16, 18, 24, 28, 30, 32, 40, 48, 54, 56, 60, 64, 72, 80, 112, 120, 128, 140, 176 }; -#define NUM_HULL_ROUNDS (sizeof(hull_table) / sizeof(word)) +word hull_table[NUM_HULL_ROUNDS] = { 0, 4, 8, 16, 18, 24, 28, 30, 32, 40, 48, 54, 56, 60, 64, 72, 80, 112, 120, 128, 140, 176 }; void CM_LookUpHullSize(vec3_t size, bool down) { int i, j; - + for(i = 0; i < 3; i++) { bool negative = false; @@ -1748,14 +1769,7 @@ void CM_LookUpHullSize(vec3_t size, bool down) break; } } - - if(j == NUM_HULL_ROUNDS) - { - //catch an error - MsgWarn("CM_LookUpHullSize: hull size[%d] is too big, reset value to default\n", i ); - size[i] = 16; //default value - } - else size[i] = result;//copy new value + size[i] = result;//copy new value } } @@ -1805,7 +1819,7 @@ cmodel_t *CM_StudioModel (char *name, byte *buffer) VectorSet(out->mins, -32, -32, -32 ); VectorSet(out->maxs, 32, 32, 32 ); } - + numsmodels++; return out; } diff --git a/engine/common/common.c b/engine/common/common.c index 150c43c2..92ff6933 100644 --- a/engine/common/common.c +++ b/engine/common/common.c @@ -28,11 +28,24 @@ jmp_buf abortframe; int com_argc; char *com_argv[MAX_NUM_ARGVS+1]; -double realtime; +int realtime; + +file_t *log_stats_file; cvar_t *host_speeds; +cvar_t *log_stats; +cvar_t *developer; +cvar_t *dedicated; + int server_state; +// host_speeds times +int time_before_game; +int time_after_game; +int time_before_ref; +int time_after_ref; + + /* ============================================================================ @@ -101,9 +114,7 @@ void Com_Error (int code, char *fmt, ...) va_start (argptr,fmt); vsprintf (msg,fmt,argptr); va_end (argptr); - - host.state = HOST_ERROR; - + if (code == ERR_DISCONNECT) { CL_Drop (); @@ -163,7 +174,7 @@ void Com_Printf (char *fmt, ...) ================ Com_DPrintf -A Msg that only shows up in developer mode > 0 +A Msg that only shows up in debug mode ================ */ void Com_DPrintf (int level, char *fmt, ...) @@ -301,7 +312,7 @@ COM_InitArgv */ void COM_InitArgv (int argc, char **argv) { - int i; + int i; char dev_level[4]; if (argc > MAX_NUM_ARGVS) @@ -325,9 +336,9 @@ void COM_InitArgv (int argc, char **argv) host.developer = atoi(dev_level); } -char *CopyString (const char *in) +char *CopyString (char *in) { - char *out; + char *out; out = Z_Malloc (strlen(in)+1); strcpy (out, in); diff --git a/engine/common/console.c b/engine/common/console.c index 0a7e39d4..b6a4dd8e 100644 --- a/engine/common/console.c +++ b/engine/common/console.c @@ -93,7 +93,7 @@ void Con_ToggleConsole_f (void) M_ForceMenuOff (); cls.key_dest = key_console; - if (host.maxclients == 1 && Com_ServerState()) + if (Cvar_VariableValue ("maxclients") == 1 && Com_ServerState ()) Cvar_Set ("paused", "1"); } } @@ -206,7 +206,7 @@ void Con_ClearNotify (void) { int i; - for (i = 0; i < NUM_CON_TIMES; i++) + for (i=0 ; i= 0) con.times[con.current % NUM_CON_TIMES] = cls.realtime; + // mark time for transparent overlay + if (con.current >= 0) + con.times[con.current % NUM_CON_TIMES] = cls.realtime; } switch (c) @@ -466,24 +467,24 @@ void Con_DrawInput (void) text = key_lines[edit_line]; - // add the cursor frame - text[key_linepos] = 10 + ((int)(cls.realtime * 4.0f) & 1); +// add the cursor frame + text[key_linepos] = 10+((int)(cls.realtime>>8)&1); - // fill out remainder with spaces - for (i = key_linepos + 1; i < con.linewidth; i++) +// fill out remainder with spaces + for (i=key_linepos+1 ; i< con.linewidth ; i++) text[i] = ' '; - // prestep if horizontally scrolling +// prestep if horizontally scrolling if (key_linepos >= con.linewidth) text += 1 + key_linepos - con.linewidth; - // draw it +// draw it y = con.vislines-16; for (i=0 ; iDrawChar ( (i+1)<<3, con.vislines - 22, text[i]); - // remove cursor +// remove cursor key_lines[edit_line][key_linepos] = 0; } @@ -500,19 +501,22 @@ void Con_DrawNotify (void) int x, v; char *text; int i; - float time; + int time; char *s; int skip; v = 0; for (i= con.current-NUM_CON_TIMES+1 ; i<=con.current ; i++) { - if (i < 0) continue; + if (i < 0) + continue; time = con.times[i % NUM_CON_TIMES]; - if (time == 0) continue; + if (time == 0) + continue; time = cls.realtime - time; - if (time > con_notifytime->value) continue; - text = con.text + (i % con.totallines) * con.linewidth; + if (time > con_notifytime->value*1000) + continue; + text = con.text + (i % con.totallines)*con.linewidth; for (x = 0 ; x < con.linewidth ; x++) re->DrawChar ( (x+1)<<3, v, text[x]); @@ -543,7 +547,7 @@ void Con_DrawNotify (void) re->DrawChar ( (x+skip)<<3, v, s[x]); x++; } - re->DrawChar ((x+skip)<<3, v, 10 + ((int)(cls.realtime * 4.0f) & 1)); + re->DrawChar ( (x+skip)<<3, v, 10+((cls.realtime>>8)&1)); v += 8; } diff --git a/engine/common/cvar.c b/engine/common/cvar.c index 0db52cdb..3c439cee 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 (const char *s) +static bool Cvar_InfoValidate (char *s) { if (strstr (s, "\\")) return false; @@ -44,11 +44,11 @@ static bool Cvar_InfoValidate (const char *s) Cvar_FindVar ============ */ -cvar_t *Cvar_FindVar (const char *var_name) +cvar_t *Cvar_FindVar (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,12 +60,13 @@ cvar_t *Cvar_FindVar (const char *var_name) Cvar_VariableValue ============ */ -float Cvar_VariableValue (const char *var_name) +float Cvar_VariableValue (char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); - if (!var) return 0; + if (!var) + return 0; return atof (var->string); } @@ -75,12 +76,13 @@ float Cvar_VariableValue (const char *var_name) Cvar_VariableString ============ */ -char *Cvar_VariableString (const char *var_name) +char *Cvar_VariableString (char *var_name) { cvar_t *var; var = Cvar_FindVar (var_name); - if (!var) return ""; + if (!var) + return ""; return var->string; } @@ -93,15 +95,16 @@ Cvar_CompleteVariable char *Cvar_CompleteVariable (char *partial) { cvar_t *cvar; - int len; + int len; len = strlen(partial); - if (!len) return NULL; + if (!len) + return NULL; // check exact match for (cvar=cvar_vars ; cvar ; cvar=cvar->next) - if (!strcmp (partial, cvar->name)) + if (!strcmp (partial,cvar->name)) return cvar->name; // check partial match @@ -121,7 +124,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 (const char *var_name, const char *var_value, int flags) +cvar_t *Cvar_Get (char *var_name, char *var_value, int flags) { cvar_t *var; @@ -173,12 +176,15 @@ cvar_t *Cvar_Get (const char *var_name, const char *var_value, int flags) Cvar_Set2 ============ */ -cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) +cvar_t *Cvar_Set2 (char *var_name, char *value, bool force) { cvar_t *var; - + var = Cvar_FindVar (var_name); - if (!var) return Cvar_Get (var_name, value, 0); // create it + if (!var) + { // create it + return Cvar_Get (var_name, value, 0); + } if (var->flags & (CVAR_USERINFO | CVAR_SERVERINFO)) { @@ -238,13 +244,13 @@ cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) var->modified = true; - // transmit at next oportunity - if (var->flags & CVAR_USERINFO) userinfo_modified = true; + if (var->flags & CVAR_USERINFO) + userinfo_modified = true; // transmit at next oportunity - 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; } @@ -254,7 +260,7 @@ cvar_t *Cvar_Set2 (const char *var_name, const char *value, bool force) Cvar_ForceSet ============ */ -cvar_t *Cvar_ForceSet (const char *var_name, const char *value) +cvar_t *Cvar_ForceSet (char *var_name, char *value) { return Cvar_Set2 (var_name, value, true); } @@ -264,7 +270,7 @@ cvar_t *Cvar_ForceSet (const char *var_name, const char *value) Cvar_Set ============ */ -cvar_t *_Cvar_Set (const char *var_name, const char *value, const char *filename, int fileline) +cvar_t *Cvar_Set (char *var_name, char *value) { return Cvar_Set2 (var_name, value, false); } @@ -346,13 +352,14 @@ Handles variable inspection and changing from the console */ bool Cvar_Command (void) { - cvar_t *v; - - // check variables + cvar_t *v; + +// 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); @@ -385,8 +392,10 @@ 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"); @@ -394,7 +403,8 @@ 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)); } @@ -465,7 +475,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; @@ -481,13 +491,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 d083f6a7..1e4423a4 100644 --- a/engine/common/cvar.h +++ b/engine/common/cvar.h @@ -6,18 +6,17 @@ #define CVAR_H extern cvar_t *cvar_vars; -cvar_t *Cvar_FindVar (const char *var_name); +cvar_t *Cvar_FindVar (char *var_name); -cvar_t *Cvar_Get (const char *var_name, const char *value, int flags); +cvar_t *Cvar_Get (char *var_name, 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 -#define Cvar_Set(name, val) _Cvar_Set (name, val, __FILE__, __LINE__) -cvar_t *_Cvar_Set (const char *var_name, const char *value, const char *filename, int fileline); +cvar_t *Cvar_Set (char *var_name, char *value); // will create the variable if it doesn't exist -cvar_t *Cvar_ForceSet (const char *var_name, const char *value); +cvar_t *Cvar_ForceSet (char *var_name, char *value); // will set the variable even if NOSET or LATCH cvar_t *Cvar_FullSet (char *var_name, char *value, int flags); @@ -25,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 (const char *var_name); +float Cvar_VariableValue (char *var_name); // returns 0 if not defined or non numeric -char *Cvar_VariableString (const char *var_name); +char *Cvar_VariableString (char *var_name); // returns an empty string if not defined char *Cvar_CompleteVariable (char *partial); diff --git a/engine/common/keys.c b/engine/common/keys.c index 2400f1e5..d4aad1e3 100644 --- a/engine/common/keys.c +++ b/engine/common/keys.c @@ -737,7 +737,7 @@ Called by the system between frames for both key up and key down events Should NOT be called during an interrupt! =================== */ -void Key_Event (int key, bool down, uint msec) +void Key_Event (int key, bool down, unsigned time) { char *kb; char cmd[1024]; @@ -835,7 +835,7 @@ void Key_Event (int key, bool down, uint msec) kb = keybindings[key]; if (kb && kb[0] == '+') { - sprintf (cmd, "-%s %i %i\n", kb+1, key, msec); + sprintf (cmd, "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } if (keyshift[key] != key) @@ -843,7 +843,7 @@ void Key_Event (int key, bool down, uint msec) kb = keybindings[keyshift[key]]; if (kb && kb[0] == '+') { - sprintf (cmd, "-%s %i %i\n", kb+1, key, msec); + sprintf (cmd, "-%s %i %i\n", kb+1, key, time); Cbuf_AddText (cmd); } } @@ -859,7 +859,7 @@ void Key_Event (int key, bool down, uint msec) if (kb[0] == '+') { // button commands add keynum and time as a parm - sprintf (cmd, "%s %i %i\n", kb, key, msec); + sprintf (cmd, "%s %i %i\n", kb, key, time); Cbuf_AddText (cmd); } else diff --git a/engine/common/keys.h b/engine/common/keys.h index e5a6eebe..f81b22e3 100644 --- a/engine/common/keys.h +++ b/engine/common/keys.h @@ -137,12 +137,10 @@ extern char chat_buffer[]; extern int chat_bufferlen; extern bool chat_team; -void Key_Event (int key, bool down, uint msec); +void Key_Event (int key, bool down, unsigned time); 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 7896886a..9d489600 100644 --- a/engine/common/menu.c +++ b/engine/common/menu.c @@ -84,7 +84,7 @@ void M_PushMenu ( void (*draw) (void), const char *(*key) (int k) ) { int i; - if (host.maxclients == 1 && Com_ServerState ()) + if (Cvar_VariableValue ("maxclients") == 1 && Com_ServerState ()) Cvar_Set ("paused", "1"); // if this menu is already present, drop back to that level @@ -321,6 +321,7 @@ void M_DrawCursor( int x, int y, int f ) for ( i = 0; i < NUM_CURSOR_FRAMES; i++ ) { sprintf( cursorname, "m_cursor%d", i ); + re->RegisterPic( cursorname ); } cached = true; @@ -424,7 +425,7 @@ void M_Main_Draw (void) strlcat( litname, "_sel", 80 ); re->DrawPic( xoffset, ystart + m_main_cursor * 40 + 13, litname ); - M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime * 8.0f) % NUM_CURSOR_FRAMES ); + M_DrawCursor( xoffset - 25, ystart + m_main_cursor * 40 + 11, (int)(cls.realtime / 100)%NUM_CURSOR_FRAMES ); re->DrawGetPicSize( &w, &h, "m_main_plaque" ); re->DrawPic( xoffset - 30 - w, ystart, "m_main_plaque" ); @@ -685,8 +686,10 @@ static void M_FindKeysForCommand (char *command, int *twokeys) static void KeyCursorDrawFunc( menuframework_s *menu ) { - if ( bind_grab ) re->DrawChar( menu->x, menu->y + menu->cursor * 9, '=' ); - else re->DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ((int)(cls.realtime * 5.0f) & 1 )); + if ( bind_grab ) + re->DrawChar( menu->x, menu->y + menu->cursor * 9, '=' ); + else + re->DrawChar( menu->x, menu->y + menu->cursor * 9, 12 + ( ( int ) ( Sys_Milliseconds() / 250 ) & 1 ) ); } static void DrawKeyBindingFunc( void *self ) @@ -1360,7 +1363,7 @@ END GAME MENU ============================================================================= */ -static float credits_start_time; +static int credits_start_time; static const char **credits; static char *creditsIndex[256]; static char *creditsBuffer; @@ -1452,20 +1455,161 @@ static const char *idcredits[] = 0 }; +static const char *xatcredits[] = +{ + "+QUAKE II MISSION PACK: THE RECKONING", + "+BY", + "+XATRIX ENTERTAINMENT, INC.", + "", + "+DESIGN AND DIRECTION", + "Drew Markham", + "", + "+PRODUCED BY", + "Greg Goodrich", + "", + "+PROGRAMMING", + "Rafael Paiz", + "", + "+LEVEL DESIGN / ADDITIONAL GAME DESIGN", + "Alex Mayberry", + "", + "+LEVEL DESIGN", + "Mal Blackwell", + "Dan Koppel", + "", + "+ART DIRECTION", + "Michael \"Maxx\" Kaufman", + "", + "+COMPUTER GRAPHICS SUPERVISOR AND", + "+CHARACTER ANIMATION DIRECTION", + "Barry Dempsey", + "", + "+SENIOR ANIMATOR AND MODELER", + "Jason Hoover", + "", + "+CHARACTER ANIMATION AND", + "+MOTION CAPTURE SPECIALIST", + "Amit Doron", + "", + "+ART", + "Claire Praderie-Markham", + "Viktor Antonov", + "Corky Lehmkuhl", + "", + "+INTRODUCTION ANIMATION", + "Dominique Drozdz", + "", + "+ADDITIONAL LEVEL DESIGN", + "Aaron Barber", + "Rhett Baldwin", + "", + "+3D CHARACTER ANIMATION TOOLS", + "Gerry Tyra, SA Technology", + "", + "+ADDITIONAL EDITOR TOOL PROGRAMMING", + "Robert Duffy", + "", + "+ADDITIONAL PROGRAMMING", + "Ryan Feltrin", + "", + "+PRODUCTION COORDINATOR", + "Victoria Sylvester", + "", + "+SOUND DESIGN", + "Gary Bradfield", + "", + "+MUSIC BY", + "Sonic Mayhem", + "", + "", + "", + "+SPECIAL THANKS", + "+TO", + "+OUR FRIENDS AT ID SOFTWARE", + "", + "John Carmack", + "John Cash", + "Brian Hook", + "Adrian Carmack", + "Kevin Cloud", + "Paul Steed", + "Tim Willits", + "Christian Antkow", + "Paul Jaquays", + "Brandon James", + "Todd Hollenshead", + "Barrett (Bear) Alexander", + "Dave \"Zoid\" Kirsch", + "Donna Jackson", + "", + "", + "", + "+THANKS TO ACTIVISION", + "+IN PARTICULAR:", + "", + "Marty Stratton", + "Henk \"The Original Ripper\" Hartong", + "Kevin Kraff", + "Jamey Gottlieb", + "Chris Hepburn", + "", + "+AND THE GAME TESTERS", + "", + "Tim Vanlaw", + "Doug Jacobs", + "Steven Rosenthal", + "David Baker", + "Chris Campbell", + "Aaron Casillas", + "Steve Elwell", + "Derek Johnstone", + "Igor Krinitskiy", + "Samantha Lee", + "Michael Spann", + "Chris Toft", + "Juan Valdes", + "", + "+THANKS TO INTERGRAPH COMPUTER SYTEMS", + "+IN PARTICULAR:", + "", + "Michael T. Nicolaou", + "", + "", + "Quake II Mission Pack: The Reckoning", + "(tm) (C)1998 Id Software, Inc. All", + "Rights Reserved. Developed by Xatrix", + "Entertainment, Inc. for Id Software,", + "Inc. Distributed by Activision Inc.", + "under license. Quake(R) is a", + "registered trademark of Id Software,", + "Inc. Quake II Mission Pack: The", + "Reckoning(tm), Quake II(tm), the Id", + "Software name, the \"Q II\"(tm) logo", + "and id(tm) logo are trademarks of Id", + "Software, Inc. Activision(R) is a", + "registered trademark of Activision,", + "Inc. Xatrix(R) is a registered", + "trademark of Xatrix Entertainment,", + "Inc. All other trademarks and trade", + "names are properties of their", + "respective owners.", + 0 +}; + void M_Credits_MenuDraw( void ) { - int i; - float y; + int i, y; /* ** draw the credits */ - for ( i = 0, y = viddef.height - (( cls.realtime - credits_start_time ) * 40.0f ); credits[i] && y < viddef.height; y += 10, i++ ) + for ( i = 0, y = viddef.height - ( ( cls.realtime - credits_start_time ) / 40.0F ); credits[i] && y < viddef.height; y += 10, i++ ) { int j, stringoffset = 0; int bold = false; - if ( y <= -8 ) continue; + if ( y <= -8 ) + continue; if ( credits[i][0] == '+' ) { @@ -1484,13 +1628,15 @@ void M_Credits_MenuDraw( void ) x = ( viddef.width - strlen( credits[i] ) * 8 - stringoffset * 8 ) / 2 + ( j + stringoffset ) * 8; - if ( bold ) re->DrawChar( x, y, credits[i][j+stringoffset] + 128 ); - else re->DrawChar( x, y, credits[i][j+stringoffset] ); + if ( bold ) + re->DrawChar( x, y, credits[i][j+stringoffset] + 128 ); + else + re->DrawChar( x, y, credits[i][j+stringoffset] ); } } - // loop demonstration - if ( y < 0 ) credits_start_time = cls.realtime; + if ( y < 0 ) + credits_start_time = cls.realtime; } const char *M_Credits_Key( int key ) @@ -1510,12 +1656,12 @@ void M_Menu_Credits_f( void ) { int n; int count; - char *p; + char *p; int isdeveloper = 0; creditsBuffer = NULL; - creditsBuffer = FS_LoadFile ("scripts/credits.txt", &count ); - if (count) + creditsBuffer = FS_LoadFile ("credits", &count ); + if (count != -1) { p = creditsBuffer; for (n = 0; n < 255; n++) @@ -1524,15 +1670,18 @@ void M_Menu_Credits_f( void ) while (*p != '\r' && *p != '\n') { p++; - if (--count == 0) break; + if (--count == 0) + break; } if (*p == '\r') { *p++ = 0; - if (--count == 0) break; + if (--count == 0) + break; } *p++ = 0; - if (--count == 0) break; + if (--count == 0) + break; } creditsIndex[++n] = 0; credits = creditsIndex; @@ -2086,8 +2235,7 @@ void StartServerActionFunc( void *self ) timelimit = atoi( s_timelimit_field.buffer ); fraglimit = atoi( s_fraglimit_field.buffer ); - host.maxclients = maxclients; - + Cvar_SetValue( "maxclients", ClampCvar( 0, maxclients, maxclients ) ); Cvar_SetValue ("timelimit", ClampCvar( 0, timelimit, timelimit ) ); Cvar_SetValue ("fraglimit", ClampCvar( 0, fraglimit, fraglimit ) ); Cvar_Set("hostname", s_hostname_field.buffer ); @@ -2347,8 +2495,10 @@ void StartServer_MenuInit( void ) s_maxclients_field.generic.statusbar = NULL; s_maxclients_field.length = 3; s_maxclients_field.visible_length = 3; - if ( host.maxclients == 1 ) strcpy( s_maxclients_field.buffer, "8" ); - else strcpy( s_maxclients_field.buffer, "32" ); // just for test + if ( Cvar_VariableValue( "maxclients" ) == 1 ) + strcpy( s_maxclients_field.buffer, "8" ); + else + strcpy( s_maxclients_field.buffer, Cvar_VariableString("maxclients") ); s_hostname_field.generic.type = MTYPE_FIELD; s_hostname_field.generic.name = "hostname"; @@ -3338,7 +3488,7 @@ void PlayerConfig_MenuDraw( void ) refdef.height = 168; refdef.fov_x = 40; refdef.fov_y = CalcFov( refdef.fov_x, refdef.width, refdef.height ); - refdef.time = cls.realtime; + refdef.time = cls.realtime*0.001; if ( s_pmi[s_player_model_box.curvalue].skindisplaynames ) { @@ -3527,7 +3677,8 @@ void M_Draw (void) SCR_DirtyScreen (); // dim everything behind it down - if (cl.cinematictime > 0) re->DrawFill (0, 0, viddef.width, viddef.height, 0); + if (cl.cinematictime > 0) + re->DrawFill (0, 0, viddef.width, viddef.height, 0); else re->DrawFadeScreen (); m_drawfunc (); diff --git a/engine/common/net_chan.c b/engine/common/net_chan.c index 9ff7cbac..3c268980 100644 --- a/engine/common/net_chan.c +++ b/engine/common/net_chan.c @@ -93,7 +93,7 @@ void Netchan_Init (void) int port; // pick a port value that should be nice and random - port = RANDOM_LONG(1, 65535); + port = Sys_Milliseconds() & 0xffff; Msg("netchan port %d\n", port ); @@ -158,7 +158,7 @@ void Netchan_Setup (netsrc_t sock, netchan_t *chan, netadr_t adr, int qport) chan->sock = sock; chan->remote_address = adr; chan->qport = qport; - chan->last_received = host.realtime * 1000; + chan->last_received = curtime; chan->incoming_sequence = 0; chan->outgoing_sequence = 1; @@ -218,11 +218,12 @@ void Netchan_Transmit (netchan_t *chan, int length, byte *data) bool send_reliable; unsigned w1, w2; - // check for message overflow +// check for message overflow if (chan->message.overflowed) { chan->fatal_error = true; - Msg ("%s:Outgoing message overflow\n", NET_AdrToString (chan->remote_address)); + Msg ("%s:Outgoing message overflow\n" + , NET_AdrToString (chan->remote_address)); return; } @@ -230,21 +231,21 @@ void Netchan_Transmit (netchan_t *chan, int length, byte *data) if (!chan->reliable_length && chan->message.cursize) { - Mem_Copy (chan->reliable_buf, chan->message_buf, chan->message.cursize); + memcpy (chan->reliable_buf, chan->message_buf, chan->message.cursize); chan->reliable_length = chan->message.cursize; chan->message.cursize = 0; chan->reliable_sequence ^= 1; } - // write the packet header +// write the packet header SZ_Init (&send, send_buf, sizeof(send_buf)); w1 = ( chan->outgoing_sequence & ~(1<<31) ) | (send_reliable<<31); w2 = ( chan->incoming_sequence & ~(1<<31) ) | (chan->incoming_reliable_sequence<<31); chan->outgoing_sequence++; - chan->last_sent = host.realtime * 1000; + chan->last_sent = curtime; MSG_WriteLong (&send, w1); MSG_WriteLong (&send, w2); @@ -297,9 +298,9 @@ bool Netchan_Process (netchan_t *chan, sizebuf_t *msg) { unsigned sequence, sequence_ack; unsigned reliable_ack, reliable_message; - int qport; + int qport; - // get sequence numbers +// get sequence numbers MSG_BeginReading (msg); sequence = MSG_ReadLong (msg); sequence_ack = MSG_ReadLong (msg); @@ -351,22 +352,22 @@ bool Netchan_Process (netchan_t *chan, sizebuf_t *msg) if (chan->dropped > 0) { if (showdrop->value) - Msg ("%s:Dropped %i packets at %i\n", - NET_AdrToString (chan->remote_address), - chan->dropped, - sequence); + Msg ("%s:Dropped %i packets at %i\n" + , NET_AdrToString (chan->remote_address) + , chan->dropped + , sequence); } - // - // if the current outgoing reliable message has been acknowledged - // clear the buffer to make way for the next - // +// +// if the current outgoing reliable message has been acknowledged +// clear the buffer to make way for the next +// if (reliable_ack == chan->reliable_sequence) chan->reliable_length = 0; // it has been received - // - // if this message contains a reliable message, bump incoming_reliable_sequence - // +// +// if this message contains a reliable message, bump incoming_reliable_sequence +// chan->incoming_sequence = sequence; chan->incoming_acknowledged = sequence_ack; chan->incoming_reliable_acknowledged = reliable_ack; @@ -375,10 +376,10 @@ bool Netchan_Process (netchan_t *chan, sizebuf_t *msg) chan->incoming_reliable_sequence ^= 1; } - // - // the message can now be read from the current message pointer - // - chan->last_received = host.realtime * 1000; +// +// the message can now be read from the current message pointer +// + chan->last_received = curtime; return true; } diff --git a/engine/common/net_msg.c b/engine/common/net_msg.c index a34d87fc..967b2304 100644 --- a/engine/common/net_msg.c +++ b/engine/common/net_msg.c @@ -536,37 +536,29 @@ void MSG_ReadData (sizebuf_t *msg_read, void *data, int len) ======================= */ -void _SZ_Init (sizebuf_t *buf, byte *data, int length, const char *filename, int fileline) +void SZ_Init (sizebuf_t *buf, byte *data, int length) { memset (buf, 0, sizeof(*buf)); - - if(buf == NULL) Sys_Error("SZ_Clear: sizebuf == NULL (called at %s:%i)\n", filename, fileline ); - if(data == NULL) Sys_Error("SZ_Init: data == NULL (called at %s:%i)\n", filename, fileline ); - if(length <= 0) Sys_Error("SZ_Init: length <= 0 (called at %s:%i)\n", filename, fileline ); - buf->data = data; buf->maxsize = length; } -void _SZ_Clear (sizebuf_t *buf, const char *filename, int fileline) +void SZ_Clear (sizebuf_t *buf) { - if(buf == NULL) Sys_Error("SZ_Clear: sizebuf == NULL (called at %s:%i)\n", filename, fileline ); - if(buf->overflowed) MsgWarn("SZ_Clear: clearing buffer was overflowed\n"); - buf->cursize = 0; buf->overflowed = false; } -void *_SZ_GetSpace (sizebuf_t *buf, int length, const char *filename, int fileline) +void *SZ_GetSpace (sizebuf_t *buf, int length) { void *data; if (buf->cursize + length > buf->maxsize) { if (length > buf->maxsize) - Sys_Error("SZ_GetSpace: buf->cursize[%d] + length[%d] > buf->maxsize[%d](called at %s:%i)\n", buf->cursize, length, buf->maxsize, filename, fileline ); + Com_Error (ERR_DROP, "SZ_GetSpace: %i is > full buffer size", length); - Msg ("SZ_GetSpace: overflow [cursize %d maxsize %d](called at %s:%i)\n", buf->cursize + length, buf->maxsize, filename, fileline ); + Msg ("SZ_GetSpace: overflow [cursize %d maxsize %d]\n", buf->cursize + length, buf->maxsize ); SZ_Clear (buf); buf->overflowed = true; } @@ -576,20 +568,20 @@ void *_SZ_GetSpace (sizebuf_t *buf, int length, const char *filename, int fileli return data; } -void _SZ_Write (sizebuf_t *buf, void *data, int length, const char *filename, int fileline) +void SZ_Write (sizebuf_t *buf, void *data, int length) { - pi->Mem.Copy(_SZ_GetSpace(buf, length, filename, fileline), data, length, filename, fileline); + Mem_Copy(SZ_GetSpace(buf, length), data, length); } -void _SZ_Print (sizebuf_t *buf, char *data, const char *filename, int fileline) +void SZ_Print (sizebuf_t *buf, char *data) { int len; len = strlen(data) + 1; if (buf->cursize) { - if (buf->data[buf->cursize - 1]) pi->Mem.Copy((byte *)_SZ_GetSpace(buf, len, filename, fileline), data, len, filename, fileline); // no trailing 0 - else pi->Mem.Copy((byte *)_SZ_GetSpace(buf, len - 1, filename, fileline) - 1, data, len, filename, fileline); // write over trailing 0 + if (buf->data[buf->cursize - 1]) Mem_Copy ((byte *)SZ_GetSpace(buf, len),data,len); //no trailing 0 + else Mem_Copy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0 } - else pi->Mem.Copy((byte *)_SZ_GetSpace(buf, len, filename, fileline), data, len, filename, fileline); + else Mem_Copy ((byte *)SZ_GetSpace(buf, len),data,len); } \ No newline at end of file diff --git a/engine/common/net_wins.c b/engine/common/net_wins.c index 9568022e..8d4fd6d5 100644 --- a/engine/common/net_wins.c +++ b/engine/common/net_wins.c @@ -367,9 +367,12 @@ bool NET_GetPacket (netsrc_t sock, netadr_t *net_from, sizebuf_t *net_message) continue; } - if (host.type == HOST_DEDICATED) // let dedicated servers continue after errors - Msg ("NET_GetPacket: %s from %s\n", NET_ErrorString(), NET_AdrToString(*net_from)); - else Com_Error (ERR_DROP, "NET_GetPacket: %s from %s", NET_ErrorString(), NET_AdrToString(*net_from)); + if (dedicated->value) // let dedicated servers continue after errors + Msg ("NET_GetPacket: %s from %s\n", NET_ErrorString(), + NET_AdrToString(*net_from)); + else + Com_Error (ERR_DROP, "NET_GetPacket: %s from %s", + NET_ErrorString(), NET_AdrToString(*net_from)); continue; } @@ -441,9 +444,10 @@ void NET_SendPacket (netsrc_t sock, int length, void *data, netadr_t to) if ((err == WSAEADDRNOTAVAIL) && ((to.type == NA_BROADCAST) || (to.type == NA_BROADCAST_IPX))) return; - if (host.type == HOST_DEDICATED) // let dedicated servers continue after errors + if (dedicated->value) // let dedicated servers continue after errors { - Msg ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), NET_AdrToString (to)); + Msg ("NET_SendPacket ERROR: %s to %s\n", NET_ErrorString(), + NET_AdrToString (to)); } else { @@ -529,10 +533,13 @@ NET_OpenIP void NET_OpenIP (void) { cvar_t *ip; - int port; + int port; + int dedicated; ip = Cvar_Get ("ip", "localhost", CVAR_NOSET); + dedicated = Cvar_VariableValue ("dedicated"); + if (!ip_sockets[NS_SERVER]) { port = Cvar_Get("ip_hostport", "0", CVAR_NOSET)->value; @@ -545,13 +552,12 @@ void NET_OpenIP (void) } } ip_sockets[NS_SERVER] = NET_IPSocket (ip->string, port); - if (!ip_sockets[NS_SERVER] && host.type == HOST_DEDICATED) - Sys_Error("Couldn't allocate dedicated server IP port"); + if (!ip_sockets[NS_SERVER] && dedicated) Sys_Error("Couldn't allocate dedicated server IP port"); } // dedicated servers don't need client ports - if (host.type == HOST_DEDICATED) return; + if (dedicated) return; if (!ip_sockets[NS_CLIENT]) { @@ -630,6 +636,9 @@ NET_OpenIPX void NET_OpenIPX (void) { int port; + int dedicated; + + dedicated = Cvar_VariableValue ("dedicated"); if (!ipx_sockets[NS_SERVER]) { @@ -646,7 +655,8 @@ void NET_OpenIPX (void) } // dedicated servers don't need client ports - if (host.type == HOST_DEDICATED) return; + if (dedicated) + return; if (!ipx_sockets[NS_CLIENT]) { @@ -671,7 +681,7 @@ NET_Config A single player game will only use the loopback code ==================== */ -void NET_Config (bool multiplayer) +void NET_Config (bool multiplayer) { int i; static bool old_config; @@ -709,26 +719,27 @@ void NET_Config (bool multiplayer) // sleeps msec or until net socket is ready void NET_Sleep(int msec) { - struct timeval timeout; - fd_set fdset; - int i = 0; + struct timeval timeout; + fd_set fdset; + extern cvar_t *dedicated; + int i; + + if (!dedicated || !dedicated->value) + return; // we're not a server, just run full speed - // we're not a server, just run full speed - if (host.type == HOST_NORMAL) return; FD_ZERO(&fdset); - - if (ip_sockets[NS_SERVER]) - { + i = 0; + if (ip_sockets[NS_SERVER]) { FD_SET(ip_sockets[NS_SERVER], &fdset); // network socket i = ip_sockets[NS_SERVER]; } - if (ipx_sockets[NS_SERVER]) - { + if (ipx_sockets[NS_SERVER]) { FD_SET(ipx_sockets[NS_SERVER], &fdset); // network socket - if (ipx_sockets[NS_SERVER] > i) i = ipx_sockets[NS_SERVER]; + if (ipx_sockets[NS_SERVER] > i) + i = ipx_sockets[NS_SERVER]; } timeout.tv_sec = msec/1000; - timeout.tv_usec = (msec%1000) * 1000; + timeout.tv_usec = (msec%1000)*1000; select(i+1, &fdset, NULL, NULL, &timeout); } diff --git a/engine/common/pmove.c b/engine/common/pmove.c index 06f21593..33a73f4a 100644 --- a/engine/common/pmove.c +++ b/engine/common/pmove.c @@ -312,7 +312,7 @@ void PM_Friction (void) { friction = pm_friction; control = speed < pm_stopspeed ? pm_stopspeed : speed; - drop += control*friction * pml.frametime; + drop += control*friction*pml.frametime; } // apply water friction @@ -1083,7 +1083,7 @@ void PM_ClampAngles (void) else if (pm->viewangles[PITCH] < 271 && pm->viewangles[PITCH] >= 180) pm->viewangles[PITCH] = 271; } - AngleVectorsRight (pm->viewangles, pml.forward, pml.right, pml.up); + AngleVectors (pm->viewangles, pml.forward, pml.right, pml.up); } /* @@ -1173,8 +1173,7 @@ void Pmove (pmove_t *pmove) // teleport pause stays exactly in place } else if (pm->s.pm_flags & PMF_TIME_WATERJUMP) - { - // waterjump has no control, but falls + { // waterjump has no control, but falls pml.velocity[2] -= pm->s.gravity * pml.frametime; if (pml.velocity[2] < 0) { // cancel as soon as we are falling down again @@ -1199,7 +1198,7 @@ void Pmove (pmove_t *pmove) angles[PITCH] = angles[PITCH] - 360; angles[PITCH] /= 3; - AngleVectorsRight (angles, pml.forward, pml.right, pml.up); + AngleVectors (angles, pml.forward, pml.right, pml.up); PM_AirMove (); } } diff --git a/engine/common/qmenu.c b/engine/common/qmenu.c index c1ccd1a0..9f5a29a7 100644 --- a/engine/common/qmenu.c +++ b/engine/common/qmenu.c @@ -116,13 +116,17 @@ void Field_Draw( menufield_s *f ) else offset = f->cursor; - if ((( int )( cls.realtime * 4.0f)) & 1 ) + if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 ) { - Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, f->generic.y + f->generic.parent->y, 11 ); + Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, + f->generic.y + f->generic.parent->y, + 11 ); } else { - Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, f->generic.y + f->generic.parent->y, ' ' ); + Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, + f->generic.y + f->generic.parent->y, + ' ' ); } } } @@ -385,11 +389,11 @@ void Menu_Draw( menuframework_s *menu ) { if ( item->flags & QMF_LEFT_JUSTIFY ) { - Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ((int)(cls.realtime * 5.0f) & 1 )); + Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) ); } else { - Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ((int)(cls.realtime * 5.0f) & 1 )); + Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) ); } } diff --git a/engine/engine.dsp b/engine/engine.dsp index 8d025685..627a8c59 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MT /W3 /GX /O2 /Ob0 /I "./" /I "prvm" /I "common" /I "server" /I "client" /I "../public" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MT /W3 /GX /O2 /Ob0 /I "./" /I "prvm" /I "common" /I "server" /I "client" /I "../public" /I "../platform/formats" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MTd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "prvm" /I "common" /I "server" /I "client" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c +# ADD CPP /nologo /MTd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "prvm" /I "common" /I "server" /I "client" /I "../public" /I "../platform/formats" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -91,7 +91,7 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 -# ADD LINK32 gdi32.lib winmm.lib kernel32.lib user32.lib wsock32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 winmm.lib wsock32.lib kernel32.lib user32.lib gdi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept # SUBTRACT LINK32 /incremental:no /map /nodefaultlib # Begin Custom Build TargetDir=\XASH3D\src_main\!source\temp\engine\!debug @@ -126,10 +126,6 @@ SOURCE=.\client\cl_fx.c # End Source File # Begin Source File -SOURCE=.\client\cl_game.c -# End Source File -# Begin Source File - SOURCE=.\client\cl_input.c # End Source File # Begin Source File @@ -278,6 +274,10 @@ SOURCE=.\server\sv_send.c # End Source File # Begin Source File +SOURCE=.\server\sv_spawn.c +# End Source File +# Begin Source File + SOURCE=.\server\sv_studio.c # End Source File # Begin Source File @@ -300,18 +300,6 @@ SOURCE=.\vid_dll.c SOURCE=.\vid_menu.c # End Source File -# Begin Source File - -SOURCE=.\prvm\vm_cmds.c -# End Source File -# Begin Source File - -SOURCE=.\prvm\vm_edict.c -# End Source File -# Begin Source File - -SOURCE=.\prvm\vm_exec.c -# End Source File # End Group # Begin Group "Header Files" @@ -350,10 +338,6 @@ SOURCE=.\common\cvar.h # End Source File # Begin Source File -SOURCE=.\prvm\edict.h -# End Source File -# Begin Source File - SOURCE=.\engine.h # End Source File # Begin Source File @@ -370,14 +354,6 @@ SOURCE=..\public\platform.h # End Source File # Begin Source File -SOURCE=.\prvm\progdefs.h -# End Source File -# Begin Source File - -SOURCE=.\prvm\progsvm.h -# End Source File -# Begin Source File - SOURCE=..\public\qfiles.h # End Source File # Begin Source File @@ -404,10 +380,6 @@ SOURCE=.\sound.h SOURCE=.\common\vid.h # End Source File -# Begin Source File - -SOURCE=.\prvm\vm_cmds.h -# End Source File # End Group # End Target # End Project diff --git a/engine/engine.h b/engine/engine.h index 3066d7f1..9982f147 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -21,7 +21,6 @@ #include "basemath.h" #include "qfiles.h" #include -#include "vprogs.h" #include "bspmodel.h" #include "const.h" #include "common.h" @@ -32,8 +31,6 @@ extern platform_exp_t *pi; extern byte *zonepool; extern jmp_buf abortframe; -extern int host_debug; - typedef enum { HOST_INIT, // initalize operations @@ -74,6 +71,8 @@ typedef struct host_parm_s extern host_parm_t host; +int Sys_Milliseconds (void); + bool _GetParmFromCmdLine( char *parm, char *out, size_t size ); #define GetParmFromCmdLine( parm, out ) _GetParmFromCmdLine( parm, out, sizeof(out)) @@ -117,7 +116,6 @@ filesystem manager #define FS_FileBase( x, y ) pi->Fs.FileBase( x, y ) #define FS_Find( x ) pi->Fs.Search( x, false ) #define FS_Printf pi->Fs.Printf -#define FS_Print pi->Fs.Print #define FS_Seek pi->Fs.Seek #define FS_Tell pi->Fs.Tell #define FS_Gets pi->Fs.Gets @@ -170,10 +168,4 @@ void Host_Init ( char *funcname, int argc, char **argv ); void Host_Main ( void ); void Host_Free ( void ); -// -// in_win.c -// -extern int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; - - #endif//ENGINE_H \ No newline at end of file diff --git a/engine/engine.plg b/engine/engine.plg deleted file mode 100644 index 89589b0b..00000000 --- a/engine/engine.plg +++ /dev/null @@ -1,89 +0,0 @@ - - -
-

Build Log

-

---------------------Configuration: engine - Win32 Debug-------------------- -

-

Command Lines

-Creating temporary file "C:\Temp\RSP89.tmp" with contents -[ -/nologo /MTd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "prvm" /I "common" /I "server" /I "client" /I "../public" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR"..\temp\engine\!debug/" /Fo"..\temp\engine\!debug/" /Fd"..\temp\engine\!debug/" /FD /c -"D:\XASH3D\src_main\!source\engine\server\sv_user.c" -] -Creating command line "cl.exe @C:\Temp\RSP89.tmp" -Creating temporary file "C:\Temp\RSP8A.tmp" with contents -[ -gdi32.lib winmm.lib kernel32.lib user32.lib wsock32.lib /nologo /subsystem:windows /dll /incremental:yes /pdb:"..\temp\engine\!debug/engine.pdb" /debug /machine:I386 /out:"..\temp\engine\!debug/engine.dll" /implib:"..\temp\engine\!debug/engine.lib" /pdbtype:sept -"\XASH3D\src_main\!source\temp\engine\!debug\cl_cin.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_ents.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_fx.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_game.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_input.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_inv.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_main.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_newfx.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_parse.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_pred.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_scrn.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_tent.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cl_view.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cmd.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cmodel.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\common.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\console.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\crc.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\cvar.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\host.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\in_win.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\keys.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\md4.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\menu.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\net_chan.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\net_msg.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\net_wins.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\pmove.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\qmenu.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\snd_dma.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\snd_mem.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\snd_mix.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\snd_win.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_ccmds.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_ents.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_game.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_init.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_main.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_phys.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_save.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_send.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_studio.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_user.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\sv_world.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\system.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\vid_dll.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\vid_menu.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\vm_cmds.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\vm_edict.obj" -"\XASH3D\src_main\!source\temp\engine\!debug\vm_exec.obj" -] -Creating command line "link.exe @C:\Temp\RSP8A.tmp" -Creating temporary file "C:\Temp\RSP8B.bat" with contents -[ -@echo off -copy \XASH3D\src_main\!source\temp\engine\!debug\engine.dll "D:\Xash3D\bin\engine.dll" -] -Creating command line "C:\Temp\RSP8B.bat" -Compiling... -sv_user.c -Linking... -

Output Window

-Performing Custom Build Step on \XASH3D\src_main\!source\temp\engine\!debug\engine.dll -‘Є®ЇЁа®ў ­® д ©«®ў: 1. - - - -

Results

-engine.dll - 0 error(s), 0 warning(s) -
- - diff --git a/engine/host.c b/engine/host.c index 9824d186..2a10e0c9 100644 --- a/engine/host.c +++ b/engine/host.c @@ -7,15 +7,14 @@ #include #include #include "engine.h" -#include "progsvm.h" -platform_exp_t *pi; // fundamental callbacks +platform_exp_t *pi; // fundamental callbacks host_parm_t host; // host parms byte *zonepool; int ActiveApp; - -// host params +bool Minimized; +extern uint sys_msg_time; void Key_Init (void); void SCR_EndLoadingPlaque (void); @@ -91,11 +90,10 @@ void Host_Init (char *funcname, int argc, char **argv) MsgDev(D_INFO, "------- Loading bin/engine.dll [%g] -------\n", ENGINE_VERSION ); - Cbuf_Init(); - Cmd_Init(); - Cvar_Init(); - Key_Init(); - PRVM_Init(); + Cbuf_Init (); + Cmd_Init (); + Cvar_Init (); + Key_Init (); // we need to add the early commands twice, because // a basedir or cddir needs to be set before execing @@ -113,17 +111,18 @@ void Host_Init (char *funcname, int argc, char **argv) Cmd_AddCommand ("error", Com_Error_f); host_speeds = Cvar_Get ("host_speeds", "0", 0); + log_stats = Cvar_Get ("log_stats", "0", 0); + developer = Cvar_Get ("developer", "0", 0); timescale = Cvar_Get ("timescale", "1", 0); fixedtime = Cvar_Get ("fixedtime", "0", 0); showtrace = Cvar_Get ("showtrace", "0", 0); + if(host.type == HOST_DEDICATED) dedicated = Cvar_Get ("dedicated", "1", CVAR_NOSET); + else dedicated = Cvar_Get ("dedicated", "0", CVAR_NOSET); s = va("%4.2f %s %s %s", VERSION, "x86", __DATE__, BUILDSTRING); Cvar_Get ("version", s, CVAR_SERVERINFO|CVAR_NOSET); - if (host.type == HOST_DEDICATED) - { - Cmd_AddCommand ("quit", Com_Quit); - } + if (dedicated->value) Cmd_AddCommand ("quit", Com_Quit); Sys_Init(); @@ -134,10 +133,10 @@ void Host_Init (char *funcname, int argc, char **argv) CL_Init(); // add + commands from command line - if (!Cbuf_AddLateCommands()) + if (!Cbuf_AddLateCommands ()) { // if the user didn't give any commands, run default action - if(host.type == HOST_NORMAL) Cbuf_AddText ("d1\n"); + if (!dedicated->value) Cbuf_AddText ("d1\n"); else Cbuf_AddText ("dedicated_start\n"); Cbuf_Execute (); } @@ -156,9 +155,34 @@ Host_Frame void Host_Frame (double time) { char *s; + static double time_before, time_between, time_after; if (setjmp (abortframe) ) return; // an ERR_DROP was thrown + if ( log_stats->modified ) + { + log_stats->modified = false; + if ( log_stats->value ) + { + if ( log_stats_file ) + { + FS_Close( log_stats_file ); + log_stats_file = 0; + } + log_stats_file = FS_Open( "stats.log", "w" ); + if ( log_stats_file ) + FS_Printf( log_stats_file, "entities,dlights,parts,frame time\n" ); + } + else + { + if ( log_stats_file ) + { + FS_Close( log_stats_file ); + log_stats_file = 0; + } + } + } + if (showtrace->value) { extern int c_traces, c_brush_traces; @@ -173,14 +197,32 @@ void Host_Frame (double time) do { s = Sys_ConsoleInput (); - if(s) Cbuf_AddText (va("%s\n",s)); + if (s) Cbuf_AddText (va("%s\n",s)); } while (s); Cbuf_Execute (); - + + if (host_speeds->value) time_before = Sys_DoubleTime(); + SV_Frame (time); + + if (host_speeds->value) time_between = Sys_DoubleTime(); + CL_Frame (time); - host.framecount++; + if (host_speeds->value) time_after = Sys_DoubleTime(); + if (host_speeds->value) + { + double all, sv, gm, cl, rf; + + all = time_after - time_before; + sv = time_between - time_before; + cl = time_after - time_between; + gm = time_after_game - time_before_game; + rf = time_after_ref - time_before_ref; + sv -= gm; + cl -= rf; + Msg ("all:%.3f sv:%.3f gm:%.3f cl:%.3f rf:%.3f\n", all, sv, gm, cl, rf); + } } /* @@ -190,38 +232,36 @@ Host_Main */ void Host_Main( void ) { - MSG msg; - static double oldtime, newtime; + MSG msg; + int time, oldtime, newtime; - host.state = HOST_FRAME; - oldtime = Sys_DoubleTime(); //first call + oldtime = Sys_Milliseconds (); // main window message loop - while (host.type != HOST_OFFLINE) + while (1) { // if at a full screen console, don't update unless needed - if (host.type == HOST_DEDICATED ) + if (Minimized || (dedicated && dedicated->value) ) { - Sleep( 1 ); + Sleep (1); } - else if(host.state == HOST_SLEEP) Sleep( 100 ); - + while (PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) { if (!GetMessage (&msg, NULL, 0, 0)) Com_Quit (); - host.sv_timer = msg.time; + sys_msg_time = msg.time; TranslateMessage (&msg); DispatchMessage (&msg); } - do { - newtime = Sys_DoubleTime(); - host.realtime = newtime - oldtime; + newtime = Sys_Milliseconds (); + time = newtime - oldtime; + } while (time < 1); - } while (host.realtime < 0.001); + _controlfp( _PC_24, _MCW_PC ); + Host_Frame (time); - Host_Frame (host.realtime); oldtime = newtime; } } @@ -234,9 +274,6 @@ Host_Shutdown */ void Host_Free (void) { - host.state = HOST_SHUTDOWN; - - SV_Shutdown ("Server shutdown\n", false); CL_Shutdown (); Host_FreePlatform(); } \ No newline at end of file diff --git a/engine/in_win.c b/engine/in_win.c index 85313429..286e9837 100644 --- a/engine/in_win.c +++ b/engine/in_win.c @@ -24,7 +24,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "engine.h" #include "./client/client.h" +extern unsigned sys_msg_time; extern HWND cl_hwnd; +extern bool ActiveApp, Minimized; // joystick defines and variables // where should defines be moved? @@ -249,13 +251,13 @@ void IN_MouseEvent (int mstate) if ( (mstate & (1<fields.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 *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] - - prvm_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)(prvm_edict_t *edict); // [INIT] used by PRVM_ED_ClearEdict - void (*free_edict)(prvm_edict_t *ed); // [INIT] used by PRVM_ED_Free - - void (*count_edicts)(void); // [INIT] used by PRVM_ED_Count_f - - bool (*load_edict)(prvm_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); - -prvm_edict_t *PRVM_ED_Alloc (void); -void PRVM_ED_Free (prvm_edict_t *ed); -void PRVM_ED_ClearEdict (prvm_edict_t *e); - -void PRVM_PrintFunctionStatements (const char *name); -void PRVM_ED_Print(prvm_edict_t *ed); -void PRVM_ED_Write (file_t *f, prvm_edict_t *ed); -const char *PRVM_ED_ParseEdict (const char *data, prvm_edict_t *ent); - -void PRVM_ED_WriteGlobals (file_t *f); -void PRVM_ED_ParseGlobals (const char *data); - -void PRVM_ED_LoadFromFile (const char *data); - -prvm_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)((prvm_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_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->fields.vp)[o]) -#define PRVM_E_INT(e,o) (((int*)e->fields.vp)[o]) -//#define PRVM_E_VECTOR(e,o) (&((float*)e->fields.vp)[o]) -#define PRVM_E_STRING(e,o) (PRVM_GetString(*(string_t *)&((float*)e->fields.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/prvm/vm_cmds.c b/engine/prvm/vm_cmds.c deleted file mode 100644 index aa49fd43..00000000 --- a/engine/prvm/vm_cmds.c +++ /dev/null @@ -1,3155 +0,0 @@ -// 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 renderer_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) -{ - prvm_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) -{ - prvm_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 fields -> 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; - prvm_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); - - strlcpy(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) -{ - prvm_edict_t *ed; - prog->xfunction->builtinsprofile += 20; - ed = PRVM_ED_Alloc(); - VM_RETURN_EDICT(ed); -} - -/* -========= -VM_remove - -remove(entity e) -========= -*/ - -void VM_remove (void) -{ - prvm_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); -// if (ed == prog->edicts) -// PRVM_ERROR ("remove: tried to remove world"); -// if (PRVM_NUM_FOR_EDICT(ed) <= sv.maxclients) -// Host_Error("remove: tried to remove a client"); -} - -/* -========= -VM_find - -entity find(entity start, .string field, string match) -========= -*/ - -void VM_find (void) -{ - int e; - int f; - const char *s, *t; - prvm_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; - prvm_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; - prvm_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; - prvm_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 = (prvm_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; - prvm_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; - prvm_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 = (prvm_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; - prvm_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) -{ - prvm_edict_t *in, *out; - VM_SAFEPARMCOUNT(2,VM_copyentity); - in = PRVM_G_EDICT(OFS_PARM0); - out = PRVM_G_EDICT(OFS_PARM1); - memcpy(out->fields.vp, in->fields.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) -{ - prvm_edict_t *e = PRVM_G_EDICT(OFS_PARM0); - prvm_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->fields.server->modelindex; - if (modelindex >= 0 && modelindex < MAX_MODELS) - { - model = sv.models[modelindex]; - if (model->data_overridetagnamesforskin && (unsigned int)tagentity->fields.server->skin < (unsigned int)model->numskins && model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames) - for (i = 0;i < model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.server->skin].num_overridetagnames;i++) - if (!strcmp(tagname, model->data_overridetagnamesforskin[(unsigned int)tagentity->fields.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) -{ - prvm_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(); - strlcpy(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(); - - strlcpy(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; - } - - strlcpy(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++ = '\''; - - strlcpy(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; - strlcat(k, b->strings[i], VM_STRINGTEMP_LENGTH); - if(sep && (i != b->num_strings-1)) - { - l += strlen(sep); - if(l>=4095) - break; - strlcat(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/prvm/vm_cmds.h b/engine/prvm/vm_cmds.h deleted file mode 100644 index 1d74e23a..00000000 --- a/engine/prvm/vm_cmds.h +++ /dev/null @@ -1,343 +0,0 @@ -// 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/prvm/vm_edict.c b/engine/prvm/vm_edict.c deleted file mode 100644 index 7fca6791..00000000 --- a/engine/prvm/vm_edict.c +++ /dev/null @@ -1,1944 +0,0 @@ -/* -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(prvm_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(edict_state_t)); - - // alloc edicts - prog->edicts = (prvm_edict_t *)Mem_Alloc(prog->progs_mempool, prog->limit_edicts * sizeof(prvm_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 = (edict_state_t *)((byte *)prog->edictprivate + i * prog->edictprivate_size); - prog->edicts[i].fields.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 = (edict_state_t *)((byte *)prog->edictprivate + i * prog->edictprivate_size); - prog->edicts[i].fields.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 (prvm_edict_t *e) -{ - memset (e->fields.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. -================= -*/ -prvm_edict_t *PRVM_ED_Alloc (void) -{ - int i; - prvm_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 (prvm_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: - strlcpy (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; - strlcpy (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(prvm_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->fields.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; - } - strlcat(tempstring, name, sizeof(tempstring)); - for (l = strlen(name);l < 14;l++) - strlcat(tempstring, " ", sizeof(tempstring)); - strlcat(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; - } - strlcat(tempstring, name, sizeof(tempstring)); - strlcat(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, prvm_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->fields.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; - prvm_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(prvm_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->fields.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->fields.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) -{ - prvm_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, prvm_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) -{ - prvm_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->fields.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->fields.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 prvm_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; - prvm_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->fields.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: - strlcat(tempstring, "string ", sizeof(tempstring)); - break; - case ev_entity: - strlcat(tempstring, "entity ", sizeof(tempstring)); - break; - case ev_function: - strlcat(tempstring, "function ", sizeof(tempstring)); - break; - case ev_field: - strlcat(tempstring, "field ", sizeof(tempstring)); - break; - case ev_void: - strlcat(tempstring, "void ", sizeof(tempstring)); - break; - case ev_float: - strlcat(tempstring, "float ", sizeof(tempstring)); - break; - case ev_vector: - strlcat(tempstring, "vector ", sizeof(tempstring)); - break; - case ev_pointer: - strlcat(tempstring, "pointer ", sizeof(tempstring)); - break; - default: - sprintf (tempstring2, "bad type %i ", d->type & ~DEF_SAVEGLOBAL); - strlcat(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; - } - strlcat(tempstring, name, sizeof(tempstring)); - for (j = (int)strlen(name);j < 25;j++) - strlcat(tempstring, " ", sizeof(tempstring)); - sprintf(tempstring2, "%5d", counts[i]); - strlcat(tempstring, tempstring2, sizeof(tempstring)); - strlcat(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); - - Com_Error (ERR_DROP, "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 pi->Mem.Alloc(prog->progs_mempool, buffersize, filename, fileline); -} - -void _PRVM_Free(void *buffer, const char *filename, int fileline) -{ - pi->Mem.Free(buffer, filename, fileline); -} - -void _PRVM_FreeAll(const char *filename, int fileline) -{ - prog->progs = NULL; - prog->fielddefs = NULL; - prog->functions = NULL; - pi->Mem.EmptyPool(prog->progs_mempool, filename, fileline); -} - -// LordHavoc: turned PRVM_EDICT_NUM into a #define for speed reasons -prvm_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/prvm/vm_exec.c b/engine/prvm/vm_exec.c deleted file mode 100644 index ef14f3dd..00000000 --- a/engine/prvm/vm_exec.c +++ /dev/null @@ -1,1120 +0,0 @@ -/* -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; - prvm_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); - } - - 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->fields.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->fields.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->fields.vp + OPB->_int))->vector[0]; - OPC->vector[1] = ((prvm_eval_t *)((int *)ed->fields.vp + OPB->_int))->vector[1]; - OPC->vector[2] = ((prvm_eval_t *)((int *)ed->fields.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->fields.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->fields.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/server/ref_server.h b/engine/server/ref_server.h new file mode 100644 index 00000000..f0064f5f --- /dev/null +++ b/engine/server/ref_server.h @@ -0,0 +1,191 @@ + +// 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 5232e728..249146a2 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -18,16 +18,24 @@ 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 "progsvm.h" -#include "vm_cmds.h" +#include "ref_server.h" //============================================================================= +typedef struct +{ + gclient_t *clients; // [maxclients] + + int maxclients; + int maxentities; + + bool autosaved; +} game_locals_t; + #define MAX_MASTERS 8 // max recipients for heartbeat packets typedef enum { @@ -45,18 +53,14 @@ typedef struct { 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 + + unsigned time; // always sv.framenum * 100 msec + int framenum; - float time; // always sv.framenum * 0.1 sec - float frametime; - float lastchecktime; - int framenum; - - int lastcheck; - char name[MAX_QPATH]; // map name, or cinematic name - cmodel_t *models[MAX_MODELS]; + struct cmodel_s *models[MAX_MODELS]; char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]; entity_state_t baselines[MAX_EDICTS]; @@ -66,20 +70,23 @@ typedef struct sizebuf_t multicast; byte multicast_buf[MAX_MSGLEN]; - prvm_edict_t **moved_edicts; - // demo server information file_t *demofile; - bool timedemo; // don't time sync + bool timedemo; // don't time sync + + byte *mempool; } 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_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 + cs_spawned // client is fully in game } client_state_t; typedef struct @@ -92,52 +99,49 @@ typedef struct int senttime; // for ping calculations } client_frame_t; -#define NUM_SPAWN_PARMS 16 #define LATENCY_COUNTS 16 #define RATE_MESSAGES 10 typedef struct client_s { - client_state_t state; + client_state_t state; char userinfo[MAX_INFO_STRING]; // name, etc - int lastframe; // for delta compression - usercmd_t lastcmd; // for filling in big drops + 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 + int commandMsec; // every seconds this is reset, if user + // commands exhaust it, assume time cheating - int frame_latency[LATENCY_COUNTS]; - int ping; + int frame_latency[LATENCY_COUNTS]; + int ping; - int message_size[RATE_MESSAGES]; // used to rate drop packets - int rate; - int surpressCount; // number of messages rate supressed + int message_size[RATE_MESSAGES]; // used to rate drop packets + int rate; + int surpressCount; // number of messages rate supressed - float spawn_parms[NUM_SPAWN_PARMS]; // quake 1 legacy - - prvm_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 + int messagelevel; // for filtering printed messages // The datagram is written to by sound calls, prints, temp ents, etc. // It can be harmlessly overflowed. - sizebuf_t datagram; + sizebuf_t datagram; byte datagram_buf[MAX_MSGLEN]; - client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here + client_frame_t frames[UPDATE_BACKUP]; // updates can be delta'd from here byte *download; // file being downloaded - int downloadsize; // total bytes (can't use EOF because of paks) - int downloadcount; // bytes sent + 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 lastmessage; // sv.framenum when packet was last received + int lastconnect; - int challenge; // challenge of this user, randomly generated + int challenge; // challenge of this user, randomly generated - netchan_t netchan; + netchan_t netchan; } client_t; // a client can leave the server in one of four ways: @@ -164,9 +168,7 @@ typedef struct typedef struct { bool initialized; // sv_init has completed - double realtime; // always increasing, no clamping, etc - - int serverflags; + int 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. @@ -174,12 +176,12 @@ typedef struct int spawncount; // incremented each server start // used to check late spawns - client_t *clients; // [host.maxclients]; - int num_client_entities; // host.maxclients * UPDATE_BACKUP * MAX_PACKET_ENTITIES + 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] - float last_heartbeat; + int last_heartbeat; challenge_t challenges[MAX_CHALLENGES]; // to prevent invalid IPs from connecting @@ -189,17 +191,6 @@ typedef struct byte demo_multicast_buf[MAX_MSGLEN]; } server_static_t; -typedef struct -{ - vec3_t boxmins, boxmaxs; // enclose the test object along entire move - float *mins, *maxs; // size of the moving object - vec3_t mins2, maxs2; // size when clipping against mosnters - float *start, *end; - trace_t trace; - prvm_edict_t *passedict; - int contentmask; -} moveclip_t; - //============================================================================= extern netadr_t net_from; @@ -211,13 +202,17 @@ 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_airaccelerate; // don't reload level state when reentering +extern cvar_t *sv_maxvelocity; +extern cvar_t *sv_gravity; // development tool extern cvar_t *sv_enforcetime; -extern client_t *sv_client; -extern prvm_edict_t *sv_player; +extern client_t *sv_client; +extern edict_t *sv_player; +extern game_locals_t game; //=========================================================== @@ -227,9 +222,9 @@ extern prvm_edict_t *sv_player; void SV_FinalMessage (char *message, bool reconnect); void SV_DropClient (client_t *drop); -int SV_ModelIndex (const char *name); -int SV_SoundIndex (const char *name); -int SV_ImageIndex (const char *name); +int SV_ModelIndex (char *name); +int SV_SoundIndex (char *name); +int SV_ImageIndex (char *name); void SV_WriteClientdataToMessage (client_t *client, sizebuf_t *msg); @@ -248,16 +243,15 @@ void Master_Packet (void); // void SV_InitGame (void); void SV_Map (bool attractloop, char *levelstring, char *savename, bool loadgame); -void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_state_t serverstate, bool attractloop, bool loadgame); -void SV_VM_Setup(void); -void SV_VM_Begin(void); -void SV_VM_End(void); + // // sv_phys.c // void SV_PrepWorldFrame (void); -void SV_Physics (void); +void SV_Physics (edict_t *ent); +void SV_DropToFloor (edict_t *ent); +void SV_CheckGround (edict_t *ent); // // sv_send.c @@ -271,7 +265,7 @@ void SV_FlushRedirect (int sv_redirected, char *outputbuf); void SV_DemoCompleted (void); void SV_SendClientMessages (void); -void SV_StartSound (vec3_t origin, prvm_edict_t *entity, int channel, +void SV_StartSound (vec3_t origin, edict_t *entity, int channel, int soundindex, float volume, float attenuation, float timeofs); void SV_ClientPrintf (client_t *cl, int level, char *fmt, ...); @@ -283,8 +277,6 @@ void SV_BroadcastCommand (char *fmt, ...); // void SV_Nextserver (void); void SV_ExecuteClientMessage (client_t *cl); -void SV_ApplyClientMove (void); -void SV_ClientThink (void); // // sv_ccmds.c @@ -297,19 +289,50 @@ 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, ...); -void SV_InitEdict (prvm_edict_t *e); + +// +// 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); // // sv_studio.c // -byte *SV_GetModelPtr(prvm_edict_t *ent); +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); +edict_t *SV_Spawn (void); +void SV_RunFrame (void); +void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo); +bool SV_ClientConnect (edict_t *ent, char *userinfo); +void SV_ClientBegin (edict_t *ent); +void ClientThink (edict_t *ent, usercmd_t *ucmd); +void SV_ClientDisconnect (edict_t *ent); +void SV_ClientCommand (edict_t *ent); +void SV_TouchTriggers (edict_t *ent); // // sv_save.c @@ -327,18 +350,18 @@ void SV_ReadLevelFile( char *name ); void SV_ClearWorld (void); // called after the world model has been loaded, before linking any entities -void SV_UnlinkEdict (prvm_edict_t *ent); +void SV_UnlinkEdict (edict_t *ent); // call before removing an entity, and before trying to move one, // so it doesn't clip against itself -void SV_LinkEdict (prvm_edict_t *ent); +void SV_LinkEdict (edict_t *ent); // Needs to be called any time an entity changes origin, mins, maxs, // or solid. Automatically unlinks if needed. // sets ent->v.absmin and ent->v.absmax // sets ent->leafnums[] for pvs determination even if the entity // is not solid -int SV_AreaEdicts (vec3_t mins, vec3_t maxs, prvm_edict_t **list, int maxcount, int areatype); +int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); // fills in a table of edict pointers with edicts that have bounding boxes // that intersect the given area. It is possible for a non-axial bmodel // to be returned that doesn't actually intersect the area on an exact @@ -356,10 +379,7 @@ int SV_PointContents (vec3_t p); // Quake 2 extends this to also check entities, to allow moving liquids -trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, prvm_edict_t *passedict, int contentmask); -trace_t SV_TraceToss (prvm_edict_t *tossent, prvm_edict_t *ignore); -trace_t SV_ClipMoveToEntity(prvm_edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask); - +trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask); // mins and maxs are relative // if the entire move stays in a solid volume, trace.allsolid will be set, @@ -368,6 +388,4 @@ trace_t SV_ClipMoveToEntity(prvm_edict_t *ent, vec3_t start, vec3_t mins, vec3_t // 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) - -#endif//SERVER_H \ No newline at end of file +// passedict is explicitly excluded from clipping checks (normally NULL) \ No newline at end of file diff --git a/engine/server/sv_ccmds.c b/engine/server/sv_ccmds.c index 3ed695fe..b21e666b 100644 --- a/engine/server/sv_ccmds.c +++ b/engine/server/sv_ccmds.c @@ -43,7 +43,7 @@ void SV_SetMaster_f (void) int i, slot; // only dedicated servers send heartbeats - if (host.type == HOST_NORMAL) + if (!dedicated->value) { Msg ("Only dedicated servers use masters.\n"); return; @@ -52,11 +52,11 @@ void SV_SetMaster_f (void) // make sure the server is listed public Cvar_Set ("public", "1"); - for (i = 1; i < MAX_MASTERS; i++) memset (&master_adr[i], 0, sizeof(master_adr[i])); + for (i=1 ; i= '0' && s[0] <= '9') { idnum = atoi(Cmd_Argv(1)); - if (idnum < 0 || idnum >= host.maxclients) + if (idnum < 0 || idnum >= maxclients->value) { Msg ("Bad client slot: %i\n", idnum); return false; @@ -123,7 +123,7 @@ bool SV_SetPlayer (void) } // check for a name match - for (i=0,cl=svs.clients ; i < host.maxclients; i++,cl++) + for (i=0,cl=svs.clients ; ivalue; i++,cl++) { if (!cl->state) continue; @@ -192,18 +192,18 @@ void SV_GameMap_f (void) // clear all the client inuse 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(host.maxclients * sizeof(bool)); - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) + savedInuse = Z_Malloc(maxclients->value * sizeof(bool)); + for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { - savedInuse[i] = cl->edict->priv.sv->free; - cl->edict->priv.sv->free = true; + savedInuse[i] = cl->edict->inuse; + cl->edict->inuse = false; } SV_WriteSaveFile( "save0" ); //autosave // we must restore these for clients to transfer over correctly - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) - cl->edict->priv.sv->free = savedInuse[i]; + for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) + cl->edict->inuse = savedInuse[i]; Z_Free (savedInuse); } } @@ -225,28 +225,23 @@ For development work */ void SV_Map_f (void) { - char level_path[MAX_QPATH]; + char *map; + char expanded[MAX_QPATH]; - sprintf(level_path, "maps/%s", Cmd_Argv(1)); - FS_DefaultExtension(level_path, ".bsp" ); - - if (FS_FileExists(level_path)) + // if not a pcx, demo, or cinematic, check to make sure the level exists + map = Cmd_Argv(1); + if (!strstr (map, ".")) { - sv.state = ss_dead; // don't save current level when changing - - SV_InitGame (); - Cvar_Set ("nextserver", ""); //reset demoloop - - SCR_BeginLoadingPlaque (); // for local system - SV_BroadcastCommand ("changing\n"); - - SV_SendClientMessages (); - SV_SpawnServer (level_path, NULL, NULL, ss_game, false, false); - Cbuf_CopyToDefer (); -//FIXME//SV_BroadcastCommand ("reconnect\n"); - strncpy (svs.mapcmd, Cmd_Argv(1), sizeof(svs.mapcmd) - 1); // archive server state + sprintf (expanded, "maps/%s.bsp", map); + if (!FS_LoadFile (expanded, NULL)) + { + Msg ("Can't find %s\n", expanded); + return; + } } - else Msg ("Can't loading %s\n", level_path); + + sv.state = ss_dead; // don't save current level when changing + SV_GameMap_f (); } /* @@ -314,7 +309,7 @@ void SV_Savegame_f (void) return; } - if (host.maxclients == 1 && svs.clients[0].edict->priv.sv->client->stats[STAT_HEALTH] <= 0) + if (maxclients->value == 1 && svs.clients[0].edict->client->ps.stats[STAT_HEALTH] <= 0) { Msg ("\nCan't savegame while dead!\n"); return; @@ -382,11 +377,11 @@ void SV_Status_f (void) Msg ("num score ping name lastmsg address qport \n"); Msg ("--- ----- ---- --------------- ------- --------------------- ------\n"); - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) + for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { if (!cl->state) continue; Msg ("%3i ", i); - Msg ("%5i ", cl->edict->priv.sv->client->stats[STAT_FRAGS]); + Msg ("%5i ", cl->edict->client->ps.stats[STAT_FRAGS]); if (cl->state == cs_connected) Msg ("CNCT "); @@ -403,7 +398,7 @@ void SV_Status_f (void) for (j=0 ; jlastmessage ); + Msg ("%7i ", svs.realtime - cl->lastmessage ); s = NET_AdrToString ( cl->netchan.remote_address); Msg ("%s", s); @@ -444,7 +439,7 @@ void SV_ConSay_f(void) strcat(text, p); - for (j = 0, client = svs.clients; j < host.maxclients; j++, client++) + for (j = 0, client = svs.clients; j < maxclients->value; j++, client++) { if (client->state != cs_spawned) continue; @@ -622,6 +617,22 @@ void SV_KillServer_f (void) NET_Config ( false ); // close network sockets } +/* +=============== +SV_ServerCommand_f + +Let the game dll handle a command +=============== +*/ +void SV_ServerCommand_f (void) +{ + if (!ge) + { + Msg ("No game loaded.\n"); + return; + } +} + //=========================================================== /* @@ -642,15 +653,13 @@ void SV_InitOperatorCommands (void) Cmd_AddCommand ("gamemap", SV_GameMap_f); Cmd_AddCommand ("setmaster", SV_SetMaster_f); - if (host.type == HOST_DEDICATED) - { - Cmd_AddCommand ("say", SV_ConSay_f); - } + if ( dedicated->value ) Cmd_AddCommand ("say", SV_ConSay_f); Cmd_AddCommand ("serverrecord", SV_ServerRecord_f); Cmd_AddCommand ("serverstop", SV_ServerStop_f); Cmd_AddCommand ("save", SV_Savegame_f); Cmd_AddCommand ("load", SV_Loadgame_f); Cmd_AddCommand ("killserver", SV_KillServer_f); + Cmd_AddCommand ("sv", SV_ServerCommand_f); } diff --git a/engine/server/sv_ents.c b/engine/server/sv_ents.c index d2a63912..7780d0b3 100644 --- a/engine/server/sv_ents.c +++ b/engine/server/sv_ents.c @@ -34,11 +34,11 @@ Encode a client frame onto the network channel // because there can be a lot of projectiles, there is a special // network protocol for them #define MAX_PROJECTILES 64 -prvm_edict_t *projectiles[MAX_PROJECTILES]; +edict_t *projectiles[MAX_PROJECTILES]; int numprojs; cvar_t *sv_projectiles; -bool SV_AddProjectileUpdate (prvm_edict_t *ent) +bool SV_AddProjectileUpdate (edict_t *ent) { if (!sv_projectiles) sv_projectiles = Cvar_Get("sv_projectiles", "1", 0); @@ -59,7 +59,7 @@ void SV_EmitProjectileUpdate (sizebuf_t *msg) { byte bits[16]; // [modelindex] [48 bits] xyz p y 12 12 12 8 8 [entitynum] [e2] int n, i; - prvm_edict_t *ent; + edict_t *ent; int x, y, z, p, yaw; int len; @@ -157,31 +157,29 @@ void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t } if (newnum == oldnum) - { - // delta update from old position + { // delta update from old position // because the force parm is false, this will not result // in any bytes being emited if the entity has not changed at all // note that players are always 'newentities', this updates their oldorigin always // and prevents warping - MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= host.maxclients); + MSG_WriteDeltaEntity (oldent, newent, msg, false, newent->number <= maxclients->value); oldindex++; newindex++; continue; } if (newnum < oldnum) - { - // this is a new entity, send it from the baseline + { // this is a new entity, send it from the baseline MSG_WriteDeltaEntity (&sv.baselines[newnum], newent, msg, true, true); newindex++; continue; } if (newnum > oldnum) - { - // the old entity isn't present in the new message + { // the old entity isn't present in the new message bits = U_REMOVE; - if (oldnum >= 256) bits |= U_NUMBER16 | U_MOREBITS1; + if (oldnum >= 256) + bits |= U_NUMBER16 | U_MOREBITS1; MSG_WriteByte (msg, bits&255 ); if (bits & 0x0000ff00) @@ -201,6 +199,11 @@ void SV_EmitPacketEntities (client_frame_t *from, client_frame_t *to, sizebuf_t } MSG_WriteShort (msg, 0); // end of packetentities + +#if 0 + if (numprojs) + SV_EmitProjectileUpdate(msg); +#endif } @@ -228,32 +231,86 @@ void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, size else ops = &from->ps; // determine what needs to be sent - if (ps->pmove.pm_type != ops->pmove.pm_type) pflags |= PS_M_TYPE; - if (!VectorICompare(ps->pmove.origin, ops->pmove.origin)) pflags |= PS_M_ORIGIN; - if (!VectorICompare(ps->pmove.velocity, ops->pmove.velocity)) pflags |= PS_M_VELOCITY; - if (ps->pmove.pm_time != ops->pmove.pm_time) pflags |= PS_M_TIME; - if (ps->pmove.pm_flags != ops->pmove.pm_flags) pflags |= PS_M_FLAGS; - if (ps->pmove.gravity != ops->pmove.gravity) pflags |= PS_M_GRAVITY; - if (!VectorICompare(ps->pmove.delta_angles, ops->pmove.delta_angles)) pflags |= PS_M_DELTA_ANGLES; - if (!VectorCompare(ps->viewoffset, ops->viewoffset)) pflags |= PS_VIEWOFFSET; - if (!VectorCompare(ps->viewangles, ops->viewangles)) pflags |= PS_VIEWANGLES; - if (!VectorCompare(ps->kick_angles, ops->kick_angles)) pflags |= PS_KICKANGLES; - if (!VectorCompare(ps->blend, ops->blend)) pflags |= PS_BLEND; - if (ps->fov != ops->fov) pflags |= PS_FOV; - if (ps->rdflags != ops->rdflags) pflags |= PS_RDFLAGS; - if (ps->gunframe != ops->gunframe) pflags |= PS_WEAPONFRAME; - if (ps->sequence != ops->sequence) pflags |= PS_WEAPONSEQUENCE; - if (ps->gunbody != ops->gunbody) pflags |= PS_WEAPONBODY; - if (ps->gunskin != ops->gunskin) pflags |= PS_WEAPONSKIN; + if (ps->pmove.pm_type != ops->pmove.pm_type) + pflags |= PS_M_TYPE; + + if (ps->pmove.origin[0] != ops->pmove.origin[0] + || ps->pmove.origin[1] != ops->pmove.origin[1] + || ps->pmove.origin[2] != ops->pmove.origin[2] ) + pflags |= PS_M_ORIGIN; + + if (ps->pmove.velocity[0] != ops->pmove.velocity[0] + || ps->pmove.velocity[1] != ops->pmove.velocity[1] + || ps->pmove.velocity[2] != ops->pmove.velocity[2] ) + pflags |= PS_M_VELOCITY; + + if (ps->pmove.pm_time != ops->pmove.pm_time) + pflags |= PS_M_TIME; + + if (ps->pmove.pm_flags != ops->pmove.pm_flags) + pflags |= PS_M_FLAGS; + + if (ps->pmove.gravity != ops->pmove.gravity) + pflags |= PS_M_GRAVITY; + + if (ps->pmove.delta_angles[0] != ops->pmove.delta_angles[0] + || ps->pmove.delta_angles[1] != ops->pmove.delta_angles[1] + || ps->pmove.delta_angles[2] != ops->pmove.delta_angles[2] ) + pflags |= PS_M_DELTA_ANGLES; + + + if (ps->viewoffset[0] != ops->viewoffset[0] + || ps->viewoffset[1] != ops->viewoffset[1] + || ps->viewoffset[2] != ops->viewoffset[2] ) + pflags |= PS_VIEWOFFSET; + + if (ps->viewangles[0] != ops->viewangles[0] + || ps->viewangles[1] != ops->viewangles[1] + || ps->viewangles[2] != ops->viewangles[2] ) + pflags |= PS_VIEWANGLES; + + if (ps->kick_angles[0] != ops->kick_angles[0] + || ps->kick_angles[1] != ops->kick_angles[1] + || ps->kick_angles[2] != ops->kick_angles[2] ) + pflags |= PS_KICKANGLES; + + if (ps->blend[0] != ops->blend[0] + || ps->blend[1] != ops->blend[1] + || ps->blend[2] != ops->blend[2] + || ps->blend[3] != ops->blend[3] ) + pflags |= PS_BLEND; + + if (ps->fov != ops->fov) + pflags |= PS_FOV; + + if (ps->rdflags != ops->rdflags) + pflags |= PS_RDFLAGS; + + if (ps->gunframe != ops->gunframe) + pflags |= PS_WEAPONFRAME; + + if (ps->sequence != ops->sequence) + pflags |= PS_WEAPONSEQUENCE; + + if (ps->gunbody != ops->gunbody) + pflags |= PS_WEAPONBODY; + + if (ps->gunskin != ops->gunskin) + pflags |= PS_WEAPONSKIN; pflags |= PS_WEAPONINDEX; + // // write it + // MSG_WriteByte (msg, svc_playerinfo); MSG_WriteLong (msg, pflags); + // // write the pmove_state_t - if (pflags & PS_M_TYPE) MSG_WriteByte (msg, ps->pmove.pm_type); + // + if (pflags & PS_M_TYPE) + MSG_WriteByte (msg, ps->pmove.pm_type); if (pflags & PS_M_ORIGIN) { @@ -269,9 +326,14 @@ void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, size MSG_WriteShort (msg, ps->pmove.velocity[2]); } - if (pflags & PS_M_TIME) MSG_WriteByte (msg, ps->pmove.pm_time); - if (pflags & PS_M_FLAGS) MSG_WriteByte (msg, ps->pmove.pm_flags); - if (pflags & PS_M_GRAVITY) MSG_WriteShort (msg, ps->pmove.gravity); + if (pflags & PS_M_TIME) + MSG_WriteByte (msg, ps->pmove.pm_time); + + if (pflags & PS_M_FLAGS) + MSG_WriteByte (msg, ps->pmove.pm_flags); + + if (pflags & PS_M_GRAVITY) + MSG_WriteShort (msg, ps->pmove.gravity); if (pflags & PS_M_DELTA_ANGLES) { @@ -280,7 +342,9 @@ void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, size MSG_WriteShort (msg, ps->pmove.delta_angles[2]); } + // // write the rest of the player_state_t + // if (pflags & PS_VIEWOFFSET) { MSG_WriteChar (msg, ps->viewoffset[0] * 4); @@ -302,7 +366,11 @@ void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, size MSG_WriteChar (msg, ps->kick_angles[2] * 4); } - if (pflags & PS_WEAPONINDEX) MSG_WriteByte (msg, ps->gunindex); + if (pflags & PS_WEAPONINDEX) + { + MSG_WriteByte (msg, ps->gunindex); + } + if (pflags & PS_WEAPONFRAME) { MSG_WriteByte (msg, ps->gunframe); @@ -314,35 +382,42 @@ void SV_WritePlayerstateToClient (client_frame_t *from, client_frame_t *to, size MSG_WriteChar (msg, ps->gunangles[2]*4); } - if (pflags & PS_WEAPONSEQUENCE) MSG_WriteByte (msg, ps->sequence); - if (pflags & PS_WEAPONBODY) MSG_WriteByte (msg, ps->gunbody); - if (pflags & PS_WEAPONSKIN) MSG_WriteByte (msg, ps->gunskin); + if (pflags & PS_WEAPONSEQUENCE) + { + MSG_WriteByte (msg, ps->sequence); + } + + if (pflags & PS_WEAPONBODY) + { + MSG_WriteByte (msg, ps->gunbody); + } + + if (pflags & PS_WEAPONSKIN) + { + MSG_WriteByte (msg, ps->gunskin); + } if (pflags & PS_BLEND) { - MSG_WriteByte (msg, ps->blend[0] * 255); - MSG_WriteByte (msg, ps->blend[1] * 255); - MSG_WriteByte (msg, ps->blend[2] * 255); - MSG_WriteByte (msg, ps->blend[3] * 255); + MSG_WriteByte (msg, ps->blend[0]*255); + MSG_WriteByte (msg, ps->blend[1]*255); + MSG_WriteByte (msg, ps->blend[2]*255); + MSG_WriteByte (msg, ps->blend[3]*255); } - if (pflags & PS_FOV) MSG_WriteByte (msg, ps->fov); - if (pflags & PS_RDFLAGS) MSG_WriteByte (msg, ps->rdflags); + if (pflags & PS_FOV) + MSG_WriteByte (msg, ps->fov); + if (pflags & PS_RDFLAGS) + MSG_WriteByte (msg, ps->rdflags); // send stats statbits = 0; - for (i = 0; i < MAX_STATS; i++) - { + for (i=0 ; istats[i] != ops->stats[i]) statbits |= 1<stats[i]); - } } @@ -361,21 +436,18 @@ void SV_WriteFrameToClient (client_t *client, sizebuf_t *msg) frame = &client->frames[sv.framenum & UPDATE_MASK]; if (client->lastframe <= 0) - { - // client is asking for a retransmit + { // client is asking for a retransmit oldframe = NULL; lastframe = -1; } else if (sv.framenum - client->lastframe >= (UPDATE_BACKUP - 3) ) - { - // client hasn't gotten a good message through in a long time + { // client hasn't gotten a good message through in a long time // Msg ("%s: Delta request from out-of-date packet.\n", client->name); oldframe = NULL; lastframe = -1; } else - { - // we have a valid message to delta from + { // we have a valid message to delta from oldframe = &client->frames[client->lastframe & UPDATE_MASK]; lastframe = client->lastframe; } @@ -465,27 +537,29 @@ copies off the playerstat and areabits. void SV_BuildClientFrame (client_t *client) { int e, i; - vec3_t org; - prvm_edict_t *ent; - prvm_edict_t *clent; + vec3_t org; + edict_t *ent; + edict_t *clent; client_frame_t *frame; entity_state_t *state; int l; int clientarea, clientcluster; int leafnum; int c_fullsend; - byte *clientphs; - byte *bitvector; + byte *clientphs; + byte *bitvector; clent = client->edict; - if (!clent->priv.sv->client) return;// not in game yet + if (!clent->client) return;// not in game yet // this is the frame we are creating frame = &client->frames[sv.framenum & UPDATE_MASK]; + frame->senttime = svs.realtime; // save it for ping calc later // find the client's PVS - for (i = 0; i < 3; i++) org[i] = clent->priv.sv->client->pmove.origin[i]*0.125 + clent->priv.sv->client->viewoffset[i]; + for (i=0 ; i<3 ; i++) + org[i] = clent->client->ps.pmove.origin[i]*0.125 + clent->client->ps.viewoffset[i]; leafnum = CM_PointLeafnum (org); clientarea = CM_LeafArea (leafnum); @@ -495,7 +569,8 @@ void SV_BuildClientFrame (client_t *client) frame->areabytes = CM_WriteAreaBits (frame->areabits, clientarea); // grab the current player_state_t - frame->ps = *clent->priv.sv->client; + frame->ps = clent->client->ps; + SV_FatPVS (org); clientphs = CM_ClusterPHS (clientcluster); @@ -506,33 +581,34 @@ void SV_BuildClientFrame (client_t *client) c_fullsend = 0; - ent = PRVM_NEXT_EDICT(prog->edicts); - for (e = 1; e < prog->num_edicts; e++, ent = PRVM_NEXT_EDICT(ent)) + for (e = 1; e < ge->num_edicts ; e++) { + ent = EDICT_NUM(e); + // ignore ents without visible models - if ((int)ent->fields.sv->flags & SVF_NOCLIENT) + if (ent->svflags & SVF_NOCLIENT) continue; // ignore ents without visible models unless they have an effect - if (!(int)ent->fields.sv->modelindex && !(int)ent->fields.sv->effects) + if (!ent->s.modelindex && !ent->s.effects && !ent->s.sound && !ent->s.event) continue; // ignore if not touching a PV leaf if (ent != clent) { // check area - if (!CM_AreasConnected (clientarea, ent->priv.sv->areanum)) - { - // doors can legally straddle two areas, so + if (!CM_AreasConnected (clientarea, ent->areanum)) + { // doors can legally straddle two areas, so // we may need to check another one - if (!ent->priv.sv->areanum2 || !CM_AreasConnected (clientarea, ent->priv.sv->areanum2)) - continue; // blocked by a door + if (!ent->areanum2 + || !CM_AreasConnected (clientarea, ent->areanum2)) + continue; // blocked by a door } // beams just check one point for PHS - if ((int)ent->fields.sv->renderfx & RF_BEAM) + if (ent->s.renderfx & RF_BEAM) { - l = ent->priv.sv->clusternums[0]; + l = ent->clusternums[0]; if ( !(clientphs[l >> 3] & (1 << (l&7) )) ) continue; } @@ -540,67 +616,55 @@ 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->priv.sv->state.sound) + if (ent->s.sound) { bitvector = fatpvs; //clientphs; } - else bitvector = fatpvs; + else + bitvector = fatpvs; - if (ent->priv.sv->num_clusters == -1) - { - // too many leafs for individual check, go by headnode - if (!CM_HeadnodeVisible (ent->priv.sv->headnode, bitvector)) + if (ent->num_clusters == -1) + { // too many leafs for individual check, go by headnode + if (!CM_HeadnodeVisible (ent->headnode, bitvector)) continue; c_fullsend++; } else { // check individual leafs - for (i=0 ; i < ent->priv.sv->num_clusters ; i++) + for (i=0 ; i < ent->num_clusters ; i++) { - l = ent->priv.sv->clusternums[i]; + l = ent->clusternums[i]; if (bitvector[l >> 3] & (1 << (l&7) )) break; } - if (i == ent->priv.sv->num_clusters) - continue; // not visible + if (i == ent->num_clusters) + continue; // not visible } - if (!(int)ent->fields.sv->modelindex) - { - // don't send sounds if they will be attenuated away + if (!ent->s.modelindex) + { // don't send sounds if they will be attenuated away vec3_t delta; float len; - VectorSubtract (org, ent->fields.sv->origin, delta); + VectorSubtract (org, ent->s.origin, delta); len = VectorLength (delta); - if (len > 400) continue; + if (len > 400) + continue; } } } // add it to the circular client_entities array state = &svs.client_entities[svs.next_client_entities % svs.num_client_entities]; - if (ent->priv.sv->state.number != e) + if (ent->s.number != e) { - MsgWarn ("SV_BuildClientFrame: invalid ent->priv.sv->state.number %d (must be %d)\n", ent->priv.sv->state.number, e ); - ent->priv.sv->state.number = e; // ptr to current entity such as entnumber + MsgWarn ("SV_BuildClientFrame: invalid ent->s.number %d\n", ent->s.number ); + ent->s.number = e; // ptr to current entity such as entnumber } - - // copy state from fields - VectorCopy (ent->fields.sv->origin, ent->priv.sv->state.origin); - VectorCopy (ent->fields.sv->angles, ent->priv.sv->state.angles); - ent->priv.sv->state.frame = (int)ent->fields.sv->frame; - ent->priv.sv->state.skin = (int)ent->fields.sv->skin; - ent->priv.sv->state.body = (int)ent->fields.sv->body; - ent->priv.sv->state.sequence = (int)ent->fields.sv->sequence; - ent->priv.sv->state.effects = (int)ent->fields.sv->effects; - ent->priv.sv->state.renderfx = (int)ent->fields.sv->renderfx; - ent->priv.sv->state.solid = (int)ent->fields.sv->solid; - - *state = ent->priv.sv->state; + *state = ent->s; // don't mark players missiles as solid - if(PRVM_PROG_TO_EDICT(ent->fields.sv->owner) == client->edict) state->solid = 0; + if (ent->owner == client->edict) state->solid = 0; svs.next_client_entities++; frame->num_entities++; @@ -619,7 +683,7 @@ Used for recording footage for merged or assembled demos void SV_RecordDemoMessage (void) { int e; - prvm_edict_t *ent; + edict_t *ent; entity_state_t nostate; sizebuf_t buf; byte buf_data[32768]; @@ -638,14 +702,18 @@ void SV_RecordDemoMessage (void) MSG_WriteByte (&buf, svc_packetentities); e = 1; - ent = PRVM_EDICT_NUM(e); - while (e < prog->num_edicts) + ent = EDICT_NUM(e); + while (e < ge->num_edicts) { // ignore ents without visible models unless they have an effect - if (!ent->priv.sv->free && ent->priv.sv->state.number && ((int)ent->fields.sv->modelindex || ent->fields.sv->effects || ent->priv.sv->state.sound || ent->priv.sv->state.event) && !((int)ent->fields.sv->flags & SVF_NOCLIENT)) - MSG_WriteDeltaEntity (&nostate, &ent->priv.sv->state, &buf, false, true); + 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); + e++; - ent = PRVM_EDICT_NUM(e); + ent = EDICT_NUM(e); } MSG_WriteShort (&buf, 0); // end of packetentities @@ -660,4 +728,3 @@ void SV_RecordDemoMessage (void) FS_Write (svs.demofile, buf.data, buf.cursize); } - \ No newline at end of file diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 541c370e..ed6e0171 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -19,140 +19,109 @@ 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" -/* -============== -PF_makevectors - -Writes new values for v_forward, v_up, and v_right based on angles -makevectors(vector) -============== -*/ -void PF_makevectors (void) -{ - AngleVectorsRight(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); -} - -void PF_makevectors2 (void) -{ - AngleVectorsLeft(PRVM_G_VECTOR(OFS_PARM0), prog->globals.server->v_forward, prog->globals.server->v_right, prog->globals.server->v_up); -} +game_export_t *ge; +HINSTANCE sv_library; +game_locals_t game; /* -================= -PF_setorigin +=============== +PF_dprintf -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) -================= +Debug print to server console +=============== */ -void PF_setorigin (void) +void PF_dprintf (char *fmt, ...) { - prvm_edict_t *e; - float *org; - - e = PRVM_G_EDICT(OFS_PARM0); - if (e == prog->edicts) - { - VM_Warning("setorigin: can not modify world entity\n"); - return; - } - if (e->priv.sv->free) - { - VM_Warning("setorigin: can not modify free entity\n"); - return; - } - org = PRVM_G_VECTOR(OFS_PARM1); - VectorCopy (org, e->fields.sv->origin); - SV_LinkEdict (e); -} - - -void SetMinMaxSize (prvm_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->fields.sv->mins); - VectorCopy (max, e->fields.sv->maxs); - VectorSubtract (max, min, e->fields.sv->size); - - SV_LinkEdict (e); -} - - -//test for stats -void PF_SetStats( void ) -{ - prvm_edict_t *e; - int stat_num; - const char *string; - short value; - - e = PRVM_G_EDICT(OFS_PARM0); - - if(!e->priv.sv->client) return; + char msg[1024]; + va_list argptr; - stat_num = (int)PRVM_G_FLOAT(OFS_PARM1); + va_start (argptr,fmt); + vsprintf (msg, fmt, argptr); + va_end (argptr); - 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->stats[stat_num] = value; + Msg ("%s", msg); } + /* -================= -PF_setsize +=============== +PF_cprintf -the size box is rotated by the current angle -LordHavoc: no it isn't... - -setsize (entity, minvector, maxvector) -================= +Print to a single client +=============== */ -void PF_setsize (void) +void PF_cprintf (edict_t *ent, int level, char *fmt, ...) { - prvm_edict_t *e; - float *min, *max; + char msg[1024]; + va_list argptr; + int n; - e = PRVM_G_EDICT(OFS_PARM0); - if (e == prog->edicts) + if (ent) { - VM_Warning("setsize: can not modify world entity\n"); - return; + n = NUM_FOR_EDICT(ent); + if (n < 1 || n > maxclients->value) + Com_Error (ERR_DROP, "cprintf to a non-client"); } - 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); + + 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) + return; // Com_Error (ERR_DROP, "centerprintf to a non-client"); + + 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 ); +} + + +/* +=============== +PF_error + +Abort the server with a game error +=============== +*/ +void PF_error (char *fmt, ...) +{ + char msg[1024]; + va_list argptr; + + va_start (argptr,fmt); + vsprintf (msg, fmt, argptr); + va_end (argptr); + + Com_Error (ERR_DROP, "Game Error: %s", msg); } @@ -160,378 +129,66 @@ void PF_setsize (void) ================= PF_setmodel -setmodel(entity, model) +Also sets mins and maxs for inline bmodels ================= */ -void PF_setmodel( void ) +void PF_setmodel (edict_t *ent, char *name) { - prvm_edict_t *e; + int i; cmodel_t *mod; - int i; - - 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; - } - - i = SV_ModelIndex(PRVM_G_STRING(OFS_PARM1)); - e->fields.sv->model = PRVM_SetEngineString(sv.configstrings[CS_MODELS+i]); - e->fields.sv->modelindex = e->priv.sv->state.modelindex = i; - - mod = CM_LoadModel(sv.configstrings[CS_MODELS+i]); - if(mod) SetMinMaxSize( e, mod->mins, mod->maxs, false ); -} - -/* -================= -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); -} + if (!name) Com_Error (ERR_DROP, "PF_setmodel: NULL"); + i = SV_ModelIndex (name); + +// ent->model = name; + ent->s.modelindex = i; -/* -================= -PF_ambientsound + mod = CM_LoadModel (name); -================= -*/ -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; - prvm_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) + if(mod) // hull setup { - VM_Warning("SV_StartSound: volume must be in range 0-1\n"); - return; + VectorCopy (mod->mins, ent->mins); + VectorCopy (mod->maxs, ent->maxs); + SV_LinkEdict (ent); } - - 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 +=============== +PF_Configstring -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) +void PF_Configstring (int index, char *val) { - float *v1, *v2; - trace_t trace; - int move; - prvm_edict_t *ent; + if (index < 0 || index >= MAX_CONFIGSTRINGS) + Com_Error (ERR_DROP, "configstring: bad index %i value %s\n", index, val); - prog->xfunction->builtinsprofile += 30; + if (!val) val = ""; - 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); + // change the string in sv + strcpy (sv.configstrings[index], val); - 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_inwater = (trace.contents & MASK_WATER) ? true : false; - prog->globals.server->trace_inopen = (trace.contents & MASK_SHOT) ? true : false; // this is correct? - - 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; - prvm_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_inwater = (trace.contents & MASK_WATER) ? true : false; - prog->globals.server->trace_inopen = (trace.contents & MASK_SHOT) ? true : false; // this is correct? - - 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); -} - -void PF_tracetoss (void) -{ - trace_t trace; - prvm_edict_t *ent; - prvm_edict_t *ignore; - - prog->xfunction->builtinsprofile += 600; - - ent = PRVM_G_EDICT(OFS_PARM0); - if (ent == prog->edicts) + if (sv.state != ss_loading) { - VM_Warning("tracetoss: can not use world entity\n"); - return; + // 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 ); } - ignore = PRVM_G_EDICT(OFS_PARM1); - - trace = SV_TraceToss (ent, ignore); - - 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_inwater = (trace.contents & MASK_WATER) ? true : false; - prog->globals.server->trace_inopen = (trace.contents & MASK_SHOT) ? true : false; // this is correct? - - 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; - prvm_edict_t *ent; - vec3_t org; - - // cycle to the next one - check = bound(1, check, host.maxclients); - if (check == host.maxclients) i = 1; - else i = check + 1; - - for (;; i++) - { - // 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->fields.sv->health <= 0 || ((int)ent->fields.sv->flags & FL_NOTARGET))) - continue; - // found a valid client (possibly the same one again) - break; - } - - // get the PVS for the entity - VectorAdd(ent->fields.sv->origin, ent->fields.sv->view_ofs, org); - - SV_FatPVS( org ); // fat pvs manually - - return i; } /* ================= -PF_inphs +PF_inPVS 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; @@ -553,14 +210,15 @@ 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; @@ -583,1043 +241,62 @@ bool PF_inphs (vec3_t p1, vec3_t p2) return true; } -/* -================= -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) +void PF_StartSound (edict_t *entity, int channel, int sound_num, float volume, float attenuation, float timeofs) { - prvm_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->fields.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->self); - VectorAdd(self->fields.sv->origin, self->fields.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); + if (!entity) return; + SV_StartSound (NULL, entity, channel, sound_num, volume, attenuation, timeofs); } -//============================================================================ -void SV_ConfigString (int index, const char *val) +//============================================== + +/* +=============== +SV_ShutdownGameProgs + +Called when either the entire server is being killed, or +it is changing to a different game directory. +=============== +*/ +void SV_ShutdownGameProgs (void) { - if (index < 0 || index >= MAX_CONFIGSTRINGS) - Com_Error (ERR_DROP, "configstring: bad index %i value %s\n", index, val); + if (!ge) return; - if (!val) val = ""; + Msg("==== ShutdownGame ====\n"); - // change the string in sv - strcpy (sv.configstrings[index], val); + //free main memory pools + Mem_FreePool(&sv.mempool); - 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 ); - } + Mem_Free( ge ); + ge = NULL; } /* =============== -PF_Configstring +SV_InitGameProgs +Init the game subsystem for a new map =============== */ -void PF_Configstring( void ) +void SCR_DebugGraph (float value, int color); + +void SV_InitGameProgs (void) { - SV_ConfigString((int)PRVM_G_FLOAT(OFS_PARM0), PRVM_G_STRING(OFS_PARM1)); + // 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 } -/* -================= -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) -{ - prvm_edict_t *ent, *chain; - vec_t radius, radius2; - vec3_t org, eorg, mins, maxs; - int i; - int numtouchedicts; - prvm_edict_t *touchedicts[MAX_EDICTS]; - - chain = (prvm_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->fields.sv->solid == SOLID_NOT) continue; - VectorSubtract(org, ent->fields.sv->origin, eorg); - VectorMAMAM(1, eorg, 0.5f, ent->fields.sv->mins, 0.5f, ent->fields.sv->maxs, eorg); - if (DotProduct(eorg, eorg) < radius2) - { - ent->fields.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) -{ - prvm_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->self); - 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->fields.sv->flags & (FL_ONGROUND|FL_FLY|FL_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->self; - - PRVM_G_FLOAT(OFS_RETURN) = 0;//SV_movestep(ent, move, true); - - // restore program state - prog->xfunction = oldf; - prog->globals.server->self = oldself; -} - -/* -=============== -PF_droptofloor - -void() droptofloor -=============== -*/ -void PF_droptofloor (void) -{ - prvm_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->self); - 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->fields.sv->origin, end); - end[2] -= 256; - - trace = SV_Trace(ent->fields.sv->origin, ent->fields.sv->mins, ent->fields.sv->maxs, end, ent, MASK_ALL ); - - if (trace.fraction != 1) - { - VectorCopy (trace.endpos, ent->fields.sv->origin); - SV_LinkEdict (ent); - ent->fields.sv->flags = (int)ent->fields.sv->flags | FL_ONGROUND; - ent->fields.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) -{ - prvm_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->fields.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 && ((prvm_edict_t *)tr.ent)->fields.sv->takedamage == DAMAGE_AIM && (flags & DF_NO_FRIENDLY_FIRE || ent->fields.sv->team <=0 || ent->fields.sv->team != ((prvm_edict_t *)tr.ent)->fields.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->fields.sv->takedamage != DAMAGE_AIM) - continue; - if (check == ent) - continue; - if (flags & DF_NO_FRIENDLY_FIRE && ent->fields.sv->team > 0 && ent->fields.sv->team == check->fields.sv->team) - continue; // don't aim at teammate - for (j = 0; j < 3; j++) - end[j] = check->fields.sv->origin[j] + 0.5 * (check->fields.sv->mins[j] + check->fields.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->fields.sv->origin, ent->fields.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) -{ - prvm_edict_t *ent; - float ideal, current, move, speed; - - ent = PRVM_PROG_TO_EDICT(prog->globals.server->self); - 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->fields.sv->angles[1]); - ideal = ent->fields.sv->ideal_yaw; - speed = ent->fields.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->fields.sv->angles[1] = anglemod(current + move); -} - -/* -============== -PF_changepitch -============== -*/ -void PF_changepitch (void) -{ - prvm_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->fields.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->fields.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_WriteDir (void) -{ - MSG_WriteDir (&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) -{ - prvm_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) -{ - prvm_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; - for (i = 0; i < NUM_SPAWN_PARMS; i++) - prog->globals.server->parm[i] = client->spawn_parms[i]; -} - -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) -{ - prvm_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->fields.sv, in->fields.sv, prog->progs->entityfields * 4); -} - -static cmodel_t *getmodel(prvm_edict_t *ed) -{ - int modelindex; - if (!ed || ed->priv.sv->free) - return NULL; - - modelindex = (int)ed->fields.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; - prvm_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 -PF_WriteDir, // #62 void(vector v) WriteDir -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 -PF_tracetoss, // #79 void(entity e, entity ignore) tracetoss (DP_QC_TRACETOSS) -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); diff --git a/engine/server/sv_init.c b/engine/server/sv_init.c index 438c6da7..42289e48 100644 --- a/engine/server/sv_init.c +++ b/engine/server/sv_init.c @@ -24,120 +24,30 @@ 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, 2, "modelindex"}, - {1, 3, "absmin"}, - {1, 2, "absmin_x"}, - {2, 2, "absmin_y"}, - {3, 2, "absmin_z"}, - {4, 3, "absmax"}, - {7, 2, "ltime"}, - {8, 2, "movetype"}, - {9, 2, "solid"}, - {10, 3, "origin"}, - {13, 3, "oldorigin"}, - {16, 3, "velocity"}, - {19, 3, "angles"}, - {22, 3, "avelocity"}, - {25, 3, "punchangle"}, - {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"}, - {39, 3, "maxs"}, - {42, 3, "size"}, - {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"}, - {68, 2, "button0"}, - {69, 2, "button1"}, - {70, 2, "button2"}, - {71, 2, "impulse"}, - {72, 2, "fixangle"}, - {73, 3, "v_angle"}, - {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"}, - {102, 1, "message"}, - {103, 2, "sounds"}, - {104, 1, "noise"}, - {105, 1, "noise1"}, - {106, 1, "noise2"}, - {107, 1, "noise3"} -}; - /* ================ SV_FindIndex ================ */ -int SV_FindIndex (const char *name, int start, int end, bool create) +int SV_FindIndex (char *name, int start, int max, bool create) { int i; - if (!name || !name[0]) return 0; - - for (i = 1; i < end && sv.configstrings[start + i][0]; i++) - if(!strcmp(sv.configstrings[start + i], name)) - return i; - if (!create) return 0; - - if (i == end) - { - MsgWarn ("SV_FindIndex: %d out range [%d - %d]\n", start, end ); + if (!name || !name[0]) return 0; - } - // register new resource - strncpy (sv.configstrings[start + i], name, sizeof(sv.configstrings[i])); + for (i=1 ; inum_edicts; entnum++) + for (entnum = 1; entnum < ge->num_edicts ; entnum++) { - svent = PRVM_EDICT_NUM(entnum); - - if (svent->priv.sv->free) - { - Msg("Can't create baseline for entity [%d]\n", entnum ); + svent = EDICT_NUM(entnum); + if (!svent->inuse) continue; - } - if (!(int)svent->fields.sv->modelindex && !(int)svent->priv.sv->state.sound && !(int)svent->fields.sv->effects) + if (!svent->s.modelindex && !svent->s.sound && !svent->s.effects) continue; + svent->s.number = entnum; - svent->priv.sv->state.number = entnum; - - if (entnum > host.maxclients && !(int)svent->fields.sv->modelindex) - continue; - - // create entity baseline - VectorCopy (svent->fields.sv->origin, svent->priv.sv->state.origin); - VectorCopy (svent->priv.sv->state.origin, svent->priv.sv->state.old_origin); - VectorCopy (svent->fields.sv->angles, svent->priv.sv->state.angles); - svent->priv.sv->state.frame = (int)svent->fields.sv->frame; - svent->priv.sv->state.skin = (int)svent->fields.sv->skin; - svent->priv.sv->state.body = (int)svent->fields.sv->body; - svent->priv.sv->state.sequence = (int)svent->fields.sv->sequence; - svent->priv.sv->state.effects = (int)svent->fields.sv->effects; - svent->priv.sv->state.renderfx = (int)svent->fields.sv->renderfx; - svent->priv.sv->state.solid = (int)svent->fields.sv->solid; - - if (entnum > 0 && entnum <= host.maxclients) - { - svent->priv.sv->state.modelindex = SV_ModelIndex("progs/player.mdl"); - } - else - { - svent->priv.sv->state.modelindex = (int)svent->fields.sv->modelindex; - } - + // // take current state as baseline - sv.baselines[entnum] = svent->priv.sv->state; + // + VectorCopy (svent->s.origin, svent->s.old_origin); + sv.baselines[entnum] = svent->s; } } -/* -================ -SV_SaveSpawnparms - -Grabs the current state of each client for saving across the -transition to another level -================ -*/ -void SV_SaveSpawnparms (void) -{ - int i, j; - - svs.serverflags = (int)prog->globals.server->serverflags; - - for (i = 0, sv_client = svs.clients; i < host.maxclients; i++, sv_client++) - { - if (sv_client->state != cs_spawned) - continue; - - // call the progs to get default spawn parms for the new client - prog->globals.server->self = PRVM_EDICT_TO_PROG(sv_client->edict); - PRVM_ExecuteProgram (prog->globals.server->SetChangeParms, "QC function SetChangeParms is missing"); - for (j = 0; j < NUM_SPAWN_PARMS; j++) - sv_client->spawn_parms[j] = prog->globals.server->parm[j]; - } -} /* ================= @@ -259,6 +118,7 @@ SV_CheckForSavegame */ void SV_CheckForSavegame (char *savename ) { + int i; char name[MAX_SYSPATH]; if (sv_noreload->value) return; @@ -275,6 +135,22 @@ void SV_CheckForSavegame (char *savename ) // get configstrings and areaportals SV_ReadLevelFile ( savename ); + + if (!sv.loadgame) + { // coming back to a level after being in a different + // level, so run it for ten seconds + + // rlava2 was sending too many lightstyles, and overflowing the + // reliable data. temporarily changing the server state to loading + // prevents these from being passed down. + server_state_t previousState; // PGM + + previousState = sv.state; // PGM + sv.state = ss_loading; // PGM + for (i = 0; i < 100; i++) SV_RunFrame (); + + sv.state = previousState; // PGM + } } @@ -289,8 +165,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; - prvm_edict_t *ent; + uint i, checksum; if (attractloop) Cvar_Set ("paused", "0"); @@ -321,17 +196,11 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat pm_airaccelerate = 0; } - SV_VM_Setup(); - SZ_Init (&sv.multicast, sv.multicast_buf, sizeof(sv.multicast_buf)); - strcpy (sv.name, server); - strcpy (sv.configstrings[CS_NAME], server); - - SV_VM_Begin(); // leave slots at start for clients only - for (i = 0; i < host.maxclients; i++) + for (i=0 ; ivalue ; i++) { // needs to reconnect if (svs.clients[i].state > cs_connected) @@ -339,8 +208,10 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat svs.clients[i].lastframe = -1; } - sv.state = ss_loading; - prog->protect_world = false; + sv.time = 1000; + + strcpy (sv.name, server); + strcpy (sv.configstrings[CS_NAME], server); if (serverstate != ss_game) { @@ -348,7 +219,7 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat } else { - strcpy (sv.configstrings[CS_MODELS+1], server); + sprintf (sv.configstrings[CS_MODELS+1], "maps/%s.bsp", server); sv.models[1] = CM_LoadMap (sv.configstrings[CS_MODELS+1], false, &checksum); } sprintf (sv.configstrings[CS_MAPCHECKSUM],"%i", checksum); @@ -362,61 +233,36 @@ void SV_SpawnServer (char *server, char *spawnpoint, char *savename, server_stat sv.models[i+1] = CM_InlineModel (sv.configstrings[CS_MODELS+1+i]); } - ent = PRVM_EDICT_NUM(0); - memset (ent->fields.sv, 0, prog->progs->entityfields * 4); - ent->priv.sv->free = false; - ent->fields.sv->model = PRVM_SetEngineString(sv.configstrings[CS_MODELS]); - ent->fields.sv->modelindex = 1; // world model - ent->fields.sv->solid = SOLID_BSP; - ent->fields.sv->movetype = MOVETYPE_PUSH; - - prog->globals.server->mapname = PRVM_SetEngineString(sv.name); + // + // spawn the rest of the entities on the map + // + + // precache and static commands can be issued during + // map initialization + sv.state = ss_loading; Com_SetServerState (sv.state); - // spawn the rest of the entities on the map - sv.moved_edicts = (prvm_edict_t **)PRVM_Alloc(prog->max_edicts * sizeof(prvm_edict_t *)); - *prog->time = sv.time = 1.0; + // load and spawn all other entities + SV_SpawnEntities ( sv.name, CM_EntityString(), spawnpoint ); - // 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 < host.maxclients; i++, sv_client++) - { - sv_client->state = cs_connected; - sv_client->edict = PRVM_EDICT_NUM(i + 1); - sv_client->edict->priv.sv->client = Z_Malloc(sizeof(player_state_t)); - ent->priv.sv->state.number = i + 1; - memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); - PRVM_ED_ClearEdict(sv_client->edict); - } - - PRVM_ED_LoadFromFile (CM_EntityString()); + // run two frames to allow everything to settle + SV_RunFrame (); + SV_RunFrame (); // all precaches are complete sv.state = serverstate; Com_SetServerState (sv.state); - prog->protect_world = true; - - // run two frames to allow everything to settle - for (i = 0; i < 2; i++) - { - sv.frametime = 0.1f; - SV_Physics(); - } // create a baseline for more efficient communications SV_CreateBaseline (); + // check for a savegame + SV_CheckForSavegame ( savename ); + // set serverinfo variable Cvar_FullSet ("mapname", sv.name, CVAR_SERVERINFO | CVAR_NOSET); Msg ("-------------------------------------\n"); - - SV_VM_End(); } /* @@ -428,8 +274,8 @@ A brand new game has been started */ void SV_InitGame (void) { - //int i; - //prvm_edict_t *ent; + int i; + edict_t *ent; char idmaster[32]; if (svs.initialized) @@ -457,38 +303,53 @@ void SV_InitGame (void) // dedicated servers are can't be single player and are usually DM // so unless they explicity set coop, force it to deathmatch - if (host.type == HOST_DEDICATED) + if (dedicated->value) { - if (!Cvar_VariableValue ("coop")) Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); + if (!Cvar_VariableValue ("coop")) + Cvar_FullSet ("deathmatch", "1", CVAR_SERVERINFO | CVAR_LATCH); } // init clients if (Cvar_VariableValue ("deathmatch")) { - if (host.maxclients <= 1) host.maxclients = 8; - else if (host.maxclients > MAX_CLIENTS) host.maxclients = MAX_CLIENTS; + if (maxclients->value <= 1) + Cvar_FullSet ("maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH); + else if (maxclients->value > MAX_CLIENTS) + Cvar_FullSet ("maxclients", va("%i", MAX_CLIENTS), CVAR_SERVERINFO | CVAR_LATCH); } else if (Cvar_VariableValue ("coop")) { - if (host.maxclients <= 1 || host.maxclients > 4) host.maxclients = 4; + if (maxclients->value <= 1 || maxclients->value > 4) + Cvar_FullSet ("maxclients", "4", CVAR_SERVERINFO | CVAR_LATCH); } else // non-deathmatch, non-coop is one player { - host.maxclients = 1; + Cvar_FullSet ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); } svs.spawncount = rand(); - svs.clients = Z_Malloc (sizeof(client_t) * host.maxclients); - svs.num_client_entities = host.maxclients * UPDATE_BACKUP * 64; - svs.client_entities = Z_Malloc(sizeof(entity_state_t) * svs.num_client_entities); + svs.clients = Z_Malloc (sizeof(client_t)*maxclients->value); + svs.num_client_entities = maxclients->value*UPDATE_BACKUP*64; + svs.client_entities = Z_Malloc (sizeof(entity_state_t)*svs.num_client_entities); // init network stuff - NET_Config ( (host.maxclients > 1) ); + NET_Config ( (maxclients->value > 1) ); // heartbeats will always be sent to the id master svs.last_heartbeat = -99999; // send immediately sprintf(idmaster, "192.246.40.37:%i", PORT_MASTER); NET_StringToAdr (idmaster, &master_adr[0]); + + // 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)); + } } @@ -577,145 +438,3 @@ void SV_Map (bool attractloop, char *levelstring, char *savename, bool loadgame) SV_BroadcastCommand ("reconnect\n"); } - -void SV_VM_BeginIncreaseEdicts(void) -{ - int i; - prvm_edict_t *ent; - - PRVM_Free( sv.moved_edicts ); - sv.moved_edicts = (prvm_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; - prvm_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(prvm_edict_t *e) -{ - int num = PRVM_NUM_FOR_EDICT(e) - 1; - e->priv.sv->move = false; // don't move on first frame - - // set here additional player effects: model, skin, etc... -} - -void SV_VM_FreeEdict(prvm_edict_t *ed) -{ - SV_UnlinkEdict (ed); // unlink from world bsp - - ed->fields.sv->model = 0; - ed->fields.sv->takedamage = 0; - ed->fields.sv->modelindex = 0; - ed->fields.sv->colormap = 0; - ed->fields.sv->skin = 0; - ed->fields.sv->frame = 0; - VectorClear(ed->fields.sv->origin); - VectorClear(ed->fields.sv->angles); - ed->fields.sv->nextthink = -1; - ed->fields.sv->solid = 0; -} - -void SV_VM_CountEdicts( void ) -{ - int i; - prvm_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->fields.sv->solid) solid++; - if (ent->fields.sv->model) models++; - if (ent->fields.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(prvm_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->fields.sv->spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) - { - return false; - } - } - else if ((current_skill <= 0 && ((int)ent->fields.sv->spawnflags & SPAWNFLAG_NOT_EASY )) || (current_skill == 1 && ((int)ent->fields.sv->spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->fields.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 = host.maxclients; - prog->edictprivate_size = sizeof(server_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 cacd2a3a..5876829f 100644 --- a/engine/server/sv_main.c +++ b/engine/server/sv_main.c @@ -42,18 +42,11 @@ cvar_t *allow_download_sounds; cvar_t *allow_download_maps; cvar_t *sv_airaccelerate; -cvar_t *sv_wateraccelerate; -cvar_t *sv_accelerate; cvar_t *sv_maxvelocity; -cvar_t *sv_maxspeed; -cvar_t *sv_friction; cvar_t *sv_gravity; -cvar_t *sv_rollangle; -cvar_t *sv_rollspeed; cvar_t *sv_noreload; // don't reload level state when reentering - cvar_t *maxclients; // FIXME: rename sv_maxclients cvar_t *sv_showclamp; @@ -86,7 +79,7 @@ void SV_DropClient (client_t *drop) { // call the prog function for removing a client // this will remove the body, among other things -//ge->ClientDisconnect (drop->edict); + SV_ClientDisconnect(drop->edict); } if (drop->download) @@ -128,12 +121,12 @@ char *SV_StatusString (void) strcat (status, "\n"); statusLength = strlen(status); - for (i=0 ; ivalue ; i++) { cl = &svs.clients[i]; if (cl->state == cs_connected || cl->state == cs_spawned ) { - sprintf (player, "%i %i \"%s\"\n", cl->edict->priv.sv->client->stats[STAT_FRAGS], cl->ping, cl->name); + sprintf (player, "%i %i \"%s\"\n", cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name); playerLength = strlen(player); if (statusLength + playerLength >= sizeof(status) ) break; // can't hold any more @@ -182,7 +175,7 @@ void SVC_Info (void) int i, count; int version; - if (host.maxclients == 1) + if (maxclients->value == 1) return; // ignore in single player version = atoi (Cmd_Argv(1)); @@ -192,11 +185,11 @@ void SVC_Info (void) else { count = 0; - for (i=0 ; ivalue ; i++) if (svs.clients[i].state >= cs_connected) count++; - sprintf (string, "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)host.maxclients); + sprintf (string, "%16s %8s %2i/%2i\n", hostname->string, sv.name, count, (int)maxclients->value); } Netchan_OutOfBandPrint (NS_SERVER, net_from, "info\n%s", string); @@ -252,7 +245,7 @@ void SVC_GetChallenge (void) // overwrite the oldest svs.challenges[oldest].challenge = rand() & 0x7fff; svs.challenges[oldest].adr = net_from; - svs.challenges[oldest].time = host.realtime; + svs.challenges[oldest].time = curtime; i = oldest; } @@ -274,7 +267,7 @@ void SVC_DirectConnect (void) int i; client_t *cl, *newcl; client_t temp; - prvm_edict_t *ent; + edict_t *ent; int edictnum; int version; int qport; @@ -336,7 +329,7 @@ void SVC_DirectConnect (void) memset (newcl, 0, sizeof(client_t)); // if there is already a slot for this ip, reuse it - for (i=0,cl=svs.clients ; ivalue ; i++,cl++) { if (cl->state == cs_free) continue; @@ -344,7 +337,7 @@ void SVC_DirectConnect (void) && ( cl->netchan.qport == qport || adr.port == cl->netchan.remote_address.port ) ) { - if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value)) + if (!NET_IsLocalAddress (adr) && (svs.realtime - cl->lastconnect) < ((int)sv_reconnect_limit->value * 1000)) { MsgWarn("SVC_DirectConnect: %s:reconnect rejected : too soon\n", NET_AdrToString (adr)); return; @@ -357,7 +350,7 @@ void SVC_DirectConnect (void) // find a client slot newcl = NULL; - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) + for (i = 0, cl = svs.clients; i < maxclients->value; i++, cl++) { if (cl->state == cs_free) { @@ -380,22 +373,19 @@ gotnewcl: sv_client = newcl; edictnum = (newcl - svs.clients) + 1; - ent = PRVM_EDICT_NUM(edictnum); + ent = EDICT_NUM(edictnum); newcl->edict = ent; newcl->challenge = challenge; // save challenge for checksumming - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(sv_client->edict); - PRVM_ExecuteProgram (prog->globals.server->ClientConnect, "QC function ClientConnect is missing"); - - //if (!(ge->ClientConnect (ent, userinfo))) - /*{ + // get the game a chance to reject this connection or modify the userinfo + if (!(SV_ClientConnect(ent, userinfo))) + { if (*Info_ValueForKey (userinfo, "rejmsg")) Netchan_OutOfBandPrint (NS_SERVER, adr, "print\n%s\nConnection refused.\n", Info_ValueForKey (userinfo, "rejmsg")); else Netchan_OutOfBandPrint (NS_SERVER, adr, "print\nConnection refused.\n" ); MsgWarn("SVC_DirectConnect: Game rejected a connection.\n"); return; - }*/ + } // parse some info from the info strings strncpy (newcl->userinfo, userinfo, sizeof(newcl->userinfo)-1); @@ -514,7 +504,7 @@ void SV_CalcPings (void) client_t *cl; int total, count; - for (i=0 ; ivalue ; i++) { cl = &svs.clients[i]; if (cl->state != cs_spawned ) @@ -547,7 +537,7 @@ void SV_CalcPings (void) #endif // let the game dll know about the ping -//cl->edict->client->ping = cl->ping; + cl->edict->client->ping = cl->ping; } } @@ -565,16 +555,16 @@ void SV_GiveMsec (void) int i; client_t *cl; - if (sv.framenum & 15) return; + if (sv.framenum & 15) + return; - for (i = 0; i < host.maxclients; i++) + for (i=0 ; ivalue ; i++) { cl = &svs.clients[i]; - if (cl->state == cs_free ) continue; - cl->commandMsec = 1800; // 1600 + some slop + cl->commandMsec = 1800; // 1600 + some slop } } @@ -607,7 +597,7 @@ void SV_ReadPackets (void) qport = MSG_ReadShort (&net_message) & 0xffff; // check for packets from connected clients - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) + for (i=0, cl=svs.clients ; ivalue ; i++,cl++) { if (cl->state == cs_free) continue; @@ -622,8 +612,7 @@ void SV_ReadPackets (void) } if (Netchan_Process(&cl->netchan, &net_message)) - { - // this is a valid, sequenced packet, so process it + { // this is a valid, sequenced packet, so process it if (cl->state != cs_zombie) { cl->lastmessage = svs.realtime; // don't timeout @@ -633,7 +622,7 @@ void SV_ReadPackets (void) break; } - if (i != host.maxclients) + if (i != maxclients->value) continue; } } @@ -658,15 +647,17 @@ void SV_CheckTimeouts (void) int droppoint; int zombiepoint; - droppoint = svs.realtime - timeout->value; - zombiepoint = svs.realtime - zombietime->value; + droppoint = svs.realtime - 1000*timeout->value; + zombiepoint = svs.realtime - 1000*zombietime->value; - for (i=0,cl=svs.clients ; ivalue ; i++,cl++) { // message times may be wrong across a changelevel - if (cl->lastmessage > svs.realtime) cl->lastmessage = svs.realtime; + if (cl->lastmessage > svs.realtime) + cl->lastmessage = svs.realtime; - if (cl->state == cs_zombie && cl->lastmessage < zombiepoint) + if (cl->state == cs_zombie + && cl->lastmessage < zombiepoint) { cl->state = cs_free; // can now be reused continue; @@ -691,15 +682,53 @@ player processing happens outside RunWorldFrame */ void SV_PrepWorldFrame (void) { - prvm_edict_t *ent; + edict_t *ent; int i; - for (i = 0; i < prog->num_edicts ; i++, ent++) + for (i=0 ; inum_edicts ; i++, ent++) { - ent = PRVM_EDICT_NUM(i); + ent = EDICT_NUM(i); // events only last for a single message - ent->priv.sv->state.event = 0; + ent->s.event = 0; } + +} + + +/* +================= +SV_RunGameFrame +================= +*/ +void SV_RunGameFrame (void) +{ + if (host_speeds->value) + time_before_game = Sys_Milliseconds (); + + // we always need to bump framenum, even if we + // don't run the world, otherwise the delta + // compression can get confused when a client + // has the "current" frame + sv.framenum++; + sv.time = sv.framenum*100; + + // don't run if paused + if (!sv_paused->value || maxclients->value > 1) + { + SV_RunFrame (); + + // never get more than one tic behind + if (sv.time < svs.realtime) + { + if (sv_showclamp->value) + Msg ("sv highclamp\n"); + svs.realtime = sv.time; + } + } + + if (host_speeds->value) + time_after_game = Sys_Milliseconds (); + } /* @@ -708,22 +737,22 @@ SV_Frame ================== */ -void SV_Frame (float time) +void SV_Frame (int msec) { - // if server is not active, do nothing - if (!svs.initialized) return; + time_before_game = time_after_game = 0; - svs.realtime += host.realtime; + // if server is not active, do nothing + if (!svs.initialized) + return; + + svs.realtime += msec; // keep the random time dependent rand (); - // setup the VM frame - SV_VM_Begin(); - // check timeouts SV_CheckTimeouts (); - + // get packets from clients SV_ReadPackets (); @@ -731,12 +760,13 @@ void SV_Frame (float time) if (!sv_timedemo->value && svs.realtime < sv.time) { // never let the time get too far off - if (sv.time - svs.realtime > 0.1) + if (sv.time - svs.realtime > 100) { - if (sv_showclamp->value) Msg ("sv lowclamp\n"); - svs.realtime = sv.time - 0.1; + if (sv_showclamp->value) + Msg ("sv lowclamp\n"); + svs.realtime = sv.time - 100; } - NET_Sleep((sv.time - svs.realtime) * 0.001); + NET_Sleep(sv.time - svs.realtime); return; } @@ -747,7 +777,7 @@ void SV_Frame (float time) SV_GiveMsec (); // let everything in the world think and move - SV_Physics(); + SV_RunGameFrame (); // send messages back to the clients that had packets read this frame SV_SendClientMessages (); @@ -761,8 +791,6 @@ void SV_Frame (float time) // clear teleport flags, etc for next frame SV_PrepWorldFrame (); - // end the server VM frame - SV_VM_End(); } //============================================================================ @@ -781,8 +809,9 @@ void Master_Heartbeat (void) char *string; int i; - // only dedicated servers send heartbeats - if (host.type == HOST_NORMAL) return; + // pgm post3.19 change, cvar pointer not validated before dereferencing + if (!dedicated || !dedicated->value) + return; // only dedicated servers send heartbeats // pgm post3.19 change, cvar pointer not validated before dereferencing if (!public_server || !public_server->value) @@ -792,7 +821,7 @@ void Master_Heartbeat (void) if (svs.last_heartbeat > svs.realtime) svs.last_heartbeat = svs.realtime; - if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS) + if (svs.realtime - svs.last_heartbeat < HEARTBEAT_SECONDS*1000) return; // not time to send yet svs.last_heartbeat = svs.realtime; @@ -801,14 +830,12 @@ void Master_Heartbeat (void) string = SV_StatusString(); // send to group master - for (i = 0; i < MAX_MASTERS; i++) - { + for (i=0 ; ivalue) + return; // only dedicated servers send heartbeats // pgm post3.19 change, cvar pointer not validated before dereferencing if (!public_server || !public_server->value) return; // a private dedicated game // send to group master - for ( i = 0; i < MAX_MASTERS; i++) - { + for (i=0 ; i 0) Msg ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i])); + if (i > 0) + Msg ("Sending heartbeat to %s\n", NET_AdrToString (master_adr[i])); Netchan_OutOfBandPrint (NS_SERVER, master_adr[i], "shutdown"); } - } } //============================================================================ @@ -856,7 +884,7 @@ void SV_UserinfoChanged (client_t *cl) int i; // call prog code to allow overrides -//ge->ClientUserinfoChanged (cl->edict, cl->userinfo); + SV_ClientUserinfoChanged(cl->edict, cl->userinfo); // name for C code strncpy (cl->name, Info_ValueForKey (cl->userinfo, "name"), sizeof(cl->name)-1); @@ -910,7 +938,8 @@ void SV_Init (void) Cvar_Get ("timelimit", "0", CVAR_SERVERINFO); Cvar_Get ("cheats", "0", CVAR_SERVERINFO|CVAR_LATCH); Cvar_Get ("protocol", va("%i", PROTOCOL_VERSION), CVAR_SERVERINFO|CVAR_NOSET);; - hostname = Cvar_Get ("hostname", "unnamed", CVAR_SERVERINFO | CVAR_ARCHIVE); + maxclients = Cvar_Get ("maxclients", "1", CVAR_SERVERINFO | CVAR_LATCH); + hostname = Cvar_Get ("hostname", "noname", CVAR_SERVERINFO | CVAR_ARCHIVE); timeout = Cvar_Get ("timeout", "125", 0); zombietime = Cvar_Get ("zombietime", "2", 0); sv_showclamp = Cvar_Get ("showclamp", "0", 0); @@ -925,17 +954,10 @@ void SV_Init (void) sv_noreload = Cvar_Get ("sv_noreload", "0", 0); - sv_wateraccelerate = Cvar_Get("sv_wateraccelerate", "-1", CVAR_ARCHIVE); - sv_airaccelerate = Cvar_Get("sv_airaccelerate", "-1", CVAR_ARCHIVE); - sv_accelerate = Cvar_Get("sv_accelerate", "10", CVAR_ARCHIVE); - sv_maxvelocity = Cvar_Get("sv_maxvelocity", "2000", CVAR_ARCHIVE ); - sv_maxspeed = Cvar_Get("sv_maxspeed", "320", CVAR_ARCHIVE); - sv_friction = Cvar_Get("sv_friction", "4", CVAR_ARCHIVE); - sv_gravity = Cvar_Get("sv_gravity", "800", CVAR_ARCHIVE); - - sv_rollangle = Cvar_Get("sv_rollangle", "2", CVAR_ARCHIVE); - sv_rollspeed = Cvar_Get("sv_rollspeed", "200", CVAR_ARCHIVE); - + sv_airaccelerate = Cvar_Get("sv_airaccelerate", "0", CVAR_LATCH); + sv_maxvelocity = Cvar_Get("sv_maxvelocity", "2000", 0 ); + sv_gravity = Cvar_Get("sv_gravity", "800", 0 ); + public_server = Cvar_Get ("public", "0", 0); sv_reconnect_limit = Cvar_Get ("sv_reconnect_limit", "3", CVAR_ARCHIVE); @@ -974,12 +996,12 @@ void SV_FinalMessage (char *message, bool reconnect) // send it twice // stagger the packets to crutch operating system limited buffers - for (i=0, cl = svs.clients ; ivalue ; i++, cl++) if (cl->state >= cs_connected) Netchan_Transmit (&cl->netchan, net_message.cursize , net_message.data); - for (i=0, cl = svs.clients ; ivalue ; i++, cl++) if (cl->state >= cs_connected) Netchan_Transmit (&cl->netchan, net_message.cursize , net_message.data); @@ -1000,7 +1022,7 @@ void SV_Shutdown (char *finalmsg, bool reconnect) if (svs.clients) SV_FinalMessage (finalmsg, reconnect); Master_Shutdown (); -//SV_ShutdownGameProgs (); + SV_ShutdownGameProgs (); // free current level if (sv.demofile) FS_Close (sv.demofile); diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index b9719183..77be12e4 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -1,130 +1,764 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// sv_phys.c - internal physic engine -//======================================================================= - #include "engine.h" #include "server.h" -// phys cvars -extern cvar_t *sv_maxvelocity; -extern cvar_t *sv_gravity; +#define STEPSIZE 18 +bool wasonground; +bool onconveyor; -void SV_CheckVelocity (prvm_edict_t *ent) +//damage types +#define DMG_CRUSH 20 +#define DMG_FALL 22 + +#define random() ((rand () & 0x7fff) / ((float)0x7fff)) +#define crandom() (2.0 * (random() - 0.5)) + +bool CanDamage (edict_t *targ, edict_t *inflictor) { - int i; - float wishspeed; + return false; +} - // bound velocity - for (i = 0; i < 3; i++) +void T_Damage (edict_t *targ, edict_t *inflictor, edict_t *attacker, vec3_t dir, vec3_t point, vec3_t normal, int damage, int knockback, int dflags, int mod) +{ +} +void T_RadiusDamage (edict_t *inflictor, edict_t *attacker, float damage, edict_t *ignore, float radius, int mod, double dmg_slope) +{ +} + + +/* +============= +SV_CheckBottom + +Returns false if any part of the bottom of the entity is off an edge that +is not a staircase. + +============= +*/ +int c_yes, c_no; + +bool SV_CheckBottom (edict_t *ent) +{ + vec3_t mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + VectorAdd (ent->s.origin, ent->mins, mins); + VectorAdd (ent->s.origin, ent->maxs, maxs); + + // if all of the points under the corners are solid world, don't bother + // with the tougher checks + // the corners must be within 16 of the midpoint + start[2] = mins[2] - 1; + + for (x = 0; x <= 1; x++) { - if (IS_NAN(ent->fields.sv->velocity[i])) + for (y = 0; y <= 1; y++) { - Msg("Got a NaN velocity on %s\n", PRVM_GetString(ent->fields.sv->classname)); - ent->fields.sv->velocity[i] = 0; - } - if (IS_NAN(ent->fields.sv->origin[i])) - { - Msg("Got a NaN origin on %s\n", PRVM_GetString(ent->fields.sv->classname)); - ent->fields.sv->origin[i] = 0; + start[0] = x ? maxs[0] : mins[0]; + start[1] = y ? maxs[1] : mins[1]; + if (SV_PointContents(start) != CONTENTS_SOLID) + goto realcheck; } } - // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster - wishspeed = DotProduct(ent->fields.sv->velocity, ent->fields.sv->velocity); - if (wishspeed > sv_maxvelocity->value * sv_maxvelocity->value) + c_yes++; + return true; // we got out easy + +realcheck: + c_no++; + + // check it for real... + start[2] = mins[2]; + + // the midpoint must be within 16 of the bottom + start[0] = stop[0] = (mins[0] + maxs[0])*0.5; + start[1] = stop[1] = (mins[1] + maxs[1])*0.5; + stop[2] = start[2] - 2*STEPSIZE; + trace = SV_Trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); + + if (trace.fraction == 1.0) + return false; + mid = bottom = trace.endpos[2]; + + // the corners must be within 16 of the midpoint + for (x = 0; x <= 1; x++) { - wishspeed = sv_maxvelocity->value / sqrt(wishspeed); - ent->fields.sv->velocity[0] *= wishspeed; - ent->fields.sv->velocity[1] *= wishspeed; - ent->fields.sv->velocity[2] *= wishspeed; + for ( y = 0; y <= 1; y++) + { + start[0] = stop[0] = x ? maxs[0] : mins[0]; + start[1] = stop[1] = y ? maxs[1] : mins[1]; + + trace = SV_Trace (start, vec3_origin, vec3_origin, stop, ent, MASK_MONSTERSOLID); + + if (trace.fraction != 1.0 && trace.endpos[2] > bottom) + bottom = trace.endpos[2]; + if (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE) + return false; + } + } + + c_yes++; + return true; +} + +/* +================ +droptofloor +================ +*/ +void SV_DropToFloor (edict_t *ent) +{ + trace_t tr; + vec3_t v, dest; + + VectorSet(v, -15,-15,-15); + VectorCopy (v, ent->mins); + VectorSet(v, 15, 15, 15); + VectorCopy (v, ent->maxs); + + if (ent->model) PF_setmodel (ent, ent->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); + + ent->solid = SOLID_BBOX; + ent->clipmask |= MASK_MONSTERSOLID; + if(!ent->health) ent->health = 20; + ent->takedamage = DAMAGE_YES; + + ent->movetype = MOVETYPE_TOSS; + + VectorSet(v, 0, 0, -128); + VectorAdd (ent->s.origin, v, dest); + + tr = SV_Trace (ent->s.origin, ent->mins, ent->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]); + SV_FreeEdict (ent); + return; + } + tr.endpos[2] += 1; + ent->mins[2] -= 1; + VectorCopy (tr.endpos, ent->s.origin); + + SV_LinkEdict (ent); +} + +void SV_CheckGround (edict_t *ent) +{ + vec3_t point; + trace_t trace; + + if((sv.time * 0.001) < ent->gravity_debounce_time) + return; + + if (ent->flags & (FL_SWIM|FL_FLY)) return; + + if (ent->velocity[2] > 100) + { + ent->groundentity = NULL; + 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; + + trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, point, ent, MASK_MONSTERSOLID); + + // check steepness + if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) + { + ent->groundentity = NULL; + return; + } + + // Lazarus: The following 2 lines were in the original code and commented out + // by id. However, the effect of this is that a player walking over + // a dead monster who is laying on a brush model will cause the + // 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; + 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]; } } -trace_t SV_TraceToss (prvm_edict_t *tossent, prvm_edict_t *ignore) +// +//================= +// other_FallingDamage +// Identical to player's P_FallingDamage... except of course ent doesn't have to be a player +//================= +// +void SV_FallingDamage (edict_t *ent) { - int i; - float gravity = 1.0; - vec3_t move, end; - vec3_t original_origin; - vec3_t original_velocity; - vec3_t original_angles; - vec3_t original_avelocity; - trace_t trace; + float delta; + float fall_time, fall_value; + int damage; + vec3_t dir; - VectorCopy(tossent->fields.sv->origin, original_origin ); - VectorCopy(tossent->fields.sv->velocity, original_velocity ); - VectorCopy(tossent->fields.sv->angles, original_angles ); - VectorCopy(tossent->fields.sv->avelocity, original_avelocity); + if (ent->movetype == MOVETYPE_NOCLIP) + return; - gravity *= sv_gravity->value * 0.05; - - for (i = 0; i < 200; i++) // LordHavoc: sanity check; never trace more than 10 seconds + if ((ent->oldvelocity[2] < 0) && (ent->velocity[2] > ent->oldvelocity[2]) && (!ent->groundentity)) { - SV_CheckVelocity (tossent); - tossent->fields.sv->velocity[2] -= gravity; - VectorMA (tossent->fields.sv->angles, 0.05, tossent->fields.sv->avelocity, tossent->fields.sv->angles); - VectorScale (tossent->fields.sv->velocity, 0.05, move); - VectorAdd (tossent->fields.sv->origin, move, end); - trace = SV_Trace(tossent->fields.sv->origin, tossent->fields.sv->mins, tossent->fields.sv->maxs, end, tossent, MASK_SOLID ); - VectorCopy (trace.endpos, tossent->fields.sv->origin); + delta = ent->oldvelocity[2]; + } + else + { + if (!ent->groundentity) + return; + delta = ent->velocity[2] - ent->oldvelocity[2]; + } + delta = delta*delta * 0.0001; - if (trace.fraction < 1) break; + // 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 (delta < 1) return; + + if (delta < 15) + { + ent->s.event = EV_FOOTSTEP; + return; } - VectorCopy(original_origin, tossent->fields.sv->origin ); - VectorCopy(original_velocity, tossent->fields.sv->velocity ); - VectorCopy(original_angles, tossent->fields.sv->angles ); - VectorCopy(original_avelocity, tossent->fields.sv->avelocity); + fall_value = delta*0.5; + if (fall_value > 40) fall_value = 40; + fall_time = (sv.time * 0.001) + 0.3; //FALL_TIME - return trace; + if (delta > 30) + { + damage = (delta-30)/2; + 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); + } +} + +/* +============= +SV_MoveStep + +Called by monster program code. +The move will be adjusted for slopes and stairs, but if the move isn't +possible, no move is done, false is returned, and +pr_global_struct->trace_normal is set to the normal of the blocking wall +============= +*/ +//FIXME since we need to test end position contents here, can we avoid doing +//it again later in catagorize position? +bool SV_MoveStep (edict_t *ent, vec3_t move, bool relink) +{ + float dz; + vec3_t oldorg, neworg, end; + trace_t trace; + int i; + float stepsize; + float jumpheight; + vec3_t test; + int contents; + + bool canjump; + float d1, d2; + int jump; // 1=jump up, -1=jump down + vec3_t forward, up; + vec3_t dir; + vec_t dist; + edict_t *target; + + // try the move + VectorCopy (ent->s.origin, oldorg); + VectorAdd (ent->s.origin, move, neworg); + + AngleVectors(ent->s.angles,forward,NULL,up); + if(ent->enemy) + target = ent->enemy; + else if(ent->movetarget) + target = ent->movetarget; + else + target = NULL; + + // flying monsters don't step up + if ( ent->flags & (FL_SWIM | FL_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) + { + if (!ent->goalentity) + ent->goalentity = ent->enemy; + dz = ent->s.origin[2] - ent->goalentity->s.origin[2]; + if (ent->goalentity->client) + { + if (dz > 40) neworg[2] -= 8; + if (!((ent->flags & FL_SWIM) && (ent->waterlevel < 2))) + if (dz < 30) neworg[2] += 8; + } + else + { + if (dz > 8) neworg[2] -= 8; + else if (dz > 0) neworg[2] -= dz; + else if (dz < -8) neworg[2] += 8; + else neworg[2] += dz; + } + } + trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, neworg, ent, MASK_MONSTERSOLID); + + // fly monsters don't enter water voluntarily + if (ent->flags & FL_FLY) + { + if (!ent->waterlevel) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = SV_PointContents(test); + if (contents & MASK_WATER) + return false; + } + } + + // swim monsters don't exit water voluntarily + if (ent->flags & FL_SWIM) + { + if (ent->waterlevel < 2) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = SV_PointContents(test); + if (!(contents & MASK_WATER)) + return false; + } + } + + if (trace.fraction == 1) + { + VectorCopy (trace.endpos, ent->s.origin); + if (relink) + { + SV_LinkEdict(ent); + SV_TouchTriggers (ent); + } + return true; + } + + if (!ent->enemy) + break; + } + + return false; + } + + // push down from a step height above the wished position + if (!(ent->monsterinfo.aiflags & AI_NOSTEP)) + stepsize = STEPSIZE; + else stepsize = 1; + + neworg[2] += stepsize; + VectorCopy (neworg, end); + end[2] -= stepsize*2; + + trace = SV_Trace (neworg, ent->mins, ent->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)) + { + // 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))) + canjump = false; + else if(target) + { + // Never jump unless it places monster closer to his goal + vec3_t dir; + VectorSubtract(target->s.origin, oldorg, dir); + d1 = VectorLength(dir); + VectorSubtract(target->s.origin, trace.endpos, dir); + d2 = VectorLength(dir); + if(d2 < d1) + canjump = true; + else + canjump = false; + } + else canjump = false; + } + else canjump = false; + + if (trace.allsolid) + { + if(canjump && (ent->monsterinfo.jumpup > 0)) + { + neworg[2] += ent->monsterinfo.jumpup - stepsize; + trace = SV_Trace (neworg, ent->mins, ent->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))) + { + // 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); + if(DotProduct(tr.plane.normal,forward) < -0.95) + { + jump = 1; + jumpheight = trace.endpos[2] - ent->s.origin[2]; + } + else return false; + } + } + else return false; + } + else return false; + } + + if (trace.startsolid) + { + neworg[2] -= stepsize; + trace = SV_Trace (neworg, ent->mins, ent->maxs, end, ent, MASK_MONSTERSOLID); + if (trace.allsolid || trace.startsolid) + return false; + } + + + // don't go in to water + // Lazarus: misc_actors don't go swimming, but wading is fine + if (ent->monsterinfo.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) + { + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = SV_PointContents(test); + if (contents & (CONTENTS_LAVA | CONTENTS_SLIME)) + return false; + } + test[2] = trace.endpos[2] + ent->viewheight - 1; + contents = SV_PointContents(test); + if (contents & MASK_WATER) + return false; + } + else if (ent->waterlevel == 0) + { + test[0] = trace.endpos[0]; + test[1] = trace.endpos[1]; + test[2] = trace.endpos[2] + ent->mins[2] + 1; + contents = SV_PointContents(test); + + if (contents & MASK_WATER) + return false; + } + + // Lazarus: Don't intentionally walk into lasers. + dist = VectorLength(move); + if(dist > 0.) + { + edict_t *e; + trace_t laser_trace; + vec_t delta; + vec3_t laser_mins, laser_maxs; + vec3_t laser_start, laser_end; + vec3_t monster_mins, monster_maxs; + + for(i = maxclients->value + 1; i < ge->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)) + 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); + 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]; + if( monster_maxs[0] < laser_mins[0] ) continue; + if( monster_maxs[1] < laser_mins[1] ) continue; + if( monster_maxs[2] < laser_mins[2] ) continue; + if( monster_mins[0] > laser_maxs[0] ) continue; + if( monster_mins[1] > laser_maxs[1] ) continue; + if( monster_mins[2] > laser_maxs[2] ) continue; + // If we arrive here, some part of the bounding box surrounding + // 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.)) + return false; + // Shift psuedo laser towards monster's current position up to + // the total distance he's proposing moving. + delta = min(16,dist); + VectorCopy(move,dir); + VectorNormalize(dir); + 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); + if(laser_trace.ent == ent) + return false; + delta += 16; + } + } + } + if ((trace.fraction == 1) && !jump && canjump && (ent->monsterinfo.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); + 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))) + jump = -1; + } + } + + + if ((trace.fraction == 1) && !jump) + { + // if monster had the ground pulled out, go ahead and fall + if ( ent->flags & FL_PARTIALGROUND ) + { + VectorAdd (ent->s.origin, move, ent->s.origin); + if (relink) + { + SV_LinkEdict(ent); + SV_TouchTriggers (ent); + } + ent->groundentity = NULL; + return true; + } + return false; // walked off an edge + } + + // check point traces down for dangling corners + VectorCopy (trace.endpos, ent->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)) + { + 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); + 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); + 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))) + { + VectorSubtract(target->s.origin, tr.endpos, dir); + d2 = VectorLength(dir); + if(d2 < d1) + skip = true; + } + } + } + + } + if (!skip) + { + if (!SV_CheckBottom (ent)) + { + if ( ent->flags & FL_PARTIALGROUND ) + { // entity had floor mostly pulled out from underneath it + // and is trying to correct + if (relink) + { + SV_LinkEdict (ent); + SV_TouchTriggers (ent); + } + return true; + } + VectorCopy (oldorg, ent->s.origin); + return false; + } + } + } + + if ( ent->flags & FL_PARTIALGROUND ) + { + ent->flags &= ~FL_PARTIALGROUND; + } + ent->groundentity = trace.ent; + if(trace.ent) ent->groundentity_linkcount = trace.ent->linkcount; + + // the move is ok + if(jump) + { + VectorScale(move, 10, ent->velocity); + if(jump > 0) + { + ent->monsterinfo.jump(ent); + ent->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; + } + if(relink) + { + SV_LinkEdict (ent); + SV_TouchTriggers (ent); + } + } + else if (relink) + { + SV_LinkEdict (ent); + SV_TouchTriggers (ent); + } + return true; +} + +/* +=============== +SV_WalkMove +=============== +*/ +bool SV_WalkMove (edict_t *ent, float yaw, float dist) +{ + vec3_t move; + + if (!ent->groundentity && !(ent->flags & (FL_FLY|FL_SWIM))) + return false; + + yaw = yaw * M_PI*2 / 360; + + move[0] = cos(yaw)*dist; + move[1] = sin(yaw)*dist; + move[2] = 0; + + return SV_MoveStep(ent, move, true); } /* ============ SV_TestEntityPosition -returns true if the entity is in solid currently ============ */ -int SV_TestEntityPosition (prvm_edict_t *ent) +edict_t *SV_TestEntityPosition (edict_t *ent) { - trace_t trace = SV_Trace(ent->fields.sv->origin, ent->fields.sv->mins, ent->fields.sv->maxs, ent->fields.sv->origin, ent, MASK_SOLID); + trace_t trace; + int mask; - if (trace.contents & MASK_SOLID) - return true; - return false; + if (ent->clipmask) mask = ent->clipmask; + else mask = MASK_SOLID; + + if(ent->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); + 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); + + 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))) + return NULL; + + // Lazarus - return a bit more useful info than simply "g_edicts" + if(trace.ent) return trace.ent; + else return ge->edicts; + } + + return NULL; +} + +/* +================ +SV_CheckVelocity +================ +*/ +void SV_CheckVelocity (edict_t *ent) +{ + if(VectorLength(ent->velocity) > sv_maxvelocity->value) + { + VectorNormalize(ent->velocity); + VectorScale(ent->velocity, sv_maxvelocity->value, ent->velocity); + } } /* ============= -SV_EntityThink +SV_RunThink -Runs thinking code if time. There is some play in the exact time the think -function will be called, because it is called before any movement is done -in a frame. Not used for pushmove objects, because they must be exact. -Returns false if the entity removed itself. +Runs thinking code for this frame if necessary ============= */ -bool SV_EntityThink (prvm_edict_t *ent) +bool SV_RunThink (edict_t *ent) { - float thinktime; + float thinktime; - thinktime = ent->fields.sv->nextthink; - if (thinktime <= 0 || thinktime > sv.time + sv.frametime) + thinktime = ent->nextthink; + if(thinktime <= 0) return true; + + if(thinktime > (sv.time * 0.001) + 0.001) return true; + + ent->nextthink = 0; + if (!ent->think) + PF_error ("NULL ent->think for %s",ent->classname); + ent->think (ent); - // 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; - - // reset nextthink, it will be restored in qc-code - ent->fields.sv->nextthink = 0; - prog->globals.server->time = thinktime; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); - PRVM_ExecuteProgram (ent->fields.sv->think, "QC function self.think is missing"); - return !ent->priv.sv->free; + return false; } /* @@ -134,48 +768,17 @@ SV_Impact Two entities have touched, so run their touch functions ================== */ -void SV_Impact (prvm_edict_t *e1, trace_t *trace) +void SV_Impact (edict_t *e1, trace_t *trace) { - int old_self, old_other; - prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; + edict_t *e2; - old_self = prog->globals.server->self; - old_other = prog->globals.server->other; + e2 = trace->ent; - prog->globals.server->time = sv.time; - if (!e1->priv.sv->free && !e2->priv.sv->free && e1->fields.sv->touch && e1->fields.sv->solid != SOLID_NOT) - { - prog->globals.server->self = PRVM_EDICT_TO_PROG(e1); - prog->globals.server->other = PRVM_EDICT_TO_PROG(e2); - 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_inwater = (trace->contents & MASK_WATER) ? true : false; - prog->globals.server->trace_inopen = (trace->contents & MASK_SHOT) ? true : false; - 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->fields.sv->touch, "QC function self.touch is missing"); - } - if (!e1->priv.sv->free && !e2->priv.sv->free && e2->fields.sv->touch && e2->fields.sv->solid != SOLID_NOT) - { - prog->globals.server->self = PRVM_EDICT_TO_PROG(e2); - prog->globals.server->other = PRVM_EDICT_TO_PROG(e1); - prog->globals.server->trace_allsolid = false; - prog->globals.server->trace_startsolid = false; - prog->globals.server->trace_fraction = 1; - prog->globals.server->trace_inwater = false; - prog->globals.server->trace_inopen = true; - VectorCopy (e2->fields.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->fields.sv->touch, "QC function self.touch is missing"); - } - prog->globals.server->self = old_self; - prog->globals.server->other = old_other; + 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); } @@ -187,17 +790,27 @@ Slide off of the impacting object returns the blocked flags (1 = floor, 2 = step / wall) ================== */ -void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) +int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) { - int i; - float backoff; + float backoff; + float change; + int i, blocked; + + blocked = 0; + if (normal[2] > 0) blocked |= 1; // floor + if (!normal[2]) blocked |= 2; // step + + backoff = DotProduct (in, normal) * overbounce; - backoff = -DotProduct (in, normal) * overbounce; - VectorMA(in, backoff, normal, out); - - for (i = 0;i < 3;i++) + for (i=0 ; i<3 ; i++) + { + change = normal[i]*backoff; + out[i] = in[i] - change; if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) out[i] = 0; + } + + return blocked; } /* @@ -209,149 +822,405 @@ Returns the clipflags if the velocity was modified (hit something solid) 1 = floor 2 = wall / step 4 = dead stop -If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored ============ */ -#define MAX_CLIP_PLANES 32 - -int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal) +#define MAX_CLIP_PLANES 5 +int SV_FlyMove (edict_t *ent, float time, int mask) { - int blocked = 0, bumpcount; - int i, j, impact, numplanes; - float d, time_left; - vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity; - trace_t trace; + edict_t *hit; + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + int blocked; + int num_retries = 0; - VectorCopy(ent->fields.sv->velocity, original_velocity); - VectorCopy(ent->fields.sv->velocity, primal_velocity); +retry: + numbumps = 4; + + blocked = 0; + VectorCopy (ent->velocity, original_velocity); + VectorCopy (ent->velocity, primal_velocity); numplanes = 0; + time_left = time; - for (bumpcount = 0; bumpcount < MAX_CLIP_PLANES; bumpcount++) + ent->groundentity = NULL; + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { - if (!ent->fields.sv->velocity[0] && !ent->fields.sv->velocity[1] && !ent->fields.sv->velocity[2]) - break; + for (i = 0; i < 3; i++) end[i] = ent->s.origin[i] + time_left * ent->velocity[i]; - VectorMA(ent->fields.sv->origin, time_left, ent->fields.sv->velocity, end); - trace = SV_Trace(ent->fields.sv->origin, ent->fields.sv->mins, ent->fields.sv->maxs, end, ent, MASK_SOLID); + trace = SV_Trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask); - // break if it moved the entire distance - if (trace.fraction == 1) - { - VectorCopy(trace.endpos, ent->fields.sv->origin); - break; + if (trace.allsolid) + { + // entity is trapped in another solid + VectorCopy (vec3_origin, ent->velocity); + return 3; } - if (!trace.ent) - { - MsgWarn("SV_FlyMove: !trace.ent"); - trace.ent = prog->edicts; - } - - if (((int) ent->fields.sv->flags & FL_ONGROUND) && ent->fields.sv->groundentity == PRVM_EDICT_TO_PROG(trace.ent)) - { - impact = false; - } - else - { - ent->fields.sv->flags = (int)ent->fields.sv->flags & ~FL_ONGROUND; - impact = true; - } - - if (trace.plane.normal[2]) - { - if (trace.plane.normal[2] > 0.7) - { - blocked |= 1; // floor - ent->fields.sv->flags = (int)ent->fields.sv->flags | FL_ONGROUND; - ent->fields.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); - } - } - else - { - blocked |= 2; // step - // save the trace for player extrafriction - if (stepnormal) VectorCopy(trace.plane.normal, stepnormal); - } - - if (trace.fraction >= 0.001) - { + if (trace.fraction > 0) + { // actually covered some distance - VectorCopy(trace.endpos, ent->fields.sv->origin); - VectorCopy(ent->fields.sv->velocity, original_velocity); + VectorCopy (trace.endpos, ent->s.origin); + VectorCopy (ent->velocity, original_velocity); numplanes = 0; } + if (trace.fraction == 1) + break; // moved the entire distance + + hit = trace.ent; + + // Lazarus: If the pushed entity is a conveyor, raise us up and + // try again + if (!num_retries && wasonground) + { + if ((hit->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); + VectorCopy (trace.endpos,end); + end[2] += 1; + VectorSubtract (end,ent->s.origin,ent->velocity); + VectorScale (ent->velocity,1.0/time_left,ent->velocity); + num_retries++; + goto retry; + } + } + + // if blocked by player AND on a conveyor + if (hit && hit->client && onconveyor) + { + vec3_t player_dest; + trace_t ptrace; + + if(ent->mass > hit->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); + if(ptrace.fraction == 1.0) + { + VectorCopy(player_dest,hit->s.origin); + SV_LinkEdict(hit); + goto retry; + } + } + blocked |= 8; + } + + if (trace.plane.normal[2] > 0.7) + { + blocked |= 1; // floor + if ( hit->solid == SOLID_BSP) + { + ent->groundentity = hit; + ent->groundentity_linkcount = hit->linkcount; + } + } + if (!trace.plane.normal[2]) + { + blocked |= 2; // step + } + // run the impact function - if (impact) - { - SV_Impact(ent, &trace); + SV_Impact (ent, &trace); + if (!ent->inuse) + break; // removed by the impact function - // break if removed by the impact function - if (ent->priv.sv->free) break; - } - - time_left *= 1 - trace.fraction; - - // clipped to another plane + + time_left -= time_left * trace.fraction; + + // cliped to another plane if (numplanes >= MAX_CLIP_PLANES) - { + { // this shouldn't really happen - VectorClear(ent->fields.sv->velocity); - blocked = 3; - break; + VectorCopy (vec3_origin, ent->velocity); + blocked |= 3; + return blocked; } - VectorCopy(trace.plane.normal, planes[numplanes]); + VectorCopy (trace.plane.normal, planes[numplanes]); numplanes++; // modify original_velocity so it parallels all of the clip planes - for (i = 0;i < numplanes;i++) + for (i=0 ; ivelocity); + } + else + { // go along the crease + if (numplanes != 2) + { +// gi.dprintf ("clip velocity, numplanes == %i\n",numplanes); + VectorCopy (vec3_origin, ent->velocity); + blocked |= 7; + return blocked; + } + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, ent->velocity); + VectorScale (dir, d, ent->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) + { + VectorCopy (vec3_origin, ent->velocity); + return blocked; + } + } + + return blocked; +} + +/* +============ +SV_PushableMove + +The basic solid body movement clip that slides along multiple planes +Returns the clipflags if the velocity was modified (hit something solid) +1 = floor +2 = wall / step +4 = dead stop +============ +*/ +#define MAX_CLIP_PLANES 5 +int SV_PushableMove (edict_t *ent, float time, int mask) +{ + edict_t *hit; + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + vec3_t end; + float time_left; + int blocked; + int num_retries = 0; + + // Corrective stuff added for bmodels with no origin brush + vec3_t mins, maxs; + vec3_t origin; + +retry: + + numbumps = 4; + ent->bouncetype = 0; + + blocked = 0; + VectorCopy (ent->velocity, original_velocity); + VectorCopy (ent->velocity, primal_velocity); + numplanes = 0; + + time_left = time; + + VectorAdd(ent->s.origin,ent->origin_offset,origin); + VectorCopy(ent->size,maxs); + VectorScale(maxs,0.5,maxs); + VectorNegate(maxs,mins); + + ent->groundentity = NULL; + + for (bumpcount=0 ; bumpcountvelocity[i]; + + trace = SV_Trace (origin, mins, maxs, end, ent, mask); + + if (trace.allsolid) + { + // entity is trapped in another solid + VectorCopy (vec3_origin, ent->velocity); + return 3; + } + + if (trace.fraction > 0) + { + // actually covered some distance + VectorCopy (trace.endpos, origin); + VectorSubtract (origin, ent->origin_offset, ent->s.origin); + VectorCopy (ent->velocity, original_velocity); + numplanes = 0; + } + + if (trace.fraction == 1) + break; // moved the entire distance + + hit = trace.ent; + + // Lazarus: If the pushed entity is a conveyor, raise us up and + // try again + if (!num_retries && wasonground) + { + if ((hit->movetype == MOVETYPE_CONVEYOR) && (trace.plane.normal[2] > 0.7)) + { + vec3_t above; + + VectorCopy(end,above); + 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); + num_retries++; + goto retry; + } + } + + // if blocked by player AND on a conveyor + if (hit->client && onconveyor) + { + vec3_t player_dest; + trace_t ptrace; + + if(ent->mass > hit->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); + if(ptrace.fraction == 1.0) + { + VectorCopy(player_dest,hit->s.origin); + SV_LinkEdict(hit); + goto retry; + } + } + blocked |= 8; + } + + if (trace.plane.normal[2] > 0.7) + { + // 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))) + { + blocked |= 1; // floor + if ( hit->solid == SOLID_BSP) + { + ent->groundentity = hit; + ent->groundentity_linkcount = hit->linkcount; + } + } + } + if (!trace.plane.normal[2]) + { + blocked |= 2; // step + } + + // run the impact function + SV_Impact (ent, &trace); + if (!ent->inuse) break; // removed by the impact function + + time_left -= time_left * trace.fraction; + + // clipped to another plane + if (numplanes >= MAX_CLIP_PLANES) + { + // this shouldn't really happen + VectorCopy (vec3_origin, ent->velocity); + blocked |= 3; + return blocked; + } + + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + + // modify original_velocity so it parallels all of the clip planes + for (i = 0; i < numplanes; i++) + { + // DH: experimenting here. 1 is no bounce, + // 1.5 bounces like a grenade, 2 is a superball + if(ent->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; + VectorCopy (vec3_origin, new_velocity); + } + else + { + // add a bit of random horizontal motion + if(!new_velocity[0]) new_velocity[0] = crandom() * new_velocity[2]/4; + if(!new_velocity[1]) new_velocity[1] = crandom() * new_velocity[2]/4; + } + } + else if(ent->bouncetype == 2) + { + VectorCopy(ent->velocity, new_velocity); + } + else + { + ClipVelocity (original_velocity, planes[i], new_velocity, 1); + } for (j = 0; j < numplanes; j++) { - if (j != i) // not ok + if ((j != i) && !VectorCompare (planes[i], planes[j])) { - if (DotProduct(new_velocity, planes[j]) < 0) - break; + if (DotProduct (new_velocity, planes[j]) < 0) + break; // not ok } } if (j == numplanes) break; } - + if (i != numplanes) - { + { // go along this plane - VectorCopy(new_velocity, ent->fields.sv->velocity); + VectorCopy (new_velocity, ent->velocity); } else - { - // go along the crease + { // go along the crease if (numplanes != 2) { - VectorClear(ent->fields.sv->velocity); - blocked = 7; - break; + VectorCopy (vec3_origin, ent->velocity); + blocked |= 7; + return blocked; } - - CrossProduct(planes[0], planes[1], dir); - VectorNormalize(dir); - d = DotProduct(dir, ent->fields.sv->velocity); - VectorScale(dir, d, ent->fields.sv->velocity); + CrossProduct (planes[0], planes[1], dir); + d = DotProduct (dir, ent->velocity); + VectorScale (dir, d, ent->velocity); } - // if current velocity is against the original velocity, - // stop dead to avoid tiny occilations in sloping corners - if (DotProduct(ent->fields.sv->velocity, primal_velocity) <= 0) + // if velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + if( !ent->bouncetype ) { - VectorClear(ent->fields.sv->velocity); - break; + if (DotProduct (ent->velocity, primal_velocity) <= 0) + { + VectorCopy (vec3_origin, ent->velocity); + return blocked; + } } } - - if ((int)ent->fields.sv->flags & FL_WATERJUMP) //from QuakeWorld - VectorCopy(primal_velocity, ent->fields.sv->velocity); return blocked; } @@ -361,11 +1230,10 @@ SV_AddGravity ============ */ -void SV_AddGravity (prvm_edict_t *ent) +void SV_AddGravity (edict_t *ent) { - float ent_gravity = 1.0; - - ent->fields.sv->velocity[2] -= ent_gravity * sv_gravity->value * sv.frametime; + if((sv.time * 0.001) > ent->gravity_debounce_time) + ent->velocity[2] -= ent->gravity * sv_gravity->value * 0.1; } /* @@ -375,675 +1243,577 @@ PUSHMOVE =============================================================================== */ + /* -============ +================================================= SV_PushEntity Does not change the entities velocity at all -============ + +called for MOVETYPE_TOSS + MOVETYPE_BOUNCE + MOVETYPE_FLY +================================================= */ -trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, bool failonbmodelstartsolid) +trace_t SV_PushEntity (edict_t *ent, vec3_t push) { - trace_t trace; - vec3_t end; + trace_t trace; + vec3_t start; + vec3_t end; + int mask; + int num_retries=0; - VectorAdd (ent->fields.sv->origin, push, end); + VectorCopy (ent->s.origin, start); + VectorAdd (start, push, end); - trace = SV_Trace(ent->fields.sv->origin, ent->fields.sv->mins, ent->fields.sv->maxs, end, ent, MASK_SOLID ); + if (ent->clipmask) + mask = ent->clipmask; + else + mask = MASK_SOLID; + +retry: + trace = SV_Trace (start, ent->mins, ent->maxs, end, ent, mask); - if (trace.startstuck && failonbmodelstartsolid) return trace; - VectorCopy (trace.endpos, ent->fields.sv->origin); + VectorCopy (trace.endpos, ent->s.origin); SV_LinkEdict (ent); - if (ent->fields.sv->solid >= SOLID_TRIGGER && trace.ent && (!((int)ent->fields.sv->flags & FL_ONGROUND) || ent->fields.sv->groundentity != PRVM_EDICT_TO_PROG(trace.ent))) + if (trace.fraction != 1.0) + { SV_Impact (ent, &trace); + + // if the pushed entity went away and the pusher is still there + if (!trace.ent->inuse && ent->inuse) + { + // move the pusher back and try again + VectorCopy (start, ent->s.origin); + SV_LinkEdict (ent); + goto retry; + } + + // Lazarus: If the pushed entity is a conveyor, raise us up and + // try again + if (!num_retries && wasonground) + { + if ((trace.ent->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); + VectorCopy (trace.endpos, end); + VectorCopy (start, ent->s.origin); + SV_LinkEdict(ent); + num_retries++; + goto retry; + } + } + if(onconveyor && !trace.ent->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 (ent->inuse) SV_TouchTriggers (ent); + return trace; +} + +typedef struct +{ + edict_t *ent; + vec3_t origin; + vec3_t angles; + float deltayaw; + +} pushed_t; + +pushed_t pushed[MAX_EDICTS], *pushed_p; +edict_t *obstacle; + +void MoveRiders_r(edict_t *platform, edict_t *ignore, vec3_t move, vec3_t amove, bool turn) +{ + int i; + edict_t *rider; + + for(i = 1, rider = EDICT_NUM(i); i <= ge->num_edicts; i++, rider = EDICT_NUM(i)) + { + if((rider->groundentity == platform) && (rider != ignore)) + { + VectorAdd(rider->s.origin, move, rider->s.origin); + if (turn && (amove[YAW] != 0.)) + { + if(!rider->client) rider->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; + } + } + SV_LinkEdict(rider); + + if(SV_TestEntityPosition(rider)) + { + // 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); + if(turn && (amove[YAW] != 0.)) + { + rider->s.angles[YAW] -= amove[YAW]; + if(rider->client) + { + rider->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); + rider->client->ps.viewangles[YAW] -= amove[YAW]; + } + } + SV_LinkEdict(rider); + } + else + { + // move this rider's riders + MoveRiders_r(rider, ignore, move, amove, turn); + } + } + } } /* ============ -SV_PushMove +RealBoundingBox +Returns the actual bounding box of a bmodel. This is a big improvement over +what q2 normally does with rotating bmodels - q2 sets absmin, absmax to a cube +that will completely contain the bmodel at *any* rotation on *any* axis, whether +the bmodel can actually rotate to that angle or not. This leads to a lot of +false block tests in SV_Push if another bmodel is in the vicinity. ============ */ -void SV_PushMove (prvm_edict_t *pusher, float movetime) +void RealBoundingBox(edict_t *ent, vec3_t mins, vec3_t maxs) { - int i, e, index; - float savesolid, movetime2, pushltime; - vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org; - int num_moved; - int numcheckentities; - static prvm_edict_t *checkentities[MAX_EDICTS]; - cmodel_t *pushermodel; - trace_t trace; + vec3_t forward, left, up, f1, l1, u1; + vec3_t p[8]; + int i, j, k, j2, k4; - if (VectorIsNull(pusher->fields.sv->velocity) && VectorIsNull(pusher->fields.sv->avelocity)) + for(k = 0; k < 2; k++) { - pusher->fields.sv->ltime += movetime; - return; - } + k4 = k * 4; + if(k) p[k4][2] = ent->maxs[2]; + else p[k4][2] = ent->mins[2]; - switch ((int)pusher->fields.sv->solid) - { - // LordHavoc: valid pusher types - case SOLID_BSP: - case SOLID_BBOX: - break; - // LordHavoc: no collisions - case SOLID_NOT: - case SOLID_TRIGGER: - VectorMA (pusher->fields.sv->origin, movetime, pusher->fields.sv->velocity, pusher->fields.sv->origin); - VectorMA (pusher->fields.sv->angles, movetime, pusher->fields.sv->avelocity, pusher->fields.sv->angles); - pusher->fields.sv->angles[0] -= 360.0 * floor(pusher->fields.sv->angles[0] * (1.0 / 360.0)); - pusher->fields.sv->angles[1] -= 360.0 * floor(pusher->fields.sv->angles[1] * (1.0 / 360.0)); - pusher->fields.sv->angles[2] -= 360.0 * floor(pusher->fields.sv->angles[2] * (1.0 / 360.0)); - pusher->fields.sv->ltime += movetime; - SV_LinkEdict (pusher); - return; - default: - MsgWarn("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.sv->solid); - return; - } + p[k4 + 1][2] = p[k4][2]; + p[k4 + 2][2] = p[k4][2]; + p[k4 + 3][2] = p[k4][2]; - index = (int) pusher->fields.sv->modelindex; - if (index < 1 || index >= MAX_MODELS) - { - MsgWarn("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.sv->modelindex); - return; - } - pushermodel = sv.models[index]; - - movetime2 = movetime; - VectorScale(pusher->fields.sv->velocity, movetime2, move1); - VectorScale(pusher->fields.sv->avelocity, movetime2, moveangle); - if (moveangle[0] || moveangle[2]) - { - for (i = 0; i < 3; i++) + for(j = 0; j < 2; j++) { - if (move1[i] > 0) + j2 = j * 2; + if(j) p[j2+k4][1] = ent->maxs[1]; + else p[j2+k4][1] = ent->mins[1]; + p[j2 + k4 + 1][1] = p[j2 + k4][1]; + + for(i = 0; i < 2; i++) { - mins[i] = pushermodel->rotatedmins[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->fields.sv->origin[i] + 1; - } - else - { - mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + pusher->fields.sv->origin[i] + 1; - } - } - } - else if (moveangle[1]) - { - for (i = 0; i < 3; i++) - { - if (move1[i] > 0) - { - mins[i] = pushermodel->yawmins[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->fields.sv->origin[i] + 1; - } - else - { - mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + pusher->fields.sv->origin[i] + 1; - } - } - } - else - { - for (i = 0; i < 3; i++) - { - if (move1[i] > 0) - { - mins[i] = pushermodel->normalmins[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->fields.sv->origin[i] + 1; - } - else - { - mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->fields.sv->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + pusher->fields.sv->origin[i] + 1; + if(i) p[i + j2 + k4][0] = ent->maxs[0]; + else p[i + j2 + k4][0] = ent->mins[0]; } } } - VectorNegate (moveangle, a); - AngleVectorsLeft(a, forward, left, up); + AngleVectors(ent->s.angles, forward, left, up); - VectorCopy (pusher->fields.sv->origin, pushorig); - VectorCopy (pusher->fields.sv->angles, pushang); - pushltime = pusher->fields.sv->ltime; + 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(p[i], l1, p[i]); + VectorAdd(p[i], u1, p[i]); + } - // move the pusher to its final position - VectorMA (pusher->fields.sv->origin, movetime, pusher->fields.sv->velocity, pusher->fields.sv->origin); - VectorMA (pusher->fields.sv->angles, movetime, pusher->fields.sv->avelocity, pusher->fields.sv->angles); - pusher->fields.sv->ltime += movetime; + VectorCopy(p[0],mins); + VectorCopy(p[0],maxs); + + for(i = 1; i < 8; i++) + { + mins[0] = min(mins[0], p[i][0]); + mins[1] = min(mins[1], p[i][1]); + mins[2] = min(mins[2], p[i][2]); + maxs[0] = max(maxs[0], p[i][0]); + maxs[1] = max(maxs[1], p[i][1]); + maxs[2] = max(maxs[2], p[i][2]); + } +} + +/* +============ +SV_Push + +Objects need to be moved back on a failed push, +otherwise riders would continue to slide. +============ +*/ +bool SV_Push (edict_t *pusher, vec3_t move, vec3_t amove) +{ + int i, e; + edict_t *check, *block; + vec3_t mins, maxs; + pushed_t *p; + vec3_t org, org2, org_check, forward, right, up; + vec3_t move2={0,0,0}; + vec3_t move3={0,0,0}; + vec3_t realmins, realmaxs; + bool turn = true; + trace_t tr; + + // clamp the move to 1/8 units, so the position will + // be accurate for client side prediction + for (i = 0; i < 3; i++) + { + float temp; + temp = move[i]*8.0; + if (temp > 0.0) temp += 0.5; + else temp -= 0.5; + move[i] = 0.125 * (int)temp; + } + + // find the bounding box + for (i = 0; i < 3; i++) + { + mins[i] = pusher->absmin[i] + move[i]; + maxs[i] = pusher->absmax[i] + move[i]; + } + + // we need this for pushing things later + VectorSubtract (vec3_origin, amove, org); + AngleVectors (org, forward, right, up); + + // 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]; + 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); SV_LinkEdict (pusher); - savesolid = pusher->fields.sv->solid; + // Lazarus: Standard Q2 takes a horrible shortcut + // with rotating brush models, setting + // absmin and absmax to a cube that would + // contain the brush model if it could + // rotate around ANY axis. The result is + // a lot of false hits on intersections, + // particularly when you have multiple + // rotating brush models in the same area. + // RealBoundingBox gives us the actual + // bounding box at the current angles. + RealBoundingBox(pusher,realmins,realmaxs); // see if any solid entities are inside the final position - num_moved = 0; + check = EDICT_NUM( 1 ); - numcheckentities = 0;//SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); - for (e = 0;e < numcheckentities; e++) + for (e = 1; e < ge->num_edicts; e++, check = EDICT_NUM(e)) { - prvm_edict_t *check = checkentities[e]; - if (check->fields.sv->movetype == MOVETYPE_NONE || check->fields.sv->movetype == MOVETYPE_PUSH || check->fields.sv->movetype == MOVETYPE_FOLLOW || check->fields.sv->movetype == MOVETYPE_NOCLIP) + if (!check->inuse) continue; + if (check == pusher->owner) continue; + if (check->movetype == MOVETYPE_PUSH || check->movetype == MOVETYPE_NONE || check->movetype == MOVETYPE_NOCLIP) continue; + if (!check->area.prev) + continue; // not linked in anywhere + // if the entity is standing on the pusher, it will definitely be moved - if (((int)check->fields.sv->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.sv->groundentity) == pusher) + if (check->groundentity != pusher) { - // remove the onground flag for non-players - if (check->fields.sv->movetype != MOVETYPE_WALK) - check->fields.sv->flags = (int)check->fields.sv->flags & ~FL_ONGROUND; - } - else - { - // if the entity is not inside the pusher's final position, leave it alone - if (!SV_ClipMoveToEntity(pusher, check->fields.sv->origin, check->fields.sv->mins, check->fields.sv->maxs, check->fields.sv->origin, MASK_SOLID).startsolid) + // 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] ) + continue; + + // see if the ent's bbox is inside the pusher's final position + if (!SV_TestEntityPosition (check)) continue; } - if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used + // 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)) { - vec3_t org2; - VectorSubtract (check->fields.sv->origin, pusher->fields.sv->origin, org); - org2[0] = DotProduct (org, forward); - org2[1] = DotProduct (org, left); - org2[2] = DotProduct (org, up); - VectorSubtract (org2, org, move); - VectorAdd (move, move1, move); + vec3_t dir; + VectorSubtract(check->s.origin,pusher->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); } - else - VectorCopy (move1, move); - VectorCopy (check->fields.sv->origin, check->priv.sv->moved_from); - VectorCopy (check->fields.sv->angles, check->priv.sv->moved_fromangles); - sv.moved_edicts[num_moved++] = check; - - // try moving the contacted entity - pusher->fields.sv->solid = SOLID_NOT; - trace = SV_PushEntity (check, move, true); - - // FIXME: turn players specially - check->fields.sv->angles[1] += trace.fraction * moveangle[1]; - pusher->fields.sv->solid = savesolid; // was SOLID_BSP - - // if it is still inside the pusher, block - if (SV_ClipMoveToEntity(pusher, check->fields.sv->origin, check->fields.sv->mins, check->fields.sv->maxs, check->fields.sv->origin, MASK_SOLID).startsolid) + if ((pusher->movetype == MOVETYPE_PUSH) || (pusher->movetype == MOVETYPE_PENDULUM) || (check->groundentity == pusher)) { - // try moving the contacted entity a tiny bit further to account for precision errors - vec3_t move2; - pusher->fields.sv->solid = SOLID_NOT; - VectorScale(move, 1.1, move2); - VectorCopy (check->priv.sv->moved_from, check->fields.sv->origin); - VectorCopy (check->priv.sv->moved_fromangles, check->fields.sv->angles); - SV_PushEntity (check, move2, true); - pusher->fields.sv->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->fields.sv->origin, check->fields.sv->mins, check->fields.sv->maxs, check->fields.sv->origin, MASK_SOLID).startsolid) + // move this entity + pushed_p->ent = check; + VectorCopy (check->s.origin, pushed_p->origin); + VectorCopy (check->s.angles, pushed_p->angles); + pushed_p++; + + // try moving the contacted entity + VectorAdd (check->s.origin, move, check->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)) { - // try moving the contacted entity a tiny bit less to account for precision errors - pusher->fields.sv->solid = SOLID_NOT; - VectorScale(move, 0.9, move2); - VectorCopy (check->priv.sv->moved_from, check->fields.sv->origin); - VectorCopy (check->priv.sv->moved_fromangles, check->fields.sv->angles); - SV_PushEntity (check, move2, true); - pusher->fields.sv->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->fields.sv->origin, check->fields.sv->mins, check->fields.sv->maxs, check->fields.sv->origin, MASK_SOLID).startsolid) + if(!check->client) { - // still inside pusher, so it's really blocked - - // fail the move - if (check->fields.sv->mins[0] == check->fields.sv->maxs[0]) - continue; - if (check->fields.sv->solid == SOLID_NOT || check->fields.sv->solid == SOLID_TRIGGER) + check->s.angles[YAW] += amove[YAW]; + } + else + { + if(amove[YAW] != 0.) { - // corpse - check->fields.sv->mins[0] = check->fields.sv->mins[1] = 0; - VectorCopy (check->fields.sv->mins, check->fields.sv->maxs); - continue; + check->client->ps.pmove.delta_angles[YAW] += ANGLE2SHORT(amove[YAW]); + check->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; + // 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; } - - VectorCopy (pushorig, pusher->fields.sv->origin); - VectorCopy (pushang, pusher->fields.sv->angles); - pusher->fields.sv->ltime = pushltime; - SV_LinkEdict (pusher); - - // move back any entities we already moved - for (i = 0;i < num_moved;i++) + if(amove[PITCH] != 0.) { - prvm_edict_t *ed = sv.moved_edicts[i]; - VectorCopy (ed->priv.sv->moved_from, ed->fields.sv->origin); - VectorCopy (ed->priv.sv->moved_fromangles, ed->fields.sv->angles); - SV_LinkEdict (ed); - } + float delta_yaw; + float pitch = amove[PITCH]; - // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if (pusher->fields.sv->blocked) - { - prog->globals.server->self = PRVM_EDICT_TO_PROG(pusher); - prog->globals.server->other = PRVM_EDICT_TO_PROG(check); - PRVM_ExecuteProgram (pusher->fields.sv->blocked, "QC function self.blocked is missing"); + delta_yaw = check->s.angles[YAW] - pusher->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; } - break; } } + + // 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((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); + 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); + 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); + 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; + + // Lazarus: func_tracktrain is a special case. Since we KNOW (if the map was + // constructed properly) that "move_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))) + { + 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); + VectorAdd(org,l,org); + org[2] += pusher->move_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); + if(!tr.startsolid) + { + VectorCopy(tr.endpos,check->s.origin); + VectorCopy(check->s.origin,org); + org[2] -= 128; + tr = SV_Trace(check->s.origin,check->mins,check->maxs,org,check,MASK_SOLID); + if(tr.fraction > 0) + VectorCopy(tr.endpos,check->s.origin); + } + } + } + } + } + + // may have pushed them off an edge + if (check->groundentity != pusher) check->groundentity = NULL; + + block = SV_TestEntityPosition (check); + + if (block && (pusher->flags & FL_TRACKTRAIN) && (check->client || (check->svflags & SVF_MONSTER)) && (check->groundentity == 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); + VectorAdd(org,l,org); + org[2] += pusher->move_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); + if(!tr.startsolid) + { + VectorCopy(tr.endpos,check->s.origin); + VectorCopy(check->s.origin,org); + org[2] -= 128; + tr = SV_Trace(check->s.origin,check->mins,check->maxs,org,check,MASK_SOLID); + if(tr.fraction > 0) + VectorCopy(tr.endpos,check->s.origin); + block = SV_TestEntityPosition (check); + } + } + + if (!block) + { // pushed ok + SV_LinkEdict (check); + // Lazarus: Move check riders, and riders of riders, and... well, you get the pic + VectorAdd(move, move2, move3); + MoveRiders_r(check,NULL,move3,amove,turn); + continue; // impact? + } + + // 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); + if(turn) + { + // Argh! - angle + check->s.angles[YAW] -= amove[YAW]; + if(check->client) + { + check->client->ps.pmove.delta_angles[YAW] -= ANGLE2SHORT(amove[YAW]); + check->client->ps.viewangles[YAW] -= amove[YAW]; + } + } + + block = SV_TestEntityPosition (check); + if (!block) + { + pushed_p--; + continue; + } } + + // save off the obstacle so we can call the block function + obstacle = check; + + // move back any entities we already moved + // go backwards, so if the same entity was pushed + // 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) + { + p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw; + } + SV_LinkEdict (p->ent); + } + return false; } - pusher->fields.sv->angles[0] -= 360.0 * floor(pusher->fields.sv->angles[0] * (1.0 / 360.0)); - pusher->fields.sv->angles[1] -= 360.0 * floor(pusher->fields.sv->angles[1] * (1.0 / 360.0)); - pusher->fields.sv->angles[2] -= 360.0 * floor(pusher->fields.sv->angles[2] * (1.0 / 360.0)); + + //FIXME: is there a better way to handle this? + // see if anything we moved has touched a trigger + for (p = pushed_p - 1; p >= pushed; p--) + SV_TouchTriggers (p->ent); + return true; } /* ================ -SV_PhysicsPusher +SV_Physics_Pusher +Bmodel objects don't interact with each other, but +push all box objects ================ */ -void SV_PhysicsPusher (prvm_edict_t *ent) +void SV_Physics_Pusher (edict_t *ent) { - float thinktime, oldltime, movetime; + vec3_t move, amove; + edict_t *part = ent; - oldltime = ent->fields.sv->ltime; + // make sure all team slaves can move before commiting + // any moves or calling any think functions + // if the move is blocked, all moved objects will be backed out + pushed_p = pushed; - thinktime = ent->fields.sv->nextthink; - if (thinktime < ent->fields.sv->ltime + sv.frametime) - { - movetime = thinktime - ent->fields.sv->ltime; - if (movetime < 0) movetime = 0; - } - else movetime = sv.frametime; + if (part->velocity[0] || part->velocity[1] || part->velocity[2] || part->avelocity[0] || part->avelocity[1] || part->avelocity[2]) + { + // object is moving + VectorScale (part->velocity, 0.1f, move); + VectorScale (part->avelocity, 0.1f, amove); - if (movetime) - { - // advances ent->fields.sv->ltime if not blocked - SV_PushMove(ent, movetime); + SV_Push(part, move, amove); // move was blocked } - if (thinktime > oldltime && thinktime <= ent->fields.sv->ltime) - { - // called QC think function - ent->fields.sv->nextthink = 0; - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); - PRVM_ExecuteProgram (ent->fields.sv->think, "QC function self.think is missing"); - } + if (pushed_p > &pushed[MAX_EDICTS]) + PF_error("pushed_p > &pushed[MAX_EDICTS], memory corrupted"); + + SV_RunThink (part); } -/* -=============================================================================== - -CLIENT MOVEMENT - -=============================================================================== -*/ -/* -============= -SV_CheckStuck - -This is a big hack to try and fix the rare case of getting stuck in the world -clipping hull. -============= -*/ -void SV_CheckStuck (prvm_edict_t *ent) -{ - int x, y, z; - vec3_t org; - - if (!SV_TestEntityPosition(ent)) - { - VectorCopy (ent->fields.sv->origin, ent->fields.sv->oldorigin); - return; - } - - VectorCopy (ent->fields.sv->origin, org); - VectorCopy (ent->fields.sv->oldorigin, ent->fields.sv->origin); - - if(!SV_TestEntityPosition(ent)) - { - Msg("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.sv->classname)); - SV_LinkEdict (ent); - return; - } - - for (z = -1; z < 18; z++) - { - for (x = -1; x <= 1; x++) - { - for (y =-1; y <= 1; y++) - { - ent->fields.sv->origin[0] = org[0] + x; - ent->fields.sv->origin[1] = org[1] + y; - ent->fields.sv->origin[2] = org[2] + z; - if (!SV_TestEntityPosition(ent)) - { - Msg("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.sv->classname), (float)x, (float)y, (float)z); - SV_LinkEdict (ent); - return; - } - } - } - } - - VectorCopy (org, ent->fields.sv->origin); - Msg("Stuck player %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.sv->classname)); -} - -void SV_UnstickEntity (prvm_edict_t *ent) -{ - int x, y, z; - vec3_t org; - - // if not stuck in a bmodel, just return - if (!SV_TestEntityPosition(ent)) - return; - - VectorCopy (ent->fields.sv->origin, org); - - for (z = -1; z < 18; z += 6) - { - for (x = -1; x <= 1; x++) - { - for (y =-1; y <= 1; y++) - { - ent->fields.sv->origin[0] = org[0] + x; - ent->fields.sv->origin[1] = org[1] + y; - ent->fields.sv->origin[2] = org[2] + z; - if (!SV_TestEntityPosition(ent)) - { - Msg("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.sv->classname), (float)x, (float)y, (float)z); - SV_LinkEdict(ent); - return; - } - } - } - } - - VectorCopy (org, ent->fields.sv->origin); - Msg("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.sv->classname)); -} +//================================================================== /* ============= -SV_CheckWater +SV_Physics_None + +Non moving objects can only think ============= */ -bool SV_CheckWater (prvm_edict_t *ent) +void SV_Physics_None (edict_t *ent) { - int cont; - vec3_t point; - - point[0] = ent->fields.sv->origin[0]; - point[1] = ent->fields.sv->origin[1]; - point[2] = ent->fields.sv->origin[2] + ent->fields.sv->mins[2] + 1; - - ent->fields.sv->waterlevel = 0; - ent->fields.sv->watertype = CONTENTS_NONE; - cont = SV_PointContents(point); - - if (cont & MASK_WATER) - { - ent->fields.sv->watertype = cont; - ent->fields.sv->waterlevel = 1; - point[2] = ent->fields.sv->origin[2] + (ent->fields.sv->mins[2] + ent->fields.sv->maxs[2]) * 0.5; - - if(SV_PointContents(point) & MASK_WATER) - { - ent->fields.sv->waterlevel = 2; - point[2] = ent->fields.sv->origin[2] + ent->fields.sv->view_ofs[2]; - if (SV_PointContents(point) & MASK_WATER) ent->fields.sv->waterlevel = 3; - } - } - - return ent->fields.sv->waterlevel > 1; -} - -/* -============ -SV_WallFriction - -============ -*/ -void SV_WallFriction (prvm_edict_t *ent, float *stepnormal) -{ - float d, i; - vec3_t forward, into, side; - - AngleVectorsRight(ent->fields.sv->v_angle, forward, NULL, NULL); - - if ((d = DotProduct (stepnormal, forward) + 0.5) < 0) - { - // cut the tangential velocity - i = DotProduct (stepnormal, ent->fields.sv->velocity); - VectorScale (stepnormal, i, into); - VectorSubtract (ent->fields.sv->velocity, into, side); - ent->fields.sv->velocity[0] = side[0] * (1 + d); - ent->fields.sv->velocity[1] = side[1] * (1 + d); - } -} - -/* -===================== -SV_TryUnstick - -Player has come to a dead stop, possibly due to the problem with limited -float precision at some angle joins in the BSP hull. - -Try fixing by pushing one pixel in each direction. - -This is a hack, but in the interest of good gameplay... -====================== -*/ -int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel) -{ - int i, clip; - vec3_t oldorg, dir; - - VectorCopy (ent->fields.sv->origin, oldorg); - VectorClear (dir); - - for (i = 0; i < 8; i++) - { - // try pushing a little in an axial direction - switch (i) - { - case 0: dir[0] = 2; dir[1] = 0; break; - case 1: dir[0] = 0; dir[1] = 2; break; - case 2: dir[0] = -2; dir[1] = 0; break; - case 3: dir[0] = 0; dir[1] = -2; break; - case 4: dir[0] = 2; dir[1] = 2; break; - case 5: dir[0] = -2; dir[1] = 2; break; - case 6: dir[0] = 2; dir[1] = -2; break; - case 7: dir[0] = -2; dir[1] = -2; break; - } - - SV_PushEntity (ent, dir, false); - - // retry the original move - ent->fields.sv->velocity[0] = oldvel[0]; - ent->fields.sv->velocity[1] = oldvel[1]; - ent->fields.sv->velocity[2] = 0; - clip = SV_FlyMove (ent, 0.1, NULL); - - if (fabs(oldorg[1] - ent->fields.sv->origin[1]) > 4 || fabs(oldorg[0] - ent->fields.sv->origin[0]) > 4) - { - Msg("SV_TryUnstick: success.\n"); - return clip; - } - // go back to the original pos and try again - VectorCopy (oldorg, ent->fields.sv->origin); - } - - // still not moving - VectorClear (ent->fields.sv->velocity); - Msg("SV_TryUnstick: failure.\n"); - return 7; -} - -/* -===================== -SV_WalkMove - -Only used by players -====================== -*/ -void SV_WalkMove(prvm_edict_t *ent) -{ - int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity; - vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity; - trace_t downtrace; - - SV_CheckVelocity(ent); - - // do a regular slide move unless it looks like you ran into a step - oldonground = (int)ent->fields.sv->flags & FL_ONGROUND; - ent->fields.sv->flags = (int)ent->fields.sv->flags & ~FL_ONGROUND; - - VectorCopy (ent->fields.sv->origin, start_origin); - VectorCopy (ent->fields.sv->velocity, start_velocity); - - clip = SV_FlyMove (ent, sv.frametime, NULL); - - SV_CheckVelocity(ent); - - VectorCopy(ent->fields.sv->origin, originalmove_origin); - VectorCopy(ent->fields.sv->velocity, originalmove_velocity); - originalmove_clip = clip; - originalmove_flags = (int)ent->fields.sv->flags; - originalmove_groundentity = ent->fields.sv->groundentity; - - if ((int)ent->fields.sv->flags & FL_WATERJUMP) - return; - - // if move didn't block on a step, return - if (clip & 2) - { - // if move was not trying to move into the step, return - if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125) - return; - - if (ent->fields.sv->movetype != MOVETYPE_FLY) - { - // return if gibbed by a trigger - if (ent->fields.sv->movetype != MOVETYPE_WALK) - return; - } - - // try moving up and forward to go up a step - // back to start pos - VectorCopy (start_origin, ent->fields.sv->origin); - VectorCopy (start_velocity, ent->fields.sv->velocity); - - // move up - VectorClear (upmove); - upmove[2] = 18; - - // FIXME: don't link? - SV_PushEntity(ent, upmove, false); - - // move forward - ent->fields.sv->velocity[2] = 0; - clip = SV_FlyMove (ent, sv.frametime, stepnormal); - ent->fields.sv->velocity[2] += start_velocity[2]; - - SV_CheckVelocity(ent); - - // check for stuckness, possibly due to the limited precision of floats - // in the clipping hulls - if (clip && fabs(originalmove_origin[1] - ent->fields.sv->origin[1]) < 0.03125 && fabs(originalmove_origin[0] - ent->fields.sv->origin[0]) < 0.03125) - { - Msg("wall\n"); - // stepping up didn't make any progress, revert to original move - VectorCopy(originalmove_origin, ent->fields.sv->origin); - VectorCopy(originalmove_velocity, ent->fields.sv->velocity); - ent->fields.sv->flags = originalmove_flags; - ent->fields.sv->groundentity = originalmove_groundentity; - return; - } - - //Msg("step - "); - - // extra friction based on view angle - if (clip & 2) SV_WallFriction (ent, stepnormal); - } - // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground - else if (ent->fields.sv->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->fields.sv->flags & FL_ONGROUND)) - return; - - // move down - VectorClear (downmove); - downmove[2] = -18 + start_velocity[2] * sv.frametime; - - // FIXME: don't link? - downtrace = SV_PushEntity (ent, downmove, false); - - if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7) - { - // this has been disabled so that you can't jump when you are stepping - // up while already jumping (also known as the Quake2 stair jump bug) - } - else - { - Msg("slope\n"); - - // if the push down didn't end up on good ground, use the move without - // the step up. This happens near wall / slope combinations, and can - // cause the player to hop up higher on a slope too steep to climb - VectorCopy(originalmove_origin, ent->fields.sv->origin); - VectorCopy(originalmove_velocity, ent->fields.sv->velocity); - ent->fields.sv->flags = originalmove_flags; - ent->fields.sv->groundentity = originalmove_groundentity; - } - - SV_CheckVelocity(ent); -} - -/* -============= -SV_Physics_Follow - -Entities that are "stuck" to another entity -============= -*/ -void SV_PhysicsFollow (prvm_edict_t *ent) -{ - vec3_t vf, vr, vu, angles, v; - prvm_edict_t *e; - // regular thinking - if (!SV_EntityThink (ent)) return; + SV_RunThink (ent); +} - e = PRVM_PROG_TO_EDICT(ent->fields.sv->aiment); - if (VectorCompare(e->fields.sv->angles, ent->fields.sv->punchangle )) - { - // quick case for no rotation - VectorAdd(e->fields.sv->origin, ent->fields.sv->view_ofs, ent->fields.sv->origin); - } - else - { - angles[0] = -ent->fields.sv->punchangle[0]; - angles[1] = ent->fields.sv->punchangle[1]; - angles[2] = ent->fields.sv->punchangle[2]; +/* +============= +SV_Physics_Noclip - AngleVectorsRight(angles, vf, vr, vu); +A moving object that doesn't obey physics +============= +*/ +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); - v[0] = ent->fields.sv->view_ofs[0] * vf[0] + ent->fields.sv->view_ofs[1] * vr[0] + ent->fields.sv->view_ofs[2] * vu[0]; - v[1] = ent->fields.sv->view_ofs[0] * vf[1] + ent->fields.sv->view_ofs[1] * vr[1] + ent->fields.sv->view_ofs[2] * vu[1]; - v[2] = ent->fields.sv->view_ofs[0] * vf[2] + ent->fields.sv->view_ofs[1] * vr[2] + ent->fields.sv->view_ofs[2] * vu[2]; - angles[0] = -e->fields.sv->angles[0]; // stupid quake legacy - angles[1] = e->fields.sv->angles[1]; - angles[2] = e->fields.sv->angles[2]; - - AngleVectorsRight(angles, vf, vr, vu); - - ent->fields.sv->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->fields.sv->origin[0]; - ent->fields.sv->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->fields.sv->origin[1]; - ent->fields.sv->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->fields.sv->origin[2]; - } - VectorAdd (e->fields.sv->angles, ent->fields.sv->v_angle, ent->fields.sv->angles); - SV_LinkEdict (ent); + SV_LinkEdict(ent); } /* @@ -1053,118 +1823,126 @@ TOSS / BOUNCE ============================================================================== */ -/* -============= -SV_CheckWaterTransition - -============= -*/ -void SV_CheckWaterTransition (prvm_edict_t *ent) -{ - int cont = SV_PointContents(ent->fields.sv->origin); - - if (!ent->fields.sv->watertype) - { - // just spawned here - ent->fields.sv->watertype = cont; - ent->fields.sv->waterlevel = 1; - return; - } - - if (cont & MASK_WATER) - { - ent->fields.sv->watertype = cont; - ent->fields.sv->waterlevel = 1; - } - else - { - ent->fields.sv->watertype = CONTENTS_NONE; - ent->fields.sv->waterlevel = 0; - } -} - /* ============= -SV_PhysicsToss +SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ -void SV_PhysicsToss (prvm_edict_t *ent) +void SV_Physics_Toss (edict_t *ent) { - trace_t trace; - vec3_t move; + trace_t trace; + vec3_t move; + float backoff; + bool wasinwater; + bool isinwater; + vec3_t old_origin; - // if onground, return without moving - if ((int)ent->fields.sv->flags & FL_ONGROUND) + // regular thinking + SV_RunThink (ent); + + if (ent->groundentity) wasonground = true; + + if (ent->velocity[2] > 0) ent->groundentity = NULL; + + // check for the groundentity going away + if (ent->groundentity) + if (!ent->groundentity->inuse) + ent->groundentity = NULL; + + // Lazarus: conveyor + if (ent->groundentity && (ent->groundentity->movetype == MOVETYPE_CONVEYOR)) { - if (ent->fields.sv->velocity[2] >= (1.0 / 32.0)) + vec3_t point, end; + trace_t tr; + edict_t *ground = ent->groundentity; + + VectorCopy(ent->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.ent HAS to be ground, but just in case we screwed something up: + if(tr.ent == ground) { - // don't stick to ground if onground and moving upward - ent->fields.sv->flags -= FL_ONGROUND; - } - else if (!ent->fields.sv->groundentity) - { - // we can trust FL_ONGROUND if groundentity is world because it never moves - return; + onconveyor = true; + ent->velocity[0] = ground->movedir[0] * ground->speed; + ent->velocity[1] = ground->movedir[1] * ground->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) + { + // then we're moving down + ent->velocity[2] = -ent->velocity[2]; + } + } + VectorScale (ent->velocity, 0.1f, move); + trace = SV_PushEntity (ent, move); + if (!ent->inuse) return; + SV_CheckGround(ent); } } + + // if onground, return without moving + if ( ent->groundentity ) + return; + + VectorCopy (ent->s.origin, old_origin); + SV_CheckVelocity (ent); // add gravity - if (ent->fields.sv->movetype == MOVETYPE_TOSS || ent->fields.sv->movetype == MOVETYPE_BOUNCE) + if (ent->movetype != MOVETYPE_FLY) SV_AddGravity (ent); // move angles - VectorMA (ent->fields.sv->angles, sv.frametime, ent->fields.sv->avelocity, ent->fields.sv->angles); + VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); // move origin - VectorScale (ent->fields.sv->velocity, sv.frametime, move); - trace = SV_PushEntity (ent, move, true); - if (ent->priv.sv->free) return; + VectorScale (ent->velocity, 0.1f, move); + trace = SV_PushEntity (ent, move); + if (!ent->inuse) + return; - if (trace.startstuck) + if (trace.fraction < 1 ) { - // try to unstick the entity - SV_UnstickEntity(ent); - trace = SV_PushEntity (ent, move, false); - if (ent->priv.sv->free) return; - } - - if (trace.fraction < 1) - { - if (ent->fields.sv->movetype == MOVETYPE_BOUNCE) - { - float d; - ClipVelocity (ent->fields.sv->velocity, trace.plane.normal, ent->fields.sv->velocity, 1.5); - - d = DotProduct(trace.plane.normal, ent->fields.sv->velocity); - if (trace.plane.normal[2] > 0.7 && fabs(d) < 60) - { - ent->fields.sv->flags = (int)ent->fields.sv->flags | FL_ONGROUND; - ent->fields.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); - VectorClear (ent->fields.sv->velocity); - VectorClear (ent->fields.sv->avelocity); - } - else ent->fields.sv->flags = (int)ent->fields.sv->flags & ~FL_ONGROUND; - } + if (ent->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 - { - ClipVelocity (ent->fields.sv->velocity, trace.plane.normal, ent->fields.sv->velocity, 1.0); - if (trace.plane.normal[2] > 0.7) + backoff = 1; + + ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); + + // stop if on ground + if (trace.plane.normal[2] > 0.7) + { + if (ent->velocity[2] < 60.0f || (ent->movetype != MOVETYPE_BOUNCE) ) { - ent->fields.sv->flags = (int)ent->fields.sv->flags | FL_ONGROUND; - ent->fields.sv->groundentity = PRVM_EDICT_TO_PROG(trace.ent); - VectorClear (ent->fields.sv->velocity); - VectorClear (ent->fields.sv->avelocity); + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->avelocity); } - else ent->fields.sv->flags = (int)ent->fields.sv->flags & ~FL_ONGROUND; } } - // check for in water - SV_CheckWaterTransition (ent); + // check for water transition + wasinwater = (ent->watertype & MASK_WATER); + ent->watertype = SV_PointContents (ent->s.origin); + isinwater = ent->watertype & MASK_WATER; + + if (isinwater) ent->waterlevel = 1; + else ent->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); } /* @@ -1174,6 +1952,7 @@ STEPPING MOVEMENT =============================================================================== */ + /* ============= SV_Physics_Step @@ -1183,234 +1962,690 @@ all movement is done with discrete steps. This is also used for objects that have become still on the ground, but will fall if the floor is pulled out from under them. +FIXME: is this true? ============= */ -void SV_PhysicsStep (prvm_edict_t *ent) -{ - int flags = (int)ent->fields.sv->flags; +//FIXME: hacked in for E3 demo +#define sv_stopspeed 100 +#define sv_friction 6 +#define sv_waterfriction 1 - // don't fall at all if fly/swim - if (!(flags & (FL_FLY | FL_SWIM))) +void SV_AddRotationalFriction (edict_t *ent) +{ + int n; + float adjustment; + + VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); + adjustment = 0.1f * sv_stopspeed * sv_friction; + + for (n = 0; n < 3; n++) { - if (flags & FL_ONGROUND) + if (ent->avelocity[n] > 0) { - // freefall if onground and moving upward - // freefall if not standing on a world surface (it may be a lift or trap door) - if (ent->fields.sv->velocity[2] >= (1.0 / 32.0) || ent->fields.sv->groundentity) + ent->avelocity[n] -= adjustment; + if (ent->avelocity[n] < 0) + ent->avelocity[n] = 0; + } + else + { + ent->avelocity[n] += adjustment; + if (ent->avelocity[n] > 0) + ent->avelocity[n] = 0; + } + } +} + +#define WATER_DENSITY 0.00190735 + +float RiderMass(edict_t *platform) +{ + float mass = 0; + int i; + edict_t *rider; + trace_t trace; + vec3_t point; + + for(i = 1, rider = EDICT_NUM(i); i <= ge->num_edicts; i++, rider = EDICT_NUM(i)) + { + if(rider == platform) continue; + if(!rider->inuse) continue; + if(rider->groundentity == platform) + { + mass += rider->mass; + mass += RiderMass(rider); + } + else if (rider->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); + point[2] -= 0.25; + trace = SV_Trace (rider->s.origin, rider->mins, rider->maxs, point, rider, MASK_MONSTERSOLID); + if ( trace.plane.normal[2] < 0.7 && !trace.startsolid) + continue; + if (!trace.startsolid && !trace.allsolid) { - ent->fields.sv->flags -= FL_ONGROUND; - SV_AddGravity(ent); - SV_CheckVelocity(ent); - SV_FlyMove(ent, sv.frametime, NULL); - SV_LinkEdict(ent); + if(trace.ent == platform) + { + mass += rider->mass; + mass += RiderMass(rider); + } + } + } + } + return mass; +} + +void SV_Physics_Step (edict_t *ent) +{ + bool hitsound = false; + float *vel; + float speed, newspeed, control; + float friction; + edict_t *ground; + edict_t *e; + int cont; + int mask; + int i; + int oldwaterlevel; + vec3_t point, end; + vec3_t old_origin, move; + + // airborne monsters should always check for ground + if (!ent->groundentity) SV_CheckGround (ent); + + oldwaterlevel = ent->waterlevel; + + VectorCopy(ent->s.origin, old_origin); + + // Lazarus: If density hasn't been calculated yet, do so now + if (ent->mass > 0 && ent->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 + } + } + + // 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) ) + { + point[0] = (ent->absmax[0] + ent->absmin[0])/2; + point[1] = (ent->absmax[1] + ent->absmin[1])/2; + point[2] = ent->absmin[2] + 1; + cont = SV_PointContents (point); + if (!(cont & MASK_WATER)) + { + ent->waterlevel = 0; + ent->watertype = 0; + } + else { + ent->watertype = cont; + ent->waterlevel = 1; + point[2] = ent->absmin[2] + ent->size[2]/2; + cont = SV_PointContents (point); + if (cont & MASK_WATER) + { + ent->waterlevel = 2; + point[2] = ent->absmax[2]; + cont = SV_PointContents (point); + if (cont & MASK_WATER) + ent->waterlevel = 3; + } + } + } + + ground = ent->groundentity; + + SV_CheckVelocity (ent); + + if (ground) wasonground = true; + + if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2]) + SV_AddRotationalFriction (ent); + + // add gravity except: + // flying monsters + // swimming monsters who are in the water + if (!wasonground) + { + if (!(ent->flags & FL_FLY)) + { + if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2))) + { + if (ent->velocity[2] < sv_gravity->value*-0.1) + hitsound = true; + if (ent->waterlevel == 0) + SV_AddGravity (ent); + } + } + } + + // friction for flying monsters that have been given vertical velocity + if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0)) + { + speed = fabs(ent->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; + } + + // friction for swimming monsters that have been given vertical velocity + if (ent->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)) + { + speed = fabs(ent->velocity[2]); + control = speed < sv_stopspeed ? sv_stopspeed : speed; + newspeed = speed - (0.1f * control * sv_waterfriction * ent->waterlevel); + if (newspeed < 0) newspeed = 0; + newspeed /= speed; + ent->velocity[2] *= newspeed; + } + } + + // Lazarus: Floating stuff + if ((ent->movetype == MOVETYPE_PUSHABLE) && (ent->flags && FL_SWIM) && (ent->waterlevel)) + { + float waterlevel; + float rider_mass, total_mass; + trace_t tr; + float Accel, Area, Drag, Force; + + VectorCopy(point,end); + if(ent->waterlevel < 3) + { + point[2] = ent->absmax[2]; + end[2] = ent->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; + } + rider_mass = RiderMass(ent); + total_mass = rider_mass + ent->mass; + Area = ent->size[0] * ent->size[1]; + if(waterlevel < ent->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) + { + speed = fabs(ent->velocity[2]); + control = speed < sv_stopspeed ? sv_stopspeed : speed; + newspeed = speed - (0.1f * control * sv_waterfriction * ent->waterlevel); + if (newspeed < 0) newspeed = 0; + newspeed /= speed; + ent->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); + 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; + } + else + { + // Crate is fully submerged + Force = -total_mass + ent->volume * WATER_DENSITY; + if(sv_gravity->value) + { + Drag = 0.00190735 * 1.05 * Area * (ent->velocity[2]*ent->velocity[2])/sv_gravity->value; + if(Drag > fabs(Force)) + { + // Drag actually CAN be > total weight, but if we do this we tend to + // get crates flying back out of the water after being dropped from some + // height + Drag = fabs(Force); + } + if(ent->velocity[2] > 0) + Drag = -Drag; + Force += Drag; + } + Accel = Force * sv_gravity->value/total_mass; + ent->velocity[2] += Accel*0.1f; + } + + if(ent->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; + else v = 50.; + current = ent->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]); + } + } + } + + // Conveyor + if (wasonground && (ground->movetype == MOVETYPE_CONVEYOR)) + { + trace_t tr; + + VectorCopy(ent->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.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; + 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) + { + // Then we're moving down. + ent->velocity[2] = -ent->velocity[2] + 2; + } + } + } + } + + if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0]) + { + int block; + // apply friction + // let dead monsters who aren't completely onground slide + + if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY))) + + if (!onconveyor) + { + if (!(ent->health <= 0.0 && !SV_CheckBottom(ent))) + { + vel = ent->velocity; + speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); + if (speed) + { + friction = sv_friction; + + control = speed < sv_stopspeed ? sv_stopspeed : speed; + newspeed = speed - 0.1f*control*friction; + + if (newspeed < 0) newspeed = 0; + newspeed /= speed; + + vel[0] *= newspeed; + vel[1] *= newspeed; + } + } + } + + 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 + else mask = MASK_SOLID; + + if (ent->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; } } else { - // freefall if not onground - int hitsound = ent->fields.sv->velocity[2] < sv_gravity->value * -0.1; - - SV_AddGravity(ent); - SV_CheckVelocity(ent); - SV_FlyMove(ent, sv.frametime, NULL); - SV_LinkEdict(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; + } } + SV_LinkEdict (ent); + SV_TouchTriggers (ent); + if (!ent->inuse) return; + + if (ent->groundentity && !wasonground && hitsound) + { + PF_StartSound (ent, 0, SV_SoundIndex("world/land.wav"), 1, 1, 0); + } + + // Move func_pushable riders + if(ent->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(e==ent) continue; + if(e->groundentity == 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); + SV_LinkEdict(e); + } + } + } + } + else if(ent->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; + } + + + // Lazarus: Add falling damage for entities that can be damaged + if( ent->takedamage ) + { + SV_FallingDamage(ent); + VectorCopy(ent->velocity,ent->oldvelocity); + } + + if ((!oldwaterlevel && ent->waterlevel) && !ent->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); } // regular thinking - SV_EntityThink(ent); - SV_CheckWaterTransition(ent); + SV_RunThink (ent); + VectorCopy(ent->velocity,ent->oldvelocity); } -void SV_PhysicsClient(prvm_edict_t *ent) -{ - SV_ApplyClientMove(); - SV_CheckVelocity(ent); // make sure the velocity is sane (not a NaN) - SV_ClientThink(); - SV_CheckVelocity(ent); // make sure the velocity is sane (not a NaN) +//============================================================================ +/* +============ +SV_DebrisEntity - // call standard client pre-think - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram (prog->globals.server->PlayerPreThink, "QC function PlayerPreThink is missing"); +Does not change the entities velocity at all +============ +*/ +trace_t SV_DebrisEntity (edict_t *ent, vec3_t push) +{ + trace_t trace; + vec3_t start; + vec3_t end; + vec3_t v1, v2; + vec_t dot, speed1, speed2; + float scale; + int damage; + int mask; + + VectorCopy (ent->s.origin, start); + VectorAdd (start, push, end); + if(ent->clipmask) mask = ent->clipmask; + else mask = MASK_SHOT; + + trace = SV_Trace (start, ent->mins, ent->maxs, end, ent, mask); + VectorCopy (trace.endpos, ent->s.origin); + SV_LinkEdict (ent); + + if (trace.fraction != 1.0) + { + if( (trace.surface) && (trace.surface->flags & SURF_SKY)) + { + SV_FreeEdict(ent); + return trace; + } + if(trace.ent->client || (trace.ent->svflags & SVF_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(!speed1) return trace; + speed2 = VectorLength(trace.ent->velocity); + VectorCopy(ent->velocity,v1); + VectorNormalize(v1); + VectorCopy(trace.ent->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); + // 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); + } + if(ent->touch) ent->touch (ent, trace.ent, &trace.plane, trace.surface); + + SV_LinkEdict(trace.ent); + } + else + { + SV_Impact (ent, &trace); + } + } + return trace; +} + +/* +============= +SV_Physics_Debris + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ +void SV_Physics_Debris (edict_t *ent) +{ + trace_t trace; + vec3_t move; + float backoff; + bool wasinwater; + bool isinwater; + vec3_t old_origin; + + // regular thinking + SV_RunThink (ent); + + if (ent->velocity[2] > 0) + ent->groundentity = NULL; + + // check for the groundentity going away + if (ent->groundentity) + if (!ent->groundentity->inuse) + ent->groundentity = NULL; + + // if onground, return without moving + if ( ent->groundentity ) + return; + + VectorCopy (ent->s.origin, old_origin); SV_CheckVelocity (ent); + SV_AddGravity (ent); - switch ((int)ent->fields.sv->movetype) + // move angles + VectorMA (ent->s.angles, 0.1f, ent->avelocity, ent->s.angles); + + // move origin + VectorScale (ent->velocity, 0.1f, move); + trace = SV_DebrisEntity (ent, move); + if (!ent->inuse) + return; + + if (trace.fraction < 1) { - case MOVETYPE_PUSH: - SV_PhysicsPusher(ent); - break; - case MOVETYPE_NONE: - if (ent->fields.sv->nextthink > 0 && ent->fields.sv->nextthink <= sv.time + sv.frametime) - SV_EntityThink(ent); - break; - case MOVETYPE_FOLLOW: - SV_PhysicsFollow(ent); - break; - case MOVETYPE_NOCLIP: - if (SV_EntityThink(ent)) - { - SV_CheckWater(ent); - VectorMA(ent->fields.sv->origin, sv.frametime, ent->fields.sv->velocity, ent->fields.sv->origin); - VectorMA(ent->fields.sv->angles, sv.frametime, ent->fields.sv->avelocity, ent->fields.sv->angles); + backoff = 1.0; + ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff); + + // stop if on ground + if (trace.plane.normal[2] > 0.3) + { + if (ent->velocity[2] < 60) + { + ent->groundentity = trace.ent; + ent->groundentity_linkcount = trace.ent->linkcount; + VectorCopy (vec3_origin, ent->velocity); + VectorCopy (vec3_origin, ent->avelocity); + } } - break; - case MOVETYPE_STEP: - SV_PhysicsStep(ent); - break; - case MOVETYPE_WALK: - if (SV_EntityThink(ent)) - { - if(!SV_CheckWater(ent) && ! ((int)ent->fields.sv->flags & FL_WATERJUMP)) - SV_AddGravity (ent); - SV_CheckStuck (ent); - SV_WalkMove (ent); - } - break; - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - if (SV_EntityThink (ent)) - SV_PhysicsToss (ent); - break; - case MOVETYPE_FLY: - if(SV_EntityThink (ent)) - { - SV_CheckWater(ent); - SV_WalkMove(ent); - } - break; - default: - MsgWarn("SV_PhysicsClient: bad movetype %i\n", (int)ent->fields.sv->movetype); - break; - } - - SV_CheckVelocity (ent); - SV_LinkEdict(ent); - SV_CheckVelocity(ent); - - // call standard player post-think - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); - PRVM_ExecuteProgram (prog->globals.server->PlayerPostThink, "QC function PlayerPostThink is missing"); -} - -void SV_PhysicsEntity(prvm_edict_t *ent) -{ - // don't run a move on newly spawned projectiles as it messes up movement - // interpolation and rocket trails - bool runmove = ent->priv.sv->move; - ent->priv.sv->move = true; - - switch ((int) ent->fields.sv->movetype) - { - case MOVETYPE_PUSH: - SV_PhysicsPusher (ent); - break; - case MOVETYPE_NONE: - if (ent->fields.sv->nextthink > 0 && ent->fields.sv->nextthink <= sv.time + sv.frametime) - SV_EntityThink (ent); - break; - case MOVETYPE_FOLLOW: - SV_PhysicsFollow (ent); - break; - case MOVETYPE_NOCLIP: - if (SV_EntityThink(ent)) - { - SV_CheckWater(ent); - VectorMA(ent->fields.sv->origin, sv.frametime, ent->fields.sv->velocity, ent->fields.sv->origin); - VectorMA(ent->fields.sv->angles, sv.frametime, ent->fields.sv->avelocity, ent->fields.sv->angles); - } - SV_LinkEdict(ent); - break; - case MOVETYPE_STEP: - SV_PhysicsStep(ent); - break; - case MOVETYPE_WALK: - if(SV_EntityThink(ent)) - { - if (!SV_CheckWater (ent) && !((int)ent->fields.sv->flags & FL_WATERJUMP)) - SV_AddGravity (ent); - SV_CheckStuck (ent); - SV_WalkMove (ent); - SV_LinkEdict (ent); - } - break; - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - case MOVETYPE_FLY: - if (SV_EntityThink (ent) && runmove) - SV_PhysicsToss (ent); - break; - default: - MsgWarn("SV_Physics: bad movetype %i\n", (int)ent->fields.sv->movetype); - break; - } -} - -void ClientEndServerFrame (prvm_edict_t *ent) -{ - int i; - - return; - - for (i = 0; i < 3; i++) - { - ent->priv.sv->state.old_origin[i] = ent->priv.sv->state.origin[i]; - ent->priv.sv->client->pmove.origin[i] = ent->priv.sv->state.origin[i]*8.0; - ent->priv.sv->client->pmove.velocity[i] = ent->fields.sv->velocity[i]*8.0; - } - -} - -void SV_Physics (void) -{ - int i; - prvm_edict_t *ent; - - - // we always need to bump framenum, even if we - // don't run the world, otherwise the delta - // compression can get confused when a client - // has the "current" frame - sv.framenum++; - sv.frametime = sv.framenum * 0.1; - - if(sv_paused->value && host.maxclients == 1) return; - - // let the progs know that a new frame has started - prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.server->time = sv.time; - prog->globals.server->frametime = sv.frametime; - PRVM_ExecuteProgram (prog->globals.server->StartFrame, "QC function StartFrame is missing"); - - // run physics on the client entities - for (i = 1, sv_client = svs.clients; i < host.maxclients; i++, sv_client++) - { - if (sv_client->edict->priv.sv->free) continue; - ClientEndServerFrame (sv_client->edict); - - // don't do physics on disconnected clients, FrikBot relies on this - if (sv_client->state != cs_spawned) - memset(&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); - else SV_PhysicsClient(sv_client->edict); - } - for (i = 1;i < prog->num_edicts; i++) + // check for water transition + wasinwater = (ent->watertype & MASK_WATER); + ent->watertype = SV_PointContents (ent->s.origin); + isinwater = ent->watertype & MASK_WATER; + + if (isinwater) ent->waterlevel = 1; + else ent->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); + +} + +/* +==================== +SV_Physics_Conveyor + +REAL simple - all we do is check for player riders and adjust their position. +Only gotcha here is we have to make sure we don't end up embedding player in +*another* object that's being moved by the conveyor. + +==================== +*/ +void SV_Physics_Conveyor(edict_t *ent) +{ + edict_t *player; + int i; + trace_t tr; + vec3_t v, move; + vec3_t point, end; + + VectorScale(ent->movedir,ent->speed,v); + VectorScale(v, 0.1f, move); + + for(i = 0; i < maxclients->value; i++) { - ent = PRVM_EDICT_NUM( i ); - if (ent->priv.sv->free) continue; - SV_PhysicsEntity(ent); + player = EDICT_NUM(i) + 1; + if(!player->inuse) continue; + if(!player->groundentity) continue; + if(player->groundentity != ent) continue; + + // Look below player; make sure he's on a conveyor + VectorCopy(player->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.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) + { + // 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); + SV_LinkEdict(player); + } } +} - prog->globals.server->self = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.server->other = PRVM_EDICT_TO_PROG(prog->edicts); - prog->globals.server->time = sv.time; - PRVM_ExecuteProgram (prog->globals.server->EndFrame, "QC function EndFrame is missing"); +void SV_Physics(edict_t *ent) +{ + if (ent->prethink) ent->prethink (ent); + wasonground = false; + onconveyor = false; - // decrement prog->num_edicts if the highest number entities died - for ( ;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.sv->free; prog->num_edicts-- ); - - sv.time += sv.frametime; + switch ( (int)ent->movetype) + { + case MOVETYPE_PUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + SV_Physics_None (ent); + break; + case MOVETYPE_NOCLIP: + SV_Physics_Noclip (ent); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_FLY: + SV_Physics_Toss (ent); + break; + case MOVETYPE_DEBRIS: + SV_Physics_Debris (ent); + break; + case MOVETYPE_WALK: + SV_Physics_None(ent); + break; + case MOVETYPE_CONVEYOR: + SV_Physics_Conveyor(ent); + break; + default: + PF_error ("SV_Physics: bad movetype %i", (int)ent->movetype); + } } \ No newline at end of file diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index c881b68f..547e7c15 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -65,7 +65,7 @@ size_t COM_UnpackString( byte *buffer, int pos, char *string ) if(!buffer || !string) return 0; in = buffer + pos; - do { in++, strsize++; } while(in && *in != '\0'); + do { in++, strsize++; } while(*in != '\0' && in != NULL ); strlcpy( string, in - (strsize - 1), strsize ); return pos + strsize; diff --git a/engine/server/sv_send.c b/engine/server/sv_send.c index 30901805..87717666 100644 --- a/engine/server/sv_send.c +++ b/engine/server/sv_send.c @@ -99,20 +99,19 @@ void SV_BroadcastPrintf (int level, char *fmt, ...) va_end (argptr); // echo to console - if (host.type == HOST_DEDICATED) + if (dedicated->value) { char copy[1024]; int i; // mask off high bits - for (i = 0; i < 1023 && string[i]; i++) - copy[i] = string[i] & 127; - - copy[i] = 0; //write null terminator + for (i=0 ; i<1023 && string[i] ; i++) + copy[i] = string[i]&127; + copy[i] = 0; Msg ("%s", copy); } - for (i = 0, cl = svs.clients; i < host.maxclients; i++, cl++) + for (i=0, cl = svs.clients ; ivalue; i++, cl++) { if (level < cl->messagelevel) continue; @@ -160,12 +159,12 @@ MULTICAST_PVS send to clients potentially visible from org MULTICAST_PHS send to clients potentially hearable from org ================= */ -void _MSG_Send (msgtype_t to, vec3_t origin, prvm_edict_t *ent, const char *filename, int fileline) +void _MSG_Send (msgtype_t to, vec3_t origin, edict_t *ent, const char *filename, int fileline) { byte *mask = NULL; int leafnum = 0, cluster = 0; int area1 = 0, area2 = 0; - int j, numclients = host.maxclients; + int j, numclients = maxclients->value; client_t *client, *current = svs.clients; bool reliable = false; @@ -209,7 +208,7 @@ void _MSG_Send (msgtype_t to, vec3_t origin, prvm_edict_t *ent, const char *file reliable = true; // intentional fallthrough case MSG_ONE: if(ent == NULL) return; - j = PRVM_NUM_FOR_EDICT(ent); + j = NUM_FOR_EDICT(ent); if (j < 1 || j > numclients) return; current = svs.clients + (j - 1); numclients = 1; // send to one @@ -229,9 +228,9 @@ void _MSG_Send (msgtype_t to, vec3_t origin, prvm_edict_t *ent, const char *file { area2 = CM_LeafArea (leafnum); cluster = CM_LeafCluster (leafnum); - leafnum = CM_PointLeafnum (client->edict->fields.sv->origin); + leafnum = CM_PointLeafnum (client->edict->s.origin); if (!CM_AreasConnected (area1, area2)) continue; - if ( mask && (!(mask[cluster>>3] & (1<<(cluster & 7))))) continue; + if ( mask && (!(mask[cluster>>3] & (1<<(cluster&7))))) continue; } if (reliable) SZ_Write (&client->netchan.message, sv.multicast.data, sv.multicast.cursize); @@ -279,7 +278,7 @@ If origin is NULL, the origin is determined from the entity origin or the midpoint of the entity box for bmodels. ================== */ -void SV_StartSound (vec3_t origin, prvm_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 soundindex, float volume, float attenuation, float timeofs) { int i, ent, flags, sendchan; vec3_t origin_v; @@ -300,7 +299,7 @@ void SV_StartSound (vec3_t origin, prvm_edict_t *entity, int channel, int soundi MsgWarn("SV_StartSound: timeofs = %f\n", timeofs); timeofs = bound(0, timeofs, 0.255 ); } - ent = PRVM_NUM_FOR_EDICT(entity); + ent = NUM_FOR_EDICT(entity); if (channel & 8) // no PHS flag { @@ -316,7 +315,7 @@ void SV_StartSound (vec3_t origin, prvm_edict_t *entity, int channel, int soundi // the client doesn't know that bmodels have weird origins // the origin can also be explicitly set - if (((int)entity->fields.sv->flags & SVF_NOCLIENT) || (entity->fields.sv->solid == SOLID_BSP) || origin ) + if ( (entity->svflags & SVF_NOCLIENT) || (entity->solid == SOLID_BSP) || origin ) flags |= SND_POS; // always send the entity number for channel overrides @@ -328,16 +327,16 @@ void SV_StartSound (vec3_t origin, prvm_edict_t *entity, int channel, int soundi if (!origin) { origin = origin_v; - if (entity->fields.sv->solid == SOLID_BSP) + if (entity->solid == SOLID_BSP) { for (i = 0; i < 3; i++) { - origin_v[i] = entity->fields.sv->origin[i]+0.5*(entity->fields.sv->mins[i]+entity->fields.sv->maxs[i]); + origin_v[i] = entity->s.origin[i]+0.5*(entity->mins[i]+entity->maxs[i]); } } else { - VectorCopy (entity->fields.sv->origin, origin_v); + VectorCopy (entity->s.origin, origin_v); } } @@ -419,8 +418,7 @@ bool SV_SendClientDatagram (client_t *client) SZ_Clear (&client->datagram); if (msg.overflowed) - { - // must have room left for the packet header + { // must have room left for the packet header Msg ("WARNING: msg overflowed for %s\n", client->name); SZ_Clear (&msg); } @@ -492,8 +490,9 @@ SV_SendClientMessages */ void SV_SendClientMessages (void) { - int i; - int msglen; + int i; + client_t *c; + int msglen; byte msgbuf[MAX_MSGLEN]; msglen = 0; @@ -501,7 +500,8 @@ void SV_SendClientMessages (void) // read the next demo message if needed if (sv.state == ss_demo && sv.demofile) { - if (sv_paused->value) msglen = 0; + if (sv_paused->value) + msglen = 0; else { // get the next message @@ -527,37 +527,39 @@ void SV_SendClientMessages (void) } // send a message to each connected client - for (i = 0, sv_client = svs.clients; i < host.maxclients; i++, sv_client++) + for (i=0, c = svs.clients ; ivalue; i++, c++) { - if (sv_client->state == cs_free) continue; - - // if the reliable message overflowed, drop the client - if (sv_client->netchan.message.overflowed) + if (!c->state) + continue; + // if the reliable message overflowed, + // drop the client + if (c->netchan.message.overflowed) { - SZ_Clear (&sv_client->netchan.message); - SZ_Clear (&sv_client->datagram); - SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", sv_client->name); - SV_DropClient (sv_client); + SZ_Clear (&c->netchan.message); + SZ_Clear (&c->datagram); + SV_BroadcastPrintf (PRINT_HIGH, "%s overflowed\n", c->name); + SV_DropClient (c); } - if (sv.state == ss_cinematic || sv.state == ss_demo || sv.state == ss_pic) - { - Netchan_Transmit (&sv_client->netchan, msglen, msgbuf); - } - else if (sv_client->state == cs_spawned) + if (sv.state == ss_cinematic + || sv.state == ss_demo + || sv.state == ss_pic + ) + Netchan_Transmit (&c->netchan, msglen, msgbuf); + else if (c->state == cs_spawned) { // don't overrun bandwidth - if (SV_RateDrop (sv_client)) continue; - SV_SendClientDatagram (sv_client); + if (SV_RateDrop (c)) + continue; + + SV_SendClientDatagram (c); } else { - // just update reliable if needed - if (sv_client->netchan.message.cursize || host.realtime - sv_client->netchan.last_sent > 1.0f) - Netchan_Transmit (&sv_client->netchan, 0, NULL); + // just update reliable if needed + if (c->netchan.message.cursize || curtime - c->netchan.last_sent > 1000 ) + Netchan_Transmit (&c->netchan, 0, NULL); } } } - - diff --git a/engine/server/sv_spawn.c b/engine/server/sv_spawn.c new file mode 100644 index 00000000..423c1003 --- /dev/null +++ b/engine/server/sv_spawn.c @@ -0,0 +1,1190 @@ +#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.001) + 0.5 * 0.1f; + + 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) + 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 +============= +*/ +char *ED_NewString (const char *string) +{ + char *newb, *new_p; + int i, l; + + l = strlen(string) + 1; + + newb = (char *)Z_Malloc(l); + + new_p = newb; + + for (i = 0; i < l; i++) + { + if (string[i] == '\\' && i < l-1) + { + i++; + if (string[i] == 'n') + *new_p++ = '\n'; + else *new_p++ = '\\'; + } + else *new_p++ = string[i]; + } + return newb; +} + +/* +=============== +ED_ParseField + +Takes a key/value pair and sets the binary values +in an edict +=============== +*/ +void ED_ParseField (char *key, const char *value, edict_t *ent) +{ + field_t *f; + byte *b; + float v; + vec3_t vec; + + for (f = fields; f->name; f++) + { + 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); + } + + if (!init) memset (ent, 0, sizeof(*ent)); + + return (char *)data; +} + + +/* +============== +SpawnEntities + +Creates a server's entity / program execution context by +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; +} + +void SV_InitEdict (edict_t *e) +{ + e->inuse = true; + e->classname = "noclass"; + e->s.number = NUM_FOR_EDICT(e); +} + + +/* +================= +SV_FreeEdict + +Marks the edict as free +================= +*/ +void SV_FreeEdict (edict_t *ed) +{ + SV_UnlinkEdict(ed); // unlink from world + + if (NUM_FOR_EDICT(ed) <= maxclients->value) + return; + + memset (ed, 0, sizeof(*ed)); + ed->classname = "freed"; + ed->freetime = sv.time; + ed->inuse = false; +} + +/* +============ +SV_TouchTriggers + +============ +*/ +void SV_TouchTriggers (edict_t *ent) +{ + int i, num; + edict_t *touch[MAX_EDICTS], *hit; + + // dead things don't activate triggers! + if ((ent->client || (ent->svflags & SVF_MONSTER)) && (ent->health <= 0)) + return; + + num = SV_AreaEdicts(ent->absmin, ent->absmax, touch, MAX_EDICTS, AREA_TRIGGERS); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for (i = 0; i < num; i++) + { + hit = touch[i]; + if (!hit->inuse) continue; + if (!hit->touch) continue; + hit->touch (hit, ent, NULL, NULL); + } +} + +/* +============= +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]); + } + + 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); +} + +static edict_t *current_player; +static gclient_t *current_client; +static vec3_t forward, right, up; +float xyspeed, bobmove, bobfracsin; // sin(bobfrac*M_PI) +int bobcycle; // odd cycles are right foot going forward + + +/* +=============== +SV_CalcRoll + +=============== +*/ +float SV_CalcRoll (vec3_t angles, vec3_t velocity) +{ + float sign; + float side; + float value; + + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs(side); + + value = 2; + + if (side < 200) side = side * value / 200; + else side = value; + + return side*sign; + +} + +/* +============== +SV_CalcGunOffset +============== +*/ +void SV_CalcGunOffset (edict_t *ent) +{ + int i; + float delta; + + // gun angles from bobbing + ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005; + ent->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->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005; + + // gun angles from delta movement + for (i=0 ; i<3 ; i++) + { + delta = ent->client->oldviewangles[i] - ent->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; + } + + // gun height + VectorClear (ent->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]; + } +} + + +void SV_CalcViewOffset (edict_t *ent) +{ + float *angles; + float bob; + float delta; + vec3_t v; + + // base angles + angles = ent->client->ps.kick_angles; + + + // add angles based on velocity + delta = DotProduct (ent->velocity, forward); + angles[PITCH] += delta * 0.002; + + delta = DotProduct (ent->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) + delta *= 6; // crouching + angles[PITCH] += delta; + delta = bobfracsin * 0.002 * xyspeed; + + if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) + delta *= 6; // crouching + if (bobcycle & 1) delta = -delta; + angles[ROLL] += delta; + + + // base origin + VectorClear (v); + + // add view height + v[2] += 22; + + // add bob height + bob = bobfracsin * xyspeed * 0.005; + if (bob > 6) bob = 6; + v[2] += bob; + + + v[0] = bound(-14, v[0], 14); + v[1] = bound(-14, v[1], 14); + v[2] = bound(-22, v[0], 30); + + VectorCopy (v, ent->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; +} + +void ClientEndServerFrame (edict_t *ent) +{ + float bobtime; + int i; + + current_player = ent; + current_client = ent->client; + + // + // If the origin or velocity have changed since ClientThink(), + // update the pmove values. This will happen when the client + // is pushed by a bmodel or kicked by an explosion. + // + // If it wasn't updated here, the view position would lag a frame + // behind the body position when pushed -- "sinking into plats" + // + 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; + } + + AngleVectors (ent->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; + + 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; + + // + // 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]); + + if (xyspeed < 5) + { + bobmove = 0; + current_client->bobtime = 0; // start at beginning of cycle again + } + else + { + // so bobbing only cycles when on ground + if (xyspeed > 210) bobmove = 0.25; + else if (xyspeed > 100) bobmove = 0.125; + else bobmove = 0.0625; + } + + bobtime = (current_client->bobtime += bobmove); + + if (current_client->ps.pmove.pm_flags & PMF_DUCKED) + bobtime *= 4; + + bobcycle = (int)bobtime; + bobfracsin = fabs(sin(bobtime*M_PI)); + + // determine the view offsets + SV_CalcViewOffset (ent); + + // determine the gun offsets + SV_CalcGunOffset (ent); + + SV_SetStats( ent ); +} + +/* +================= +ClientEndServerFrames +================= +*/ +void ClientEndServerFrames (void) +{ + int i; + edict_t *ent; + + // calc the player views now that all pushing + // and damage has been added + for (i = 1; i < maxclients->value; i++) + { + ent = EDICT_NUM(i); + if (!ent->inuse || !ent->client) + continue; + ClientEndServerFrame (ent); + } +} + +/* +================ +SV_RunFrame + +Advances the world by 0.1 seconds +================ +*/ +void SV_RunFrame (void) +{ + int i; + edict_t *ent; + + // + // treat each object in turn + // even the world gets a chance to think + // + + ent = EDICT_NUM(0); + for (i = 0; i < ge->num_edicts; i++, ent++) + { + if (!ent->inuse) continue; + + VectorCopy (ent->s.origin, ent->s.old_origin); + + if (i > 0 && i <= maxclients->value) + continue; //don't apply phys on clients + SV_Physics(ent); + } + + // build the playerstate_t structures for all players + ClientEndServerFrames (); +} + +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; + + return true; +} + +void SV_ClientUserinfoChanged (edict_t *ent, char *userinfo) +{ + char *s; + int playernum; + + // check for malformed or illegal info strings + if (!Info_Validate(userinfo)) + { + strcpy (userinfo, "\\name\\badinfo\\skin\\male/grunt"); + } + + // set skin + s = Info_ValueForKey (userinfo, "skin"); + + playernum = NUM_FOR_EDICT(ent) - 1; + + // combine name and skin into a configstring + PF_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); +} + +/* +=========== +SV_ClientBegin + +called when a client has finished connecting, and is ready +to be placed into the game. This will happen every level load. +============ +*/ +void SV_ClientBegin (edict_t *ent) +{ + int i; + + ent->client = game.clients + 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) + { + // 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]); + } + else + { + // a spawn point will completely reinitialize the entity + // except for the persistant data that was initialized at + // ClientConnect() time + SV_InitEdict (ent); + ent->classname = "player"; + SV_PutClientInServer (ent); + } + + // make sure all view stuff is valid + ClientEndServerFrame (ent); +} + +/* +============== +ClientThink + +This will be called once for each client frame, which will +usually be a couple times for each server frame. +============== +*/ +void ClientThink (edict_t *ent, usercmd_t *ucmd) +{ + gclient_t *client; + edict_t *other; + pmove_t pm; + vec3_t view; + vec3_t oldorigin, oldvelocity; + int i, j; + + client = ent->client; + + VectorCopy(ent->s.origin, oldorigin); + VectorCopy(ent->velocity, oldvelocity); + + ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION; + + VectorCopy(ent->s.origin,view); + view[2] += 22; + + 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; + else client->ps.pmove.pm_type = PM_NORMAL; + client->ps.pmove.gravity = 0; + + pm.s = client->ps.pmove; + + for (i = 0; i < 3; i++) + { + pm.s.origin[i] = ent->s.origin[i]*8; + pm.s.velocity[i] = ent->velocity[i]*8; + } + + if (memcmp(&client->old_pmove, &pm.s, sizeof(pm.s))) + pm.snapinitial = true; + + pm.cmd = *ucmd; + + pm.trace = PM_trace; // adds default parms + pm.pointcontents = SV_PointContents; + + // perform a pmove + Pmove (&pm); + + // save results of pmove + client->ps.pmove = pm.s; + client->old_pmove = pm.s; + + 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; + } + VectorCopy (pm.mins, ent->mins); + VectorCopy (pm.maxs, ent->maxs); + + SV_LinkEdict(ent); + + if (ent->movetype != MOVETYPE_NOCLIP) + SV_TouchTriggers (ent); + + for (i = 0; i < pm.numtouch; i++) + { + other = pm.touchents[i]; + for (j = 0; j < i; j++) + { + if (pm.touchents[j] == other) + break; + } + if (j != i) continue; // duplicated + if (!other->touch) continue; + other->touch (other, ent, NULL, NULL); + } +} + +/* +=========== +SV_ClientDisconnect + +Called when a player drops from the server. +Will not be called between levels. +============ +*/ +void SV_ClientDisconnect (edict_t *ent) +{ + int playernum; + + if (!ent->client) return; + + Msg("player disconnected\n"); + + // send effect + MSG_Begin( svc_muzzleflash ); + MSG_WriteShort( &sv.multicast, NUM_FOR_EDICT(ent) ); + MSG_WriteByte( &sv.multicast, MZ_LOGOUT ); + MSG_Send(MSG_PVS, ent->s.origin, NULL); + + SV_UnlinkEdict(ent); + ent->s.modelindex = 0; + ent->solid = SOLID_NOT; + ent->inuse = false; + ent->classname = "disconnected"; + + playernum = NUM_FOR_EDICT(ent) - 1; + PF_Configstring (CS_PLAYERSKINS + playernum, ""); + +} + +/* +================== +Cmd_Say_f +================== +*/ +void Cmd_Say_f (edict_t *ent, bool team, bool arg0) +{ + int j; + edict_t *other; + char *p; + char text[2048]; + + if (Cmd_Argc () < 2 && !arg0) return; + + sprintf (text, "%s: ", "all"); + + if (arg0) + { + strcat (text, Cmd_Argv(0)); + strcat (text, " "); + strcat (text, Cmd_Args()); + } + else + { + p = Cmd_Args(); + + if (*p == '"') + { + p++; + p[strlen(p)-1] = 0; + } + strcat(text, p); + } + + // don't let text be too long for malicious reasons + if (strlen(text) > 150) text[150] = 0; + + strcat(text, "\n"); + + if (dedicated->value) + PF_cprintf(NULL, PRINT_CHAT, "%s", text); + + for (j = 1; j <= game.maxclients; j++) + { + other = EDICT_NUM(j); + if (!other->inuse) continue; + if (!other->client) continue; + PF_cprintf(other, PRINT_CHAT, "%s", text); + } +} + +/* +================== +HelpComputer + +Draw help computer. +================== +*/ +void SV_HelpComputer (edict_t *ent) +{ + char string[1024]; + char *sk = "medium"; + + sprintf (string, "xv 32 yv 8 picn help " // background + "xv 202 yv 12 string2 \"%s\" " // skill + "xv 0 yv 24 cstring2 \"%s\" " // level name + "xv 0 yv 54 cstring2 \"%s\" " // help 1 + "xv 0 yv 110 cstring2 \"%s\" " // help 2 + "xv 50 yv 164 string2 \" kills goals secrets\" " + "xv 50 yv 172 string2 \"%3i/%3i %i/%i %i/%i\" ", + sk, + sv.name, + "", + "", + 0, 0, + 0, 0, + 0, 0); + + MSG_Begin (svc_layout); + MSG_WriteString (&sv.multicast, string); + MSG_Send (MSG_ONE_R, NULL, ent ); +} + +/* +================== +Cmd_Help_f + +Display the current help message +================== +*/ +void Cmd_Help_f (edict_t *ent) +{ + SV_HelpComputer (ent); +} + +/* +================= +SV_ClientCommand +================= +*/ +void SV_ClientCommand (edict_t *ent) +{ + char *cmd; + char *parm; + + if (!ent->client) return; // not fully in game yet + + cmd = Cmd_Argv(0); + + if(Cmd_Argc() < 2) parm = NULL; + else parm = Cmd_Argv(1); + + if (strcasecmp (cmd, "say") == 0) + { + Cmd_Say_f (ent, false, false); + return; + } + if (strcasecmp (cmd, "say_team") == 0) + { + Cmd_Say_f (ent, true, false); + return; + } + if (strcasecmp (cmd, "help") == 0) + { + Cmd_Help_f (ent); + return; + } +} \ No newline at end of file diff --git a/engine/server/sv_studio.c b/engine/server/sv_studio.c index 2c923d0a..1ace6b5b 100644 --- a/engine/server/sv_studio.c +++ b/engine/server/sv_studio.c @@ -19,7 +19,8 @@ int SV_StudioExtractBbox( studiohdr_t *phdr, int sequence, float *mins, float *m return 1; } -byte *SV_GetModelPtr(prvm_edict_t *ent) +byte *SV_GetModelPtr(edict_t *ent) { + if(!ent) return NULL; return NULL; } \ No newline at end of file diff --git a/engine/server/sv_user.c b/engine/server/sv_user.c index 5d151291..fc7736fa 100644 --- a/engine/server/sv_user.c +++ b/engine/server/sv_user.c @@ -22,17 +22,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "engine.h" #include "server.h" -extern cvar_t *sv_maxspeed; -extern cvar_t *sv_accelerate; -extern cvar_t *sv_wateraccelerate; -extern cvar_t *sv_friction; -extern cvar_t *sv_rollangle; -extern cvar_t *sv_rollspeed; - -prvm_edict_t *sv_player; -static bool onground; -static vec3_t wishdir, forward, right, up; -static float wishspeed; +edict_t *sv_player; /* ============================================================ @@ -70,7 +60,7 @@ void SV_New_f (void) { char *gamedir; int playernum; - prvm_edict_t *ent; + edict_t *ent; if (sv_client->state != cs_connected) { @@ -108,8 +98,8 @@ void SV_New_f (void) if (sv.state == ss_game) { // set up the entity for the client - ent = PRVM_EDICT_NUM(playernum+1); - ent->priv.sv->state.number = playernum+1; + ent = EDICT_NUM(playernum+1); + ent->s.number = playernum+1; sv_client->edict = ent; memset (&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd)); @@ -204,8 +194,7 @@ void SV_Baselines_f (void) // write a packet full of data - while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 - && start < MAX_EDICTS) + while ( sv_client->netchan.message.cursize < MAX_MSGLEN/2 && start < MAX_EDICTS) { base = &sv.baselines[start]; if (base->modelindex || base->sound || base->effects) @@ -237,8 +226,6 @@ SV_Begin_f */ void SV_Begin_f (void) { - int i; - // handle the case of a level changing while a client was connecting if ( atoi(Cmd_Argv(1)) != svs.spawncount ) { @@ -248,22 +235,9 @@ void SV_Begin_f (void) } sv_client->state = cs_spawned; - - if(!sv_player->priv.sv->free) - { - // call the game begin function - prog->globals.server->time = sv.time; - prog->globals.server->self = PRVM_EDICT_TO_PROG(sv_client->edict); - PRVM_ExecuteProgram (prog->globals.server->PutClientInServer, "QC function PutClientInServer is missing"); - } - for (i = 0; i < 3; i++) - { - sv_player->priv.sv->client->pmove.origin[i] = sv_player->priv.sv->state.origin[i] = sv_player->fields.sv->origin[i]*8.0; - sv_player->priv.sv->client->pmove.velocity[i] = sv_player->fields.sv->velocity[i]*8.0; - } - sv_player->priv.sv->client->gunindex = SV_ModelIndex("models/weapons/v_glock.mdl" ); - sv_player->priv.sv->client->fov = 90; - + + // call the game begin function + SV_ClientBegin(sv_player); Cbuf_InsertFromDefer (); } @@ -370,7 +344,7 @@ void SV_BeginDownload_f(void) } SV_NextDownload_f (); - MsgDev(D_INFO, "Downloading %s to %s\n", name, sv_client->name); + MsgDev (D_INFO, "Downloading %s to %s\n", name, sv_client->name); } @@ -485,8 +459,8 @@ void SV_ExecuteUserCommand (char *s) } } -//if (!u->name && sv.state == ss_game) -//ge->ClientCommand (sv_player); + if (!u->name && sv.state == ss_game) + SV_ClientCommand(sv_player); } /* @@ -497,18 +471,8 @@ USER CMD EXECUTION =========================================================================== */ -trace_t PM_trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end) +void SV_ClientThink (client_t *cl, usercmd_t *cmd) { - return SV_Trace (start, mins, maxs, end, sv_client->edict, MASK_SOLID); -} - -void SV_ClientRun (client_t *cl, usercmd_t *cmd) -{ - pmove_t pm; - int i; - - sv_client = cl; - cl->commandMsec -= cmd->msec; if (cl->commandMsec < 0 && sv_enforcetime->value ) @@ -516,359 +480,7 @@ void SV_ClientRun (client_t *cl, usercmd_t *cmd) MsgWarn("SV_ClientThink: commandMsec underflow from %s\n", cl->name); return; } - - // set up for pmove - memset (&pm, 0, sizeof(pm)); - cl->edict->priv.sv->client->pmove.pm_flags |= PMF_NO_PREDICTION; - - if (cl->edict->fields.sv->movetype == MOVETYPE_NOCLIP) - cl->edict->priv.sv->client->pmove.pm_type = PM_SPECTATOR; - else if (cl->edict->fields.sv->movetype == MOVETYPE_WALK) - cl->edict->priv.sv->client->pmove.pm_type = PM_NORMAL; - else if (cl->edict->fields.sv->movetype == MOVETYPE_NONE) - cl->edict->priv.sv->client->pmove.pm_type = PM_FREEZE; - cl->edict->priv.sv->client->pmove.gravity = 0; - - pm.s = cl->edict->priv.sv->client->pmove; - - for (i = 0; i < 3; i++) - { - pm.s.origin[i] = cl->edict->fields.sv->origin[i] * 8; - pm.s.velocity[i] = cl->edict->fields.sv->velocity[i] * 8; - } - pm.cmd = *cmd; - - pm.trace = PM_trace; // adds default parms - pm.pointcontents = SV_PointContents; - - Msg("org before pmove [%i %i %i]\n", pm.s.origin[0], pm.s.origin[1], pm.s.origin[2] ); - - Pmove (&pm); //run pmove - - // save results of pmove - cl->edict->priv.sv->client->pmove = pm.s; - - Msg("org after pmove [%i %i %i]\n", pm.s.origin[0], pm.s.origin[1], pm.s.origin[2] ); - - for (i = 0; i < 3; i++) - { - cl->edict->priv.sv->state.old_origin[i] = pm.s.origin[i]*0.125; - cl->edict->fields.sv->origin[i] = pm.s.origin[i]*0.125; - cl->edict->fields.sv->velocity[i] = pm.s.velocity[i]*0.125; - } - VectorCopy (pm.mins, cl->edict->fields.sv->mins); - VectorCopy (pm.maxs, cl->edict->fields.sv->maxs); - - VectorCopy (pm.viewangles, cl->edict->fields.sv->v_angle); - VectorCopy (pm.viewangles, cl->edict->priv.sv->client->viewangles); - VectorCopy(cl->edict->fields.sv->view_ofs, cl->edict->priv.sv->client->viewoffset ); - - SV_LinkEdict( cl->edict ); - - //SV_ClientThink(); -} - -/* -=============== -SV_CalcRoll - -=============== -*/ -float SV_CalcRoll (vec3_t angles, vec3_t velocity) -{ - float sign; - float side; - float value; - - side = DotProduct (velocity, right); - sign = side < 0 ? -1 : 1; - side = fabs(side); - - value = sv_rollangle->value; - - if (side < sv_rollspeed->value) - side = side * value / sv_rollspeed->value; - else side = value; - - return side*sign; - -} - - -/* -================== -SV_UserFriction - -================== -*/ -void SV_UserFriction (void) -{ - float speed, newspeed, control, friction; - vec3_t start, stop; - trace_t trace; - - speed = sqrt(sv_client->edict->fields.sv->velocity[0]*sv_client->edict->fields.sv->velocity[0]+sv_client->edict->fields.sv->velocity[1]*sv_client->edict->fields.sv->velocity[1]); - if (!speed) return; - - // if the leading edge is over a dropoff, increase friction - start[0] = stop[0] = sv_client->edict->fields.sv->origin[0] + sv_client->edict->fields.sv->velocity[0]/speed*16; - start[1] = stop[1] = sv_client->edict->fields.sv->origin[1] + sv_client->edict->fields.sv->velocity[1]/speed*16; - start[2] = sv_client->edict->fields.sv->origin[2] + sv_client->edict->fields.sv->mins[2]; - stop[2] = start[2] - 34; - - trace = SV_Trace (start, vec3_origin, vec3_origin, stop, sv_client->edict, MASK_SOLID ); - - if (trace.fraction == 1.0) friction = sv_friction->value * 2; - else friction = sv_friction->value; - - // apply friction - - control = max(speed, 100); - newspeed = speed - sv.frametime * control * friction; - - if (newspeed < 0) newspeed = 0; - else newspeed /= speed; - - VectorScale(sv_client->edict->fields.sv->velocity, newspeed, sv_client->edict->fields.sv->velocity); -} - -/* -============== -SV_Accelerate -============== -*/ -void SV_Accelerate (void) -{ - int i; - float addspeed, accelspeed, currentspeed; - - currentspeed = DotProduct (sv_client->edict->fields.sv->velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) return; - accelspeed = sv_accelerate->value * sv.frametime * wishspeed; - - if (accelspeed > addspeed) accelspeed = addspeed; - - for (i = 0; i < 3; i++) sv_client->edict->fields.sv->velocity[i] += accelspeed * wishdir[i]; -} - -void SV_AirAccelerate (vec3_t wishveloc) -{ - int i; - float addspeed, wishspd, accelspeed, currentspeed; - - wishspd = VectorNormalize (wishveloc); - if (wishspd > sv_maxspeed->value / 10) wishspd = sv_maxspeed->value / 10; - currentspeed = DotProduct (sv_client->edict->fields.sv->velocity, wishveloc); - addspeed = wishspd - currentspeed; - if (addspeed <= 0) return; - accelspeed = (sv_airaccelerate->value < 0 ? sv_accelerate->value : sv_airaccelerate->value) * wishspeed * sv.frametime; - if (accelspeed > addspeed) accelspeed = addspeed; - - for (i = 0; i < 3; i++) sv_client->edict->fields.sv->velocity[i] += accelspeed*wishveloc[i]; -} - -void DropPunchAngle (void) -{ - float len; - - len = VectorNormalize(sv_client->edict->fields.sv->punchangle); - - len -= 10 * sv.frametime; - if (len < 0) len = 0; - VectorScale (sv_client->edict->fields.sv->punchangle, len, sv_client->edict->fields.sv->punchangle); -} - -/* -=================== -SV_AirMove - -=================== -*/ -void SV_AirMove (void) -{ - int i; - vec3_t wishvel; - float fmove, smove, temp; - - wishvel[0] = wishvel[2] = 0; - wishvel[1] = sv_client->edict->fields.sv->angles[1]; - AngleVectorsRight (wishvel, forward, right, up); - - fmove = 0;//cmd.forwardmove; - smove = 0;//cmd.sidemove; - - // hack to not let you back into teleporter - if (sv.time < sv_client->edict->fields.sv->teleport_time && fmove < 0) - fmove = 0; - - for (i=0 ; i<3 ; i++) - wishvel[i] = forward[i]*fmove + right[i]*smove; - - if ((int)sv_client->edict->fields.sv->movetype != MOVETYPE_WALK) - wishvel[2] += fmove; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - if (wishspeed > sv_maxspeed->value) - { - temp = sv_maxspeed->value/wishspeed; - VectorScale (wishvel, temp, wishvel); - wishspeed = sv_maxspeed->value; - } - - if (sv_client->edict->fields.sv->movetype == MOVETYPE_NOCLIP) - { - // noclip - VectorCopy (wishvel, sv_client->edict->fields.sv->velocity); - } - else if (onground && (!(sv_client->edict->fields.sv->button2))) - { - SV_UserFriction (); - SV_Accelerate (); - } - else - { - // not on ground, so little effect on velocity - SV_AirAccelerate (wishvel); - } -} - -/* -=================== -SV_WaterMove - -=================== -*/ -void SV_WaterMove (void) -{ - int i; - vec3_t wishvel; - float speed, newspeed, wishspeed, addspeed, accelspeed, temp; - - // user intentions - AngleVectorsRight (sv_client->edict->fields.sv->v_angle, forward, right, up); - - /*for (i = 0; i < 3; i++) - wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove; - - if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove) - wishvel[2] -= 60; // drift towards bottom - else - wishvel[2] += cmd.upmove; - - */ - wishspeed = VectorLength(wishvel); - if (wishspeed > sv_maxspeed->value) - { - temp = sv_maxspeed->value/wishspeed; - VectorScale (wishvel, temp, wishvel); - wishspeed = sv_maxspeed->value; - } - wishspeed *= 0.7; - - // water friction - speed = VectorLength(sv_client->edict->fields.sv->velocity); - if (speed) - { - newspeed = speed - sv.frametime * speed * -1; - if (newspeed < 0) - newspeed = 0; - temp = newspeed/speed; - VectorScale(sv_client->edict->fields.sv->velocity, temp, sv_client->edict->fields.sv->velocity); - } - else - newspeed = 0; - - // water acceleration - if (!wishspeed) - return; - - addspeed = wishspeed - newspeed; - if (addspeed <= 0) - return; - - VectorNormalize (wishvel); - accelspeed = (sv_wateraccelerate->value < 0 ? sv_accelerate->value : sv_wateraccelerate->value) * wishspeed * sv.frametime; - if (accelspeed > addspeed) accelspeed = addspeed; - - for (i = 0; i < 3; i++) sv_client->edict->fields.sv->velocity[i] += accelspeed * wishvel[i]; -} - -void SV_WaterJump (void) -{ - if (sv.time > sv_client->edict->fields.sv->teleport_time || !sv_client->edict->fields.sv->waterlevel) - { - sv_client->edict->fields.sv->flags = (int)sv_client->edict->fields.sv->flags & ~FL_WATERJUMP; - sv_client->edict->fields.sv->teleport_time = 0; - } - sv_client->edict->fields.sv->velocity[0] = sv_client->edict->fields.sv->movedir[0]; - sv_client->edict->fields.sv->velocity[1] = sv_client->edict->fields.sv->movedir[1]; -} - - -/* -=================== -SV_ClientThink - -the move fields specify an intended velocity in pix/sec -the angle fields specify an exact angular motion in degrees -=================== -*/ -void SV_ClientThink (void) -{ - vec3_t v_angle; - - if (sv_client->edict->fields.sv->movetype == MOVETYPE_NONE) - return; - - onground = (int)sv_client->edict->fields.sv->flags & FL_ONGROUND; - - DropPunchAngle (); - - // if dead, behave differently - if (sv_client->edict->fields.sv->health <= 0) return; - - // angles - // show 1/3 the pitch angle and all the roll angle - VectorAdd (sv_client->edict->fields.sv->v_angle, sv_client->edict->fields.sv->punchangle, v_angle); - sv_client->edict->fields.sv->angles[ROLL] = SV_CalcRoll (sv_client->edict->fields.sv->angles, sv_client->edict->fields.sv->velocity)*4; - if (!sv_client->edict->fields.sv->fixangle) - { - sv_client->edict->fields.sv->angles[PITCH] = -v_angle[PITCH]/3; - sv_client->edict->fields.sv->angles[YAW] = v_angle[YAW]; - } - - if ( (int)sv_client->edict->fields.sv->flags & FL_WATERJUMP ) - { - SV_WaterJump (); - return; - } - - // walk - if ((sv_client->edict->fields.sv->waterlevel >= 2) && (sv_client->edict->fields.sv->movetype != MOVETYPE_NOCLIP)) - { - SV_WaterMove(); - return; - } - - SV_AirMove(); -} - -void SV_ApplyClientMove (void) -{ - usercmd_t *move = &sv_client->lastcmd; - - if (!move->msec) return; - - // set the edict fields - sv_client->edict->fields.sv->button0 = move->buttons & 1; - sv_client->edict->fields.sv->button2 = (move->buttons & 2)>>1; - if (move->impulse) sv_client->edict->fields.sv->impulse = move->impulse; - - // only send the impulse to qc once - move->impulse = 0; - VectorCopy(sv_client->edict->priv.sv->client->viewangles, sv_client->edict->fields.sv->v_angle); + ClientThink (cl->edict, cmd); } /* @@ -885,13 +497,13 @@ void SV_ExecuteClientMessage (client_t *cl) int c; char *s; - usercmd_t nullcmd; - usercmd_t oldest, oldcmd, newcmd; + usercmd_t nullcmd; + usercmd_t oldest, oldcmd, newcmd; int net_drop; int stringCmdCount; int checksum, calculatedChecksum; int checksumIndex; - bool move_issued; + bool move_issued; int lastframe; sv_client = cl; @@ -963,9 +575,7 @@ void SV_ExecuteClientMessage (client_t *cl) MsgWarn("SV_ExecuteClientMessage: failed command checksum for %s (%d != %d)/%d\n", cl->name, calculatedChecksum, checksum, cl->netchan.incoming_sequence); return; } - - //Msg("sv_paused->value %g\n", sv_paused->value ); - + if (!sv_paused->value) { net_drop = cl->netchan.dropped; @@ -973,13 +583,13 @@ void SV_ExecuteClientMessage (client_t *cl) { while (net_drop > 2) { - SV_ClientRun (cl, &cl->lastcmd); + SV_ClientThink (cl, &cl->lastcmd); net_drop--; } - if (net_drop > 1) SV_ClientRun (cl, &oldest); - if (net_drop > 0) SV_ClientRun (cl, &oldcmd); + if (net_drop > 1) SV_ClientThink (cl, &oldest); + if (net_drop > 0) SV_ClientThink (cl, &oldcmd); } - SV_ClientRun (cl, &newcmd); + SV_ClientThink (cl, &newcmd); } cl->lastcmd = newcmd; break; diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index f0ccf041..dac9e951 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -30,6 +30,14 @@ 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) + typedef struct areanode_s { int axis; // -1 = leaf node @@ -45,12 +53,12 @@ typedef struct areanode_s areanode_t sv_areanodes[AREA_NODES]; int sv_numareanodes; -float *area_mins, *area_maxs; -prvm_edict_t **area_list; +float *area_mins, *area_maxs; +edict_t **area_list; int area_count, area_maxcount; int area_type; -int SV_HullForEntity (prvm_edict_t *ent); +int SV_HullForEntity (edict_t *ent); // ClearLink is used for new headnodes @@ -65,9 +73,8 @@ void RemoveLink (link_t *l) l->prev->next = l->next; } -void InsertLinkBefore (link_t *l, link_t *before, int entnum) +void InsertLinkBefore (link_t *l, link_t *before) { - l->entnum = entnum; l->next = before; l->prev = before->prev; l->prev->next = l; @@ -140,11 +147,12 @@ SV_UnlinkEdict =============== */ -void SV_UnlinkEdict (prvm_edict_t *ent) +void SV_UnlinkEdict (edict_t *ent) { - 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; + if (!ent->area.prev) + return; // not linked in anywhere + RemoveLink (&ent->area); + ent->area.prev = ent->area.next = NULL; } @@ -155,95 +163,90 @@ SV_LinkEdict =============== */ #define MAX_TOTAL_ENT_LEAFS 128 -void SV_LinkEdict (prvm_edict_t *ent) +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->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) - { - Msg("Can't link entity [%d]\n", ent->priv.sv->state.number ); - return; - } + 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; // set the size - VectorSubtract (ent->fields.sv->maxs, ent->fields.sv->mins, ent->fields.sv->size); + VectorSubtract (ent->maxs, ent->mins, ent->size); // encode the size into the entity_state for client prediction - if (ent->fields.sv->solid == SOLID_BBOX && !((int)ent->fields.sv->flags & SVF_DEADMONSTER)) + if (ent->solid == SOLID_BBOX && !(ent->svflags & SVF_DEADMONSTER)) { // assume that x/y are equal and symetric - i = ent->fields.sv->maxs[0]/8; - if(i < 1) i = 1; - if(i > 31) i = 31; + i = ent->maxs[0]/8; + if (i<1) i = 1; + if (i>31) i = 31; // z is not symetric - j = (-ent->fields.sv->mins[2])/8; + j = (-ent->mins[2])/8; if (j < 1) j = 1; if (j > 31) j = 31; // and z maxs can be negative... - k = (ent->fields.sv->maxs[2]+32)/8; - if (k < 1) k = 1; - if (k > 63) k = 63; - ent->fields.sv->solid = (k<<10) | (j<<5) | i; + k = (ent->maxs[2]+32)/8; + if (k<1) k = 1; + if (k>63) k = 63; + ent->s.solid = (k<<10) | (j<<5) | i; } - else if (ent->fields.sv->solid == SOLID_BSP) + else if (ent->solid == SOLID_BSP) { - ent->fields.sv->solid = 31; // a solid_bbox will never create this value + ent->s.solid = 31; // a solid_bbox will never create this value } - else ent->fields.sv->solid = 0; + else ent->s.solid = 0; // set the abs box - if (ent->fields.sv->solid == SOLID_BSP && (!VectorIsNull(ent->fields.sv->angles))) + if (ent->solid == SOLID_BSP && (ent->s.angles[0] || ent->s.angles[1] || ent->s.angles[2]) ) { // expand for rotation float max = 0, v; int i; - for (i = 0; i < 3; i++) + for (i=0 ; i<3 ; i++) { - v =fabs( ent->fields.sv->mins[i]); + v =fabs( ent->mins[i]); if (v > max) max = v; - v =fabs( ent->fields.sv->maxs[i]); + v =fabs( ent->maxs[i]); if (v > max) max = v; } - for (i = 0; i < 3; i++) + for (i=0 ; i<3 ; i++) { - ent->fields.sv->absmin[i] = ent->fields.sv->origin[i] - max; - ent->fields.sv->absmax[i] = ent->fields.sv->origin[i] + max; + ent->absmin[i] = ent->s.origin[i] - max; + ent->absmax[i] = ent->s.origin[i] + max; } } else - { - // normal - VectorAdd (ent->fields.sv->origin, ent->fields.sv->mins, ent->fields.sv->absmin); - VectorAdd (ent->fields.sv->origin, ent->fields.sv->maxs, ent->fields.sv->absmax); + { // normal + VectorAdd (ent->s.origin, ent->mins, ent->absmin); + VectorAdd (ent->s.origin, ent->maxs, ent->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->fields.sv->absmin[0] -= 1; - ent->fields.sv->absmin[1] -= 1; - ent->fields.sv->absmin[2] -= 1; - ent->fields.sv->absmax[0] += 1; - ent->fields.sv->absmax[1] += 1; - ent->fields.sv->absmax[2] += 1; + ent->absmin[0] -= 1; + ent->absmin[1] -= 1; + ent->absmin[2] -= 1; + ent->absmax[0] += 1; + ent->absmax[1] += 1; + ent->absmax[2] += 1; // link to PVS leafs - ent->priv.sv->num_clusters = 0; - ent->priv.sv->areanum = 0; - ent->priv.sv->areanum2 = 0; + ent->num_clusters = 0; + ent->areanum = 0; + ent->areanum2 = 0; //get all leafs, including solids - num_leafs = CM_BoxLeafnums (ent->fields.sv->absmin, ent->fields.sv->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); + num_leafs = CM_BoxLeafnums (ent->absmin, ent->absmax, leafs, MAX_TOTAL_ENT_LEAFS, &topnode); // set areas for (i = 0; i < num_leafs; i++) @@ -253,25 +256,25 @@ void SV_LinkEdict (prvm_edict_t *ent) if (area) { // doors may legally straggle two areas, // but nothing should evern need more than that - if (ent->priv.sv->areanum && ent->priv.sv->areanum != area) + if (ent->areanum && ent->areanum != 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->fields.sv->absmin[0], ent->fields.sv->absmin[1], ent->fields.sv->absmin[2]); - ent->priv.sv->areanum2 = 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; } - else ent->priv.sv->areanum = area; + else ent->areanum = area; } } if (num_leafs >= MAX_TOTAL_ENT_LEAFS) { // assume we missed some leafs, and mark by headnode - ent->priv.sv->num_clusters = -1; - ent->priv.sv->headnode = topnode; + ent->num_clusters = -1; + ent->headnode = topnode; } else { - ent->priv.sv->num_clusters = 0; + ent->num_clusters = 0; for (i = 0; i < num_leafs; i++) { if (clusters[i] == -1) continue; // not a visible leaf @@ -281,43 +284,42 @@ void SV_LinkEdict (prvm_edict_t *ent) } if (j == i) { - if (ent->priv.sv->num_clusters == MAX_ENT_CLUSTERS) + if (ent->num_clusters == MAX_ENT_CLUSTERS) { // assume we missed some leafs, and mark by headnode - ent->priv.sv->num_clusters = -1; - ent->priv.sv->headnode = topnode; + ent->num_clusters = -1; + ent->headnode = topnode; break; } - ent->priv.sv->clusternums[ent->priv.sv->num_clusters++] = clusters[i]; + ent->clusternums[ent->num_clusters++] = clusters[i]; } } } // if first time, make sure old_origin is valid - if (!ent->priv.sv->linkcount) + if (!ent->linkcount) { - VectorCopy (ent->fields.sv->origin, ent->fields.sv->oldorigin); + VectorCopy (ent->s.origin, ent->s.old_origin); } - ent->priv.sv->linkcount++; + ent->linkcount++; - if (ent->fields.sv->solid == SOLID_NOT) return; + if (ent->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->fields.sv->absmin[node->axis] > node->dist) + if (ent->absmin[node->axis] > node->dist) node = node->children[0]; - else if (ent->fields.sv->absmax[node->axis] < node->dist) + else if (ent->absmax[node->axis] < node->dist) node = node->children[1]; else break; // crosses the node } // link it in - if (ent->fields.sv->solid == SOLID_TRIGGER) - InsertLinkBefore (&ent->priv.sv->area, &node->trigger_edicts, PRVM_NUM_FOR_EDICT(ent)); - else InsertLinkBefore (&ent->priv.sv->area, &node->solid_edicts, PRVM_NUM_FOR_EDICT(ent)); + if (ent->solid == SOLID_TRIGGER) InsertLinkBefore (&ent->area, &node->trigger_edicts); + else InsertLinkBefore (&ent->area, &node->solid_edicts); } @@ -331,7 +333,7 @@ SV_AreaEdicts_r void SV_AreaEdicts_r (areanode_t *node) { link_t *l, *next, *start; - prvm_edict_t *check; + edict_t *check; int count = 0; // touch linked edicts @@ -342,11 +344,11 @@ void SV_AreaEdicts_r (areanode_t *node) for (l = start->next; l != start; l = next) { next = l->next; - check = PRVM_EDICT_NUM_UNSIGNED(l->entnum); + check = EDICT_FROM_AREA(l); - if (check->fields.sv->solid == SOLID_NOT) continue; // deactivated - if (check->fields.sv->absmin[0] > area_maxs[0] || check->fields.sv->absmin[1] > area_maxs[1] || check->fields.sv->absmin[2] > area_maxs[2] - || check->fields.sv->absmax[0] < area_mins[0] || check->fields.sv->absmax[1] < area_mins[1] || check->fields.sv->absmax[2] < area_mins[2]) + 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]) continue; // not touching if (area_count == area_maxcount) @@ -362,8 +364,10 @@ void SV_AreaEdicts_r (areanode_t *node) if (node->axis == -1) return; // terminal node // recurse down both sides - if ( area_maxs[node->axis] > node->dist ) SV_AreaEdicts_r ( node->children[0] ); - if ( area_mins[node->axis] < node->dist ) SV_AreaEdicts_r ( node->children[1] ); + if ( area_maxs[node->axis] > node->dist ) + SV_AreaEdicts_r ( node->children[0] ); + if ( area_mins[node->axis] < node->dist ) + SV_AreaEdicts_r ( node->children[1] ); } /* @@ -371,7 +375,7 @@ void SV_AreaEdicts_r (areanode_t *node) SV_AreaEdicts ================ */ -int SV_AreaEdicts (vec3_t mins, vec3_t maxs, prvm_edict_t **list, int maxcount, int areatype) +int SV_AreaEdicts (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype) { area_mins = mins; area_maxs = maxs; @@ -395,7 +399,7 @@ SV_PointContents */ int SV_PointContents (vec3_t p) { - prvm_edict_t *touch[MAX_EDICTS], *hit; + edict_t *touch[MAX_EDICTS], *hit; int i, num; int contents, c2; int headnode; @@ -413,14 +417,30 @@ int SV_PointContents (vec3_t p) // might intersect, so do an exact clip headnode = SV_HullForEntity (hit); - angles = hit->fields.sv->angles; - if (hit->fields.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - c2 = CM_TransformedPointContents (p, headnode, hit->fields.sv->origin, hit->fields.sv->angles); + 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); contents |= c2; } return contents; } + + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + edict_t *passedict; + int contentmask; + +} moveclip_t; + + + /* ================ SV_HullForEntity @@ -431,15 +451,15 @@ Offset is filled in to contain the adjustment that must be added to the testing object's origin to get a point to use with the returned hull. ================ */ -int SV_HullForEntity (prvm_edict_t *ent) +int SV_HullForEntity (edict_t *ent) { cmodel_t *model; // decide which clipping hull to use, based on the size - if (ent->fields.sv->solid == SOLID_BSP) + if (ent->solid == SOLID_BSP) { // explicit hulls in the BSP model - model = sv.models[ (int)ent->fields.sv->modelindex ]; + model = sv.models[ ent->s.modelindex ]; if (!model) { @@ -450,7 +470,7 @@ int SV_HullForEntity (prvm_edict_t *ent) } // create a temp hull from bounding box sizes - return CM_HeadnodeForBox (ent->fields.sv->mins, ent->fields.sv->maxs); + return CM_HeadnodeForBox (ent->mins, ent->maxs); } /* @@ -462,7 +482,7 @@ SV_ClipMoveToEntities void SV_ClipMoveToEntities ( moveclip_t *clip ) { int i, num; - prvm_edict_t *touchlist[MAX_EDICTS], *touch; + edict_t *touchlist[MAX_EDICTS], *touch; trace_t trace; int headnode; float *angles; @@ -474,32 +494,30 @@ void SV_ClipMoveToEntities ( moveclip_t *clip ) for (i = 0; i < num; i++) { touch = touchlist[i]; - if (touch->fields.sv->solid == SOLID_NOT) continue; + if (touch->solid == SOLID_NOT) continue; if (touch == clip->passedict) continue; if (clip->trace.allsolid) return; if (clip->passedict) { - if (PRVM_PROG_TO_EDICT(touch->fields.sv->owner) == clip->passedict) - continue; // don't clip against own missiles - if (PRVM_PROG_TO_EDICT(clip->passedict->fields.sv->owner) == touch) - continue; // don't clip against owner + if (touch->owner == clip->passedict) continue; // don't clip against own missiles + if (clip->passedict->owner == touch) continue; // don't clip against owner } - if ( !(clip->contentmask & CONTENTS_DEADMONSTER) && ((int)touch->fields.sv->flags & SVF_DEADMONSTER) ) + if ( !(clip->contentmask & CONTENTS_DEADMONSTER) && (touch->svflags & SVF_DEADMONSTER) ) continue; // might intersect, so do an exact clip headnode = SV_HullForEntity (touch); - angles = touch->fields.sv->angles; - if (touch->fields.sv->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate + angles = touch->s.angles; + if (touch->solid != SOLID_BSP) angles = vec3_origin; // boxes don't rotate - if ((int)touch->fields.sv->flags & SVF_MONSTER) + if (touch->svflags & SVF_MONSTER) { - trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins2, clip->maxs2, headnode, clip->contentmask, touch->fields.sv->origin, angles); + trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins2, clip->maxs2, headnode, clip->contentmask, touch->s.origin, angles); } else { - trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins, clip->maxs, headnode, clip->contentmask, touch->fields.sv->origin, angles); + trace = CM_TransformedBoxTrace (clip->start, clip->end, clip->mins, clip->maxs, headnode, clip->contentmask, touch->s.origin, angles); } if (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction) { @@ -511,11 +529,7 @@ void SV_ClipMoveToEntities ( moveclip_t *clip ) } else clip->trace = trace; } - else if (trace.startsolid) - { - clip->trace.startsolid = true; - //clip->trace.startstuck = true; - } + else if (trace.startsolid) clip->trace.startsolid = true; } } @@ -554,7 +568,7 @@ Passedict and edicts owned by passedict are explicitly not checked. ================== */ -trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, prvm_edict_t *passedict, int contentmask) +trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passedict, int contentmask) { moveclip_t clip; @@ -565,7 +579,7 @@ trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, prvm_edict // clip to world clip.trace = CM_BoxTrace (start, end, mins, maxs, 0, contentmask); - clip.trace.ent = prog->edicts; + clip.trace.ent = ge->edicts; if (clip.trace.fraction == 0) return clip.trace; // blocked by the world clip.contentmask = contentmask; @@ -587,8 +601,3 @@ trace_t SV_Trace (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, prvm_edict return clip.trace; } -trace_t SV_ClipMoveToEntity(prvm_edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int contentsmask) -{ - // correct ?? - return CM_BoxTrace(start, end, mins, maxs, ent->priv.sv->headnode, contentsmask); -} \ No newline at end of file diff --git a/engine/snd_dma.c b/engine/snd_dma.c index 530b2f28..51d6ca02 100644 --- a/engine/snd_dma.c +++ b/engine/snd_dma.c @@ -53,8 +53,8 @@ vec3_t listener_up; bool s_registering; -float soundtime; // sample PAIRS -float paintedtime; // sample PAIRS +int soundtime; // sample PAIRS +int paintedtime; // sample PAIRS // during registration it is possible to have more sounds // than could actually be referenced during gameplay, @@ -80,7 +80,7 @@ cvar_t *s_mixahead; cvar_t *s_primary; -float s_rawend; +int s_rawend; portable_samplepair_t s_rawsamples[MAX_RAW_SAMPLES]; @@ -120,7 +120,8 @@ void S_Init (void) Msg("\n------- sound initialization -------\n"); cv = Cvar_Get ("s_initsound", "1", 0); - if (!cv->value) Msg ("not initializing.\n"); + if (!cv->value) + Msg ("not initializing.\n"); else { s_volume = Cvar_Get ("s_volume", "0.7", CVAR_ARCHIVE); @@ -136,7 +137,8 @@ void S_Init (void) Cmd_AddCommand("soundlist", S_SoundList); Cmd_AddCommand("soundinfo", S_SoundInfo_f); - if (!SNDDMA_Init()) return; + if (!SNDDMA_Init()) + return; S_InitScaletable (); @@ -147,6 +149,7 @@ void S_Init (void) paintedtime = 0; Msg ("sound sampling rate: %i\n", dma.speed); + S_StopAllSounds (); } @@ -163,7 +166,8 @@ void S_Shutdown(void) int i; sfx_t *sfx; - if (!sound_started) return; + if (!sound_started) + return; SNDDMA_Shutdown(); @@ -177,10 +181,13 @@ void S_Shutdown(void) // free all sounds for (i=0, sfx=known_sfx ; i < num_sfx ; i++,sfx++) { - if (!sfx->name[0]) continue; - if (sfx->cache) Z_Free (sfx->cache); + if (!sfx->name[0]) + continue; + if (sfx->cache) + Z_Free (sfx->cache); memset (sfx, 0, sizeof(*sfx)); } + num_sfx = 0; } @@ -195,7 +202,7 @@ S_FindName ================== */ -sfx_t *S_FindName (const char *name, bool create) +sfx_t *S_FindName (char *name, bool create) { int i; sfx_t *sfx; @@ -295,7 +302,7 @@ S_RegisterSound ================== */ -sfx_t *S_RegisterSound (const char *name) +sfx_t *S_RegisterSound (char *name) { sfx_t *sfx; @@ -364,19 +371,18 @@ S_PickChannel */ channel_t *S_PickChannel(int entnum, int entchannel) { - int ch_idx; - int first_to_die; - float life_left; + int ch_idx; + int first_to_die; + int life_left; channel_t *ch; if (entchannel<0) Com_Error (ERR_DROP, "S_PickChannel: entchannel<0"); - // Check for replacement sound, or find the best one to replace - first_to_die = -1; - life_left = 32768.0; - - for (ch_idx = 0; ch_idx < MAX_CHANNELS; ch_idx++) +// Check for replacement sound, or find the best one to replace + first_to_die = -1; + life_left = 0x7fffffff; + for (ch_idx=0 ; ch_idx < MAX_CHANNELS ; ch_idx++) { if (entchannel != 0 // channel 0 never overrides && channels[ch_idx].entnum == entnum @@ -686,16 +692,16 @@ void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float f ps->sfx = sfx; // drift s_beginofs - start = cl.frame.servertime * dma.speed + s_beginofs; + start = cl.frame.servertime * 0.001 * dma.speed + s_beginofs; if (start < paintedtime) { start = paintedtime; - s_beginofs = start - (cl.frame.servertime * dma.speed); + s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); } else if (start > paintedtime + 0.3 * dma.speed) { start = paintedtime + 0.1 * dma.speed; - s_beginofs = start - (cl.frame.servertime * dma.speed); + s_beginofs = start - (cl.frame.servertime * 0.001 * dma.speed); } else { @@ -726,7 +732,7 @@ void S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, float f S_StartLocalSound ================== */ -int S_StartLocalSound (const char *sound) +int S_StartLocalSound (char *sound) { sfx_t *sfx; @@ -886,7 +892,7 @@ void S_AddLoopSounds (void) ch->rightvol = right_total; ch->autosound = true; // remove next frame ch->sfx = sfx; - ch->pos = fmod(paintedtime, sc->length); + ch->pos = paintedtime % sc->length; ch->end = paintedtime + sc->length - ch->pos; } } @@ -920,7 +926,7 @@ void S_RawSamples (int samples, int rate, int width, int channels, byte *data) { // optimized case for (i=0 ; i= samples) break; - dst = (int)s_rawend & (MAX_RAW_SAMPLES-1); + dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = LittleShort(((short *)data)[src*2]) << 8; @@ -951,7 +957,7 @@ void S_RawSamples (int samples, int rate, int width, int channels, byte *data) src = i*scale; if (src >= samples) break; - dst = (int)s_rawend & (MAX_RAW_SAMPLES-1); + dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = LittleShort(((short *)data)[src]) << 8; @@ -966,7 +972,7 @@ void S_RawSamples (int samples, int rate, int width, int channels, byte *data) src = i*scale; if (src >= samples) break; - dst = (int)s_rawend & (MAX_RAW_SAMPLES-1); + dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = ((char *)data)[src*2] << 16; @@ -981,7 +987,7 @@ void S_RawSamples (int samples, int rate, int width, int channels, byte *data) src = i*scale; if (src >= samples) break; - dst = (int)s_rawend & (MAX_RAW_SAMPLES-1); + dst = s_rawend&(MAX_RAW_SAMPLES-1); s_rawend++; s_rawsamples[dst].left = (((byte *)data)[src]-128) << 16; @@ -1104,8 +1110,8 @@ void GetSoundtime(void) void S_Update_(void) { - uint endtime; - int samps; + unsigned endtime; + int samps; if (!sound_started) return; @@ -1121,7 +1127,7 @@ void S_Update_(void) // check to make sure that we haven't overshot if (paintedtime < soundtime) { - MsgWarn("S_Update_: overflow [%g]\n", soundtime - paintedtime); + MsgWarn("S_Update_: overflow\n"); paintedtime = soundtime; } diff --git a/engine/snd_loc.h b/engine/snd_loc.h index d8e8bf65..8fba57d1 100644 --- a/engine/snd_loc.h +++ b/engine/snd_loc.h @@ -28,7 +28,7 @@ typedef struct typedef struct { - float length; + int length; int loopstart; int speed; // not needed, because converted on load? int width; @@ -39,7 +39,7 @@ typedef struct typedef struct sfx_s { char name[MAX_QPATH]; - int registration_sequence; + int registration_sequence; sfxcache_t *cache; char *truename; } sfx_t; @@ -53,21 +53,21 @@ typedef struct playsound_s sfx_t *sfx; float volume; float attenuation; - int entnum; - int entchannel; - bool fixed_origin; // use origin field instead of entnum's origin + int entnum; + int entchannel; + bool fixed_origin; // use origin field instead of entnum's origin vec3_t origin; - float begin; // begin on this sample + unsigned begin; // begin on this sample } playsound_t; typedef struct { - int channels; - int samples; // mono samples in buffer - int submission_chunk; // don't mix less than this # - int samplepos; // in mono samples - int samplebits; - int speed; + int channels; + int samples; // mono samples in buffer + int submission_chunk; // don't mix less than this # + int samplepos; // in mono samples + int samplebits; + int speed; byte *buffer; } dma_t; @@ -75,18 +75,18 @@ typedef struct typedef struct { sfx_t *sfx; // sfx number - int leftvol; // 0-255 volume - int rightvol; // 0-255 volume - float end; // end time in global paintsamples + int leftvol; // 0-255 volume + int rightvol; // 0-255 volume + int end; // end time in global paintsamples int pos; // sample position in sfx - int looping; // where to loop, -1 = no looping OBSOLETE? - int entnum; // to allow overriding a specific sound - int entchannel; // + int looping; // where to loop, -1 = no looping OBSOLETE? + int entnum; // to allow overriding a specific sound + int entchannel; // vec3_t origin; // only use if fixed_origin is set vec_t dist_mult; // distance multiplier (attenuation/clipK) - int master_vol; // 0-255 master volume - bool fixed_origin; // use origin instead of fetching entnum's origin - bool autosound; // from an entity->sound, cleared each frame + int master_vol; // 0-255 master volume + bool fixed_origin; // use origin instead of fetching entnum's origin + bool autosound; // from an entity->sound, cleared each frame } channel_t; typedef struct @@ -126,8 +126,8 @@ void SNDDMA_Submit(void); #define MAX_CHANNELS 32 extern channel_t channels[MAX_CHANNELS]; -extern float paintedtime; -extern float s_rawend; +extern int paintedtime; +extern int s_rawend; extern vec3_t listener_origin; extern vec3_t listener_forward; extern vec3_t listener_right; @@ -155,7 +155,7 @@ sfxcache_t *S_LoadSound (sfx_t *s); void S_IssuePlaysound (playsound_t *ps); -void S_PaintChannels(float endtime); +void S_PaintChannels(int endtime); // picks a channel based on priorities, empty slots, number of channels channel_t *S_PickChannel(int entnum, int entchannel); diff --git a/engine/snd_mix.c b/engine/snd_mix.c index 2a306d7b..97fc94c0 100644 --- a/engine/snd_mix.c +++ b/engine/snd_mix.c @@ -109,17 +109,17 @@ S_TransferPaintBuffer =================== */ -void S_TransferPaintBuffer(float endtime) +void S_TransferPaintBuffer(int endtime) { int out_idx; - float count; + int count; int out_mask; int *p; int step; - int val; - dword *pbuf; + int val; + unsigned long *pbuf; - pbuf = (dword*)dma.buffer; + pbuf = (unsigned long *)dma.buffer; if (s_testsound->value) { @@ -129,7 +129,7 @@ void S_TransferPaintBuffer(float endtime) // write a fixed sine wave count = (endtime - paintedtime); for (i=0 ; ivalue*256; - //Msg ("%i to %i\n", paintedtime, endtime); +//Msg ("%i to %i\n", paintedtime, endtime); while (paintedtime < endtime) { // if paintbuffer is smaller than DMA buffer @@ -221,11 +221,12 @@ void S_PaintChannels(float endtime) continue; } - if (ps->begin < end) end = ps->begin;// stop here + if (ps->begin < end) + end = ps->begin; // stop here break; } - // clear the paint buffer + // clear the paint buffer if (s_rawend < paintedtime) { // Msg ("clear\n"); @@ -241,7 +242,7 @@ void S_PaintChannels(float endtime) for (i=paintedtime ; inumfilenames; i++ ) - { - sprintf(basepath, "%s/%s", GI.gamedir, gamedll->filenames[i]); - hinstance = LoadLibrary ( basepath ); - - if (!hinstance) - { - sprintf(basepath, "%s/%s", GI.basedir, gamedll->filenames[i]); - hinstance = LoadLibrary ( basepath ); - } - - if (hinstance) - { - if (( GetGameAPI = (void *)GetProcAddress( hinstance, procname )) == 0 ) - Sys_UnloadGame( hinstance ); - else break; - } - else MsgWarn("Can't loading %s\n", gamedll->filenames[i] ); - } - - GetGameAPI = (void *)GetProcAddress (hinstance, procname ); - - if (!GetGameAPI) - { - Sys_UnloadGame( hinstance ); - return NULL; - } - return GetGameAPI (parms); -} - //======================================================================= /* diff --git a/engine/vid_dll.c b/engine/vid_dll.c index 36530929..0265bb60 100644 --- a/engine/vid_dll.c +++ b/engine/vid_dll.c @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. renderer_exp_t *re; extern HWND cl_hwnd; +extern bool ActiveApp, Minimized; extern HINSTANCE global_hInstance; #ifndef WM_MOUSEWHEEL @@ -54,6 +55,9 @@ HWND cl_hwnd; // Main window handle for life of program LONG WINAPI MainWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); + +extern unsigned sys_msg_time; + /* ========================================================================== @@ -179,25 +183,29 @@ int MapKey (int key) } } -void AppActivate(bool fActive, bool fMinimize) +void AppActivate(BOOL fActive, BOOL minimize) { - if(fActive && !fMinimize) host.state = HOST_FRAME; - else if(fMinimize) host.state = HOST_SLEEP; - else host.state = HOST_NOFOCUS; + Minimized = minimize; Key_ClearStates(); - // minimize/restore mouse-capture on demand - if(host.state == HOST_FRAME) - { - IN_Activate (true); - S_Activate (true); - } + // we don't want to act like we're active if we're minimized + if (fActive && !Minimized) + ActiveApp = true; else + ActiveApp = false; + + // minimize/restore mouse-capture on demand + if (!ActiveApp) { IN_Activate (false); S_Activate (false); } + else + { + IN_Activate (true); + S_Activate (true); + } } /* @@ -215,13 +223,13 @@ LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { if ( ( ( int ) wParam ) > 0 ) { - Key_Event( K_MWHEELUP, true, host.sv_timer ); - Key_Event( K_MWHEELUP, false, host.sv_timer ); + Key_Event( K_MWHEELUP, true, sys_msg_time ); + Key_Event( K_MWHEELUP, false, sys_msg_time ); } else { - Key_Event( K_MWHEELDOWN, true, host.sv_timer ); - Key_Event( K_MWHEELDOWN, false, host.sv_timer ); + Key_Event( K_MWHEELDOWN, true, sys_msg_time ); + Key_Event( K_MWHEELDOWN, false, sys_msg_time ); } return DefWindowProc (hWnd, uMsg, wParam, lParam); } @@ -235,13 +243,13 @@ LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) */ if ( ( short ) HIWORD( wParam ) > 0 ) { - Key_Event( K_MWHEELUP, true, host.sv_timer ); - Key_Event( K_MWHEELUP, false, host.sv_timer ); + Key_Event( K_MWHEELUP, true, sys_msg_time ); + Key_Event( K_MWHEELUP, false, sys_msg_time ); } else { - Key_Event( K_MWHEELDOWN, true, host.sv_timer ); - Key_Event( K_MWHEELDOWN, false, host.sv_timer ); + Key_Event( K_MWHEELDOWN, true, sys_msg_time ); + Key_Event( K_MWHEELDOWN, false, sys_msg_time ); } break; @@ -297,7 +305,7 @@ LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) Cvar_SetValue( "vid_ypos", yPos + r.top); vid_xpos->modified = false; vid_ypos->modified = false; - if (host.state == HOST_FRAME) + if (ActiveApp) IN_Activate (true); } } @@ -343,11 +351,11 @@ LONG WINAPI MainWndProc ( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) } // fall through case WM_KEYDOWN: - Key_Event( MapKey( lParam ), true, host.sv_timer); + Key_Event( MapKey( lParam ), true, sys_msg_time); break; case WM_SYSKEYUP: case WM_KEYUP: - Key_Event( MapKey( lParam ), false, host.sv_timer); + Key_Event( MapKey( lParam ), false, sys_msg_time); break; default: // pass all unhandled messages to DefWindowProc return DefWindowProc (hWnd, uMsg, wParam, lParam); @@ -462,12 +470,6 @@ char *FS_Title( void ) return GI.title; } -cvar_t *VID_Cvar_Set (const char *var_name, const char *value) -{ - return Cvar_Set( var_name, value ); -} - - /* ============== VID_InitRenderer @@ -496,7 +498,7 @@ void VID_InitRenderer( void ) ri.gamedir = FS_Gamedir; ri.title = FS_Title; ri.Cvar_Get = Cvar_Get; - ri.Cvar_Set = VID_Cvar_Set; + ri.Cvar_Set = Cvar_Set; ri.Cvar_SetValue = Cvar_SetValue; ri.Vid_GetModeInfo = VID_GetModeInfo; ri.Vid_MenuInit = VID_MenuInit; diff --git a/public/basemath.h b/public/basemath.h index 9a75233b..6623ccec 100644 --- a/public/basemath.h +++ b/public/basemath.h @@ -33,13 +33,12 @@ _inline void VectorScale(const vec3_t a, const float b, vec3_t c){c[0]=b*a[0];c[ #define VectorSet(v, x, y, z) {v[0] = x; v[1] = y; v[2] = z;} #define VectorClear(x) {x[0] = x[1] = x[2] = 0;} #define VectorNegate(x, y) {y[0] =-x[0]; y[1]=-x[1]; y[2]=-x[2];} -_inline float anglemod(const float a){return(360.0/65536) * ((int)(a*(65536/360.0)) & 65535);} - #define VectorM(scale1, b1, c) ((c)[0] = (scale1) * (b1)[0],(c)[1] = (scale1) * (b1)[1],(c)[2] = (scale1) * (b1)[2]) +#define VectorMA(a, scale, b, c) ((c)[0] = (a)[0] + (scale) * (b)[0],(c)[1] = (a)[1] + (scale) * (b)[1],(c)[2] = (a)[2] + (scale) * (b)[2]) #define VectorMAM(scale1, b1, scale2, b2, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2]) #define VectorMAMAM(scale1, b1, scale2, b2, scale3, b3, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2]) #define VectorMAMAMAM(scale1, b1, scale2, b2, scale3, b3, scale4, b4, c) ((c)[0] = (scale1) * (b1)[0] + (scale2) * (b2)[0] + (scale3) * (b3)[0] + (scale4) * (b4)[0],(c)[1] = (scale1) * (b1)[1] + (scale2) * (b2)[1] + (scale3) * (b3)[1] + (scale4) * (b4)[1],(c)[2] = (scale1) * (b1)[2] + (scale2) * (b2)[2] + (scale3) * (b3)[2] + (scale4) * (b4)[2]) - +_inline float anglemod(const float a){return(360.0/65536) * ((int)(a*(65536/360.0)) & 65535);} _inline void VectorBound(const float min, vec3_t v, const float max) { @@ -130,13 +129,6 @@ _inline void VectorIRotate (const vec3_t in1, const matrix3x4 in2, vec3_t out) out[2] = in1[0] * in2[0][2] + in1[1] * in2[1][2] + in1[2] * in2[2][2]; } -_inline void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) -{ - vc[0] = va[0] + scale * vb[0]; - vc[1] = va[1] + scale * vb[1]; - vc[2] = va[2] + scale * vb[2]; -} - _inline void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) { cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; @@ -177,7 +169,7 @@ _inline void VectorVectors(vec3_t forward, vec3_t right, vec3_t up) CrossProduct(right, forward, up); } -_inline void AngleVectorsRight(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +_inline void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) { float angle; static float sr, sp, sy, cr, cp, cy; @@ -199,45 +191,21 @@ _inline void AngleVectorsRight(vec3_t angles, vec3_t forward, vec3_t right, vec3 forward[1] = cp*sy; forward[2] = -sp; } - if (right || up) + if (right) { - if (angles[ROLL]) - { - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - if (right) - { - right[0] = -1*(sr*sp*cy+cr*-sy); - right[1] = -1*(sr*sp*sy+cr*cy); - right[2] = -1*(sr*cp); - } - if (up) - { - up[0] = (cr*sp*cy+-sr*-sy); - up[1] = (cr*sp*sy+-sr*cy); - up[2] = cr*cp; - } - } - else - { - if (right) - { - right[0] = sy; - right[1] = -cy; - right[2] = 0; - } - if (up) - { - up[0] = (sp*cy); - up[1] = (sp*sy); - up[2] = cp; - } - } + right[0] = (-1*sr*sp*cy+-1*cr*-sy); + right[1] = (-1*sr*sp*sy+-1*cr*cy); + right[2] = -1*sr*cp; + } + if (up) + { + up[0] = (cr*sp*cy+-sr*-sy); + up[1] = (cr*sp*sy+-sr*cy); + up[2] = cr*cp; } } -_inline void AngleVectorsLeft(const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up) +_inline void AngleVectorsFLU(const vec3_t angles, vec3_t forward, vec3_t left, vec3_t up) { float angle; static float sr, sp, sy, cr, cp, cy; diff --git a/public/basetypes.h b/public/basetypes.h index cd2d82b5..0998a1bf 100644 --- a/public/basetypes.h +++ b/public/basetypes.h @@ -44,6 +44,8 @@ typedef struct vfile_s vfile_t; 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 int progsnum_t; typedef struct progfuncs_s progfuncs_t; diff --git a/public/bspmodel.h b/public/bspmodel.h index b109d664..d4083dd7 100644 --- a/public/bspmodel.h +++ b/public/bspmodel.h @@ -207,15 +207,6 @@ typedef struct cmodel_s vec3_t mins, maxs; // boundbox vec3_t origin; // for sounds or lights int headnode; // bsp info - - vec3_t normalmins; // bounding box at angles '0 0 0' - vec3_t normalmaxs; - - vec3_t yawmins; // bounding box if yaw angle is not 0, but pitch and roll are used - vec3_t yawmaxs; - - vec3_t rotatedmins; // bounding box if pitch or roll are used - vec3_t rotatedmaxs; int numframes; //sprite framecount void *extradata; //for studio models diff --git a/public/const.h b/public/const.h index df652a07..bcd559d3 100644 --- a/public/const.h +++ b/public/const.h @@ -79,10 +79,10 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define PRINT_HIGH 2 // critical messages #define PRINT_CHAT 3 // chat messages -#define SPAWNFLAG_NOT_EASY 256 -#define SPAWNFLAG_NOT_MEDIUM 512 -#define SPAWNFLAG_NOT_HARD 1024 -#define SPAWNFLAG_NOT_DEATHMATCH 2048 +#define SPAWNFLAG_NOT_EASY 0x00000100 +#define SPAWNFLAG_NOT_MEDIUM 0x00000200 +#define SPAWNFLAG_NOT_HARD 0x00000400 +#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800 // entity_state_t->renderfx flags #define RF_MINLIGHT 1 // allways have some light (viewmodel) @@ -148,29 +148,23 @@ typedef enum WEAPON_FIRING } weaponstate_t; -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 -{ - MOVETYPE_NONE = 0, // never moves, but can collide - MOVETYPE_NOCLIP, // origin and angles change with no interaction - MOVETYPE_PUSH, // no clip to world, push on box contact - MOVETYPE_WALK, // player case - MOVETYPE_STEP, // monster case (get rid of this) - MOVETYPE_FLY, // ignore gravity - MOVETYPE_TOSS, // gravity - MOVETYPE_BOUNCE, - MOVETYPE_FOLLOW, // attached models - MOVETYPE_COMPLEX, // complex moving ents (parent system) - MOVETYPE_RAGDOLL, // npc ragdoll (not implemented yet) - -} movetype_t; +#define MOVETYPE_NONE 0 // never moves +#define MOVETYPE_NOCLIP 1 // origin and angles change with no interaction +#define MOVETYPE_PUSH 2 // no clip to world, push on box contact +#define MOVETYPE_STOP 3 // no clip to world, stops on box contact +#define MOVETYPE_WALK 4 // gravity +#define MOVETYPE_STEP 5 // gravity, special edge handling +#define MOVETYPE_FLY 6 +#define MOVETYPE_TOSS 7 // gravity +#define MOVETYPE_FLYMISSILE 8 // extra size to monsters +#define MOVETYPE_BOUNCE 9 +#define MOVETYPE_FOLLOW 10 // attached models +#define MOVETYPE_VEHICLE 11 +#define MOVETYPE_PUSHABLE 12 +#define MOVETYPE_DEBRIS 13 // non-solid debris that can still hurt you +#define MOVETYPE_RAIN 14 // identical to MOVETYPE_FLYMISSILE, but doesn't cause splash noises when touching water. +#define MOVETYPE_PENDULUM 15 // same as MOVETYPE_PUSH, but used only for pendulums to grab special-case problems +#define MOVETYPE_CONVEYOR 16 /* ============================================================== @@ -217,8 +211,30 @@ void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ); void PerpendicularVector( vec3_t dst, const vec3_t src ); void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); + + void Com_PageInMemory (byte *buffer, int size); +//============================================= + +// +// key / value info strings +// +char *Info_ValueForKey (char *s, char *key); +void Info_RemoveKey (char *s, char *key); +void Info_SetValueForKey (char *s, char *key, char *value); +bool Info_Validate (char *s); + +/* +============================================================== + +SYSTEM SPECIFIC + +============================================================== +*/ + +extern int curtime; // time returned by last Sys_Milliseconds + /* ============================================================== @@ -247,16 +263,14 @@ COLLISION DETECTION // a trace is returned when a box is swept through the world typedef struct { - bool allsolid; // if true, plane is not valid - bool startsolid; // if true, the initial point was in a solid area - bool startstuck; // if true, the initial point was stuck into SOLID_BSP model - - float fraction; // time completed, 1.0 = didn't hit anything + bool allsolid; // if true, plane is not valid + bool startsolid; // if true, the initial point was in a solid area + float fraction; // time completed, 1.0 = didn't hit anything vec3_t endpos; // final position - cplane_t plane; // surface normal at impact - csurface_t *surface; // surface hit - int contents; // contents on other side of surface hit - prvm_edict_t *ent; // not set by CM_*() functions + 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 } trace_t; @@ -298,7 +312,7 @@ typedef struct byte pm_time; // each unit = 8 ms short gravity; short delta_angles[3]; // add to command angles to get view direction - // changed by spawns, rotating objects, and teleporters + // changed by spawns, rotating objects, and teleporters } pmove_state_t; @@ -324,7 +338,6 @@ typedef struct usercmd_s short forwardmove, sidemove, upmove; byte impulse; // remove? byte lightlevel; // light level the player is standing on - } usercmd_t; @@ -340,14 +353,14 @@ typedef struct // results (out) int numtouch; - prvm_edict_t *touchents[MAXTOUCH]; + struct edict_s *touchents[MAXTOUCH]; vec3_t viewangles; // clamped float viewheight; vec3_t mins, maxs; // bounding box size - prvm_edict_t *groundentity; + struct edict_s *groundentity; int watertype; int waterlevel; @@ -790,16 +803,16 @@ typedef struct // these fields do not need to be communicated bit-precise - vec3_t viewangles; // for fixed views - vec3_t viewoffset; // add to pmovestate->origin + vec3_t viewangles; // for fixed views + vec3_t viewoffset; // add to pmovestate->origin vec3_t kick_angles; // add to view direction to get render angles - // set by weapon kicks, pain effects, etc + // set by weapon kicks, pain effects, etc vec3_t gunangles; vec3_t gunoffset; int gunindex; int gunframe; // studio frame - int sequence; // studio animation sequence + int sequence; // stuido animation sequence int gunbody; int gunskin; diff --git a/public/ref_client.h b/public/ref_client.h deleted file mode 100644 index bf7b4837..00000000 --- a/public/ref_client.h +++ /dev/null @@ -1,11 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 © -// ref_client.h - client user interface -//======================================================================= -#ifndef REF_CLIENT_H -#define REF_CLIENT_H - -//dll handle -typedef void *(*client_api_t)(void); - -#endif//REF_CLIENT_H \ No newline at end of file diff --git a/public/ref_server.h b/public/ref_server.h deleted file mode 100644 index b9a84433..00000000 --- a/public/ref_server.h +++ /dev/null @@ -1,201 +0,0 @@ - -// game.h -- game dll information visible to server -#include "savefile.h" - -#define GAME_API_VERSION 3 - -// 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 - -// 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, *next; -} link_t; - -#define MAX_ENT_CLUSTERS 16 - -#ifndef GAME_INCLUDE - -struct gclient_s -{ - player_state_t ps; // communicated by server to clients - int ping; - // the game dll can add anything it wants after - // this point in the structure -}; - - -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; - - // the game dll can add anything it wants after - // this point in the structure -}; - -#endif // GAME_INCLUDE - -//=============================================================== - -// -// functions provided by the main engine -// -typedef struct game_import_s -{ - //shared xash systems - filesystem_api_t Fs; - vfilesystem_api_t VFs; - memsystem_api_t Mem; - scriptsystem_api_t Script; // basic script-machine - compilers_api_t Compile; // compilers callback - infostring_api_t Info; - message_write_t Msg; // network messaging - - // special messages - void (*bprintf) (int printlevel, char *fmt, ...); - void (*dprintf) (char *fmt, ...); - void (*cprintf) (edict_t *ent, int printlevel, char *fmt, ...); - void (*centerprintf) (edict_t *ent, char *fmt, ...); - void (*sound) (edict_t *ent, int channel, int soundindex, float volume, float attenuation, float timeofs); - void (*positioned_sound) (vec3_t origin, edict_t *ent, int channel, int soundinedex, float volume, float attenuation, float timeofs); - - // get game info - gameinfo_t (*GameInfo)( void ); - - // config strings hold all the index strings, the lightstyles, - // and misc data like the sky definition and cdtrack. - // All of the current configstrings are sent to clients when - // they connect, and changes are sent to all connected clients. - void (*configstring) (int num, char *string); - - void (*error) (char *fmt, ...); - - // the *index functions create configstrings and some internal server state - int (*modelindex) (char *name); - int (*soundindex) (char *name); - int (*imageindex) (char *name); - - void (*setmodel) (edict_t *ent, char *name); - - // collision detection - trace_t (*trace) (vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, edict_t *passent, int contentmask); - int (*pointcontents) (vec3_t point); - bool (*inPVS) (vec3_t p1, vec3_t p2); - bool (*inPHS) (vec3_t p1, vec3_t p2); - void (*SetAreaPortalState) (int portalnum, bool open); - bool (*AreasConnected) (int area1, int area2); - - // an entity will never be sent to a client or used for collision - // if it is not passed to linkentity. If the size, position, or - // solidity changes, it must be relinked. - void (*linkentity) (edict_t *ent); - void (*unlinkentity) (edict_t *ent); // call before removing an interactive edict - int (*BoxEdicts) (vec3_t mins, vec3_t maxs, edict_t **list, int maxcount, int areatype); - void (*Pmove) (pmove_t *pmove); // player movement code common with client prediction - - // common studio utils - byte *(*getmodelhdr) (edict_t *ent);//returned a pointer on a studiohdr_t for current entity - - // console variable interaction - cvar_t *(*cvar) (char *var_name, char *value, int flags); - cvar_t *(*cvar_set) (char *var_name, char *value); - cvar_t *(*cvar_forceset) (char *var_name, char *value); - - // ClientCommand and ServerCommand parameter access - int (*argc) (void); - char *(*argv) (int n); - char *(*args) (void); // concatenation of all argv >= 1 - - // add commands to the server console as if they were typed in - // for map changing, etc - void (*AddCommandString) (char *text); - - void (*DebugGraph) (float value, int color); -} game_import_t; - -// -// functions exported by the game subsystem -// -typedef struct game_export_s -{ - int apiversion; - - // the init function will only be called when a game starts, - // not each time a level is loaded. Persistant data for clients - // and the server can be allocated in init - void (*Init) (void); - void (*Shutdown) (void); - - // each new level entered will cause a call to SpawnEntities - void (*SpawnEntities) (char *mapname, char *entstring, char *spawnpoint); - - void (*WriteLump) (dsavehdr_t *hdr, file_t *f, int lumpnum, bool autosave); - void (*ReadLump) (byte *base, lump_t *l, int lumpnum); - - bool (*ClientConnect) (edict_t *ent, char *userinfo); - void (*ClientBegin) (edict_t *ent); - void (*ClientUserinfoChanged) (edict_t *ent, char *userinfo); - void (*ClientDisconnect) (edict_t *ent); - void (*ClientCommand) (edict_t *ent); - void (*ClientThink) (edict_t *ent, usercmd_t *cmd); - - void (*RunFrame) (void); - - // ServerCommand will be called when an "sv " command is issued on the - // server console. - // The game can issue gi.argc() / gi.argv() commands to get the rest - // of the parameters - void (*ServerCommand) (void); - - // - // global variables shared between game and server - // - - // The edict array is allocated in the game dll so it - // can vary in size from one game to another. - // - // The size will be fixed when ge->Init() is called - edict_t *edicts; - int edict_size; - int num_edicts; // current number, <= max_edicts - int max_edicts; -} game_export_t; - -//dll handle -typedef game_export_t (*server_api_t)(game_import_t); \ No newline at end of file diff --git a/public/ref_system.h b/public/ref_system.h index 630cc283..e8e13e44 100644 --- a/public/ref_system.h +++ b/public/ref_system.h @@ -293,7 +293,7 @@ typedef struct float vieworg[3]; float viewangles[3]; float blend[4]; // rgba 0-1 full screen blend - double time; // time is used to auto animate + float time; // time is used to auto animate int rdflags; // RDF_UNDERWATER, etc byte *areabits; // if not NULL, only areas with set bits will be drawn diff --git a/release.bat b/release.bat index 2b94735a..e812f2a7 100644 --- a/release.bat +++ b/release.bat @@ -24,7 +24,7 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% renderer/renderer.dsp %CONFIG%"renderer - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -progs\qcclib.exe -O3 +progs\qcclib.exe if errorlevel 1 set BUILD_ERROR=1 if "%BUILD_ERROR%"=="" goto build_ok @@ -56,5 +56,5 @@ if exist progs\server.dat copy progs\server.dat D:\Xash3D\xash\server.dat echo Build succeeded! echo Please wait. Xash is now loading cd D:\Xash3D\ -xash.exe +map qctest +xash.exe -game valve +map skytest -debug :done \ No newline at end of file diff --git a/renderer/gl_mesh.c b/renderer/gl_mesh.c index 435f0b7e..8233db8b 100644 --- a/renderer/gl_mesh.c +++ b/renderer/gl_mesh.c @@ -125,7 +125,7 @@ void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp) // move should be the delta back to the previous frame * backlerp VectorSubtract (currententity->oldorigin, currententity->origin, delta); - AngleVectorsRight(currententity->angles, vectors[0], vectors[1], vectors[2]); + AngleVectors(currententity->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left @@ -454,7 +454,7 @@ static bool R_CullAliasModel( vec3_t bbox[8], entity_t *e ) */ VectorCopy( e->angles, angles ); angles[YAW] = -angles[YAW]; - AngleVectorsRight( angles, vectors[0], vectors[1], vectors[2] ); + AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); for ( i = 0; i < 8; i++ ) { diff --git a/renderer/gl_rmain.c b/renderer/gl_rmain.c index 166259e3..9cd3e757 100644 --- a/renderer/gl_rmain.c +++ b/renderer/gl_rmain.c @@ -499,7 +499,7 @@ void R_SetupFrame (void) // build the transformation matrix for the given view angles VectorCopy (r_newrefdef.vieworg, r_origin); - AngleVectorsRight(r_newrefdef.viewangles, vforward, vright, vup); + AngleVectors(r_newrefdef.viewangles, vforward, vright, vup); // current viewcluster if ( !( r_newrefdef.rdflags & RDF_NOWORLDMODEL ) ) diff --git a/renderer/gl_rsurf.c b/renderer/gl_rsurf.c index aa8460c8..569e1a86 100644 --- a/renderer/gl_rsurf.c +++ b/renderer/gl_rsurf.c @@ -976,7 +976,7 @@ void R_DrawBrushModel ( int passnum ) vec3_t forward, right, up; VectorCopy (modelorg, temp); - AngleVectorsRight(e->angles, forward, right, up); + AngleVectors(e->angles, forward, right, up); modelorg[0] = DotProduct (temp, forward); modelorg[1] = -DotProduct (temp, right); modelorg[2] = DotProduct (temp, up); diff --git a/renderer/r_sprite.c b/renderer/r_sprite.c index d7b4abde..2854f9b7 100644 --- a/renderer/r_sprite.c +++ b/renderer/r_sprite.c @@ -281,7 +281,7 @@ void R_DrawSpriteModel( int passnum ) switch( psprite->type ) { case SPR_ORIENTED: - AngleVectorsRight(e->angles, forward, right, up); + AngleVectors(e->angles, forward, right, up); VectorScale(forward, 0.01, forward );//offset for decals VectorSubtract(e->origin, forward, e->origin ); break; diff --git a/renderer/r_studio.c b/renderer/r_studio.c index 3c6c4c76..4aef08a6 100644 --- a/renderer/r_studio.c +++ b/renderer/r_studio.c @@ -1012,7 +1012,7 @@ static bool R_StudioComputeBBox( vec3_t *bbox ) //rotate the bounding box VectorCopy( e->angles, angles ); angles[PITCH] = -angles[PITCH]; - AngleVectorsRight( angles, vectors[0], vectors[1], vectors[2] ); + AngleVectors( angles, vectors[0], vectors[1], vectors[2] ); for ( i = 0; i < 8; i++ ) {