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