]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_phys.c
removed the commented out RecursiveHullCheckPoint function
[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         // don't stick to ground if onground and moving upward
1226         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1227                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1228
1229 // if onground, return without moving
1230         if ((int)ent->v->flags & FL_ONGROUND)
1231         {
1232                 if (!sv_gameplayfix_noairborncorpse.integer)
1233                         return;
1234                 if (ent->v->groundentity == 0)
1235                         return;
1236                 // if ent was supported by a brush model on previous frame,
1237                 // and groundentity is now freed, set groundentity to 0 (floating)
1238                 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1239                 if (groundentity->v->solid == SOLID_BSP)
1240                 {
1241                         ent->e->suspendedinairflag = true;
1242                         return;
1243                 }
1244                 else if (ent->e->suspendedinairflag && groundentity->e->free)
1245                 {
1246                         // leave it suspended in the air
1247                         ent->v->groundentity = 0;
1248                         ent->e->suspendedinairflag = false;
1249                         return;
1250                 }
1251         }
1252         ent->e->suspendedinairflag = false;
1253
1254         SV_CheckVelocity (ent);
1255
1256 // add gravity
1257         if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1258                 SV_AddGravity (ent);
1259
1260 // move angles
1261         VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1262
1263 // move origin
1264         VectorScale (ent->v->velocity, sv.frametime, move);
1265         trace = SV_PushEntity (ent, move);
1266         if (ent->e->free)
1267                 return;
1268
1269         if (trace.fraction < 1)
1270         {
1271                 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1272                 {
1273                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1274                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1275                 }
1276                 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1277                 {
1278                         float d;
1279                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1280                         // LordHavoc: fixed grenades not bouncing when fired down a slope
1281                         if (sv_gameplayfix_grenadebouncedownslopes.integer)
1282                         {
1283                                 d = DotProduct(trace.plane.normal, ent->v->velocity);
1284                                 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1285                                 {
1286                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1287                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1288                                         VectorClear (ent->v->velocity);
1289                                         VectorClear (ent->v->avelocity);
1290                                 }
1291                                 else
1292                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1293                         }
1294                         else
1295                         {
1296                                 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
1297                                 {
1298                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1299                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1300                                         VectorClear (ent->v->velocity);
1301                                         VectorClear (ent->v->avelocity);
1302                                 }
1303                                 else
1304                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1305                         }
1306                 }
1307                 else
1308                 {
1309                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1310                         if (trace.plane.normal[2] > 0.7)
1311                         {
1312                                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1313                                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1314                                 VectorClear (ent->v->velocity);
1315                                 VectorClear (ent->v->avelocity);
1316                         }
1317                         else
1318                                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1319                 }
1320         }
1321
1322 // check for in water
1323         SV_CheckWaterTransition (ent);
1324 }
1325
1326 /*
1327 ===============================================================================
1328
1329 STEPPING MOVEMENT
1330
1331 ===============================================================================
1332 */
1333
1334 /*
1335 =============
1336 SV_Physics_Step
1337
1338 Monsters freefall when they don't have a ground entity, otherwise
1339 all movement is done with discrete steps.
1340
1341 This is also used for objects that have become still on the ground, but
1342 will fall if the floor is pulled out from under them.
1343 =============
1344 */
1345 void SV_Physics_Step (edict_t *ent)
1346 {
1347         // don't stick to ground if onground and moving upward
1348         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1349                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1350
1351         // freefall if not onground/fly/swim
1352         if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1353         {
1354                 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1355
1356                 SV_AddGravity(ent);
1357                 SV_CheckVelocity(ent);
1358                 SV_FlyMove(ent, sv.frametime, NULL);
1359                 SV_LinkEdict(ent, true);
1360
1361                 // just hit ground
1362                 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1363                         SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1364         }
1365
1366 // regular thinking
1367         SV_RunThink(ent);
1368
1369         SV_CheckWaterTransition(ent);
1370 }
1371
1372 //============================================================================
1373
1374 /*
1375 ================
1376 SV_Physics
1377
1378 ================
1379 */
1380 void SV_Physics (void)
1381 {
1382         int i, newnum_edicts;
1383         edict_t *ent;
1384         qbyte runmove[MAX_EDICTS];
1385
1386 // let the progs know that a new frame has started
1387         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1388         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1389         pr_global_struct->time = sv.time;
1390         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1391
1392         newnum_edicts = 0;
1393         for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1394                 if ((runmove[i] = !ent->e->free))
1395                         newnum_edicts = i + 1;
1396         sv.num_edicts = max(svs.maxclients + 1, newnum_edicts);
1397
1398 //
1399 // treat each object in turn
1400 //
1401
1402         for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1403         {
1404                 if (ent->e->free)
1405                         continue;
1406
1407                 if (pr_global_struct->force_retouch)
1408                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1409
1410                 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1411                 {
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                 else if (sv_freezenonclients.integer)
1421                         continue;
1422
1423                 // LordHavoc: merged client and normal entity physics
1424                 switch ((int) ent->v->movetype)
1425                 {
1426                 case MOVETYPE_PUSH:
1427                 case MOVETYPE_FAKEPUSH:
1428                         SV_Physics_Pusher (ent);
1429                         break;
1430                 case MOVETYPE_NONE:
1431                         // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1432                         if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1433                                 SV_RunThink (ent);
1434                         break;
1435                 case MOVETYPE_FOLLOW:
1436                         SV_Physics_Follow (ent);
1437                         break;
1438                 case MOVETYPE_NOCLIP:
1439                         if (SV_RunThink(ent))
1440                         {
1441                                 SV_CheckWater(ent);
1442                                 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1443                                 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1444                         }
1445                         // relink normal entities here, players always get relinked so don't relink twice
1446                         if (!(i > 0 && i <= svs.maxclients))
1447                                 SV_LinkEdict(ent, false);
1448                         break;
1449                 case MOVETYPE_STEP:
1450                         SV_Physics_Step (ent);
1451                         break;
1452                 case MOVETYPE_WALK:
1453                         if (SV_RunThink (ent))
1454                         {
1455                                 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1456                                         SV_AddGravity (ent);
1457                                 SV_CheckStuck (ent);
1458                                 SV_WalkMove (ent);
1459                                 // relink normal entities here, players always get relinked so don't relink twice
1460                                 if (!(i > 0 && i <= svs.maxclients))
1461                                         SV_LinkEdict (ent, true);
1462                         }
1463                         break;
1464                 case MOVETYPE_TOSS:
1465                 case MOVETYPE_BOUNCE:
1466                 case MOVETYPE_BOUNCEMISSILE:
1467                 case MOVETYPE_FLYMISSILE:
1468                         // regular thinking
1469                         if (SV_RunThink (ent) && runmove[i])
1470                                 SV_Physics_Toss (ent);
1471                         break;
1472                 case MOVETYPE_FLY:
1473                         if (SV_RunThink (ent) && runmove[i])
1474                         {
1475                                 if (i > 0 && i <= svs.maxclients)
1476                                 {
1477                                         SV_CheckWater (ent);
1478                                         SV_WalkMove (ent);
1479                                 }
1480                                 else
1481                                         SV_Physics_Toss (ent);
1482                         }
1483                         break;
1484                 default:
1485                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1486                         break;
1487                 }
1488
1489                 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1490                 {
1491                         SV_CheckVelocity (ent);
1492
1493                         // call standard player post-think
1494                         SV_LinkEdict (ent, true);
1495
1496                         SV_CheckVelocity (ent);
1497
1498                         pr_global_struct->time = sv.time;
1499                         pr_global_struct->self = EDICT_TO_PROG(ent);
1500                         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1501                 }
1502         }
1503
1504         if (pr_global_struct->force_retouch > 0)
1505                 pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);
1506
1507         // LordHavoc: endframe support
1508         if (EndFrameQC)
1509         {
1510                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1511                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1512                 pr_global_struct->time = sv.time;
1513                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1514         }
1515
1516         if (!sv_freezenonclients.integer)
1517                 sv.time += sv.frametime;
1518 }
1519
1520
1521 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1522 {
1523         int i;
1524         float gravity, savesolid;
1525         vec3_t move, end;
1526         edict_t tempent, *tent;
1527         entvars_t vars;
1528         eval_t *val;
1529         trace_t trace;
1530
1531         // copy the vars over
1532         memcpy(&vars, tossent->v, sizeof(entvars_t));
1533         // set up the temp entity to point to the copied vars
1534         tent = &tempent;
1535         tent->v = &vars;
1536
1537         savesolid = tossent->v->solid;
1538         tossent->v->solid = SOLID_NOT;
1539
1540         // this has to fetch the field from the original edict, since our copy is truncated
1541         val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1542         if (val != NULL && val->_float != 0)
1543                 gravity = val->_float;
1544         else
1545                 gravity = 1.0;
1546         gravity *= sv_gravity.value * 0.05;
1547
1548         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1549         {
1550                 SV_CheckVelocity (tent);
1551                 tent->v->velocity[2] -= gravity;
1552                 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1553                 VectorScale (tent->v->velocity, 0.05, move);
1554                 VectorAdd (tent->v->origin, move, end);
1555                 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1556                 VectorCopy (trace.endpos, tent->v->origin);
1557
1558                 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1559                         break;
1560         }
1561         tossent->v->solid = savesolid;
1562         trace.fraction = 0; // not relevant
1563         return trace;
1564 }
1565