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