]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_phys.c
73b013df452c9f366fa88a15263e4dd57bba62df
[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, "NULL think function");
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                         VectorClear(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                         VectorClear(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                                 VectorClear(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                         VectorClear(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         VectorNegate (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, "NULL think function");
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         VectorClear (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         VectorClear (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         VectorClear (upmove);
1018         VectorClear (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, "QC function PlayerPreThink is missing");
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_CheckWater (ent);
1120                 SV_FlyMove (ent, host_frametime, NULL);
1121                 break;
1122                 
1123         case MOVETYPE_NOCLIP:
1124                 if (!SV_RunThink (ent))
1125                         return;
1126                 SV_CheckWater (ent);
1127                 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1128                 break;
1129                 
1130         default:
1131                 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1132         }
1133
1134 //
1135 // call standard player post-think
1136 //              
1137         SV_LinkEdict (ent, true);
1138
1139         pr_global_struct->time = sv.time;
1140         pr_global_struct->self = EDICT_TO_PROG(ent);
1141         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1142 }
1143
1144 //============================================================================
1145
1146 /*
1147 =============
1148 SV_Physics_None
1149
1150 Non moving objects can only think
1151 =============
1152 */
1153 void SV_Physics_None (edict_t *ent)
1154 {
1155 // regular thinking
1156         SV_RunThink (ent);
1157 }
1158
1159 /*
1160 =============
1161 SV_Physics_Follow
1162
1163 Entities that are "stuck" to another entity
1164 =============
1165 */
1166 void SV_Physics_Follow (edict_t *ent)
1167 {
1168         vec3_t vf, vr, vu, angles;
1169         edict_t *e;
1170 // regular thinking
1171         if (!SV_RunThink (ent))
1172                 return;
1173         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1174         e = PROG_TO_EDICT(ent->v.aiment);
1175         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])
1176         {
1177                 // quick case for no rotation
1178                 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1179         }
1180         else
1181         {
1182                 angles[0] = -(e->v.angles[0] - ent->v.punchangle[0]);
1183                 angles[1] = e->v.angles[1] - ent->v.punchangle[1];
1184                 angles[2] = e->v.angles[2] - ent->v.punchangle[2];
1185                 AngleVectors (angles, vf, vr, vu);
1186                 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];
1187                 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];
1188                 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];
1189                 /*
1190                 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];
1191                 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];
1192                 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];
1193                 */
1194         }
1195         VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1196 //      VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1197         SV_LinkEdict (ent, true);
1198 }
1199
1200 /*
1201 =============
1202 SV_Physics_Noclip
1203
1204 A moving object that doesn't obey physics
1205 =============
1206 */
1207 void SV_Physics_Noclip (edict_t *ent)
1208 {
1209 // regular thinking
1210         if (!SV_RunThink (ent))
1211                 return;
1212         
1213         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1214         VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1215
1216         SV_LinkEdict (ent, false);
1217 }
1218
1219 /*
1220 ==============================================================================
1221
1222 TOSS / BOUNCE
1223
1224 ==============================================================================
1225 */
1226
1227 /*
1228 =============
1229 SV_CheckWaterTransition
1230
1231 =============
1232 */
1233 void SV_CheckWaterTransition (edict_t *ent)
1234 {
1235         int             cont;
1236         cont = SV_PointContents (ent->v.origin);
1237         if (!ent->v.watertype)
1238         {       // just spawned here
1239                 ent->v.watertype = cont;
1240                 ent->v.waterlevel = 1;
1241                 return;
1242         }
1243         
1244         if (cont <= CONTENTS_WATER)
1245         {
1246                 if (ent->v.watertype == CONTENTS_EMPTY)
1247                 {       // just crossed into water
1248                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1249                 }               
1250                 ent->v.watertype = cont;
1251                 ent->v.waterlevel = 1;
1252         }
1253         else
1254         {
1255                 if (ent->v.watertype != CONTENTS_EMPTY)
1256                 {       // just crossed into water
1257                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1258                 }               
1259                 ent->v.watertype = CONTENTS_EMPTY;
1260                 ent->v.waterlevel = cont;
1261         }
1262 }
1263
1264 /*
1265 =============
1266 SV_Physics_Toss
1267
1268 Toss, bounce, and fly movement.  When onground, do nothing.
1269 =============
1270 */
1271 void SV_Physics_Toss (edict_t *ent)
1272 {
1273         trace_t trace;
1274         vec3_t  move;
1275         float   backoff;
1276         // regular thinking
1277         if (!SV_RunThink (ent))
1278                 return;
1279
1280 // if onground, return without moving
1281         if ( ((int)ent->v.flags & FL_ONGROUND) )
1282                 return;
1283
1284         SV_CheckVelocity (ent);
1285
1286 // add gravity
1287         if (ent->v.movetype != MOVETYPE_FLY
1288         && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1289         && ent->v.movetype != MOVETYPE_FLYMISSILE)
1290                 SV_AddGravity (ent);
1291
1292 // move angles
1293         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1294
1295 // move origin
1296         VectorScale (ent->v.velocity, host_frametime, move);
1297         trace = SV_PushEntity (ent, move);
1298         if (trace.fraction == 1)
1299                 return;
1300         if (ent->free)
1301                 return;
1302         
1303         if (ent->v.movetype == MOVETYPE_BOUNCE)
1304                 backoff = 1.5;
1305         else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1306                 backoff = 2.0;
1307         else
1308                 backoff = 1;
1309
1310         ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1311
1312 // stop if on ground
1313         if (trace.plane.normal[2] > 0.7)
1314         {               
1315                 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1316                 {
1317                         ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1318                         ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1319                         VectorClear (ent->v.velocity);
1320                         VectorClear (ent->v.avelocity);
1321                 }
1322         }
1323         
1324 // check for in water
1325         SV_CheckWaterTransition (ent);
1326 }
1327
1328 /*
1329 ===============================================================================
1330
1331 STEPPING MOVEMENT
1332
1333 ===============================================================================
1334 */
1335
1336 /*
1337 =============
1338 SV_Physics_Step
1339
1340 Monsters freefall when they don't have a ground entity, otherwise
1341 all movement is done with discrete steps.
1342
1343 This is also used for objects that have become still on the ground, but
1344 will fall if the floor is pulled out from under them.
1345 =============
1346 */
1347 void SV_Physics_Step (edict_t *ent)
1348 {
1349         qboolean        hitsound;
1350
1351 // freefall if not onground
1352         if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1353         {
1354                 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1355                         hitsound = true;
1356                 else
1357                         hitsound = false;
1358
1359                 SV_AddGravity (ent);
1360                 SV_CheckVelocity (ent);
1361                 SV_FlyMove (ent, host_frametime, NULL);
1362                 SV_LinkEdict (ent, true);
1363
1364                 if ( (int)ent->v.flags & FL_ONGROUND )  // just hit ground
1365                 {
1366                         if (hitsound)
1367                                 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1368                 }
1369         }
1370
1371 // regular thinking
1372         SV_RunThink (ent);
1373         
1374         SV_CheckWaterTransition (ent);
1375 }
1376
1377 //============================================================================
1378
1379 /*
1380 ================
1381 SV_Physics
1382
1383 ================
1384 */
1385 extern dfunction_t *EndFrameQC;
1386 void SV_Physics (void)
1387 {
1388         int             i;
1389         edict_t *ent;
1390
1391 // let the progs know that a new frame has started
1392         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1393         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1394         pr_global_struct->time = sv.time;
1395         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1396
1397 //SV_CheckAllEnts ();
1398
1399 //
1400 // treat each object in turn
1401 //
1402         ent = sv.edicts;
1403         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1404         {
1405                 if (ent->free)
1406                         continue;
1407
1408                 if (pr_global_struct->force_retouch)
1409                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1410
1411                 if (i > 0 && i <= svs.maxclients)
1412                 {
1413                         SV_Physics_Client (ent, i);
1414                         continue;
1415                 }
1416
1417                 switch ((int) ent->v.movetype)
1418                 {
1419                 case MOVETYPE_PUSH:
1420                         SV_Physics_Pusher (ent);
1421                         break;
1422                 case MOVETYPE_NONE:
1423                         SV_Physics_None (ent);
1424                         break;
1425                 case MOVETYPE_FOLLOW:
1426                         SV_Physics_Follow (ent);
1427                         break;
1428                 case MOVETYPE_NOCLIP:
1429                         SV_Physics_Noclip (ent);
1430                         break;
1431                 case MOVETYPE_STEP:
1432                         SV_Physics_Step (ent);
1433                         break;
1434                 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1435                 case MOVETYPE_WALK:
1436                         if (SV_RunThink (ent))
1437                         {
1438                                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1439                                         SV_AddGravity (ent);
1440                                 SV_CheckStuck (ent);
1441                                 SV_WalkMove (ent);
1442                         }
1443                         break;
1444                 case MOVETYPE_TOSS:
1445                 case MOVETYPE_BOUNCE:
1446                 case MOVETYPE_BOUNCEMISSILE:
1447                 case MOVETYPE_FLY:
1448                 case MOVETYPE_FLYMISSILE:
1449                         SV_Physics_Toss (ent);
1450                         break;
1451                 default:
1452                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1453                         break;
1454                 }
1455         }
1456         
1457         if (pr_global_struct->force_retouch)
1458                 pr_global_struct->force_retouch--;      
1459
1460         // LordHavoc: endframe support
1461         if (EndFrameQC)
1462         {
1463                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1464                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1465                 pr_global_struct->time = sv.time;
1466                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1467         }
1468
1469         sv.time += host_frametime;
1470 }
1471
1472
1473 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1474 {
1475         int i;
1476         edict_t tempent, *tent;
1477         trace_t trace;
1478         vec3_t  move;
1479         vec3_t  end;
1480         double  save_frametime;
1481
1482         save_frametime = host_frametime;
1483         host_frametime = 0.05;
1484
1485         memcpy(&tempent, ent, sizeof(edict_t));
1486         tent = &tempent;
1487
1488         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1489         {
1490                 SV_CheckVelocity (tent);
1491                 SV_AddGravity (tent);
1492                 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1493                 VectorScale (tent->v.velocity, host_frametime, move);
1494                 VectorAdd (tent->v.origin, move, end);
1495                 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);   
1496                 VectorCopy (trace.endpos, tent->v.origin);
1497
1498                 if (trace.ent)
1499                         if (trace.ent != ignore)
1500                                 break;
1501         }
1502         host_frametime = save_frametime;
1503         return trace;
1504 }