]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - sv_phys.c
fix for grenades sinking into brush model floor in start.bsp
[xonotic/darkplaces.git] / sv_phys.c
index ffe1ce9c2b667086abbede91b1852bc94c4c4ac9..76b12e25f27b8d8b176f4392bce15be6b24cd263 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,26 @@ 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"};
 
 #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);
+}
+
 /*
 ================
 SV_CheckAllEnts
 /*
 ================
 SV_CheckAllEnts
@@ -56,19 +66,19 @@ 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)
                        continue;
                if (check->v.movetype == MOVETYPE_PUSH
        {
                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)
+                || 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))
@@ -83,8 +93,8 @@ SV_CheckVelocity
 */
 void SV_CheckVelocity (edict_t *ent)
 {
 */
 void SV_CheckVelocity (edict_t *ent)
 {
-       int             i;
-       float   wishspeed;
+       int i;
+       float wishspeed;
 
 //
 // bound velocity
 
 //
 // bound velocity
@@ -101,13 +111,6 @@ void SV_CheckVelocity (edict_t *ent)
                        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_strings + 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
@@ -118,7 +121,6 @@ void SV_CheckVelocity (edict_t *ent)
                ent->v.velocity[0] *= wishspeed;
                ent->v.velocity[1] *= wishspeed;
                ent->v.velocity[2] *= wishspeed;
                ent->v.velocity[0] *= wishspeed;
                ent->v.velocity[1] *= wishspeed;
                ent->v.velocity[2] *= wishspeed;
-               wishspeed = sv_maxvelocity.value;
        }
 }
 
        }
 }
 
@@ -134,21 +136,22 @@ 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;
 
        thinktime = ent->v.nextthink;
-       if (thinktime <= 0 || thinktime > sv.time + host_frametime)
+       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.
+               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);
        ent->v.nextthink = 0;
        pr_global_struct->time = thinktime;
        pr_global_struct->self = EDICT_TO_PROG(ent);
        pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
-       PR_ExecuteProgram (ent->v.think);
+       PR_ExecuteProgram (ent->v.think, "NULL think function");
        return !ent->free;
 }
 
        return !ent->free;
 }
 
@@ -161,24 +164,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;
        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->time = sv.time;
        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_ExecuteProgram (e1->v.touch);
+               PR_ExecuteProgram (e1->v.touch, "");
        }
        }
-       
+
        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);
        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_ExecuteProgram (e2->v.touch);
+               PR_ExecuteProgram (e2->v.touch, "");
        }
 
        pr_global_struct->self = old_self;
        }
 
        pr_global_struct->self = old_self;
@@ -194,30 +197,30 @@ 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
-
+#define STOP_EPSILON 0.1
 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
 {
 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
 {
-       float   backoff;
-       float   change;
-       int             i, blocked;
-       
+       int i, blocked;
+       float backoff, change;
+
        blocked = 0;
        blocked = 0;
+       // flag if it's a floor
        if (normal[2] > 0)
        if (normal[2] > 0)
-               blocked |= 1;           // floor
+               blocked |= 1;
+       // flag if it's a step
        if (!normal[2])
        if (!normal[2])
-               blocked |= 2;           // step
-       
+               blocked |= 2;
+
        backoff = DotProduct (in, normal) * overbounce;
 
        backoff = DotProduct (in, normal) * overbounce;
 
-       for (i=0 ; i<3 ; i++)
+       for (i = 0;i < 3;i++)
        {
        {
-               change = normal[i]*backoff;
+               change = normal[i] * backoff;
                out[i] = in[i] - change;
                if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
                        out[i] = 0;
        }
                out[i] = in[i] - change;
                if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
                        out[i] = 0;
        }
-       
+
        return blocked;
 }
 
        return blocked;
 }
 
@@ -234,28 +237,22 @@ Returns the clipflags if the velocity was modified (hit something solid)
 If steptrace is not NULL, the trace of any vertical wall hit will be stored
 ============
 */
 If steptrace is not NULL, the trace of any vertical wall hit will be stored
 ============
 */
-#define        MAX_CLIP_PLANES 5
+// LordHavoc: increased from 5 to 20
+#define MAX_CLIP_PLANES 20
 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
 {
 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
 {
-       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;
-       
+       int i, j, blocked, impact, numplanes, bumpcount, numbumps;
+       float d, time_left;
+       vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
+       trace_t trace;
+
        numbumps = 4;
        numbumps = 4;
-       
+
        blocked = 0;
        VectorCopy (ent->v.velocity, original_velocity);
        VectorCopy (ent->v.velocity, primal_velocity);
        numplanes = 0;
        blocked = 0;
        VectorCopy (ent->v.velocity, original_velocity);
        VectorCopy (ent->v.velocity, primal_velocity);
        numplanes = 0;
-       
+
        time_left = time;
 
        for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
        time_left = time;
 
        for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
@@ -266,103 +263,124 @@ int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
                for (i=0 ; i<3 ; i++)
                        end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
 
                for (i=0 ; i<3 ; i++)
                        end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
 
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
+               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
 
                if (trace.allsolid)
 
                if (trace.allsolid)
-               {       // entity is trapped in another solid
-                       VectorCopy (vec3_origin, ent->v.velocity);
+               {
+                       // 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;
                }
 
                if (trace.fraction > 0)
                        return 3;
                }
 
                if (trace.fraction > 0)
-               {       // actually covered some distance
+               {
+                       // actually covered some distance
                        VectorCopy (trace.endpos, ent->v.origin);
                        VectorCopy (ent->v.velocity, original_velocity);
                        numplanes = 0;
                }
 
                        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
+                        break;
 
                if (!trace.ent)
                        Host_Error ("SV_FlyMove: !trace.ent");
 
 
                if (!trace.ent)
                        Host_Error ("SV_FlyMove: !trace.ent");
 
-               if (trace.plane.normal[2] > 0.7)
+               if ((int) ent->v.flags & FL_ONGROUND)
                {
                {
-                       blocked |= 1;           // floor
-                       if (trace.ent->v.solid == SOLID_BSP)
+                       if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
+                               impact = false;
+                       else
                        {
                        {
-                               ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
-                               ent->v.groundentity = EDICT_TO_PROG(trace.ent);
+                               ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
+                               impact = true;
                        }
                }
                        }
                }
+               else
+                       impact = true;
+
+               if (trace.plane.normal[2] > 0.7)
+               {
+                       // floor
+                       blocked |= 1;
+                       ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
+                       ent->v.groundentity = EDICT_TO_PROG(trace.ent);
+               }
                if (!trace.plane.normal[2])
                {
                if (!trace.plane.normal[2])
                {
-                       blocked |= 2;           // step
+                       // step
+                       blocked |= 2;
+                       // save the trace for player extrafriction
                        if (steptrace)
                        if (steptrace)
-                               *steptrace = trace;     // save for player extrafriction
+                               *steptrace = trace;
+               }
+
+               // run the impact function
+               if (impact)
+               {
+                       SV_Impact (ent, trace.ent);
+
+                       // break if removed by the impact function
+                       if (ent->free)
+                               break;
                }
 
                }
 
-//
-// run the impact function
-//
-               SV_Impact (ent, trace.ent);
-               if (ent->free)
-                       break;          // removed by the impact function
 
 
-               
                time_left -= time_left * 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);
+               {
+                       // this shouldn't really happen
+                       VectorClear(ent->v.velocity);
                        return 3;
                }
 
                VectorCopy (trace.plane.normal, planes[numplanes]);
                numplanes++;
 
                        return 3;
                }
 
                VectorCopy (trace.plane.normal, planes[numplanes]);
                numplanes++;
 
-//
-// modify original_velocity so it parallels all of the clip planes
-//
+               // 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 (j != i)
                                {
                for (i=0 ; i<numplanes ; i++)
                {
                        ClipVelocity (original_velocity, planes[i], new_velocity, 1);
                        for (j=0 ; j<numplanes ; j++)
                                if (j != i)
                                {
+                                       // not ok
                                        if (DotProduct (new_velocity, planes[j]) < 0)
                                        if (DotProduct (new_velocity, planes[j]) < 0)
-                                               break;  // not ok
+                                               break;
                                }
                        if (j == numplanes)
                                break;
                }
                                }
                        if (j == numplanes)
                                break;
                }
-               
+
                if (i != numplanes)
                if (i != numplanes)
-               {       // go along this plane
+               {
+                       // go along this plane
                        VectorCopy (new_velocity, ent->v.velocity);
                }
                else
                        VectorCopy (new_velocity, ent->v.velocity);
                }
                else
-               {       // go along the crease
+               {
+                       // go along the crease
                        if (numplanes != 2)
                        {
                        if (numplanes != 2)
                        {
-//                             Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
-                               VectorCopy (vec3_origin, ent->v.velocity);
+                               VectorClear(ent->v.velocity);
                                return 7;
                        }
                        CrossProduct (planes[0], planes[1], dir);
                                return 7;
                        }
                        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);
                }
 
                        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 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 (DotProduct (ent->v.velocity, primal_velocity) <= 0)
                {
-                       VectorCopy (vec3_origin, ent->v.velocity);
+                       VectorClear(ent->v.velocity);
                        return blocked;
                }
        }
                        return blocked;
                }
        }
@@ -379,16 +397,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;
 }
 
 
 }
 
 
@@ -407,29 +424,30 @@ SV_PushEntity
 Does not change the entities velocity at all
 ============
 */
 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, vec3_t pushangles)
 {
 {
-       trace_t trace;
-       vec3_t  end;
-               
+       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)
        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
+               // only clip against bmodels
                trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
        else
                trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
        else
-               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);       
-       
+               trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
+
        VectorCopy (trace.endpos, ent->v.origin);
        VectorCopy (trace.endpos, ent->v.origin);
+       // FIXME: turn players specially
+       ent->v.angles[1] += trace.fraction * pushangles[1];
        SV_LinkEdict (ent, true);
 
        SV_LinkEdict (ent, true);
 
-       if (trace.ent)
-               SV_Impact (ent, trace.ent);             
-
+       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,16 +456,18 @@ 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;
+       int                     i, e, index;
        edict_t         *check;
        edict_t         *check;
-       vec3_t          mins, maxs, move;
-       vec3_t          entorig, pushorig;
+       float           savesolid, movetime2, pushltime;
+       vec3_t          mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
        int                     num_moved;
        edict_t         *moved_edict[MAX_EDICTS];
        int                     num_moved;
        edict_t         *moved_edict[MAX_EDICTS];
-       vec3_t          moved_from[MAX_EDICTS];
-       float           savesolid;
+       vec3_t          moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
+       model_t         *pushermodel;
+       trace_t         trace;
 
        switch ((int) pusher->v.solid)
        {
 
        switch ((int) pusher->v.solid)
        {
@@ -461,33 +481,90 @@ void SV_PushMove (edict_t *pusher, float movetime)
        case SOLID_NOT:
        case SOLID_TRIGGER:
                VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
        case SOLID_NOT:
        case SOLID_TRIGGER:
                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);
                return;
        default:
                Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
        }
                pusher->v.ltime += movetime;
                SV_LinkEdict (pusher, false);
                return;
        default:
                Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
        }
-       if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
+       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;
        }
        {
                pusher->v.ltime += movetime;
                return;
        }
-
-       for (i=0 ; i<3 ; i++)
+       index = (int) pusher->v.modelindex;
+       if (index < 1 || index >= MAX_MODELS)
+               Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
+       pushermodel = sv.models[index];
+
+       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;
+                       }
+               }
+       }
+
+       VectorNegate (moveangle, a);
+       AngleVectorsFLU (a, forward, left, up);
 
        VectorCopy (pusher->v.origin, pushorig);
 
        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);
+       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);
 
        pusher->v.ltime += movetime;
        SV_LinkEdict (pusher, false);
 
+       savesolid = pusher->v.solid;
 
 // see if any solid entities are inside the final position
        num_moved = 0;
 
 // see if any solid entities are inside the final position
        num_moved = 0;
@@ -506,211 +583,76 @@ void SV_PushMove (edict_t *pusher, float movetime)
                if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
                {
                        if (check->v.absmin[0] >= maxs[0]
                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[0] <= mins[0]
+                        || check->v.absmin[1] >= maxs[1]
                         || check->v.absmax[1] <= mins[1]
                         || check->v.absmax[1] <= mins[1]
+                        || check->v.absmin[2] >= maxs[2]
                         || check->v.absmax[2] <= mins[2])
                                continue;
 
                         || check->v.absmax[2] <= mins[2])
                                continue;
 
-                       // see if the ent's bbox is inside the pusher's final position
-                       if (!SV_TestEntityPosition (check))
+                       trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
+                       if (!trace.startsolid)
                                continue;
                }
 
                                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, 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 (forward[0] < 0.999f) // quick way to check if any rotation is used
                {
                {
-                       // try moving the contacted entity
-                       pusher->v.solid = SOLID_NOT;
-                       SV_PushEntity (check, move);
-                       pusher->v.solid = savesolid; // was SOLID_BSP
-
-                       // 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 (entorig, check->v.origin);
-                               SV_LinkEdict (check, true);
-
-                               VectorCopy (pushorig, pusher->v.origin);
-                               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);
-                                       SV_LinkEdict (moved_edict[i], false);
-                               }
-                               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;
-
-       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;
+                       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;
                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.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
+               VectorCopy (check->v.angles, moved_fromangles[num_moved]);
+               moved_edict[num_moved++] = check;
 
 
-               VectorAdd (check->v.angles, amove, check->v.angles);
+               // try moving the contacted entity
+               pusher->v.solid = SOLID_NOT;
+               trace = SV_PushEntity (check, move, moveangle);
+               pusher->v.solid = savesolid; // was SOLID_BSP
 
 
-       // if it is still inside the pusher, block
+               // if it is still inside the pusher, block
                if (SV_TestEntityPosition (check))
                if (SV_TestEntityPosition (check))
-               {       // fail the move
+               {
+                       // fail the move
                        if (check->v.mins[0] == check->v.maxs[0])
                                continue;
                        if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
                        if (check->v.mins[0] == check->v.maxs[0])
                                continue;
                        if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
-                       {       // corpse
+                       {
+                               // corpse
                                check->v.mins[0] = check->v.mins[1] = 0;
                                VectorCopy (check->v.mins, check->v.maxs);
                                continue;
                        }
                                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);
+                       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++)
+                       {
+                               VectorCopy (moved_from[i], moved_edict[i]->v.origin);
+                               VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
+                               SV_LinkEdict (moved_edict[i], false);
+                       }
 
                        // 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);
 
                        // 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);
+                               PR_ExecuteProgram (pusher->v.blocked, "");
                        }
                        return;
                }
                        }
                        return;
                }
@@ -725,55 +667,31 @@ 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;
 
        oldltime = ent->v.ltime;
-       
-       /*
+
        thinktime = ent->v.nextthink;
        thinktime = ent->v.nextthink;
-       if (thinktime < ent->v.ltime + host_frametime)
+       if (thinktime < ent->v.ltime + sv.frametime)
        {
                movetime = thinktime - ent->v.ltime;
                if (movetime < 0)
                        movetime = 0;
        }
        else
        {
                movetime = thinktime - ent->v.ltime;
                if (movetime < 0)
                        movetime = 0;
        }
        else
-               movetime = host_frametime;
+               movetime = sv.frametime;
 
        if (movetime)
 
        if (movetime)
-       {
-               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 (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
-               SV_PushRotate (ent, host_frametime);
-       else
-       {
-               thinktime = ent->v.nextthink;
-               if (thinktime < ent->v.ltime + host_frametime)
-               {
-                       movetime = thinktime - ent->v.ltime;
-                       if (movetime < 0)
-                               movetime = 0;
-               }
-               else
-                       movetime = host_frametime;
-               if (movetime)
-                       SV_PushMove (ent, movetime);    // advances ent->v.ltime if not blocked
-       }
-               
+               // advances ent->v.ltime if not blocked
+               SV_PushMove (ent, movetime);
+
        if (thinktime > oldltime && thinktime <= ent->v.ltime)
        {
                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);
        if (thinktime > oldltime && thinktime <= ent->v.ltime)
        {
                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_ExecuteProgram (ent->v.think);
+               PR_ExecuteProgram (ent->v.think, "NULL think function");
                if (ent->free)
                        return;
        }
                if (ent->free)
                        return;
        }
@@ -799,9 +717,8 @@ 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))
        {
@@ -817,7 +734,7 @@ void SV_CheckStuck (edict_t *ent)
                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++)
@@ -832,7 +749,7 @@ void SV_CheckStuck (edict_t *ent)
                                        return;
                                }
                        }
                                        return;
                                }
                        }
-                       
+
        VectorCopy (org, ent->v.origin);
        Con_DPrintf ("player is stuck.\n");
 }
        VectorCopy (org, ent->v.origin);
        Con_DPrintf ("player is stuck.\n");
 }
@@ -845,32 +762,32 @@ 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[0] = ent->v.origin[0];
        point[1] = ent->v.origin[1];
-       point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;       
-       
+       point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
+
        ent->v.waterlevel = 0;
        ent->v.watertype = CONTENTS_EMPTY;
        ent->v.waterlevel = 0;
        ent->v.watertype = CONTENTS_EMPTY;
-       cont = SV_PointContents (point);
+       cont = Mod_PointInLeaf(point, sv.worldmodel)->contents;
        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;
        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);
+               cont = Mod_PointInLeaf(point, sv.worldmodel)->contents;
                if (cont <= CONTENTS_WATER)
                {
                        ent->v.waterlevel = 2;
                        point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
                if (cont <= CONTENTS_WATER)
                {
                        ent->v.waterlevel = 2;
                        point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
-                       cont = SV_PointContents (point);
+                       cont = Mod_PointInLeaf(point, sv.worldmodel)->contents;
                        if (cont <= CONTENTS_WATER)
                                ent->v.waterlevel = 3;
                }
        }
                        if (cont <= CONTENTS_WATER)
                                ent->v.waterlevel = 3;
                }
        }
-       
+
        return ent->v.waterlevel > 1;
 }
 
        return ent->v.waterlevel > 1;
 }
 
@@ -882,22 +799,21 @@ SV_WallFriction
 */
 void SV_WallFriction (edict_t *ent, trace_t *trace)
 {
 */
 void SV_WallFriction (edict_t *ent, trace_t *trace)
 {
-       vec3_t          forward, right, up;
-       float           d, i;
-       vec3_t          into, side;
-       
-       AngleVectors (ent->v.v_angle, forward, right, up);
+       float d, i;
+       vec3_t forward, into, side;
+
+       AngleVectors (ent->v.v_angle, forward, NULL, NULL);
        d = DotProduct (trace->plane.normal, forward);
        d = DotProduct (trace->plane.normal, forward);
-       
+
        d += 0.5;
        if (d >= 0)
                return;
        d += 0.5;
        if (d >= 0)
                return;
-               
-// cut the tangential velocity
+
+       // cut the tangential velocity
        i = DotProduct (trace->plane.normal, ent->v.velocity);
        VectorScale (trace->plane.normal, i, into);
        VectorSubtract (ent->v.velocity, into, side);
        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);
 }
        ent->v.velocity[0] = side[0] * (1 + d);
        ent->v.velocity[1] = side[1] * (1 + d);
 }
@@ -916,51 +832,47 @@ 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;
-       
+       int i, clip;
+       vec3_t oldorg, dir;
+       trace_t steptrace;
+
        VectorCopy (ent->v.origin, oldorg);
        VectorCopy (ent->v.origin, oldorg);
-       VectorCopy (vec3_origin, dir);
+       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);
 
 
-// retry the original move
+               SV_PushEntity (ent, dir, vec3_origin);
+
+               // retry the original move
                ent->v.velocity[0] = oldvel[0];
                ent->v.velocity[0] = oldvel[0];
-               ent->v. velocity[1] = oldvel[1];
-               ent->v. velocity[2] = 0;
+               ent->v.velocity[1] = oldvel[1];
+               ent->v.velocity[2] = 0;
                clip = SV_FlyMove (ent, 0.1, &steptrace);
 
                clip = SV_FlyMove (ent, 0.1, &steptrace);
 
-               if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
-               || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
-               {
-//Con_DPrintf ("unstuck!\n");
+               if (fabs(oldorg[1] - ent->v.origin[1]) > 4
+                || fabs(oldorg[0] - ent->v.origin[0]) > 4)
                        return clip;
                        return clip;
-               }
-                       
-// go back to the original pos and try again
+
+               // go back to the original pos and try again
                VectorCopy (oldorg, ent->v.origin);
        }
                VectorCopy (oldorg, ent->v.origin);
        }
-       
-       VectorCopy (vec3_origin, ent->v.velocity);
-       return 7;               // still not moving
+
+       // still not moving
+       VectorClear (ent->v.velocity);
+       return 7;
 }
 
 /*
 }
 
 /*
@@ -970,81 +882,82 @@ 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
-//
+       int clip, oldonground;
+       vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel;
+       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;
        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);
        VectorCopy (ent->v.origin, oldorg);
        VectorCopy (ent->v.velocity, oldvel);
-       
-       clip = SV_FlyMove (ent, host_frametime, &steptrace);
 
 
+       clip = SV_FlyMove (ent, sv.frametime, &steptrace);
+
+       // if move didn't block on a step, return
        if ( !(clip & 2) )
        if ( !(clip & 2) )
-               return;         // move didn't block on a step
-
-       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;
                return;
-       
+
+       if (ent->v.movetype != MOVETYPE_FLY)
+       {
+               if (!oldonground && ent->v.waterlevel == 0 && !sv_jumpstep.integer)
+                       // don't stair up while jumping
+                       return;
+
+               if (ent->v.movetype != MOVETYPE_WALK)
+                       // gibbed by a trigger
+                       return;
+       }
+
+       if (sv_nostep.integer)
+               return;
+
        if ( (int)sv_player->v.flags & FL_WATERJUMP )
                return;
 
        VectorCopy (ent->v.origin, nosteporg);
        VectorCopy (ent->v.velocity, nostepvel);
 
        if ( (int)sv_player->v.flags & FL_WATERJUMP )
                return;
 
        VectorCopy (ent->v.origin, nosteporg);
        VectorCopy (ent->v.velocity, nostepvel);
 
-//
-// try moving up and forward to go up a step
-//
-       VectorCopy (oldorg, ent->v.origin);     // back to start pos
+       // try moving up and forward to go up a step
+       // back to start pos
+       VectorCopy (oldorg, ent->v.origin);
 
 
-       VectorCopy (vec3_origin, upmove);
-       VectorCopy (vec3_origin, downmove);
-       upmove[2] = STEPSIZE;
-       downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
+       VectorClear (upmove);
+       VectorClear (downmove);
+       upmove[2] = sv_stepheight.value;
+       downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
 
 
-// move up
-       SV_PushEntity (ent, upmove);    // FIXME: don't link?
+       // move up
+       // FIXME: don't link?
+       SV_PushEntity (ent, upmove, vec3_origin);
 
 
-// move forward
+       // move forward
        ent->v.velocity[0] = oldvel[0];
        ent->v.velocity[0] = oldvel[0];
-       ent->v. velocity[1] = oldvel[1];
-       ent->v. velocity[2] = 0;
-       clip = SV_FlyMove (ent, host_frametime, &steptrace);
+       ent->v.velocity[1] = oldvel[1];
+       ent->v.velocity[2] = 0;
+       clip = SV_FlyMove (ent, sv.frametime, &steptrace);
+       ent->v.velocity[2] += oldvel[2];
 
 
-// check for stuckness, possibly due to the limited precision of floats
-// in the clipping hulls
-       if (clip)
-       {
-               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);
-               }
-       }
-       
-// extra friction based on view angle
-       if ( clip & 2 )
+       // check for stuckness, possibly due to the limited precision of floats
+       // in the clipping hulls
+       /*
+       if (clip
+        && 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);
+       */
+
+       // extra friction based on view angle
+       if (clip & 2 && sv_wallfriction.integer)
                SV_WallFriction (ent, &steptrace);
 
                SV_WallFriction (ent, &steptrace);
 
-// move down
-       downtrace = SV_PushEntity (ent, downmove);      // FIXME: don't link?
+       // move down
+       // FIXME: don't link?
+       downtrace = SV_PushEntity (ent, downmove, vec3_origin);
 
        if (downtrace.plane.normal[2] > 0.7)
        {
 
        if (downtrace.plane.normal[2] > 0.7)
        {
@@ -1056,9 +969,9 @@ void SV_WalkMove (edict_t *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     
+               // 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);
        }
                VectorCopy (nosteporg, ent->v.origin);
                VectorCopy (nostepvel, ent->v.velocity);
        }
@@ -1079,11 +992,11 @@ void SV_Physics_Client (edict_t  *ent, int num)
 
 //
 // call standard client pre-think
 
 //
 // call standard client pre-think
-//     
+//
        pr_global_struct->time = sv.time;
        pr_global_struct->self = EDICT_TO_PROG(ent);
        pr_global_struct->time = sv.time;
        pr_global_struct->self = EDICT_TO_PROG(ent);
-       PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
-       
+       PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
+
 //
 // do a move
 //
 //
 // do a move
 //
@@ -1107,7 +1020,7 @@ void SV_Physics_Client (edict_t   *ent, int num)
                SV_CheckStuck (ent);
                SV_WalkMove (ent);
                break;
                SV_CheckStuck (ent);
                SV_WalkMove (ent);
                break;
-               
+
        case MOVETYPE_TOSS:
        case MOVETYPE_BOUNCE:
                SV_Physics_Toss (ent);
        case MOVETYPE_TOSS:
        case MOVETYPE_BOUNCE:
                SV_Physics_Toss (ent);
@@ -1116,44 +1029,35 @@ void SV_Physics_Client (edict_t *ent, int num)
        case MOVETYPE_FLY:
                if (!SV_RunThink (ent))
                        return;
        case MOVETYPE_FLY:
                if (!SV_RunThink (ent))
                        return;
-               SV_FlyMove (ent, host_frametime, NULL);
+               SV_CheckWater (ent);
+               //SV_FlyMove (ent, sv.frametime, NULL);
+               SV_WalkMove (ent);
                break;
                break;
-               
+
        case MOVETYPE_NOCLIP:
                if (!SV_RunThink (ent))
                        return;
        case MOVETYPE_NOCLIP:
                if (!SV_RunThink (ent))
                        return;
-               VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
+               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);
                break;
                break;
-               
+
        default:
                Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
        }
 
 //
 // call standard player post-think
        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);
        SV_LinkEdict (ent, true);
 
        pr_global_struct->time = sv.time;
        pr_global_struct->self = EDICT_TO_PROG(ent);
-       PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
+       PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
 }
 
 //============================================================================
 
 }
 
 //============================================================================
 
-/*
-=============
-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,21 +1067,38 @@ Entities that are "stuck" to another entity
 */
 void SV_Physics_Follow (edict_t *ent)
 {
 */
 void SV_Physics_Follow (edict_t *ent)
 {
-       vec3_t vf, vu, vr, angles;
+       vec3_t vf, vr, vu, angles, v;
        edict_t *e;
        edict_t *e;
-// regular thinking
-       SV_RunThink (ent);
+
+       // regular thinking
+       if (!SV_RunThink (ent))
+               return;
+
        // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
        e = PROG_TO_EDICT(ent->v.aiment);
        // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
        e = PROG_TO_EDICT(ent->v.aiment);
-       angles[0] = -e->v.angles[0];
-       angles[1] = e->v.angles[1];
-       angles[2] = e->v.angles[2];
-       AngleVectors (angles, vf, vr, vu);
-       VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin);
-       VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin);
-       VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin);
+       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
+               VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
+       }
+       else
+       {
+               angles[0] = -ent->v.punchangle[0];
+               angles[1] =  ent->v.punchangle[1];
+               angles[2] =  ent->v.punchangle[2];
+               AngleVectors (angles, vf, vr, vu);
+               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 (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);
        SV_LinkEdict (ent, true);
 }
 
        SV_LinkEdict (ent, true);
 }
 
@@ -1190,12 +1111,12 @@ A moving object that doesn't obey physics
 */
 void SV_Physics_Noclip (edict_t *ent)
 {
 */
 void SV_Physics_Noclip (edict_t *ent)
 {
-// regular thinking
+       // regular thinking
        if (!SV_RunThink (ent))
                return;
        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);
+
+       VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
+       VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
 
        SV_LinkEdict (ent, false);
 }
 
        SV_LinkEdict (ent, false);
 }
@@ -1217,29 +1138,30 @@ SV_CheckWaterTransition
 void SV_CheckWaterTransition (edict_t *ent)
 {
        int             cont;
 void SV_CheckWaterTransition (edict_t *ent)
 {
        int             cont;
-       cont = SV_PointContents (ent->v.origin);
+       cont = Mod_PointInLeaf(ent->v.origin, sv.worldmodel)->contents;
        if (!ent->v.watertype)
        if (!ent->v.watertype)
-       {       // just spawned here
+       {
+               // just spawned here
                ent->v.watertype = cont;
                ent->v.waterlevel = 1;
                return;
        }
                ent->v.watertype = cont;
                ent->v.waterlevel = 1;
                return;
        }
-       
+
        if (cont <= CONTENTS_WATER)
        {
                if (ent->v.watertype == CONTENTS_EMPTY)
        if (cont <= CONTENTS_WATER)
        {
                if (ent->v.watertype == CONTENTS_EMPTY)
-               {       // just crossed into water
+                       // just crossed into water
                        SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
                        SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
-               }               
+
                ent->v.watertype = cont;
                ent->v.waterlevel = 1;
        }
        else
        {
                if (ent->v.watertype != CONTENTS_EMPTY)
                ent->v.watertype = cont;
                ent->v.waterlevel = 1;
        }
        else
        {
                if (ent->v.watertype != CONTENTS_EMPTY)
-               {       // just crossed into water
+                       // just crossed into water
                        SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
                        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 = cont;
        }
@@ -1254,57 +1176,89 @@ 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;
 
 // if onground, return without moving
        // regular thinking
        if (!SV_RunThink (ent))
                return;
 
 // if onground, return without moving
-       if ( ((int)ent->v.flags & FL_ONGROUND) )
-               return;
+       if ((int)ent->v.flags & FL_ONGROUND)
+       {
+               VectorClear(ent->v.velocity);
+               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->suspendedinairflag = true;
+                       return;
+               }
+               else if (ent->suspendedinairflag && groundentity->free)
+               {
+                       // leave it suspended in the air
+                       ent->v.groundentity = 0;
+                       ent->suspendedinairflag = false;
+                       return;
+               }
+       }
+       ent->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);
-       trace = SV_PushEntity (ent, move);
-       if (trace.fraction == 1)
-               return;
+       VectorScale (ent->v.velocity, sv.frametime, move);
+       trace = SV_PushEntity (ent, move, vec3_origin);
        if (ent->free)
                return;
        if (ent->free)
                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)
+               {
+                       ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
+                       // LordHavoc: fixed grenades not bouncing when fired down a slope
+                       if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 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);
 }
@@ -1330,23 +1284,41 @@ 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;
+       int flags, fall, hitsound;
 
 
-// freefall if not onground
-       if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
+       // freefall if not fly/swim
+       fall = true;
+       flags = (int)ent->v.flags;
+       if (flags & (FL_FLY | FL_SWIM))
+       {
+               if (flags & FL_FLY)
+                       fall = false;
+               else if ((flags & FL_SWIM) && Mod_PointInLeaf(ent->v.origin, sv.worldmodel)->contents != CONTENTS_EMPTY)
+                       fall = false;
+       }
+       if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
+               fall = false;
+
+       if (fall)
        {
                if (ent->v.velocity[2] < sv_gravity.value*-0.1)
        {
                if (ent->v.velocity[2] < sv_gravity.value*-0.1)
+               {
                        hitsound = true;
                        hitsound = true;
+                       if (flags & FL_ONGROUND)
+                               hitsound = false;
+               }
                else
                        hitsound = false;
 
                SV_AddGravity (ent);
                SV_CheckVelocity (ent);
                else
                        hitsound = false;
 
                SV_AddGravity (ent);
                SV_CheckVelocity (ent);
-               SV_FlyMove (ent, host_frametime, NULL);
-               SV_LinkEdict (ent, true);
+               SV_FlyMove (ent, sv.frametime, NULL);
+               SV_LinkEdict (ent, false);
 
 
-               if ( (int)ent->v.flags & FL_ONGROUND )  // just hit ground
+               // just hit ground
+               if ((int)ent->v.flags & FL_ONGROUND)
                {
                {
+                       VectorClear(ent->v.velocity);
                        if (hitsound)
                                SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
                }
                        if (hitsound)
                                SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
                }
@@ -1354,7 +1326,7 @@ void SV_Physics_Step (edict_t *ent)
 
 // regular thinking
        SV_RunThink (ent);
 
 // regular thinking
        SV_RunThink (ent);
-       
+
        SV_CheckWaterTransition (ent);
 }
 
        SV_CheckWaterTransition (ent);
 }
 
@@ -1366,19 +1338,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
@@ -1404,7 +1373,9 @@ void SV_Physics (void)
                        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_FOLLOW:
                        SV_Physics_Follow (ent);
@@ -1423,6 +1394,7 @@ void SV_Physics (void)
                                        SV_AddGravity (ent);
                                SV_CheckStuck (ent);
                                SV_WalkMove (ent);
                                        SV_AddGravity (ent);
                                SV_CheckStuck (ent);
                                SV_WalkMove (ent);
+                               SV_LinkEdict (ent, true);
                        }
                        break;
                case MOVETYPE_TOSS:
                        }
                        break;
                case MOVETYPE_TOSS:
@@ -1437,9 +1409,9 @@ void SV_Physics (void)
                        break;
                }
        }
                        break;
                }
        }
-       
+
        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)
@@ -1447,42 +1419,51 @@ 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), "");
        }
 
        }
 
-       sv.time += host_frametime;
+       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;
+       eval_t *val;
+       trace_t trace;
 
 
-       save_frametime = host_frametime;
-       host_frametime = 0.05;
-
-       memcpy(&tempent, ent, sizeof(edict_t));
+       memcpy(&tempent, tossent, sizeof(edict_t));
        tent = &tempent;
        tent = &tempent;
+       savesolid = tossent->v.solid;
+       tossent->v.solid = SOLID_NOT;
+
+       // 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);
+               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);
                VectorAdd (tent->v.origin, move, end);
-               trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);   
+               trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
                VectorCopy (trace.endpos, tent->v.origin);
 
                VectorCopy (trace.endpos, tent->v.origin);
 
-               if (trace.ent)
+               if (trace.fraction < 1 && trace.ent)
                        if (trace.ent != ignore)
                                break;
        }
                        if (trace.ent != ignore)
                                break;
        }
-       host_frametime = save_frametime;
+       tossent->v.solid = savesolid;
+       trace.fraction = 0; // not relevant
        return trace;
 }
        return trace;
 }
+