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