]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - sv_phys.c
added Print versions of Printf functions and made all calls that do not need formatin...
[xonotic/darkplaces.git] / sv_phys.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_phys.c
21
22 #include "quakedef.h"
23
24 /*
25
26
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
28
29 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
30
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38 solid_edge items only clip against bsp models.
39
40 */
41
42 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"};
43 cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"};
44 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"};
45 cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"};
47 cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"};
48 cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"};
49 cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"};
50 cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "1"};
51 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"};
52
53 #define MOVE_EPSILON    0.01
54
55 void SV_Physics_Toss (edict_t *ent);
56
57 void SV_Phys_Init (void)
58 {
59         Cvar_RegisterVariable(&sv_stepheight);
60         Cvar_RegisterVariable(&sv_jumpstep);
61         Cvar_RegisterVariable(&sv_wallfriction);
62         Cvar_RegisterVariable(&sv_newflymove);
63         Cvar_RegisterVariable(&sv_freezenonclients);
64 }
65
66 /*
67 ================
68 SV_CheckAllEnts
69 ================
70 */
71 void SV_CheckAllEnts (void)
72 {
73         int e;
74         edict_t *check;
75
76         // see if any solid entities are inside the final position
77         check = NEXT_EDICT(sv.edicts);
78         for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
79         {
80                 if (check->e->free)
81                         continue;
82                 if (check->v->movetype == MOVETYPE_PUSH
83                  || check->v->movetype == MOVETYPE_NONE
84                  || check->v->movetype == MOVETYPE_FOLLOW
85                  || check->v->movetype == MOVETYPE_NOCLIP)
86                         continue;
87
88                 if (SV_TestEntityPosition (check))
89                         Con_Print("entity in invalid position\n");
90         }
91 }
92
93 /*
94 ================
95 SV_CheckVelocity
96 ================
97 */
98 void SV_CheckVelocity (edict_t *ent)
99 {
100         int i;
101         float wishspeed;
102
103 //
104 // bound velocity
105 //
106         for (i=0 ; i<3 ; i++)
107         {
108                 if (IS_NAN(ent->v->velocity[i]))
109                 {
110                         Con_Printf("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname));
111                         ent->v->velocity[i] = 0;
112                 }
113                 if (IS_NAN(ent->v->origin[i]))
114                 {
115                         Con_Printf("Got a NaN origin on %s\n", PR_GetString(ent->v->classname));
116                         ent->v->origin[i] = 0;
117                 }
118         }
119
120         // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
121         wishspeed = DotProduct(ent->v->velocity, ent->v->velocity);
122         if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
123         {
124                 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
125                 ent->v->velocity[0] *= wishspeed;
126                 ent->v->velocity[1] *= wishspeed;
127                 ent->v->velocity[2] *= wishspeed;
128         }
129 }
130
131 /*
132 =============
133 SV_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         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
475 /*
476 ============
477 SV_AddGravity
478
479 ============
480 */
481 void SV_AddGravity (edict_t *ent)
482 {
483         float ent_gravity;
484         eval_t *val;
485
486         val = GETEDICTFIELDVALUE(ent, eval_gravity);
487         if (val!=0 && val->_float)
488                 ent_gravity = val->_float;
489         else
490                 ent_gravity = 1.0;
491         ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
492 }
493
494
495 /*
496 ===============================================================================
497
498 PUSHMOVE
499
500 ===============================================================================
501 */
502
503 /*
504 ============
505 SV_PushEntity
506
507 Does not change the entities velocity at all
508 ============
509 */
510 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
511 {
512         trace_t trace;
513         vec3_t end;
514
515         VectorAdd (ent->v->origin, push, end);
516
517         if (ent->v->movetype == MOVETYPE_FLYMISSILE)
518                 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE, ent);
519         else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
520                 // only clip against bmodels
521                 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, ent);
522         else
523                 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
524
525         VectorCopy (trace.endpos, ent->v->origin);
526         // FIXME: turn players specially
527         ent->v->angles[1] += trace.fraction * pushangles[1];
528         SV_LinkEdict (ent, true);
529
530         if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
531                 SV_Impact (ent, trace.ent);
532         return trace;
533 }
534
535
536 /*
537 ============
538 SV_PushMove
539
540 ============
541 */
542 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
543 void SV_PushMove (edict_t *pusher, float movetime)
544 {
545         int i, e, index;
546         edict_t *check, *ed;
547         float savesolid, movetime2, pushltime;
548         vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
549         int num_moved;
550         model_t *pushermodel;
551
552         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])
553         {
554                 pusher->v->ltime += movetime;
555                 return;
556         }
557
558         switch ((int) pusher->v->solid)
559         {
560         // LordHavoc: valid pusher types
561         case SOLID_BSP:
562         case SOLID_BBOX:
563         case SOLID_SLIDEBOX:
564         case SOLID_CORPSE: // LordHavoc: this would be weird...
565                 break;
566         // LordHavoc: no collisions
567         case SOLID_NOT:
568         case SOLID_TRIGGER:
569                 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
570                 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
571                 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
572                 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
573                 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
574                 pusher->v->ltime += movetime;
575                 SV_LinkEdict (pusher, false);
576                 return;
577         default:
578                 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
579         }
580         index = (int) pusher->v->modelindex;
581         if (index < 1 || index >= MAX_MODELS)
582                 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
583         pushermodel = sv.models[index];
584
585         movetime2 = movetime;
586         VectorScale(pusher->v->velocity, movetime2, move1);
587         VectorScale(pusher->v->avelocity, movetime2, moveangle);
588         if (moveangle[0] || moveangle[2])
589         {
590                 for (i = 0;i < 3;i++)
591                 {
592                         if (move1[i] > 0)
593                         {
594                                 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
595                                 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
596                         }
597                         else
598                         {
599                                 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
600                                 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
601                         }
602                 }
603         }
604         else if (moveangle[1])
605         {
606                 for (i = 0;i < 3;i++)
607                 {
608                         if (move1[i] > 0)
609                         {
610                                 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
611                                 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
612                         }
613                         else
614                         {
615                                 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
616                                 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
617                         }
618                 }
619         }
620         else
621         {
622                 for (i = 0;i < 3;i++)
623                 {
624                         if (move1[i] > 0)
625                         {
626                                 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
627                                 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
628                         }
629                         else
630                         {
631                                 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
632                                 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
633                         }
634                 }
635         }
636
637         VectorNegate (moveangle, a);
638         AngleVectorsFLU (a, forward, left, up);
639
640         VectorCopy (pusher->v->origin, pushorig);
641         VectorCopy (pusher->v->angles, pushang);
642         pushltime = pusher->v->ltime;
643
644 // move the pusher to it's final position
645
646         VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
647         VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
648         pusher->v->ltime += movetime;
649         SV_LinkEdict (pusher, false);
650
651         savesolid = pusher->v->solid;
652
653 // see if any solid entities are inside the final position
654         num_moved = 0;
655         check = NEXT_EDICT(sv.edicts);
656         for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
657         {
658                 if (check->e->free)
659                         continue;
660                 if (check->v->movetype == MOVETYPE_PUSH
661                  || check->v->movetype == MOVETYPE_NONE
662                  || check->v->movetype == MOVETYPE_FOLLOW
663                  || check->v->movetype == MOVETYPE_NOCLIP
664                  || check->v->movetype == MOVETYPE_FAKEPUSH)
665                         continue;
666
667                 // if the entity is standing on the pusher, it will definitely be moved
668                 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
669                 {
670                         if (check->v->absmin[0] >= maxs[0]
671                          || check->v->absmax[0] <= mins[0]
672                          || check->v->absmin[1] >= maxs[1]
673                          || check->v->absmax[1] <= mins[1]
674                          || check->v->absmin[2] >= maxs[2]
675                          || check->v->absmax[2] <= mins[2])
676                                 continue;
677
678                         if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
679                                 continue;
680                 }
681
682                 if (forward[0] != 1) // quick way to check if any rotation is used
683                 {
684                         VectorSubtract (check->v->origin, pusher->v->origin, org);
685                         org2[0] = DotProduct (org, forward);
686                         org2[1] = DotProduct (org, left);
687                         org2[2] = DotProduct (org, up);
688                         VectorSubtract (org2, org, move);
689                         VectorAdd (move, move1, move);
690                 }
691                 else
692                         VectorCopy (move1, move);
693
694                 // remove the onground flag for non-players
695                 if (check->v->movetype != MOVETYPE_WALK)
696                         check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
697
698                 VectorCopy (check->v->origin, check->e->moved_from);
699                 VectorCopy (check->v->angles, check->e->moved_fromangles);
700                 sv.moved_edicts[num_moved++] = check;
701
702                 // try moving the contacted entity
703                 pusher->v->solid = SOLID_NOT;
704                 SV_PushEntity (check, move, moveangle);
705                 pusher->v->solid = savesolid; // was SOLID_BSP
706
707                 // if it is still inside the pusher, block
708                 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
709                 {
710                         // try moving the contacted entity a tiny bit further to account for precision errors
711                         pusher->v->solid = SOLID_NOT;
712                         VectorScale(move, 0.1, move);
713                         SV_PushEntity (check, move, vec3_origin);
714                         pusher->v->solid = savesolid;
715                         if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
716                         {
717                                 // still inside pusher, so it's really blocked
718
719                                 // fail the move
720                                 if (check->v->mins[0] == check->v->maxs[0])
721                                         continue;
722                                 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
723                                 {
724                                         // corpse
725                                         check->v->mins[0] = check->v->mins[1] = 0;
726                                         VectorCopy (check->v->mins, check->v->maxs);
727                                         continue;
728                                 }
729
730                                 VectorCopy (pushorig, pusher->v->origin);
731                                 VectorCopy (pushang, pusher->v->angles);
732                                 pusher->v->ltime = pushltime;
733                                 SV_LinkEdict (pusher, false);
734
735                                 // move back any entities we already moved
736                                 for (i = 0;i < num_moved;i++)
737                                 {
738                                         ed = sv.moved_edicts[i];
739                                         VectorCopy (ed->e->moved_from, ed->v->origin);
740                                         VectorCopy (ed->e->moved_fromangles, ed->v->angles);
741                                         SV_LinkEdict (ed, false);
742                                 }
743
744                                 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
745                                 if (pusher->v->blocked)
746                                 {
747                                         pr_global_struct->self = EDICT_TO_PROG(pusher);
748                                         pr_global_struct->other = EDICT_TO_PROG(check);
749                                         PR_ExecuteProgram (pusher->v->blocked, "");
750                                 }
751                                 break;
752                         }
753                 }
754         }
755         pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
756         pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
757         pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
758 }
759
760 /*
761 ================
762 SV_Physics_Pusher
763
764 ================
765 */
766 void SV_Physics_Pusher (edict_t *ent)
767 {
768         float thinktime, oldltime, movetime;
769
770         oldltime = ent->v->ltime;
771
772         thinktime = ent->v->nextthink;
773         if (thinktime < ent->v->ltime + sv.frametime)
774         {
775                 movetime = thinktime - ent->v->ltime;
776                 if (movetime < 0)
777                         movetime = 0;
778         }
779         else
780                 movetime = sv.frametime;
781
782         if (movetime)
783                 // advances ent->v->ltime if not blocked
784                 SV_PushMove (ent, movetime);
785
786         if (thinktime > oldltime && thinktime <= ent->v->ltime)
787         {
788                 ent->v->nextthink = 0;
789                 pr_global_struct->time = sv.time;
790                 pr_global_struct->self = EDICT_TO_PROG(ent);
791                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
792                 PR_ExecuteProgram (ent->v->think, "NULL think function");
793         }
794 }
795
796
797 /*
798 ===============================================================================
799
800 CLIENT MOVEMENT
801
802 ===============================================================================
803 */
804
805 /*
806 =============
807 SV_CheckStuck
808
809 This is a big hack to try and fix the rare case of getting stuck in the world
810 clipping hull.
811 =============
812 */
813 void SV_CheckStuck (edict_t *ent)
814 {
815         int i, j, z;
816         vec3_t org;
817
818         if (!SV_TestEntityPosition(ent))
819         {
820                 VectorCopy (ent->v->origin, ent->v->oldorigin);
821                 return;
822         }
823
824         VectorCopy (ent->v->origin, org);
825         VectorCopy (ent->v->oldorigin, ent->v->origin);
826         if (!SV_TestEntityPosition(ent))
827         {
828                 Con_DPrint("Unstuck.\n");
829                 SV_LinkEdict (ent, true);
830                 return;
831         }
832
833         for (z=0 ; z< 18 ; z++)
834                 for (i=-1 ; i <= 1 ; i++)
835                         for (j=-1 ; j <= 1 ; j++)
836                         {
837                                 ent->v->origin[0] = org[0] + i;
838                                 ent->v->origin[1] = org[1] + j;
839                                 ent->v->origin[2] = org[2] + z;
840                                 if (!SV_TestEntityPosition(ent))
841                                 {
842                                         Con_DPrint("Unstuck.\n");
843                                         SV_LinkEdict (ent, true);
844                                         return;
845                                 }
846                         }
847
848         VectorCopy (org, ent->v->origin);
849         Con_DPrint("player is stuck.\n");
850 }
851
852
853 /*
854 =============
855 SV_CheckWater
856 =============
857 */
858 qboolean SV_CheckWater (edict_t *ent)
859 {
860         int cont;
861         vec3_t point;
862
863         point[0] = ent->v->origin[0];
864         point[1] = ent->v->origin[1];
865         point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
866
867         ent->v->waterlevel = 0;
868         ent->v->watertype = CONTENTS_EMPTY;
869         cont = SV_PointQ1Contents(point);
870         if (cont <= CONTENTS_WATER)
871         {
872                 ent->v->watertype = cont;
873                 ent->v->waterlevel = 1;
874                 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
875                 cont = SV_PointQ1Contents(point);
876                 if (cont <= CONTENTS_WATER)
877                 {
878                         ent->v->waterlevel = 2;
879                         point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
880                         cont = SV_PointQ1Contents(point);
881                         if (cont <= CONTENTS_WATER)
882                                 ent->v->waterlevel = 3;
883                 }
884         }
885
886         return ent->v->waterlevel > 1;
887 }
888
889 /*
890 ============
891 SV_WallFriction
892
893 ============
894 */
895 void SV_WallFriction (edict_t *ent, float *stepnormal)
896 {
897         float d, i;
898         vec3_t forward, into, side;
899
900         AngleVectors (ent->v->v_angle, forward, NULL, NULL);
901         if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
902         {
903                 // cut the tangential velocity
904                 i = DotProduct (stepnormal, ent->v->velocity);
905                 VectorScale (stepnormal, i, into);
906                 VectorSubtract (ent->v->velocity, into, side);
907                 ent->v->velocity[0] = side[0] * (1 + d);
908                 ent->v->velocity[1] = side[1] * (1 + d);
909         }
910 }
911
912 /*
913 =====================
914 SV_TryUnstick
915
916 Player has come to a dead stop, possibly due to the problem with limited
917 float precision at some angle joins in the BSP hull.
918
919 Try fixing by pushing one pixel in each direction.
920
921 This is a hack, but in the interest of good gameplay...
922 ======================
923 */
924 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
925 {
926         int i, clip;
927         vec3_t oldorg, dir;
928
929         VectorCopy (ent->v->origin, oldorg);
930         VectorClear (dir);
931
932         for (i=0 ; i<8 ; i++)
933         {
934                 // try pushing a little in an axial direction
935                 switch (i)
936                 {
937                         case 0: dir[0] = 2; dir[1] = 0; break;
938                         case 1: dir[0] = 0; dir[1] = 2; break;
939                         case 2: dir[0] = -2; dir[1] = 0; break;
940                         case 3: dir[0] = 0; dir[1] = -2; break;
941                         case 4: dir[0] = 2; dir[1] = 2; break;
942                         case 5: dir[0] = -2; dir[1] = 2; break;
943                         case 6: dir[0] = 2; dir[1] = -2; break;
944                         case 7: dir[0] = -2; dir[1] = -2; break;
945                 }
946
947                 SV_PushEntity (ent, dir, vec3_origin);
948
949                 // retry the original move
950                 ent->v->velocity[0] = oldvel[0];
951                 ent->v->velocity[1] = oldvel[1];
952                 ent->v->velocity[2] = 0;
953                 clip = SV_FlyMove (ent, 0.1, NULL);
954
955                 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
956                  || fabs(oldorg[0] - ent->v->origin[0]) > 4)
957                 {
958                         Con_DPrint("TryUnstick - success.\n");
959                         return clip;
960                 }
961
962                 // go back to the original pos and try again
963                 VectorCopy (oldorg, ent->v->origin);
964         }
965
966         // still not moving
967         VectorClear (ent->v->velocity);
968         Con_DPrint("TryUnstick - failure.\n");
969         return 7;
970 }
971
972 /*
973 =====================
974 SV_WalkMove
975
976 Only used by players
977 ======================
978 */
979 void SV_WalkMove (edict_t *ent)
980 {
981         int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
982         vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal, originalmove_origin, originalmove_velocity;
983         trace_t downtrace;
984
985         SV_CheckVelocity(ent);
986
987         // do a regular slide move unless it looks like you ran into a step
988         oldonground = (int)ent->v->flags & FL_ONGROUND;
989         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
990
991         VectorCopy (ent->v->origin, oldorg);
992         VectorCopy (ent->v->velocity, oldvel);
993
994         clip = SV_FlyMove (ent, sv.frametime, NULL);
995         VectorCopy(ent->v->origin, originalmove_origin);
996         VectorCopy(ent->v->velocity, originalmove_velocity);
997         originalmove_clip = clip;
998         originalmove_flags = (int)ent->v->flags;
999         originalmove_groundentity = ent->v->groundentity; 
1000
1001         SV_CheckVelocity(ent);
1002
1003         // if move didn't block on a step, return
1004         if ( !(clip & 2) )
1005                 return;
1006
1007         // if move was not trying to move into the step, return
1008         if (fabs(oldvel[0]) < 0.03125 && fabs(oldvel[1]) < 0.03125)
1009                 return;
1010
1011         if (ent->v->movetype != MOVETYPE_FLY)
1012         {
1013                 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
1014                         // don't stair up while jumping
1015                         return;
1016
1017                 if (ent->v->movetype != MOVETYPE_WALK)
1018                         // gibbed by a trigger
1019                         return;
1020         }
1021
1022         SV_CheckVelocity(ent);
1023
1024         if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP )
1025                 return;
1026
1027         VectorCopy (ent->v->origin, nosteporg);
1028         VectorCopy (ent->v->velocity, nostepvel);
1029
1030         // try moving up and forward to go up a step
1031         // back to start pos
1032         VectorCopy (oldorg, ent->v->origin);
1033
1034         VectorClear (upmove);
1035         VectorClear (downmove);
1036         upmove[2] = sv_stepheight.value;
1037         downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
1038
1039         // move up
1040         // FIXME: don't link?
1041         SV_PushEntity(ent, upmove, vec3_origin);
1042
1043         // move forward
1044         ent->v->velocity[0] = oldvel[0];
1045         ent->v->velocity[1] = oldvel[1];
1046         ent->v->velocity[2] = 0;
1047         clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1048         ent->v->velocity[2] += oldvel[2];
1049
1050         // check for stuckness, possibly due to the limited precision of floats
1051         // in the clipping hulls
1052         if (clip
1053          && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
1054          && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
1055         {
1056                 // stepping up didn't make any progress, revert to original move
1057                 VectorCopy(originalmove_origin, ent->v->origin);
1058                 VectorCopy(originalmove_velocity, ent->v->velocity);
1059                 clip = originalmove_clip;
1060                 ent->v->flags = originalmove_flags;
1061                 ent->v->groundentity = originalmove_groundentity; 
1062                 // now try to unstick if needed
1063                 //clip = SV_TryUnstick (ent, oldvel);
1064                 return;
1065         }
1066
1067         // extra friction based on view angle
1068         if (clip & 2 && sv_wallfriction.integer)
1069                 SV_WallFriction (ent, stepnormal);
1070
1071         // move down
1072         // FIXME: don't link?
1073         downtrace = SV_PushEntity (ent, downmove, vec3_origin);
1074
1075         if (downtrace.plane.normal[2] > 0.7)
1076         {
1077                 // LordHavoc: disabled this so you can walk on monsters/players
1078                 //if (ent->v->solid == SOLID_BSP)
1079                 {
1080                         ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1081                         ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1082                 }
1083         }
1084         else
1085         {
1086                 // if the push down didn't end up on good ground, use the move without
1087                 // the step up.  This happens near wall / slope combinations, and can
1088                 // cause the player to hop up higher on a slope too steep to climb
1089                 VectorCopy (nosteporg, ent->v->origin);
1090                 VectorCopy (nostepvel, ent->v->velocity);
1091         }
1092
1093         SV_CheckVelocity(ent);
1094 }
1095
1096 //============================================================================
1097
1098 /*
1099 =============
1100 SV_Physics_Follow
1101
1102 Entities that are "stuck" to another entity
1103 =============
1104 */
1105 void SV_Physics_Follow (edict_t *ent)
1106 {
1107         vec3_t vf, vr, vu, angles, v;
1108         edict_t *e;
1109
1110         // regular thinking
1111         if (!SV_RunThink (ent))
1112                 return;
1113
1114         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1115         e = PROG_TO_EDICT(ent->v->aiment);
1116         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])
1117         {
1118                 // quick case for no rotation
1119                 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1120         }
1121         else
1122         {
1123                 angles[0] = -ent->v->punchangle[0];
1124                 angles[1] =  ent->v->punchangle[1];
1125                 angles[2] =  ent->v->punchangle[2];
1126                 AngleVectors (angles, vf, vr, vu);
1127                 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1128                 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1129                 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1130                 angles[0] = -e->v->angles[0];
1131                 angles[1] =  e->v->angles[1];
1132                 angles[2] =  e->v->angles[2];
1133                 AngleVectors (angles, vf, vr, vu);
1134                 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1135                 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1136                 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1137         }
1138         VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1139         SV_LinkEdict (ent, true);
1140 }
1141
1142 /*
1143 ==============================================================================
1144
1145 TOSS / BOUNCE
1146
1147 ==============================================================================
1148 */
1149
1150 /*
1151 =============
1152 SV_CheckWaterTransition
1153
1154 =============
1155 */
1156 void SV_CheckWaterTransition (edict_t *ent)
1157 {
1158         int cont;
1159         cont = SV_PointQ1Contents(ent->v->origin);
1160         if (!ent->v->watertype)
1161         {
1162                 // just spawned here
1163                 ent->v->watertype = cont;
1164                 ent->v->waterlevel = 1;
1165                 return;
1166         }
1167
1168         // check if the entity crossed into or out of water
1169         if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1170                 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1171
1172         if (cont <= CONTENTS_WATER)
1173         {
1174                 ent->v->watertype = cont;
1175                 ent->v->waterlevel = 1;
1176         }
1177         else
1178         {
1179                 ent->v->watertype = CONTENTS_EMPTY;
1180                 ent->v->waterlevel = 0;
1181         }
1182 }
1183
1184 /*
1185 =============
1186 SV_Physics_Toss
1187
1188 Toss, bounce, and fly movement.  When onground, do nothing.
1189 =============
1190 */
1191 void SV_Physics_Toss (edict_t *ent)
1192 {
1193         trace_t trace;
1194         vec3_t move;
1195         edict_t *groundentity;
1196
1197         // regular thinking
1198         if (!SV_RunThink (ent))
1199                 return;
1200
1201 // if onground, return without moving
1202         if ((int)ent->v->flags & FL_ONGROUND)
1203         {
1204                 if (ent->v->groundentity == 0)
1205                         return;
1206                 // if ent was supported by a brush model on previous frame,
1207                 // and groundentity is now freed, set groundentity to 0 (floating)
1208                 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1209                 if (groundentity->v->solid == SOLID_BSP)
1210                 {
1211                         ent->e->suspendedinairflag = true;
1212                         return;
1213                 }
1214                 else if (ent->e->suspendedinairflag && groundentity->e->free)
1215                 {
1216                         // leave it suspended in the air
1217                         ent->v->groundentity = 0;
1218                         ent->e->suspendedinairflag = false;
1219                         return;
1220                 }
1221         }
1222         ent->e->suspendedinairflag = false;
1223
1224         SV_CheckVelocity (ent);
1225
1226 // add gravity
1227         if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1228                 SV_AddGravity (ent);
1229
1230 // move angles
1231         VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1232
1233 // move origin
1234         VectorScale (ent->v->velocity, sv.frametime, move);
1235         trace = SV_PushEntity (ent, move, vec3_origin);
1236         if (ent->e->free)
1237                 return;
1238
1239         if (trace.fraction < 1)
1240         {
1241                 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1242                 {
1243                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1244                         ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1245                 }
1246                 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1247                 {
1248                         float d;
1249                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1250                         // LordHavoc: fixed grenades not bouncing when fired down a slope
1251                         d = DotProduct(trace.plane.normal, ent->v->velocity);
1252                         if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1253                         {
1254                                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1255                                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1256                                 VectorClear (ent->v->velocity);
1257                                 VectorClear (ent->v->avelocity);
1258                         }
1259                         else
1260                                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1261                 }
1262                 else
1263                 {
1264                         ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1265                         if (trace.plane.normal[2] > 0.7)
1266                         {
1267                                 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1268                                 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1269                                 VectorClear (ent->v->velocity);
1270                                 VectorClear (ent->v->avelocity);
1271                         }
1272                         else
1273                                 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1274                 }
1275         }
1276
1277 // check for in water
1278         SV_CheckWaterTransition (ent);
1279 }
1280
1281 /*
1282 ===============================================================================
1283
1284 STEPPING MOVEMENT
1285
1286 ===============================================================================
1287 */
1288
1289 /*
1290 =============
1291 SV_Physics_Step
1292
1293 Monsters freefall when they don't have a ground entity, otherwise
1294 all movement is done with discrete steps.
1295
1296 This is also used for objects that have become still on the ground, but
1297 will fall if the floor is pulled out from under them.
1298 =============
1299 */
1300 void SV_Physics_Step (edict_t *ent)
1301 {
1302         // freefall if not onground/fly/swim
1303         if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1304         {
1305                 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1306
1307                 SV_AddGravity(ent);
1308                 SV_CheckVelocity(ent);
1309                 SV_FlyMove(ent, sv.frametime, NULL);
1310                 SV_LinkEdict(ent, true);
1311
1312                 // just hit ground
1313                 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1314                         SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1315         }
1316
1317 // regular thinking
1318         SV_RunThink(ent);
1319
1320         SV_CheckWaterTransition(ent);
1321 }
1322
1323 //============================================================================
1324
1325 /*
1326 ================
1327 SV_Physics
1328
1329 ================
1330 */
1331 void SV_Physics (void)
1332 {
1333         int i;
1334         edict_t *ent;
1335
1336 // let the progs know that a new frame has started
1337         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1338         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1339         pr_global_struct->time = sv.time;
1340         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1341
1342 //
1343 // treat each object in turn
1344 //
1345         ent = sv.edicts;
1346         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1347         {
1348                 if (ent->e->free)
1349                         continue;
1350
1351                 if (pr_global_struct->force_retouch)
1352                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1353
1354                 if (i <= svs.maxclients)
1355                 {
1356                         if (i > 0)
1357                         {
1358                                 if (!svs.clients[i-1].spawned)
1359                                         continue;
1360                                 // connected slot
1361                                 // call standard client pre-think
1362                                 SV_CheckVelocity (ent);
1363                                 pr_global_struct->time = sv.time;
1364                                 pr_global_struct->self = EDICT_TO_PROG(ent);
1365                                 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1366                                 SV_CheckVelocity (ent);
1367                         }
1368                 }
1369                 else if (sv_freezenonclients.integer)
1370                         continue;
1371
1372                 // LordHavoc: merged client and normal entity physics
1373                 switch ((int) ent->v->movetype)
1374                 {
1375                 case MOVETYPE_PUSH:
1376                 case MOVETYPE_FAKEPUSH:
1377                         SV_Physics_Pusher (ent);
1378                         break;
1379                 case MOVETYPE_NONE:
1380                         // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1381                         if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1382                                 SV_RunThink (ent);
1383                         break;
1384                 case MOVETYPE_FOLLOW:
1385                         SV_Physics_Follow (ent);
1386                         break;
1387                 case MOVETYPE_NOCLIP:
1388                         if (SV_RunThink(ent))
1389                         {
1390                                 SV_CheckWater(ent);
1391                                 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1392                                 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1393                         }
1394                         // relink normal entities here, players always get relinked so don't relink twice
1395                         if (!(i > 0 && i <= svs.maxclients))
1396                                 SV_LinkEdict(ent, false);
1397                         break;
1398                 case MOVETYPE_STEP:
1399                         SV_Physics_Step (ent);
1400                         break;
1401                 case MOVETYPE_WALK:
1402                         if (SV_RunThink (ent))
1403                         {
1404                                 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1405                                         SV_AddGravity (ent);
1406                                 SV_CheckStuck (ent);
1407                                 SV_WalkMove (ent);
1408                                 // relink normal entities here, players always get relinked so don't relink twice
1409                                 if (!(i > 0 && i <= svs.maxclients))
1410                                         SV_LinkEdict (ent, true);
1411                         }
1412                         break;
1413                 case MOVETYPE_TOSS:
1414                 case MOVETYPE_BOUNCE:
1415                 case MOVETYPE_BOUNCEMISSILE:
1416                 case MOVETYPE_FLYMISSILE:
1417                         SV_Physics_Toss (ent);
1418                         break;
1419                 case MOVETYPE_FLY:
1420                         if (i > 0 && i <= svs.maxclients)
1421                         {
1422                                 if (SV_RunThink (ent))
1423                                 {
1424                                         SV_CheckWater (ent);
1425                                         SV_WalkMove (ent);
1426                                 }
1427                         }
1428                         else
1429                                 SV_Physics_Toss (ent);
1430                         break;
1431                 default:
1432                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1433                         break;
1434                 }
1435
1436                 if (i <= svs.maxclients && i > 0 && !ent->e->free)
1437                 {
1438                         SV_CheckVelocity (ent);
1439
1440                         // call standard player post-think
1441                         SV_LinkEdict (ent, true);
1442
1443                         SV_CheckVelocity (ent);
1444
1445                         pr_global_struct->time = sv.time;
1446                         pr_global_struct->self = EDICT_TO_PROG(ent);
1447                         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1448                 }
1449         }
1450
1451         if (pr_global_struct->force_retouch)
1452                 pr_global_struct->force_retouch--;
1453
1454         // LordHavoc: endframe support
1455         if (EndFrameQC)
1456         {
1457                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1458                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1459                 pr_global_struct->time = sv.time;
1460                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1461         }
1462
1463         if (!sv_freezenonclients.integer)
1464                 sv.time += sv.frametime;
1465 }
1466
1467
1468 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1469 {
1470         int i;
1471         float gravity, savesolid;
1472         vec3_t move, end;
1473         edict_t tempent, *tent;
1474         entvars_t vars;
1475         eval_t *val;
1476         trace_t trace;
1477
1478         // copy the vars over
1479         memcpy(&vars, tossent->v, sizeof(entvars_t));
1480         // set up the temp entity to point to the copied vars
1481         tent = &tempent;
1482         tent->v = &vars;
1483
1484         savesolid = tossent->v->solid;
1485         tossent->v->solid = SOLID_NOT;
1486
1487         // this has to fetch the field from the original edict, since our copy is truncated
1488         val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1489         if (val != NULL && val->_float != 0)
1490                 gravity = val->_float;
1491         else
1492                 gravity = 1.0;
1493         gravity *= sv_gravity.value * 0.05;
1494
1495         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1496         {
1497                 SV_CheckVelocity (tent);
1498                 tent->v->velocity[2] -= gravity;
1499                 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1500                 VectorScale (tent->v->velocity, 0.05, move);
1501                 VectorAdd (tent->v->origin, move, end);
1502                 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1503                 VectorCopy (trace.endpos, tent->v->origin);
1504
1505                 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1506                         break;
1507         }
1508         tossent->v->solid = savesolid;
1509         trace.fraction = 0; // not relevant
1510         return trace;
1511 }
1512