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.
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
-onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
+onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
*/
-cvar_t sv_friction = {"sv_friction","4",false,true};
-cvar_t sv_stopspeed = {"sv_stopspeed","100"};
-cvar_t sv_gravity = {"sv_gravity","800",false,true};
-cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
-cvar_t sv_nostep = {"sv_nostep","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)"};
+
+// TODO: move this extern to server.h
+extern cvar_t sv_clmovement_waitforinput;
#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)
+{
+ Cvar_RegisterVariable(&sv_stepheight);
+ Cvar_RegisterVariable(&sv_jumpstep);
+ 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
+ {
+ if (sv.worldmodel->brushq1.hulls && !VectorCompare(ent->fields.server->mins, ent->fields.server->maxs))
+ {
+ // q1bsp/hlbsp use hulls and if the entity does not exactly match
+ // a hull size it is incorrectly tested, so this code tries to
+ // 'fix' it slightly...
+ int i;
+ vec3_t v;
+ for (i = 0;i < 8;i++)
+ {
+ v[0] = (i & 1) ? ent->fields.server->maxs[0] : ent->fields.server->mins[0];
+ v[1] = (i & 2) ? ent->fields.server->maxs[1] : ent->fields.server->mins[1];
+ v[2] = (i & 4) ? ent->fields.server->maxs[2] : ent->fields.server->mins[2];
+ if (SV_PointSuperContents(v) & SUPERCONTENTS_SOLID)
+ return true;
+ }
+ }
+ return false;
+ }
+}
/*
================
*/
void SV_CheckAllEnts (void)
{
- int e;
- edict_t *check;
+ int e;
+ 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))
+ // see if any solid entities are inside the final position
+ check = PRVM_NEXT_EDICT(prog->edicts);
+ for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
{
- if (check->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))
- Con_Printf ("entity in invalid position\n");
+ Con_Print("entity in invalid position\n");
+ }
+}
+
+// DRESK - Support for Entity Contents Transition Event
+/*
+================
+SV_CheckContentsTransition
+
+returns true if entity had a valid contentstransition function call
+================
+*/
+int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
+{
+ int bValidFunctionCall;
+ prvm_eval_t *contentstransition;
+
+ // Default Valid Function Call to False
+ bValidFunctionCall = false;
+
+ if(ent->fields.server->watertype != nContents)
+ { // Changed Contents
+ // Acquire Contents Transition Function from QC
+ contentstransition = PRVM_GETEDICTFIELDVALUE(ent, eval_contentstransition);
+
+ if(contentstransition->function)
+ { // Valid Function; Execute
+ // Assign Valid Function
+ bValidFunctionCall = true;
+ // Prepare Parameters (Original Contents, New Contents)
+ // Original Contents
+ PRVM_G_FLOAT(OFS_PARM0) = ent->fields.server->watertype;
+ // New Contents
+ PRVM_G_FLOAT(OFS_PARM1) = nContents;
+ // Execute VM Function
+ PRVM_ExecuteProgram(contentstransition->function, "contentstransition: NULL function");
+ }
}
+
+ // Return if Function Call was Valid
+ return bValidFunctionCall;
}
+
/*
================
SV_CheckVelocity
================
*/
-void SV_CheckVelocity (edict_t *ent)
+void SV_CheckVelocity (prvm_edict_t *ent)
{
- int i;
- float wishspeed;
+ int i;
+ float wishspeed;
//
// bound velocity
//
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_strings + 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_strings + 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: maxvelocity fix, see below
-/*
- if (ent->v.velocity[i] > sv_maxvelocity.value)
- ent->v.velocity[i] = sv_maxvelocity.value;
- else if (ent->v.velocity[i] < -sv_maxvelocity.value)
- ent->v.velocity[i] = -sv_maxvelocity.value;
-*/
}
// 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;
- wishspeed = sv_maxvelocity.value;
+ ent->fields.server->velocity[0] *= wishspeed;
+ ent->fields.server->velocity[1] *= wishspeed;
+ ent->fields.server->velocity[2] *= wishspeed;
}
}
Returns false if the entity removed itself.
=============
*/
-qboolean SV_RunThink (edict_t *ent)
+qboolean SV_RunThink (prvm_edict_t *ent)
{
- float thinktime;
+ float thinktime;
- thinktime = ent->v.nextthink;
- if (thinktime <= 0 || thinktime > sv.time + host_frametime)
+ 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; // don't let things stay in the past.
- // it is possible to start that way
- // by a trigger with a local time.
- ent->v.nextthink = 0;
- pr_global_struct->time = thinktime;
- pr_global_struct->self = EDICT_TO_PROG(ent);
- pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
- PR_ExecuteProgram (ent->v.think, "NULL think function");
- return !ent->free;
+ 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;
}
/*
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;
-
- old_self = pr_global_struct->self;
- old_other = pr_global_struct->other;
-
- pr_global_struct->time = sv.time;
- if (e1->v.touch && e1->v.solid != SOLID_NOT)
+ int old_self, old_other;
+ prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
+ prvm_eval_t *val;
+
+ old_self = prog->globals.server->self;
+ old_other = prog->globals.server->other;
+
+ 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, "");
+ 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)
+ val->string = PRVM_SetTempString(trace->hittexture->name);
+ 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, "");
+ 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;
}
returns the blocked flags (1 = floor, 2 = step / wall)
==================
*/
-#define STOP_EPSILON 0.1
-
-int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+#define STOP_EPSILON 0.1
+void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
{
- 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;
+ int i;
+ float backoff;
- for (i=0 ; i<3 ; i++)
- {
- change = normal[i]*backoff;
- out[i] = in[i] - change;
+ backoff = -DotProduct (in, normal) * overbounce;
+ VectorMA(in, backoff, normal, out);
+
+ for (i = 0;i < 3;i++)
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
out[i] = 0;
- }
-
- return blocked;
}
1 = floor
2 = wall / step
4 = dead stop
-If steptrace is not NULL, the trace of any vertical wall hit will be stored
+If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
============
*/
-// LordHavoc: increased from 5 to 20, to partially fix angled corner sticking
-// (example - start.bsp hall to e1m4, leading to the pool there are two
-// angled corners, which you could get stuck on, now they are just a one
-// frame hiccup)
-#define MAX_CLIP_PLANES 20
-int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
+// LordHavoc: increased from 5 to 32
+#define MAX_CLIP_PLANES 32
+int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal)
{
- 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;
-
- numbumps = 4;
-
+ int blocked, 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;
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;
-
- for (bumpcount=0 ; bumpcount<numbumps ; 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;
- for (i=0 ; i<3 ; i++)
- end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
+ 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->fields.server->origin, start);
+ start[2] += 3;//0.03125;
+ VectorMA(ent->fields.server->origin, time_left, ent->fields.server->velocity, end);
+ end[2] += 3;//0.03125;
+ 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;
+ }
+#endif
+#if 0
+ //j = -1;
+ for (i = 0;i < numplanes;i++)
+ {
+ 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->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
+ if (trace.fraction < testtrace.fraction)
+ {
+ trace = testtrace;
+ VectorCopy(start, ent->fields.server->origin);
+ //j = i;
+ }
+ }
+ //if (j >= 0)
+ // VectorAdd(ent->fields.server->origin, planes[j], start);
+#endif
+ }
+#endif
- trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
+#if 0
+ 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.allsolid)
- { // entity is trapped in another solid
- VectorClear(ent->v.velocity);
+#if 0
+ if (trace.bmodelstartsolid)
+ {
+ // 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->fields.server->velocity);
return 3;
}
+#endif
- if (trace.fraction > 0)
- { // actually covered some distance
- VectorCopy (trace.endpos, ent->v.origin);
- VectorCopy (ent->v.velocity, original_velocity);
- numplanes = 0;
- }
-
+ // break if it moved the entire distance
if (trace.fraction == 1)
- break; // moved the entire distance
+ {
+ VectorCopy(trace.endpos, ent->fields.server->origin);
+ break;
+ }
if (!trace.ent)
- Host_Error ("SV_FlyMove: !trace.ent");
+ {
+ 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] > 0.7)
+ if (trace.plane.normal[2])
{
- blocked |= 1; // floor
- if (trace.ent->v.solid == SOLID_BSP)
+ if (trace.plane.normal[2] > 0.7)
{
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(trace.ent);
+ // floor
+ blocked |= 1;
+ ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
+ ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(trace.ent);
}
}
- if (!trace.plane.normal[2])
+ else
{
- blocked |= 2; // step
- if (steptrace)
- *steptrace = trace; // save for player extrafriction
+ // step
+ blocked |= 2;
+ // save the trace for player extrafriction
+ if (stepnormal)
+ VectorCopy(trace.plane.normal, stepnormal);
}
-//
-// run the impact function
-//
- SV_Impact (ent, trace.ent);
- if (ent->free)
- break; // removed by the impact function
-
-
- time_left -= time_left * trace.fraction;
-
- // cliped to another plane
+ if (trace.fraction >= 0.001)
+ {
+ // actually covered some distance
+ 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);
+
+ // break if removed by the impact function
+ if (ent->priv.server->free)
+ break;
+ }
+
+ time_left *= 1 - trace.fraction;
+
+ // clipped to another plane
if (numplanes >= MAX_CLIP_PLANES)
- { // this shouldn't really happen
- VectorClear(ent->v.velocity);
- return 3;
+ {
+ // this shouldn't really happen
+ VectorClear(ent->fields.server->velocity);
+ blocked = 3;
+ break;
}
- VectorCopy (trace.plane.normal, planes[numplanes]);
+ /*
+ for (i = 0;i < numplanes;i++)
+ if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
+ break;
+ if (i < numplanes)
+ {
+ VectorAdd(ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity);
+ continue;
+ }
+ */
+
+ VectorCopy(trace.plane.normal, planes[numplanes]);
numplanes++;
-//
-// modify original_velocity so it parallels all of the clip planes
-//
- for (i=0 ; i<numplanes ; i++)
+ if (sv_newflymove.integer)
+ ClipVelocity(ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1);
+ else
{
- ClipVelocity (original_velocity, planes[i], new_velocity, 1);
- for (j=0 ; j<numplanes ; j++)
- if (j != i)
+ // modify original_velocity so it parallels all of the clip planes
+ for (i = 0;i < numplanes;i++)
+ {
+ ClipVelocity(original_velocity, planes[i], new_velocity, 1);
+ for (j = 0;j < numplanes;j++)
{
- if (DotProduct (new_velocity, planes[j]) < 0)
- break; // not ok
+ if (j != i)
+ {
+ // not ok
+ if (DotProduct(new_velocity, planes[j]) < 0)
+ break;
+ }
}
- if (j == numplanes)
- break;
- }
-
- if (i != numplanes)
- { // go along this plane
- VectorCopy (new_velocity, ent->v.velocity);
- }
- else
- { // go along the crease
- if (numplanes != 2)
+ if (j == numplanes)
+ break;
+ }
+
+ if (i != numplanes)
+ {
+ // go along this plane
+ VectorCopy(new_velocity, ent->fields.server->velocity);
+ }
+ else
{
-// Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
- VectorClear(ent->v.velocity);
- return 7;
+ // go along the crease
+ if (numplanes != 2)
+ {
+ 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->fields.server->velocity);
+ VectorScale(dir, d, ent->fields.server->velocity);
}
- CrossProduct (planes[0], planes[1], dir);
- d = DotProduct (dir, ent->v.velocity);
- VectorScale (dir, d, ent->v.velocity);
}
-//
-// if original velocity is against the original velocity, stop dead
-// to avoid tiny occilations in sloping corners
-//
- if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
+ // if current velocity is against the original velocity,
+ // stop dead to avoid tiny occilations in sloping corners
+ if (DotProduct(ent->fields.server->velocity, primal_velocity) <= 0)
{
- VectorClear(ent->v.velocity);
- return blocked;
+ VectorClear(ent->fields.server->velocity);
+ break;
}
}
+ //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]);
+
+ /*
+ 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->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, MOVE_NORMAL, ent);
+ }
+ */
+
+ // LordHavoc: this came from QW and allows you to get out of water more easily
+ if (sv_gameplayfix_qwplayerphysics.integer && ((int)ent->fields.server->flags & FL_WATERJUMP))
+ VectorCopy(primal_velocity, ent->fields.server->velocity);
return blocked;
}
-
/*
============
SV_AddGravity
============
*/
-void SV_AddGravity (edict_t *ent)
+void SV_AddGravity (prvm_edict_t *ent)
{
- float ent_gravity;
-
- eval_t *val;
+ float ent_gravity;
+ 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 * host_frametime;
+ ent->fields.server->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
}
Does not change the entities velocity at all
============
*/
-trace_t SV_PushEntity (edict_t *ent, vec3_t push)
+static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid)
{
- trace_t trace;
- vec3_t end;
-
- VectorAdd (ent->v.origin, push, end);
-
- if (ent->v.movetype == MOVETYPE_FLYMISSILE)
- trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
- else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
- // only clip against bmodels
- trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
+ int type;
+ trace_t trace;
+ vec3_t end;
+
+ VectorAdd (ent->fields.server->origin, push, end);
+
+ if (ent->fields.server->movetype == MOVETYPE_FLYMISSILE)
+ type = MOVE_MISSILE;
+ else if (ent->fields.server->solid == SOLID_TRIGGER || ent->fields.server->solid == SOLID_NOT)
+ type = MOVE_NOMONSTERS; // only clip against bmodels
else
- trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
-
- VectorCopy (trace.endpos, ent->v.origin);
- SV_LinkEdict (ent, true);
+ type = MOVE_NORMAL;
- if (trace.ent)
- SV_Impact (ent, trace.ent);
+ trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent);
+ if (trace.bmodelstartsolid && failonbmodelstartsolid)
+ return trace;
+ VectorCopy (trace.endpos, ent->fields.server->origin);
+ SV_LinkEdict (ent, true);
+
+ if (ent->fields.server->solid >= SOLID_TRIGGER && 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;
-}
+}
/*
============
*/
-void SV_PushMove (edict_t *pusher, float movetime)
+void SV_PushMove (prvm_edict_t *pusher, float movetime)
{
- int i, e;
- edict_t *check;
- vec3_t mins, maxs, move;
- vec3_t entorig, pushorig;
- int num_moved;
- edict_t *moved_edict[MAX_EDICTS];
- vec3_t moved_from[MAX_EDICTS];
- float savesolid;
-
- switch ((int) pusher->v.solid)
+ 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];
+ model_t *pushermodel;
+ trace_t trace;
+
+ 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->fields.server->ltime += movetime;
+ return;
+ }
+
+ switch ((int) pusher->fields.server->solid)
{
// LordHavoc: valid pusher types
case SOLID_BSP:
// LordHavoc: no collisions
case SOLID_NOT:
case SOLID_TRIGGER:
- VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
- 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:
- Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
- }
- if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
- {
- pusher->v.ltime += movetime;
+ Con_Printf("SV_PushMove: entity #%i, unrecognized solid type %f\n", PRVM_NUM_FOR_EDICT(pusher), pusher->fields.server->solid);
return;
}
-
- for (i=0 ; i<3 ; i++)
+ index = (int) pusher->fields.server->modelindex;
+ if (index < 1 || index >= MAX_MODELS)
{
- move[i] = pusher->v.velocity[i] * movetime;
- mins[i] = pusher->v.absmin[i] + move[i];
- maxs[i] = pusher->v.absmax[i] + move[i];
+ 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];
- VectorCopy (pusher->v.origin, pushorig);
-
-// move the pusher to it's final position
-
- VectorAdd (pusher->v.origin, move, pusher->v.origin);
- pusher->v.ltime += movetime;
- SV_LinkEdict (pusher, false);
-
-
-// see if any solid entities are inside the final position
- num_moved = 0;
- check = NEXT_EDICT(sv.edicts);
- for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
+ movetime2 = movetime;
+ VectorScale(pusher->fields.server->velocity, movetime2, move1);
+ VectorScale(pusher->fields.server->avelocity, movetime2, moveangle);
+ if (moveangle[0] || moveangle[2])
{
- if (check->free)
- continue;
- if (check->v.movetype == MOVETYPE_PUSH
- || check->v.movetype == MOVETYPE_NONE
- || check->v.movetype == MOVETYPE_FOLLOW
- || check->v.movetype == MOVETYPE_NOCLIP)
- 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 (check->v.absmin[0] >= maxs[0]
- || check->v.absmin[1] >= maxs[1]
- || check->v.absmin[2] >= maxs[2]
- || check->v.absmax[0] <= mins[0]
- || check->v.absmax[1] <= mins[1]
- || check->v.absmax[2] <= mins[2])
- continue;
-
- // see if the ent's bbox is inside the pusher's final position
- if (!SV_TestEntityPosition (check))
- continue;
- }
-
- // 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, entorig);
- VectorCopy (check->v.origin, moved_from[num_moved]);
- moved_edict[num_moved] = check;
- num_moved++;
-
- // LordHavoc: pusher fixes (teleport train bug, etc)
- savesolid = pusher->v.solid;
- if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
+ for (i = 0;i < 3;i++)
{
- // try moving the contacted entity
- pusher->v.solid = SOLID_NOT;
- SV_PushEntity (check, move);
- pusher->v.solid = savesolid; // was SOLID_BSP
-
- // if it is still inside the pusher, block
- if (SV_TestEntityPosition (check))
- { // fail the move
- if (check->v.mins[0] == check->v.maxs[0])
- continue;
- if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
- { // corpse
- check->v.mins[0] = check->v.mins[1] = 0;
- VectorCopy (check->v.mins, check->v.maxs);
- continue;
- }
-
- VectorCopy (entorig, check->v.origin);
- SV_LinkEdict (check, true);
-
- VectorCopy (pushorig, pusher->v.origin);
- SV_LinkEdict (pusher, false);
- pusher->v.ltime -= movetime;
-
- // 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, "");
- }
-
- // move back any entities we already moved
- num_moved--; // LordHavoc: pop off check, because it was already restored
- for (i=0 ; i<num_moved ; i++)
- {
- VectorCopy (moved_from[i], moved_edict[i]->v.origin);
- SV_LinkEdict (moved_edict[i], false);
- }
- return;
- }
+ if (move1[i] > 0)
+ {
+ 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->fields.server->origin[i] - 1;
+ maxs[i] = pushermodel->rotatedmaxs[i] + pusher->fields.server->origin[i] + 1;
+ }
}
}
-
-
-}
-
-/*
-============
-SV_PushRotate
-
-============
-*/
-void SV_PushRotate (edict_t *pusher, float movetime)
-{
- int i, e;
- edict_t *check;
- vec3_t move, a, amove;
- vec3_t entorigin, entangles, pushorigin, pushangles;
- int num_moved;
- edict_t *moved_edict[MAX_EDICTS];
- vec3_t moved_from[MAX_EDICTS];
- vec3_t angled_from[MAX_EDICTS];
- vec3_t org, org2;
- vec3_t forward, right, up;
- float savesolid;
-
- switch ((int) pusher->v.solid)
+ else if (moveangle[1])
{
- // LordHavoc: valid pusher types
- case SOLID_BSP:
- case SOLID_BBOX:
- case SOLID_SLIDEBOX:
- case SOLID_CORPSE: // LordHavoc: this would be weird...
- break;
- // LordHavoc: no collisions
- case SOLID_NOT:
- case SOLID_TRIGGER:
- VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
- pusher->v.ltime += movetime;
- SV_LinkEdict (pusher, false);
- return;
- default:
- Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
+ for (i = 0;i < 3;i++)
+ {
+ if (move1[i] > 0)
+ {
+ 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->fields.server->origin[i] - 1;
+ maxs[i] = pushermodel->yawmaxs[i] + pusher->fields.server->origin[i] + 1;
+ }
+ }
}
- if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
+ else
{
- pusher->v.ltime += movetime;
- return;
+ for (i = 0;i < 3;i++)
+ {
+ if (move1[i] > 0)
+ {
+ 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->fields.server->origin[i] - 1;
+ maxs[i] = pushermodel->normalmaxs[i] + pusher->fields.server->origin[i] + 1;
+ }
+ }
}
- for (i=0 ; i<3 ; i++)
- amove[i] = pusher->v.avelocity[i] * movetime;
+ VectorNegate (moveangle, a);
+ AngleVectorsFLU (a, forward, left, up);
- VectorNegate (amove, a);
- AngleVectors (a, forward, right, up);
+ VectorCopy (pusher->fields.server->origin, pushorig);
+ VectorCopy (pusher->fields.server->angles, pushang);
+ pushltime = pusher->fields.server->ltime;
- VectorCopy (pusher->v.origin, pushorigin);
- VectorCopy (pusher->v.angles, pushangles);
-
-// move the pusher to it's final position
+// move the pusher to its final position
- VectorAdd (pusher->v.angles, amove, 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->fields.server->solid;
// see if any solid entities are inside the final position
num_moved = 0;
- check = NEXT_EDICT(sv.edicts);
- for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
+
+ numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
+ for (e = 0;e < numcheckentities;e++)
{
- if (check->free)
- continue;
- if (check->v.movetype == MOVETYPE_PUSH
- || check->v.movetype == MOVETYPE_NONE
- || check->v.movetype == MOVETYPE_FOLLOW
- || check->v.movetype == MOVETYPE_NOCLIP)
+ 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 definately be moved
- if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
+ // if the entity is standing on the pusher, it will definitely be moved
+ if (((int)check->fields.server->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.server->groundentity) == pusher)
{
- if (check->v.absmin[0] >= pusher->v.absmax[0]
- || check->v.absmin[1] >= pusher->v.absmax[1]
- || check->v.absmin[2] >= pusher->v.absmax[2]
- || check->v.absmax[0] <= pusher->v.absmin[0]
- || check->v.absmax[1] <= pusher->v.absmin[1]
- || check->v.absmax[2] <= pusher->v.absmin[2])
- continue;
-
- // see if the ent's bbox is inside the pusher's final position
- if (!SV_TestEntityPosition (check))
+ // 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;
+ }
+ else
+ {
+ // 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->v.movetype != MOVETYPE_WALK)
- check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
-
- VectorCopy (check->v.origin, entorigin);
- VectorCopy (check->v.origin, moved_from[num_moved]);
- VectorCopy (check->v.angles, entangles);
- VectorCopy (check->v.angles, angled_from[num_moved]);
- moved_edict[num_moved] = check;
- num_moved++;
-
- // calculate destination position
- VectorSubtract (check->v.origin, pusher->v.origin, org);
- org2[0] = DotProduct (org, forward);
- org2[1] = -DotProduct (org, right);
- org2[2] = DotProduct (org, up);
- VectorSubtract (org2, org, move);
-
- // try moving the contacted entity
- savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
- pusher->v.solid = SOLID_NOT;
- SV_PushEntity (check, move);
- pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
-
- VectorAdd (check->v.angles, amove, check->v.angles);
-
- // if it is still inside the pusher, block
- if (SV_TestEntityPosition (check))
- { // fail the move
- if (check->v.mins[0] == check->v.maxs[0])
- continue;
- if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
- { // corpse
- check->v.mins[0] = check->v.mins[1] = 0;
- VectorCopy (check->v.mins, check->v.maxs);
- continue;
- }
-
- VectorCopy (entorigin, check->v.origin);
- VectorCopy (entangles, check->v.angles);
- SV_LinkEdict (check, true);
-
- VectorCopy (pushorigin, pusher->v.origin);
- VectorCopy (pushangles, pusher->v.angles);
- SV_LinkEdict (pusher, false);
- pusher->v.ltime -= movetime;
-
- // 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, "");
- }
-
- // move back any entities we already moved
- num_moved--; // LordHavoc: pop off check, because it was already restored
- for (i=0 ; i<num_moved ; i++)
+
+ if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used
+ {
+ 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);
+ VectorSubtract (org2, org, move);
+ VectorAdd (move, move1, move);
+ }
+ else
+ VectorCopy (move1, move);
+
+ 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->fields.server->solid = SOLID_NOT;
+ trace = SV_PushEntity (check, move, true);
+ // FIXME: turn players specially
+ check->fields.server->angles[1] += trace.fraction * moveangle[1];
+ pusher->fields.server->solid = savesolid; // was SOLID_BSP
+ //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
+
+ // if it is still inside the pusher, block
+ 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
+ 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, true);
+ 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)
{
- VectorCopy (moved_from[i], moved_edict[i]->v.origin);
- VectorCopy (angled_from[i], moved_edict[i]->v.angles);
- SV_LinkEdict (moved_edict[i], false);
+ // 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, true);
+ 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->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;
+ }
+
+ VectorCopy (pushorig, pusher->fields.server->origin);
+ VectorCopy (pushang, pusher->fields.server->angles);
+ pusher->fields.server->ltime = pushltime;
+ SV_LinkEdict (pusher, false);
+
+ // 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;
+ }
}
- return;
}
}
+ 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));
}
/*
================
*/
-void SV_Physics_Pusher (edict_t *ent)
+void SV_Physics_Pusher (prvm_edict_t *ent)
{
- float thinktime;
- float oldltime;
- float movetime;
-
- oldltime = ent->v.ltime;
-
- thinktime = ent->v.nextthink;
- if (thinktime < ent->v.ltime + host_frametime)
+ float thinktime, oldltime, movetime;
+
+ oldltime = ent->fields.server->ltime;
+
+ 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;
}
else
- movetime = host_frametime;
+ movetime = sv.frametime;
if (movetime)
+ // advances ent->fields.server->ltime if not blocked
+ SV_PushMove (ent, movetime);
+
+ if (thinktime > oldltime && thinktime <= ent->fields.server->ltime)
{
- if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
- SV_PushRotate (ent, movetime);
- else
- SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
- }
-
- if (thinktime > oldltime && thinktime <= ent->v.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, "NULL think function");
- if (ent->free)
- return;
+ 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");
}
-
}
clipping hull.
=============
*/
-void SV_CheckStuck (edict_t *ent)
+void SV_CheckStuck (prvm_edict_t *ent)
{
- int i, j;
- int z;
- vec3_t org;
+ 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_DPrintf ("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_DPrintf ("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_DPrintf ("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);
+ if (developer.integer >= 100)
+ Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
}
SV_CheckWater
=============
*/
-qboolean SV_CheckWater (edict_t *ent)
+qboolean SV_CheckWater (prvm_edict_t *ent)
{
- vec3_t point;
- int cont;
-
- point[0] = ent->v.origin[0];
- point[1] = ent->v.origin[1];
- point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
-
- ent->v.waterlevel = 0;
- ent->v.watertype = CONTENTS_EMPTY;
- cont = SV_PointContents (point);
- if (cont <= CONTENTS_WATER)
+ int cont;
+ int nNativeContents;
+ vec3_t point;
+
+ 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;
+
+ // DRESK - Support for Entity Contents Transition Event
+ // NOTE: Some logic needed to be slightly re-ordered
+ // to not affect performance and allow for the feature.
+
+ // Acquire Super Contents Prior to Resets
+ cont = SV_PointSuperContents(point);
+ // Acquire Native Contents Here
+ nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
+
+ // DRESK - Support for Entity Contents Transition Event
+ if(ent->fields.server->watertype)
+ // Entity did NOT Spawn; Check
+ SV_CheckContentsTransition(ent, nNativeContents);
+
+
+ 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_PointContents (point);
- if (cont <= CONTENTS_WATER)
+ ent->fields.server->watertype = nNativeContents;
+ 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_PointContents (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;
}
/*
============
*/
-void SV_WallFriction (edict_t *ent, trace_t *trace)
+void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
{
- vec3_t forward, right, up;
- float d, i;
- vec3_t into, side;
-
- AngleVectors (ent->v.v_angle, forward, right, up);
- d = DotProduct (trace->plane.normal, forward);
-
- d += 0.5;
- if (d >= 0)
- return;
-
-// cut the tangential velocity
- i = DotProduct (trace->plane.normal, ent->v.velocity);
- VectorScale (trace->plane.normal, i, into);
- VectorSubtract (ent->v.velocity, into, side);
-
- ent->v.velocity[0] = side[0] * (1 + d);
- ent->v.velocity[1] = side[1] * (1 + d);
+ float d, i;
+ vec3_t forward, into, side;
+
+ 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->fields.server->velocity);
+ VectorScale (stepnormal, i, into);
+ 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);
+ }
}
/*
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;
- vec3_t oldorg;
- vec3_t dir;
- int clip;
- trace_t steptrace;
-
- VectorCopy (ent->v.origin, oldorg);
+ int i, clip;
+ vec3_t oldorg, dir;
+
+ VectorCopy (ent->fields.server->origin, oldorg);
VectorClear (dir);
for (i=0 ; i<8 ; i++)
{
-// try pushing a little in an axial direction
+ // 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;
+ 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);
-// retry the original move
- ent->v.velocity[0] = oldvel[0];
- ent->v. velocity[1] = oldvel[1];
- ent->v. velocity[2] = 0;
- clip = SV_FlyMove (ent, 0.1, &steptrace);
+ SV_PushEntity (ent, dir, false);
+
+ // retry the original move
+ 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_DPrintf ("unstuck!\n");
+ Con_DPrint("TryUnstick - success.\n");
return clip;
}
-
-// go back to the original pos and try again
- VectorCopy (oldorg, ent->v.origin);
+
+ // go back to the original pos and try again
+ VectorCopy (oldorg, ent->fields.server->origin);
}
-
- VectorClear (ent->v.velocity);
- return 7; // still not moving
+
+ // still not moving
+ VectorClear (ent->fields.server->velocity);
+ Con_DPrint("TryUnstick - failure.\n");
+ return 7;
}
/*
Only used by players
======================
*/
-#define STEPSIZE 18
-void SV_WalkMove (edict_t *ent)
+void SV_WalkMove (prvm_edict_t *ent)
{
- vec3_t upmove, downmove;
- vec3_t oldorg, oldvel;
- vec3_t nosteporg, nostepvel;
- int clip;
- int oldonground;
- trace_t steptrace, downtrace;
-
-//
-// 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;
-
- VectorCopy (ent->v.origin, oldorg);
- VectorCopy (ent->v.velocity, oldvel);
-
- clip = SV_FlyMove (ent, host_frametime, &steptrace);
-
- if ( !(clip & 2) )
- return; // move didn't block on a step
-
- if (!oldonground && ent->v.waterlevel == 0)
- return; // don't stair up while jumping
-
- if (ent->v.movetype != MOVETYPE_WALK)
- return; // gibbed by a trigger
-
- if (sv_nostep.value)
- return;
-
- if ( (int)sv_player->v.flags & FL_WATERJUMP )
- return;
+ 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;
- VectorCopy (ent->v.origin, nosteporg);
- VectorCopy (ent->v.velocity, nostepvel);
+ SV_CheckVelocity(ent);
-//
-// try moving up and forward to go up a step
-//
- VectorCopy (oldorg, ent->v.origin); // back to start pos
+ // do a regular slide move unless it looks like you ran into a step
+ oldonground = (int)ent->fields.server->flags & FL_ONGROUND;
+ ent->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
- VectorClear (upmove);
- VectorClear (downmove);
- upmove[2] = STEPSIZE;
- downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
+ VectorCopy (ent->fields.server->origin, start_origin);
+ VectorCopy (ent->fields.server->velocity, start_velocity);
-// move up
- SV_PushEntity (ent, upmove); // FIXME: don't link?
+ clip = SV_FlyMove (ent, sv.frametime, NULL);
-// move forward
- ent->v.velocity[0] = oldvel[0];
- ent->v. velocity[1] = oldvel[1];
- ent->v. velocity[2] = 0;
- clip = SV_FlyMove (ent, host_frametime, &steptrace);
+ SV_CheckVelocity(ent);
-// check for stuckness, possibly due to the limited precision of floats
-// in the clipping hulls
- if (clip)
- {
- if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
- && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
- { // stepping up didn't make any progress
- clip = SV_TryUnstick (ent, oldvel);
- }
- }
-
-// extra friction based on view angle
- if ( clip & 2 )
- SV_WallFriction (ent, &steptrace);
+ VectorCopy(ent->fields.server->origin, originalmove_origin);
+ VectorCopy(ent->fields.server->velocity, originalmove_velocity);
+ originalmove_clip = clip;
+ originalmove_flags = (int)ent->fields.server->flags;
+ originalmove_groundentity = ent->fields.server->groundentity;
+
+ if ((int)ent->fields.server->flags & FL_WATERJUMP)
+ return;
-// move down
- downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
+ if (sv_nostep.integer)
+ return;
- if (downtrace.plane.normal[2] > 0.7)
+ // if move didn't block on a step, return
+ if (clip & 2)
{
- if (ent->v.solid == SOLID_BSP)
+ // 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.server->movetype != MOVETYPE_FLY)
{
- ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
- ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
+ // return if gibbed by a trigger
+ 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->fields.server->waterlevel == 0)
+ return;
}
- }
- else
- {
-// 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 (nosteporg, ent->v.origin);
- VectorCopy (nostepvel, ent->v.velocity);
- }
-}
+ // try moving up and forward to go up a step
+ // back to start pos
+ 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, false);
+
+ // move forward
+ ent->fields.server->velocity[2] = 0;
+ clip = SV_FlyMove (ent, sv.frametime, stepnormal);
+ 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->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->fields.server->origin);
+ VectorCopy(originalmove_velocity, ent->fields.server->velocity);
+ //clip = originalmove_clip;
+ ent->fields.server->flags = originalmove_flags;
+ ent->fields.server->groundentity = originalmove_groundentity;
+ // now try to unstick if needed
+ //clip = SV_TryUnstick (ent, oldvel);
+ return;
+ }
-/*
-================
-SV_Physics_Client
+ //Con_Printf("step - ");
-Player character actions
-================
-*/
-void SV_Physics_Client (edict_t *ent, int num)
-{
- if ( ! svs.clients[num-1].active )
- return; // unconnected slot
+ // extra friction based on view angle
+ if (clip & 2 && sv_wallfriction.integer)
+ 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->fields.server->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->fields.server->flags & FL_ONGROUND)))
+ return;
-//
-// call standard client pre-think
-//
- 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");
-
-//
-// do a move
-//
- SV_CheckVelocity (ent);
+ // move down
+ VectorClear (downmove);
+ downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
+ // FIXME: don't link?
+ downtrace = SV_PushEntity (ent, downmove, false);
-//
-// decide which move function to call
-//
- switch ((int)ent->v.movetype)
+ if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
{
- case MOVETYPE_NONE:
- if (!SV_RunThink (ent))
- return;
- break;
-
- case MOVETYPE_WALK:
- if (!SV_RunThink (ent))
- return;
- 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:
- SV_Physics_Toss (ent);
- break;
-
- case MOVETYPE_FLY:
- if (!SV_RunThink (ent))
- return;
- SV_CheckWater (ent);
- SV_FlyMove (ent, host_frametime, NULL);
- break;
-
- case MOVETYPE_NOCLIP:
- if (!SV_RunThink (ent))
- return;
- SV_CheckWater (ent);
- VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
- break;
-
- default:
- Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
+ // 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->fields.server->solid == SOLID_BSP)
+ {
+ //Con_Printf("onground\n");
+ ent->fields.server->flags = (int)ent->fields.server->flags | FL_ONGROUND;
+ ent->fields.server->groundentity = PRVM_EDICT_TO_PROG(downtrace.ent);
+ }
+#endif
+ }
+ else
+ {
+ //Con_Printf("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.server->origin);
+ VectorCopy(originalmove_velocity, ent->fields.server->velocity);
+ //clip = originalmove_clip;
+ ent->fields.server->flags = originalmove_flags;
+ ent->fields.server->groundentity = originalmove_groundentity;
}
-//
-// call standard player post-think
-//
- SV_LinkEdict (ent, true);
-
- 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");
+ SV_CheckVelocity(ent);
}
//============================================================================
-/*
-=============
-SV_Physics_None
-
-Non moving objects can only think
-=============
-*/
-void SV_Physics_None (edict_t *ent)
-{
-// regular thinking
- SV_RunThink (ent);
-}
-
/*
=============
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;
-// regular thinking
+ 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->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[0] * vf[2] + e->v.origin[0];
- ent->v.origin[1] = ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[1] * vr[2] + e->v.origin[1];
- ent->v.origin[2] = ent->v.view_ofs[2] * vu[0] + ent->v.view_ofs[2] * vu[1] + ent->v.view_ofs[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 (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
+ VectorAdd (e->fields.server->angles, ent->fields.server->v_angle, ent->fields.server->angles);
SV_LinkEdict (ent, true);
}
-/*
-=============
-SV_Physics_Noclip
-
-A moving object that doesn't obey physics
-=============
-*/
-void SV_Physics_Noclip (edict_t *ent)
-{
-// regular thinking
- if (!SV_RunThink (ent))
- return;
-
- VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
- VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
-
- SV_LinkEdict (ent, false);
-}
-
/*
==============================================================================
=============
*/
-void SV_CheckWaterTransition (edict_t *ent)
+void SV_CheckWaterTransition (prvm_edict_t *ent)
{
- int cont;
- cont = SV_PointContents (ent->v.origin);
- if (!ent->v.watertype)
- { // just spawned here
- ent->v.watertype = cont;
- ent->v.waterlevel = 1;
+ int cont;
+ cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(ent->fields.server->origin));
+ if (!ent->fields.server->watertype)
+ {
+ // just spawned here
+ ent->fields.server->watertype = cont;
+ ent->fields.server->waterlevel = 1;
return;
}
-
+
+ // DRESK - Support for Entity Contents Transition Event
+ // NOTE: Call here BEFORE updating the watertype below,
+ // and suppress watersplash sound if a valid function
+ // call was made to allow for custom "splash" sounds.
+ if( !SV_CheckContentsTransition(ent, cont) )
+ { // Contents Transition Function Invalid; Potentially Play Water Sound
+ // check if the entity crossed into or out of water
+ 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)
{
- if (ent->v.watertype == CONTENTS_EMPTY)
- { // just crossed into water
- SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
- }
- ent->v.watertype = cont;
- ent->v.waterlevel = 1;
+ ent->fields.server->watertype = cont;
+ ent->fields.server->waterlevel = 1;
}
else
{
- if (ent->v.watertype != CONTENTS_EMPTY)
- { // just crossed into water
- SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
- }
- ent->v.watertype = CONTENTS_EMPTY;
- ent->v.waterlevel = cont;
+ ent->fields.server->watertype = CONTENTS_EMPTY;
+ ent->fields.server->waterlevel = 0;
}
}
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;
- float backoff;
- // regular thinking
- if (!SV_RunThink (ent))
- return;
+ trace_t trace;
+ vec3_t move;
// if onground, return without moving
- if ( ((int)ent->v.flags & FL_ONGROUND) )
- return;
+ if ((int)ent->fields.server->flags & FL_ONGROUND)
+ {
+ if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
+ {
+ // don't stick to ground if onground and moving upward
+ ent->fields.server->flags -= FL_ONGROUND;
+ }
+ else if (!ent->fields.server->groundentity || !sv_gameplayfix_noairborncorpse.integer)
+ {
+ // we can trust FL_ONGROUND if groundentity is world because it never moves
+ return;
+ }
+ else if (ent->priv.server->suspendedinairflag && PRVM_PROG_TO_EDICT(ent->fields.server->groundentity)->priv.server->free)
+ {
+ // if ent was supported by a brush model on previous frame,
+ // and groundentity is now freed, set groundentity to 0 (world)
+ // which leaves it suspended in the air
+ ent->fields.server->groundentity = 0;
+ return;
+ }
+ }
+ ent->priv.server->suspendedinairflag = false;
SV_CheckVelocity (ent);
// add gravity
- if (ent->v.movetype != MOVETYPE_FLY
- && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
- && ent->v.movetype != MOVETYPE_FLYMISSILE)
+ if (ent->fields.server->movetype == MOVETYPE_TOSS || ent->fields.server->movetype == MOVETYPE_BOUNCE)
SV_AddGravity (ent);
// move angles
- VectorMA (ent->v.angles, host_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, host_frametime, move);
- trace = SV_PushEntity (ent, move);
- if (trace.fraction == 1)
- return;
- if (ent->free)
+ VectorScale (ent->fields.server->velocity, sv.frametime, move);
+ trace = SV_PushEntity (ent, move, true);
+ if (ent->priv.server->free)
return;
-
- if (ent->v.movetype == MOVETYPE_BOUNCE)
- backoff = 1.5;
- else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
- backoff = 2.0;
- else
- backoff = 1;
-
- ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
+ if (trace.bmodelstartsolid)
+ {
+ // try to unstick the entity
+ SV_UnstickEntity(ent);
+ trace = SV_PushEntity (ent, move, false);
+ if (ent->priv.server->free)
+ return;
+ }
-// stop if on ground
- if (trace.plane.normal[2] > 0.7)
- {
- if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
+ if (trace.fraction < 1)
+ {
+ if (ent->fields.server->movetype == MOVETYPE_BOUNCEMISSILE)
+ {
+ 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->fields.server->movetype == MOVETYPE_BOUNCE)
+ {
+ float d;
+ 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->fields.server->velocity);
+ if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
+ {
+ 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->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+ }
+ else
+ {
+ if (trace.plane.normal[2] > 0.7 && ent->fields.server->velocity[2] < 60)
+ {
+ 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->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
+ }
+ }
+ else
{
- 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);
+ ClipVelocity (ent->fields.server->velocity, trace.plane.normal, ent->fields.server->velocity, 1.0);
+ if (trace.plane.normal[2] > 0.7)
+ {
+ 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->fields.server->flags = (int)ent->fields.server->flags & ~FL_ONGROUND;
}
}
-
+
// check for in water
SV_CheckWaterTransition (ent);
}
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)
{
- qboolean hitsound;
-
-// freefall if not onground
- 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)))
{
- if (ent->v.velocity[2] < sv_gravity.value*-0.1)
- hitsound = true;
+ if (flags & FL_ONGROUND)
+ {
+ // freefall if onground and moving upward
+ // freefall if not standing on a world surface (it may be a lift or trap door)
+ if ((ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer) || ent->fields.server->groundentity)
+ {
+ ent->fields.server->flags -= FL_ONGROUND;
+ SV_AddGravity(ent);
+ SV_CheckVelocity(ent);
+ SV_FlyMove(ent, sv.frametime, NULL);
+ SV_LinkEdict(ent, true);
+ }
+ }
else
- hitsound = false;
+ {
+ // 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, host_frametime, NULL);
- SV_LinkEdict (ent, true);
+ SV_AddGravity(ent);
+ SV_CheckVelocity(ent);
+ SV_FlyMove(ent, sv.frametime, NULL);
+ SV_LinkEdict(ent, true);
- if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
- {
- if (hitsound)
- 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);
+ 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
================
*/
-extern dfunction_t *EndFrameQC;
void SV_Physics (void)
{
- int i;
- 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");
-
-//SV_CheckAllEnts ();
+ 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");
//
// treat each object in turn
//
- ent = sv.edicts;
- for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
- {
- if (ent->free)
- continue;
- if (pr_global_struct->force_retouch)
- SV_LinkEdict (ent, true); // force retouch even for stationary
+ // 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
- if (i > 0 && i <= svs.maxclients)
+ // 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->priv.server->free)
{
- SV_Physics_Client (ent, i);
- continue;
- }
-
- switch ((int) ent->v.movetype)
- {
- case MOVETYPE_PUSH:
- SV_Physics_Pusher (ent);
- break;
- case MOVETYPE_NONE:
- SV_Physics_None (ent);
- break;
- case MOVETYPE_FOLLOW:
- SV_Physics_Follow (ent);
- break;
- case MOVETYPE_NOCLIP:
- SV_Physics_Noclip (ent);
- break;
- case MOVETYPE_STEP:
- SV_Physics_Step (ent);
- break;
- // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
- case MOVETYPE_WALK:
- if (SV_RunThink (ent))
- {
- 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_FLY:
- case MOVETYPE_FLYMISSILE:
- SV_Physics_Toss (ent);
- 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->clmovement_skipphysicsframes > 0)
+ host_client->clmovement_skipphysicsframes--;
+ else
+ SV_Physics_ClientEntity(ent);
}
}
-
- if (pr_global_struct->force_retouch)
- pr_global_struct->force_retouch--;
+
+ // 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 (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), "");
+ 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");
}
- sv.time += host_frametime;
+ // 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 *ent, edict_t *ignore)
+trace_t SV_Trace_Toss (prvm_edict_t *tossent, prvm_edict_t *ignore)
{
int i;
- edict_t tempent, *tent;
- trace_t trace;
- vec3_t move;
- vec3_t end;
- double save_frametime;
-
- save_frametime = host_frametime;
- host_frametime = 0.05;
-
- memcpy(&tempent, ent, sizeof(edict_t));
- tent = &tempent;
+ float gravity;
+ vec3_t move, end;
+ vec3_t original_origin;
+ vec3_t original_velocity;
+ vec3_t original_angles;
+ vec3_t original_avelocity;
+ prvm_eval_t *val;
+ trace_t trace;
+
+ 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);
+
+ val = PRVM_GETEDICTFIELDVALUE(tossent, eval_gravity);
+ if (val != NULL && val->_float != 0)
+ gravity = val->_float;
+ else
+ gravity = 1.0;
+ gravity *= sv_gravity.value * 0.05;
for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
{
- SV_CheckVelocity (tent);
- SV_AddGravity (tent);
- VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
- VectorScale (tent->v.velocity, host_frametime, 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.ent)
- if (trace.ent != ignore)
- break;
+ 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;
}
- host_frametime = save_frametime;
+
+ 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;
}
+