cvar_t sv_gameplayfix_noairborncorpse = {0, "sv_gameplayfix_noairborncorpse", "1", "causes entities (corpses, items, etc) sitting ontop of moving entities (players) to fall when the moving entity (player) is no longer supporting them"};
cvar_t sv_gameplayfix_noairborncorpse_allowsuspendeditems = {0, "sv_gameplayfix_noairborncorpse_allowsuspendeditems", "1", "causes entities sitting ontop of objects that are instantaneously remove to float in midair (special hack to allow a common level design trick for floating items)"};
cvar_t sv_gameplayfix_nudgeoutofsolid = {0, "sv_gameplayfix_nudgeoutofsolid", "1", "attempts to fix physics errors (where an object ended up in solid for some reason)"};
-cvar_t sv_gameplayfix_nudgeoutofsolid_bias = {0, "sv_gameplayfix_nudgeoutofsolid_bias", "0", "over-correction on nudgeoutofsolid logic, to prevent constant contact"};
+cvar_t sv_gameplayfix_nudgeoutofsolid_separation = {0, "sv_gameplayfix_nudgeoutofsolid_separation", "0.03125", "keep objects this distance apart to prevent collision issues on seams"};
cvar_t sv_gameplayfix_q2airaccelerate = {0, "sv_gameplayfix_q2airaccelerate", "0", "Quake2-style air acceleration"};
cvar_t sv_gameplayfix_nogravityonground = {0, "sv_gameplayfix_nogravityonground", "0", "turn off gravity when on ground (to get rid of sliding)"};
cvar_t sv_gameplayfix_setmodelrealbox = {0, "sv_gameplayfix_setmodelrealbox", "1", "fixes a bug in Quake that made setmodel always set the entity box to ('-16 -16 -16', '16 16 16') rather than properly checking the model box, breaks some poorly coded mods"};
Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse);
Cvar_RegisterVariable (&sv_gameplayfix_noairborncorpse_allowsuspendeditems);
Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid);
- Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_bias);
+ Cvar_RegisterVariable (&sv_gameplayfix_nudgeoutofsolid_separation);
Cvar_RegisterVariable (&sv_gameplayfix_q2airaccelerate);
Cvar_RegisterVariable (&sv_gameplayfix_nogravityonground);
Cvar_RegisterVariable (&sv_gameplayfix_setmodelrealbox);
*/
static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
{
+ int solid;
+ int movetype;
int type;
int bump;
+ vec3_t mins, maxs;
vec3_t original, original_velocity;
+ vec3_t start;
vec3_t end;
- VectorCopy(ent->fields.server->origin, original);
- VectorAdd (ent->fields.server->origin, push, end);
+ solid = (int)ent->fields.server->solid;
+ movetype = (int)ent->fields.server->movetype;
+ VectorCopy(ent->fields.server->mins, mins);
+ VectorCopy(ent->fields.server->maxs, maxs);
+
+ // move start position out of solids
+ if (sv_gameplayfix_nudgeoutofsolid.integer && sv_gameplayfix_nudgeoutofsolid_separation.value >= 0)
+ {
+ 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(ent->fields.server->origin, stuckorigin);
+ VectorCopy(mins, stuckmins);
+ VectorCopy(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, ent->fields.server->origin);
+ break;
+ }
+ nudge = -stucktrace.startdepth;
+ VectorMA(stuckorigin, nudge, stucktrace.startdepthnormal, stuckorigin);
+ }
+ }
+
+ VectorCopy(ent->fields.server->origin, start);
+ VectorAdd(start, push, end);
- if (ent->fields.server->movetype == MOVETYPE_FLYMISSILE)
+ if (movetype == MOVETYPE_FLYMISSILE)
type = MOVE_MISSILE;
- else if (ent->fields.server->solid == SOLID_TRIGGER || ent->fields.server->solid == SOLID_NOT)
+ else if (solid == SOLID_TRIGGER || solid == SOLID_NOT)
type = MOVE_NOMONSTERS; // only clip against bmodels
else
type = MOVE_NORMAL;
- *trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
- bump = 0;
- while (trace->bmodelstartsolid && sv_gameplayfix_nudgeoutofsolid.integer)
- {
- vec_t nudge = -trace->startdepth + sv_gameplayfix_nudgeoutofsolid_bias.value;
- VectorMA(ent->fields.server->origin, nudge, trace->startdepthnormal, ent->fields.server->origin);
- *trace = SV_TraceBox(ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
- bump++;
- if (bump > 10)
- {
- VectorCopy(original, ent->fields.server->origin);
- break;
- }
- }
+ *trace = SV_TraceBox(start, mins, maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
if (trace->bmodelstartsolid && failonbmodelstartsolid)
return true;
- VectorCopy (trace->endpos, ent->fields.server->origin);
+ VectorCopy(trace->endpos, ent->fields.server->origin);
VectorCopy(ent->fields.server->origin, original);
VectorCopy(ent->fields.server->velocity, original_velocity);