// sv_phys.c
#include "quakedef.h"
+#include "prvm_cmds.h"
/*
void SV_Physics_Toss (prvm_edict_t *ent);
-int SV_GetPitchSign(prvm_edict_t *ent)
+int SV_GetPitchSign(prvm_prog_t *prog, prvm_edict_t *ent)
{
- dp_model_t *model;
+ model_t *model;
if (
(model = SV_GetModelFromEdict(ent))
?
int SV_GenericHitSuperContentsMask(const prvm_edict_t *passedict)
{
+ prvm_prog_t *prog = SVVM_prog;
if (passedict)
{
int dphitcontentsmask = (int)PRVM_serveredictfloat(passedict, dphitcontentsmask);
SV_TracePoint
==================
*/
-trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+trace_t SV_TracePoint(const vec3_t start, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
{
+ prvm_prog_t *prog = SVVM_prog;
int i, bodysupercontents;
int passedictprog;
float pitchsign = 1;
prvm_edict_t *traceowner, *touch;
trace_t trace;
+ // temporary storage because prvm_vec_t may differ from vec_t
+ vec3_t touchmins, touchmaxs;
// bounding box of entire move area
vec3_t clipboxmins, clipboxmaxs;
// size when clipping against monsters
// matrices to transform into/out of other entity's space
matrix4x4_t matrix, imatrix;
// model of other entity
- dp_model_t *model;
+ model_t *model;
// list of entities to test for collisions
int numtouchedicts;
static prvm_edict_t *touchedicts[MAX_EDICTS];
+ int clipgroup;
- //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
+ //return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
VectorCopy(start, clipstart);
VectorClear(clipmins2);
#endif
// clip to world
- Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask);
- cliptrace.bmodelstartsolid = cliptrace.startsolid;
+ Collision_ClipPointToWorld(&cliptrace, sv.worldmodel, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
+ cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
if (cliptrace.startsolid || cliptrace.fraction < 1)
cliptrace.ent = prog->edicts;
if (type == MOVE_WORLDONLY)
if (type == MOVE_MISSILE)
{
- // LordHavoc: modified this, was = -15, now -= 15
+ // LadyHavoc: modified this, was = -15, now -= 15
for (i = 0;i < 3;i++)
{
clipmins2[i] -= 15;
// debug override to test against everything
if (sv_debugmove.integer)
{
- clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
- clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
+ clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+ clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
}
// if the passedict is world, make it NULL (to avoid two checks each time)
// precalculate passedict's owner edict pointer for comparisons
traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
+ clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
+
// clip to entities
// because this uses World_EntitiestoBox, we know all entity boxes overlap
// the clip region, so we can skip culling checks in the loop below
// don't clip owner against owned entities
if (passedictprog == PRVM_serveredictedict(touch, owner))
continue;
+ // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+ if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
+ continue;
// don't clip points against points (they can't collide)
if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
continue;
if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
{
model = SV_GetModelFromEdict(touch);
- pitchsign = SV_GetPitchSign(touch);
+ pitchsign = SV_GetPitchSign(prog, touch);
}
if (model)
Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
else
Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
Matrix4x4_Invert_Simple(&imatrix, &matrix);
- VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
- VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
- VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+ VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
+ VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
+ VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
+ VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
+ VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
- Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask);
+ Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, 0.0f);
else
- Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask);
+ Collision_ClipPointToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
}
SV_TraceLine
==================
*/
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
-trace_t SV_TraceLine(const vec3_t start, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#else
-trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#endif
+trace_t SV_TraceLine(const vec3_t start, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
{
+ prvm_prog_t *prog = SVVM_prog;
int i, bodysupercontents;
int passedictprog;
float pitchsign = 1;
prvm_edict_t *traceowner, *touch;
trace_t trace;
+ // temporary storage because prvm_vec_t may differ from vec_t
+ vec3_t touchmins, touchmaxs;
// bounding box of entire move area
vec3_t clipboxmins, clipboxmaxs;
// size when clipping against monsters
// matrices to transform into/out of other entity's space
matrix4x4_t matrix, imatrix;
// model of other entity
- dp_model_t *model;
+ model_t *model;
// list of entities to test for collisions
int numtouchedicts;
static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
- vec3_t end;
- vec_t len = 0;
-
- if (VectorCompare(start, pEnd))
- return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
-
- if(collision_endposnudge.value > 0)
- {
- // TRICK: make the trace 1 qu longer!
- VectorSubtract(pEnd, start, end);
- len = VectorNormalizeLength(end);
- VectorMA(pEnd, collision_endposnudge.value, end, end);
- }
- else
- VectorCopy(pEnd, end);
-#else
+ int clipgroup;
if (VectorCompare(start, end))
- return SV_TracePoint(start, type, passedict, hitsupercontentsmask);
-#endif
+ return SV_TracePoint(start, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
//return SV_TraceBox(start, vec3_origin, vec3_origin, end, type, passedict, hitsupercontentsmask);
#endif
// clip to world
- Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, false);
- cliptrace.bmodelstartsolid = cliptrace.startsolid;
+ Collision_ClipLineToWorld(&cliptrace, sv.worldmodel, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, false);
+ cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
if (cliptrace.startsolid || cliptrace.fraction < 1)
cliptrace.ent = prog->edicts;
if (type == MOVE_WORLDONLY)
if (type == MOVE_MISSILE)
{
- // LordHavoc: modified this, was = -15, now -= 15
+ // LadyHavoc: modified this, was = -15, now -= 15
for (i = 0;i < 3;i++)
{
clipmins2[i] -= 15;
// debug override to test against everything
if (sv_debugmove.integer)
{
- clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
- clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
+ clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+ clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
}
// if the passedict is world, make it NULL (to avoid two checks each time)
// precalculate passedict's owner edict pointer for comparisons
traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
+ clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
+
// clip to entities
// because this uses World_EntitiestoBox, we know all entity boxes overlap
// the clip region, so we can skip culling checks in the loop below
// don't clip owner against owned entities
if (passedictprog == PRVM_serveredictedict(touch, owner))
continue;
+ // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+ if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
+ continue;
// don't clip points against points (they can't collide)
if (VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
continue;
if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
{
model = SV_GetModelFromEdict(touch);
- pitchsign = SV_GetPitchSign(touch);
+ pitchsign = SV_GetPitchSign(prog, touch);
}
if (model)
Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
else
Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
Matrix4x4_Invert_Simple(&imatrix, &matrix);
- VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
- VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
- VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+ VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
+ VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
+ VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
+ VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
+ VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
- Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+ Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
else
- Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, false);
+ Collision_ClipLineToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend, false);
Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
}
finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
- if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
- Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
return cliptrace;
}
SV_Move
==================
*/
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
#if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+static trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
#else
-trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#endif
-#else
-#if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#else
-trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
-#endif
+trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
#endif
{
+ prvm_prog_t *prog = SVVM_prog;
vec3_t hullmins, hullmaxs;
int i, bodysupercontents;
int passedictprog;
float pitchsign = 1;
- qboolean pointtrace;
+ qbool pointtrace;
prvm_edict_t *traceowner, *touch;
trace_t trace;
+ // temporary storage because prvm_vec_t may differ from vec_t
+ vec3_t touchmins, touchmaxs;
// bounding box of entire move area
vec3_t clipboxmins, clipboxmaxs;
// size of the moving object
// matrices to transform into/out of other entity's space
matrix4x4_t matrix, imatrix;
// model of other entity
- dp_model_t *model;
+ model_t *model;
// list of entities to test for collisions
int numtouchedicts;
static prvm_edict_t *touchedicts[MAX_EDICTS];
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
- vec3_t end;
- vec_t len = 0;
-
- if (VectorCompare(mins, maxs))
- {
- vec3_t shiftstart, shiftend;
- VectorAdd(start, mins, shiftstart);
- VectorAdd(pEnd, mins, shiftend);
- if (VectorCompare(start, pEnd))
- trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
- else
- trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
- VectorSubtract(trace.endpos, mins, trace.endpos);
- return trace;
- }
-
- if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
- {
- // TRICK: make the trace 1 qu longer!
- VectorSubtract(pEnd, start, end);
- len = VectorNormalizeLength(end);
- VectorMA(pEnd, collision_endposnudge.value, end, end);
- }
- else
- VectorCopy(pEnd, end);
-#else
+ int clipgroup;
if (VectorCompare(mins, maxs))
{
vec3_t shiftstart, shiftend;
VectorAdd(start, mins, shiftstart);
VectorAdd(end, mins, shiftend);
if (VectorCompare(start, end))
- trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask);
+ trace = SV_TracePoint(shiftstart, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
else
- trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask);
+ trace = SV_TraceLine(shiftstart, shiftend, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
VectorSubtract(trace.endpos, mins, trace.endpos);
return trace;
}
-#endif
VectorCopy(start, clipstart);
VectorCopy(end, clipend);
#endif
// clip to world
- Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
- cliptrace.bmodelstartsolid = cliptrace.startsolid;
+ Collision_ClipToWorld(&cliptrace, sv.worldmodel, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
+ cliptrace.worldstartsolid = cliptrace.bmodelstartsolid = cliptrace.startsolid;
if (cliptrace.startsolid || cliptrace.fraction < 1)
cliptrace.ent = prog->edicts;
if (type == MOVE_WORLDONLY)
if (type == MOVE_MISSILE)
{
- // LordHavoc: modified this, was = -15, now -= 15
+ // LadyHavoc: modified this, was = -15, now -= 15
for (i = 0;i < 3;i++)
{
clipmins2[i] -= 15;
// debug override to test against everything
if (sv_debugmove.integer)
{
- clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = -999999999;
- clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = 999999999;
+ clipboxmins[0] = clipboxmins[1] = clipboxmins[2] = (vec_t)-999999999;
+ clipboxmaxs[0] = clipboxmaxs[1] = clipboxmaxs[2] = (vec_t)999999999;
}
// if the passedict is world, make it NULL (to avoid two checks each time)
// precalculate passedict's owner edict pointer for comparisons
traceowner = passedict ? PRVM_PROG_TO_EDICT(PRVM_serveredictedict(passedict, owner)) : 0;
+ clipgroup = passedict ? (int)PRVM_serveredictfloat(passedict, clipgroup) : 0;
+
// clip to entities
// because this uses World_EntitiestoBox, we know all entity boxes overlap
// the clip region, so we can skip culling checks in the loop below
// don't clip owner against owned entities
if (passedictprog == PRVM_serveredictedict(touch, owner))
continue;
+ // don't clip against any entities in the same clipgroup (DP_RM_CLIPGROUP)
+ if (clipgroup && clipgroup == (int)PRVM_serveredictfloat(touch, clipgroup))
+ continue;
// don't clip points against points (they can't collide)
if (pointtrace && VectorCompare(PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs)) && (type != MOVE_MISSILE || !((int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)))
continue;
if ((int) PRVM_serveredictfloat(touch, solid) == SOLID_BSP || type == MOVE_HITMODEL)
{
model = SV_GetModelFromEdict(touch);
- pitchsign = SV_GetPitchSign(touch);
+ pitchsign = SV_GetPitchSign(prog, touch);
}
if (model)
Matrix4x4_CreateFromQuakeEntity(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2], pitchsign * PRVM_serveredictvector(touch, angles)[0], PRVM_serveredictvector(touch, angles)[1], PRVM_serveredictvector(touch, angles)[2], 1);
else
Matrix4x4_CreateTranslate(&matrix, PRVM_serveredictvector(touch, origin)[0], PRVM_serveredictvector(touch, origin)[1], PRVM_serveredictvector(touch, origin)[2]);
Matrix4x4_Invert_Simple(&imatrix, &matrix);
- VM_GenerateFrameGroupBlend(touch->priv.server->framegroupblend, touch);
- VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model);
- VM_UpdateEdictSkeleton(touch, model, touch->priv.server->frameblend);
+ VM_GenerateFrameGroupBlend(prog, touch->priv.server->framegroupblend, touch);
+ VM_FrameBlendFromFrameGroupBlend(touch->priv.server->frameblend, touch->priv.server->framegroupblend, model, sv.time);
+ VM_UpdateEdictSkeleton(prog, touch, model, touch->priv.server->frameblend);
+ VectorCopy(PRVM_serveredictvector(touch, mins), touchmins);
+ VectorCopy(PRVM_serveredictvector(touch, maxs), touchmaxs);
if (type == MOVE_MISSILE && (int)PRVM_serveredictfloat(touch, flags) & FL_MONSTER)
- Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask);
+ Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins2, clipmaxs2, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
else
- Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, PRVM_serveredictvector(touch, mins), PRVM_serveredictvector(touch, maxs), bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask);
+ Collision_ClipToGenericEntity(&trace, model, touch->priv.server->frameblend, &touch->priv.server->skeleton, touchmins, touchmaxs, bodysupercontents, &matrix, &imatrix, clipstart, clipmins, clipmaxs, clipend, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
Collision_CombineTraces(&cliptrace, &trace, (void *)touch, PRVM_serveredictfloat(touch, solid) == SOLID_BSP);
}
finished:
-#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
- if(!VectorCompare(start, pEnd) && collision_endposnudge.value > 0)
- Collision_ShortenTrace(&cliptrace, len / (len + collision_endposnudge.value), pEnd);
-#endif
return cliptrace;
}
#if COLLISIONPARANOID >= 1
-trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+trace_t SV_TraceBox(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int type, prvm_edict_t *passedict, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float extend)
{
+ prvm_prog_t *prog = SVVM_prog;
int endstuck;
trace_t trace;
vec3_t temp;
- trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask);
+ trace = SV_TraceBox_(start, mins, maxs, end, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend);
if (passedict)
{
VectorCopy(trace.endpos, temp);
- endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask).startsolid;
+ endstuck = SV_TraceBox_(temp, mins, maxs, temp, type, passedict, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, extend).startsolid;
#if COLLISIONPARANOID < 3
if (trace.startsolid || endstuck)
#endif
int SV_PointSuperContents(const vec3_t point)
{
+ prvm_prog_t *prog = SVVM_prog;
int supercontents = 0;
int i;
prvm_edict_t *touch;
// matrices to transform into/out of other entity's space
matrix4x4_t matrix, imatrix;
// model of other entity
- dp_model_t *model;
+ model_t *model;
int frame;
// list of entities to test for collisions
int numtouchedicts;
int SV_EntitiesInBox(const vec3_t mins, const vec3_t maxs, int maxedicts, prvm_edict_t **resultedicts)
{
+ prvm_prog_t *prog = SVVM_prog;
vec3_t paddedmins, paddedmaxs;
if (maxedicts < 1 || resultedicts == NULL)
return 0;
- VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
- VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
+ // LadyHavoc: discovered this actually causes its own bugs (dm6 teleporters being too close to info_teleport_destination)
+ //VectorSet(paddedmins, mins[0] - 10, mins[1] - 10, mins[2] - 1);
+ //VectorSet(paddedmaxs, maxs[0] + 10, maxs[1] + 10, maxs[2] + 1);
+ VectorCopy(mins, paddedmins);
+ VectorCopy(maxs, paddedmaxs);
if (sv_areadebug.integer)
{
int numresultedicts = 0;
for (edictindex = 1;edictindex < prog->num_edicts;edictindex++)
{
ed = PRVM_EDICT_NUM(edictindex);
- if (!ed->priv.required->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
+ if (!ed->free && BoxesOverlap(PRVM_serveredictvector(ed, absmin), PRVM_serveredictvector(ed, absmax), paddedmins, paddedmaxs))
{
resultedicts[numresultedicts++] = ed;
if (numresultedicts == maxedicts)
void SV_LinkEdict_TouchAreaGrid_Call(prvm_edict_t *touch, prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(touch);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(ent);
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobalfloat(trace_dphitcontents) = 0;
PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
PRVM_serverglobalstring(trace_dphittexturename) = 0;
- PRVM_ExecuteProgram (PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(touch, touch), "QC function self.touch is missing");
}
void SV_LinkEdict_TouchAreaGrid(prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int i, numtouchedicts, old_self, old_other;
prvm_edict_t *touch;
static prvm_edict_t *touchedicts[MAX_EDICTS];
if (ent == prog->edicts)
return; // don't add the world
- if (ent->priv.server->free)
+ if (ent->free)
return;
if (PRVM_serveredictfloat(ent, solid) == SOLID_NOT)
v[0] = mins[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
VectorCopy(u, rotatedmins); VectorCopy(u, rotatedmaxs);
v[0] = maxs[0]; v[1] = mins[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = mins[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = maxs[0]; v[1] = maxs[1]; v[2] = mins[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = mins[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = maxs[0]; v[1] = mins[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = mins[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
v[0] = maxs[0]; v[1] = maxs[1]; v[2] = maxs[2]; Matrix4x4_Transform(&m, v, u);
- if(rotatedmins[0] > u[0]) rotatedmins[0] = u[0]; if(rotatedmins[1] > u[1]) rotatedmins[1] = u[1]; if(rotatedmins[2] > u[2]) rotatedmins[2] = u[2];
- if(rotatedmaxs[0] < u[0]) rotatedmaxs[0] = u[0]; if(rotatedmaxs[1] < u[1]) rotatedmaxs[1] = u[1]; if(rotatedmaxs[2] < u[2]) rotatedmaxs[2] = u[2];
+ if(rotatedmins[0] > u[0]) { rotatedmins[0] = u[0]; } if(rotatedmins[1] > u[1]) { rotatedmins[1] = u[1]; } if(rotatedmins[2] > u[2]) { rotatedmins[2] = u[2]; }
+ if(rotatedmaxs[0] < u[0]) { rotatedmaxs[0] = u[0]; } if(rotatedmaxs[1] < u[1]) { rotatedmaxs[1] = u[1]; } if(rotatedmaxs[2] < u[2]) { rotatedmaxs[2] = u[2]; }
}
/*
*/
void SV_LinkEdict (prvm_edict_t *ent)
{
- dp_model_t *model;
- vec3_t mins, maxs;
+ prvm_prog_t *prog = SVVM_prog;
+ model_t *model;
+ vec3_t mins, maxs, entmins, entmaxs, entangles;
int modelindex;
if (ent == prog->edicts)
return; // don't add the world
- if (ent->priv.server->free)
+ if (ent->free)
return;
modelindex = (int)PRVM_serveredictfloat(ent, modelindex);
}
model = SV_GetModelByIndex(modelindex);
- VM_GenerateFrameGroupBlend(ent->priv.server->framegroupblend, ent);
- VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model);
- VM_UpdateEdictSkeleton(ent, model, ent->priv.server->frameblend);
+ VM_GenerateFrameGroupBlend(prog, ent->priv.server->framegroupblend, ent);
+ VM_FrameBlendFromFrameGroupBlend(ent->priv.server->frameblend, ent->priv.server->framegroupblend, model, sv.time);
+ VM_UpdateEdictSkeleton(prog, ent, model, ent->priv.server->frameblend);
// set the abs box
{
// TODO maybe should do this for rotating SOLID_BSP too? Would behave better with rotating doors
// TODO special handling for spheres?
- RotateBBox(PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, angles), mins, maxs);
+ VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
+ VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
+ VectorCopy(PRVM_serveredictvector(ent, angles), entangles);
+ RotateBBox(entmins, entmaxs, entangles, mins, maxs);
VectorAdd(PRVM_serveredictvector(ent, origin), mins, mins);
VectorAdd(PRVM_serveredictvector(ent, origin), maxs, maxs);
}
VectorAdd(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, maxs), maxs);
}
-//
-// to make items easier to pick up and allow them to be grabbed off
-// of shelves, the abs sizes are expanded
-//
- if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
+ if (sv_legacy_bbox_expand.integer)
{
- mins[0] -= 15;
- mins[1] -= 15;
- mins[2] -= 1;
- maxs[0] += 15;
- maxs[1] += 15;
- maxs[2] += 1;
- }
- else
- {
- // because movement is clipped an epsilon away from an actual edge,
- // we must fully check even when bounding boxes don't quite touch
- mins[0] -= 1;
- mins[1] -= 1;
- mins[2] -= 1;
- maxs[0] += 1;
- maxs[1] += 1;
- maxs[2] += 1;
+ if ((int)PRVM_serveredictfloat(ent, flags) & FL_ITEM)
+ {
+ // to make items easier to pick up and allow them to be grabbed off
+ // of shelves, the abs sizes are expanded
+ mins[0] -= 15;
+ mins[1] -= 15;
+ mins[2] -= 1;
+ maxs[0] += 15;
+ maxs[1] += 15;
+ maxs[2] += 1;
+ }
+ else
+ {
+ // because movement is clipped an epsilon away from an actual edge,
+ // we must fully check even when bounding boxes don't quite touch
+ mins[0] -= 1;
+ mins[1] -= 1;
+ mins[2] -= 1;
+ maxs[0] += 1;
+ maxs[1] += 1;
+ maxs[2] += 1;
+ }
}
VectorCopy(mins, PRVM_serveredictvector(ent, absmin));
VectorCopy(maxs, PRVM_serveredictvector(ent, absmax));
- World_LinkEdict(&sv.world, ent, mins, maxs);
+ World_LinkEdict(&sv.world, ent, mins, maxs, sv_areagrid_link_SOLID_NOT.integer);
}
/*
*/
static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
{
- int contents;
- vec3_t org;
+ prvm_prog_t *prog = SVVM_prog;
+ int hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
+ int skipsupercontentsmask = 0;
+ int skipmaterialflagsmask = 0;
+ vec3_t org, entorigin, entmins, entmaxs;
trace_t trace;
- contents = SV_GenericHitSuperContentsMask(ent);
VectorAdd(PRVM_serveredictvector(ent, origin), offset, org);
- trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, contents);
- if (trace.startsupercontents & contents)
+ VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
+ VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
+ VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
+ trace = SV_TraceBox(org, entmins, entmaxs, entorigin, ((PRVM_serveredictfloat(ent, movetype) == MOVETYPE_FLY_WORLDONLY) ? MOVE_WORLDONLY : MOVE_NOMONSTERS), ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value);
+ if (trace.startsupercontents & hitsupercontentsmask)
return true;
else
{
// FIXME: this breaks entities larger than the hull size
int i;
vec3_t v, m1, m2, s;
- VectorAdd(org, PRVM_serveredictvector(ent, mins), m1);
- VectorAdd(org, PRVM_serveredictvector(ent, maxs), m2);
+ VectorAdd(org, entmins, m1);
+ VectorAdd(org, entmaxs, m2);
VectorSubtract(m2, m1, s);
#define EPSILON (1.0f / 32.0f)
if (s[0] >= EPSILON*2) {m1[0] += EPSILON;m2[0] -= EPSILON;}
v[0] = (i & 1) ? m2[0] : m1[0];
v[1] = (i & 2) ? m2[1] : m1[1];
v[2] = (i & 4) ? m2[2] : m1[2];
- if (SV_PointSuperContents(v) & contents)
+ if (SV_PointSuperContents(v) & hitsupercontentsmask)
return true;
}
}
#else
// verify if the endpos is REALLY outside solid
VectorCopy(trace.endpos, org);
- trace = SV_TraceBox(org, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), org, MOVE_NOMONSTERS, ent, contents);
+ trace = SV_TraceBox(org, entmins, entmaxs, org, MOVE_NOMONSTERS, ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value);
if(trace.startsolid)
Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
else
return false;
}
-/*
-================
-SV_CheckAllEnts
-================
-*/
-void SV_CheckAllEnts (void)
-{
- int e;
- prvm_edict_t *check;
-
- // see if any solid entities are inside the final position
- check = PRVM_NEXT_EDICT(prog->edicts);
- for (e = 1;e < prog->num_edicts;e++, check = PRVM_NEXT_EDICT(check))
- {
- if (check->priv.server->free)
- continue;
- if (PRVM_serveredictfloat(check, movetype) == MOVETYPE_PUSH
- || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NONE
- || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FOLLOW
- || PRVM_serveredictfloat(check, movetype) == MOVETYPE_NOCLIP
- || PRVM_serveredictfloat(check, movetype) == MOVETYPE_FLY_WORLDONLY)
- continue;
-
- if (SV_TestEntityPosition (check, vec3_origin))
- Con_Print("entity in invalid position\n");
- }
-}
-
// DRESK - Support for Entity Contents Transition Event
/*
================
returns true if entity had a valid contentstransition function call
================
*/
-int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
+static int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
{
+ prvm_prog_t *prog = SVVM_prog;
int bValidFunctionCall;
// Default Valid Function Call to False
// Assign Valid Function
bValidFunctionCall = true;
// Prepare Parameters (Original Contents, New Contents)
- // Original Contents
- PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
- // New Contents
- PRVM_G_FLOAT(OFS_PARM1) = nContents;
- // Assign Self
- PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+ // Original Contents
+ PRVM_G_FLOAT(OFS_PARM0) = PRVM_serveredictfloat(ent, watertype);
+ // New Contents
+ PRVM_G_FLOAT(OFS_PARM1) = nContents;
+ // Assign Self
+ PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+ // Set Time
+ PRVM_serverglobalfloat(time) = sv.time;
// Execute VM Function
- PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, contentstransition), "contentstransition: NULL function");
}
}
*/
void SV_CheckVelocity (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int i;
float wishspeed;
//
for (i=0 ; i<3 ; i++)
{
- if (IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
+ if (PRVM_IS_NAN(PRVM_serveredictvector(ent, velocity)[i]))
{
- Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+ Con_Printf("Got a NaN velocity on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
PRVM_serveredictvector(ent, velocity)[i] = 0;
}
- if (IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
+ if (PRVM_IS_NAN(PRVM_serveredictvector(ent, origin)[i]))
{
- Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+ Con_Printf("Got a NaN origin on entity #%i (%s)\n", PRVM_NUM_FOR_EDICT(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
PRVM_serveredictvector(ent, origin)[i] = 0;
}
}
- // LordHavoc: a hack to ensure that the (rather silly) id1 quakec
+ // LadyHavoc: a hack to ensure that the (rather silly) id1 quakec
// player_run/player_stand1 does not horribly malfunction if the
// velocity becomes a denormalized float
- if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0001)
+ if (VectorLength2(PRVM_serveredictvector(ent, velocity)) < 0.0000001)
VectorClear(PRVM_serveredictvector(ent, velocity));
- // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
+ // LadyHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
wishspeed = DotProduct(PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, velocity));
if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
{
Returns false if the entity removed itself.
=============
*/
-qboolean SV_RunThink (prvm_edict_t *ent)
+static qbool SV_RunThink (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int iterations;
// don't let things stay in the past.
if (PRVM_serveredictfloat(ent, nextthink) <= 0 || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime)
return true;
- for (iterations = 0;iterations < 128 && !ent->priv.server->free;iterations++)
+ for (iterations = 0;iterations < 128 && !ent->free;iterations++)
{
PRVM_serverglobalfloat(time) = max(sv.time, PRVM_serveredictfloat(ent, nextthink));
PRVM_serveredictfloat(ent, nextthink) = 0;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
- PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
// mods often set nextthink to time to cause a think every frame,
// we don't want to loop in that case, so exit if the new nextthink is
// <= the time the qc was told, also exit if it is past the end of the
if (PRVM_serveredictfloat(ent, nextthink) <= PRVM_serverglobalfloat(time) || PRVM_serveredictfloat(ent, nextthink) > sv.time + sv.frametime || !sv_gameplayfix_multiplethinksperframe.integer)
break;
}
- return !ent->priv.server->free;
+ return !ent->free;
}
/*
Two entities have touched, so run their touch functions
==================
*/
-extern void VM_SetTraceGlobals(const trace_t *trace);
-extern sizebuf_t vm_tempstringsbuf;
-void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+static void SV_Impact (prvm_edict_t *e1, trace_t *trace)
{
+ prvm_prog_t *prog = SVVM_prog;
int restorevm_tempstringsbuf_cursize;
int old_self, old_other;
prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
old_self = PRVM_serverglobaledict(self);
old_other = PRVM_serverglobaledict(other);
- restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ restorevm_tempstringsbuf_cursize = prog->tempstringsbuf.cursize;
- VM_SetTraceGlobals(trace);
+ VM_SetTraceGlobals(prog, trace);
- PRVM_serverglobalfloat(time) = sv.time;
- if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
+ if (!e1->free && !e2->free && PRVM_serveredictfunction(e1, touch) && PRVM_serveredictfloat(e1, solid) != SOLID_NOT)
{
+ PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e1);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e2);
- PRVM_ExecuteProgram (PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(e1, touch), "QC function self.touch is missing");
}
- if (!e1->priv.server->free && !e2->priv.server->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
+ if (!e1->free && !e2->free && PRVM_serveredictfunction(e2, touch) && PRVM_serveredictfloat(e2, solid) != SOLID_NOT)
{
+ PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(e2);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(e1);
VectorCopy(PRVM_serveredictvector(e2, origin), PRVM_serverglobalvector(trace_endpos));
PRVM_serverglobalfloat(trace_dphitcontents) = 0;
PRVM_serverglobalfloat(trace_dphitq3surfaceflags) = 0;
PRVM_serverglobalstring(trace_dphittexturename) = 0;
- PRVM_ExecuteProgram (PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(e2, touch), "QC function self.touch is missing");
}
PRVM_serverglobaledict(self) = old_self;
PRVM_serverglobaledict(other) = old_other;
- vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+ prog->tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
}
==================
*/
#define STOP_EPSILON 0.1
-void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+static void ClipVelocity (prvm_vec3_t in, vec3_t normal, prvm_vec3_t out, prvm_vec_t overbounce)
{
int i;
float backoff;
============
*/
static float SV_Gravity (prvm_edict_t *ent);
-static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink, qbool checkstuck);
#define MAX_CLIP_PLANES 5
-static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask, float stepheight)
+static int SV_FlyMove (prvm_edict_t *ent, float time, qbool applygravity, float *stepnormal, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, float stepheight)
{
+ prvm_prog_t *prog = SVVM_prog;
int blocked, bumpcount;
int i, j, numplanes;
float d, time_left, gravity;
- vec3_t dir, push, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
+ vec3_t dir, push, planes[MAX_CLIP_PLANES];
+ prvm_vec3_t primal_velocity, original_velocity, new_velocity, restore_velocity;
#if 0
vec3_t end;
#endif
return 0;
gravity = 0;
- if(sv_gameplayfix_nogravityonground.integer)
- if((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
- applygravity = false;
+ VectorCopy(PRVM_serveredictvector(ent, velocity), restore_velocity);
- if (applygravity)
+ if(applygravity)
{
- if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
- {
- gravity = SV_Gravity(ent) * 0.5f;
- PRVM_serveredictvector(ent, velocity)[2] -= gravity;
- }
- else
+ gravity = SV_Gravity(ent);
+
+ if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
{
- applygravity = false;
- PRVM_serveredictvector(ent, velocity)[2] -= SV_Gravity(ent);
+ if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
+ PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
+ else
+ PRVM_serveredictvector(ent, velocity)[2] -= gravity;
}
}
+
blocked = 0;
VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
VectorCopy(PRVM_serveredictvector(ent, velocity), primal_velocity);
break;
VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
- if(!SV_PushEntity(&trace, ent, push, false, false))
+ if(!SV_PushEntity(&trace, ent, push, false, true))
{
// we got teleported by a touch function
// let's abort the move
break;
}
+ // this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
+ // abort move if we're stuck in the world (and didn't make it out)
+ if (trace.worldstartsolid && trace.allsolid && trace.startdepth < 0)
+ {
+ VectorCopy(restore_velocity, PRVM_serveredictvector(ent, velocity));
+ return 3;
+ }
+
if (trace.fraction == 1)
break;
+
+ time_left *= 1 - trace.fraction;
+
if (trace.plane.normal[2])
{
if (trace.plane.normal[2] > 0.7)
trace_t steptrace3;
//Con_Printf("step %f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
VectorSet(steppush, 0, 0, stepheight);
+ VectorScale(PRVM_serveredictvector(ent, velocity), time_left, push);
VectorCopy(PRVM_serveredictvector(ent, origin), org);
- if(!SV_PushEntity(&steptrace, ent, steppush, false, false))
+ if(!SV_PushEntity(&steptrace, ent, steppush, false, true))
{
blocked |= 8;
break;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
- if(!SV_PushEntity(&steptrace2, ent, push, false, false))
+ if(!SV_PushEntity(&steptrace2, ent, push, false, true))
{
blocked |= 8;
break;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
VectorSet(steppush, 0, 0, org[2] - PRVM_serveredictvector(ent, origin)[2]);
- if(!SV_PushEntity(&steptrace3, ent, steppush, false, false))
+ if(!SV_PushEntity(&steptrace3, ent, steppush, false, true))
{
blocked |= 8;
break;
}
//Con_Printf("%f %f %f : ", PRVM_serveredictvector(ent, origin)[0], PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
// accept the new position if it made some progress...
- if (fabs(PRVM_serveredictvector(ent, origin)[0] - org[0]) >= 0.03125 || fabs(PRVM_serveredictvector(ent, origin)[1] - org[1]) >= 0.03125)
+ // previously this checked if absolute distance >= 0.03125 which made stepping up unreliable
+ if (PRVM_serveredictvector(ent, origin)[0] - org[0] || PRVM_serveredictvector(ent, origin)[1] - org[1])
{
//Con_Printf("accepted (delta %f %f %f)\n", PRVM_serveredictvector(ent, origin)[0] - org[0], PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
trace = steptrace2;
if (stepnormal)
VectorCopy(trace.plane.normal, stepnormal);
}
+
+ // Unlike some other movetypes Quake's SV_FlyMove calls SV_Impact only after setting ONGROUND which id1 fiends rely on.
+ // If we stepped up (sv_gameplayfix_stepmultipletimes) this will impact the steptrace2 plane instead of the original.
+ if (PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace.ent)
+ SV_Impact(ent, &trace);
+ if (ent->free)
+ return blocked; // removed by the impact function
+
if (trace.fraction >= 0.001)
{
// actually covered some distance
numplanes = 0;
}
- time_left *= 1 - trace.fraction;
-
// clipped to another plane
if (numplanes >= MAX_CLIP_PLANES)
{
break;
}
CrossProduct(planes[0], planes[1], dir);
- // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
+ // LadyHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
VectorNormalize(dir);
d = DotProduct(dir, PRVM_serveredictvector(ent, velocity));
VectorScale(dir, d, PRVM_serveredictvector(ent, velocity));
/*
if ((blocked & 1) == 0 && bumpcount > 1)
{
- // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
+ // LadyHavoc: fix the 'fall to your death in a wedge corner' glitch
// flag ONGROUND if there's ground under it
- trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask);
+ trace = SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), end, MOVE_NORMAL, ent, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
}
*/
- // LordHavoc: this came from QW and allows you to get out of water more easily
+ // LadyHavoc: this came from QW and allows you to get out of water more easily
if (sv_gameplayfix_easierwaterjump.integer && ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP) && !(blocked & 8))
VectorCopy(primal_velocity, PRVM_serveredictvector(ent, velocity));
- if (applygravity && !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
- PRVM_serveredictvector(ent, velocity)[2] -= gravity;
+
+ if(applygravity)
+ {
+ if(!sv_gameplayfix_nogravityonground.integer || !((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
+ {
+ if (sv_gameplayfix_gravityunaffectedbyticrate.integer)
+ PRVM_serveredictvector(ent, velocity)[2] -= gravity * 0.5f;
+ }
+ }
+
return blocked;
}
*/
static float SV_Gravity (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
float ent_gravity;
ent_gravity = PRVM_serveredictfloat(ent, gravity);
===============================================================================
*/
-static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
+static qbool SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
{
+ prvm_prog_t *prog = SVVM_prog;
int bump;
trace_t stucktrace;
vec3_t stuckorigin;
testorigin[coord] += stuckmins[coord] - goodmins[coord];
}
- stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+ stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
if (stucktrace.bmodelstartsolid)
{
// BAD BAD, can't fix that
return true;
}
-static qboolean SV_NudgeOutOfSolid(prvm_edict_t *ent)
-{
- int bump;
- trace_t stucktrace;
- vec3_t stuckorigin;
- vec3_t stuckmins, stuckmaxs;
- vec_t nudge;
- vec_t separation = sv_gameplayfix_nudgeoutofsolid_separation.value;
- if (sv.worldmodel && sv.worldmodel->brushq1.numclipnodes)
- separation = 0.0f; // when using hulls, it can not be enlarged
- VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
- VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
- VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
- stuckmins[0] -= separation;
- stuckmins[1] -= separation;
- stuckmins[2] -= separation;
- stuckmaxs[0] += separation;
- stuckmaxs[1] += separation;
- stuckmaxs[2] += separation;
- for (bump = 0;bump < 10;bump++)
- {
- stucktrace = SV_TraceBox(stuckorigin, stuckmins, stuckmaxs, stuckorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
- if (!stucktrace.bmodelstartsolid || stucktrace.startdepth >= 0)
- {
- // found a good location, use it
- VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
- return true;
- }
- nudge = -stucktrace.startdepth;
- VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
- }
- return false;
-}
-
/*
============
SV_PushEntity
Returns true if the push did not result in the entity being teleported by QC code.
============
*/
-static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
+static qbool SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qbool dolink, qbool checkstuck)
{
+ prvm_prog_t *prog = SVVM_prog;
int solid;
int movetype;
int type;
vec3_t mins, maxs;
- vec3_t original, original_velocity;
vec3_t start;
vec3_t end;
VectorCopy(PRVM_serveredictvector(ent, mins), mins);
VectorCopy(PRVM_serveredictvector(ent, maxs), maxs);
- // move start position out of solids
- if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
- {
- SV_NudgeOutOfSolid(ent);
- }
-
VectorCopy(PRVM_serveredictvector(ent, origin), start);
VectorAdd(start, push, end);
else
type = MOVE_NORMAL;
- *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
- if (trace->bmodelstartsolid && failonbmodelstartsolid)
- return true;
+ *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
+ // abort move if we're stuck in the world (and didn't make it out)
+ if (trace->worldstartsolid && trace->allsolid && trace->startdepth < 0 && checkstuck)
+ {
+ // checking startdepth eliminates many false positives on Q1BSP with mod_q1bsp_polygoncollisions 0
+ // but it's still not guaranteed that we're stuck in a bmodel at this point
+ if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
+ {
+ switch (PHYS_NudgeOutOfSolid(prog, ent))
+ {
+ case 0:
+ Con_Printf(CON_WARN "NudgeOutOfSolid couldn't fix stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
+ return true; // definitely stuck in a bmodel
+ case 1:
+ Con_DPrintf("NudgeOutOfSolid fixed stuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), PRVM_serveredictvector(ent, origin)[0] - start[0], PRVM_serveredictvector(ent, origin)[1] - start[1], PRVM_serveredictvector(ent, origin)[2] - start[2]);
+ VectorCopy(PRVM_serveredictvector(ent, origin), start);
+ VectorAdd(start, push, end);
+ *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
+
+ // definitely not stuck in a bmodel, move may proceed
+ }
+ }
+ else if (sv_gameplayfix_unstickentities.integer && SV_UnstickEntity(ent))
+ {
+ // bones_was_here: pretty sure we can deprecate sv_gameplayfix_unstickentities, sv_gameplayfix_nudgeoutofsolid is much nicer
+ VectorCopy(PRVM_serveredictvector(ent, origin), start);
+ VectorAdd(start, push, end);
+ *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent), 0, 0, collision_extendmovelength.value);
+ }
+ else
+ return true; // assuming stuck, bones_was_here TODO: always use PHYS_NudgeOutOfSolid (remove sv_gameplayfix_nudgeoutofsolid)?
+ }
VectorCopy(trace->endpos, PRVM_serveredictvector(ent, origin));
- VectorCopy(PRVM_serveredictvector(ent, origin), original);
- VectorCopy(PRVM_serveredictvector(ent, velocity), original_velocity);
+ ent->priv.required->mark = PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN; // -2: setorigin running
SV_LinkEdict(ent);
#if 0
if(!trace->startsolid)
- if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
+ if(SV_TraceBox(PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), PRVM_serveredictvector(ent, origin), type, ent, SV_GenericHitSuperContentsMask(ent), 0).startsolid)
{
Con_Printf("something eeeeevil happened\n");
}
#endif
if (dolink)
+ {
SV_LinkEdict_TouchAreaGrid(ent);
- if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
- SV_Impact (ent, trace);
+ if((PRVM_serveredictfloat(ent, solid) >= SOLID_TRIGGER && trace->ent && (!((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND) || PRVM_serveredictedict(ent, groundentity) != PRVM_EDICT_TO_PROG(trace->ent))))
+ SV_Impact (ent, trace);
+ }
- return VectorCompare(PRVM_serveredictvector(ent, origin), original) && VectorCompare(PRVM_serveredictvector(ent, velocity), original_velocity);
+ if(ent->priv.required->mark == PRVM_EDICT_MARK_SETORIGIN_CAUGHT)
+ {
+ ent->priv.required->mark = 0;
+ return false;
+ }
+ else if(ent->priv.required->mark == PRVM_EDICT_MARK_WAIT_FOR_SETORIGIN)
+ {
+ ent->priv.required->mark = 0;
+ return true;
+ }
+ else
+ {
+ Con_Printf("The edict mark had been overwritten! Please debug this.\n");
+ return true;
+ }
}
============
*/
-void SV_PushMove (prvm_edict_t *pusher, float movetime)
+static void SV_PushMove (prvm_edict_t *pusher, float movetime)
{
+ prvm_prog_t *prog = SVVM_prog;
int i, e, index;
int pusherowner, pusherprog;
int checkcontents;
- qboolean rotated;
+ qbool rotated;
float savesolid, movetime2, pushltime;
- vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org;
+ vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, pushermins, pushermaxs, checkorigin, checkmins, checkmaxs;
int num_moved;
int numcheckentities;
static prvm_edict_t *checkentities[MAX_EDICTS];
- dp_model_t *pushermodel;
+ model_t *pushermodel;
trace_t trace, trace2;
matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
static unsigned short moved_edicts[MAX_EDICTS];
switch ((int) PRVM_serveredictfloat(pusher, solid))
{
- // LordHavoc: valid pusher types
+ // LadyHavoc: valid pusher types
case SOLID_BSP:
case SOLID_BBOX:
case SOLID_SLIDEBOX:
- case SOLID_CORPSE: // LordHavoc: this would be weird...
+ case SOLID_CORPSE: // LadyHavoc: this would be weird...
break;
- // LordHavoc: no collisions
+ // LadyHavoc: no collisions
case SOLID_NOT:
case SOLID_TRIGGER:
VectorMA (PRVM_serveredictvector(pusher, origin), movetime, PRVM_serveredictvector(pusher, velocity), PRVM_serveredictvector(pusher, origin));
// final position, move it
if (!((int)PRVM_serveredictfloat(check, flags) & FL_ONGROUND) || PRVM_PROG_TO_EDICT(PRVM_serveredictedict(check, groundentity)) != pusher)
{
- Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
+ VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
+ VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
+ VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
+ VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
+ VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
+ Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, 0, 0, collision_extendmovelength.value);
//trace = SV_TraceBox(PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), MOVE_NOMONSTERS, check, checkcontents);
if (!trace.startsolid)
{
// try moving the contacted entity
PRVM_serveredictfloat(pusher, solid) = SOLID_NOT;
- if(!SV_PushEntity (&trace, check, move, true, true))
+ if(!SV_PushEntity(&trace, check, move, true, true))
{
// entity "check" got teleported
PRVM_serveredictvector(check, angles)[1] += trace.fraction * moveangle[1];
PRVM_serveredictfloat(check, flags) = (int)PRVM_serveredictfloat(check, flags) & ~FL_ONGROUND;
// if it is still inside the pusher, block
- Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, PRVM_serveredictvector(pusher, mins), PRVM_serveredictvector(pusher, maxs), SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, PRVM_serveredictvector(check, origin), PRVM_serveredictvector(check, mins), PRVM_serveredictvector(check, maxs), PRVM_serveredictvector(check, origin), checkcontents);
+ VectorCopy(PRVM_serveredictvector(pusher, mins), pushermins);
+ VectorCopy(PRVM_serveredictvector(pusher, maxs), pushermaxs);
+ VectorCopy(PRVM_serveredictvector(check, origin), checkorigin);
+ VectorCopy(PRVM_serveredictvector(check, mins), checkmins);
+ VectorCopy(PRVM_serveredictvector(check, maxs), checkmaxs);
+ Collision_ClipToGenericEntity(&trace, pushermodel, pusher->priv.server->frameblend, &pusher->priv.server->skeleton, pushermins, pushermaxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, checkorigin, checkmins, checkmaxs, checkorigin, checkcontents, 0, 0, collision_extendmovelength.value);
if (trace.startsolid)
{
vec3_t move2;
// if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
if (PRVM_serveredictfunction(pusher, blocked))
{
+ PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(pusher);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(check);
- PRVM_ExecuteProgram (PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(pusher, blocked), "QC function self.blocked is missing");
}
break;
}
================
*/
-void SV_Physics_Pusher (prvm_edict_t *ent)
+static void SV_Physics_Pusher (prvm_edict_t *ent)
{
- float thinktime, oldltime, movetime;
+ prvm_prog_t *prog = SVVM_prog;
+ prvm_vec_t thinktime, oldltime, movetime;
oldltime = PRVM_serveredictfloat(ent, ltime);
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
- PRVM_ExecuteProgram (PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, think), "QC function self.think is missing");
}
}
}
unstickresult_t;
-unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
+static unstickresult_t SV_UnstickEntityReturnOffset (prvm_edict_t *ent, vec3_t offset)
{
+ prvm_prog_t *prog = SVVM_prog;
int i, maxunstick;
// if not stuck in a bmodel, just return
return UNSTICK_STUCK;
}
-qboolean SV_UnstickEntity (prvm_edict_t *ent)
+qbool SV_UnstickEntity (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
vec3_t offset;
switch(SV_UnstickEntityReturnOffset(ent, offset))
{
case UNSTICK_GOOD:
return true;
case UNSTICK_UNSTUCK:
- Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+ Con_DPrintf("Unstuck entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
return true;
case UNSTICK_STUCK:
if (developer_extra.integer)
- Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+ Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
return false;
default:
Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
clipping hull.
=============
*/
-void SV_CheckStuck (prvm_edict_t *ent)
+static void SV_CheckStuck (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
vec3_t offset;
switch(SV_UnstickEntityReturnOffset(ent, offset))
VectorCopy (PRVM_serveredictvector(ent, origin), PRVM_serveredictvector(ent, oldorigin));
break;
case UNSTICK_UNSTUCK:
- Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
+ Con_DPrintf("Unstuck player entity %i (classname \"%s\") with offset %f %f %f.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)), offset[0], offset[1], offset[2]);
break;
case UNSTICK_STUCK:
VectorSubtract(PRVM_serveredictvector(ent, oldorigin), PRVM_serveredictvector(ent, origin), offset);
if (!SV_TestEntityPosition(ent, offset))
{
- Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+ Con_DPrintf("Unstuck player entity %i (classname \"%s\") by restoring oldorigin.\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
SV_LinkEdict(ent);
//SV_LinkEdict_TouchAreaGrid(ent);
}
else
- Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(PRVM_serveredictstring(ent, classname)));
+ Con_DPrintf("Stuck player entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(prog, PRVM_serveredictstring(ent, classname)));
break;
default:
Con_Printf("SV_UnstickEntityReturnOffset returned a value outside its enum.\n");
SV_CheckWater
=============
*/
-qboolean SV_CheckWater (prvm_edict_t *ent)
+static qbool SV_CheckWater (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int cont;
int nNativeContents;
vec3_t point;
// Acquire Super Contents Prior to Resets
cont = SV_PointSuperContents(point);
// Acquire Native Contents Here
- nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
+ nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(cont);
// DRESK - Support for Entity Contents Transition Event
if(PRVM_serveredictfloat(ent, watertype))
============
*/
-void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
+static void SV_WallFriction (prvm_edict_t *ent, float *stepnormal)
{
+ prvm_prog_t *prog = SVVM_prog;
float d, i;
- vec3_t forward, into, side;
+ vec3_t forward, into, side, v_angle;
- AngleVectors (PRVM_serveredictvector(ent, v_angle), forward, NULL, NULL);
+ VectorCopy(PRVM_serveredictvector(ent, v_angle), v_angle);
+ AngleVectors (v_angle, forward, NULL, NULL);
if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
{
// cut the tangential velocity
PRVM_serveredictvector(ent, velocity)[0] = oldvel[0];
PRVM_serveredictvector(ent, velocity)[1] = oldvel[1];
PRVM_serveredictvector(ent, velocity)[2] = 0;
- clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent));
+ clip = SV_FlyMove (ent, 0.1, NULL, SV_GenericHitSuperContentsMask(ent), 0);
if (fabs(oldorg[1] - PRVM_serveredictvector(ent, origin)[1]) > 4
|| fabs(oldorg[0] - PRVM_serveredictvector(ent, origin)[0]) > 4)
Only used by players
======================
*/
-void SV_WalkMove (prvm_edict_t *ent)
+static void SV_WalkMove (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int clip;
int oldonground;
//int originalmove_clip;
int originalmove_flags;
int originalmove_groundentity;
- int hitsupercontentsmask;
+ int hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
+ int skipsupercontentsmask = 0;
+ int skipmaterialflagsmask = 0;
int type;
- vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
+ vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity, entmins, entmaxs;
trace_t downtrace, trace;
- qboolean applygravity;
+ qbool applygravity;
// if frametime is 0 (due to client sending the same timestamp twice),
// don't move
applygravity = !SV_CheckWater (ent) && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_WALK && ! ((int)PRVM_serveredictfloat(ent, flags) & FL_WATERJUMP);
- hitsupercontentsmask = SV_GenericHitSuperContentsMask(ent);
-
SV_CheckVelocity(ent);
// do a regular slide move unless it looks like you ran into a step
VectorCopy (PRVM_serveredictvector(ent, origin), start_origin);
VectorCopy (PRVM_serveredictvector(ent, velocity), start_velocity);
- clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
+ clip = SV_FlyMove (ent, sv.frametime, applygravity, NULL, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, sv_gameplayfix_stepmultipletimes.integer ? sv_stepheight.value : 0);
if(sv_gameplayfix_downtracesupportsongroundflag.integer)
if(!(clip & 1))
type = MOVE_NOMONSTERS; // only clip against bmodels
else
type = MOVE_NORMAL;
- trace = SV_TraceBox(upmove, PRVM_serveredictvector(ent, mins), PRVM_serveredictvector(ent, maxs), downmove, type, ent, SV_GenericHitSuperContentsMask(ent));
+ VectorCopy(PRVM_serveredictvector(ent, mins), entmins);
+ VectorCopy(PRVM_serveredictvector(ent, maxs), entmaxs);
+ trace = SV_TraceBox(upmove, entmins, entmaxs, downmove, type, ent, SV_GenericHitSuperContentsMask(ent), skipsupercontentsmask, skipmaterialflagsmask, collision_extendmovelength.value);
if(trace.fraction < 1 && trace.plane.normal[2] > 0.7)
+ {
clip |= 1; // but we HAVE found a floor
+ // set groundentity so we get carried when walking onto a mover with sv_gameplayfix_nogravityonground
+ PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
+ }
}
// if the move did not hit the ground at any point, we're not on ground
if (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_WALK)
return;
- // only step up while jumping if that is enabled
- if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
+ // return if attempting to jump while airborn (unless sv_jumpstep)
+ if (!sv_jumpstep.integer)
if (!oldonground && PRVM_serveredictfloat(ent, waterlevel) == 0)
return;
}
// move up
VectorClear (upmove);
upmove[2] = sv_stepheight.value;
- if(!SV_PushEntity(&trace, ent, upmove, false, true))
+ if(!SV_PushEntity(&trace, ent, upmove, true, true))
{
// we got teleported when upstepping... must abort the move
return;
// move forward
PRVM_serveredictvector(ent, velocity)[2] = 0;
- clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, 0);
+ clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask, 0);
PRVM_serveredictvector(ent, velocity)[2] += start_velocity[2];
if(clip & 8)
{
// move down
VectorClear (downmove);
downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
- if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
+ if(!SV_PushEntity(&downtrace, ent, downmove, true, true))
{
// we got teleported when downstepping... must abort the move
return;
// this has been disabled so that you can't jump when you are stepping
// up while already jumping (also known as the Quake2 double jump bug)
#if 0
- // LordHavoc: disabled this check so you can walk on monsters/players
+ // LadyHavoc: disabled this check so you can walk on monsters/players
//if (PRVM_serveredictfloat(ent, solid) == SOLID_BSP)
{
//Con_Printf("onground\n");
Entities that are "stuck" to another entity
=============
*/
-void SV_Physics_Follow (prvm_edict_t *ent)
+static void SV_Physics_Follow (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
vec3_t vf, vr, vu, angles, v;
prvm_edict_t *e;
- // regular thinking
- if (!SV_RunThink (ent))
- return;
-
- // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
+ // LadyHavoc: implemented rotation on MOVETYPE_FOLLOW objects
e = PRVM_PROG_TO_EDICT(PRVM_serveredictedict(ent, aiment));
if (PRVM_serveredictvector(e, angles)[0] == PRVM_serveredictvector(ent, punchangle)[0] && PRVM_serveredictvector(e, angles)[1] == PRVM_serveredictvector(ent, punchangle)[1] && PRVM_serveredictvector(e, angles)[2] == PRVM_serveredictvector(ent, punchangle)[2])
{
=============
*/
-void SV_CheckWaterTransition (prvm_edict_t *ent)
+static void SV_CheckWaterTransition (prvm_edict_t *ent)
{
- // LordHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
+ vec3_t entorigin;
+ prvm_prog_t *prog = SVVM_prog;
+ // LadyHavoc: bugfixes in this function are keyed to the sv_gameplayfix_bugfixedcheckwatertransition cvar - if this cvar is 0 then all the original bugs should be reenabled for compatibility
int cont;
- cont = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, SV_PointSuperContents(PRVM_serveredictvector(ent, origin)));
+ VectorCopy(PRVM_serveredictvector(ent, origin), entorigin);
+ cont = Mod_Q1BSP_NativeContentsFromSuperContents(SV_PointSuperContents(entorigin));
if (!PRVM_serveredictfloat(ent, watertype))
{
// just spawned here
void SV_Physics_Toss (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
trace_t trace;
vec3_t move;
vec_t movetime;
int bump;
prvm_edict_t *groundentity;
+ float d, ent_gravity;
+ float bouncefactor;
+ float bouncestop;
// if onground, return without moving
if ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND)
// we can trust FL_ONGROUND if groundentity is world because it never moves
return;
}
- else if (ent->priv.server->suspendedinairflag && groundentity->priv.server->free)
+ else if (ent->priv.server->suspendedinairflag && groundentity->free)
{
// if ent was supported by a brush model on previous frame,
// and groundentity is now freed, set groundentity to 0 (world)
for (bump = 0;bump < MAX_CLIP_PLANES && movetime > 0;bump++)
{
// move origin
- VectorScale (PRVM_serveredictvector(ent, velocity), movetime, move);
- if(!SV_PushEntity (&trace, ent, move, true, true))
+ VectorScale(PRVM_serveredictvector(ent, velocity), movetime, move);
+ // The buzzsaw traps in r2m6 and r2m7 use MOVETYPE_FLY and rely on moving while stuck in the world.
+ // Quake movetypes checked allsolid only in SV_FlyMove().
+ if(!SV_PushEntity(&trace, ent, move, true, PRVM_serveredictfloat(ent, movetype) != MOVETYPE_FLY))
return; // teleported
- if (ent->priv.server->free)
+ if (ent->free)
return;
- if (trace.bmodelstartsolid)
- {
- // try to unstick the entity
- if (sv_gameplayfix_unstickentities.integer)
- SV_UnstickEntity(ent);
- if(!SV_PushEntity (&trace, ent, move, false, true))
- return; // teleported
- if (ent->priv.server->free)
- return;
- }
if (trace.fraction == 1)
break;
movetime *= 1 - min(1, trace.fraction);
- if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE)
+ switch((int)PRVM_serveredictfloat(ent, movetype))
{
- float bouncefactor;
+ case MOVETYPE_BOUNCEMISSILE:
bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
if (!bouncefactor)
bouncefactor = 1.0f;
- ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
+ ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
- }
- else if (PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCE)
- {
- float d, ent_gravity;
- float bouncefactor;
- float bouncestop;
-
+ if (!sv_gameplayfix_slidemoveprojectiles.integer)
+ movetime = 0;
+ break;
+ case MOVETYPE_BOUNCE:
bouncefactor = PRVM_serveredictfloat(ent, bouncefactor);
if (!bouncefactor)
bouncefactor = 0.5f;
if (!bouncestop)
bouncestop = 60.0f / 800.0f;
- ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
+ ClipVelocity(PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1 + bouncefactor);
ent_gravity = PRVM_serveredictfloat(ent, gravity);
if (!ent_gravity)
ent_gravity = 1.0f;
- // LordHavoc: fixed grenades not bouncing when fired down a slope
+ // LadyHavoc: fixed grenades not bouncing when fired down a slope
if (sv_gameplayfix_grenadebouncedownslopes.integer)
+ d = fabs(DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity)));
+ else
+ d = PRVM_serveredictvector(ent, velocity)[2];
+ if (trace.plane.normal[2] > 0.7 && d < sv_gravity.value * bouncestop * ent_gravity)
{
- d = DotProduct(trace.plane.normal, PRVM_serveredictvector(ent, velocity));
- if (trace.plane.normal[2] > 0.7 && fabs(d) < sv_gravity.value * bouncestop * ent_gravity)
- {
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
- PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
- VectorClear (PRVM_serveredictvector(ent, velocity));
- VectorClear (PRVM_serveredictvector(ent, avelocity));
- }
- else
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+ PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
+ PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
+ VectorClear(PRVM_serveredictvector(ent, velocity));
+ VectorClear(PRVM_serveredictvector(ent, avelocity));
+ movetime = 0;
}
else
{
- if (trace.plane.normal[2] > 0.7 && PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * bouncestop * ent_gravity)
- {
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) | FL_ONGROUND;
- PRVM_serveredictedict(ent, groundentity) = PRVM_EDICT_TO_PROG(trace.ent);
- VectorClear (PRVM_serveredictvector(ent, velocity));
- VectorClear (PRVM_serveredictvector(ent, avelocity));
- }
- else
- PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+ PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
+ if (!sv_gameplayfix_slidemoveprojectiles.integer)
+ movetime = 0;
}
- }
- else
- {
+ break;
+ default:
ClipVelocity (PRVM_serveredictvector(ent, velocity), trace.plane.normal, PRVM_serveredictvector(ent, velocity), 1.0);
if (trace.plane.normal[2] > 0.7)
{
ent->priv.server->suspendedinairflag = true;
VectorClear (PRVM_serveredictvector(ent, velocity));
VectorClear (PRVM_serveredictvector(ent, avelocity));
+ movetime = 0;
}
else
+ {
PRVM_serveredictfloat(ent, flags) = (int)PRVM_serveredictfloat(ent, flags) & ~FL_ONGROUND;
- }
- if (!sv_gameplayfix_slidemoveprojectiles.integer || (PRVM_serveredictfloat(ent, movetype) != MOVETYPE_BOUNCE && PRVM_serveredictfloat(ent, movetype) == MOVETYPE_BOUNCEMISSILE) || ((int)PRVM_serveredictfloat(ent, flags) & FL_ONGROUND))
+ if (!sv_gameplayfix_slidemoveprojectiles.integer)
+ movetime = 0;
+ }
break;
+ }
}
// check for in water
will fall if the floor is pulled out from under them.
=============
*/
-void SV_Physics_Step (prvm_edict_t *ent)
+static void SV_Physics_Step (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
int flags = (int)PRVM_serveredictfloat(ent, flags);
// DRESK
{
PRVM_serveredictfloat(ent, flags) -= FL_ONGROUND;
SV_CheckVelocity(ent);
- SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
+ SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0, 0, 0);
SV_LinkEdict(ent);
SV_LinkEdict_TouchAreaGrid(ent);
ent->priv.server->waterposition_forceupdate = true;
int hitsound = PRVM_serveredictvector(ent, velocity)[2] < sv_gravity.value * -0.1;
SV_CheckVelocity(ent);
- SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0);
+ SV_FlyMove(ent, sv.frametime, true, NULL, SV_GenericHitSuperContentsMask(ent), 0, 0, 0);
SV_LinkEdict(ent);
SV_LinkEdict_TouchAreaGrid(ent);
if(PRVM_serveredictfunction(ent, movetypesteplandevent))
{ // Valid Function; Execute
// Prepare Parameters
- // Assign Velocity at Impact
- PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
- PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
- PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
- // Assign Self
- PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+ // Assign Velocity at Impact
+ PRVM_G_VECTOR(OFS_PARM0)[0] = backupVelocity[0];
+ PRVM_G_VECTOR(OFS_PARM0)[1] = backupVelocity[1];
+ PRVM_G_VECTOR(OFS_PARM0)[2] = backupVelocity[2];
+ // Assign Self
+ PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
+ // Set Time
+ PRVM_serverglobalfloat(time) = sv.time;
// Execute VM Function
- PRVM_ExecuteProgram(PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
+ prog->ExecuteProgram(prog, PRVM_serveredictfunction(ent, movetypesteplandevent), "movetypesteplandevent: NULL function");
}
else
// Check for Engine Landing Sound
ent->priv.server->waterposition_forceupdate = true;
}
}
-
-// regular thinking
- if (!SV_RunThink(ent))
- return;
-
- if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
- {
- ent->priv.server->waterposition_forceupdate = false;
- VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
- SV_CheckWaterTransition(ent);
- }
}
//============================================================================
static void SV_Physics_Entity (prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
// don't run think/move on newly spawned projectiles as it messes up
// movement interpolation and rocket trails, and is inconsistent with
// respect to entities spawned in the same frame
// (if an ent spawns a higher numbered ent, it moves in the same frame,
// but if it spawns a lower numbered ent, it doesn't - this never moves
// ents in the first frame regardless)
- qboolean runmove = ent->priv.server->move;
+ qbool runmove = ent->priv.server->move;
ent->priv.server->move = true;
if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
return;
SV_Physics_Pusher (ent);
break;
case MOVETYPE_NONE:
- // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
+ // LadyHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
SV_RunThink (ent);
break;
case MOVETYPE_FOLLOW:
- SV_Physics_Follow (ent);
+ if(SV_RunThink(ent))
+ SV_Physics_Follow (ent);
break;
case MOVETYPE_NOCLIP:
if (SV_RunThink(ent))
break;
case MOVETYPE_STEP:
SV_Physics_Step (ent);
+ // regular thinking
+ if (SV_RunThink(ent))
+ if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
+ {
+ ent->priv.server->waterposition_forceupdate = false;
+ VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
+ SV_CheckWaterTransition(ent);
+ }
break;
case MOVETYPE_WALK:
if (SV_RunThink (ent))
}
break;
default:
+ if((int) PRVM_serveredictfloat(ent, movetype) >= MOVETYPE_USER_FIRST && (int) PRVM_serveredictfloat(ent, movetype) <= MOVETYPE_USER_LAST)
+ break;
Con_Printf ("SV_Physics: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
break;
}
}
+static void SV_Physics_ClientEntity_NoThink (prvm_edict_t *ent)
+{
+ prvm_prog_t *prog = SVVM_prog;
+
+ // don't run think at all, that is done during server frames
+ // instead, call the movetypes directly so they match client input
+
+ // This probably only makes sense for CSQC-networked (SendEntity field set) player entities
+ switch ((int) PRVM_serveredictfloat(ent, movetype))
+ {
+ case MOVETYPE_PUSH:
+ case MOVETYPE_FAKEPUSH:
+ // push physics relies heavily on think times and calls, and so cannot be predicted currently
+ Con_Printf ("SV_Physics_ClientEntity_NoThink: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
+ break;
+ case MOVETYPE_NONE:
+ break;
+ case MOVETYPE_FOLLOW:
+ SV_Physics_Follow (ent);
+ break;
+ case MOVETYPE_NOCLIP:
+ VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
+ VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
+ break;
+ case MOVETYPE_STEP:
+ SV_Physics_Step (ent);
+ break;
+ case MOVETYPE_WALK:
+ SV_WalkMove (ent);
+ break;
+ case MOVETYPE_TOSS:
+ case MOVETYPE_BOUNCE:
+ case MOVETYPE_BOUNCEMISSILE:
+ case MOVETYPE_FLYMISSILE:
+ SV_Physics_Toss (ent);
+ break;
+ case MOVETYPE_FLY:
+ case MOVETYPE_FLY_WORLDONLY:
+ SV_WalkMove (ent);
+ break;
+ case MOVETYPE_PHYSICS:
+ break;
+ default:
+ if((int) PRVM_serveredictfloat(ent, movetype) >= MOVETYPE_USER_FIRST && (int) PRVM_serveredictfloat(ent, movetype) <= MOVETYPE_USER_LAST)
+ break;
+ Con_Printf ("SV_Physics_ClientEntity_NoThink: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
+ break;
+ }
+}
+
+// asynchronous path
void SV_Physics_ClientMove(void)
{
+ prvm_prog_t *prog = SVVM_prog;
prvm_edict_t *ent;
ent = host_client->edict;
// call player physics, this needs the proper frametime
PRVM_serverglobalfloat(frametime) = sv.frametime;
- SV_ClientThink();
+ SV_PlayerPhysics();
// call standard client pre-think, with frametime = 0
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobalfloat(frametime) = 0;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
- PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
PRVM_serverglobalfloat(frametime) = sv.frametime;
// make sure the velocity is sane (not a NaN)
SV_CheckVelocity(ent);
- // perform MOVETYPE_WALK behavior
- SV_WalkMove (ent);
+ // perform movetype behaviour
+ // note: will always be MOVETYPE_WALK if disableclientprediction = 0
+ SV_Physics_ClientEntity_NoThink (ent);
// call standard player post-think, with frametime = 0
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobalfloat(frametime) = 0;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
- PRVM_ExecuteProgram (PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
PRVM_serverglobalfloat(frametime) = sv.frametime;
if(PRVM_serveredictfloat(ent, fixangle))
{
// angle fixing was requested by physics code...
// so store the current angles for later use
- memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
- host_client->fixangle_angles_set = TRUE;
+ VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
+ host_client->fixangle_angles_set = true;
// and clear fixangle for the next frame
PRVM_serveredictfloat(ent, fixangle) = 0;
static void SV_Physics_ClientEntity_PreThink(prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
// don't do physics on disconnected clients, FrikBot relies on this
- if (!host_client->spawned)
+ if (!host_client->begun)
return;
// make sure the velocity is sane (not a NaN)
// don't run physics here if running asynchronously
if (host_client->clmovement_inputtimeout <= 0)
{
- SV_ClientThink();
+ SV_PlayerPhysics();
//host_client->cmd.time = max(host_client->cmd.time, sv.time);
}
// call standard client pre-think
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
- PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPreThink), "QC function PlayerPreThink is missing");
// make sure the velocity is still sane (not a NaN)
SV_CheckVelocity(ent);
static void SV_Physics_ClientEntity_PostThink(prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
// don't do physics on disconnected clients, FrikBot relies on this
- if (!host_client->spawned)
+ if (!host_client->begun)
return;
// make sure the velocity is sane (not a NaN)
// call standard player post-think
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(ent);
- PRVM_ExecuteProgram(PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(PlayerPostThink), "QC function PlayerPostThink is missing");
// make sure the velocity is still sane (not a NaN)
SV_CheckVelocity(ent);
{
// angle fixing was requested by physics code...
// so store the current angles for later use
- memcpy(host_client->fixangle_angles, PRVM_serveredictvector(ent, angles), sizeof(host_client->fixangle_angles));
- host_client->fixangle_angles_set = TRUE;
+ VectorCopy(PRVM_serveredictvector(ent, angles), host_client->fixangle_angles);
+ host_client->fixangle_angles_set = true;
// and clear fixangle for the next frame
PRVM_serveredictfloat(ent, fixangle) = 0;
static void SV_Physics_ClientEntity(prvm_edict_t *ent)
{
+ prvm_prog_t *prog = SVVM_prog;
// don't do physics on disconnected clients, FrikBot relies on this
- if (!host_client->spawned)
+ if (!host_client->begun)
{
memset(&host_client->cmd, 0, sizeof(host_client->cmd));
return;
SV_Physics_Pusher (ent);
break;
case MOVETYPE_NONE:
- // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
+ // LadyHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
if (PRVM_serveredictfloat(ent, nextthink) > 0 && PRVM_serveredictfloat(ent, nextthink) <= sv.time + sv.frametime)
SV_RunThink (ent);
break;
case MOVETYPE_FOLLOW:
- SV_Physics_Follow (ent);
+ SV_RunThink (ent);
+ if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
+ SV_Physics_Follow (ent);
break;
case MOVETYPE_NOCLIP:
SV_RunThink(ent);
- SV_CheckWater(ent);
- VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
- VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
+ if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
+ {
+ SV_CheckWater(ent);
+ VectorMA(PRVM_serveredictvector(ent, origin), sv.frametime, PRVM_serveredictvector(ent, velocity), PRVM_serveredictvector(ent, origin));
+ VectorMA(PRVM_serveredictvector(ent, angles), sv.frametime, PRVM_serveredictvector(ent, avelocity), PRVM_serveredictvector(ent, angles));
+ }
break;
case MOVETYPE_STEP:
- SV_Physics_Step (ent);
+ if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
+ SV_Physics_Step (ent);
+ if (SV_RunThink(ent))
+ if (ent->priv.server->waterposition_forceupdate || !VectorCompare(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin))
+ {
+ ent->priv.server->waterposition_forceupdate = false;
+ VectorCopy(PRVM_serveredictvector(ent, origin), ent->priv.server->waterposition_origin);
+ SV_CheckWaterTransition(ent);
+ }
break;
case MOVETYPE_WALK:
SV_RunThink (ent);
case MOVETYPE_FLYMISSILE:
// regular thinking
SV_RunThink (ent);
- SV_Physics_Toss (ent);
+ if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
+ SV_Physics_Toss (ent);
break;
case MOVETYPE_FLY:
case MOVETYPE_FLY_WORLDONLY:
SV_RunThink (ent);
- SV_WalkMove (ent);
+ if (host_client->clmovement_inputtimeout <= 0) // don't run physics here if running asynchronously
+ SV_WalkMove (ent);
break;
case MOVETYPE_PHYSICS:
SV_RunThink (ent);
break;
default:
+ if((int) PRVM_serveredictfloat(ent, movetype) >= MOVETYPE_USER_FIRST && (int) PRVM_serveredictfloat(ent, movetype) <= MOVETYPE_USER_LAST)
+ break;
Con_Printf ("SV_Physics_ClientEntity: bad movetype %i\n", (int)PRVM_serveredictfloat(ent, movetype));
break;
}
*/
void SV_Physics (void)
{
+ prvm_prog_t *prog = SVVM_prog;
int i;
prvm_edict_t *ent;
+ // free memory for resources that are no longer referenced
+ PRVM_GarbageCollection(prog);
+
// let the progs know that a new frame has started
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
PRVM_serverglobalfloat(time) = sv.time;
PRVM_serverglobalfloat(frametime) = sv.frametime;
- PRVM_ExecuteProgram (PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(StartFrame), "QC function StartFrame is missing");
+#ifdef USEODE
// run physics engine
World_Physics_Frame(&sv.world, sv.frametime, sv_gravity.value);
+#endif
//
// treat each object in turn
// if force_retouch, relink all the entities
if (PRVM_serverglobalfloat(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)
+ if (!ent->free)
SV_LinkEdict_TouchAreaGrid(ent); // force retouch even for stationary
if (sv_gameplayfix_consistentplayerprethink.integer)
{
// run physics on the client entities in 3 stages
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)
+ if (!ent->free)
SV_Physics_ClientEntity_PreThink(ent);
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)
+ if (!ent->free)
SV_Physics_ClientEntity(ent);
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)
+ if (!ent->free)
SV_Physics_ClientEntity_PostThink(ent);
}
else
// 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)
+ if (!ent->free)
{
SV_Physics_ClientEntity_PreThink(ent);
SV_Physics_ClientEntity(ent);
if (!sv_freezenonclients.integer)
{
for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
- if (!ent->priv.server->free)
+ if (!ent->free)
SV_Physics_Entity(ent);
// make a second pass to see if any ents spawned this frame and make
// sure they run their move/think
if (sv_gameplayfix_delayprojectiles.integer < 0)
for (i = svs.maxclients + 1, ent = PRVM_EDICT_NUM(i);i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
- if (!ent->priv.server->move && !ent->priv.server->free)
+ if (!ent->priv.server->move && !ent->free)
SV_Physics_Entity(ent);
}
if (PRVM_serverglobalfloat(force_retouch) > 0)
PRVM_serverglobalfloat(force_retouch) = max(0, PRVM_serverglobalfloat(force_retouch) - 1);
- // LordHavoc: endframe support
+ // LadyHavoc: endframe support
if (PRVM_serverfunction(EndFrame))
{
PRVM_serverglobaledict(self) = PRVM_EDICT_TO_PROG(prog->edicts);
PRVM_serverglobaledict(other) = PRVM_EDICT_TO_PROG(prog->edicts);
PRVM_serverglobalfloat(time) = sv.time;
- PRVM_ExecuteProgram (PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
+ prog->ExecuteProgram(prog, PRVM_serverfunction(EndFrame), "QC function EndFrame is missing");
}
// decrement prog->num_edicts if the highest number entities died
- for (;PRVM_ED_CanAlloc(PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
+ for (;PRVM_ED_CanAlloc(prog, PRVM_EDICT_NUM(prog->num_edicts - 1));prog->num_edicts--);
if (!sv_freezenonclients.integer)
sv.time += sv.frametime;