]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
changed a lot of Con_DPrint/Con_DPrintf calls to Con_Print/Con_Printf (non-technical...
[xonotic/darkplaces.git] / sv_phys.c
index 06e1f40ee68b52382bcce35cb07bc97847acee2c..ee0239084cad2839d1bf1ad9229464e51337b3e8 100644 (file)
--- a/sv_phys.c
+++ b/sv_phys.c
@@ -8,7 +8,7 @@ of the License, or (at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 See the GNU General Public License for more details.
 
 
 See the GNU General Public License for more details.
 
@@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
 
 
 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
 
-onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects 
+onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
 
 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
 
 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
@@ -39,16 +39,30 @@ solid_edge items only clip against bsp models.
 
 */
 
 
 */
 
-cvar_t sv_friction = {"sv_friction","4",false,true};
-cvar_t sv_stopspeed = {"sv_stopspeed","100"};
-cvar_t sv_gravity = {"sv_gravity","800",false,true};
-cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
-cvar_t sv_nostep = {"sv_nostep","0"};
+cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"};
+cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"};
+cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"};
+cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"};
+cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"};
+cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"};
+cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"};
+cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"};
+cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "1"};
+cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"};
 
 #define        MOVE_EPSILON    0.01
 
 void SV_Physics_Toss (edict_t *ent);
 
 
 #define        MOVE_EPSILON    0.01
 
 void SV_Physics_Toss (edict_t *ent);
 
+void SV_Phys_Init (void)
+{
+       Cvar_RegisterVariable(&sv_stepheight);
+       Cvar_RegisterVariable(&sv_jumpstep);
+       Cvar_RegisterVariable(&sv_wallfriction);
+       Cvar_RegisterVariable(&sv_newflymove);
+       Cvar_RegisterVariable(&sv_freezenonclients);
+}
+
 /*
 ================
 SV_CheckAllEnts
 /*
 ================
 SV_CheckAllEnts
@@ -56,23 +70,23 @@ SV_CheckAllEnts
 */
 void SV_CheckAllEnts (void)
 {
 */
 void SV_CheckAllEnts (void)
 {
-       int                     e;
-       edict_t         *check;
+       int e;
+       edict_t *check;
 
 
-// see if any solid entities are inside the final position
+       // see if any solid entities are inside the final position
        check = NEXT_EDICT(sv.edicts);
        check = NEXT_EDICT(sv.edicts);
-       for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
+       for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
        {
        {
-               if (check->free)
+               if (check->e->free)
                        continue;
                        continue;
-               if (check->v.movetype == MOVETYPE_PUSH
-               || check->v.movetype == MOVETYPE_NONE
-               || check->v.movetype == MOVETYPE_FOLLOW
-               || check->v.movetype == MOVETYPE_NOCLIP)
+               if (check->v->movetype == MOVETYPE_PUSH
+                || check->v->movetype == MOVETYPE_NONE
+                || check->v->movetype == MOVETYPE_FOLLOW
+                || check->v->movetype == MOVETYPE_NOCLIP)
                        continue;
 
                if (SV_TestEntityPosition (check))
                        continue;
 
                if (SV_TestEntityPosition (check))
-                       Con_Print("entity in invalid position\n");
+                       Con_Print("entity in invalid position\n");
        }
 }
 
        }
 }
 
@@ -83,42 +97,34 @@ SV_CheckVelocity
 */
 void SV_CheckVelocity (edict_t *ent)
 {
 */
 void SV_CheckVelocity (edict_t *ent)
 {
-       int             i;
-       float   wishspeed;
+       int i;
+       float wishspeed;
 
 //
 // bound velocity
 //
        for (i=0 ; i<3 ; i++)
        {
 
 //
 // bound velocity
 //
        for (i=0 ; i<3 ; i++)
        {
-               if (IS_NAN(ent->v.velocity[i]))
+               if (IS_NAN(ent->v->velocity[i]))
                {
                {
-                       Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
-                       ent->v.velocity[i] = 0;
+                       Con_Printf("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname));
+                       ent->v->velocity[i] = 0;
                }
                }
-               if (IS_NAN(ent->v.origin[i]))
+               if (IS_NAN(ent->v->origin[i]))
                {
                {
-                       Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
-                       ent->v.origin[i] = 0;
+                       Con_Printf("Got a NaN origin on %s\n", PR_GetString(ent->v->classname));
+                       ent->v->origin[i] = 0;
                }
                }
-               // LordHavoc: maxvelocity fix, see below
-/*
-               if (ent->v.velocity[i] > sv_maxvelocity.value)
-                       ent->v.velocity[i] = sv_maxvelocity.value;
-               else if (ent->v.velocity[i] < -sv_maxvelocity.value)
-                       ent->v.velocity[i] = -sv_maxvelocity.value;
-*/
        }
 
        // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
        }
 
        // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
-       wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
+       wishspeed = DotProduct(ent->v->velocity, ent->v->velocity);
        if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
        {
                wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
        if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
        {
                wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
-               ent->v.velocity[0] *= wishspeed;
-               ent->v.velocity[1] *= wishspeed;
-               ent->v.velocity[2] *= wishspeed;
-               wishspeed = sv_maxvelocity.value;
+               ent->v->velocity[0] *= wishspeed;
+               ent->v->velocity[1] *= wishspeed;
+               ent->v->velocity[2] *= wishspeed;
        }
 }
 
        }
 }
 
@@ -134,22 +140,23 @@ Returns false if the entity removed itself.
 */
 qboolean SV_RunThink (edict_t *ent)
 {
 */
 qboolean SV_RunThink (edict_t *ent)
 {
-       float   thinktime;
+       float thinktime;
 
 
-       thinktime = ent->v.nextthink;
-       if (thinktime <= 0 || thinktime > sv.time + host_frametime)
+       thinktime = ent->v->nextthink;
+       if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
                return true;
                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)
        if (thinktime < sv.time)
-               thinktime = sv.time;    // don't let things stay in the past.
-                                                               // it is possible to start that way
-                                                               // by a trigger with a local time.
-       ent->v.nextthink = 0;
+               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_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);
-       return !ent->free;
+       PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
+       return !ent->e->free;
 }
 
 /*
 }
 
 /*
@@ -161,24 +168,24 @@ Two entities have touched, so run their touch functions
 */
 void SV_Impact (edict_t *e1, edict_t *e2)
 {
 */
 void SV_Impact (edict_t *e1, edict_t *e2)
 {
-       int             old_self, old_other;
-       
+       int old_self, old_other;
+
        old_self = pr_global_struct->self;
        old_other = pr_global_struct->other;
        old_self = pr_global_struct->self;
        old_other = pr_global_struct->other;
-       
+
        pr_global_struct->time = sv.time;
        pr_global_struct->time = sv.time;
-       if (e1->v.touch && e1->v.solid != SOLID_NOT)
+       if (e1->v->touch && e1->v->solid != SOLID_NOT)
        {
                pr_global_struct->self = EDICT_TO_PROG(e1);
                pr_global_struct->other = EDICT_TO_PROG(e2);
        {
                pr_global_struct->self = EDICT_TO_PROG(e1);
                pr_global_struct->other = EDICT_TO_PROG(e2);
-               PR_ExecuteProgram (e1->v.touch);
+               PR_ExecuteProgram (e1->v->touch, "QC function self.touch is missing");
        }
        }
-       
-       if (e2->v.touch && e2->v.solid != SOLID_NOT)
+
+       if (e2->v->touch && e2->v->solid != SOLID_NOT)
        {
                pr_global_struct->self = EDICT_TO_PROG(e2);
                pr_global_struct->other = EDICT_TO_PROG(e1);
        {
                pr_global_struct->self = EDICT_TO_PROG(e2);
                pr_global_struct->other = EDICT_TO_PROG(e1);
-               PR_ExecuteProgram (e2->v.touch);
+               PR_ExecuteProgram (e2->v->touch, "QC function self.touch is missing");
        }
 
        pr_global_struct->self = old_self;
        }
 
        pr_global_struct->self = old_self;
@@ -194,31 +201,18 @@ Slide off of the impacting object
 returns the blocked flags (1 = floor, 2 = step / wall)
 ==================
 */
 returns the blocked flags (1 = floor, 2 = step / wall)
 ==================
 */
-#define        STOP_EPSILON    0.1
-
-int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
+#define STOP_EPSILON 0.1
+void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
 {
 {
-       float   backoff;
-       float   change;
-       int             i, blocked;
-       
-       blocked = 0;
-       if (normal[2] > 0)
-               blocked |= 1;           // floor
-       if (!normal[2])
-               blocked |= 2;           // step
-       
-       backoff = DotProduct (in, normal) * overbounce;
+       int i;
+       float backoff;
 
 
-       for (i=0 ; i<3 ; i++)
-       {
-               change = normal[i]*backoff;
-               out[i] = in[i] - change;
+       backoff = -DotProduct (in, normal) * overbounce;
+       VectorMA(in, backoff, normal, out);
+
+       for (i = 0;i < 3;i++)
                if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
                        out[i] = 0;
                if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
                        out[i] = 0;
-       }
-       
-       return blocked;
 }
 
 
 }
 
 
@@ -231,145 +225,268 @@ Returns the clipflags if the velocity was modified (hit something solid)
 1 = floor
 2 = wall / step
 4 = dead stop
 1 = floor
 2 = wall / step
 4 = dead stop
-If steptrace is not NULL, the trace of any vertical wall hit will be stored
+If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
 ============
 */
 ============
 */
-#define        MAX_CLIP_PLANES 5
-int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
+// LordHavoc: increased from 5 to 20
+#define MAX_CLIP_PLANES 20
+int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
 {
 {
-       int                     bumpcount, numbumps;
-       vec3_t          dir;
-       float           d;
-       int                     numplanes;
-       vec3_t          planes[MAX_CLIP_PLANES];
-       vec3_t          primal_velocity, original_velocity, new_velocity;
-       int                     i, j;
-       trace_t         trace;
-       vec3_t          end;
-       float           time_left;
-       int                     blocked;
-       
-       numbumps = 4;
-       
+       int blocked, bumpcount;
+       edict_t *hackongroundentity;
+       int i, j, impact, numplanes;
+       float d, time_left;
+       vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
+       trace_t trace;
        blocked = 0;
        blocked = 0;
-       VectorCopy (ent->v.velocity, original_velocity);
-       VectorCopy (ent->v.velocity, primal_velocity);
+       VectorCopy(ent->v->velocity, original_velocity);
+       VectorCopy(ent->v->velocity, primal_velocity);
        numplanes = 0;
        numplanes = 0;
-       
        time_left = time;
        time_left = time;
-
-       for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
+       hackongroundentity = NULL;
+       for (bumpcount = 0;bumpcount < 8;bumpcount++)
        {
        {
-               if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
+               if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
                        break;
 
                        break;
 
-               for (i=0 ; i<3 ; i++)
-                       end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
+               VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
+               trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+#if 0
+               //if (trace.fraction < 0.002)
+               {
+#if 1
+                       vec3_t start;
+                       trace_t testtrace;
+                       VectorCopy(ent->v->origin, start);
+                       start[2] += 3;//0.03125;
+                       VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
+                       end[2] += 3;//0.03125;
+                       testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+                       if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->v->velocity) < DotProduct(testtrace.plane.normal, ent->v->velocity)))
+                       {
+                               Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction);
+                               trace = testtrace;
+                       }
+#endif
+#if 0
+                       //j = -1;
+                       for (i = 0;i < numplanes;i++)
+                       {
+                               VectorCopy(ent->v->origin, start);
+                               VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
+                               VectorMA(start, 3, planes[i], start);
+                               VectorMA(end, 3, planes[i], end);
+                               testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+                               if (trace.fraction < testtrace.fraction)
+                               {
+                                       trace = testtrace;
+                                       VectorCopy(start, ent->v->origin);
+                                       //j = i;
+                               }
+                       }
+                       //if (j >= 0)
+                       //      VectorAdd(ent->v->origin, planes[j], start);
+#endif
+               }
+#endif
 
 
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
+#if 0
+               Con_Printf("entity %i bump %i: velocity %f %f %f trace %f", ent - sv.edicts, bumpcount, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2], trace.fraction);
+               if (trace.fraction < 1)
+                       Con_Printf(" : %f %f %f", trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
+               Con_Print("\n");
+#endif
 
 
-               if (trace.allsolid)
-               {       // entity is trapped in another solid
-                       VectorCopy (vec3_origin, ent->v.velocity);
+               /*
+               if (trace.startsolid)
+               {
+                       // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
+                       // entity is trapped in another solid
+                       VectorClear(ent->v->velocity);
                        return 3;
                }
                        return 3;
                }
+               */
 
 
-               if (trace.fraction > 0)
-               {       // actually covered some distance
-                       VectorCopy (trace.endpos, ent->v.origin);
-                       VectorCopy (ent->v.velocity, original_velocity);
-                       numplanes = 0;
-               }
-
+               // break if it moved the entire distance
                if (trace.fraction == 1)
                if (trace.fraction == 1)
-                        break;         // moved the entire distance
+               {
+                       VectorCopy(trace.endpos, ent->v->origin);
+                       break;
+               }
 
                if (!trace.ent)
 
                if (!trace.ent)
-                       Host_Error ("SV_FlyMove: !trace.ent");
+                       Host_Error("SV_FlyMove: !trace.ent");
+
+               if ((int) ent->v->flags & FL_ONGROUND)
+               {
+                       if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
+                               impact = false;
+                       else
+                       {
+                               ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
+                               impact = true;
+                       }
+               }
+               else
+                       impact = true;
 
 
-               if (trace.plane.normal[2] > 0.7)
+               if (trace.plane.normal[2])
                {
                {
-                       blocked |= 1;           // floor
-                       if (trace.ent->v.solid == SOLID_BSP)
+                       if (trace.plane.normal[2] > 0.7)
                        {
                        {
-                               ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
-                               ent->v.groundentity = EDICT_TO_PROG(trace.ent);
+                               // floor
+                               blocked |= 1;
+                               ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+                               ent->v->groundentity = EDICT_TO_PROG(trace.ent);
                        }
                        }
+                       else if (trace.fraction < 0.001)
+                               hackongroundentity = trace.ent;
                }
                }
-               if (!trace.plane.normal[2])
+               else
                {
                {
-                       blocked |= 2;           // step
-                       if (steptrace)
-                               *steptrace = trace;     // save for player extrafriction
+                       // step
+                       blocked |= 2;
+                       // save the trace for player extrafriction
+                       if (stepnormal)
+                               VectorCopy(trace.plane.normal, stepnormal);
                }
 
                }
 
-//
-// run the impact function
-//
-               SV_Impact (ent, trace.ent);
-               if (ent->free)
-                       break;          // removed by the impact function
+               if (trace.fraction >= 0.001)
+               {
+                       // actually covered some distance
+                       VectorCopy(trace.endpos, ent->v->origin);
+                       VectorCopy(ent->v->velocity, original_velocity);
+                       numplanes = 0;
+               }
+
+               // run the impact function
+               if (impact)
+               {
+                       SV_Impact(ent, trace.ent);
+
+                       // break if removed by the impact function
+                       if (ent->e->free)
+                               break;
+               }
+
+               time_left *= 1 - trace.fraction;
 
 
-               
-               time_left -= time_left * trace.fraction;
-               
-       // cliped to another plane
+               // clipped to another plane
                if (numplanes >= MAX_CLIP_PLANES)
                if (numplanes >= MAX_CLIP_PLANES)
-               {       // this shouldn't really happen
-                       VectorCopy (vec3_origin, ent->v.velocity);
-                       return 3;
+               {
+                       // this shouldn't really happen
+                       VectorClear(ent->v->velocity);
+                       blocked = 3;
+                       break;
                }
 
                }
 
-               VectorCopy (trace.plane.normal, planes[numplanes]);
+               /*
+               for (i = 0;i < numplanes;i++)
+                       if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
+                               break;
+               if (i < numplanes)
+               {
+                       VectorAdd(ent->v->velocity, trace.plane.normal, ent->v->velocity);
+                       continue;
+               }
+               */
+
+               VectorCopy(trace.plane.normal, planes[numplanes]);
                numplanes++;
 
                numplanes++;
 
-//
-// modify original_velocity so it parallels all of the clip planes
-//
-               for (i=0 ; i<numplanes ; i++)
+               if (sv_newflymove.integer)
+                       ClipVelocity(ent->v->velocity, trace.plane.normal, ent->v->velocity, 1);
+               else
                {
                {
-                       ClipVelocity (original_velocity, planes[i], new_velocity, 1);
-                       for (j=0 ; j<numplanes ; j++)
-                               if (j != i)
+                       // modify original_velocity so it parallels all of the clip planes
+                       for (i = 0;i < numplanes;i++)
+                       {
+                               ClipVelocity(original_velocity, planes[i], new_velocity, 1);
+                               for (j = 0;j < numplanes;j++)
                                {
                                {
-                                       if (DotProduct (new_velocity, planes[j]) < 0)
-                                               break;  // not ok
+                                       if (j != i)
+                                       {
+                                               // not ok
+                                               if (DotProduct(new_velocity, planes[j]) < 0)
+                                                       break;
+                                       }
                                }
                                }
-                       if (j == numplanes)
-                               break;
-               }
-               
-               if (i != numplanes)
-               {       // go along this plane
-                       VectorCopy (new_velocity, ent->v.velocity);
-               }
-               else
-               {       // go along the crease
-                       if (numplanes != 2)
+                               if (j == numplanes)
+                                       break;
+                       }
+
+                       if (i != numplanes)
                        {
                        {
-//                             Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
-                               VectorCopy (vec3_origin, ent->v.velocity);
-                               return 7;
+                               // go along this plane
+                               VectorCopy(new_velocity, ent->v->velocity);
+                       }
+                       else
+                       {
+                               // go along the crease
+                               if (numplanes != 2)
+                               {
+                                       VectorClear(ent->v->velocity);
+                                       blocked = 7;
+                                       break;
+                               }
+                               CrossProduct(planes[0], planes[1], dir);
+                               // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
+                               VectorNormalize(dir);
+                               d = DotProduct(dir, ent->v->velocity);
+                               VectorScale(dir, d, ent->v->velocity);
                        }
                        }
-                       CrossProduct (planes[0], planes[1], dir);
-                       d = DotProduct (dir, ent->v.velocity);
-                       VectorScale (dir, d, ent->v.velocity);
                }
 
                }
 
-//
-// if original velocity is against the original velocity, stop dead
-// to avoid tiny occilations in sloping corners
-//
-               if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
+               // if original velocity is against the original velocity,
+               // stop dead to avoid tiny occilations in sloping corners
+               if (DotProduct(ent->v->velocity, primal_velocity) <= 0)
                {
                {
-                       VectorCopy (vec3_origin, ent->v.velocity);
-                       return blocked;
+                       VectorClear(ent->v->velocity);
+                       break;
                }
        }
 
                }
        }
 
+       //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - sv.edicts, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]);
+
+       /*
+       // FIXME: this doesn't work well at all, find another solution
+       // if player is ontop of a non-onground floor and made no progress,
+       // set onground anyway (this tends to happen if standing in a wedge)
+       if (bumpcount == 8 && hackongroundentity)
+       {
+               blocked |= 1;
+               ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+               ent->v->groundentity = EDICT_TO_PROG(hackongroundentity);
+       }
+       */
+       
+       /*
+       if ((blocked & 1) == 0 && bumpcount > 1)
+       {
+               // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
+               // flag ONGROUND if there's ground under it
+               trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+       }
+       */
        return blocked;
 }
 
        return blocked;
 }
 
+int SV_SetOnGround (edict_t *ent)
+{
+       vec3_t end;
+       trace_t trace;
+       if ((int)ent->v->flags & FL_ONGROUND)
+               return 1;
+       VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1);
+       trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
+       if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7)
+       {
+               ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+               ent->v->groundentity = EDICT_TO_PROG(trace.ent);
+               return 1;
+       }
+       return 0;
+}
 
 /*
 ============
 
 /*
 ============
@@ -379,16 +496,15 @@ SV_AddGravity
 */
 void SV_AddGravity (edict_t *ent)
 {
 */
 void SV_AddGravity (edict_t *ent)
 {
-       float   ent_gravity;
-
-       eval_t  *val;
+       float ent_gravity;
+       eval_t *val;
 
        val = GETEDICTFIELDVALUE(ent, eval_gravity);
        if (val!=0 && val->_float)
                ent_gravity = val->_float;
        else
                ent_gravity = 1.0;
 
        val = GETEDICTFIELDVALUE(ent, eval_gravity);
        if (val!=0 && val->_float)
                ent_gravity = val->_float;
        else
                ent_gravity = 1.0;
-       ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
+       ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
 }
 
 
 }
 
 
@@ -409,27 +525,28 @@ Does not change the entities velocity at all
 */
 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
 {
 */
 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
 {
-       trace_t trace;
-       vec3_t  end;
-               
-       VectorAdd (ent->v.origin, push, end);
-
-       if (ent->v.movetype == MOVETYPE_FLYMISSILE)
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
-       else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
-       // only clip against bmodels
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
+       int type;
+       trace_t trace;
+       vec3_t end;
+
+       VectorAdd (ent->v->origin, push, end);
+
+       if (ent->v->movetype == MOVETYPE_FLYMISSILE)
+               type = MOVE_MISSILE;
+       else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
+               type = MOVE_NOMONSTERS; // only clip against bmodels
        else
        else
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);       
-       
-       VectorCopy (trace.endpos, ent->v.origin);
-       SV_LinkEdict (ent, true);
+               type = MOVE_NORMAL;
 
 
-       if (trace.ent)
-               SV_Impact (ent, trace.ent);             
+       trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent);
 
 
+       VectorCopy (trace.endpos, ent->v->origin);
+       SV_LinkEdict (ent, true);
+
+       if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
+               SV_Impact (ent, trace.ent);
        return trace;
        return trace;
-}                                      
+}
 
 
 /*
 
 
 /*
@@ -438,18 +555,24 @@ SV_PushMove
 
 ============
 */
 
 ============
 */
+trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
 void SV_PushMove (edict_t *pusher, float movetime)
 {
 void SV_PushMove (edict_t *pusher, float movetime)
 {
-       int                     i, e;
-       edict_t         *check;
-       vec3_t          mins, maxs, move;
-       vec3_t          entorig, pushorig;
-       int                     num_moved;
-       edict_t         *moved_edict[MAX_EDICTS];
-       vec3_t          moved_from[MAX_EDICTS];
-       float           savesolid;
-
-       switch ((int) pusher->v.solid)
+       int i, e, index;
+       edict_t *check, *ed;
+       float savesolid, movetime2, pushltime;
+       vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
+       int num_moved;
+       model_t *pushermodel;
+       trace_t trace;
+
+       if (!pusher->v->velocity[0] && !pusher->v->velocity[1] && !pusher->v->velocity[2] && !pusher->v->avelocity[0] && !pusher->v->avelocity[1] && !pusher->v->avelocity[2])
+       {
+               pusher->v->ltime += movetime;
+               return;
+       }
+
+       switch ((int) pusher->v->solid)
        {
        // LordHavoc: valid pusher types
        case SOLID_BSP:
        {
        // LordHavoc: valid pusher types
        case SOLID_BSP:
@@ -460,279 +583,201 @@ void SV_PushMove (edict_t *pusher, float movetime)
        // LordHavoc: no collisions
        case SOLID_NOT:
        case SOLID_TRIGGER:
        // LordHavoc: no collisions
        case SOLID_NOT:
        case SOLID_TRIGGER:
-               VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
-               pusher->v.ltime += movetime;
+               VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
+               VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
+               pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
+               pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
+               pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
+               pusher->v->ltime += movetime;
                SV_LinkEdict (pusher, false);
                return;
        default:
                SV_LinkEdict (pusher, false);
                return;
        default:
-               Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
+               Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
+               return;
        }
        }
-       if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
+       index = (int) pusher->v->modelindex;
+       if (index < 1 || index >= MAX_MODELS)
        {
        {
-               pusher->v.ltime += movetime;
+               Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
                return;
        }
                return;
        }
+       pushermodel = sv.models[index];
 
 
-       for (i=0 ; i<3 ; i++)
+       movetime2 = movetime;
+       VectorScale(pusher->v->velocity, movetime2, move1);
+       VectorScale(pusher->v->avelocity, movetime2, moveangle);
+       if (moveangle[0] || moveangle[2])
        {
        {
-               move[i] = pusher->v.velocity[i] * movetime;
-               mins[i] = pusher->v.absmin[i] + move[i];
-               maxs[i] = pusher->v.absmax[i] + move[i];
+               for (i = 0;i < 3;i++)
+               {
+                       if (move1[i] > 0)
+                       {
+                               mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
+                       }
+                       else
+                       {
+                               mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
+                       }
+               }
+       }
+       else if (moveangle[1])
+       {
+               for (i = 0;i < 3;i++)
+               {
+                       if (move1[i] > 0)
+                       {
+                               mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
+                       }
+                       else
+                       {
+                               mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
+                       }
+               }
+       }
+       else
+       {
+               for (i = 0;i < 3;i++)
+               {
+                       if (move1[i] > 0)
+                       {
+                               mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
+                       }
+                       else
+                       {
+                               mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
+                               maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
+                       }
+               }
        }
 
        }
 
-       VectorCopy (pusher->v.origin, pushorig);
-       
+       VectorNegate (moveangle, a);
+       AngleVectorsFLU (a, forward, left, up);
+
+       VectorCopy (pusher->v->origin, pushorig);
+       VectorCopy (pusher->v->angles, pushang);
+       pushltime = pusher->v->ltime;
+
 // move the pusher to it's final position
 
 // move the pusher to it's final position
 
-       VectorAdd (pusher->v.origin, move, pusher->v.origin);
-       pusher->v.ltime += movetime;
+       VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
+       VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
+       pusher->v->ltime += movetime;
        SV_LinkEdict (pusher, false);
 
        SV_LinkEdict (pusher, false);
 
+       savesolid = pusher->v->solid;
 
 // see if any solid entities are inside the final position
        num_moved = 0;
        check = NEXT_EDICT(sv.edicts);
        for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
        {
 
 // see if any solid entities are inside the final position
        num_moved = 0;
        check = NEXT_EDICT(sv.edicts);
        for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
        {
-               if (check->free)
+               if (check->e->free)
                        continue;
                        continue;
-               if (check->v.movetype == MOVETYPE_PUSH
-                || check->v.movetype == MOVETYPE_NONE
-                || check->v.movetype == MOVETYPE_FOLLOW
-                || check->v.movetype == MOVETYPE_NOCLIP)
+               if (check->v->movetype == MOVETYPE_PUSH
+                || check->v->movetype == MOVETYPE_NONE
+                || check->v->movetype == MOVETYPE_FOLLOW
+                || check->v->movetype == MOVETYPE_NOCLIP
+                || check->v->movetype == MOVETYPE_FAKEPUSH)
                        continue;
 
                // if the entity is standing on the pusher, it will definitely be moved
                        continue;
 
                // if the entity is standing on the pusher, it will definitely be moved
-               if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
+               if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
                {
                {
-                       if (check->v.absmin[0] >= maxs[0]
-                        || check->v.absmin[1] >= maxs[1]
-                        || check->v.absmin[2] >= maxs[2]
-                        || check->v.absmax[0] <= mins[0]
-                        || check->v.absmax[1] <= mins[1]
-                        || check->v.absmax[2] <= mins[2])
+                       if (check->v->absmin[0] >= maxs[0]
+                        || check->v->absmax[0] <= mins[0]
+                        || check->v->absmin[1] >= maxs[1]
+                        || check->v->absmax[1] <= mins[1]
+                        || check->v->absmin[2] >= maxs[2]
+                        || check->v->absmax[2] <= mins[2])
                                continue;
 
                                continue;
 
-                       // see if the ent's bbox is inside the pusher's final position
-                       if (!SV_TestEntityPosition (check))
+                       if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
                                continue;
                }
 
                                continue;
                }
 
+               if (forward[0] != 1) // quick way to check if any rotation is used
+               {
+                       VectorSubtract (check->v->origin, pusher->v->origin, org);
+                       org2[0] = DotProduct (org, forward);
+                       org2[1] = DotProduct (org, left);
+                       org2[2] = DotProduct (org, up);
+                       VectorSubtract (org2, org, move);
+                       VectorAdd (move, move1, move);
+               }
+               else
+                       VectorCopy (move1, move);
+
                // remove the onground flag for non-players
                // remove the onground flag for non-players
-               if (check->v.movetype != MOVETYPE_WALK)
-                       check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
-               
-               VectorCopy (check->v.origin, entorig);
-               VectorCopy (check->v.origin, moved_from[num_moved]);
-               moved_edict[num_moved] = check;
-               num_moved++;
-
-               // LordHavoc: pusher fixes (teleport train bug, etc)
-               savesolid = pusher->v.solid;
-               if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
+               if (check->v->movetype != MOVETYPE_WALK)
+                       check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
+
+               VectorCopy (check->v->origin, check->e->moved_from);
+               VectorCopy (check->v->angles, check->e->moved_fromangles);
+               sv.moved_edicts[num_moved++] = check;
+
+               // try moving the contacted entity
+               pusher->v->solid = SOLID_NOT;
+               trace = SV_PushEntity (check, move);
+               // FIXME: turn players specially
+               check->v->angles[1] += trace.fraction * moveangle[1];
+               pusher->v->solid = savesolid; // was SOLID_BSP
+
+               // if it is still inside the pusher, block
+               if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
                {
                {
-                       // try moving the contacted entity
-                       pusher->v.solid = SOLID_NOT;
+                       // try moving the contacted entity a tiny bit further to account for precision errors
+                       pusher->v->solid = SOLID_NOT;
+                       VectorScale(move, 0.1, move);
                        SV_PushEntity (check, move);
                        SV_PushEntity (check, move);
-                       pusher->v.solid = savesolid; // was SOLID_BSP
+                       pusher->v->solid = savesolid;
+                       if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
+                       {
+                               // still inside pusher, so it's really blocked
 
 
-                       // if it is still inside the pusher, block
-                       if (SV_TestEntityPosition (check))
-                       {       // fail the move
-                               if (check->v.mins[0] == check->v.maxs[0])
+                               // fail the move
+                               if (check->v->mins[0] == check->v->maxs[0])
                                        continue;
                                        continue;
-                               if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
-                               {       // corpse
-                                       check->v.mins[0] = check->v.mins[1] = 0;
-                                       VectorCopy (check->v.mins, check->v.maxs);
+                               if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
+                               {
+                                       // corpse
+                                       check->v->mins[0] = check->v->mins[1] = 0;
+                                       VectorCopy (check->v->mins, check->v->maxs);
                                        continue;
                                }
                                        continue;
                                }
-                               
-                               VectorCopy (entorig, check->v.origin);
-                               SV_LinkEdict (check, true);
 
 
-                               VectorCopy (pushorig, pusher->v.origin);
+                               VectorCopy (pushorig, pusher->v->origin);
+                               VectorCopy (pushang, pusher->v->angles);
+                               pusher->v->ltime = pushltime;
                                SV_LinkEdict (pusher, false);
                                SV_LinkEdict (pusher, false);
-                               pusher->v.ltime -= movetime;
+
+                               // move back any entities we already moved
+                               for (i = 0;i < num_moved;i++)
+                               {
+                                       ed = sv.moved_edicts[i];
+                                       VectorCopy (ed->e->moved_from, ed->v->origin);
+                                       VectorCopy (ed->e->moved_fromangles, ed->v->angles);
+                                       SV_LinkEdict (ed, false);
+                               }
 
                                // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
 
                                // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
-                               if (pusher->v.blocked)
+                               if (pusher->v->blocked)
                                {
                                        pr_global_struct->self = EDICT_TO_PROG(pusher);
                                        pr_global_struct->other = EDICT_TO_PROG(check);
                                {
                                        pr_global_struct->self = EDICT_TO_PROG(pusher);
                                        pr_global_struct->other = EDICT_TO_PROG(check);
-                                       PR_ExecuteProgram (pusher->v.blocked);
-                               }
-                               
-                               // move back any entities we already moved
-                               num_moved--; // LordHavoc: pop off check, because it was already restored
-                               for (i=0 ; i<num_moved ; i++)
-                               {
-                                       VectorCopy (moved_from[i], moved_edict[i]->v.origin);
-                                       SV_LinkEdict (moved_edict[i], false);
+                                       PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing");
                                }
                                }
-                               return;
-                       }       
-               }
-       }
-
-       
-}
-
-/*
-============
-SV_PushRotate
-
-============
-*/
-void SV_PushRotate (edict_t *pusher, float movetime)
-{
-       int                     i, e;
-       edict_t         *check;
-       vec3_t          move, a, amove;
-       vec3_t          entorigin, entangles, pushorigin, pushangles;
-       int                     num_moved;
-       edict_t         *moved_edict[MAX_EDICTS];
-       vec3_t          moved_from[MAX_EDICTS];
-       vec3_t          angled_from[MAX_EDICTS];
-       vec3_t          org, org2;
-       vec3_t          forward, right, up;
-       float           savesolid;
-
-       switch ((int) pusher->v.solid)
-       {
-       // LordHavoc: valid pusher types
-       case SOLID_BSP:
-       case SOLID_BBOX:
-       case SOLID_SLIDEBOX:
-       case SOLID_CORPSE: // LordHavoc: this would be weird...
-               break;
-       // LordHavoc: no collisions
-       case SOLID_NOT:
-       case SOLID_TRIGGER:
-               VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
-               pusher->v.ltime += movetime;
-               SV_LinkEdict (pusher, false);
-               return;
-       default:
-               Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
-       }
-       if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
-       {
-               pusher->v.ltime += movetime;
-               return;
-       }
-
-       for (i=0 ; i<3 ; i++)
-               amove[i] = pusher->v.avelocity[i] * movetime;
-
-       VectorSubtract (vec3_origin, amove, a);
-       AngleVectors (a, forward, right, up);
-
-       VectorCopy (pusher->v.origin, pushorigin);
-       VectorCopy (pusher->v.angles, pushangles);
-       
-// move the pusher to it's final position
-
-       VectorAdd (pusher->v.angles, amove, pusher->v.angles);
-       pusher->v.ltime += movetime;
-       SV_LinkEdict (pusher, false);
-
-
-// see if any solid entities are inside the final position
-       num_moved = 0;
-       check = NEXT_EDICT(sv.edicts);
-       for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
-       {
-               if (check->free)
-                       continue;
-               if (check->v.movetype == MOVETYPE_PUSH
-                || check->v.movetype == MOVETYPE_NONE
-                || check->v.movetype == MOVETYPE_FOLLOW
-                || check->v.movetype == MOVETYPE_NOCLIP)
-                       continue;
-
-       // if the entity is standing on the pusher, it will definately be moved
-               if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
-               {
-                       if (check->v.absmin[0] >= pusher->v.absmax[0]
-                        || check->v.absmin[1] >= pusher->v.absmax[1]
-                        || check->v.absmin[2] >= pusher->v.absmax[2]
-                        || check->v.absmax[0] <= pusher->v.absmin[0]
-                        || check->v.absmax[1] <= pusher->v.absmin[1]
-                        || check->v.absmax[2] <= pusher->v.absmin[2])
-                               continue;
-
-               // see if the ent's bbox is inside the pusher's final position
-                       if (!SV_TestEntityPosition (check))
-                               continue;
-               }
-
-       // remove the onground flag for non-players
-               if (check->v.movetype != MOVETYPE_WALK)
-                       check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
-               
-               VectorCopy (check->v.origin, entorigin);
-               VectorCopy (check->v.origin, moved_from[num_moved]);
-               VectorCopy (check->v.angles, entangles);
-               VectorCopy (check->v.angles, angled_from[num_moved]);
-               moved_edict[num_moved] = check;
-               num_moved++;
-
-               // calculate destination position
-               VectorSubtract (check->v.origin, pusher->v.origin, org);
-               org2[0] = DotProduct (org, forward);
-               org2[1] = -DotProduct (org, right);
-               org2[2] = DotProduct (org, up);
-               VectorSubtract (org2, org, move);
-
-               // try moving the contacted entity 
-               savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
-               pusher->v.solid = SOLID_NOT;
-               SV_PushEntity (check, move);
-               pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
-
-               VectorAdd (check->v.angles, amove, check->v.angles);
-
-       // if it is still inside the pusher, block
-               if (SV_TestEntityPosition (check))
-               {       // fail the move
-                       if (check->v.mins[0] == check->v.maxs[0])
-                               continue;
-                       if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
-                       {       // corpse
-                               check->v.mins[0] = check->v.mins[1] = 0;
-                               VectorCopy (check->v.mins, check->v.maxs);
-                               continue;
-                       }
-                       
-                       VectorCopy (entorigin, check->v.origin);
-                       VectorCopy (entangles, check->v.angles);
-                       SV_LinkEdict (check, true);
-
-                       VectorCopy (pushorigin, pusher->v.origin);
-                       VectorCopy (pushangles, pusher->v.angles);
-                       SV_LinkEdict (pusher, false);
-                       pusher->v.ltime -= movetime;
-
-                       // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
-                       if (pusher->v.blocked)
-                       {
-                               pr_global_struct->self = EDICT_TO_PROG(pusher);
-                               pr_global_struct->other = EDICT_TO_PROG(check);
-                               PR_ExecuteProgram (pusher->v.blocked);
-                       }
-                       
-               // move back any entities we already moved
-                       num_moved--; // LordHavoc: pop off check, because it was already restored
-                       for (i=0 ; i<num_moved ; i++)
-                       {
-                               VectorCopy (moved_from[i], moved_edict[i]->v.origin);
-                               VectorCopy (angled_from[i], moved_edict[i]->v.angles);
-                               SV_LinkEdict (moved_edict[i], false);
+                               break;
                        }
                        }
-                       return;
                }
        }
                }
        }
+       pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
+       pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
+       pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
 }
 
 /*
 }
 
 /*
@@ -743,41 +788,32 @@ SV_Physics_Pusher
 */
 void SV_Physics_Pusher (edict_t *ent)
 {
 */
 void SV_Physics_Pusher (edict_t *ent)
 {
-       float   thinktime;
-       float   oldltime;
-       float   movetime;
+       float thinktime, oldltime, movetime;
 
 
-       oldltime = ent->v.ltime;
-       
-       thinktime = ent->v.nextthink;
-       if (thinktime < ent->v.ltime + host_frametime)
+       oldltime = ent->v->ltime;
+
+       thinktime = ent->v->nextthink;
+       if (thinktime < ent->v->ltime + sv.frametime)
        {
        {
-               movetime = thinktime - ent->v.ltime;
+               movetime = thinktime - ent->v->ltime;
                if (movetime < 0)
                        movetime = 0;
        }
        else
                if (movetime < 0)
                        movetime = 0;
        }
        else
-               movetime = host_frametime;
+               movetime = sv.frametime;
 
        if (movetime)
 
        if (movetime)
+               // advances ent->v->ltime if not blocked
+               SV_PushMove (ent, movetime);
+
+       if (thinktime > oldltime && thinktime <= ent->v->ltime)
        {
        {
-               if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
-                       SV_PushRotate (ent, movetime);
-               else
-                       SV_PushMove (ent, movetime);    // advances ent->v.ltime if not blocked
-       }
-               
-       if (thinktime > oldltime && thinktime <= ent->v.ltime)
-       {
-               ent->v.nextthink = 0;
+               ent->v->nextthink = 0;
                pr_global_struct->time = sv.time;
                pr_global_struct->self = EDICT_TO_PROG(ent);
                pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
                pr_global_struct->time = sv.time;
                pr_global_struct->self = EDICT_TO_PROG(ent);
                pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
-               PR_ExecuteProgram (ent->v.think);
-               if (ent->free)
-                       return;
+               PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
        }
        }
-
 }
 
 
 }
 
 
@@ -799,42 +835,41 @@ clipping hull.
 */
 void SV_CheckStuck (edict_t *ent)
 {
 */
 void SV_CheckStuck (edict_t *ent)
 {
-       int             i, j;
-       int             z;
-       vec3_t  org;
+       int i, j, z;
+       vec3_t org;
 
        if (!SV_TestEntityPosition(ent))
        {
 
        if (!SV_TestEntityPosition(ent))
        {
-               VectorCopy (ent->v.origin, ent->v.oldorigin);
+               VectorCopy (ent->v->origin, ent->v->oldorigin);
                return;
        }
 
                return;
        }
 
-       VectorCopy (ent->v.origin, org);
-       VectorCopy (ent->v.oldorigin, ent->v.origin);
+       VectorCopy (ent->v->origin, org);
+       VectorCopy (ent->v->oldorigin, ent->v->origin);
        if (!SV_TestEntityPosition(ent))
        {
        if (!SV_TestEntityPosition(ent))
        {
-               Con_DPrint("Unstuck.\n");
+               Con_DPrint("Unstuck.\n");
                SV_LinkEdict (ent, true);
                return;
        }
                SV_LinkEdict (ent, true);
                return;
        }
-       
+
        for (z=0 ; z< 18 ; z++)
                for (i=-1 ; i <= 1 ; i++)
                        for (j=-1 ; j <= 1 ; j++)
                        {
        for (z=0 ; z< 18 ; z++)
                for (i=-1 ; i <= 1 ; i++)
                        for (j=-1 ; j <= 1 ; j++)
                        {
-                               ent->v.origin[0] = org[0] + i;
-                               ent->v.origin[1] = org[1] + j;
-                               ent->v.origin[2] = org[2] + z;
+                               ent->v->origin[0] = org[0] + i;
+                               ent->v->origin[1] = org[1] + j;
+                               ent->v->origin[2] = org[2] + z;
                                if (!SV_TestEntityPosition(ent))
                                {
                                if (!SV_TestEntityPosition(ent))
                                {
-                                       Con_DPrint("Unstuck.\n");
+                                       Con_DPrint("Unstuck.\n");
                                        SV_LinkEdict (ent, true);
                                        return;
                                }
                        }
                                        SV_LinkEdict (ent, true);
                                        return;
                                }
                        }
-                       
-       VectorCopy (org, ent->v.origin);
-       Con_DPrint("player is stuck.\n");
+
+       VectorCopy (org, ent->v->origin);
+       Con_DPrint("player is stuck.\n");
 }
 
 
 }
 
 
@@ -845,33 +880,33 @@ SV_CheckWater
 */
 qboolean SV_CheckWater (edict_t *ent)
 {
 */
 qboolean SV_CheckWater (edict_t *ent)
 {
-       vec3_t  point;
-       int             cont;
+       int cont;
+       vec3_t point;
 
 
-       point[0] = ent->v.origin[0];
-       point[1] = ent->v.origin[1];
-       point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;       
-       
-       ent->v.waterlevel = 0;
-       ent->v.watertype = CONTENTS_EMPTY;
-       cont = SV_PointContents (point);
+       point[0] = ent->v->origin[0];
+       point[1] = ent->v->origin[1];
+       point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
+
+       ent->v->waterlevel = 0;
+       ent->v->watertype = CONTENTS_EMPTY;
+       cont = SV_PointQ1Contents(point);
        if (cont <= CONTENTS_WATER)
        {
        if (cont <= CONTENTS_WATER)
        {
-               ent->v.watertype = cont;
-               ent->v.waterlevel = 1;
-               point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
-               cont = SV_PointContents (point);
+               ent->v->watertype = 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 (cont <= CONTENTS_WATER)
                {
-                       ent->v.waterlevel = 2;
-                       point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
-                       cont = SV_PointContents (point);
+                       ent->v->waterlevel = 2;
+                       point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
+                       cont = SV_PointQ1Contents(point);
                        if (cont <= CONTENTS_WATER)
                        if (cont <= CONTENTS_WATER)
-                               ent->v.waterlevel = 3;
+                               ent->v->waterlevel = 3;
                }
        }
                }
        }
-       
-       return ent->v.waterlevel > 1;
+
+       return ent->v->waterlevel > 1;
 }
 
 /*
 }
 
 /*
@@ -880,26 +915,21 @@ SV_WallFriction
 
 ============
 */
 
 ============
 */
-void SV_WallFriction (edict_t *ent, trace_t *trace)
+void SV_WallFriction (edict_t *ent, float *stepnormal)
 {
 {
-       vec3_t          forward, right, up;
-       float           d, i;
-       vec3_t          into, side;
-       
-       AngleVectors (ent->v.v_angle, forward, right, up);
-       d = DotProduct (trace->plane.normal, forward);
-       
-       d += 0.5;
-       if (d >= 0)
-               return;
-               
-// cut the tangential velocity
-       i = DotProduct (trace->plane.normal, ent->v.velocity);
-       VectorScale (trace->plane.normal, i, into);
-       VectorSubtract (ent->v.velocity, into, side);
-       
-       ent->v.velocity[0] = side[0] * (1 + d);
-       ent->v.velocity[1] = side[1] * (1 + d);
+       float d, i;
+       vec3_t forward, into, side;
+
+       AngleVectors (ent->v->v_angle, forward, NULL, NULL);
+       if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
+       {
+               // cut the tangential velocity
+               i = DotProduct (stepnormal, ent->v->velocity);
+               VectorScale (stepnormal, i, into);
+               VectorSubtract (ent->v->velocity, into, side);
+               ent->v->velocity[0] = side[0] * (1 + d);
+               ent->v->velocity[1] = side[1] * (1 + d);
+       }
 }
 
 /*
 }
 
 /*
@@ -916,51 +946,50 @@ This is a hack, but in the interest of good gameplay...
 */
 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
 {
 */
 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
 {
-       int             i;
-       vec3_t  oldorg;
-       vec3_t  dir;
-       int             clip;
-       trace_t steptrace;
-       
-       VectorCopy (ent->v.origin, oldorg);
-       VectorCopy (vec3_origin, dir);
+       int i, clip;
+       vec3_t oldorg, dir;
+
+       VectorCopy (ent->v->origin, oldorg);
+       VectorClear (dir);
 
        for (i=0 ; i<8 ; i++)
        {
 
        for (i=0 ; i<8 ; i++)
        {
-// try pushing a little in an axial direction
+               // try pushing a little in an axial direction
                switch (i)
                {
                switch (i)
                {
-                       case 0: dir[0] = 2; dir[1] = 0; break;
-                       case 1: dir[0] = 0; dir[1] = 2; break;
-                       case 2: dir[0] = -2; dir[1] = 0; break;
-                       case 3: dir[0] = 0; dir[1] = -2; break;
-                       case 4: dir[0] = 2; dir[1] = 2; break;
-                       case 5: dir[0] = -2; dir[1] = 2; break;
-                       case 6: dir[0] = 2; dir[1] = -2; break;
-                       case 7: dir[0] = -2; dir[1] = -2; break;
+                       case 0: dir[0] = 2; dir[1] = 0; break;
+                       case 1: dir[0] = 0; dir[1] = 2; break;
+                       case 2: dir[0] = -2; dir[1] = 0; break;
+                       case 3: dir[0] = 0; dir[1] = -2; break;
+                       case 4: dir[0] = 2; dir[1] = 2; break;
+                       case 5: dir[0] = -2; dir[1] = 2; break;
+                       case 6: dir[0] = 2; dir[1] = -2; break;
+                       case 7: dir[0] = -2; dir[1] = -2; break;
                }
                }
-               
+
                SV_PushEntity (ent, dir);
 
                SV_PushEntity (ent, dir);
 
-// retry the original move
-               ent->v.velocity[0] = oldvel[0];
-               ent->vvelocity[1] = oldvel[1];
-               ent->vvelocity[2] = 0;
-               clip = SV_FlyMove (ent, 0.1, &steptrace);
+               // retry the original move
+               ent->v->velocity[0] = oldvel[0];
+               ent->v->velocity[1] = oldvel[1];
+               ent->v->velocity[2] = 0;
+               clip = SV_FlyMove (ent, 0.1, NULL);
 
 
-               if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
-               || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
+               if (fabs(oldorg[1] - ent->v->origin[1]) > 4
+                || fabs(oldorg[0] - ent->v->origin[0]) > 4)
                {
                {
-//Con_DPrintf ("unstuck!\n");
+                       Con_DPrint("TryUnstick - success.\n");
                        return clip;
                }
                        return clip;
                }
-                       
-// go back to the original pos and try again
-               VectorCopy (oldorg, ent->v.origin);
+
+               // go back to the original pos and try again
+               VectorCopy (oldorg, ent->v->origin);
        }
        }
-       
-       VectorCopy (vec3_origin, ent->v.velocity);
-       return 7;               // still not moving
+
+       // still not moving
+       VectorClear (ent->v->velocity);
+       Con_DPrint("TryUnstick - failure.\n");
+       return 7;
 }
 
 /*
 }
 
 /*
@@ -970,190 +999,138 @@ SV_WalkMove
 Only used by players
 ======================
 */
 Only used by players
 ======================
 */
-#define        STEPSIZE        18
 void SV_WalkMove (edict_t *ent)
 {
 void SV_WalkMove (edict_t *ent)
 {
-       vec3_t          upmove, downmove;
-       vec3_t          oldorg, oldvel;
-       vec3_t          nosteporg, nostepvel;
-       int                     clip;
-       int                     oldonground;
-       trace_t         steptrace, downtrace;
-       
-//
-// do a regular slide move unless it looks like you ran into a step
-//
-       oldonground = (int)ent->v.flags & FL_ONGROUND;
-       ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
-       
-       VectorCopy (ent->v.origin, oldorg);
-       VectorCopy (ent->v.velocity, oldvel);
-       
-       clip = SV_FlyMove (ent, host_frametime, &steptrace);
+       int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
+       vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
+       trace_t downtrace;
 
 
-       if ( !(clip & 2) )
-               return;         // move didn't block on a step
+       SV_CheckVelocity(ent);
 
 
-       if (!oldonground && ent->v.waterlevel == 0)
-               return;         // don't stair up while jumping
-       
-       if (ent->v.movetype != MOVETYPE_WALK)
-               return;         // gibbed by a trigger
-       
-       if (sv_nostep.value)
-               return;
-       
-       if ( (int)sv_player->v.flags & FL_WATERJUMP )
-               return;
+       // do a regular slide move unless it looks like you ran into a step
+       oldonground = (int)ent->v->flags & FL_ONGROUND;
+       ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
 
 
-       VectorCopy (ent->v.origin, nosteporg);
-       VectorCopy (ent->v.velocity, nostepvel);
+       VectorCopy (ent->v->origin, start_origin);
+       VectorCopy (ent->v->velocity, start_velocity);
 
 
-//
-// try moving up and forward to go up a step
-//
-       VectorCopy (oldorg, ent->v.origin);     // back to start pos
+       clip = SV_FlyMove (ent, sv.frametime, NULL);
 
 
-       VectorCopy (vec3_origin, upmove);
-       VectorCopy (vec3_origin, downmove);
-       upmove[2] = STEPSIZE;
-       downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
+       SV_SetOnGround (ent);
+       SV_CheckVelocity(ent);
 
 
-// move up
-       SV_PushEntity (ent, upmove);    // FIXME: don't link?
+       VectorCopy(ent->v->origin, originalmove_origin);
+       VectorCopy(ent->v->velocity, originalmove_velocity);
+       originalmove_clip = clip;
+       originalmove_flags = (int)ent->v->flags;
+       originalmove_groundentity = ent->v->groundentity;
 
 
-// move forward
-       ent->v.velocity[0] = oldvel[0];
-       ent->v. velocity[1] = oldvel[1];
-       ent->v. velocity[2] = 0;
-       clip = SV_FlyMove (ent, host_frametime, &steptrace);
+       if ((int)ent->v->flags & FL_WATERJUMP)
+               return;
 
 
-// check for stuckness, possibly due to the limited precision of floats
-// in the clipping hulls
-       if (clip)
+       if (sv_nostep.integer)
+               return;
+       
+       // if move didn't block on a step, return
+       if (clip & 2)
        {
        {
-               if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
-               && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
-               {       // stepping up didn't make any progress
-                       clip = SV_TryUnstick (ent, oldvel);
+               // 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;
                }
                }
-       }
        
        
-// extra friction based on view angle
-       if ( clip & 2 )
-               SV_WallFriction (ent, &steptrace);
+               // 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
+                && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
+                && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
+               {
+                       //Con_Printf("wall\n");
+                       // stepping up didn't make any progress, revert to original move
+                       VectorCopy(originalmove_origin, ent->v->origin);
+                       VectorCopy(originalmove_velocity, ent->v->velocity);
+                       //clip = originalmove_clip;
+                       ent->v->flags = originalmove_flags;
+                       ent->v->groundentity = originalmove_groundentity; 
+                       // now try to unstick if needed
+                       //clip = SV_TryUnstick (ent, oldvel);
+                       return;
+               }
 
 
-// move down
-       downtrace = SV_PushEntity (ent, downmove);      // FIXME: don't link?
+               //Con_Printf("step - ");
 
 
-       if (downtrace.plane.normal[2] > 0.7)
+               // extra friction based on view angle
+               if (clip & 2 && sv_wallfriction.integer)
+                       SV_WallFriction (ent, stepnormal);
+       }
+       // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
+       else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
+               return;
+
+       // move down
+       VectorClear (downmove);
+       downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
+       // FIXME: don't link?
+       downtrace = SV_PushEntity (ent, downmove);
+
+       if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
        {
        {
-               if (ent->v.solid == SOLID_BSP)
+               // LordHavoc: disabled this check so you can walk on monsters/players
+               //if (ent->v->solid == SOLID_BSP)
                {
                {
-                       ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
-                       ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
+                       //Con_Printf("onground\n");
+                       ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+                       ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
                }
        }
        else
        {
                }
        }
        else
        {
-// if the push down didn't end up on good ground, use the move without
-// the step up.  This happens near wall / slope combinations, and can
-// cause the player to hop up higher on a slope too steep to climb     
-               VectorCopy (nosteporg, ent->v.origin);
-               VectorCopy (nostepvel, ent->v.velocity);
+               //Con_Printf("slope\n");
+               // if the push down didn't end up on good ground, use the move without
+               // the step up.  This happens near wall / slope combinations, and can
+               // cause the player to hop up higher on a slope too steep to climb
+               VectorCopy(originalmove_origin, ent->v->origin);
+               VectorCopy(originalmove_velocity, ent->v->velocity);
+               //clip = originalmove_clip;
+               ent->v->flags = originalmove_flags;
+               ent->v->groundentity = originalmove_groundentity; 
        }
        }
-}
-
-
-/*
-================
-SV_Physics_Client
-
-Player character actions
-================
-*/
-void SV_Physics_Client (edict_t        *ent, int num)
-{
-       if ( ! svs.clients[num-1].active )
-               return;         // unconnected slot
-
-//
-// call standard client pre-think
-//     
-       pr_global_struct->time = sv.time;
-       pr_global_struct->self = EDICT_TO_PROG(ent);
-       PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
-       
-//
-// do a move
-//
-       SV_CheckVelocity (ent);
-
-//
-// decide which move function to call
-//
-       switch ((int)ent->v.movetype)
-       {
-       case MOVETYPE_NONE:
-               if (!SV_RunThink (ent))
-                       return;
-               break;
-
-       case MOVETYPE_WALK:
-               if (!SV_RunThink (ent))
-                       return;
-               if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
-                       SV_AddGravity (ent);
-               SV_CheckStuck (ent);
-               SV_WalkMove (ent);
-               break;
-               
-       case MOVETYPE_TOSS:
-       case MOVETYPE_BOUNCE:
-               SV_Physics_Toss (ent);
-               break;
-
-       case MOVETYPE_FLY:
-               if (!SV_RunThink (ent))
-                       return;
-               SV_FlyMove (ent, host_frametime, NULL);
-               break;
-               
-       case MOVETYPE_NOCLIP:
-               if (!SV_RunThink (ent))
-                       return;
-               VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
-               break;
-               
-       default:
-               Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
-       }
-
-//
-// call standard player post-think
-//             
-       SV_LinkEdict (ent, true);
 
 
-       pr_global_struct->time = sv.time;
-       pr_global_struct->self = EDICT_TO_PROG(ent);
-       PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
+       SV_SetOnGround (ent);
+       SV_CheckVelocity(ent);
 }
 
 //============================================================================
 
 }
 
 //============================================================================
 
-/*
-=============
-SV_Physics_None
-
-Non moving objects can only think
-=============
-*/
-void SV_Physics_None (edict_t *ent)
-{
-// regular thinking
-       SV_RunThink (ent);
-}
-
 /*
 =============
 SV_Physics_Follow
 /*
 =============
 SV_Physics_Follow
@@ -1163,57 +1140,41 @@ Entities that are "stuck" to another entity
 */
 void SV_Physics_Follow (edict_t *ent)
 {
 */
 void SV_Physics_Follow (edict_t *ent)
 {
-       vec3_t vf, vr, vu, angles;
+       vec3_t vf, vr, vu, angles, v;
        edict_t *e;
        edict_t *e;
-// regular thinking
+
+       // regular thinking
        if (!SV_RunThink (ent))
                return;
        if (!SV_RunThink (ent))
                return;
+
        // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
        // 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])
+       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])
        {
                // quick case for no rotation
        {
                // quick case for no rotation
-               VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
+               VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
        }
        else
        {
        }
        else
        {
-               angles[0] = -(e->v.angles[0] - ent->v.punchangle[0]);
-               angles[1] = e->v.angles[1] - ent->v.punchangle[1];
-               angles[2] = e->v.angles[2] - ent->v.punchangle[2];
+               angles[0] = -ent->v->punchangle[0];
+               angles[1] =  ent->v->punchangle[1];
+               angles[2] =  ent->v->punchangle[2];
                AngleVectors (angles, vf, vr, vu);
                AngleVectors (angles, vf, vr, vu);
-               ent->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0] + e->v.origin[0];
-               ent->v.origin[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1] + e->v.origin[1];
-               ent->v.origin[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2] + e->v.origin[2];
-               /*
-               ent->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[0] * vf[2] + e->v.origin[0];
-               ent->v.origin[1] = ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[1] * vr[2] + e->v.origin[1];
-               ent->v.origin[2] = ent->v.view_ofs[2] * vu[0] + ent->v.view_ofs[2] * vu[1] + ent->v.view_ofs[2] * vu[2] + e->v.origin[2];
-               */
+               v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
+               v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
+               v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
+               angles[0] = -e->v->angles[0];
+               angles[1] =  e->v->angles[1];
+               angles[2] =  e->v->angles[2];
+               AngleVectors (angles, vf, vr, vu);
+               ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
+               ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
+               ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
        }
        }
-       VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
-//     VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
+       VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
        SV_LinkEdict (ent, true);
 }
 
        SV_LinkEdict (ent, true);
 }
 
-/*
-=============
-SV_Physics_Noclip
-
-A moving object that doesn't obey physics
-=============
-*/
-void SV_Physics_Noclip (edict_t *ent)
-{
-// regular thinking
-       if (!SV_RunThink (ent))
-               return;
-       
-       VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
-       VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
-
-       SV_LinkEdict (ent, false);
-}
-
 /*
 ==============================================================================
 
 /*
 ==============================================================================
 
@@ -1230,32 +1191,29 @@ SV_CheckWaterTransition
 */
 void SV_CheckWaterTransition (edict_t *ent)
 {
 */
 void SV_CheckWaterTransition (edict_t *ent)
 {
-       int             cont;
-       cont = SV_PointContents (ent->v.origin);
-       if (!ent->v.watertype)
-       {       // just spawned here
-               ent->v.watertype = cont;
-               ent->v.waterlevel = 1;
+       int cont;
+       cont = SV_PointQ1Contents(ent->v->origin);
+       if (!ent->v->watertype)
+       {
+               // just spawned here
+               ent->v->watertype = cont;
+               ent->v->waterlevel = 1;
                return;
        }
                return;
        }
-       
+
+       // check if the entity crossed into or out of water
+       if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
+               SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
+
        if (cont <= CONTENTS_WATER)
        {
        if (cont <= CONTENTS_WATER)
        {
-               if (ent->v.watertype == CONTENTS_EMPTY)
-               {       // just crossed into water
-                       SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
-               }               
-               ent->v.watertype = cont;
-               ent->v.waterlevel = 1;
+               ent->v->watertype = cont;
+               ent->v->waterlevel = 1;
        }
        else
        {
        }
        else
        {
-               if (ent->v.watertype != CONTENTS_EMPTY)
-               {       // just crossed into water
-                       SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
-               }               
-               ent->v.watertype = CONTENTS_EMPTY;
-               ent->v.waterlevel = cont;
+               ent->v->watertype = CONTENTS_EMPTY;
+               ent->v->waterlevel = 0;
        }
 }
 
        }
 }
 
@@ -1268,57 +1226,111 @@ Toss, bounce, and fly movement.  When onground, do nothing.
 */
 void SV_Physics_Toss (edict_t *ent)
 {
 */
 void SV_Physics_Toss (edict_t *ent)
 {
-       trace_t trace;
-       vec3_t  move;
-       float   backoff;
+       trace_t trace;
+       vec3_t move;
+       edict_t *groundentity;
+
        // regular thinking
        if (!SV_RunThink (ent))
                return;
 
        // regular thinking
        if (!SV_RunThink (ent))
                return;
 
+       // don't stick to ground if onground and moving upward
+       if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
+               ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
+
 // if onground, return without moving
 // if onground, return without moving
-       if ( ((int)ent->v.flags & FL_ONGROUND) )
-               return;
+       if ((int)ent->v->flags & FL_ONGROUND)
+       {
+               if (!sv_gameplayfix_noairborncorpse.integer)
+                       return;
+               if (ent->v->groundentity == 0)
+                       return;
+               // if ent was supported by a brush model on previous frame,
+               // and groundentity is now freed, set groundentity to 0 (floating)
+               groundentity = PROG_TO_EDICT(ent->v->groundentity);
+               if (groundentity->v->solid == SOLID_BSP)
+               {
+                       ent->e->suspendedinairflag = true;
+                       return;
+               }
+               else if (ent->e->suspendedinairflag && groundentity->e->free)
+               {
+                       // leave it suspended in the air
+                       ent->v->groundentity = 0;
+                       ent->e->suspendedinairflag = false;
+                       return;
+               }
+       }
+       ent->e->suspendedinairflag = false;
 
        SV_CheckVelocity (ent);
 
 // add gravity
 
        SV_CheckVelocity (ent);
 
 // add gravity
-       if (ent->v.movetype != MOVETYPE_FLY
-       && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
-       && ent->v.movetype != MOVETYPE_FLYMISSILE)
+       if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
                SV_AddGravity (ent);
 
 // move angles
                SV_AddGravity (ent);
 
 // move angles
-       VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
+       VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
 
 // move origin
 
 // move origin
-       VectorScale (ent->v.velocity, host_frametime, move);
+       VectorScale (ent->v->velocity, sv.frametime, move);
        trace = SV_PushEntity (ent, move);
        trace = SV_PushEntity (ent, move);
-       if (trace.fraction == 1)
-               return;
-       if (ent->free)
+       if (ent->e->free)
                return;
                return;
-       
-       if (ent->v.movetype == MOVETYPE_BOUNCE)
-               backoff = 1.5;
-       else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
-               backoff = 2.0;
-       else
-               backoff = 1;
-
-       ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
 
 
-// stop if on ground
-       if (trace.plane.normal[2] > 0.7)
-       {               
-               if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
+       if (trace.fraction < 1)
+       {
+               if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
                {
                {
-                       ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
-                       ent->v.groundentity = EDICT_TO_PROG(trace.ent);
-                       VectorCopy (vec3_origin, ent->v.velocity);
-                       VectorCopy (vec3_origin, ent->v.avelocity);
+                       ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
+                       ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
+               }
+               else if (ent->v->movetype == MOVETYPE_BOUNCE)
+               {
+                       float d;
+                       ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
+                       // LordHavoc: fixed grenades not bouncing when fired down a slope
+                       if (sv_gameplayfix_grenadebouncedownslopes.integer)
+                       {
+                               d = DotProduct(trace.plane.normal, ent->v->velocity);
+                               if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
+                               {
+                                       ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+                                       ent->v->groundentity = EDICT_TO_PROG(trace.ent);
+                                       VectorClear (ent->v->velocity);
+                                       VectorClear (ent->v->avelocity);
+                               }
+                               else
+                                       ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
+                       }
+                       else
+                       {
+                               if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
+                               {
+                                       ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+                                       ent->v->groundentity = EDICT_TO_PROG(trace.ent);
+                                       VectorClear (ent->v->velocity);
+                                       VectorClear (ent->v->avelocity);
+                               }
+                               else
+                                       ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
+                       }
+               }
+               else
+               {
+                       ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
+                       if (trace.plane.normal[2] > 0.7)
+                       {
+                               ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
+                               ent->v->groundentity = EDICT_TO_PROG(trace.ent);
+                               VectorClear (ent->v->velocity);
+                               VectorClear (ent->v->avelocity);
+                       }
+                       else
+                               ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
                }
        }
                }
        }
-       
+
 // check for in water
        SV_CheckWaterTransition (ent);
 }
 // check for in water
        SV_CheckWaterTransition (ent);
 }
@@ -1344,32 +1356,29 @@ will fall if the floor is pulled out from under them.
 */
 void SV_Physics_Step (edict_t *ent)
 {
 */
 void SV_Physics_Step (edict_t *ent)
 {
-       qboolean        hitsound;
+       // don't stick to ground if onground and moving upward
+       if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
+               ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
 
 
-// freefall if not onground
-       if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
+       // freefall if not onground/fly/swim
+       if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
        {
        {
-               if (ent->v.velocity[2] < sv_gravity.value*-0.1)
-                       hitsound = true;
-               else
-                       hitsound = false;
+               int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
 
 
-               SV_AddGravity (ent);
-               SV_CheckVelocity (ent);
-               SV_FlyMove (ent, host_frametime, NULL);
-               SV_LinkEdict (ent, true);
+               SV_AddGravity(ent);
+               SV_CheckVelocity(ent);
+               SV_FlyMove(ent, sv.frametime, NULL);
+               SV_LinkEdict(ent, true);
 
 
-               if ( (int)ent->v.flags & FL_ONGROUND )  // just hit ground
-               {
-                       if (hitsound)
-                               SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
-               }
+               // just hit ground
+               if (hitsound && (int)ent->v->flags & FL_ONGROUND)
+                       SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
        }
 
 // regular thinking
        }
 
 // regular thinking
-       SV_RunThink (ent);
-       
-       SV_CheckWaterTransition (ent);
+       SV_RunThink(ent);
+
+       SV_CheckWaterTransition(ent);
 }
 
 //============================================================================
 }
 
 //============================================================================
@@ -1380,19 +1389,16 @@ SV_Physics
 
 ================
 */
 
 ================
 */
-extern dfunction_t *EndFrameQC;
 void SV_Physics (void)
 {
 void SV_Physics (void)
 {
-       int             i;
-       edict_t *ent;
+       int i;
+       edict_t *ent;
 
 // let the progs know that a new frame has started
        pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->time = sv.time;
 
 // let the progs know that a new frame has started
        pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
        pr_global_struct->time = sv.time;
-       PR_ExecuteProgram (pr_global_struct->StartFrame);
-
-//SV_CheckAllEnts ();
+       PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
 
 //
 // treat each object in turn
 
 //
 // treat each object in turn
@@ -1400,60 +1406,106 @@ void SV_Physics (void)
        ent = sv.edicts;
        for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
        {
        ent = sv.edicts;
        for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
        {
-               if (ent->free)
+               if (ent->e->free)
                        continue;
 
                if (pr_global_struct->force_retouch)
                        SV_LinkEdict (ent, true);       // force retouch even for stationary
 
                        continue;
 
                if (pr_global_struct->force_retouch)
                        SV_LinkEdict (ent, true);       // force retouch even for stationary
 
-               if (i > 0 && i <= svs.maxclients)
+               if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
                {
                {
-                       SV_Physics_Client (ent, i);
-                       continue;
+                       // 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;
 
 
-               switch ((int) ent->v.movetype)
+               // LordHavoc: merged client and normal entity physics
+               switch ((int) ent->v->movetype)
                {
                case MOVETYPE_PUSH:
                {
                case MOVETYPE_PUSH:
+               case MOVETYPE_FAKEPUSH:
                        SV_Physics_Pusher (ent);
                        break;
                case MOVETYPE_NONE:
                        SV_Physics_Pusher (ent);
                        break;
                case MOVETYPE_NONE:
-                       SV_Physics_None (ent);
+                       // 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:
                        break;
                case MOVETYPE_FOLLOW:
                        SV_Physics_Follow (ent);
                        break;
                case MOVETYPE_NOCLIP:
-                       SV_Physics_Noclip (ent);
+                       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;
                        break;
                case MOVETYPE_STEP:
                        SV_Physics_Step (ent);
                        break;
-               // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
                case MOVETYPE_WALK:
                        if (SV_RunThink (ent))
                        {
                case MOVETYPE_WALK:
                        if (SV_RunThink (ent))
                        {
-                               if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
+                               if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
                                        SV_AddGravity (ent);
                                SV_CheckStuck (ent);
                                SV_WalkMove (ent);
                                        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:
                        }
                        break;
                case MOVETYPE_TOSS:
                case MOVETYPE_BOUNCE:
                case MOVETYPE_BOUNCEMISSILE:
-               case MOVETYPE_FLY:
                case MOVETYPE_FLYMISSILE:
                        SV_Physics_Toss (ent);
                        break;
                case MOVETYPE_FLYMISSILE:
                        SV_Physics_Toss (ent);
                        break;
+               case MOVETYPE_FLY:
+                       if (i > 0 && i <= svs.maxclients)
+                       {
+                               if (SV_RunThink (ent))
+                               {
+                                       SV_CheckWater (ent);
+                                       SV_WalkMove (ent);
+                               }
+                       }
+                       else
+                               SV_Physics_Toss (ent);
+                       break;
                default:
                default:
-                       Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
+                       Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
                        break;
                }
                        break;
                }
+
+               if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
+               {
+                       SV_CheckVelocity (ent);
+
+                       // 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)
        if (pr_global_struct->force_retouch)
-               pr_global_struct->force_retouch--;      
+               pr_global_struct->force_retouch--;
 
        // LordHavoc: endframe support
        if (EndFrameQC)
 
        // LordHavoc: endframe support
        if (EndFrameQC)
@@ -1461,42 +1513,56 @@ void SV_Physics (void)
                pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
                pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
                pr_global_struct->time = sv.time;
                pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
                pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
                pr_global_struct->time = sv.time;
-               PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
+               PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
        }
 
        }
 
-       sv.time += host_frametime;
+       if (!sv_freezenonclients.integer)
+               sv.time += sv.frametime;
 }
 
 
 }
 
 
-trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
+trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
 {
        int i;
 {
        int i;
-       edict_t tempent, *tent;
-       trace_t trace;
-       vec3_t  move;
-       vec3_t  end;
-       double  save_frametime;
+       float gravity, savesolid;
+       vec3_t move, end;
+       edict_t tempent, *tent;
+       entvars_t vars;
+       eval_t *val;
+       trace_t trace;
+
+       // copy the vars over
+       memcpy(&vars, tossent->v, sizeof(entvars_t));
+       // set up the temp entity to point to the copied vars
+       tent = &tempent;
+       tent->v = &vars;
 
 
-       save_frametime = host_frametime;
-       host_frametime = 0.05;
+       savesolid = tossent->v->solid;
+       tossent->v->solid = SOLID_NOT;
 
 
-       memcpy(&tempent, ent, sizeof(edict_t));
-       tent = &tempent;
+       // this has to fetch the field from the original edict, since our copy is truncated
+       val = GETEDICTFIELDVALUE(tossent, eval_gravity);
+       if (val != NULL && val->_float != 0)
+               gravity = val->_float;
+       else
+               gravity = 1.0;
+       gravity *= sv_gravity.value * 0.05;
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
                SV_CheckVelocity (tent);
 
        for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
        {
                SV_CheckVelocity (tent);
-               SV_AddGravity (tent);
-               VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
-               VectorScale (tent->v.velocity, host_frametime, move);
-               VectorAdd (tent->v.origin, move, end);
-               trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);   
-               VectorCopy (trace.endpos, tent->v.origin);
-
-               if (trace.ent)
-                       if (trace.ent != ignore)
-                               break;
+               tent->v->velocity[2] -= gravity;
+               VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
+               VectorScale (tent->v->velocity, 0.05, move);
+               VectorAdd (tent->v->origin, move, end);
+               trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
+               VectorCopy (trace.endpos, tent->v->origin);
+
+               if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
+                       break;
        }
        }
-       host_frametime = save_frametime;
+       tossent->v->solid = savesolid;
+       trace.fraction = 0; // not relevant
        return trace;
 }
        return trace;
 }
+