]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
redesigned tempstring system, now uses a fixed size buffer based on the prvm_tempstri...
[xonotic/darkplaces.git] / sv_phys.c
index 725aa884e89ca78fa9ee752807e466e1405f6953..dbd6b33e3b9877a479faef313035c4660fdffa1e 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -20,8 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 // sv_phys.c
 
 #include "quakedef.h"
-// used only for VM_GetTempString
-#include "prvm_cmds.h"
 
 /*
 
@@ -91,7 +89,25 @@ static int SV_TestEntityPosition (prvm_edict_t *ent)
        if (trace.startsupercontents & SUPERCONTENTS_SOLID)
                return true;
        else
+       {
+               if (sv.worldmodel->brushq1.hulls && !VectorCompare(ent->fields.server->mins, ent->fields.server->maxs))
+               {
+                       // q1bsp/hlbsp use hulls and if the entity does not exactly match
+                       // a hull size it is incorrectly tested, so this code tries to
+                       // 'fix' it slightly...
+                       int i;
+                       vec3_t v;
+                       for (i = 0;i < 8;i++)
+                       {
+                               v[0] = (i & 1) ? ent->fields.server->maxs[0] : ent->fields.server->mins[0];
+                               v[1] = (i & 2) ? ent->fields.server->maxs[1] : ent->fields.server->mins[1];
+                               v[2] = (i & 4) ? ent->fields.server->maxs[2] : ent->fields.server->mins[2];
+                               if (SV_PointSuperContents(v) & SUPERCONTENTS_SOLID)
+                                       return true;
+                       }
+               }
                return false;
+       }
 }
 
 /*
@@ -121,6 +137,46 @@ void SV_CheckAllEnts (void)
        }
 }
 
+// DRESK - Support for Entity Contents Transition Event
+/*
+================
+SV_CheckContentsTransition
+
+returns true if entity had a valid contentstransition function call
+================
+*/
+int SV_CheckContentsTransition(prvm_edict_t *ent, const int nContents)
+{
+       int bValidFunctionCall;
+       prvm_eval_t *contentstransition;
+
+       // Default Valid Function Call to False
+       bValidFunctionCall = false;
+
+       if(ent->fields.server->watertype != nContents)
+       { // Changed Contents
+               // Acquire Contents Transition Function from QC
+               contentstransition = PRVM_GETEDICTFIELDVALUE(ent, eval_contentstransition);
+
+               if(contentstransition->function)
+               { // Valid Function; Execute
+                       // Assign Valid Function
+                       bValidFunctionCall = true;
+                       // Prepare Parameters (Original Contents, New Contents)
+                               // Original Contents
+                               PRVM_G_FLOAT(OFS_PARM0) = ent->fields.server->watertype;
+                               // New Contents
+                               PRVM_G_FLOAT(OFS_PARM1) = nContents;
+                       // Execute VM Function
+                       PRVM_ExecuteProgram(contentstransition->function, "contentstransition: NULL function");
+               }
+       }
+
+       // Return if Function Call was Valid
+       return bValidFunctionCall;
+}
+
+
 /*
 ================
 SV_CheckVelocity
@@ -232,11 +288,7 @@ void SV_Impact (prvm_edict_t *e1, trace_t *trace)
                if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
                {
                        if (trace->hittexture)
-                       {
-                               char *s = VM_GetTempString();
-                               strlcpy(s, trace->hittexture->name, VM_STRINGTEMP_LENGTH);
-                               val->string = PRVM_SetEngineString(s);
-                       }
+                               val->string = PRVM_SetTempString(trace->hittexture->name);
                        else
                                val->string = 0;
                }
@@ -374,6 +426,7 @@ int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal)
                Con_Print("\n");
 #endif
 
+#if 0
                if (trace.bmodelstartsolid)
                {
                        // LordHavoc: note: this code is what makes entities stick in place
@@ -383,6 +436,7 @@ int SV_FlyMove (prvm_edict_t *ent, float time, float *stepnormal)
                        VectorClear(ent->fields.server->velocity);
                        return 3;
                }
+#endif
 
                // break if it moved the entire distance
                if (trace.fraction == 1)
@@ -571,7 +625,7 @@ SV_PushEntity
 Does not change the entities velocity at all
 ============
 */
-trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push)
+static trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push, qboolean failonbmodelstartsolid)
 {
        int type;
        trace_t trace;
@@ -587,11 +641,13 @@ trace_t SV_PushEntity (prvm_edict_t *ent, vec3_t push)
                type = MOVE_NORMAL;
 
        trace = SV_Move (ent->fields.server->origin, ent->fields.server->mins, ent->fields.server->maxs, end, type, ent);
+       if (trace.bmodelstartsolid && failonbmodelstartsolid)
+               return trace;
 
        VectorCopy (trace.endpos, ent->fields.server->origin);
        SV_LinkEdict (ent, true);
 
-       if (trace.ent && (!((int)ent->fields.server->flags & FL_ONGROUND) || ent->fields.server->groundentity != PRVM_EDICT_TO_PROG(trace.ent)))
+       if (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)))
                SV_Impact (ent, &trace);
        return trace;
 }
@@ -734,15 +790,18 @@ void SV_PushMove (prvm_edict_t *pusher, float movetime)
                        continue;
 
                // if the entity is standing on the pusher, it will definitely be moved
-               if (!(((int)check->fields.server->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.server->groundentity) == pusher))
+               if (((int)check->fields.server->flags & FL_ONGROUND) && PRVM_PROG_TO_EDICT(check->fields.server->groundentity) == pusher)
                {
-                       // if the entity is not inside the pusher's final position, leave it alone
-                       if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid)
-                               continue;
                        // remove the onground flag for non-players
                        if (check->fields.server->movetype != MOVETYPE_WALK)
                                check->fields.server->flags = (int)check->fields.server->flags & ~FL_ONGROUND;
                }
+               else
+               {
+                       // if the entity is not inside the pusher's final position, leave it alone
+                       if (!SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid)
+                               continue;
+               }
 
 
                if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used
@@ -764,10 +823,11 @@ 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);
+               trace = SV_PushEntity (check, move, true);
                // FIXME: turn players specially
                check->fields.server->angles[1] += trace.fraction * moveangle[1];
                pusher->fields.server->solid = savesolid; // was SOLID_BSP
+               //Con_Printf("%s:%d frac %f startsolid %d bmodelstartsolid %d allsolid %d\n", __FILE__, __LINE__, trace.fraction, trace.startsolid, trace.bmodelstartsolid, trace.allsolid);
 
                // if it is still inside the pusher, block
                if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid)
@@ -778,7 +838,7 @@ 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);
+                       SV_PushEntity (check, move2, true);
                        pusher->fields.server->solid = savesolid;
                        if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid)
                        {
@@ -787,7 +847,7 @@ 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);
+                               SV_PushEntity (check, move2, true);
                                pusher->fields.server->solid = savesolid;
                                if (SV_ClipMoveToEntity(pusher, check->fields.server->origin, check->fields.server->mins, check->fields.server->maxs, check->fields.server->origin, 0, SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY).startsolid)
                                {
@@ -954,7 +1014,8 @@ static void SV_UnstickEntity (prvm_edict_t *ent)
                        }
 
        VectorCopy (org, ent->fields.server->origin);
-       Con_DPrintf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
+       if (developer.integer >= 100)
+               Con_Printf("Stuck entity %i (classname \"%s\").\n", (int)PRVM_EDICT_TO_PROG(ent), PRVM_GetString(ent->fields.server->classname));
 }
 
 
@@ -966,18 +1027,34 @@ SV_CheckWater
 qboolean SV_CheckWater (prvm_edict_t *ent)
 {
        int cont;
+       int nNativeContents;
        vec3_t point;
 
        point[0] = ent->fields.server->origin[0];
        point[1] = ent->fields.server->origin[1];
        point[2] = ent->fields.server->origin[2] + ent->fields.server->mins[2] + 1;
 
+       // DRESK - Support for Entity Contents Transition Event
+       // NOTE: Some logic needed to be slightly re-ordered
+       // to not affect performance and allow for the feature.
+
+       // Acquire Super Contents Prior to Resets
+       cont = SV_PointSuperContents(point);
+       // Acquire Native Contents Here
+       nNativeContents = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
+
+       // DRESK - Support for Entity Contents Transition Event
+       if(ent->fields.server->watertype)
+               // Entity did NOT Spawn; Check
+               SV_CheckContentsTransition(ent, nNativeContents);
+
+
        ent->fields.server->waterlevel = 0;
        ent->fields.server->watertype = CONTENTS_EMPTY;
        cont = SV_PointSuperContents(point);
        if (cont & (SUPERCONTENTS_LIQUIDSMASK))
        {
-               ent->fields.server->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
+               ent->fields.server->watertype = nNativeContents;
                ent->fields.server->waterlevel = 1;
                point[2] = ent->fields.server->origin[2] + (ent->fields.server->mins[2] + ent->fields.server->maxs[2])*0.5;
                if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
@@ -1050,7 +1127,7 @@ int SV_TryUnstick (prvm_edict_t *ent, vec3_t oldvel)
                        case 7: dir[0] = -2; dir[1] = -2; break;
                }
 
-               SV_PushEntity (ent, dir);
+               SV_PushEntity (ent, dir, false);
 
                // retry the original move
                ent->fields.server->velocity[0] = oldvel[0];
@@ -1141,7 +1218,7 @@ void SV_WalkMove (prvm_edict_t *ent)
                VectorClear (upmove);
                upmove[2] = sv_stepheight.value;
                // FIXME: don't link?
-               SV_PushEntity(ent, upmove);
+               SV_PushEntity(ent, upmove, false);
 
                // move forward
                ent->fields.server->velocity[2] = 0;
@@ -1182,7 +1259,7 @@ void SV_WalkMove (prvm_edict_t *ent)
        VectorClear (downmove);
        downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
        // FIXME: don't link?
-       downtrace = SV_PushEntity (ent, downmove);
+       downtrace = SV_PushEntity (ent, downmove, false);
 
        if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
        {
@@ -1286,9 +1363,16 @@ void SV_CheckWaterTransition (prvm_edict_t *ent)
                return;
        }
 
-       // check if the entity crossed into or out of water
-       if (sv_sound_watersplash.string && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
-               SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1);
+       // DRESK - Support for Entity Contents Transition Event
+       // NOTE: Call here BEFORE updating the watertype below,
+       // and suppress watersplash sound if a valid function
+       // call was made to allow for custom "splash" sounds.
+       if( !SV_CheckContentsTransition(ent, cont) )
+       { // Contents Transition Function Invalid; Potentially Play Water Sound
+               // check if the entity crossed into or out of water
+               if (sv_sound_watersplash.string && ((ent->fields.server->watertype == CONTENTS_WATER || ent->fields.server->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME)))
+                       SV_StartSound (ent, 0, sv_sound_watersplash.string, 255, 1);
+       }
 
        if (cont <= CONTENTS_WATER)
        {
@@ -1317,22 +1401,23 @@ void SV_Physics_Toss (prvm_edict_t *ent)
 // if onground, return without moving
        if ((int)ent->fields.server->flags & FL_ONGROUND)
        {
-               // don't stick to ground if onground and moving upward
-               if (ent->fields.server->velocity[2] >= (1.0 / 32.0))
+               if (ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer)
+               {
+                       // don't stick to ground if onground and moving upward
                        ent->fields.server->flags -= FL_ONGROUND;
-               else
+               }
+               else if (!ent->fields.server->groundentity || !sv_gameplayfix_noairborncorpse.integer)
+               {
+                       // we can trust FL_ONGROUND if groundentity is world because it never moves
+                       return;
+               }
+               else if (ent->priv.server->suspendedinairflag && PRVM_PROG_TO_EDICT(ent->fields.server->groundentity)->priv.server->free)
                {
-                       prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity);
-                       if (ground->fields.server->solid == SOLID_BSP || !sv_gameplayfix_noairborncorpse.integer)
-                               return;
                        // if ent was supported by a brush model on previous frame,
-                       // and groundentity is now freed, set groundentity to 0 (floating)
-                       if (ent->priv.server->suspendedinairflag && ground->priv.server->free)
-                       {
-                               // leave it suspended in the air
-                               ent->fields.server->groundentity = 0;
-                               return;
-                       }
+                       // and groundentity is now freed, set groundentity to 0 (world)
+                       // which leaves it suspended in the air
+                       ent->fields.server->groundentity = 0;
+                       return;
                }
        }
        ent->priv.server->suspendedinairflag = false;
@@ -1348,14 +1433,14 @@ void SV_Physics_Toss (prvm_edict_t *ent)
 
 // move origin
        VectorScale (ent->fields.server->velocity, sv.frametime, move);
-       trace = SV_PushEntity (ent, move);
+       trace = SV_PushEntity (ent, move, true);
        if (ent->priv.server->free)
                return;
        if (trace.bmodelstartsolid)
        {
                // try to unstick the entity
                SV_UnstickEntity(ent);
-               trace = SV_PushEntity (ent, move);
+               trace = SV_PushEntity (ent, move, false);
                if (ent->priv.server->free)
                        return;
        }
@@ -1447,9 +1532,8 @@ void SV_Physics_Step (prvm_edict_t *ent)
                if (flags & FL_ONGROUND)
                {
                        // freefall if onground and moving upward
-                       // freefall if not standing on a world surface (it may be a lift)
-                       prvm_edict_t *ground = PRVM_PROG_TO_EDICT(ent->fields.server->groundentity);
-                       if (ent->fields.server->velocity[2] >= (1.0 / 32.0) || (ground->fields.server->solid != SOLID_BSP && sv_gameplayfix_noairborncorpse.integer))
+                       // freefall if not standing on a world surface (it may be a lift or trap door)
+                       if ((ent->fields.server->velocity[2] >= (1.0 / 32.0) && sv_gameplayfix_upwardvelocityclearsongroundflag.integer) || ent->fields.server->groundentity)
                        {
                                ent->fields.server->flags -= FL_ONGROUND;
                                SV_AddGravity(ent);