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