X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=sv_phys.c;h=2355d16b7764716ebcee306df6993b647a2954f4;hp=9f7a0adca90e597a0c878883f759ccbdb5b77509;hb=cb642c507a7bc68ddf0f021347372d7dbb1d76d5;hpb=287b68565e118e90f3d36498681f2b287a4e6d20 diff --git a/sv_phys.c b/sv_phys.c index 9f7a0adc..2355d16b 100644 --- a/sv_phys.c +++ b/sv_phys.c @@ -20,6 +20,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // sv_phys.c #include "quakedef.h" +// used only for VM_GetTempString +#include "prvm_cmds.h" /* @@ -39,20 +41,25 @@ solid_edge items only clip against bsp models. */ -cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"}; -cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"}; -cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"}; -cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"}; -cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"}; -cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"}; -cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"}; -cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"}; -cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "1"}; -cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"}; +cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4", "how fast you slow down"}; +cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"}; +cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100", "how fast you come to a complete stop"}; +cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800", "how fast you fall (512 = roughly earth gravity)"}; +cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000", "universal speed limit on all entities"}; +cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0", "prevents MOVETYPE_STEP entities (monsters) from moving"}; +cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18", "how high you can step up (TW_SV_STEPCONTROL extension)"}; +cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "0", "whether you can step up while jumping (sv_gameplayfix_stepwhilejumping must also be 1)"}; +cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"}; +cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "0", "enables simpler/buggier player physics (not recommended)"}; +cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0", "freezes time, except for players, allowing you to walk around and take screenshots of explosions"}; +cvar_t sv_playerphysicsqc = {CVAR_NOTIFY, "sv_playerphysicsqc", "1", "enables QuakeC function to override player physics"}; + +cvar_t sv_sound_watersplash = {0, "sv_sound_watersplash", "misc/h2ohit1.wav", "sound to play when MOVETYPE_FLY/TOSS/BOUNCE/STEP entity enters or leaves water (empty cvar disables the sound)"}; +cvar_t sv_sound_land = {0, "sv_sound_land", "demon/dland2.wav", "sound to play when MOVETYPE_STEP entity hits the ground at high speed (empty cvar disables the sound)"}; #define MOVE_EPSILON 0.01 -void SV_Physics_Toss (edict_t *ent); +void SV_Physics_Toss (prvm_edict_t *ent); void SV_Phys_Init (void) { @@ -61,6 +68,27 @@ void SV_Phys_Init (void) Cvar_RegisterVariable(&sv_wallfriction); Cvar_RegisterVariable(&sv_newflymove); Cvar_RegisterVariable(&sv_freezenonclients); + + Cvar_RegisterVariable(&sv_playerphysicsqc); + + Cvar_RegisterVariable(&sv_sound_watersplash); + Cvar_RegisterVariable(&sv_sound_land); +} + +/* +============ +SV_TestEntityPosition + +returns true if the entity is in solid currently +============ +*/ +static int SV_TestEntityPosition (prvm_edict_t *ent) +{ + trace_t trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent); + if (trace.startsupercontents & SUPERCONTENTS_SOLID) + return true; + else + return false; } /* @@ -71,18 +99,18 @@ SV_CheckAllEnts void SV_CheckAllEnts (void) { int e; - edict_t *check; + prvm_edict_t *check; // see if any solid entities are inside the final position - check = NEXT_EDICT(sv.edicts); - for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check)) + check = PRVM_NEXT_EDICT(prog->edicts); + for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check)) { - if (check->e->free) + if (check->priv.server->free) continue; - if (check->v->movetype == MOVETYPE_PUSH - || check->v->movetype == MOVETYPE_NONE - || check->v->movetype == MOVETYPE_FOLLOW - || check->v->movetype == MOVETYPE_NOCLIP) + if (check->fields.server->movetype == MOVETYPE_PUSH + || check->fields.server->movetype == MOVETYPE_NONE + || check->fields.server->movetype == MOVETYPE_FOLLOW + || check->fields.server->movetype == MOVETYPE_NOCLIP) continue; if (SV_TestEntityPosition (check)) @@ -95,7 +123,7 @@ void SV_CheckAllEnts (void) SV_CheckVelocity ================ */ -void SV_CheckVelocity (edict_t *ent) +void SV_CheckVelocity (prvm_edict_t *ent) { int i; float wishspeed; @@ -105,29 +133,60 @@ void SV_CheckVelocity (edict_t *ent) // for (i=0 ; i<3 ; i++) { - if (IS_NAN(ent->v->velocity[i])) + if (IS_NAN(ent->fields.server->velocity[i])) { - Con_Printf("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname)); - ent->v->velocity[i] = 0; + Con_Printf("Got a NaN velocity on %s\n", PRVM_GetString(ent->fields.server->classname)); + ent->fields.server->velocity[i] = 0; } - if (IS_NAN(ent->v->origin[i])) + if (IS_NAN(ent->fields.server->origin[i])) { - Con_Printf("Got a NaN origin on %s\n", PR_GetString(ent->v->classname)); - ent->v->origin[i] = 0; + Con_Printf("Got a NaN origin on %s\n", PRVM_GetString(ent->fields.server->classname)); + ent->fields.server->origin[i] = 0; } } // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster - wishspeed = DotProduct(ent->v->velocity, ent->v->velocity); + wishspeed = DotProduct(ent->fields.server->velocity, ent->fields.server->velocity); if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value) { wishspeed = sv_maxvelocity.value / sqrt(wishspeed); - ent->v->velocity[0] *= wishspeed; - ent->v->velocity[1] *= wishspeed; - ent->v->velocity[2] *= wishspeed; + ent->fields.server->velocity[0] *= wishspeed; + ent->fields.server->velocity[1] *= wishspeed; + ent->fields.server->velocity[2] *= wishspeed; } } +/* +============= +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. +============= +*/ +qboolean SV_RunThink (prvm_edict_t *ent) +{ + float thinktime; + + thinktime = ent->fields.server->nextthink; + if (thinktime <= 0 || thinktime > sv.time + sv.frametime) + return true; + + // don't let things stay in the past. + // it is possible to start that way by a trigger with a local time. + if (thinktime < sv.time) + thinktime = sv.time; + + ent->fields.server->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.server->think, "QC function self.think is missing"); + return !ent->priv.server->free; +} + /* ================== SV_Impact @@ -135,30 +194,78 @@ SV_Impact Two entities have touched, so run their touch functions ================== */ -void SV_Impact (edict_t *e1, edict_t *e2) +void SV_Impact (prvm_edict_t *e1, trace_t *trace) { int old_self, old_other; + prvm_edict_t *e2 = (prvm_edict_t *)trace->ent; + prvm_eval_t *val; - old_self = pr_global_struct->self; - old_other = pr_global_struct->other; + old_self = prog->globals.server->self; + old_other = prog->globals.server->other; - pr_global_struct->time = sv.time; - if (e1->v->touch && e1->v->solid != SOLID_NOT) + prog->globals.server->time = sv.time; + if (!e1->priv.server->free && !e2->priv.server->free && e1->fields.server->touch && e1->fields.server->solid != SOLID_NOT) { - pr_global_struct->self = EDICT_TO_PROG(e1); - pr_global_struct->other = EDICT_TO_PROG(e2); - PR_ExecuteProgram (e1->v->touch, "QC function self.touch is missing"); + 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->inwater; + prog->globals.server->trace_inopen = trace->inopen; + 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); + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + val->_float = trace->startsupercontents; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + val->_float = trace->hitsupercontents; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + val->_float = trace->hitq3surfaceflags; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + { + if (trace->hittexture) + { + char *s = VM_GetTempString(); + strlcpy(s, trace->hittexture->name, VM_STRINGTEMP_LENGTH); + val->string = PRVM_SetEngineString(s); + } + else + val->string = 0; + } + PRVM_ExecuteProgram (e1->fields.server->touch, "QC function self.touch is missing"); } - if (e2->v->touch && e2->v->solid != SOLID_NOT) + if (!e1->priv.server->free && !e2->priv.server->free && e2->fields.server->touch && e2->fields.server->solid != SOLID_NOT) { - pr_global_struct->self = EDICT_TO_PROG(e2); - pr_global_struct->other = EDICT_TO_PROG(e1); - PR_ExecuteProgram (e2->v->touch, "QC function self.touch is missing"); + 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.server->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); + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dpstartcontents))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitcontents))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphitq3surfaceflags))) + val->_float = 0; + if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename))) + val->string = 0; + PRVM_ExecuteProgram (e2->fields.server->touch, "QC function self.touch is missing"); } - pr_global_struct->self = old_self; - pr_global_struct->other = old_other; + prog->globals.server->self = old_self; + prog->globals.server->other = old_other; } @@ -197,41 +304,39 @@ Returns the clipflags if the velocity was modified (hit something solid) If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored ============ */ -// LordHavoc: increased from 5 to 20 -#define MAX_CLIP_PLANES 20 -int SV_FlyMove (edict_t *ent, float time, float *stepnormal) +// LordHavoc: increased from 5 to 32 +#define MAX_CLIP_PLANES 32 +int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal) { int blocked, bumpcount; - edict_t *hackongroundentity; 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; blocked = 0; - VectorCopy(ent->v->velocity, original_velocity); - VectorCopy(ent->v->velocity, primal_velocity); + VectorCopy(ent->fields.server->velocity, original_velocity); + VectorCopy(ent->fields.server->velocity, primal_velocity); numplanes = 0; time_left = time; - hackongroundentity = NULL; - for (bumpcount = 0;bumpcount < 8;bumpcount++) + for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++) { - if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2]) + if (!ent->fields.server->velocity[0] && !ent->fields.server->velocity[1] && !ent->fields.server->velocity[2]) break; - VectorMA(ent->v->origin, time_left, ent->v->velocity, end); - trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + VectorMA(ent->fields.server->origin, time_left, ent->fields.server->velocity, end); + trace = SV_Move(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent); #if 0 //if (trace.fraction < 0.002) { #if 1 vec3_t start; trace_t testtrace; - VectorCopy(ent->v->origin, start); + VectorCopy(ent->fields.server->origin, start); start[2] += 3;//0.03125; - VectorMA(ent->v->origin, time_left, ent->v->velocity, end); + VectorMA(ent->fields.server->origin, time_left, ent->fields.server->velocity, end); end[2] += 3;//0.03125; - testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); - if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->v->velocity) < DotProduct(testtrace.plane.normal, ent->v->velocity))) + testtrace = SV_Move(start, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent); + if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->fields.server->velocity) < DotProduct(testtrace.plane.normal, ent->fields.server->velocity))) { Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction); trace = testtrace; @@ -241,63 +346,61 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) //j = -1; for (i = 0;i < numplanes;i++) { - VectorCopy(ent->v->origin, start); - VectorMA(ent->v->origin, time_left, ent->v->velocity, end); + VectorCopy(ent->fields.server->origin, start); + VectorMA(ent->fields.server->origin, time_left, ent->fields.server->velocity, end); VectorMA(start, 3, planes[i], start); VectorMA(end, 3, planes[i], end); - testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + testtrace = SV_Move(start, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent); if (trace.fraction < testtrace.fraction) { trace = testtrace; - VectorCopy(start, ent->v->origin); + VectorCopy(start, ent->fields.server->origin); //j = i; } } //if (j >= 0) - // VectorAdd(ent->v->origin, planes[j], start); + // VectorAdd(ent->fields.server->origin, planes[j], start); #endif } #endif #if 0 - Con_Printf("entity %i bump %i: velocity %f %f %f trace %f", ent - sv.edicts, bumpcount, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2], trace.fraction); + Con_Printf("entity %i bump %i: velocity %f %f %f trace %f", ent - prog->edicts, bumpcount, ent->fields.server->velocity[0], ent->fields.server->velocity[1], ent->fields.server->velocity[2], trace.fraction); if (trace.fraction < 1) Con_Printf(" : %f %f %f", trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]); Con_Print("\n"); #endif - /* - if (trace.startsolid) + if (trace.bmodelstartsolid) { - // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world) + // LordHavoc: note: this code is what makes entities stick in place + // if embedded in world only (you can walk through other objects if + // stuck) // entity is trapped in another solid - VectorClear(ent->v->velocity); + VectorClear(ent->fields.server->velocity); return 3; } - */ // break if it moved the entire distance if (trace.fraction == 1) { - VectorCopy(trace.endpos, ent->v->origin); + VectorCopy(trace.endpos, ent->fields.server->origin); break; } if (!trace.ent) - Host_Error("SV_FlyMove: !trace.ent"); - - if ((int) ent->v->flags & FL_ONGROUND) { - if (ent->v->groundentity == EDICT_TO_PROG(trace.ent)) - impact = false; - else - { - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - impact = true; - } + Con_Printf ("SV_FlyMove: !trace.ent"); + trace.ent = prog->edicts; } + + if (((int) ent->fields.server->flags & FL_ONGROUND) && ent->fields.server->groundentity == PRVM_EDICT_TO_PROG(trace.ent)) + impact = false; else + { + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; impact = true; + } if (trace.plane.normal[2]) { @@ -305,11 +408,9 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) { // floor blocked |= 1; - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; + ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); } - else if (trace.fraction < 0.001) - hackongroundentity = trace.ent; } else { @@ -323,18 +424,18 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) if (trace.fraction >= 0.001) { // actually covered some distance - VectorCopy(trace.endpos, ent->v->origin); - VectorCopy(ent->v->velocity, original_velocity); + VectorCopy(trace.endpos, ent->fields.server->origin); + VectorCopy(ent->fields.server->velocity, original_velocity); numplanes = 0; } // run the impact function if (impact) { - SV_Impact(ent, trace.ent); + SV_Impact(ent, &trace); // break if removed by the impact function - if (ent->e->free) + if (ent->priv.server->free) break; } @@ -344,7 +445,7 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen - VectorClear(ent->v->velocity); + VectorClear(ent->fields.server->velocity); blocked = 3; break; } @@ -355,7 +456,7 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) break; if (i < numplanes) { - VectorAdd(ent->v->velocity, trace.plane.normal, ent->v->velocity); + VectorAdd(ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity); continue; } */ @@ -364,7 +465,7 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) numplanes++; if (sv_newflymove.integer) - ClipVelocity(ent->v->velocity, trace.plane.normal, ent->v->velocity, 1); + ClipVelocity(ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1); else { // modify original_velocity so it parallels all of the clip planes @@ -387,93 +488,64 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal) if (i != numplanes) { // go along this plane - VectorCopy(new_velocity, ent->v->velocity); + VectorCopy(new_velocity, ent->fields.server->velocity); } else { // go along the crease if (numplanes != 2) { - VectorClear(ent->v->velocity); + VectorClear(ent->fields.server->velocity); blocked = 7; break; } CrossProduct(planes[0], planes[1], dir); // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners VectorNormalize(dir); - d = DotProduct(dir, ent->v->velocity); - VectorScale(dir, d, ent->v->velocity); + d = DotProduct(dir, ent->fields.server->velocity); + VectorScale(dir, d, ent->fields.server->velocity); } } - // if original velocity is against the original velocity, + // if current velocity is against the original velocity, // stop dead to avoid tiny occilations in sloping corners - if (DotProduct(ent->v->velocity, primal_velocity) <= 0) + if (DotProduct(ent->fields.server->velocity, primal_velocity) <= 0) { - VectorClear(ent->v->velocity); + VectorClear(ent->fields.server->velocity); break; } } - //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - sv.edicts, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]); + //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - prog->edicts, blocked, ent->fields.server->velocity[0], ent->fields.server->velocity[1], ent->fields.server->velocity[2]); - /* - // FIXME: this doesn't work well at all, find another solution - // if player is ontop of a non-onground floor and made no progress, - // set onground anyway (this tends to happen if standing in a wedge) - if (bumpcount == 8 && hackongroundentity) - { - blocked |= 1; - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(hackongroundentity); - } - */ - /* if ((blocked & 1) == 0 && bumpcount > 1) { // LordHavoc: fix the 'fall to your death in a wedge corner' glitch // flag ONGROUND if there's ground under it - trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); + trace = SV_Move(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent); } */ return blocked; } -int SV_SetOnGround (edict_t *ent) -{ - vec3_t end; - trace_t trace; - if ((int)ent->v->flags & FL_ONGROUND) - return 1; - VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1); - trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent); - if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7) - { - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - return 1; - } - return 0; -} - /* ============ SV_AddGravity ============ */ -void SV_AddGravity (edict_t *ent) +void SV_AddGravity (prvm_edict_t *ent) { float ent_gravity; - eval_t *val; + prvm_eval_t *val; - val = GETEDICTFIELDVALUE(ent, eval_gravity); + val = PRVM_GETEDICTFIELDVALUE(ent, eval_gravity); if (val!=0 && val->_float) ent_gravity = val->_float; else ent_gravity = 1.0; - ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime; + ent->fields.server->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime; } @@ -492,28 +564,28 @@ SV_PushEntity Does not change the entities velocity at all ============ */ -trace_t SV_PushEntity (edict_t *ent, vec3_t push) +trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push) { int type; trace_t trace; vec3_t end; - VectorAdd (ent->v->origin, push, end); + VectorAdd (ent->fields.server->origin, push, end); - if (ent->v->movetype == MOVETYPE_FLYMISSILE) + if (ent->fields.server->movetype == MOVETYPE_FLYMISSILE) type = MOVE_MISSILE; - else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT) + else if (ent->fields.server->solid == SOLID_TRIGGER || ent->fields.server->solid == SOLID_NOT) type = MOVE_NOMONSTERS; // only clip against bmodels else type = MOVE_NORMAL; - trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent); + trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent); - VectorCopy (trace.endpos, ent->v->origin); + VectorCopy (trace.endpos, ent->fields.server->origin); SV_LinkEdict (ent, true); - if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent))) - SV_Impact (ent, trace.ent); + if (trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent))) + SV_Impact (ent, &trace); return trace; } @@ -524,26 +596,24 @@ SV_PushMove ============ */ -trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); -void SV_PushMove (edict_t *pusher, float movetime) +void SV_PushMove (prvm_edict_t *pusher, float movetime) { int i, e, index; - edict_t *check, *ed; float savesolid, movetime2, pushltime; - vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2; + vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org; int num_moved; int numcheckentities; - static edict_t *checkentities[MAX_EDICTS]; + static prvm_edict_t *checkentities[MAX_EDICTS]; model_t *pushermodel; trace_t trace; - if (!pusher->v->velocity[0] && !pusher->v->velocity[1] && !pusher->v->velocity[2] && !pusher->v->avelocity[0] && !pusher->v->avelocity[1] && !pusher->v->avelocity[2]) + if (!pusher->fields.server->velocity[0] && !pusher->fields.server->velocity[1] && !pusher->fields.server->velocity[2] && !pusher->fields.server->avelocity[0] && !pusher->fields.server->avelocity[1] && !pusher->fields.server->avelocity[2]) { - pusher->v->ltime += movetime; + pusher->fields.server->ltime += movetime; return; } - switch ((int) pusher->v->solid) + switch ((int) pusher->fields.server->solid) { // LordHavoc: valid pusher types case SOLID_BSP: @@ -554,42 +624,42 @@ void SV_PushMove (edict_t *pusher, float movetime) // LordHavoc: no collisions case SOLID_NOT: case SOLID_TRIGGER: - VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin); - VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles); - pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0)); - pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0)); - pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0)); - pusher->v->ltime += movetime; + VectorMA (pusher->fields.server->origin, movetime, pusher->fields.server->velocity, pusher->fields.server->origin); + VectorMA (pusher->fields.server->angles, movetime, pusher->fields.server->avelocity, pusher->fields.server->angles); + pusher->fields.server->angles[0] -= 360.0 * floor(pusher->fields.server->angles[0] * (1.0 / 360.0)); + pusher->fields.server->angles[1] -= 360.0 * floor(pusher->fields.server->angles[1] * (1.0 / 360.0)); + pusher->fields.server->angles[2] -= 360.0 * floor(pusher->fields.server->angles[2] * (1.0 / 360.0)); + pusher->fields.server->ltime += movetime; SV_LinkEdict (pusher, false); return; default: - Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid); + Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.server->solid); return; } - index = (int) pusher->v->modelindex; + index = (int) pusher->fields.server->modelindex; if (index < 1 || index >= MAX_MODELS) { - Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex); + Con_Printf("SV_PushMove: entity #%i has an invalid modelindex %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.server->modelindex); return; } pushermodel = sv.models[index]; movetime2 = movetime; - VectorScale(pusher->v->velocity, movetime2, move1); - VectorScale(pusher->v->avelocity, movetime2, moveangle); + VectorScale(pusher->fields.server->velocity, movetime2, move1); + VectorScale(pusher->fields.server->avelocity, movetime2, moveangle); if (moveangle[0] || moveangle[2]) { for (i = 0;i < 3;i++) { if (move1[i] > 0) { - mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->rotatedmins[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1; } else { - mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->rotatedmaxs[i] + pusher->fields.server->origin[i] + 1; } } } @@ -599,13 +669,13 @@ void SV_PushMove (edict_t *pusher, float movetime) { if (move1[i] > 0) { - mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->yawmins[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1; } else { - mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->yawmaxs[i] + pusher->fields.server->origin[i] + 1; } } } @@ -615,13 +685,13 @@ void SV_PushMove (edict_t *pusher, float movetime) { if (move1[i] > 0) { - mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->normalmins[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->fields.server->origin[i] + 1; } else { - mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1; - maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1; + mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->fields.server->origin[i] - 1; + maxs[i] = pushermodel->normalmaxs[i] + pusher->fields.server->origin[i] + 1; } } } @@ -629,41 +699,49 @@ void SV_PushMove (edict_t *pusher, float movetime) VectorNegate (moveangle, a); AngleVectorsFLU (a, forward, left, up); - VectorCopy (pusher->v->origin, pushorig); - VectorCopy (pusher->v->angles, pushang); - pushltime = pusher->v->ltime; + VectorCopy (pusher->fields.server->origin, pushorig); + VectorCopy (pusher->fields.server->angles, pushang); + pushltime = pusher->fields.server->ltime; -// move the pusher to it's final position +// move the pusher to its final position - VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin); - VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles); - pusher->v->ltime += movetime; + VectorMA (pusher->fields.server->origin, movetime, pusher->fields.server->velocity, pusher->fields.server->origin); + VectorMA (pusher->fields.server->angles, movetime, pusher->fields.server->avelocity, pusher->fields.server->angles); + pusher->fields.server->ltime += movetime; SV_LinkEdict (pusher, false); - savesolid = pusher->v->solid; + savesolid = pusher->fields.server->solid; // see if any solid entities are inside the final position num_moved = 0; numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities); - for (e = 1;e < numcheckentities;e++) + for (e = 0;e < numcheckentities;e++) { - check = checkentities[e]; - if (check->v->movetype == MOVETYPE_PUSH - || check->v->movetype == MOVETYPE_NONE - || check->v->movetype == MOVETYPE_FOLLOW - || check->v->movetype == MOVETYPE_NOCLIP - || check->v->movetype == MOVETYPE_FAKEPUSH) + prvm_edict_t *check = checkentities[e]; + if (check->fields.server->movetype == MOVETYPE_NONE + || check->fields.server->movetype == MOVETYPE_PUSH + || check->fields.server->movetype == MOVETYPE_FOLLOW + || check->fields.server->movetype == MOVETYPE_NOCLIP + || check->fields.server->movetype == MOVETYPE_FAKEPUSH) continue; // if the entity is standing on the pusher, it will definitely be moved - if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher)) - if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) + if (!(((int)check->fields.server->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.server->groundentity) == pusher)) + { + // if the entity is not inside the pusher's final position, leave it alone + if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) continue; + // remove the onground flag for non-players + if (check->fields.server->movetype != MOVETYPE_WALK) + check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND; + } - if (forward[0] != 1) // quick way to check if any rotation is used + + if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used { - VectorSubtract (check->v->origin, pusher->v->origin, org); + vec3_t org2; + VectorSubtract (check->fields.server->origin, pusher->fields.server->origin, org); org2[0] = DotProduct (org, forward); org2[1] = DotProduct (org, left); org2[2] = DotProduct (org, up); @@ -673,72 +751,81 @@ void SV_PushMove (edict_t *pusher, float movetime) else VectorCopy (move1, move); - // remove the onground flag for non-players - if (check->v->movetype != MOVETYPE_WALK) - check->v->flags = (int)check->v->flags & ~FL_ONGROUND; - - VectorCopy (check->v->origin, check->e->moved_from); - VectorCopy (check->v->angles, check->e->moved_fromangles); + VectorCopy (check->fields.server->origin, check->priv.server->moved_from); + VectorCopy (check->fields.server->angles, check->priv.server->moved_fromangles); sv.moved_edicts[num_moved++] = check; // try moving the contacted entity - pusher->v->solid = SOLID_NOT; + pusher->fields.server->solid = SOLID_NOT; trace = SV_PushEntity (check, move); // FIXME: turn players specially - check->v->angles[1] += trace.fraction * moveangle[1]; - pusher->v->solid = savesolid; // was SOLID_BSP + check->fields.server->angles[1] += trace.fraction * moveangle[1]; + pusher->fields.server->solid = savesolid; // was SOLID_BSP // if it is still inside the pusher, block - if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { // try moving the contacted entity a tiny bit further to account for precision errors - pusher->v->solid = SOLID_NOT; - VectorScale(move, 0.1, move); - SV_PushEntity (check, move); - pusher->v->solid = savesolid; - if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid) + vec3_t move2; + pusher->fields.server->solid = SOLID_NOT; + VectorScale(move, 1.1, move2); + VectorCopy (check->priv.server->moved_from, check->fields.server->origin); + VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); + SV_PushEntity (check, move2); + pusher->fields.server->solid = savesolid; + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { - // still inside pusher, so it's really blocked - - // fail the move - if (check->v->mins[0] == check->v->maxs[0]) - continue; - if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER) + // try moving the contacted entity a tiny bit less to account for precision errors + pusher->fields.server->solid = SOLID_NOT; + VectorScale(move, 0.9, move2); + VectorCopy (check->priv.server->moved_from, check->fields.server->origin); + VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles); + SV_PushEntity (check, move2); + pusher->fields.server->solid = savesolid; + if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid) { - // corpse - check->v->mins[0] = check->v->mins[1] = 0; - VectorCopy (check->v->mins, check->v->maxs); - continue; - } + // still inside pusher, so it's really blocked - VectorCopy (pushorig, pusher->v->origin); - VectorCopy (pushang, pusher->v->angles); - pusher->v->ltime = pushltime; - SV_LinkEdict (pusher, false); + // fail the move + if (check->fields.server->mins[0] == check->fields.server->maxs[0]) + continue; + if (check->fields.server->solid == SOLID_NOT || check->fields.server->solid == SOLID_TRIGGER) + { + // corpse + check->fields.server->mins[0] = check->fields.server->mins[1] = 0; + VectorCopy (check->fields.server->mins, check->fields.server->maxs); + continue; + } - // move back any entities we already moved - for (i = 0;i < num_moved;i++) - { - ed = sv.moved_edicts[i]; - VectorCopy (ed->e->moved_from, ed->v->origin); - VectorCopy (ed->e->moved_fromangles, ed->v->angles); - SV_LinkEdict (ed, false); - } + VectorCopy (pushorig, pusher->fields.server->origin); + VectorCopy (pushang, pusher->fields.server->angles); + pusher->fields.server->ltime = pushltime; + SV_LinkEdict (pusher, false); - // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone - if (pusher->v->blocked) - { - pr_global_struct->self = EDICT_TO_PROG(pusher); - pr_global_struct->other = EDICT_TO_PROG(check); - PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing"); + // move back any entities we already moved + for (i = 0;i < num_moved;i++) + { + prvm_edict_t *ed = sv.moved_edicts[i]; + VectorCopy (ed->priv.server->moved_from, ed->fields.server->origin); + VectorCopy (ed->priv.server->moved_fromangles, ed->fields.server->angles); + SV_LinkEdict (ed, false); + } + + // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone + if (pusher->fields.server->blocked) + { + prog->globals.server->self = PRVM_EDICT_TO_PROG(pusher); + prog->globals.server->other = PRVM_EDICT_TO_PROG(check); + PRVM_ExecuteProgram (pusher->fields.server->blocked, "QC function self.blocked is missing"); + } + break; } - break; } } } - pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0)); - pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0)); - pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0)); + pusher->fields.server->angles[0] -= 360.0 * floor(pusher->fields.server->angles[0] * (1.0 / 360.0)); + pusher->fields.server->angles[1] -= 360.0 * floor(pusher->fields.server->angles[1] * (1.0 / 360.0)); + pusher->fields.server->angles[2] -= 360.0 * floor(pusher->fields.server->angles[2] * (1.0 / 360.0)); } /* @@ -747,16 +834,16 @@ SV_Physics_Pusher ================ */ -void SV_Physics_Pusher (edict_t *ent) +void SV_Physics_Pusher (prvm_edict_t *ent) { float thinktime, oldltime, movetime; - oldltime = ent->v->ltime; + oldltime = ent->fields.server->ltime; - thinktime = ent->v->nextthink; - if (thinktime < ent->v->ltime + sv.frametime) + thinktime = ent->fields.server->nextthink; + if (thinktime < ent->fields.server->ltime + sv.frametime) { - movetime = thinktime - ent->v->ltime; + movetime = thinktime - ent->fields.server->ltime; if (movetime < 0) movetime = 0; } @@ -764,16 +851,16 @@ void SV_Physics_Pusher (edict_t *ent) movetime = sv.frametime; if (movetime) - // advances ent->v->ltime if not blocked + // advances ent->fields.server->ltime if not blocked SV_PushMove (ent, movetime); - if (thinktime > oldltime && thinktime <= ent->v->ltime) + if (thinktime > oldltime && thinktime <= ent->fields.server->ltime) { - ent->v->nextthink = 0; - pr_global_struct->time = sv.time; - pr_global_struct->self = EDICT_TO_PROG(ent); - pr_global_struct->other = EDICT_TO_PROG(sv.edicts); - PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); + ent->fields.server->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.server->think, "QC function self.think is missing"); } } @@ -794,43 +881,73 @@ This is a big hack to try and fix the rare case of getting stuck in the world clipping hull. ============= */ -void SV_CheckStuck (edict_t *ent) +void SV_CheckStuck (prvm_edict_t *ent) { int i, j, z; vec3_t org; if (!SV_TestEntityPosition(ent)) { - VectorCopy (ent->v->origin, ent->v->oldorigin); + VectorCopy (ent->fields.server->origin, ent->fields.server->oldorigin); return; } - VectorCopy (ent->v->origin, org); - VectorCopy (ent->v->oldorigin, ent->v->origin); + VectorCopy (ent->fields.server->origin, org); + VectorCopy (ent->fields.server->oldorigin, ent->fields.server->origin); if (!SV_TestEntityPosition(ent)) { - Con_DPrint("Unstuck.\n"); + Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); SV_LinkEdict (ent, true); return; } - for (z=0 ; z< 18 ; z++) + for (z=-1 ; z< 18 ; z++) for (i=-1 ; i <= 1 ; i++) for (j=-1 ; j <= 1 ; j++) { - ent->v->origin[0] = org[0] + i; - ent->v->origin[1] = org[1] + j; - ent->v->origin[2] = org[2] + z; + ent->fields.server->origin[0] = org[0] + i; + ent->fields.server->origin[1] = org[1] + j; + ent->fields.server->origin[2] = org[2] + z; if (!SV_TestEntityPosition(ent)) { - Con_DPrint("Unstuck.\n"); + Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), (float)i, (float)j, (float)z); SV_LinkEdict (ent, true); return; } } - VectorCopy (org, ent->v->origin); - Con_DPrint("player is stuck.\n"); + VectorCopy (org, ent->fields.server->origin); + Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); +} + +static void SV_UnstickEntity (prvm_edict_t *ent) +{ + int i, j, z; + vec3_t org; + + // if not stuck in a bmodel, just return + if (!SV_TestEntityPosition(ent)) + return; + + VectorCopy (ent->fields.server->origin, org); + + for (z=-1 ; z< 18 ; z += 6) + for (i=-1 ; i <= 1 ; i++) + for (j=-1 ; j <= 1 ; j++) + { + ent->fields.server->origin[0] = org[0] + i; + ent->fields.server->origin[1] = org[1] + j; + ent->fields.server->origin[2] = org[2] + z; + if (!SV_TestEntityPosition(ent)) + { + Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname), (float)i, (float)j, (float)z); + SV_LinkEdict (ent, true); + return; + } + } + + VectorCopy (org, ent->fields.server->origin); + Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname)); } @@ -839,35 +956,33 @@ void SV_CheckStuck (edict_t *ent) SV_CheckWater ============= */ -qboolean SV_CheckWater (edict_t *ent) +qboolean SV_CheckWater (prvm_edict_t *ent) { int cont; vec3_t point; - point[0] = ent->v->origin[0]; - point[1] = ent->v->origin[1]; - point[2] = ent->v->origin[2] + ent->v->mins[2] + 1; + point[0] = ent->fields.server->origin[0]; + point[1] = ent->fields.server->origin[1]; + point[2] = ent->fields.server->origin[2] + ent->fields.server->mins[2] + 1; - ent->v->waterlevel = 0; - ent->v->watertype = CONTENTS_EMPTY; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) + ent->fields.server->waterlevel = 0; + ent->fields.server->watertype = CONTENTS_EMPTY; + cont = SV_PointSuperContents(point); + if (cont & (SUPERCONTENTS_LIQUIDSMASK)) { - ent->v->watertype = cont; - ent->v->waterlevel = 1; - point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) + ent->fields.server->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont); + ent->fields.server->waterlevel = 1; + point[2] = ent->fields.server->origin[2] + (ent->fields.server->mins[2] + ent->fields.server->maxs[2])*0.5; + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) { - ent->v->waterlevel = 2; - point[2] = ent->v->origin[2] + ent->v->view_ofs[2]; - cont = SV_PointQ1Contents(point); - if (cont <= CONTENTS_WATER) - ent->v->waterlevel = 3; + ent->fields.server->waterlevel = 2; + point[2] = ent->fields.server->origin[2] + ent->fields.server->view_ofs[2]; + if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK)) + ent->fields.server->waterlevel = 3; } } - return ent->v->waterlevel > 1; + return ent->fields.server->waterlevel > 1; } /* @@ -876,20 +991,20 @@ SV_WallFriction ============ */ -void SV_WallFriction (edict_t *ent, float *stepnormal) +void SV_WallFriction (prvm_edict_t *ent, float *stepnormal) { float d, i; vec3_t forward, into, side; - AngleVectors (ent->v->v_angle, forward, NULL, NULL); + AngleVectors (ent->fields.server->v_angle, forward, NULL, NULL); if ((d = DotProduct (stepnormal, forward) + 0.5) < 0) { // cut the tangential velocity - i = DotProduct (stepnormal, ent->v->velocity); + i = DotProduct (stepnormal, ent->fields.server->velocity); VectorScale (stepnormal, i, into); - VectorSubtract (ent->v->velocity, into, side); - ent->v->velocity[0] = side[0] * (1 + d); - ent->v->velocity[1] = side[1] * (1 + d); + VectorSubtract (ent->fields.server->velocity, into, side); + ent->fields.server->velocity[0] = side[0] * (1 + d); + ent->fields.server->velocity[1] = side[1] * (1 + d); } } @@ -905,12 +1020,12 @@ Try fixing by pushing one pixel in each direction. This is a hack, but in the interest of good gameplay... ====================== */ -int SV_TryUnstick (edict_t *ent, vec3_t oldvel) +int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel) { int i, clip; vec3_t oldorg, dir; - VectorCopy (ent->v->origin, oldorg); + VectorCopy (ent->fields.server->origin, oldorg); VectorClear (dir); for (i=0 ; i<8 ; i++) @@ -931,24 +1046,24 @@ int SV_TryUnstick (edict_t *ent, vec3_t oldvel) SV_PushEntity (ent, dir); // retry the original move - ent->v->velocity[0] = oldvel[0]; - ent->v->velocity[1] = oldvel[1]; - ent->v->velocity[2] = 0; + ent->fields.server->velocity[0] = oldvel[0]; + ent->fields.server->velocity[1] = oldvel[1]; + ent->fields.server->velocity[2] = 0; clip = SV_FlyMove (ent, 0.1, NULL); - if (fabs(oldorg[1] - ent->v->origin[1]) > 4 - || fabs(oldorg[0] - ent->v->origin[0]) > 4) + if (fabs(oldorg[1] - ent->fields.server->origin[1]) > 4 + || fabs(oldorg[0] - ent->fields.server->origin[0]) > 4) { Con_DPrint("TryUnstick - success.\n"); return clip; } // go back to the original pos and try again - VectorCopy (oldorg, ent->v->origin); + VectorCopy (oldorg, ent->fields.server->origin); } // still not moving - VectorClear (ent->v->velocity); + VectorClear (ent->fields.server->velocity); Con_DPrint("TryUnstick - failure.\n"); return 7; } @@ -960,7 +1075,7 @@ SV_WalkMove Only used by players ====================== */ -void SV_WalkMove (edict_t *ent) +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; @@ -969,79 +1084,78 @@ void SV_WalkMove (edict_t *ent) SV_CheckVelocity(ent); // do a regular slide move unless it looks like you ran into a step - oldonground = (int)ent->v->flags & FL_ONGROUND; - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + oldonground = (int)ent->fields.server->flags & FL_ONGROUND; + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; - VectorCopy (ent->v->origin, start_origin); - VectorCopy (ent->v->velocity, start_velocity); + VectorCopy (ent->fields.server->origin, start_origin); + VectorCopy (ent->fields.server->velocity, start_velocity); clip = SV_FlyMove (ent, sv.frametime, NULL); - SV_SetOnGround (ent); SV_CheckVelocity(ent); - VectorCopy(ent->v->origin, originalmove_origin); - VectorCopy(ent->v->velocity, originalmove_velocity); + VectorCopy(ent->fields.server->origin, originalmove_origin); + VectorCopy(ent->fields.server->velocity, originalmove_velocity); originalmove_clip = clip; - originalmove_flags = (int)ent->v->flags; - originalmove_groundentity = ent->v->groundentity; + originalmove_flags = (int)ent->fields.server->flags; + originalmove_groundentity = ent->fields.server->groundentity; - if ((int)ent->v->flags & FL_WATERJUMP) + if ((int)ent->fields.server->flags & FL_WATERJUMP) return; if (sv_nostep.integer) 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->v->movetype != MOVETYPE_FLY) + + if (ent->fields.server->movetype != MOVETYPE_FLY) { // return if gibbed by a trigger - if (ent->v->movetype != MOVETYPE_WALK) + if (ent->fields.server->movetype != MOVETYPE_WALK) return; - + // only step up while jumping if that is enabled if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer)) - if (!oldonground && ent->v->waterlevel == 0) + if (!oldonground && ent->fields.server->waterlevel == 0) return; } - + // try moving up and forward to go up a step // back to start pos - VectorCopy (start_origin, ent->v->origin); - VectorCopy (start_velocity, ent->v->velocity); - + VectorCopy (start_origin, ent->fields.server->origin); + VectorCopy (start_velocity, ent->fields.server->velocity); + // move up VectorClear (upmove); upmove[2] = sv_stepheight.value; // FIXME: don't link? SV_PushEntity(ent, upmove); - + // move forward - ent->v->velocity[2] = 0; + ent->fields.server->velocity[2] = 0; clip = SV_FlyMove (ent, sv.frametime, stepnormal); - ent->v->velocity[2] += start_velocity[2]; - + ent->fields.server->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->v->origin[1]) < 0.03125 - && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125) + && fabs(originalmove_origin[1] - ent->fields.server->origin[1]) < 0.03125 + && fabs(originalmove_origin[0] - ent->fields.server->origin[0]) < 0.03125) { //Con_Printf("wall\n"); // stepping up didn't make any progress, revert to original move - VectorCopy(originalmove_origin, ent->v->origin); - VectorCopy(originalmove_velocity, ent->v->velocity); + VectorCopy(originalmove_origin, ent->fields.server->origin); + VectorCopy(originalmove_velocity, ent->fields.server->velocity); //clip = originalmove_clip; - ent->v->flags = originalmove_flags; - ent->v->groundentity = originalmove_groundentity; + ent->fields.server->flags = originalmove_flags; + ent->fields.server->groundentity = originalmove_groundentity; // now try to unstick if needed //clip = SV_TryUnstick (ent, oldvel); return; @@ -1054,7 +1168,7 @@ void SV_WalkMove (edict_t *ent) 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 (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND))) + else if (!(sv_gameplayfix_stepdown.integer && ent->fields.server->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->fields.server->flags & FL_ONGROUND))) return; // move down @@ -1065,13 +1179,17 @@ void SV_WalkMove (edict_t *ent) 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) +#if 0 // LordHavoc: disabled this check so you can walk on monsters/players - //if (ent->v->solid == SOLID_BSP) + //if (ent->fields.server->solid == SOLID_BSP) { //Con_Printf("onground\n"); - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(downtrace.ent); + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; + ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(downtrace.ent); } +#endif } else { @@ -1079,14 +1197,13 @@ void SV_WalkMove (edict_t *ent) // if the push down didn't end up on good ground, use the move without // the step up. This happens near wall / slope combinations, and can // cause the player to hop up higher on a slope too steep to climb - VectorCopy(originalmove_origin, ent->v->origin); - VectorCopy(originalmove_velocity, ent->v->velocity); + VectorCopy(originalmove_origin, ent->fields.server->origin); + VectorCopy(originalmove_velocity, ent->fields.server->velocity); //clip = originalmove_clip; - ent->v->flags = originalmove_flags; - ent->v->groundentity = originalmove_groundentity; + ent->fields.server->flags = originalmove_flags; + ent->fields.server->groundentity = originalmove_groundentity; } - SV_SetOnGround (ent); SV_CheckVelocity(ent); } @@ -1099,37 +1216,40 @@ SV_Physics_Follow Entities that are "stuck" to another entity ============= */ -void SV_Physics_Follow (edict_t *ent) +void SV_Physics_Follow (prvm_edict_t *ent) { vec3_t vf, vr, vu, angles, v; - edict_t *e; + prvm_edict_t *e; // regular thinking + if (!SV_RunThink (ent)) + return; + // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects - e = PROG_TO_EDICT(ent->v->aiment); - if (e->v->angles[0] == ent->v->punchangle[0] && e->v->angles[1] == ent->v->punchangle[1] && e->v->angles[2] == ent->v->punchangle[2]) + e = PRVM_PROG_TO_EDICT(ent->fields.server->aiment); + if (e->fields.server->angles[0] == ent->fields.server->punchangle[0] && e->fields.server->angles[1] == ent->fields.server->punchangle[1] && e->fields.server->angles[2] == ent->fields.server->punchangle[2]) { // quick case for no rotation - VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin); + VectorAdd(e->fields.server->origin, ent->fields.server->view_ofs, ent->fields.server->origin); } else { - angles[0] = -ent->v->punchangle[0]; - angles[1] = ent->v->punchangle[1]; - angles[2] = ent->v->punchangle[2]; + angles[0] = -ent->fields.server->punchangle[0]; + angles[1] = ent->fields.server->punchangle[1]; + angles[2] = ent->fields.server->punchangle[2]; AngleVectors (angles, vf, vr, vu); - v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0]; - v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1]; - v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2]; - angles[0] = -e->v->angles[0]; - angles[1] = e->v->angles[1]; - angles[2] = e->v->angles[2]; + v[0] = ent->fields.server->view_ofs[0] * vf[0] + ent->fields.server->view_ofs[1] * vr[0] + ent->fields.server->view_ofs[2] * vu[0]; + v[1] = ent->fields.server->view_ofs[0] * vf[1] + ent->fields.server->view_ofs[1] * vr[1] + ent->fields.server->view_ofs[2] * vu[1]; + v[2] = ent->fields.server->view_ofs[0] * vf[2] + ent->fields.server->view_ofs[1] * vr[2] + ent->fields.server->view_ofs[2] * vu[2]; + angles[0] = -e->fields.server->angles[0]; + angles[1] = e->fields.server->angles[1]; + angles[2] = e->fields.server->angles[2]; AngleVectors (angles, vf, vr, vu); - ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0]; - ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1]; - ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2]; + ent->fields.server->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->fields.server->origin[0]; + ent->fields.server->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->fields.server->origin[1]; + ent->fields.server->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->fields.server->origin[2]; } - VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles); + VectorAdd (e->fields.server->angles, ent->fields.server->v_angle, ent->fields.server->angles); SV_LinkEdict (ent, true); } @@ -1147,31 +1267,31 @@ SV_CheckWaterTransition ============= */ -void SV_CheckWaterTransition (edict_t *ent) +void SV_CheckWaterTransition (prvm_edict_t *ent) { int cont; - cont = SV_PointQ1Contents(ent->v->origin); - if (!ent->v->watertype) + cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(ent->fields.server->origin)); + if (!ent->fields.server->watertype) { // just spawned here - ent->v->watertype = cont; - ent->v->waterlevel = 1; + ent->fields.server->watertype = cont; + ent->fields.server->waterlevel = 1; return; } // check if the entity crossed into or out of water - if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)) - SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1); + if (sv_sound_watersplash.string && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))) + SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1); if (cont <= CONTENTS_WATER) { - ent->v->watertype = cont; - ent->v->waterlevel = 1; + ent->fields.server->watertype = cont; + ent->fields.server->waterlevel = 1; } else { - ent->v->watertype = CONTENTS_EMPTY; - ent->v->waterlevel = 0; + ent->fields.server->watertype = CONTENTS_EMPTY; + ent->fields.server->waterlevel = 0; } } @@ -1182,106 +1302,109 @@ SV_Physics_Toss Toss, bounce, and fly movement. When onground, do nothing. ============= */ -void SV_Physics_Toss (edict_t *ent) +void SV_Physics_Toss (prvm_edict_t *ent) { trace_t trace; vec3_t move; - edict_t *groundentity; - - // don't stick to ground if onground and moving upward - if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND)) - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; // if onground, return without moving - if ((int)ent->v->flags & FL_ONGROUND) + if ((int)ent->fields.server->flags & FL_ONGROUND) { - if (!sv_gameplayfix_noairborncorpse.integer) - return; - if (ent->v->groundentity == 0) - return; - // if ent was supported by a brush model on previous frame, - // and groundentity is now freed, set groundentity to 0 (floating) - groundentity = PROG_TO_EDICT(ent->v->groundentity); - if (groundentity->v->solid == SOLID_BSP) - { - ent->e->suspendedinairflag = true; - return; - } - else if (ent->e->suspendedinairflag && groundentity->e->free) + // don't stick to ground if onground and moving upward + if (ent->fields.server->velocity[2] >= (1.0 / 32.0)) + ent->fields.server->flags -= FL_ONGROUND; + else { - // leave it suspended in the air - ent->v->groundentity = 0; - ent->e->suspendedinairflag = false; - return; + prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity); + if (ground->fields.server->solid == SOLID_BSP || !sv_gameplayfix_noairborncorpse.integer) + return; + // if ent was supported by a brush model on previous frame, + // and groundentity is now freed, set groundentity to 0 (floating) + if (ent->priv.server->suspendedinairflag && ground->priv.server->free) + { + // leave it suspended in the air + ent->fields.server->groundentity = 0; + return; + } } } - ent->e->suspendedinairflag = false; + ent->priv.server->suspendedinairflag = false; SV_CheckVelocity (ent); // add gravity - if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE) + if (ent->fields.server->movetype == MOVETYPE_TOSS || ent->fields.server->movetype == MOVETYPE_BOUNCE) SV_AddGravity (ent); // move angles - VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); + VectorMA (ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles); // move origin - VectorScale (ent->v->velocity, sv.frametime, move); + VectorScale (ent->fields.server->velocity, sv.frametime, move); trace = SV_PushEntity (ent, move); - if (ent->e->free) + if (ent->priv.server->free) return; + if (trace.bmodelstartsolid) + { + // try to unstick the entity + SV_UnstickEntity(ent); + trace = SV_PushEntity (ent, move); + if (ent->priv.server->free) + return; + } if (trace.fraction < 1) { - if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE) + if (ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE) { - ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0); - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 2.0); + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; } - else if (ent->v->movetype == MOVETYPE_BOUNCE) + else if (ent->fields.server->movetype == MOVETYPE_BOUNCE) { float d; - ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5); + ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.5); // LordHavoc: fixed grenades not bouncing when fired down a slope if (sv_gameplayfix_grenadebouncedownslopes.integer) { - d = DotProduct(trace.plane.normal, ent->v->velocity); + d = DotProduct(trace.plane.normal, ent->fields.server->velocity); if (trace.plane.normal[2] > 0.7 && fabs(d) < 60) { - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - VectorClear (ent->v->velocity); - VectorClear (ent->v->avelocity); + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; + ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + VectorClear (ent->fields.server->velocity); + VectorClear (ent->fields.server->avelocity); } else - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; } else { - if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60) + if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < 60) { - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - VectorClear (ent->v->velocity); - VectorClear (ent->v->avelocity); + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; + ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + VectorClear (ent->fields.server->velocity); + VectorClear (ent->fields.server->avelocity); } else - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; } } else { - ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0); + ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.0); if (trace.plane.normal[2] > 0.7) { - ent->v->flags = (int)ent->v->flags | FL_ONGROUND; - ent->v->groundentity = EDICT_TO_PROG(trace.ent); - VectorClear (ent->v->velocity); - VectorClear (ent->v->avelocity); + ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND; + ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent); + if (((prvm_edict_t *)trace.ent)->fields.server->solid == SOLID_BSP) + ent->priv.server->suspendedinairflag = true; + VectorClear (ent->fields.server->velocity); + VectorClear (ent->fields.server->avelocity); } else - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; + ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND; } } @@ -1308,32 +1431,202 @@ 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. ============= */ -void SV_Physics_Step (edict_t *ent) +void SV_Physics_Step (prvm_edict_t *ent) { - // don't stick to ground if onground and moving upward - if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND)) - ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND; - - // freefall if not onground/fly/swim - if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM))) + int flags = (int)ent->fields.server->flags; + // don't fall at all if fly/swim + if (!(flags & (FL_FLY | FL_SWIM))) { - int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1; + if (flags & FL_ONGROUND) + { + // freefall if onground and moving upward + // freefall if not standing on a world surface (it may be a lift) + prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity); + if (ent->fields.server->velocity[2] >= (1.0 / 32.0) || (ground->fields.server->solid != SOLID_BSP && sv_gameplayfix_noairborncorpse.integer)) + { + ent->fields.server->flags -= FL_ONGROUND; + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); + } + } + else + { + // freefall if not onground + int hitsound = ent->fields.server->velocity[2] < sv_gravity.value * -0.1; - SV_AddGravity(ent); - SV_CheckVelocity(ent); - SV_FlyMove(ent, sv.frametime, NULL); - SV_LinkEdict(ent, true); + SV_AddGravity(ent); + SV_CheckVelocity(ent); + SV_FlyMove(ent, sv.frametime, NULL); + SV_LinkEdict(ent, true); - // just hit ground - if (hitsound && (int)ent->v->flags & FL_ONGROUND) - SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1); + // just hit ground + if (hitsound && (int)ent->fields.server->flags & FL_ONGROUND && sv_sound_land.string) + SV_StartSound(ent, 0, sv_sound_land.string, 255, 1); + } } +// regular thinking + SV_RunThink(ent); + SV_CheckWaterTransition(ent); } //============================================================================ +static void SV_Physics_Entity (prvm_edict_t *ent) +{ + // don't run a move on newly spawned projectiles as it messes up movement + // interpolation and rocket trails + qboolean runmove = ent->priv.server->move; + ent->priv.server->move = true; + switch ((int) ent->fields.server->movetype) + { + case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (ent->fields.server->nextthink > 0 && ent->fields.server->nextthink <= sv.time + sv.frametime) + SV_RunThink (ent); + break; + case MOVETYPE_FOLLOW: + SV_Physics_Follow (ent); + break; + case MOVETYPE_NOCLIP: + if (SV_RunThink(ent)) + { + SV_CheckWater(ent); + VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin); + VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles); + } + SV_LinkEdict(ent, false); + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_WALK: + if (SV_RunThink (ent)) + { + if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) ) + SV_AddGravity (ent); + SV_CheckStuck (ent); + SV_WalkMove (ent); + SV_LinkEdict (ent, true); + } + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_FLY: + // regular thinking + if (SV_RunThink (ent) && runmove) + SV_Physics_Toss (ent); + break; + default: + Con_Printf ("SV_Physics: bad movetype %i\n", (int)ent->fields.server->movetype); + break; + } +} + +void SV_ApplyClientMove (void); +void SV_Physics_ClientEntity (prvm_edict_t *ent) +{ + SV_ApplyClientMove(); + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + // LordHavoc: QuakeC replacement for SV_ClientThink (player movement) + if (SV_PlayerPhysicsQC && sv_playerphysicsqc.integer) + { + prog->globals.server->time = sv.time; + prog->globals.server->self = PRVM_EDICT_TO_PROG(ent); + PRVM_ExecuteProgram ((func_t)(SV_PlayerPhysicsQC - prog->functions), "QC function SV_PlayerPhysics is missing"); + } + else + SV_ClientThink (); + // make sure the velocity is sane (not a NaN) + SV_CheckVelocity(ent); + // LordHavoc: a hack to ensure that the (rather silly) id1 quakec + // player_run/player_stand1 does not horribly malfunction if the + // velocity becomes a number that is both == 0 and != 0 + // (sounds to me like NaN but to be absolutely safe...) + if (DotProduct(ent->fields.server->velocity, ent->fields.server->velocity) < 0.0001) + VectorClear(ent->fields.server->velocity); + // 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"); + SV_CheckVelocity (ent); + + switch ((int) ent->fields.server->movetype) + { + case MOVETYPE_PUSH: + case MOVETYPE_FAKEPUSH: + SV_Physics_Pusher (ent); + break; + case MOVETYPE_NONE: + // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects + if (ent->fields.server->nextthink > 0 && ent->fields.server->nextthink <= sv.time + sv.frametime) + SV_RunThink (ent); + break; + case MOVETYPE_FOLLOW: + SV_Physics_Follow (ent); + break; + case MOVETYPE_NOCLIP: + if (SV_RunThink(ent)) + { + SV_CheckWater(ent); + VectorMA(ent->fields.server->origin, sv.frametime, ent->fields.server->velocity, ent->fields.server->origin); + VectorMA(ent->fields.server->angles, sv.frametime, ent->fields.server->avelocity, ent->fields.server->angles); + } + break; + case MOVETYPE_STEP: + SV_Physics_Step (ent); + break; + case MOVETYPE_WALK: + if (SV_RunThink (ent)) + { + if (!SV_CheckWater (ent) && ! ((int)ent->fields.server->flags & FL_WATERJUMP) ) + SV_AddGravity (ent); + SV_CheckStuck (ent); + SV_WalkMove (ent); + } + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_BOUNCEMISSILE: + case MOVETYPE_FLYMISSILE: + // regular thinking + if (SV_RunThink (ent)) + SV_Physics_Toss (ent); + break; + case MOVETYPE_FLY: + if (SV_RunThink (ent)) + { + SV_CheckWater (ent); + SV_WalkMove (ent); + } + break; + default: + Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)ent->fields.server->movetype); + break; + } + + SV_CheckVelocity (ent); + + // call standard player post-think + SV_LinkEdict (ent, true); + + SV_CheckVelocity (ent); + + 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"); +} + /* ================ SV_Physics @@ -1342,193 +1635,84 @@ SV_Physics */ void SV_Physics (void) { - int i, end, retouch; - float nexttime; - vec3_t oldorigin; - edict_t *ent; + int i; + prvm_edict_t *ent; // let the progs know that a new frame has started - pr_global_struct->self = EDICT_TO_PROG(sv.edicts); - pr_global_struct->other = EDICT_TO_PROG(sv.edicts); - pr_global_struct->time = sv.time; - PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing"); - - retouch = pr_global_struct->force_retouch > 0; - end = i = sv_freezenonclients.integer ? svs.maxclients + 1 : sv.num_edicts; - for (i = 0, ent = sv.edicts;i < end;i++, ent = NEXT_EDICT(ent)) - { - if (ent->e->free || ent->v->movetype == MOVETYPE_NONE) - continue; + 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"); - // LordHavoc: merged client and normal entity physics - VectorCopy(ent->v->origin, oldorigin); - - switch ((int) ent->v->movetype) - { - case MOVETYPE_PUSH: - case MOVETYPE_FAKEPUSH: - SV_Physics_Pusher (ent); - break; - case MOVETYPE_NONE: - break; - case MOVETYPE_FOLLOW: - SV_Physics_Follow (ent); - break; - case MOVETYPE_NOCLIP: - SV_CheckWater(ent); - VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin); - VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles); - break; - case MOVETYPE_STEP: - SV_Physics_Step (ent); - break; - case MOVETYPE_WALK: - if (!SV_CheckWater(ent) && ! ((int)ent->v->flags & FL_WATERJUMP) ) - SV_AddGravity(ent); - SV_CheckStuck(ent); - SV_WalkMove(ent); - break; - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - case MOVETYPE_BOUNCEMISSILE: - case MOVETYPE_FLYMISSILE: - SV_Physics_Toss(ent); - break; - case MOVETYPE_FLY: - if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned) - { - SV_CheckWater(ent); - SV_WalkMove(ent); - } - else - SV_Physics_Toss(ent); - break; - default: - Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype); - break; - } - - if (!VectorCompare(ent->v->origin, oldorigin) || retouch) - SV_LinkEdict(ent, true); - } - - for (i = 1, ent = NEXT_EDICT(sv.edicts);i <= svs.maxclients;i++, ent = NEXT_EDICT(ent)) - { - if (ent->e->free || !svs.clients[i-1].spawned) - continue; +// +// treat each object in turn +// - // call standard client pre-think - SV_CheckVelocity (ent); - pr_global_struct->time = sv.time; - pr_global_struct->self = EDICT_TO_PROG(ent); - PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing"); - SV_CheckVelocity (ent); - } + // if force_retouch, relink all the entities + if (prog->globals.server->force_retouch > 0) + for (i = 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_LinkEdict (ent, true); // force retouch even for stationary - nexttime = sv.time + sv.frametime; - end = i = sv_freezenonclients.integer ? svs.maxclients + 1 : sv.num_edicts; - for (i = 0, ent = sv.edicts;i < end;i++, ent = NEXT_EDICT(ent)) + // run physics on the client entities + for (i = 1, ent = PRVM_EDICT_NUM(i), host_client = svs.clients;i <= svs.maxclients;i++, ent = PRVM_NEXT_EDICT(ent), host_client++) { - if (ent->e->free) - continue; - - // LordHavoc: merged client and normal entity physics - switch ((int) ent->v->movetype) + if (!ent->priv.server->free) { - case MOVETYPE_PUSH: - case MOVETYPE_FAKEPUSH: - // push thinks are called from SV_Physics_Pusher - break; - case MOVETYPE_NONE: - case MOVETYPE_FOLLOW: - case MOVETYPE_NOCLIP: - case MOVETYPE_STEP: - case MOVETYPE_WALK: - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - case MOVETYPE_BOUNCEMISSILE: - case MOVETYPE_FLY: - case MOVETYPE_FLYMISSILE: - // LordHavoc: manually inlined SV_RunThink here - if (ent->v->nextthink > 0 && ent->v->nextthink <= nexttime) - { - /* - 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. - */ - float thinktime = ent->v->nextthink; - if (thinktime && thinktime < sv.time + sv.frametime) - { - ent->v->nextthink = 0; - // don't let things stay in the past. - // it is possible to start that way by a trigger with a local time. - pr_global_struct->time = max(thinktime, sv.time); - pr_global_struct->self = EDICT_TO_PROG(ent); - pr_global_struct->other = EDICT_TO_PROG(sv.edicts); - PR_ExecuteProgram (ent->v->think, "QC function self.think is missing"); - } - } - break; - default: - Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype); - break; + // don't do physics on disconnected clients, FrikBot relies on this + if (!host_client->spawned) + memset(&host_client->cmd, 0, sizeof(host_client->cmd)); + // don't run physics here if running asynchronously + else if (!host_client->movesequence) + SV_Physics_ClientEntity(ent); } } - for (i = 1, ent = NEXT_EDICT(sv.edicts);i <= svs.maxclients;i++, ent = NEXT_EDICT(ent)) - { - if (ent->e->free || !svs.clients[i-1].spawned) - continue; - - // call standard player post-think - SV_LinkEdict (ent, true); - SV_CheckVelocity (ent); - pr_global_struct->time = sv.time; - pr_global_struct->self = EDICT_TO_PROG(ent); - PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing"); - } + // run physics on all the non-client entities + if (!sv_freezenonclients.integer) + for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent)) + if (!ent->priv.server->free) + SV_Physics_Entity(ent); - if (pr_global_struct->force_retouch > 0) - pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1); + if (prog->globals.server->force_retouch > 0) + prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1); // LordHavoc: endframe support if (EndFrameQC) { - pr_global_struct->self = EDICT_TO_PROG(sv.edicts); - pr_global_struct->other = EDICT_TO_PROG(sv.edicts); - pr_global_struct->time = sv.time; - PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing"); + 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 ((func_t)(EndFrameQC - prog->functions), "QC function EndFrame is missing"); } + // decrement prog->num_edicts if the highest number entities died + for (;PRVM_EDICT_NUM(prog->num_edicts - 1)->priv.server->free;prog->num_edicts--); + if (!sv_freezenonclients.integer) sv.time += sv.frametime; } -trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore) +trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore) { int i; - float gravity, savesolid; + float gravity; vec3_t move, end; - edict_t tempent, *tent; - entvars_t vars; - eval_t *val; + vec3_t original_origin; + vec3_t original_velocity; + vec3_t original_angles; + vec3_t original_avelocity; + prvm_eval_t *val; trace_t trace; - // copy the vars over - memcpy(&vars, tossent->v, sizeof(entvars_t)); - // set up the temp entity to point to the copied vars - tent = &tempent; - tent->v = &vars; + VectorCopy(tossent->fields.server->origin , original_origin ); + VectorCopy(tossent->fields.server->velocity , original_velocity ); + VectorCopy(tossent->fields.server->angles , original_angles ); + VectorCopy(tossent->fields.server->avelocity, original_avelocity); - savesolid = tossent->v->solid; - tossent->v->solid = SOLID_NOT; - - // this has to fetch the field from the original edict, since our copy is truncated - val = GETEDICTFIELDVALUE(tossent, eval_gravity); + val = PRVM_GETEDICTFIELDVALUE(tossent, eval_gravity); if (val != NULL && val->_float != 0) gravity = val->_float; else @@ -1537,19 +1721,23 @@ trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore) for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds { - SV_CheckVelocity (tent); - tent->v->velocity[2] -= gravity; - VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles); - VectorScale (tent->v->velocity, 0.05, move); - VectorAdd (tent->v->origin, move, end); - trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent); - VectorCopy (trace.endpos, tent->v->origin); - - if (trace.fraction < 1 && trace.ent && trace.ent != ignore) + SV_CheckVelocity (tossent); + tossent->fields.server->velocity[2] -= gravity; + VectorMA (tossent->fields.server->angles, 0.05, tossent->fields.server->avelocity, tossent->fields.server->angles); + VectorScale (tossent->fields.server->velocity, 0.05, move); + VectorAdd (tossent->fields.server->origin, move, end); + trace = SV_Move (tossent->fields.server->origin, tossent->fields.server->mins, tossent->fields.server->maxs, end, MOVE_NORMAL, tossent); + VectorCopy (trace.endpos, tossent->fields.server->origin); + + if (trace.fraction < 1) break; } - tossent->v->solid = savesolid; - trace.fraction = 0; // not relevant + + VectorCopy(original_origin , tossent->fields.server->origin ); + VectorCopy(original_velocity , tossent->fields.server->velocity ); + VectorCopy(original_angles , tossent->fields.server->angles ); + VectorCopy(original_avelocity, tossent->fields.server->avelocity); + return trace; }