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