]> git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
unsticking: properly handle playerclip
[xonotic/darkplaces.git] / sv_phys.c
index 70bf3477b1d85838407de7c27115b31ba123deba..9c67efdb36b6d92c577ea3977726bcf431bbaeee 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -91,6 +91,7 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
        vec3_t hullmins, hullmaxs;
        int i, bodysupercontents;
        int passedictprog;
+       float pitchsign;
        qboolean pointtrace;
        prvm_edict_t *traceowner, *touch;
        trace_t trace;
@@ -218,9 +219,22 @@ trace_t SV_Move(const vec3_t start, const vec3_t mins, const vec3_t maxs, const
                        // 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);
@@ -484,11 +498,13 @@ returns true if the entity is in solid currently
 */
 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
        {
@@ -512,7 +528,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
                                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;
                        }
                }
@@ -526,7 +542,7 @@ static int SV_TestEntityPosition (prvm_edict_t *ent, vec3_t offset)
 #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
@@ -684,14 +700,16 @@ qboolean SV_RunThink (prvm_edict_t *ent)
 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;
 
@@ -699,6 +717,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        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;
@@ -731,6 +751,8 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
        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);
 }
 
 
@@ -766,11 +788,12 @@ Returns the clipflags if the velocity was modified (hit something solid)
 1 = floor
 2 = wall / step
 4 = dead stop
+8 = teleported by touch method
 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
 ============
 */
 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)
@@ -813,13 +836,11 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
 #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
+                       blocked |= 8;
                        break;
                }
 
@@ -1004,7 +1025,7 @@ static int SV_FlyMove (prvm_edict_t *ent, float time, qboolean applygravity, flo
        */
 
        // LordHavoc: this came from QW and allows you to get out of water more easily
-       if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP))
+       if (sv_gameplayfix_easierwaterjump.integer && ((int)ent->fields.server->flags & FL_WATERJUMP) && !(blocked & 8))
                VectorCopy(primal_velocity, ent->fields.server->velocity);
        if (applygravity && !((int)ent->fields.server->flags & FL_ONGROUND))
                ent->fields.server->velocity[2] -= gravity;
@@ -1044,12 +1065,13 @@ PUSHMOVE
 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;
 
@@ -1062,23 +1084,31 @@ static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmo
        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;
 }
 
 
@@ -1100,7 +1130,7 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
        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];
 
@@ -1281,7 +1311,13 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
 
                // 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
@@ -1303,7 +1339,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        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)
@@ -1313,7 +1353,11 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                                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)
@@ -1638,7 +1682,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
                        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];
@@ -1675,7 +1719,7 @@ void SV_WalkMove (prvm_edict_t *ent)
 {
        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),
@@ -1706,11 +1750,8 @@ void SV_WalkMove (prvm_edict_t *ent)
        SV_CheckVelocity(ent);
        SV_LinkEdict (ent, true);
 
-       VectorCopy(ent->fields.server->origin, originalmove_origin);
-       VectorCopy(ent->fields.server->velocity, originalmove_velocity);
-       originalmove_clip = clip;
-       originalmove_flags = (int)ent->fields.server->flags;
-       originalmove_groundentity = ent->fields.server->groundentity;
+       if(clip & 8) // teleport
+               return;
 
        if ((int)ent->fields.server->flags & FL_WATERJUMP)
                return;
@@ -1718,6 +1759,12 @@ void SV_WalkMove (prvm_edict_t *ent)
        if (sv_nostep.integer)
                return;
 
+       VectorCopy(ent->fields.server->origin, originalmove_origin);
+       VectorCopy(ent->fields.server->velocity, originalmove_velocity);
+       originalmove_clip = clip;
+       originalmove_flags = (int)ent->fields.server->flags;
+       originalmove_groundentity = ent->fields.server->groundentity;
+
        // if move didn't block on a step, return
        if (clip & 2)
        {
@@ -1745,12 +1792,22 @@ void SV_WalkMove (prvm_edict_t *ent)
                // 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);
@@ -1786,7 +1843,11 @@ void SV_WalkMove (prvm_edict_t *ent)
        // 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)
        {
@@ -1966,14 +2027,16 @@ void SV_Physics_Toss (prvm_edict_t *ent)
        {
        // 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;
                }