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