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