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