]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_phys.c
make screenshots rightside up again (or rather, upside down like TGA wants, which...
[xonotic/darkplaces.git] / sv_phys.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_phys.c
21
22 #include "quakedef.h"
23
24 /*
25
26
27 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.
28
29 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects 
30
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38 solid_edge items only clip against bsp models.
39
40 */
41
42 cvar_t  sv_friction = {"sv_friction","4",false,true};
43 cvar_t  sv_stopspeed = {"sv_stopspeed","100"};
44 cvar_t  sv_gravity = {"sv_gravity","800",false,true};
45 cvar_t  sv_maxvelocity = {"sv_maxvelocity","2000"};
46 cvar_t  sv_nostep = {"sv_nostep","0"};
47
48 #define MOVE_EPSILON    0.01
49
50 void SV_Physics_Toss (edict_t *ent);
51
52 /*
53 ================
54 SV_CheckAllEnts
55 ================
56 */
57 void SV_CheckAllEnts (void)
58 {
59         int                     e;
60         edict_t         *check;
61
62 // see if any solid entities are inside the final position
63         check = NEXT_EDICT(sv.edicts);
64         for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
65         {
66                 if (check->free)
67                         continue;
68                 if (check->v.movetype == MOVETYPE_PUSH
69                 || check->v.movetype == MOVETYPE_NONE
70                 || check->v.movetype == MOVETYPE_FOLLOW
71                 || check->v.movetype == MOVETYPE_NOCLIP)
72                         continue;
73
74                 if (SV_TestEntityPosition (check))
75                         Con_Printf ("entity in invalid position\n");
76         }
77 }
78
79 /*
80 ================
81 SV_CheckVelocity
82 ================
83 */
84 void SV_CheckVelocity (edict_t *ent)
85 {
86         int             i;
87         float   wishspeed;
88
89 //
90 // bound velocity
91 //
92         for (i=0 ; i<3 ; i++)
93         {
94                 if (IS_NAN(ent->v.velocity[i]))
95                 {
96                         Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
97                         ent->v.velocity[i] = 0;
98                 }
99                 if (IS_NAN(ent->v.origin[i]))
100                 {
101                         Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
102                         ent->v.origin[i] = 0;
103                 }
104                 // LordHavoc: maxvelocity fix, see below
105 /*
106                 if (ent->v.velocity[i] > sv_maxvelocity.value)
107                         ent->v.velocity[i] = sv_maxvelocity.value;
108                 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
109                         ent->v.velocity[i] = -sv_maxvelocity.value;
110 */
111         }
112
113         // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
114         wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
115         if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
116         {
117                 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
118                 ent->v.velocity[0] *= wishspeed;
119                 ent->v.velocity[1] *= wishspeed;
120                 ent->v.velocity[2] *= wishspeed;
121                 wishspeed = sv_maxvelocity.value;
122         }
123 }
124
125 /*
126 =============
127 SV_RunThink
128
129 Runs thinking code if time.  There is some play in the exact time the think
130 function will be called, because it is called before any movement is done
131 in a frame.  Not used for pushmove objects, because they must be exact.
132 Returns false if the entity removed itself.
133 =============
134 */
135 qboolean SV_RunThink (edict_t *ent)
136 {
137         float   thinktime;
138
139         thinktime = ent->v.nextthink;
140         if (thinktime <= 0 || thinktime > sv.time + host_frametime)
141                 return true;
142                 
143         if (thinktime < sv.time)
144                 thinktime = sv.time;    // don't let things stay in the past.
145                                                                 // it is possible to start that way
146                                                                 // by a trigger with a local time.
147         ent->v.nextthink = 0;
148         pr_global_struct->time = thinktime;
149         pr_global_struct->self = EDICT_TO_PROG(ent);
150         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
151         PR_ExecuteProgram (ent->v.think);
152         return !ent->free;
153 }
154
155 /*
156 ==================
157 SV_Impact
158
159 Two entities have touched, so run their touch functions
160 ==================
161 */
162 void SV_Impact (edict_t *e1, edict_t *e2)
163 {
164         int             old_self, old_other;
165         
166         old_self = pr_global_struct->self;
167         old_other = pr_global_struct->other;
168         
169         pr_global_struct->time = sv.time;
170         if (e1->v.touch && e1->v.solid != SOLID_NOT)
171         {
172                 pr_global_struct->self = EDICT_TO_PROG(e1);
173                 pr_global_struct->other = EDICT_TO_PROG(e2);
174                 PR_ExecuteProgram (e1->v.touch);
175         }
176         
177         if (e2->v.touch && e2->v.solid != SOLID_NOT)
178         {
179                 pr_global_struct->self = EDICT_TO_PROG(e2);
180                 pr_global_struct->other = EDICT_TO_PROG(e1);
181                 PR_ExecuteProgram (e2->v.touch);
182         }
183
184         pr_global_struct->self = old_self;
185         pr_global_struct->other = old_other;
186 }
187
188
189 /*
190 ==================
191 ClipVelocity
192
193 Slide off of the impacting object
194 returns the blocked flags (1 = floor, 2 = step / wall)
195 ==================
196 */
197 #define STOP_EPSILON    0.1
198
199 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
200 {
201         float   backoff;
202         float   change;
203         int             i, blocked;
204         
205         blocked = 0;
206         if (normal[2] > 0)
207                 blocked |= 1;           // floor
208         if (!normal[2])
209                 blocked |= 2;           // step
210         
211         backoff = DotProduct (in, normal) * overbounce;
212
213         for (i=0 ; i<3 ; i++)
214         {
215                 change = normal[i]*backoff;
216                 out[i] = in[i] - change;
217                 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
218                         out[i] = 0;
219         }
220         
221         return blocked;
222 }
223
224
225 /*
226 ============
227 SV_FlyMove
228
229 The basic solid body movement clip that slides along multiple planes
230 Returns the clipflags if the velocity was modified (hit something solid)
231 1 = floor
232 2 = wall / step
233 4 = dead stop
234 If steptrace is not NULL, the trace of any vertical wall hit will be stored
235 ============
236 */
237 #define MAX_CLIP_PLANES 5
238 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
239 {
240         int                     bumpcount, numbumps;
241         vec3_t          dir;
242         float           d;
243         int                     numplanes;
244         vec3_t          planes[MAX_CLIP_PLANES];
245         vec3_t          primal_velocity, original_velocity, new_velocity;
246         int                     i, j;
247         trace_t         trace;
248         vec3_t          end;
249         float           time_left;
250         int                     blocked;
251         
252         numbumps = 4;
253         
254         blocked = 0;
255         VectorCopy (ent->v.velocity, original_velocity);
256         VectorCopy (ent->v.velocity, primal_velocity);
257         numplanes = 0;
258         
259         time_left = time;
260
261         for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
262         {
263                 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
264                         break;
265
266                 for (i=0 ; i<3 ; i++)
267                         end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
268
269                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
270
271                 if (trace.allsolid)
272                 {       // entity is trapped in another solid
273                         VectorCopy (vec3_origin, ent->v.velocity);
274                         return 3;
275                 }
276
277                 if (trace.fraction > 0)
278                 {       // actually covered some distance
279                         VectorCopy (trace.endpos, ent->v.origin);
280                         VectorCopy (ent->v.velocity, original_velocity);
281                         numplanes = 0;
282                 }
283
284                 if (trace.fraction == 1)
285                          break;         // moved the entire distance
286
287                 if (!trace.ent)
288                         Host_Error ("SV_FlyMove: !trace.ent");
289
290                 if (trace.plane.normal[2] > 0.7)
291                 {
292                         blocked |= 1;           // floor
293                         if (trace.ent->v.solid == SOLID_BSP)
294                         {
295                                 ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
296                                 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
297                         }
298                 }
299                 if (!trace.plane.normal[2])
300                 {
301                         blocked |= 2;           // step
302                         if (steptrace)
303                                 *steptrace = trace;     // save for player extrafriction
304                 }
305
306 //
307 // run the impact function
308 //
309                 SV_Impact (ent, trace.ent);
310                 if (ent->free)
311                         break;          // removed by the impact function
312
313                 
314                 time_left -= time_left * trace.fraction;
315                 
316         // cliped to another plane
317                 if (numplanes >= MAX_CLIP_PLANES)
318                 {       // this shouldn't really happen
319                         VectorCopy (vec3_origin, ent->v.velocity);
320                         return 3;
321                 }
322
323                 VectorCopy (trace.plane.normal, planes[numplanes]);
324                 numplanes++;
325
326 //
327 // modify original_velocity so it parallels all of the clip planes
328 //
329                 for (i=0 ; i<numplanes ; i++)
330                 {
331                         ClipVelocity (original_velocity, planes[i], new_velocity, 1);
332                         for (j=0 ; j<numplanes ; j++)
333                                 if (j != i)
334                                 {
335                                         if (DotProduct (new_velocity, planes[j]) < 0)
336                                                 break;  // not ok
337                                 }
338                         if (j == numplanes)
339                                 break;
340                 }
341                 
342                 if (i != numplanes)
343                 {       // go along this plane
344                         VectorCopy (new_velocity, ent->v.velocity);
345                 }
346                 else
347                 {       // go along the crease
348                         if (numplanes != 2)
349                         {
350 //                              Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
351                                 VectorCopy (vec3_origin, ent->v.velocity);
352                                 return 7;
353                         }
354                         CrossProduct (planes[0], planes[1], dir);
355                         d = DotProduct (dir, ent->v.velocity);
356                         VectorScale (dir, d, ent->v.velocity);
357                 }
358
359 //
360 // if original velocity is against the original velocity, stop dead
361 // to avoid tiny occilations in sloping corners
362 //
363                 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
364                 {
365                         VectorCopy (vec3_origin, ent->v.velocity);
366                         return blocked;
367                 }
368         }
369
370         return blocked;
371 }
372
373
374 /*
375 ============
376 SV_AddGravity
377
378 ============
379 */
380 void SV_AddGravity (edict_t *ent)
381 {
382         float   ent_gravity;
383
384         eval_t  *val;
385
386         val = GETEDICTFIELDVALUE(ent, eval_gravity);
387         if (val!=0 && val->_float)
388                 ent_gravity = val->_float;
389         else
390                 ent_gravity = 1.0;
391         ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
392 }
393
394
395 /*
396 ===============================================================================
397
398 PUSHMOVE
399
400 ===============================================================================
401 */
402
403 /*
404 ============
405 SV_PushEntity
406
407 Does not change the entities velocity at all
408 ============
409 */
410 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
411 {
412         trace_t trace;
413         vec3_t  end;
414                 
415         VectorAdd (ent->v.origin, push, end);
416
417         if (ent->v.movetype == MOVETYPE_FLYMISSILE)
418                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
419         else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
420         // only clip against bmodels
421                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
422         else
423                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);       
424         
425         VectorCopy (trace.endpos, ent->v.origin);
426         SV_LinkEdict (ent, true);
427
428         if (trace.ent)
429                 SV_Impact (ent, trace.ent);             
430
431         return trace;
432 }                                       
433
434
435 /*
436 ============
437 SV_PushMove
438
439 ============
440 */
441 void SV_PushMove (edict_t *pusher, float movetime)
442 {
443         int                     i, e;
444         edict_t         *check;
445         vec3_t          mins, maxs, move;
446         vec3_t          entorig, pushorig;
447         int                     num_moved;
448         edict_t         *moved_edict[MAX_EDICTS];
449         vec3_t          moved_from[MAX_EDICTS];
450         float           savesolid;
451
452         switch ((int) pusher->v.solid)
453         {
454         // LordHavoc: valid pusher types
455         case SOLID_BSP:
456         case SOLID_BBOX:
457         case SOLID_SLIDEBOX:
458         case SOLID_CORPSE: // LordHavoc: this would be weird...
459                 break;
460         // LordHavoc: no collisions
461         case SOLID_NOT:
462         case SOLID_TRIGGER:
463                 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
464                 pusher->v.ltime += movetime;
465                 SV_LinkEdict (pusher, false);
466                 return;
467         default:
468                 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
469         }
470         if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
471         {
472                 pusher->v.ltime += movetime;
473                 return;
474         }
475
476         for (i=0 ; i<3 ; i++)
477         {
478                 move[i] = pusher->v.velocity[i] * movetime;
479                 mins[i] = pusher->v.absmin[i] + move[i];
480                 maxs[i] = pusher->v.absmax[i] + move[i];
481         }
482
483         VectorCopy (pusher->v.origin, pushorig);
484         
485 // move the pusher to it's final position
486
487         VectorAdd (pusher->v.origin, move, pusher->v.origin);
488         pusher->v.ltime += movetime;
489         SV_LinkEdict (pusher, false);
490
491
492 // see if any solid entities are inside the final position
493         num_moved = 0;
494         check = NEXT_EDICT(sv.edicts);
495         for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
496         {
497                 if (check->free)
498                         continue;
499                 if (check->v.movetype == MOVETYPE_PUSH
500                  || check->v.movetype == MOVETYPE_NONE
501                  || check->v.movetype == MOVETYPE_FOLLOW
502                  || check->v.movetype == MOVETYPE_NOCLIP)
503                         continue;
504
505                 // if the entity is standing on the pusher, it will definitely be moved
506                 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
507                 {
508                         if (check->v.absmin[0] >= maxs[0]
509                          || check->v.absmin[1] >= maxs[1]
510                          || check->v.absmin[2] >= maxs[2]
511                          || check->v.absmax[0] <= mins[0]
512                          || check->v.absmax[1] <= mins[1]
513                          || check->v.absmax[2] <= mins[2])
514                                 continue;
515
516                         // see if the ent's bbox is inside the pusher's final position
517                         if (!SV_TestEntityPosition (check))
518                                 continue;
519                 }
520
521                 // remove the onground flag for non-players
522                 if (check->v.movetype != MOVETYPE_WALK)
523                         check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
524                 
525                 VectorCopy (check->v.origin, entorig);
526                 VectorCopy (check->v.origin, moved_from[num_moved]);
527                 moved_edict[num_moved] = check;
528                 num_moved++;
529
530                 // LordHavoc: pusher fixes (teleport train bug, etc)
531                 savesolid = pusher->v.solid;
532                 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
533                 {
534                         // try moving the contacted entity
535                         pusher->v.solid = SOLID_NOT;
536                         SV_PushEntity (check, move);
537                         pusher->v.solid = savesolid; // was SOLID_BSP
538
539                         // if it is still inside the pusher, block
540                         if (SV_TestEntityPosition (check))
541                         {       // fail the move
542                                 if (check->v.mins[0] == check->v.maxs[0])
543                                         continue;
544                                 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
545                                 {       // corpse
546                                         check->v.mins[0] = check->v.mins[1] = 0;
547                                         VectorCopy (check->v.mins, check->v.maxs);
548                                         continue;
549                                 }
550                                 
551                                 VectorCopy (entorig, check->v.origin);
552                                 SV_LinkEdict (check, true);
553
554                                 VectorCopy (pushorig, pusher->v.origin);
555                                 SV_LinkEdict (pusher, false);
556                                 pusher->v.ltime -= movetime;
557
558                                 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
559                                 if (pusher->v.blocked)
560                                 {
561                                         pr_global_struct->self = EDICT_TO_PROG(pusher);
562                                         pr_global_struct->other = EDICT_TO_PROG(check);
563                                         PR_ExecuteProgram (pusher->v.blocked);
564                                 }
565                                 
566                                 // move back any entities we already moved
567                                 num_moved--; // LordHavoc: pop off check, because it was already restored
568                                 for (i=0 ; i<num_moved ; i++)
569                                 {
570                                         VectorCopy (moved_from[i], moved_edict[i]->v.origin);
571                                         SV_LinkEdict (moved_edict[i], false);
572                                 }
573                                 return;
574                         }       
575                 }
576         }
577
578         
579 }
580
581 /*
582 ============
583 SV_PushRotate
584
585 ============
586 */
587 void SV_PushRotate (edict_t *pusher, float movetime)
588 {
589         int                     i, e;
590         edict_t         *check;
591         vec3_t          move, a, amove;
592         vec3_t          entorigin, entangles, pushorigin, pushangles;
593         int                     num_moved;
594         edict_t         *moved_edict[MAX_EDICTS];
595         vec3_t          moved_from[MAX_EDICTS];
596         vec3_t          angled_from[MAX_EDICTS];
597         vec3_t          org, org2;
598         vec3_t          forward, right, up;
599         float           savesolid;
600
601         switch ((int) pusher->v.solid)
602         {
603         // LordHavoc: valid pusher types
604         case SOLID_BSP:
605         case SOLID_BBOX:
606         case SOLID_SLIDEBOX:
607         case SOLID_CORPSE: // LordHavoc: this would be weird...
608                 break;
609         // LordHavoc: no collisions
610         case SOLID_NOT:
611         case SOLID_TRIGGER:
612                 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
613                 pusher->v.ltime += movetime;
614                 SV_LinkEdict (pusher, false);
615                 return;
616         default:
617                 Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
618         }
619         if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
620         {
621                 pusher->v.ltime += movetime;
622                 return;
623         }
624
625         for (i=0 ; i<3 ; i++)
626                 amove[i] = pusher->v.avelocity[i] * movetime;
627
628         VectorSubtract (vec3_origin, amove, a);
629         AngleVectors (a, forward, right, up);
630
631         VectorCopy (pusher->v.origin, pushorigin);
632         VectorCopy (pusher->v.angles, pushangles);
633         
634 // move the pusher to it's final position
635
636         VectorAdd (pusher->v.angles, amove, pusher->v.angles);
637         pusher->v.ltime += movetime;
638         SV_LinkEdict (pusher, false);
639
640
641 // see if any solid entities are inside the final position
642         num_moved = 0;
643         check = NEXT_EDICT(sv.edicts);
644         for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
645         {
646                 if (check->free)
647                         continue;
648                 if (check->v.movetype == MOVETYPE_PUSH
649                  || check->v.movetype == MOVETYPE_NONE
650                  || check->v.movetype == MOVETYPE_FOLLOW
651                  || check->v.movetype == MOVETYPE_NOCLIP)
652                         continue;
653
654         // if the entity is standing on the pusher, it will definately be moved
655                 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
656                 {
657                         if (check->v.absmin[0] >= pusher->v.absmax[0]
658                          || check->v.absmin[1] >= pusher->v.absmax[1]
659                          || check->v.absmin[2] >= pusher->v.absmax[2]
660                          || check->v.absmax[0] <= pusher->v.absmin[0]
661                          || check->v.absmax[1] <= pusher->v.absmin[1]
662                          || check->v.absmax[2] <= pusher->v.absmin[2])
663                                 continue;
664
665                 // see if the ent's bbox is inside the pusher's final position
666                         if (!SV_TestEntityPosition (check))
667                                 continue;
668                 }
669
670         // remove the onground flag for non-players
671                 if (check->v.movetype != MOVETYPE_WALK)
672                         check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
673                 
674                 VectorCopy (check->v.origin, entorigin);
675                 VectorCopy (check->v.origin, moved_from[num_moved]);
676                 VectorCopy (check->v.angles, entangles);
677                 VectorCopy (check->v.angles, angled_from[num_moved]);
678                 moved_edict[num_moved] = check;
679                 num_moved++;
680
681                 // calculate destination position
682                 VectorSubtract (check->v.origin, pusher->v.origin, org);
683                 org2[0] = DotProduct (org, forward);
684                 org2[1] = -DotProduct (org, right);
685                 org2[2] = DotProduct (org, up);
686                 VectorSubtract (org2, org, move);
687
688                 // try moving the contacted entity 
689                 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
690                 pusher->v.solid = SOLID_NOT;
691                 SV_PushEntity (check, move);
692                 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
693
694                 VectorAdd (check->v.angles, amove, check->v.angles);
695
696         // if it is still inside the pusher, block
697                 if (SV_TestEntityPosition (check))
698                 {       // fail the move
699                         if (check->v.mins[0] == check->v.maxs[0])
700                                 continue;
701                         if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
702                         {       // corpse
703                                 check->v.mins[0] = check->v.mins[1] = 0;
704                                 VectorCopy (check->v.mins, check->v.maxs);
705                                 continue;
706                         }
707                         
708                         VectorCopy (entorigin, check->v.origin);
709                         VectorCopy (entangles, check->v.angles);
710                         SV_LinkEdict (check, true);
711
712                         VectorCopy (pushorigin, pusher->v.origin);
713                         VectorCopy (pushangles, pusher->v.angles);
714                         SV_LinkEdict (pusher, false);
715                         pusher->v.ltime -= movetime;
716
717                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
718                         if (pusher->v.blocked)
719                         {
720                                 pr_global_struct->self = EDICT_TO_PROG(pusher);
721                                 pr_global_struct->other = EDICT_TO_PROG(check);
722                                 PR_ExecuteProgram (pusher->v.blocked);
723                         }
724                         
725                 // move back any entities we already moved
726                         num_moved--; // LordHavoc: pop off check, because it was already restored
727                         for (i=0 ; i<num_moved ; i++)
728                         {
729                                 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
730                                 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
731                                 SV_LinkEdict (moved_edict[i], false);
732                         }
733                         return;
734                 }
735         }
736 }
737
738 /*
739 ================
740 SV_Physics_Pusher
741
742 ================
743 */
744 void SV_Physics_Pusher (edict_t *ent)
745 {
746         float   thinktime;
747         float   oldltime;
748         float   movetime;
749
750         oldltime = ent->v.ltime;
751         
752         thinktime = ent->v.nextthink;
753         if (thinktime < ent->v.ltime + host_frametime)
754         {
755                 movetime = thinktime - ent->v.ltime;
756                 if (movetime < 0)
757                         movetime = 0;
758         }
759         else
760                 movetime = host_frametime;
761
762         if (movetime)
763         {
764                 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
765                         SV_PushRotate (ent, movetime);
766                 else
767                         SV_PushMove (ent, movetime);    // advances ent->v.ltime if not blocked
768         }
769                 
770         if (thinktime > oldltime && thinktime <= ent->v.ltime)
771         {
772                 ent->v.nextthink = 0;
773                 pr_global_struct->time = sv.time;
774                 pr_global_struct->self = EDICT_TO_PROG(ent);
775                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
776                 PR_ExecuteProgram (ent->v.think);
777                 if (ent->free)
778                         return;
779         }
780
781 }
782
783
784 /*
785 ===============================================================================
786
787 CLIENT MOVEMENT
788
789 ===============================================================================
790 */
791
792 /*
793 =============
794 SV_CheckStuck
795
796 This is a big hack to try and fix the rare case of getting stuck in the world
797 clipping hull.
798 =============
799 */
800 void SV_CheckStuck (edict_t *ent)
801 {
802         int             i, j;
803         int             z;
804         vec3_t  org;
805
806         if (!SV_TestEntityPosition(ent))
807         {
808                 VectorCopy (ent->v.origin, ent->v.oldorigin);
809                 return;
810         }
811
812         VectorCopy (ent->v.origin, org);
813         VectorCopy (ent->v.oldorigin, ent->v.origin);
814         if (!SV_TestEntityPosition(ent))
815         {
816                 Con_DPrintf ("Unstuck.\n");
817                 SV_LinkEdict (ent, true);
818                 return;
819         }
820         
821         for (z=0 ; z< 18 ; z++)
822                 for (i=-1 ; i <= 1 ; i++)
823                         for (j=-1 ; j <= 1 ; j++)
824                         {
825                                 ent->v.origin[0] = org[0] + i;
826                                 ent->v.origin[1] = org[1] + j;
827                                 ent->v.origin[2] = org[2] + z;
828                                 if (!SV_TestEntityPosition(ent))
829                                 {
830                                         Con_DPrintf ("Unstuck.\n");
831                                         SV_LinkEdict (ent, true);
832                                         return;
833                                 }
834                         }
835                         
836         VectorCopy (org, ent->v.origin);
837         Con_DPrintf ("player is stuck.\n");
838 }
839
840
841 /*
842 =============
843 SV_CheckWater
844 =============
845 */
846 qboolean SV_CheckWater (edict_t *ent)
847 {
848         vec3_t  point;
849         int             cont;
850
851         point[0] = ent->v.origin[0];
852         point[1] = ent->v.origin[1];
853         point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;       
854         
855         ent->v.waterlevel = 0;
856         ent->v.watertype = CONTENTS_EMPTY;
857         cont = SV_PointContents (point);
858         if (cont <= CONTENTS_WATER)
859         {
860                 ent->v.watertype = cont;
861                 ent->v.waterlevel = 1;
862                 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
863                 cont = SV_PointContents (point);
864                 if (cont <= CONTENTS_WATER)
865                 {
866                         ent->v.waterlevel = 2;
867                         point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
868                         cont = SV_PointContents (point);
869                         if (cont <= CONTENTS_WATER)
870                                 ent->v.waterlevel = 3;
871                 }
872         }
873         
874         return ent->v.waterlevel > 1;
875 }
876
877 /*
878 ============
879 SV_WallFriction
880
881 ============
882 */
883 void SV_WallFriction (edict_t *ent, trace_t *trace)
884 {
885         vec3_t          forward, right, up;
886         float           d, i;
887         vec3_t          into, side;
888         
889         AngleVectors (ent->v.v_angle, forward, right, up);
890         d = DotProduct (trace->plane.normal, forward);
891         
892         d += 0.5;
893         if (d >= 0)
894                 return;
895                 
896 // cut the tangential velocity
897         i = DotProduct (trace->plane.normal, ent->v.velocity);
898         VectorScale (trace->plane.normal, i, into);
899         VectorSubtract (ent->v.velocity, into, side);
900         
901         ent->v.velocity[0] = side[0] * (1 + d);
902         ent->v.velocity[1] = side[1] * (1 + d);
903 }
904
905 /*
906 =====================
907 SV_TryUnstick
908
909 Player has come to a dead stop, possibly due to the problem with limited
910 float precision at some angle joins in the BSP hull.
911
912 Try fixing by pushing one pixel in each direction.
913
914 This is a hack, but in the interest of good gameplay...
915 ======================
916 */
917 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
918 {
919         int             i;
920         vec3_t  oldorg;
921         vec3_t  dir;
922         int             clip;
923         trace_t steptrace;
924         
925         VectorCopy (ent->v.origin, oldorg);
926         VectorCopy (vec3_origin, dir);
927
928         for (i=0 ; i<8 ; i++)
929         {
930 // try pushing a little in an axial direction
931                 switch (i)
932                 {
933                         case 0: dir[0] = 2; dir[1] = 0; break;
934                         case 1: dir[0] = 0; dir[1] = 2; break;
935                         case 2: dir[0] = -2; dir[1] = 0; break;
936                         case 3: dir[0] = 0; dir[1] = -2; break;
937                         case 4: dir[0] = 2; dir[1] = 2; break;
938                         case 5: dir[0] = -2; dir[1] = 2; break;
939                         case 6: dir[0] = 2; dir[1] = -2; break;
940                         case 7: dir[0] = -2; dir[1] = -2; break;
941                 }
942                 
943                 SV_PushEntity (ent, dir);
944
945 // retry the original move
946                 ent->v.velocity[0] = oldvel[0];
947                 ent->v. velocity[1] = oldvel[1];
948                 ent->v. velocity[2] = 0;
949                 clip = SV_FlyMove (ent, 0.1, &steptrace);
950
951                 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
952                 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
953                 {
954 //Con_DPrintf ("unstuck!\n");
955                         return clip;
956                 }
957                         
958 // go back to the original pos and try again
959                 VectorCopy (oldorg, ent->v.origin);
960         }
961         
962         VectorCopy (vec3_origin, ent->v.velocity);
963         return 7;               // still not moving
964 }
965
966 /*
967 =====================
968 SV_WalkMove
969
970 Only used by players
971 ======================
972 */
973 #define STEPSIZE        18
974 void SV_WalkMove (edict_t *ent)
975 {
976         vec3_t          upmove, downmove;
977         vec3_t          oldorg, oldvel;
978         vec3_t          nosteporg, nostepvel;
979         int                     clip;
980         int                     oldonground;
981         trace_t         steptrace, downtrace;
982         
983 //
984 // do a regular slide move unless it looks like you ran into a step
985 //
986         oldonground = (int)ent->v.flags & FL_ONGROUND;
987         ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
988         
989         VectorCopy (ent->v.origin, oldorg);
990         VectorCopy (ent->v.velocity, oldvel);
991         
992         clip = SV_FlyMove (ent, host_frametime, &steptrace);
993
994         if ( !(clip & 2) )
995                 return;         // move didn't block on a step
996
997         if (!oldonground && ent->v.waterlevel == 0)
998                 return;         // don't stair up while jumping
999         
1000         if (ent->v.movetype != MOVETYPE_WALK)
1001                 return;         // gibbed by a trigger
1002         
1003         if (sv_nostep.value)
1004                 return;
1005         
1006         if ( (int)sv_player->v.flags & FL_WATERJUMP )
1007                 return;
1008
1009         VectorCopy (ent->v.origin, nosteporg);
1010         VectorCopy (ent->v.velocity, nostepvel);
1011
1012 //
1013 // try moving up and forward to go up a step
1014 //
1015         VectorCopy (oldorg, ent->v.origin);     // back to start pos
1016
1017         VectorCopy (vec3_origin, upmove);
1018         VectorCopy (vec3_origin, downmove);
1019         upmove[2] = STEPSIZE;
1020         downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1021
1022 // move up
1023         SV_PushEntity (ent, upmove);    // FIXME: don't link?
1024
1025 // move forward
1026         ent->v.velocity[0] = oldvel[0];
1027         ent->v. velocity[1] = oldvel[1];
1028         ent->v. velocity[2] = 0;
1029         clip = SV_FlyMove (ent, host_frametime, &steptrace);
1030
1031 // check for stuckness, possibly due to the limited precision of floats
1032 // in the clipping hulls
1033         if (clip)
1034         {
1035                 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1036                 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1037                 {       // stepping up didn't make any progress
1038                         clip = SV_TryUnstick (ent, oldvel);
1039                 }
1040         }
1041         
1042 // extra friction based on view angle
1043         if ( clip & 2 )
1044                 SV_WallFriction (ent, &steptrace);
1045
1046 // move down
1047         downtrace = SV_PushEntity (ent, downmove);      // FIXME: don't link?
1048
1049         if (downtrace.plane.normal[2] > 0.7)
1050         {
1051                 if (ent->v.solid == SOLID_BSP)
1052                 {
1053                         ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
1054                         ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1055                 }
1056         }
1057         else
1058         {
1059 // if the push down didn't end up on good ground, use the move without
1060 // the step up.  This happens near wall / slope combinations, and can
1061 // cause the player to hop up higher on a slope too steep to climb      
1062                 VectorCopy (nosteporg, ent->v.origin);
1063                 VectorCopy (nostepvel, ent->v.velocity);
1064         }
1065 }
1066
1067
1068 /*
1069 ================
1070 SV_Physics_Client
1071
1072 Player character actions
1073 ================
1074 */
1075 void SV_Physics_Client (edict_t *ent, int num)
1076 {
1077         if ( ! svs.clients[num-1].active )
1078                 return;         // unconnected slot
1079
1080 //
1081 // call standard client pre-think
1082 //      
1083         pr_global_struct->time = sv.time;
1084         pr_global_struct->self = EDICT_TO_PROG(ent);
1085         PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1086         
1087 //
1088 // do a move
1089 //
1090         SV_CheckVelocity (ent);
1091
1092 //
1093 // decide which move function to call
1094 //
1095         switch ((int)ent->v.movetype)
1096         {
1097         case MOVETYPE_NONE:
1098                 if (!SV_RunThink (ent))
1099                         return;
1100                 break;
1101
1102         case MOVETYPE_WALK:
1103                 if (!SV_RunThink (ent))
1104                         return;
1105                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1106                         SV_AddGravity (ent);
1107                 SV_CheckStuck (ent);
1108                 SV_WalkMove (ent);
1109                 break;
1110                 
1111         case MOVETYPE_TOSS:
1112         case MOVETYPE_BOUNCE:
1113                 SV_Physics_Toss (ent);
1114                 break;
1115
1116         case MOVETYPE_FLY:
1117                 if (!SV_RunThink (ent))
1118                         return;
1119                 SV_FlyMove (ent, host_frametime, NULL);
1120                 break;
1121                 
1122         case MOVETYPE_NOCLIP:
1123                 if (!SV_RunThink (ent))
1124                         return;
1125                 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1126                 break;
1127                 
1128         default:
1129                 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1130         }
1131
1132 //
1133 // call standard player post-think
1134 //              
1135         SV_LinkEdict (ent, true);
1136
1137         pr_global_struct->time = sv.time;
1138         pr_global_struct->self = EDICT_TO_PROG(ent);
1139         PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1140 }
1141
1142 //============================================================================
1143
1144 /*
1145 =============
1146 SV_Physics_None
1147
1148 Non moving objects can only think
1149 =============
1150 */
1151 void SV_Physics_None (edict_t *ent)
1152 {
1153 // regular thinking
1154         SV_RunThink (ent);
1155 }
1156
1157 /*
1158 =============
1159 SV_Physics_Follow
1160
1161 Entities that are "stuck" to another entity
1162 =============
1163 */
1164 void SV_Physics_Follow (edict_t *ent)
1165 {
1166         vec3_t vf, vr, vu, angles;
1167         edict_t *e;
1168 // regular thinking
1169         if (!SV_RunThink (ent))
1170                 return;
1171         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1172         e = PROG_TO_EDICT(ent->v.aiment);
1173         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])
1174         {
1175                 // quick case for no rotation
1176                 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1177         }
1178         else
1179         {
1180                 angles[0] = -(e->v.angles[0] - ent->v.punchangle[0]);
1181                 angles[1] = e->v.angles[1] - ent->v.punchangle[1];
1182                 angles[2] = e->v.angles[2] - ent->v.punchangle[2];
1183                 AngleVectors (angles, vf, vr, vu);
1184                 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];
1185                 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];
1186                 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];
1187                 /*
1188                 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];
1189                 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];
1190                 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];
1191                 */
1192         }
1193         VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1194 //      VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1195         SV_LinkEdict (ent, true);
1196 }
1197
1198 /*
1199 =============
1200 SV_Physics_Noclip
1201
1202 A moving object that doesn't obey physics
1203 =============
1204 */
1205 void SV_Physics_Noclip (edict_t *ent)
1206 {
1207 // regular thinking
1208         if (!SV_RunThink (ent))
1209                 return;
1210         
1211         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1212         VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1213
1214         SV_LinkEdict (ent, false);
1215 }
1216
1217 /*
1218 ==============================================================================
1219
1220 TOSS / BOUNCE
1221
1222 ==============================================================================
1223 */
1224
1225 /*
1226 =============
1227 SV_CheckWaterTransition
1228
1229 =============
1230 */
1231 void SV_CheckWaterTransition (edict_t *ent)
1232 {
1233         int             cont;
1234         cont = SV_PointContents (ent->v.origin);
1235         if (!ent->v.watertype)
1236         {       // just spawned here
1237                 ent->v.watertype = cont;
1238                 ent->v.waterlevel = 1;
1239                 return;
1240         }
1241         
1242         if (cont <= CONTENTS_WATER)
1243         {
1244                 if (ent->v.watertype == CONTENTS_EMPTY)
1245                 {       // just crossed into water
1246                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1247                 }               
1248                 ent->v.watertype = cont;
1249                 ent->v.waterlevel = 1;
1250         }
1251         else
1252         {
1253                 if (ent->v.watertype != CONTENTS_EMPTY)
1254                 {       // just crossed into water
1255                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1256                 }               
1257                 ent->v.watertype = CONTENTS_EMPTY;
1258                 ent->v.waterlevel = cont;
1259         }
1260 }
1261
1262 /*
1263 =============
1264 SV_Physics_Toss
1265
1266 Toss, bounce, and fly movement.  When onground, do nothing.
1267 =============
1268 */
1269 void SV_Physics_Toss (edict_t *ent)
1270 {
1271         trace_t trace;
1272         vec3_t  move;
1273         float   backoff;
1274         // regular thinking
1275         if (!SV_RunThink (ent))
1276                 return;
1277
1278 // if onground, return without moving
1279         if ( ((int)ent->v.flags & FL_ONGROUND) )
1280                 return;
1281
1282         SV_CheckVelocity (ent);
1283
1284 // add gravity
1285         if (ent->v.movetype != MOVETYPE_FLY
1286         && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1287         && ent->v.movetype != MOVETYPE_FLYMISSILE)
1288                 SV_AddGravity (ent);
1289
1290 // move angles
1291         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1292
1293 // move origin
1294         VectorScale (ent->v.velocity, host_frametime, move);
1295         trace = SV_PushEntity (ent, move);
1296         if (trace.fraction == 1)
1297                 return;
1298         if (ent->free)
1299                 return;
1300         
1301         if (ent->v.movetype == MOVETYPE_BOUNCE)
1302                 backoff = 1.5;
1303         else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1304                 backoff = 2.0;
1305         else
1306                 backoff = 1;
1307
1308         ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1309
1310 // stop if on ground
1311         if (trace.plane.normal[2] > 0.7)
1312         {               
1313                 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1314                 {
1315                         ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1316                         ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1317                         VectorCopy (vec3_origin, ent->v.velocity);
1318                         VectorCopy (vec3_origin, ent->v.avelocity);
1319                 }
1320         }
1321         
1322 // check for in water
1323         SV_CheckWaterTransition (ent);
1324 }
1325
1326 /*
1327 ===============================================================================
1328
1329 STEPPING MOVEMENT
1330
1331 ===============================================================================
1332 */
1333
1334 /*
1335 =============
1336 SV_Physics_Step
1337
1338 Monsters freefall when they don't have a ground entity, otherwise
1339 all movement is done with discrete steps.
1340
1341 This is also used for objects that have become still on the ground, but
1342 will fall if the floor is pulled out from under them.
1343 =============
1344 */
1345 void SV_Physics_Step (edict_t *ent)
1346 {
1347         qboolean        hitsound;
1348
1349 // freefall if not onground
1350         if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1351         {
1352                 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1353                         hitsound = true;
1354                 else
1355                         hitsound = false;
1356
1357                 SV_AddGravity (ent);
1358                 SV_CheckVelocity (ent);
1359                 SV_FlyMove (ent, host_frametime, NULL);
1360                 SV_LinkEdict (ent, true);
1361
1362                 if ( (int)ent->v.flags & FL_ONGROUND )  // just hit ground
1363                 {
1364                         if (hitsound)
1365                                 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1366                 }
1367         }
1368
1369 // regular thinking
1370         SV_RunThink (ent);
1371         
1372         SV_CheckWaterTransition (ent);
1373 }
1374
1375 //============================================================================
1376
1377 /*
1378 ================
1379 SV_Physics
1380
1381 ================
1382 */
1383 extern dfunction_t *EndFrameQC;
1384 void SV_Physics (void)
1385 {
1386         int             i;
1387         edict_t *ent;
1388
1389 // let the progs know that a new frame has started
1390         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1391         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1392         pr_global_struct->time = sv.time;
1393         PR_ExecuteProgram (pr_global_struct->StartFrame);
1394
1395 //SV_CheckAllEnts ();
1396
1397 //
1398 // treat each object in turn
1399 //
1400         ent = sv.edicts;
1401         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1402         {
1403                 if (ent->free)
1404                         continue;
1405
1406                 if (pr_global_struct->force_retouch)
1407                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1408
1409                 if (i > 0 && i <= svs.maxclients)
1410                 {
1411                         SV_Physics_Client (ent, i);
1412                         continue;
1413                 }
1414
1415                 switch ((int) ent->v.movetype)
1416                 {
1417                 case MOVETYPE_PUSH:
1418                         SV_Physics_Pusher (ent);
1419                         break;
1420                 case MOVETYPE_NONE:
1421                         SV_Physics_None (ent);
1422                         break;
1423                 case MOVETYPE_FOLLOW:
1424                         SV_Physics_Follow (ent);
1425                         break;
1426                 case MOVETYPE_NOCLIP:
1427                         SV_Physics_Noclip (ent);
1428                         break;
1429                 case MOVETYPE_STEP:
1430                         SV_Physics_Step (ent);
1431                         break;
1432                 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1433                 case MOVETYPE_WALK:
1434                         if (SV_RunThink (ent))
1435                         {
1436                                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1437                                         SV_AddGravity (ent);
1438                                 SV_CheckStuck (ent);
1439                                 SV_WalkMove (ent);
1440                         }
1441                         break;
1442                 case MOVETYPE_TOSS:
1443                 case MOVETYPE_BOUNCE:
1444                 case MOVETYPE_BOUNCEMISSILE:
1445                 case MOVETYPE_FLY:
1446                 case MOVETYPE_FLYMISSILE:
1447                         SV_Physics_Toss (ent);
1448                         break;
1449                 default:
1450                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1451                         break;
1452                 }
1453         }
1454         
1455         if (pr_global_struct->force_retouch)
1456                 pr_global_struct->force_retouch--;      
1457
1458         // LordHavoc: endframe support
1459         if (EndFrameQC)
1460         {
1461                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1462                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1463                 pr_global_struct->time = sv.time;
1464                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1465         }
1466
1467         sv.time += host_frametime;
1468 }
1469
1470
1471 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1472 {
1473         int i;
1474         edict_t tempent, *tent;
1475         trace_t trace;
1476         vec3_t  move;
1477         vec3_t  end;
1478         double  save_frametime;
1479
1480         save_frametime = host_frametime;
1481         host_frametime = 0.05;
1482
1483         memcpy(&tempent, ent, sizeof(edict_t));
1484         tent = &tempent;
1485
1486         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1487         {
1488                 SV_CheckVelocity (tent);
1489                 SV_AddGravity (tent);
1490                 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1491                 VectorScale (tent->v.velocity, host_frametime, move);
1492                 VectorAdd (tent->v.origin, move, end);
1493                 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);   
1494                 VectorCopy (trace.endpos, tent->v.origin);
1495
1496                 if (trace.ent)
1497                         if (trace.ent != ignore)
1498                                 break;
1499         }
1500         host_frametime = save_frametime;
1501         return trace;
1502 }