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