]> icculus.org git repositories - divverent/darkplaces.git/blob - sv_phys.c
moved r_shadow_ white and normal cubemaps to r_texture_
[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 = 0;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 || left[1] != 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_PointSuperContents(point);
885         if (cont & (SUPERCONTENTS_LIQUIDSMASK))
886         {
887                 ent->v->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
888                 ent->v->waterlevel = 1;
889                 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
890                 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
891                 {
892                         ent->v->waterlevel = 2;
893                         point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
894                         if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
895                                 ent->v->waterlevel = 3;
896                 }
897         }
898
899         return ent->v->waterlevel > 1;
900 }
901
902 /*
903 ============
904 SV_WallFriction
905
906 ============
907 */
908 void SV_WallFriction (edict_t *ent, float *stepnormal)
909 {
910         float d, i;
911         vec3_t forward, into, side;
912
913         AngleVectors (ent->v->v_angle, forward, NULL, NULL);
914         if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
915         {
916                 // cut the tangential velocity
917                 i = DotProduct (stepnormal, ent->v->velocity);
918                 VectorScale (stepnormal, i, into);
919                 VectorSubtract (ent->v->velocity, into, side);
920                 ent->v->velocity[0] = side[0] * (1 + d);
921                 ent->v->velocity[1] = side[1] * (1 + d);
922         }
923 }
924
925 /*
926 =====================
927 SV_TryUnstick
928
929 Player has come to a dead stop, possibly due to the problem with limited
930 float precision at some angle joins in the BSP hull.
931
932 Try fixing by pushing one pixel in each direction.
933
934 This is a hack, but in the interest of good gameplay...
935 ======================
936 */
937 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
938 {
939         int i, clip;
940         vec3_t oldorg, dir;
941
942         VectorCopy (ent->v->origin, oldorg);
943         VectorClear (dir);
944
945         for (i=0 ; i<8 ; i++)
946         {
947                 // try pushing a little in an axial direction
948                 switch (i)
949                 {
950                         case 0: dir[0] = 2; dir[1] = 0; break;
951                         case 1: dir[0] = 0; dir[1] = 2; break;
952                         case 2: dir[0] = -2; dir[1] = 0; break;
953                         case 3: dir[0] = 0; dir[1] = -2; break;
954                         case 4: dir[0] = 2; dir[1] = 2; break;
955                         case 5: dir[0] = -2; dir[1] = 2; break;
956                         case 6: dir[0] = 2; dir[1] = -2; break;
957                         case 7: dir[0] = -2; dir[1] = -2; break;
958                 }
959
960                 SV_PushEntity (ent, dir);
961
962                 // retry the original move
963                 ent->v->velocity[0] = oldvel[0];
964                 ent->v->velocity[1] = oldvel[1];
965                 ent->v->velocity[2] = 0;
966                 clip = SV_FlyMove (ent, 0.1, NULL);
967
968                 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
969                  || fabs(oldorg[0] - ent->v->origin[0]) > 4)
970                 {
971                         Con_DPrint("TryUnstick - success.\n");
972                         return clip;
973                 }
974
975                 // go back to the original pos and try again
976                 VectorCopy (oldorg, ent->v->origin);
977         }
978
979         // still not moving
980         VectorClear (ent->v->velocity);
981         Con_DPrint("TryUnstick - failure.\n");
982         return 7;
983 }
984
985 /*
986 =====================
987 SV_WalkMove
988
989 Only used by players
990 ======================
991 */
992 void SV_WalkMove (edict_t *ent)
993 {
994         int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
995         vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
996         trace_t downtrace;
997
998         SV_CheckVelocity(ent);
999
1000         // do a regular slide move unless it looks like you ran into a step
1001         oldonground = (int)ent->v->flags & FL_ONGROUND;
1002         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1003
1004         VectorCopy (ent->v->origin, start_origin);
1005         VectorCopy (ent->v->velocity, start_velocity);
1006
1007         clip = SV_FlyMove (ent, sv.frametime, NULL);
1008
1009         SV_SetOnGround (ent);
1010         SV_CheckVelocity(ent);
1011
1012         VectorCopy(ent->v->origin, originalmove_origin);
1013         VectorCopy(ent->v->velocity, originalmove_velocity);
1014         originalmove_clip = clip;
1015         originalmove_flags = (int)ent->v->flags;
1016         originalmove_groundentity = ent->v->groundentity;
1017
1018         if ((int)ent->v->flags & FL_WATERJUMP)
1019                 return;
1020
1021         if (sv_nostep.integer)
1022                 return;
1023
1024         // if move didn't block on a step, return
1025         if (clip & 2)
1026         {
1027                 // if move was not trying to move into the step, return
1028                 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
1029                         return;
1030
1031                 if (ent->v->movetype != MOVETYPE_FLY)
1032                 {
1033                         // return if gibbed by a trigger
1034                         if (ent->v->movetype != MOVETYPE_WALK)
1035                                 return;
1036
1037                         // only step up while jumping if that is enabled
1038                         if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
1039                                 if (!oldonground && ent->v->waterlevel == 0)
1040                                         return;
1041                 }
1042
1043                 // try moving up and forward to go up a step
1044                 // back to start pos
1045                 VectorCopy (start_origin, ent->v->origin);
1046                 VectorCopy (start_velocity, ent->v->velocity);
1047
1048                 // move up
1049                 VectorClear (upmove);
1050                 upmove[2] = sv_stepheight.value;
1051                 // FIXME: don't link?
1052                 SV_PushEntity(ent, upmove);
1053
1054                 // move forward
1055                 ent->v->velocity[2] = 0;
1056                 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1057                 ent->v->velocity[2] += start_velocity[2];
1058
1059                 SV_CheckVelocity(ent);
1060
1061                 // check for stuckness, possibly due to the limited precision of floats
1062                 // in the clipping hulls
1063                 if (clip
1064                  && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
1065                  && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
1066                 {
1067                         //Con_Printf("wall\n");
1068                         // stepping up didn't make any progress, revert to original move
1069                         VectorCopy(originalmove_origin, ent->v->origin);
1070                         VectorCopy(originalmove_velocity, ent->v->velocity);
1071                         //clip = originalmove_clip;
1072                         ent->v->flags = originalmove_flags;
1073                         ent->v->groundentity = originalmove_groundentity;
1074                         // now try to unstick if needed
1075                         //clip = SV_TryUnstick (ent, oldvel);
1076                         return;
1077                 }
1078
1079                 //Con_Printf("step - ");
1080
1081                 // extra friction based on view angle
1082                 if (clip & 2 && sv_wallfriction.integer)
1083                         SV_WallFriction (ent, stepnormal);
1084         }
1085         // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
1086         else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
1087                 return;
1088
1089         // move down
1090         VectorClear (downmove);
1091         downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
1092         // FIXME: don't link?
1093         downtrace = SV_PushEntity (ent, downmove);
1094
1095         if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
1096         {
1097                 // LordHavoc: disabled this check so you can walk on monsters/players
1098                 //if (ent->v->solid == SOLID_BSP)
1099                 {
1100                         //Con_Printf("onground\n");
1101                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1102                         ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1103                 }
1104         }
1105         else
1106         {
1107                 //Con_Printf("slope\n");
1108                 // if the push down didn't end up on good ground, use the move without
1109                 // the step up.  This happens near wall / slope combinations, and can
1110                 // cause the player to hop up higher on a slope too steep to climb
1111                 VectorCopy(originalmove_origin, ent->v->origin);
1112                 VectorCopy(originalmove_velocity, ent->v->velocity);
1113                 //clip = originalmove_clip;
1114                 ent->v->flags = originalmove_flags;
1115                 ent->v->groundentity = originalmove_groundentity;
1116         }
1117
1118         SV_SetOnGround (ent);
1119         SV_CheckVelocity(ent);
1120 }
1121
1122 //============================================================================
1123
1124 /*
1125 =============
1126 SV_Physics_Follow
1127
1128 Entities that are "stuck" to another entity
1129 =============
1130 */
1131 void SV_Physics_Follow (edict_t *ent)
1132 {
1133         vec3_t vf, vr, vu, angles, v;
1134         edict_t *e;
1135
1136         // regular thinking
1137         if (!SV_RunThink (ent))
1138                 return;
1139
1140         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1141         e = PROG_TO_EDICT(ent->v->aiment);
1142         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])
1143         {
1144                 // quick case for no rotation
1145                 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1146         }
1147         else
1148         {
1149                 angles[0] = -ent->v->punchangle[0];
1150                 angles[1] =  ent->v->punchangle[1];
1151                 angles[2] =  ent->v->punchangle[2];
1152                 AngleVectors (angles, vf, vr, vu);
1153                 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1154                 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1155                 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1156                 angles[0] = -e->v->angles[0];
1157                 angles[1] =  e->v->angles[1];
1158                 angles[2] =  e->v->angles[2];
1159                 AngleVectors (angles, vf, vr, vu);
1160                 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1161                 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1162                 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1163         }
1164         VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1165         SV_LinkEdict (ent, true);
1166 }
1167
1168 /*
1169 ==============================================================================
1170
1171 TOSS / BOUNCE
1172
1173 ==============================================================================
1174 */
1175
1176 /*
1177 =============
1178 SV_CheckWaterTransition
1179
1180 =============
1181 */
1182 void SV_CheckWaterTransition (edict_t *ent)
1183 {
1184         int cont;
1185         cont = SV_PointQ1Contents(ent->v->origin);
1186         if (!ent->v->watertype)
1187         {
1188                 // just spawned here
1189                 ent->v->watertype = cont;
1190                 ent->v->waterlevel = 1;
1191                 return;
1192         }
1193
1194         // check if the entity crossed into or out of water
1195         if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1196                 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1197
1198         if (cont <= CONTENTS_WATER)
1199         {
1200                 ent->v->watertype = cont;
1201                 ent->v->waterlevel = 1;
1202         }
1203         else
1204         {
1205                 ent->v->watertype = CONTENTS_EMPTY;
1206                 ent->v->waterlevel = 0;
1207         }
1208 }
1209
1210 /*
1211 =============
1212 SV_Physics_Toss
1213
1214 Toss, bounce, and fly movement.  When onground, do nothing.
1215 =============
1216 */
1217 void SV_Physics_Toss (edict_t *ent)
1218 {
1219         trace_t trace;
1220         vec3_t move;
1221         edict_t *groundentity;
1222
1223         // don't stick to ground if onground and moving upward
1224         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1225                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1226
1227 // if onground, return without moving
1228         if ((int)ent->v->flags & FL_ONGROUND)
1229         {
1230                 if (!sv_gameplayfix_noairborncorpse.integer)
1231                         return;
1232                 if (ent->v->groundentity == 0)
1233                         return;
1234                 // if ent was supported by a brush model on previous frame,
1235                 // and groundentity is now freed, set groundentity to 0 (floating)
1236                 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1237                 if (groundentity->v->solid == SOLID_BSP)
1238                 {
1239                         ent->e->suspendedinairflag = true;
1240                         return;
1241                 }
1242                 else if (ent->e->suspendedinairflag && groundentity->e->free)
1243                 {
1244                         // leave it suspended in the air
1245                         ent->v->groundentity = 0;
1246                         ent->e->suspendedinairflag = false;
1247                         return;
1248                 }
1249         }
1250         ent->e->suspendedinairflag = false;
1251
1252         SV_CheckVelocity (ent);
1253
1254 // add gravity
1255         if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1256                 SV_AddGravity (ent);
1257
1258 // move angles
1259         VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1260
1261 // move origin
1262         VectorScale (ent->v->velocity, sv.frametime, move);
1263         trace = SV_PushEntity (ent, move);
1264         if (ent->e->free)
1265                 return;
1266
1267         if (trace.fraction < 1)
1268         {
1269                 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1270                 {
1271                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1272                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1273                 }
1274                 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1275                 {
1276                         float d;
1277                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1278                         // LordHavoc: fixed grenades not bouncing when fired down a slope
1279                         if (sv_gameplayfix_grenadebouncedownslopes.integer)
1280                         {
1281                                 d = DotProduct(trace.plane.normal, ent->v->velocity);
1282                                 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1283                                 {
1284                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1285                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1286                                         VectorClear (ent->v->velocity);
1287                                         VectorClear (ent->v->avelocity);
1288                                 }
1289                                 else
1290                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1291                         }
1292                         else
1293                         {
1294                                 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
1295                                 {
1296                                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1297                                         ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1298                                         VectorClear (ent->v->velocity);
1299                                         VectorClear (ent->v->avelocity);
1300                                 }
1301                                 else
1302                                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1303                         }
1304                 }
1305                 else
1306                 {
1307                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1308                         if (trace.plane.normal[2] > 0.7)
1309                         {
1310                                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1311                                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1312                                 VectorClear (ent->v->velocity);
1313                                 VectorClear (ent->v->avelocity);
1314                         }
1315                         else
1316                                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1317                 }
1318         }
1319
1320 // check for in water
1321         SV_CheckWaterTransition (ent);
1322 }
1323
1324 /*
1325 ===============================================================================
1326
1327 STEPPING MOVEMENT
1328
1329 ===============================================================================
1330 */
1331
1332 /*
1333 =============
1334 SV_Physics_Step
1335
1336 Monsters freefall when they don't have a ground entity, otherwise
1337 all movement is done with discrete steps.
1338
1339 This is also used for objects that have become still on the ground, but
1340 will fall if the floor is pulled out from under them.
1341 =============
1342 */
1343 void SV_Physics_Step (edict_t *ent)
1344 {
1345         // don't stick to ground if onground and moving upward
1346         if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1347                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1348
1349         // freefall if not onground/fly/swim
1350         if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1351         {
1352                 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1353
1354                 SV_AddGravity(ent);
1355                 SV_CheckVelocity(ent);
1356                 SV_FlyMove(ent, sv.frametime, NULL);
1357                 SV_LinkEdict(ent, true);
1358
1359                 // just hit ground
1360                 if (hitsound && (int)ent->v->flags & FL_ONGROUND && gamemode != GAME_NEXUIZ)
1361                         SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1362         }
1363
1364 // regular thinking
1365         SV_RunThink(ent);
1366
1367         SV_CheckWaterTransition(ent);
1368 }
1369
1370 //============================================================================
1371
1372 /*
1373 ================
1374 SV_Physics
1375
1376 ================
1377 */
1378 void SV_Physics (void)
1379 {
1380         int i, newnum_edicts;
1381         edict_t *ent;
1382         qbyte runmove[MAX_EDICTS];
1383
1384 // let the progs know that a new frame has started
1385         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1386         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1387         pr_global_struct->time = sv.time;
1388         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1389
1390         newnum_edicts = 0;
1391         for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1392                 if ((runmove[i] = !ent->e->free))
1393                         newnum_edicts = i + 1;
1394         sv.num_edicts = max(svs.maxclients + 1, newnum_edicts);
1395
1396 //
1397 // treat each object in turn
1398 //
1399
1400         for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1401         {
1402                 if (ent->e->free)
1403                         continue;
1404
1405                 if (pr_global_struct->force_retouch)
1406                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1407
1408                 if (i >= 1 && i <= svs.maxclients)
1409                 {
1410                         // don't do physics on disconnected clients, FrikBot relies on this
1411                         if (!svs.clients[i-1].spawned)
1412                                 continue;
1413                         // connected slot
1414                         // call standard client pre-think
1415                         SV_CheckVelocity (ent);
1416                         pr_global_struct->time = sv.time;
1417                         pr_global_struct->self = EDICT_TO_PROG(ent);
1418                         PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1419                         SV_CheckVelocity (ent);
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                         // regular thinking
1470                         if (SV_RunThink (ent) && runmove[i])
1471                                 SV_Physics_Toss (ent);
1472                         break;
1473                 case MOVETYPE_FLY:
1474                         if (SV_RunThink (ent) && runmove[i])
1475                         {
1476                                 if (i > 0 && i <= svs.maxclients)
1477                                 {
1478                                         SV_CheckWater (ent);
1479                                         SV_WalkMove (ent);
1480                                 }
1481                                 else
1482                                         SV_Physics_Toss (ent);
1483                         }
1484                         break;
1485                 default:
1486                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1487                         break;
1488                 }
1489
1490                 if (i >= 1 && i <= svs.maxclients)
1491                 {
1492                         SV_CheckVelocity (ent);
1493
1494                         // call standard player post-think
1495                         SV_LinkEdict (ent, true);
1496
1497                         SV_CheckVelocity (ent);
1498
1499                         pr_global_struct->time = sv.time;
1500                         pr_global_struct->self = EDICT_TO_PROG(ent);
1501                         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1502                 }
1503         }
1504
1505         if (pr_global_struct->force_retouch > 0)
1506                 pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);
1507
1508         // LordHavoc: endframe support
1509         if (EndFrameQC)
1510         {
1511                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1512                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1513                 pr_global_struct->time = sv.time;
1514                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1515         }
1516
1517         if (!sv_freezenonclients.integer)
1518                 sv.time += sv.frametime;
1519 }
1520
1521
1522 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1523 {
1524         int i;
1525         float gravity, savesolid;
1526         vec3_t move, end;
1527         edict_t tempent, *tent;
1528         entvars_t vars;
1529         eval_t *val;
1530         trace_t trace;
1531
1532         // copy the vars over
1533         memcpy(&vars, tossent->v, sizeof(entvars_t));
1534         // set up the temp entity to point to the copied vars
1535         tent = &tempent;
1536         tent->v = &vars;
1537
1538         savesolid = tossent->v->solid;
1539         tossent->v->solid = SOLID_NOT;
1540
1541         // this has to fetch the field from the original edict, since our copy is truncated
1542         val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1543         if (val != NULL && val->_float != 0)
1544                 gravity = val->_float;
1545         else
1546                 gravity = 1.0;
1547         gravity *= sv_gravity.value * 0.05;
1548
1549         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1550         {
1551                 SV_CheckVelocity (tent);
1552                 tent->v->velocity[2] -= gravity;
1553                 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1554                 VectorScale (tent->v->velocity, 0.05, move);
1555                 VectorAdd (tent->v->origin, move, end);
1556                 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1557                 VectorCopy (trace.endpos, tent->v->origin);
1558
1559                 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1560                         break;
1561         }
1562         tossent->v->solid = savesolid;
1563         trace.fraction = 0; // not relevant
1564         return trace;
1565 }
1566