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