SV_Move
==================
*/
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+#if COLLISIONPARANOID >= 1
+trace_t SV_Move_(const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t pEnd, int type, prvm_edict_t *passedict, int hitsupercontentsmask)
+#else
+trace_t SV_Move(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_Move_(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_Move(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
+#endif
{
vec3_t hullmins, hullmaxs;
int i, bodysupercontents;
int passedictprog;
+ float pitchsign = 1;
qboolean pointtrace;
prvm_edict_t *traceowner, *touch;
trace_t trace;
// list of entities to test for collisions
int numtouchedicts;
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))
+ {
+ // TRICK: make the trace 1 qu longer!
+ VectorSubtract(pEnd, start, end);
+ len = VectorNormalizeLength(end);
+ VectorAdd(pEnd, end, end);
+ }
+ else
+ VectorCopy(pEnd, end);
+#endif
VectorCopy(start, clipstart);
VectorCopy(end, clipend);
if (cliptrace.startsolid || cliptrace.fraction < 1)
cliptrace.ent = prog->edicts;
if (type == MOVE_WORLDONLY)
- return cliptrace;
+ goto finished;
if (type == MOVE_MISSILE)
{
// if the modelindex is 0, it shouldn't be SOLID_BSP!
if (modelindex > 0 && modelindex < MAX_MODELS)
model = sv.models[(int)touch->fields.server->modelindex];
+ //pitchsign = 1;
+ if (
+ ((modelindex = (int)touch->fields.server->modelindex) >= 1 && modelindex < MAX_MODELS && (model = sv.models[(int)touch->fields.server->modelindex]))
+ ?
+ model->type == mod_alias
+ :
+ (
+ (((unsigned char)PRVM_EDICTFIELDVALUE(touch, prog->fieldoffsets.pflags)->_float) & PFLAGS_FULLDYNAMIC)
+ ||
+ ((gamemode == GAME_TENEBRAE) && ((unsigned int)touch->fields.server->effects & (16 | 32)))
+ )
+ )
+ pitchsign = -1;
}
if (model)
- Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
+ Matrix4x4_CreateFromQuakeEntity(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2], pitchsign * touch->fields.server->angles[0], touch->fields.server->angles[1], touch->fields.server->angles[2], 1);
else
Matrix4x4_CreateTranslate(&matrix, touch->fields.server->origin[0], touch->fields.server->origin[1], touch->fields.server->origin[2]);
Matrix4x4_Invert_Simple(&imatrix, &matrix);
Collision_CombineTraces(&cliptrace, &trace, (void *)touch, touch->fields.server->solid == SOLID_BSP);
}
+finished:
+#ifdef COLLISION_STUPID_TRACE_ENDPOS_IN_SOLID_WORKAROUND
+ if(!VectorCompare(start, pEnd))
+ Collision_ShortenTrace(&cliptrace, len / (len + 1), pEnd);
+#endif
return cliptrace;
}
*/
static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
{
+ int contents;
vec3_t org;
trace_t trace;
+ contents = SV_GenericHitSuperContentsMask(ent);
VectorAdd(ent->fields.server->origin, offset, org);
- trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID);
- if (trace.startsupercontents & SUPERCONTENTS_SOLID)
+ trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, MOVE_NOMONSTERS, ent, contents);
+ if (trace.startsupercontents & contents)
return true;
else
{
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) & SUPERCONTENTS_SOLID)
+ if (SV_PointSuperContents(v) & contents)
return true;
}
}
#else
// verify if the endpos is REALLY outside solid
VectorCopy(trace.endpos, org);
- trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, SUPERCONTENTS_SOLID);
+ trace = SV_Move (org, ent->fields.server->mins, ent->fields.server->maxs, org, MOVE_NOMONSTERS, ent, contents);
if(trace.startsolid)
Con_Printf("SV_TestEntityPosition: trace.endpos detected to be in solid. NOT using it.\n");
else
SV_Impact
Two entities have touched, so run their touch functions
+returns true if the impact kept the origin of the touching entity intact
==================
*/
extern void VM_SetTraceGlobals(const trace_t *trace);
extern sizebuf_t vm_tempstringsbuf;
-void SV_Impact (prvm_edict_t *e1, trace_t *trace)
+qboolean SV_Impact (prvm_edict_t *e1, trace_t *trace)
{
int restorevm_tempstringsbuf_cursize;
int old_self, old_other;
+ vec3_t org;
prvm_edict_t *e2 = (prvm_edict_t *)trace->ent;
prvm_eval_t *val;
old_other = prog->globals.server->other;
restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ VectorCopy(e1->fields.server->origin, org);
+
VM_SetTraceGlobals(trace);
prog->globals.server->time = sv.time;
prog->globals.server->self = old_self;
prog->globals.server->other = old_other;
vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
+
+ return VectorCompare(e1->fields.server->origin, org);
}
============
*/
static float SV_Gravity (prvm_edict_t *ent);
-static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
+static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink);
// LordHavoc: increased from 5 to 32
#define MAX_CLIP_PLANES 32
static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, float *stepnormal, int hitsupercontentsmask)
#if 0
VectorAdd(ent->fields.server->origin, push, end);
#endif
- trace = SV_PushEntity(ent, push, false, false); // the caller calls SV_LinkEntity on the own later
-
- VectorCopy(trace.endpos, push); // convert to float for comparing
- if(!VectorCompare(push, ent->fields.server->origin))
+ if(!SV_PushEntity(&trace, ent, push, false, false))
{
// we got teleported by a touch function
// let's abort the move
SV_PushEntity
Does not change the entities velocity at all
+The trace struct is filled with the trace that has been done.
+Returns true if the push did not result in the entity being teleported by QC code.
============
*/
-static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
+static qboolean SV_PushEntity (trace_t *trace, prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid, qboolean dolink)
{
int type;
- trace_t trace;
vec3_t end;
qboolean impact;
else
type = MOVE_NORMAL;
- trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent, SV_GenericHitSuperContentsMask(ent));
- if (trace.bmodelstartsolid && failonbmodelstartsolid)
- return trace;
+ *trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->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);
+
+#if 0
+ if(!trace->startsolid)
+ if(SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, ent->fields.server->origin, type, ent, SV_GenericHitSuperContentsMask(ent)).startsolid)
+ {
+ Con_Printf("something eeeeevil happened\n");
+ }
+#endif
- impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent)));
+ impact = (ent->fields.server->solid >= SOLID_TRIGGER && trace->ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace->ent)));
if(impact)
{
SV_LinkEdict (ent, dolink);
- SV_Impact (ent, &trace);
+ return SV_Impact (ent, trace);
}
else if(dolink)
SV_LinkEdict (ent, true);
- return trace;
+ return true;
}
int numcheckentities;
static prvm_edict_t *checkentities[MAX_EDICTS];
dp_model_t *pushermodel;
- trace_t trace;
+ trace_t trace, trace2;
matrix4x4_t pusherfinalmatrix, pusherfinalimatrix;
unsigned short moved_edicts[MAX_EDICTS];
// try moving the contacted entity
pusher->fields.server->solid = SOLID_NOT;
- trace = SV_PushEntity (check, move, true, true);
+ if(!SV_PushEntity (&trace, check, move, true, true))
+ {
+ // entity "check" got teleported
+ check->fields.server->angles[1] += trace.fraction * moveangle[1];
+ pusher->fields.server->solid = savesolid; // was SOLID_BSP
+ continue; // pushed enough
+ }
// FIXME: turn players specially
check->fields.server->angles[1] += trace.fraction * moveangle[1];
pusher->fields.server->solid = savesolid; // was SOLID_BSP
VectorScale(move, 1.1, move2);
VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
- SV_PushEntity (check, move2, true, true);
+ if(!SV_PushEntity (&trace2, check, move2, true, true))
+ {
+ // entity "check" got teleported
+ continue;
+ }
pusher->fields.server->solid = savesolid;
Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
if (trace.startsolid)
VectorScale(move, 0.9, move2);
VectorCopy (check->priv.server->moved_from, check->fields.server->origin);
VectorCopy (check->priv.server->moved_fromangles, check->fields.server->angles);
- SV_PushEntity (check, move2, true, true);
+ if(!SV_PushEntity (&trace2, check, move2, true, true))
+ {
+ // entity "check" got teleported
+ continue;
+ }
pusher->fields.server->solid = savesolid;
Collision_ClipToGenericEntity(&trace, pushermodel, (int) pusher->fields.server->frame, pusher->fields.server->mins, pusher->fields.server->maxs, SUPERCONTENTS_BODY, &pusherfinalmatrix, &pusherfinalimatrix, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, checkcontents);
if (trace.startsolid)
case 7: dir[0] = -2; dir[1] = -2; break;
}
- SV_PushEntity (ent, dir, false, true);
+ SV_PushEntity (&trace, ent, dir, false, true);
// retry the original move
ent->fields.server->velocity[0] = oldvel[0];
{
int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity, hitsupercontentsmask;
vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
- trace_t downtrace;
+ trace_t downtrace, trace;
qboolean applygravity;
// if frametime is 0 (due to client sending the same timestamp twice),
// move up
VectorClear (upmove);
upmove[2] = sv_stepheight.value;
- SV_PushEntity(ent, upmove, false, true);
+ if(!SV_PushEntity(&trace, ent, upmove, false, true))
+ {
+ // we got teleported when upstepping... must abort the move
+ return;
+ }
// move forward
ent->fields.server->velocity[2] = 0;
clip = SV_FlyMove (ent, sv.frametime, applygravity, stepnormal, hitsupercontentsmask);
ent->fields.server->velocity[2] += start_velocity[2];
+ if(clip & 8)
+ {
+ // we got teleported when upstepping... must abort the move
+ // note that z velocity handling may not be what QC expects here, but we cannot help it
+ return;
+ }
SV_CheckVelocity(ent);
SV_LinkEdict (ent, true);
// move down
VectorClear (downmove);
downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
- downtrace = SV_PushEntity (ent, downmove, false, true);
+ if(!SV_PushEntity (&downtrace, ent, downmove, false, true))
+ {
+ // we got teleported when downstepping... must abort the move
+ return;
+ }
if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
{
// and groundentity is now freed, set groundentity to 0 (world)
// which leaves it suspended in the air
ent->fields.server->groundentity = 0;
- return;
+ if (sv_gameplayfix_noairborncorpse_allowsuspendeditems.integer)
+ return;
}
}
ent->priv.server->suspendedinairflag = false;
{
// move origin
VectorScale (ent->fields.server->velocity, movetime, move);
- trace = SV_PushEntity (ent, move, true, true);
+ if(!SV_PushEntity (&trace, ent, move, true, true))
+ return; // teleported
if (ent->priv.server->free)
return;
if (trace.bmodelstartsolid)
{
// try to unstick the entity
SV_UnstickEntity(ent);
- trace = SV_PushEntity (ent, move, false, true);
+ if(!SV_PushEntity (&trace, ent, move, false, true))
+ return; // teleported
if (ent->priv.server->free)
return;
}
// ents in the first frame regardless)
qboolean runmove = ent->priv.server->move;
ent->priv.server->move = true;
- if (!runmove && sv_gameplayfix_delayprojectiles.integer)
+ if (!runmove && sv_gameplayfix_delayprojectiles.integer > 0)
return;
switch ((int) ent->fields.server->movetype)
{
// run physics on all the non-client entities
if (!sv_freezenonclients.integer)
+ {
for (;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
if (!ent->priv.server->free)
SV_Physics_Entity(ent);
+ // 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)
+ SV_Physics_Entity(ent);
+ }
if (prog->globals.server->force_retouch > 0)
prog->globals.server->force_retouch = max(0, prog->globals.server->force_retouch - 1);