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