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