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