]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_phys.c
reverted back to per-entity prethink-think-move-postthink process to fix mods
[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 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, "QC function self.think is missing");
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, "QC function self.touch is missing");
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, "QC function self.touch is missing");
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 int SV_SetOnGround (edict_t *ent)
475 {
476         vec3_t end;
477         trace_t trace;
478         if ((int)ent->v->flags & FL_ONGROUND)
479                 return 1;
480         VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1);
481         trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
482         if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7)
483         {
484                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
485                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
486                 return 1;
487         }
488         return 0;
489 }
490
491 /*
492 ============
493 SV_AddGravity
494
495 ============
496 */
497 void SV_AddGravity (edict_t *ent)
498 {
499         float ent_gravity;
500         eval_t *val;
501
502         val = GETEDICTFIELDVALUE(ent, eval_gravity);
503         if (val!=0 && val->_float)
504                 ent_gravity = val->_float;
505         else
506                 ent_gravity = 1.0;
507         ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
508 }
509
510
511 /*
512 ===============================================================================
513
514 PUSHMOVE
515
516 ===============================================================================
517 */
518
519 /*
520 ============
521 SV_PushEntity
522
523 Does not change the entities velocity at all
524 ============
525 */
526 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
527 {
528         int type;
529         trace_t trace;
530         vec3_t end;
531
532         VectorAdd (ent->v->origin, push, end);
533
534         if (ent->v->movetype == MOVETYPE_FLYMISSILE)
535                 type = MOVE_MISSILE;
536         else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
537                 type = MOVE_NOMONSTERS; // only clip against bmodels
538         else
539                 type = MOVE_NORMAL;
540
541         trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent);
542
543         VectorCopy (trace.endpos, ent->v->origin);
544         SV_LinkEdict (ent, true);
545
546         if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
547                 SV_Impact (ent, trace.ent);
548         return trace;
549 }
550
551
552 /*
553 ============
554 SV_PushMove
555
556 ============
557 */
558 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
559 void SV_PushMove (edict_t *pusher, float movetime)
560 {
561         int i, e, index;
562         edict_t *check, *ed;
563         float savesolid, movetime2, pushltime;
564         vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
565         int num_moved;
566         int numcheckentities;
567         static edict_t *checkentities[MAX_EDICTS];
568         model_t *pushermodel;
569         trace_t trace;
570
571         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])
572         {
573                 pusher->v->ltime += movetime;
574                 return;
575         }
576
577         switch ((int) pusher->v->solid)
578         {
579         // LordHavoc: valid pusher types
580         case SOLID_BSP:
581         case SOLID_BBOX:
582         case SOLID_SLIDEBOX:
583         case SOLID_CORPSE: // LordHavoc: this would be weird...
584                 break;
585         // LordHavoc: no collisions
586         case SOLID_NOT:
587         case SOLID_TRIGGER:
588                 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
589                 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
590                 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
591                 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
592                 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
593                 pusher->v->ltime += movetime;
594                 SV_LinkEdict (pusher, false);
595                 return;
596         default:
597                 Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
598                 return;
599         }
600         index = (int) pusher->v->modelindex;
601         if (index < 1 || index >= MAX_MODELS)
602         {
603                 Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
604                 return;
605         }
606         pushermodel = sv.models[index];
607
608         movetime2 = movetime;
609         VectorScale(pusher->v->velocity, movetime2, move1);
610         VectorScale(pusher->v->avelocity, movetime2, moveangle);
611         if (moveangle[0] || moveangle[2])
612         {
613                 for (i = 0;i < 3;i++)
614                 {
615                         if (move1[i] > 0)
616                         {
617                                 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
618                                 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
619                         }
620                         else
621                         {
622                                 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
623                                 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
624                         }
625                 }
626         }
627         else if (moveangle[1])
628         {
629                 for (i = 0;i < 3;i++)
630                 {
631                         if (move1[i] > 0)
632                         {
633                                 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
634                                 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
635                         }
636                         else
637                         {
638                                 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
639                                 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
640                         }
641                 }
642         }
643         else
644         {
645                 for (i = 0;i < 3;i++)
646                 {
647                         if (move1[i] > 0)
648                         {
649                                 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
650                                 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
651                         }
652                         else
653                         {
654                                 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
655                                 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
656                         }
657                 }
658         }
659
660         VectorNegate (moveangle, a);
661         AngleVectorsFLU (a, forward, left, up);
662
663         VectorCopy (pusher->v->origin, pushorig);
664         VectorCopy (pusher->v->angles, pushang);
665         pushltime = pusher->v->ltime;
666
667 // move the pusher to it's final position
668
669         VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
670         VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
671         pusher->v->ltime += movetime;
672         SV_LinkEdict (pusher, false);
673
674         savesolid = pusher->v->solid;
675
676 // see if any solid entities are inside the final position
677         num_moved = 0;
678
679         numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
680         for (e = 1;e < numcheckentities;e++)
681         {
682                 check = checkentities[e];
683                 if (check->v->movetype == MOVETYPE_PUSH
684                  || check->v->movetype == MOVETYPE_NONE
685                  || check->v->movetype == MOVETYPE_FOLLOW
686                  || check->v->movetype == MOVETYPE_NOCLIP
687                  || check->v->movetype == MOVETYPE_FAKEPUSH)
688                         continue;
689
690                 // if the entity is standing on the pusher, it will definitely be moved
691                 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
692                         if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
693                                 continue;
694
695                 if (forward[0] != 1) // quick way to check if any rotation is used
696                 {
697                         VectorSubtract (check->v->origin, pusher->v->origin, org);
698                         org2[0] = DotProduct (org, forward);
699                         org2[1] = DotProduct (org, left);
700                         org2[2] = DotProduct (org, up);
701                         VectorSubtract (org2, org, move);
702                         VectorAdd (move, move1, move);
703                 }
704                 else
705                         VectorCopy (move1, move);
706
707                 // remove the onground flag for non-players
708                 if (check->v->movetype != MOVETYPE_WALK)
709                         check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
710
711                 VectorCopy (check->v->origin, check->e->moved_from);
712                 VectorCopy (check->v->angles, check->e->moved_fromangles);
713                 sv.moved_edicts[num_moved++] = check;
714
715                 // try moving the contacted entity
716                 pusher->v->solid = SOLID_NOT;
717                 trace = SV_PushEntity (check, move);
718                 // FIXME: turn players specially
719                 check->v->angles[1] += trace.fraction * moveangle[1];
720                 pusher->v->solid = savesolid; // was SOLID_BSP
721
722                 // if it is still inside the pusher, block
723                 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
724                 {
725                         // try moving the contacted entity a tiny bit further to account for precision errors
726                         pusher->v->solid = SOLID_NOT;
727                         VectorScale(move, 0.1, move);
728                         SV_PushEntity (check, move);
729                         pusher->v->solid = savesolid;
730                         if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
731                         {
732                                 // still inside pusher, so it's really blocked
733
734                                 // fail the move
735                                 if (check->v->mins[0] == check->v->maxs[0])
736                                         continue;
737                                 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
738                                 {
739                                         // corpse
740                                         check->v->mins[0] = check->v->mins[1] = 0;
741                                         VectorCopy (check->v->mins, check->v->maxs);
742                                         continue;
743                                 }
744
745                                 VectorCopy (pushorig, pusher->v->origin);
746                                 VectorCopy (pushang, pusher->v->angles);
747                                 pusher->v->ltime = pushltime;
748                                 SV_LinkEdict (pusher, false);
749
750                                 // move back any entities we already moved
751                                 for (i = 0;i < num_moved;i++)
752                                 {
753                                         ed = sv.moved_edicts[i];
754                                         VectorCopy (ed->e->moved_from, ed->v->origin);
755                                         VectorCopy (ed->e->moved_fromangles, ed->v->angles);
756                                         SV_LinkEdict (ed, false);
757                                 }
758
759                                 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
760                                 if (pusher->v->blocked)
761                                 {
762                                         pr_global_struct->self = EDICT_TO_PROG(pusher);
763                                         pr_global_struct->other = EDICT_TO_PROG(check);
764                                         PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing");
765                                 }
766                                 break;
767                         }
768                 }
769         }
770         pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
771         pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
772         pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
773 }
774
775 /*
776 ================
777 SV_Physics_Pusher
778
779 ================
780 */
781 void SV_Physics_Pusher (edict_t *ent)
782 {
783         float thinktime, oldltime, movetime;
784
785         oldltime = ent->v->ltime;
786
787         thinktime = ent->v->nextthink;
788         if (thinktime < ent->v->ltime + sv.frametime)
789         {
790                 movetime = thinktime - ent->v->ltime;
791                 if (movetime < 0)
792                         movetime = 0;
793         }
794         else
795                 movetime = sv.frametime;
796
797         if (movetime)
798                 // advances ent->v->ltime if not blocked
799                 SV_PushMove (ent, movetime);
800
801         if (thinktime > oldltime && thinktime <= ent->v->ltime)
802         {
803                 ent->v->nextthink = 0;
804                 pr_global_struct->time = sv.time;
805                 pr_global_struct->self = EDICT_TO_PROG(ent);
806                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
807                 PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
808         }
809 }
810
811
812 /*
813 ===============================================================================
814
815 CLIENT MOVEMENT
816
817 ===============================================================================
818 */
819
820 /*
821 =============
822 SV_CheckStuck
823
824 This is a big hack to try and fix the rare case of getting stuck in the world
825 clipping hull.
826 =============
827 */
828 void SV_CheckStuck (edict_t *ent)
829 {
830         int i, j, z;
831         vec3_t org;
832
833         if (!SV_TestEntityPosition(ent))
834         {
835                 VectorCopy (ent->v->origin, ent->v->oldorigin);
836                 return;
837         }
838
839         VectorCopy (ent->v->origin, org);
840         VectorCopy (ent->v->oldorigin, ent->v->origin);
841         if (!SV_TestEntityPosition(ent))
842         {
843                 Con_DPrint("Unstuck.\n");
844                 SV_LinkEdict (ent, true);
845                 return;
846         }
847
848         for (z=0 ; z< 18 ; z++)
849                 for (i=-1 ; i <= 1 ; i++)
850                         for (j=-1 ; j <= 1 ; j++)
851                         {
852                                 ent->v->origin[0] = org[0] + i;
853                                 ent->v->origin[1] = org[1] + j;
854                                 ent->v->origin[2] = org[2] + z;
855                                 if (!SV_TestEntityPosition(ent))
856                                 {
857                                         Con_DPrint("Unstuck.\n");
858                                         SV_LinkEdict (ent, true);
859                                         return;
860                                 }
861                         }
862
863         VectorCopy (org, ent->v->origin);
864         Con_DPrint("player is stuck.\n");
865 }
866
867
868 /*
869 =============
870 SV_CheckWater
871 =============
872 */
873 qboolean SV_CheckWater (edict_t *ent)
874 {
875         int cont;
876         vec3_t point;
877
878         point[0] = ent->v->origin[0];
879         point[1] = ent->v->origin[1];
880         point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
881
882         ent->v->waterlevel = 0;
883         ent->v->watertype = CONTENTS_EMPTY;
884         cont = SV_PointQ1Contents(point);
885         if (cont <= CONTENTS_WATER)
886         {
887                 ent->v->watertype = cont;
888                 ent->v->waterlevel = 1;
889                 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
890                 cont = SV_PointQ1Contents(point);
891                 if (cont <= CONTENTS_WATER)
892                 {
893                         ent->v->waterlevel = 2;
894                         point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
895                         cont = SV_PointQ1Contents(point);
896                         if (cont <= CONTENTS_WATER)
897                                 ent->v->waterlevel = 3;
898                 }
899         }
900
901         return ent->v->waterlevel > 1;
902 }
903
904 /*
905 ============
906 SV_WallFriction
907
908 ============
909 */
910 void SV_WallFriction (edict_t *ent, float *stepnormal)
911 {
912         float d, i;
913         vec3_t forward, into, side;
914
915         AngleVectors (ent->v->v_angle, forward, NULL, NULL);
916         if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
917         {
918                 // cut the tangential velocity
919                 i = DotProduct (stepnormal, ent->v->velocity);
920                 VectorScale (stepnormal, i, into);
921                 VectorSubtract (ent->v->velocity, into, side);
922                 ent->v->velocity[0] = side[0] * (1 + d);
923                 ent->v->velocity[1] = side[1] * (1 + d);
924         }
925 }
926
927 /*
928 =====================
929 SV_TryUnstick
930
931 Player has come to a dead stop, possibly due to the problem with limited
932 float precision at some angle joins in the BSP hull.
933
934 Try fixing by pushing one pixel in each direction.
935
936 This is a hack, but in the interest of good gameplay...
937 ======================
938 */
939 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
940 {
941         int i, clip;
942         vec3_t oldorg, dir;
943
944         VectorCopy (ent->v->origin, oldorg);
945         VectorClear (dir);
946
947         for (i=0 ; i<8 ; i++)
948         {
949                 // try pushing a little in an axial direction
950                 switch (i)
951                 {
952                         case 0: dir[0] = 2; dir[1] = 0; break;
953                         case 1: dir[0] = 0; dir[1] = 2; break;
954                         case 2: dir[0] = -2; dir[1] = 0; break;
955                         case 3: dir[0] = 0; dir[1] = -2; break;
956                         case 4: dir[0] = 2; dir[1] = 2; break;
957                         case 5: dir[0] = -2; dir[1] = 2; break;
958                         case 6: dir[0] = 2; dir[1] = -2; break;
959                         case 7: dir[0] = -2; dir[1] = -2; break;
960                 }
961
962                 SV_PushEntity (ent, dir);
963
964                 // retry the original move
965                 ent->v->velocity[0] = oldvel[0];
966                 ent->v->velocity[1] = oldvel[1];
967                 ent->v->velocity[2] = 0;
968                 clip = SV_FlyMove (ent, 0.1, NULL);
969
970                 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
971                  || fabs(oldorg[0] - ent->v->origin[0]) > 4)
972                 {
973                         Con_DPrint("TryUnstick - success.\n");
974                         return clip;
975                 }
976
977                 // go back to the original pos and try again
978                 VectorCopy (oldorg, ent->v->origin);
979         }
980
981         // still not moving
982         VectorClear (ent->v->velocity);
983         Con_DPrint("TryUnstick - failure.\n");
984         return 7;
985 }
986
987 /*
988 =====================
989 SV_WalkMove
990
991 Only used by players
992 ======================
993 */
994 void SV_WalkMove (edict_t *ent)
995 {
996         int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
997         vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
998         trace_t downtrace;
999
1000         SV_CheckVelocity(ent);
1001
1002         // do a regular slide move unless it looks like you ran into a step
1003         oldonground = (int)ent->v->flags & FL_ONGROUND;
1004         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1005
1006         VectorCopy (ent->v->origin, start_origin);
1007         VectorCopy (ent->v->velocity, start_velocity);
1008
1009         clip = SV_FlyMove (ent, sv.frametime, NULL);
1010
1011         SV_SetOnGround (ent);
1012         SV_CheckVelocity(ent);
1013
1014         VectorCopy(ent->v->origin, originalmove_origin);
1015         VectorCopy(ent->v->velocity, originalmove_velocity);
1016         originalmove_clip = clip;
1017         originalmove_flags = (int)ent->v->flags;
1018         originalmove_groundentity = ent->v->groundentity;
1019
1020         if ((int)ent->v->flags & FL_WATERJUMP)
1021                 return;
1022
1023         if (sv_nostep.integer)
1024                 return;
1025         
1026         // if move didn't block on a step, return
1027         if (clip & 2)
1028         {
1029                 // if move was not trying to move into the step, return
1030                 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
1031                         return;
1032         
1033                 if (ent->v->movetype != MOVETYPE_FLY)
1034                 {
1035                         // return if gibbed by a trigger
1036                         if (ent->v->movetype != MOVETYPE_WALK)
1037                                 return;
1038         
1039                         // only step up while jumping if that is enabled
1040                         if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
1041                                 if (!oldonground && ent->v->waterlevel == 0)
1042                                         return;
1043                 }
1044         
1045                 // try moving up and forward to go up a step
1046                 // back to start pos
1047                 VectorCopy (start_origin, ent->v->origin);
1048                 VectorCopy (start_velocity, ent->v->velocity);
1049         
1050                 // move up
1051                 VectorClear (upmove);
1052                 upmove[2] = sv_stepheight.value;
1053                 // FIXME: don't link?
1054                 SV_PushEntity(ent, upmove);
1055         
1056                 // move forward
1057                 ent->v->velocity[2] = 0;
1058                 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1059                 ent->v->velocity[2] += start_velocity[2];
1060         
1061                 SV_CheckVelocity(ent);
1062         
1063                 // check for stuckness, possibly due to the limited precision of floats
1064                 // in the clipping hulls
1065                 if (clip
1066                  && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
1067                  && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
1068                 {
1069                         //Con_Printf("wall\n");
1070                         // stepping up didn't make any progress, revert to original move
1071                         VectorCopy(originalmove_origin, ent->v->origin);
1072                         VectorCopy(originalmove_velocity, ent->v->velocity);
1073                         //clip = originalmove_clip;
1074                         ent->v->flags = originalmove_flags;
1075                         ent->v->groundentity = originalmove_groundentity; 
1076                         // now try to unstick if needed
1077                         //clip = SV_TryUnstick (ent, oldvel);
1078                         return;
1079                 }
1080
1081                 //Con_Printf("step - ");
1082
1083                 // extra friction based on view angle
1084                 if (clip & 2 && sv_wallfriction.integer)
1085                         SV_WallFriction (ent, stepnormal);
1086         }
1087         // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
1088         else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
1089                 return;
1090
1091         // move down
1092         VectorClear (downmove);
1093         downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
1094         // FIXME: don't link?
1095         downtrace = SV_PushEntity (ent, downmove);
1096
1097         if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
1098         {
1099                 // LordHavoc: disabled this check so you can walk on monsters/players
1100                 //if (ent->v->solid == SOLID_BSP)
1101                 {
1102                         //Con_Printf("onground\n");
1103                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1104                         ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1105                 }
1106         }
1107         else
1108         {
1109                 //Con_Printf("slope\n");
1110                 // if the push down didn't end up on good ground, use the move without
1111                 // the step up.  This happens near wall / slope combinations, and can
1112                 // cause the player to hop up higher on a slope too steep to climb
1113                 VectorCopy(originalmove_origin, ent->v->origin);
1114                 VectorCopy(originalmove_velocity, ent->v->velocity);
1115                 //clip = originalmove_clip;
1116                 ent->v->flags = originalmove_flags;
1117                 ent->v->groundentity = originalmove_groundentity; 
1118         }
1119
1120         SV_SetOnGround (ent);
1121         SV_CheckVelocity(ent);
1122 }
1123
1124 //============================================================================
1125
1126 /*
1127 =============
1128 SV_Physics_Follow
1129
1130 Entities that are "stuck" to another entity
1131 =============
1132 */
1133 void SV_Physics_Follow (edict_t *ent)
1134 {
1135         vec3_t vf, vr, vu, angles, v;
1136         edict_t *e;
1137
1138         // regular thinking
1139         if (!SV_RunThink (ent))
1140                 return;
1141
1142         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1143         e = PROG_TO_EDICT(ent->v->aiment);
1144         if (e->v->angles[0] == ent->v->punchangle[0] && e->v->angles[1] == ent->v->punchangle[1] && e->v->angles[2] == ent->v->punchangle[2])
1145         {
1146                 // quick case for no rotation
1147                 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1148         }
1149         else
1150         {
1151                 angles[0] = -ent->v->punchangle[0];
1152                 angles[1] =  ent->v->punchangle[1];
1153                 angles[2] =  ent->v->punchangle[2];
1154                 AngleVectors (angles, vf, vr, vu);
1155                 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1156                 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1157                 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1158                 angles[0] = -e->v->angles[0];
1159                 angles[1] =  e->v->angles[1];
1160                 angles[2] =  e->v->angles[2];
1161                 AngleVectors (angles, vf, vr, vu);
1162                 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1163                 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1164                 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1165         }
1166         VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1167         SV_LinkEdict (ent, true);
1168 }
1169
1170 /*
1171 ==============================================================================
1172
1173 TOSS / BOUNCE
1174
1175 ==============================================================================
1176 */
1177
1178 /*
1179 =============
1180 SV_CheckWaterTransition
1181
1182 =============
1183 */
1184 void SV_CheckWaterTransition (edict_t *ent)
1185 {
1186         int cont;
1187         cont = SV_PointQ1Contents(ent->v->origin);
1188         if (!ent->v->watertype)
1189         {
1190                 // just spawned here
1191                 ent->v->watertype = cont;
1192                 ent->v->waterlevel = 1;
1193                 return;
1194         }
1195
1196         // check if the entity crossed into or out of water
1197         if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1198                 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1199
1200         if (cont <= CONTENTS_WATER)
1201         {
1202                 ent->v->watertype = cont;
1203                 ent->v->waterlevel = 1;
1204         }
1205         else
1206         {
1207                 ent->v->watertype = CONTENTS_EMPTY;
1208                 ent->v->waterlevel = 0;
1209         }
1210 }
1211
1212 /*
1213 =============
1214 SV_Physics_Toss
1215
1216 Toss, bounce, and fly movement.  When onground, do nothing.
1217 =============
1218 */
1219 void SV_Physics_Toss (edict_t *ent)
1220 {
1221         trace_t trace;
1222         vec3_t move;
1223         edict_t *groundentity;
1224
1225         // regular thinking
1226         if (!SV_RunThink (ent))
1227                 return;
1228
1229         // don't stick to ground if onground and moving upward
1230         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1231                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1232
1233 // if onground, return without moving
1234         if ((int)ent->v->flags & FL_ONGROUND)
1235         {
1236                 if (!sv_gameplayfix_noairborncorpse.integer)
1237                         return;
1238                 if (ent->v->groundentity == 0)
1239                         return;
1240                 // if ent was supported by a brush model on previous frame,
1241                 // and groundentity is now freed, set groundentity to 0 (floating)
1242                 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1243                 if (groundentity->v->solid == SOLID_BSP)
1244                 {
1245                         ent->e->suspendedinairflag = true;
1246                         return;
1247                 }
1248                 else if (ent->e->suspendedinairflag && groundentity->e->free)
1249                 {
1250                         // leave it suspended in the air
1251                         ent->v->groundentity = 0;
1252                         ent->e->suspendedinairflag = false;
1253                         return;
1254                 }
1255         }
1256         ent->e->suspendedinairflag = false;
1257
1258         SV_CheckVelocity (ent);
1259
1260 // add gravity
1261         if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1262                 SV_AddGravity (ent);
1263
1264 // move angles
1265         VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1266
1267 // move origin
1268         VectorScale (ent->v->velocity, sv.frametime, move);
1269         trace = SV_PushEntity (ent, move);
1270         if (ent->e->free)
1271                 return;
1272
1273         if (trace.fraction < 1)
1274         {
1275                 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1276                 {
1277                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1278                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1279                 }
1280                 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1281                 {
1282                         float d;
1283                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1284                         // LordHavoc: fixed grenades not bouncing when fired down a slope
1285                         if (sv_gameplayfix_grenadebouncedownslopes.integer)
1286                         {
1287                                 d = DotProduct(trace.plane.normal, ent->v->velocity);
1288                                 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1289                                 {
1290                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1291                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1292                                         VectorClear (ent->v->velocity);
1293                                         VectorClear (ent->v->avelocity);
1294                                 }
1295                                 else
1296                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1297                         }
1298                         else
1299                         {
1300                                 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
1301                                 {
1302                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1303                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1304                                         VectorClear (ent->v->velocity);
1305                                         VectorClear (ent->v->avelocity);
1306                                 }
1307                                 else
1308                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1309                         }
1310                 }
1311                 else
1312                 {
1313                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1314                         if (trace.plane.normal[2] > 0.7)
1315                         {
1316                                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1317                                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1318                                 VectorClear (ent->v->velocity);
1319                                 VectorClear (ent->v->avelocity);
1320                         }
1321                         else
1322                                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1323                 }
1324         }
1325
1326 // check for in water
1327         SV_CheckWaterTransition (ent);
1328 }
1329
1330 /*
1331 ===============================================================================
1332
1333 STEPPING MOVEMENT
1334
1335 ===============================================================================
1336 */
1337
1338 /*
1339 =============
1340 SV_Physics_Step
1341
1342 Monsters freefall when they don't have a ground entity, otherwise
1343 all movement is done with discrete steps.
1344
1345 This is also used for objects that have become still on the ground, but
1346 will fall if the floor is pulled out from under them.
1347 =============
1348 */
1349 void SV_Physics_Step (edict_t *ent)
1350 {
1351         // don't stick to ground if onground and moving upward
1352         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1353                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1354
1355         // freefall if not onground/fly/swim
1356         if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1357         {
1358                 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1359
1360                 SV_AddGravity(ent);
1361                 SV_CheckVelocity(ent);
1362                 SV_FlyMove(ent, sv.frametime, NULL);
1363                 SV_LinkEdict(ent, true);
1364
1365                 // just hit ground
1366                 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1367                         SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1368         }
1369
1370 // regular thinking
1371         SV_RunThink(ent);
1372
1373         SV_CheckWaterTransition(ent);
1374 }
1375
1376 //============================================================================
1377
1378 /*
1379 ================
1380 SV_Physics
1381
1382 ================
1383 */
1384 void SV_Physics (void)
1385 {
1386         int i;
1387         edict_t *ent;
1388
1389 // let the progs know that a new frame has started
1390         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1391         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1392         pr_global_struct->time = sv.time;
1393         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1394
1395 //
1396 // treat each object in turn
1397 //
1398         ent = sv.edicts;
1399         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1400         {
1401                 if (ent->e->free)
1402                         continue;
1403
1404                 if (pr_global_struct->force_retouch)
1405                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1406
1407                 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1408                 {
1409                         // connected slot
1410                         // call standard client pre-think
1411                         SV_CheckVelocity (ent);
1412                         pr_global_struct->time = sv.time;
1413                         pr_global_struct->self = EDICT_TO_PROG(ent);
1414                         PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1415                         SV_CheckVelocity (ent);
1416                 }
1417                 else if (sv_freezenonclients.integer)
1418                         continue;
1419
1420                 // LordHavoc: merged client and normal entity physics
1421                 switch ((int) ent->v->movetype)
1422                 {
1423                 case MOVETYPE_PUSH:
1424                 case MOVETYPE_FAKEPUSH:
1425                         SV_Physics_Pusher (ent);
1426                         break;
1427                 case MOVETYPE_NONE:
1428                         // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1429                         if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1430                                 SV_RunThink (ent);
1431                         break;
1432                 case MOVETYPE_FOLLOW:
1433                         SV_Physics_Follow (ent);
1434                         break;
1435                 case MOVETYPE_NOCLIP:
1436                         if (SV_RunThink(ent))
1437                         {
1438                                 SV_CheckWater(ent);
1439                                 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1440                                 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1441                         }
1442                         // relink normal entities here, players always get relinked so don't relink twice
1443                         if (!(i > 0 && i <= svs.maxclients))
1444                                 SV_LinkEdict(ent, false);
1445                         break;
1446                 case MOVETYPE_STEP:
1447                         SV_Physics_Step (ent);
1448                         break;
1449                 case MOVETYPE_WALK:
1450                         if (SV_RunThink (ent))
1451                         {
1452                                 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1453                                         SV_AddGravity (ent);
1454                                 SV_CheckStuck (ent);
1455                                 SV_WalkMove (ent);
1456                                 // relink normal entities here, players always get relinked so don't relink twice
1457                                 if (!(i > 0 && i <= svs.maxclients))
1458                                         SV_LinkEdict (ent, true);
1459                         }
1460                         break;
1461                 case MOVETYPE_TOSS:
1462                 case MOVETYPE_BOUNCE:
1463                 case MOVETYPE_BOUNCEMISSILE:
1464                 case MOVETYPE_FLYMISSILE:
1465                         SV_Physics_Toss (ent);
1466                         break;
1467                 case MOVETYPE_FLY:
1468                         if (i > 0 && i <= svs.maxclients)
1469                         {
1470                                 if (SV_RunThink (ent))
1471                                 {
1472                                         SV_CheckWater (ent);
1473                                         SV_WalkMove (ent);
1474                                 }
1475                         }
1476                         else
1477                                 SV_Physics_Toss (ent);
1478                         break;
1479                 default:
1480                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1481                         break;
1482                 }
1483
1484                 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1485                 {
1486                         SV_CheckVelocity (ent);
1487
1488                         // call standard player post-think
1489                         SV_LinkEdict (ent, true);
1490
1491                         SV_CheckVelocity (ent);
1492
1493                         pr_global_struct->time = sv.time;
1494                         pr_global_struct->self = EDICT_TO_PROG(ent);
1495                         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1496                 }
1497         }
1498
1499         if (pr_global_struct->force_retouch > 0)
1500                 pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);
1501
1502         // LordHavoc: endframe support
1503         if (EndFrameQC)
1504         {
1505                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1506                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1507                 pr_global_struct->time = sv.time;
1508                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1509         }
1510
1511         if (!sv_freezenonclients.integer)
1512                 sv.time += sv.frametime;
1513 }
1514
1515
1516 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1517 {
1518         int i;
1519         float gravity, savesolid;
1520         vec3_t move, end;
1521         edict_t tempent, *tent;
1522         entvars_t vars;
1523         eval_t *val;
1524         trace_t trace;
1525
1526         // copy the vars over
1527         memcpy(&vars, tossent->v, sizeof(entvars_t));
1528         // set up the temp entity to point to the copied vars
1529         tent = &tempent;
1530         tent->v = &vars;
1531
1532         savesolid = tossent->v->solid;
1533         tossent->v->solid = SOLID_NOT;
1534
1535         // this has to fetch the field from the original edict, since our copy is truncated
1536         val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1537         if (val != NULL && val->_float != 0)
1538                 gravity = val->_float;
1539         else
1540                 gravity = 1.0;
1541         gravity *= sv_gravity.value * 0.05;
1542
1543         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1544         {
1545                 SV_CheckVelocity (tent);
1546                 tent->v->velocity[2] -= gravity;
1547                 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1548                 VectorScale (tent->v->velocity, 0.05, move);
1549                 VectorAdd (tent->v->origin, move, end);
1550                 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1551                 VectorCopy (trace.endpos, tent->v->origin);
1552
1553                 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1554                         break;
1555         }
1556         tossent->v->solid = savesolid;
1557         trace.fraction = 0; // not relevant
1558         return trace;
1559 }
1560