]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
no longer uses SZ_Alloc for cmd_text buffer
[xonotic/darkplaces.git] / sv_phys.c
index 9f7a0adca90e597a0c878883f759ccbdb5b77509..59c02e1e804403b2ecb503c717f6f8a41ead2791 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -128,6 +128,37 @@ void SV_CheckVelocity (edict_t *ent)
        }
 }
 
+/*
+=============
+SV_RunThink
+
+Runs thinking code if time.  There is some play in the exact time the think
+function will be called, because it is called before any movement is done
+in a frame.  Not used for pushmove objects, because they must be exact.
+Returns false if the entity removed itself.
+=============
+*/
+qboolean SV_RunThink (edict_t *ent)
+{
+       float thinktime;
+
+       thinktime = ent->v->nextthink;
+       if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
+               return true;
+
+       // don't let things stay in the past.
+       // it is possible to start that way by a trigger with a local time.
+       if (thinktime < sv.time)
+               thinktime = sv.time;
+
+       ent->v->nextthink = 0;
+       pr_global_struct->time = thinktime;
+       pr_global_struct->self = EDICT_TO_PROG(ent);
+       pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
+       PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
+       return !ent->e->free;
+}
+
 /*
 ==================
 SV_Impact
@@ -428,7 +459,7 @@ int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
                ent->v->groundentity = EDICT_TO_PROG(hackongroundentity);
        }
        */
-       
+
        /*
        if ((blocked & 1) == 0 && bumpcount > 1)
        {
@@ -850,19 +881,17 @@ qboolean SV_CheckWater (edict_t *ent)
 
        ent->v->waterlevel = 0;
        ent->v->watertype = CONTENTS_EMPTY;
-       cont = SV_PointQ1Contents(point);
-       if (cont <= CONTENTS_WATER)
+       cont = SV_PointSuperContents(point);
+       if (cont & (SUPERCONTENTS_LIQUIDSMASK))
        {
-               ent->v->watertype = cont;
+               ent->v->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
                ent->v->waterlevel = 1;
                point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
-               cont = SV_PointQ1Contents(point);
-               if (cont <= CONTENTS_WATER)
+               if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
                {
                        ent->v->waterlevel = 2;
                        point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
-                       cont = SV_PointQ1Contents(point);
-                       if (cont <= CONTENTS_WATER)
+                       if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
                                ent->v->waterlevel = 3;
                }
        }
@@ -991,44 +1020,44 @@ void SV_WalkMove (edict_t *ent)
 
        if (sv_nostep.integer)
                return;
-       
+
        // if move didn't block on a step, return
        if (clip & 2)
        {
                // if move was not trying to move into the step, return
                if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
                        return;
-       
+
                if (ent->v->movetype != MOVETYPE_FLY)
                {
                        // return if gibbed by a trigger
                        if (ent->v->movetype != MOVETYPE_WALK)
                                return;
-       
+
                        // only step up while jumping if that is enabled
                        if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
                                if (!oldonground && ent->v->waterlevel == 0)
                                        return;
                }
-       
+
                // try moving up and forward to go up a step
                // back to start pos
                VectorCopy (start_origin, ent->v->origin);
                VectorCopy (start_velocity, ent->v->velocity);
-       
+
                // move up
                VectorClear (upmove);
                upmove[2] = sv_stepheight.value;
                // FIXME: don't link?
                SV_PushEntity(ent, upmove);
-       
+
                // move forward
                ent->v->velocity[2] = 0;
                clip = SV_FlyMove (ent, sv.frametime, stepnormal);
                ent->v->velocity[2] += start_velocity[2];
-       
+
                SV_CheckVelocity(ent);
-       
+
                // check for stuckness, possibly due to the limited precision of floats
                // in the clipping hulls
                if (clip
@@ -1041,7 +1070,7 @@ void SV_WalkMove (edict_t *ent)
                        VectorCopy(originalmove_velocity, ent->v->velocity);
                        //clip = originalmove_clip;
                        ent->v->flags = originalmove_flags;
-                       ent->v->groundentity = originalmove_groundentity; 
+                       ent->v->groundentity = originalmove_groundentity;
                        // now try to unstick if needed
                        //clip = SV_TryUnstick (ent, oldvel);
                        return;
@@ -1083,7 +1112,7 @@ void SV_WalkMove (edict_t *ent)
                VectorCopy(originalmove_velocity, ent->v->velocity);
                //clip = originalmove_clip;
                ent->v->flags = originalmove_flags;
-               ent->v->groundentity = originalmove_groundentity; 
+               ent->v->groundentity = originalmove_groundentity;
        }
 
        SV_SetOnGround (ent);
@@ -1105,6 +1134,9 @@ void SV_Physics_Follow (edict_t *ent)
        edict_t *e;
 
        // regular thinking
+       if (!SV_RunThink (ent))
+               return;
+
        // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
        e = PROG_TO_EDICT(ent->v->aiment);
        if (e->v->angles[0] == ent->v->punchangle[0] && e->v->angles[1] == ent->v->punchangle[1] && e->v->angles[2] == ent->v->punchangle[2])
@@ -1329,6 +1361,9 @@ void SV_Physics_Step (edict_t *ent)
                        SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
        }
 
+// regular thinking
+       SV_RunThink(ent);
+
        SV_CheckWaterTransition(ent);
 }
 
@@ -1342,10 +1377,9 @@ SV_Physics
 */
 void SV_Physics (void)
 {
-       int i, end, retouch;
-       float nexttime;
-       vec3_t oldorigin;
+       int i, newnum_edicts;
        edict_t *ent;
+       qbyte runmove[MAX_EDICTS];
 
 // let the progs know that a new frame has started
        pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
@@ -1353,16 +1387,38 @@ void SV_Physics (void)
        pr_global_struct->time = sv.time;
        PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
 
-       retouch = pr_global_struct->force_retouch > 0;
-       end = i = sv_freezenonclients.integer ? svs.maxclients + 1 : sv.num_edicts;
-       for (i = 0, ent = sv.edicts;i < end;i++, ent = NEXT_EDICT(ent))
+       newnum_edicts = 0;
+       for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
+               if ((runmove[i] = !ent->e->free))
+                       newnum_edicts = i + 1;
+       sv.num_edicts = max(svs.maxclients + 1, newnum_edicts);
+
+//
+// treat each object in turn
+//
+
+       for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
        {
-               if (ent->e->free || ent->v->movetype == MOVETYPE_NONE)
+               if (ent->e->free)
                        continue;
 
-               // LordHavoc: merged client and normal entity physics
-               VectorCopy(ent->v->origin, oldorigin);
+               if (pr_global_struct->force_retouch)
+                       SV_LinkEdict (ent, true);       // force retouch even for stationary
 
+               if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
+               {
+                       // connected slot
+                       // call standard client pre-think
+                       SV_CheckVelocity (ent);
+                       pr_global_struct->time = sv.time;
+                       pr_global_struct->self = EDICT_TO_PROG(ent);
+                       PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
+                       SV_CheckVelocity (ent);
+               }
+               else if (sv_freezenonclients.integer)
+                       continue;
+
+               // LordHavoc: merged client and normal entity physics
                switch ((int) ent->v->movetype)
                {
                case MOVETYPE_PUSH:
@@ -1370,127 +1426,79 @@ void SV_Physics (void)
                        SV_Physics_Pusher (ent);
                        break;
                case MOVETYPE_NONE:
+                       // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
+                       if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
+                               SV_RunThink (ent);
                        break;
                case MOVETYPE_FOLLOW:
                        SV_Physics_Follow (ent);
                        break;
                case MOVETYPE_NOCLIP:
-                       SV_CheckWater(ent);
-                       VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
-                       VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
+                       if (SV_RunThink(ent))
+                       {
+                               SV_CheckWater(ent);
+                               VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
+                               VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
+                       }
+                       // relink normal entities here, players always get relinked so don't relink twice
+                       if (!(i > 0 && i <= svs.maxclients))
+                               SV_LinkEdict(ent, false);
                        break;
                case MOVETYPE_STEP:
                        SV_Physics_Step (ent);
                        break;
                case MOVETYPE_WALK:
-                       if (!SV_CheckWater(ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
-                               SV_AddGravity(ent);
-                       SV_CheckStuck(ent);
-                       SV_WalkMove(ent);
+                       if (SV_RunThink (ent))
+                       {
+                               if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
+                                       SV_AddGravity (ent);
+                               SV_CheckStuck (ent);
+                               SV_WalkMove (ent);
+                               // relink normal entities here, players always get relinked so don't relink twice
+                               if (!(i > 0 && i <= svs.maxclients))
+                                       SV_LinkEdict (ent, true);
+                       }
                        break;
                case MOVETYPE_TOSS:
                case MOVETYPE_BOUNCE:
                case MOVETYPE_BOUNCEMISSILE:
                case MOVETYPE_FLYMISSILE:
-                       SV_Physics_Toss(ent);
+                       // regular thinking
+                       if (SV_RunThink (ent) && runmove[i])
+                               SV_Physics_Toss (ent);
                        break;
                case MOVETYPE_FLY:
-                       if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
+                       if (SV_RunThink (ent) && runmove[i])
                        {
-                               SV_CheckWater(ent);
-                               SV_WalkMove(ent);
+                               if (i > 0 && i <= svs.maxclients)
+                               {
+                                       SV_CheckWater (ent);
+                                       SV_WalkMove (ent);
+                               }
+                               else
+                                       SV_Physics_Toss (ent);
                        }
-                       else
-                               SV_Physics_Toss(ent);
                        break;
                default:
                        Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
                        break;
                }
 
-               if (!VectorCompare(ent->v->origin, oldorigin) || retouch)
-                       SV_LinkEdict(ent, true);
-       }
+               if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
+               {
+                       SV_CheckVelocity (ent);
 
-       for (i = 1, ent = NEXT_EDICT(sv.edicts);i <= svs.maxclients;i++, ent = NEXT_EDICT(ent))
-       {
-               if (ent->e->free || !svs.clients[i-1].spawned)
-                       continue;
+                       // call standard player post-think
+                       SV_LinkEdict (ent, true);
 
-               // call standard client pre-think
-               SV_CheckVelocity (ent);
-               pr_global_struct->time = sv.time;
-               pr_global_struct->self = EDICT_TO_PROG(ent);
-               PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
-               SV_CheckVelocity (ent);
-       }
+                       SV_CheckVelocity (ent);
 
-       nexttime = sv.time + sv.frametime;
-       end = i = sv_freezenonclients.integer ? svs.maxclients + 1 : sv.num_edicts;
-       for (i = 0, ent = sv.edicts;i < end;i++, ent = NEXT_EDICT(ent))
-       {
-               if (ent->e->free)
-                       continue;
-
-               // LordHavoc: merged client and normal entity physics
-               switch ((int) ent->v->movetype)
-               {
-               case MOVETYPE_PUSH:
-               case MOVETYPE_FAKEPUSH:
-                       // push thinks are called from SV_Physics_Pusher 
-                       break;
-               case MOVETYPE_NONE:
-               case MOVETYPE_FOLLOW:
-               case MOVETYPE_NOCLIP:
-               case MOVETYPE_STEP:
-               case MOVETYPE_WALK:
-               case MOVETYPE_TOSS:
-               case MOVETYPE_BOUNCE:
-               case MOVETYPE_BOUNCEMISSILE:
-               case MOVETYPE_FLY:
-               case MOVETYPE_FLYMISSILE:
-                       // LordHavoc: manually inlined SV_RunThink here
-                       if (ent->v->nextthink > 0 && ent->v->nextthink <= nexttime)
-                       {
-                               /*
-                               SV_RunThink
-                               Runs thinking code if time.  There is some play in the exact time the think
-                               function will be called, because it is called before any movement is done
-                               in a frame.  Not used for pushmove objects, because they must be exact.
-                               Returns false if the entity removed itself.
-                               */
-                               float thinktime = ent->v->nextthink;
-                               if (thinktime && thinktime < sv.time + sv.frametime)
-                               {
-                                       ent->v->nextthink = 0;
-                                       // don't let things stay in the past.
-                                       // it is possible to start that way by a trigger with a local time.
-                                       pr_global_struct->time = max(thinktime, sv.time);
-                                       pr_global_struct->self = EDICT_TO_PROG(ent);
-                                       pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
-                                       PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
-                               }
-                       }
-                       break;
-               default:
-                       Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
-                       break;
+                       pr_global_struct->time = sv.time;
+                       pr_global_struct->self = EDICT_TO_PROG(ent);
+                       PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
                }
        }
 
-       for (i = 1, ent = NEXT_EDICT(sv.edicts);i <= svs.maxclients;i++, ent = NEXT_EDICT(ent))
-       {
-               if (ent->e->free || !svs.clients[i-1].spawned)
-                       continue;
-
-               // call standard player post-think
-               SV_LinkEdict (ent, true);
-               SV_CheckVelocity (ent);
-               pr_global_struct->time = sv.time;
-               pr_global_struct->self = EDICT_TO_PROG(ent);
-               PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
-       }
-
        if (pr_global_struct->force_retouch > 0)
                pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);