]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_phys.c
bmodel rotation physics now work
[divverent/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         if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
602         {
603                 pusher->v.ltime += movetime;
604                 return;
605         }
606
607         for (i=0 ; i<3 ; i++)
608                 amove[i] = pusher->v.avelocity[i] * movetime;
609
610         VectorSubtract (vec3_origin, amove, a);
611         AngleVectors (a, forward, right, up);
612
613         VectorCopy (pusher->v.origin, pushorigin);
614         VectorCopy (pusher->v.angles, pushangles);
615         
616 // move the pusher to it's final position
617
618         VectorAdd (pusher->v.angles, amove, pusher->v.angles);
619         pusher->v.ltime += movetime;
620         SV_LinkEdict (pusher, false);
621
622
623 // see if any solid entities are inside the final position
624         num_moved = 0;
625         check = NEXT_EDICT(sv.edicts);
626         for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
627         {
628                 if (check->free)
629                         continue;
630                 if (check->v.movetype == MOVETYPE_PUSH
631                  || check->v.movetype == MOVETYPE_NONE
632                  || check->v.movetype == MOVETYPE_FOLLOW
633                  || check->v.movetype == MOVETYPE_NOCLIP)
634                         continue;
635
636         // if the entity is standing on the pusher, it will definately be moved
637                 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
638                 {
639                         if (check->v.absmin[0] >= pusher->v.absmax[0]
640                          || check->v.absmin[1] >= pusher->v.absmax[1]
641                          || check->v.absmin[2] >= pusher->v.absmax[2]
642                          || check->v.absmax[0] <= pusher->v.absmin[0]
643                          || check->v.absmax[1] <= pusher->v.absmin[1]
644                          || check->v.absmax[2] <= pusher->v.absmin[2])
645                                 continue;
646
647                 // see if the ent's bbox is inside the pusher's final position
648                         if (!SV_TestEntityPosition (check))
649                                 continue;
650                 }
651
652         // remove the onground flag for non-players
653                 if (check->v.movetype != MOVETYPE_WALK)
654                         check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
655                 
656                 VectorCopy (check->v.origin, entorigin);
657                 VectorCopy (check->v.origin, moved_from[num_moved]);
658                 VectorCopy (check->v.angles, entangles);
659                 VectorCopy (check->v.angles, angled_from[num_moved]);
660                 moved_edict[num_moved] = check;
661                 num_moved++;
662
663                 // calculate destination position
664                 VectorSubtract (check->v.origin, pusher->v.origin, org);
665                 org2[0] = DotProduct (org, forward);
666                 org2[1] = -DotProduct (org, right);
667                 org2[2] = DotProduct (org, up);
668                 VectorSubtract (org2, org, move);
669
670                 // try moving the contacted entity 
671                 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
672                 pusher->v.solid = SOLID_NOT;
673                 SV_PushEntity (check, move);
674                 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
675
676                 VectorAdd (check->v.angles, amove, check->v.angles);
677
678         // if it is still inside the pusher, block
679                 if (SV_TestEntityPosition (check))
680                 {       // fail the move
681                         if (check->v.mins[0] == check->v.maxs[0])
682                                 continue;
683                         if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
684                         {       // corpse
685                                 check->v.mins[0] = check->v.mins[1] = 0;
686                                 VectorCopy (check->v.mins, check->v.maxs);
687                                 continue;
688                         }
689                         
690                         VectorCopy (entorigin, check->v.origin);
691                         VectorCopy (entangles, check->v.angles);
692                         SV_LinkEdict (check, true);
693
694                         VectorCopy (pushorigin, pusher->v.origin);
695                         VectorCopy (pushangles, pusher->v.angles);
696                         SV_LinkEdict (pusher, false);
697                         pusher->v.ltime -= movetime;
698
699                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
700                         if (pusher->v.blocked)
701                         {
702                                 pr_global_struct->self = EDICT_TO_PROG(pusher);
703                                 pr_global_struct->other = EDICT_TO_PROG(check);
704                                 PR_ExecuteProgram (pusher->v.blocked);
705                         }
706                         
707                 // move back any entities we already moved
708                         num_moved--; // LordHavoc: pop off check, because it was already restored
709                         for (i=0 ; i<num_moved ; i++)
710                         {
711                                 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
712                                 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
713                                 SV_LinkEdict (moved_edict[i], false);
714                         }
715                         return;
716                 }
717         }
718 }
719
720 /*
721 ================
722 SV_Physics_Pusher
723
724 ================
725 */
726 void SV_Physics_Pusher (edict_t *ent)
727 {
728         float   thinktime;
729         float   oldltime;
730         float   movetime;
731
732         oldltime = ent->v.ltime;
733         
734         /*
735         thinktime = ent->v.nextthink;
736         if (thinktime < ent->v.ltime + host_frametime)
737         {
738                 movetime = thinktime - ent->v.ltime;
739                 if (movetime < 0)
740                         movetime = 0;
741         }
742         else
743                 movetime = host_frametime;
744
745         if (movetime)
746         {
747                 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
748                         SV_PushRotate (ent, movetime);
749                 else
750                         SV_PushMove (ent, movetime);    // advances ent->v.ltime if not blocked
751         }
752         */
753         if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
754                 SV_PushRotate (ent, host_frametime);
755         else
756         {
757                 thinktime = ent->v.nextthink;
758                 if (thinktime < ent->v.ltime + host_frametime)
759                 {
760                         movetime = thinktime - ent->v.ltime;
761                         if (movetime < 0)
762                                 movetime = 0;
763                 }
764                 else
765                         movetime = host_frametime;
766                 if (movetime)
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, vu, vr, angles;
1167         edict_t *e;
1168 // regular thinking
1169         SV_RunThink (ent);
1170         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1171         e = PROG_TO_EDICT(ent->v.aiment);
1172         angles[0] = -e->v.angles[0];
1173         angles[1] = e->v.angles[1];
1174         angles[2] = e->v.angles[2];
1175         AngleVectors (angles, vf, vr, vu);
1176         VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin);
1177         VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin);
1178         VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin);
1179         VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1180 //      VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1181         SV_LinkEdict (ent, true);
1182 }
1183
1184 /*
1185 =============
1186 SV_Physics_Noclip
1187
1188 A moving object that doesn't obey physics
1189 =============
1190 */
1191 void SV_Physics_Noclip (edict_t *ent)
1192 {
1193 // regular thinking
1194         if (!SV_RunThink (ent))
1195                 return;
1196         
1197         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1198         VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1199
1200         SV_LinkEdict (ent, false);
1201 }
1202
1203 /*
1204 ==============================================================================
1205
1206 TOSS / BOUNCE
1207
1208 ==============================================================================
1209 */
1210
1211 /*
1212 =============
1213 SV_CheckWaterTransition
1214
1215 =============
1216 */
1217 void SV_CheckWaterTransition (edict_t *ent)
1218 {
1219         int             cont;
1220         cont = SV_PointContents (ent->v.origin);
1221         if (!ent->v.watertype)
1222         {       // just spawned here
1223                 ent->v.watertype = cont;
1224                 ent->v.waterlevel = 1;
1225                 return;
1226         }
1227         
1228         if (cont <= CONTENTS_WATER)
1229         {
1230                 if (ent->v.watertype == CONTENTS_EMPTY)
1231                 {       // just crossed into water
1232                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1233                 }               
1234                 ent->v.watertype = cont;
1235                 ent->v.waterlevel = 1;
1236         }
1237         else
1238         {
1239                 if (ent->v.watertype != CONTENTS_EMPTY)
1240                 {       // just crossed into water
1241                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1242                 }               
1243                 ent->v.watertype = CONTENTS_EMPTY;
1244                 ent->v.waterlevel = cont;
1245         }
1246 }
1247
1248 /*
1249 =============
1250 SV_Physics_Toss
1251
1252 Toss, bounce, and fly movement.  When onground, do nothing.
1253 =============
1254 */
1255 void SV_Physics_Toss (edict_t *ent)
1256 {
1257         trace_t trace;
1258         vec3_t  move;
1259         float   backoff;
1260         // regular thinking
1261         if (!SV_RunThink (ent))
1262                 return;
1263
1264 // if onground, return without moving
1265         if ( ((int)ent->v.flags & FL_ONGROUND) )
1266                 return;
1267
1268         SV_CheckVelocity (ent);
1269
1270 // add gravity
1271         if (ent->v.movetype != MOVETYPE_FLY
1272         && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1273         && ent->v.movetype != MOVETYPE_FLYMISSILE)
1274                 SV_AddGravity (ent);
1275
1276 // move angles
1277         VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1278
1279 // move origin
1280         VectorScale (ent->v.velocity, host_frametime, move);
1281         trace = SV_PushEntity (ent, move);
1282         if (trace.fraction == 1)
1283                 return;
1284         if (ent->free)
1285                 return;
1286         
1287         if (ent->v.movetype == MOVETYPE_BOUNCE)
1288                 backoff = 1.5;
1289         else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1290                 backoff = 2.0;
1291         else
1292                 backoff = 1;
1293
1294         ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1295
1296 // stop if on ground
1297         if (trace.plane.normal[2] > 0.7)
1298         {               
1299                 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1300                 {
1301                         ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1302                         ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1303                         VectorCopy (vec3_origin, ent->v.velocity);
1304                         VectorCopy (vec3_origin, ent->v.avelocity);
1305                 }
1306         }
1307         
1308 // check for in water
1309         SV_CheckWaterTransition (ent);
1310 }
1311
1312 /*
1313 ===============================================================================
1314
1315 STEPPING MOVEMENT
1316
1317 ===============================================================================
1318 */
1319
1320 /*
1321 =============
1322 SV_Physics_Step
1323
1324 Monsters freefall when they don't have a ground entity, otherwise
1325 all movement is done with discrete steps.
1326
1327 This is also used for objects that have become still on the ground, but
1328 will fall if the floor is pulled out from under them.
1329 =============
1330 */
1331 void SV_Physics_Step (edict_t *ent)
1332 {
1333         qboolean        hitsound;
1334
1335 // freefall if not onground
1336         if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1337         {
1338                 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1339                         hitsound = true;
1340                 else
1341                         hitsound = false;
1342
1343                 SV_AddGravity (ent);
1344                 SV_CheckVelocity (ent);
1345                 SV_FlyMove (ent, host_frametime, NULL);
1346                 SV_LinkEdict (ent, true);
1347
1348                 if ( (int)ent->v.flags & FL_ONGROUND )  // just hit ground
1349                 {
1350                         if (hitsound)
1351                                 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1352                 }
1353         }
1354
1355 // regular thinking
1356         SV_RunThink (ent);
1357         
1358         SV_CheckWaterTransition (ent);
1359 }
1360
1361 //============================================================================
1362
1363 /*
1364 ================
1365 SV_Physics
1366
1367 ================
1368 */
1369 extern dfunction_t *EndFrameQC;
1370 void SV_Physics (void)
1371 {
1372         int             i;
1373         edict_t *ent;
1374
1375 // let the progs know that a new frame has started
1376         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1377         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1378         pr_global_struct->time = sv.time;
1379         PR_ExecuteProgram (pr_global_struct->StartFrame);
1380
1381 //SV_CheckAllEnts ();
1382
1383 //
1384 // treat each object in turn
1385 //
1386         ent = sv.edicts;
1387         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1388         {
1389                 if (ent->free)
1390                         continue;
1391
1392                 if (pr_global_struct->force_retouch)
1393                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1394
1395                 if (i > 0 && i <= svs.maxclients)
1396                 {
1397                         SV_Physics_Client (ent, i);
1398                         continue;
1399                 }
1400
1401                 switch ((int) ent->v.movetype)
1402                 {
1403                 case MOVETYPE_PUSH:
1404                         SV_Physics_Pusher (ent);
1405                         break;
1406                 case MOVETYPE_NONE:
1407                         SV_Physics_None (ent);
1408                         break;
1409                 case MOVETYPE_FOLLOW:
1410                         SV_Physics_Follow (ent);
1411                         break;
1412                 case MOVETYPE_NOCLIP:
1413                         SV_Physics_Noclip (ent);
1414                         break;
1415                 case MOVETYPE_STEP:
1416                         SV_Physics_Step (ent);
1417                         break;
1418                 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1419                 case MOVETYPE_WALK:
1420                         if (SV_RunThink (ent))
1421                         {
1422                                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1423                                         SV_AddGravity (ent);
1424                                 SV_CheckStuck (ent);
1425                                 SV_WalkMove (ent);
1426                         }
1427                         break;
1428                 case MOVETYPE_TOSS:
1429                 case MOVETYPE_BOUNCE:
1430                 case MOVETYPE_BOUNCEMISSILE:
1431                 case MOVETYPE_FLY:
1432                 case MOVETYPE_FLYMISSILE:
1433                         SV_Physics_Toss (ent);
1434                         break;
1435                 default:
1436                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1437                         break;
1438                 }
1439         }
1440         
1441         if (pr_global_struct->force_retouch)
1442                 pr_global_struct->force_retouch--;      
1443
1444         // LordHavoc: endframe support
1445         if (EndFrameQC)
1446         {
1447                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1448                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1449                 pr_global_struct->time = sv.time;
1450                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1451         }
1452
1453         sv.time += host_frametime;
1454 }
1455
1456
1457 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1458 {
1459         int i;
1460         edict_t tempent, *tent;
1461         trace_t trace;
1462         vec3_t  move;
1463         vec3_t  end;
1464         double  save_frametime;
1465
1466         save_frametime = host_frametime;
1467         host_frametime = 0.05;
1468
1469         memcpy(&tempent, ent, sizeof(edict_t));
1470         tent = &tempent;
1471
1472         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1473         {
1474                 SV_CheckVelocity (tent);
1475                 SV_AddGravity (tent);
1476                 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1477                 VectorScale (tent->v.velocity, host_frametime, move);
1478                 VectorAdd (tent->v.origin, move, end);
1479                 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);   
1480                 VectorCopy (trace.endpos, tent->v.origin);
1481
1482                 if (trace.ent)
1483                         if (trace.ent != ignore)
1484                                 break;
1485         }
1486         host_frametime = save_frametime;
1487         return trace;
1488 }