+static qboolean SV_NudgeOutOfSolid_PivotIsKnownGood(prvm_edict_t *ent, vec3_t pivot)
+{
+ int bump;
+ trace_t stucktrace;
+ vec3_t stuckorigin;
+ vec3_t stuckmins, stuckmaxs;
+ vec3_t goodmins, goodmaxs;
+ vec3_t testorigin;
+ vec_t nudge;
+ vec3_t move;
+ VectorCopy(PRVM_serveredictvector(ent, origin), stuckorigin);
+ VectorCopy(PRVM_serveredictvector(ent, mins), stuckmins);
+ VectorCopy(PRVM_serveredictvector(ent, maxs), stuckmaxs);
+ VectorCopy(pivot, goodmins);
+ VectorCopy(pivot, goodmaxs);
+ for (bump = 0;bump < 6;bump++)
+ {
+ int coord = 2-(bump >> 1);
+ //int coord = (bump >> 1);
+ int dir = (bump & 1);
+ int subbump;
+
+ for(subbump = 0; ; ++subbump)
+ {
+ VectorCopy(stuckorigin, testorigin);
+ if(dir)
+ {
+ // pushing maxs
+ testorigin[coord] += stuckmaxs[coord] - goodmaxs[coord];
+ }
+ else
+ {
+ // pushing mins
+ testorigin[coord] += stuckmins[coord] - goodmins[coord];
+ }
+
+ stucktrace = SV_TraceBox(stuckorigin, goodmins, goodmaxs, testorigin, MOVE_NOMONSTERS, ent, SV_GenericHitSuperContentsMask(ent));
+ if (stucktrace.bmodelstartsolid)
+ {
+ // BAD BAD, can't fix that
+ return false;
+ }
+
+ if (stucktrace.fraction >= 1)
+ break; // it WORKS!
+
+ if(subbump >= 10)
+ {
+ // BAD BAD, can't fix that
+ return false;
+ }
+
+ // we hit something... let's move out of it
+ VectorSubtract(stucktrace.endpos, testorigin, move);
+ nudge = DotProduct(stucktrace.plane.normal, move) + 0.03125f; // FIXME cvar this constant
+ VectorMA(stuckorigin, nudge, stucktrace.plane.normal, stuckorigin);
+ }
+ /*
+ if(subbump > 0)
+ Con_Printf("subbump: %d\n", subbump);
+ */
+
+ if(dir)
+ {
+ // pushing maxs
+ goodmaxs[coord] = stuckmaxs[coord];
+ }
+ else
+ {
+ // pushing mins
+ goodmins[coord] = stuckmins[coord];
+ }
+ }
+
+ // WE WIN
+ VectorCopy(stuckorigin, PRVM_serveredictvector(ent, origin));
+
+ 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;
+}
+