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