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