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