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