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