cleaned up and fixed collisions with brush models (example: you can now ramp jump...
[xonotic/darkplaces.git] / sv_phys.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sv_phys.c
21
22 #include "quakedef.h"
23
24 /*
25
26
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
28
29 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
30
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
37
38 solid_edge items only clip against bsp models.
39
40 */
41
42 cvar_t  sv_friction = {CVAR_NOTIFY, "sv_friction","4"};
43 cvar_t  sv_stopspeed = {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, impact;
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                 {
273                         // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
274                         // entity is trapped in another solid
275                         VectorClear(ent->v.velocity);
276                         return 3;
277                 }
278
279                 if (trace.fraction > 0)
280                 {       // actually covered some distance
281                         VectorCopy (trace.endpos, ent->v.origin);
282                         VectorCopy (ent->v.velocity, original_velocity);
283                         numplanes = 0;
284                 }
285
286                 if (trace.fraction == 1)
287                          break;         // moved the entire distance
288
289                 if (!trace.ent)
290                         Host_Error ("SV_FlyMove: !trace.ent");
291
292                 if ((int) ent->v.flags & FL_ONGROUND)
293                 {
294                         if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
295                                 impact = false;
296                         else
297                         {
298                                 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
299                                 impact = true;
300                         }
301                 }
302                 else
303                         impact = true;
304
305                 if (trace.plane.normal[2] > 0.7)
306                 {
307                         blocked |= 1;           // floor
308                         //if (trace.ent->v.solid == SOLID_BSP)
309                         {
310                                 ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
311                                 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
312                         }
313                 }
314                 if (!trace.plane.normal[2])
315                 {
316                         blocked |= 2;           // step
317                         if (steptrace)
318                                 *steptrace = trace;     // save for player extrafriction
319                 }
320
321 //
322 // run the impact function
323 //
324                 if (impact)
325                         SV_Impact (ent, trace.ent);
326                 if (ent->free)
327                         break;          // removed by the impact function
328
329
330                 time_left -= time_left * trace.fraction;
331
332         // cliped to another plane
333                 if (numplanes >= MAX_CLIP_PLANES)
334                 {       // this shouldn't really happen
335                         VectorClear(ent->v.velocity);
336                         return 3;
337                 }
338
339                 VectorCopy (trace.plane.normal, planes[numplanes]);
340                 numplanes++;
341
342 //
343 // modify original_velocity so it parallels all of the clip planes
344 //
345                 for (i=0 ; i<numplanes ; i++)
346                 {
347                         ClipVelocity (original_velocity, planes[i], new_velocity, 1);
348                         for (j=0 ; j<numplanes ; j++)
349                                 if (j != i)
350                                 {
351                                         if (DotProduct (new_velocity, planes[j]) < 0)
352                                                 break;  // not ok
353                                 }
354                         if (j == numplanes)
355                                 break;
356                 }
357
358                 if (i != numplanes)
359                 {       // go along this plane
360                         VectorCopy (new_velocity, ent->v.velocity);
361                 }
362                 else
363                 {       // go along the crease
364                         if (numplanes != 2)
365                         {
366 //                              Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
367                                 VectorClear(ent->v.velocity);
368                                 return 7;
369                         }
370                         CrossProduct (planes[0], planes[1], dir);
371                         // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
372                         VectorNormalize(dir);
373                         d = DotProduct (dir, ent->v.velocity);
374                         VectorScale (dir, d, ent->v.velocity);
375                 }
376
377 //
378 // if original velocity is against the original velocity, stop dead
379 // to avoid tiny occilations in sloping corners
380 //
381                 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
382                 {
383                         VectorClear(ent->v.velocity);
384                         return blocked;
385                 }
386         }
387
388         return blocked;
389 }
390
391
392 /*
393 ============
394 SV_AddGravity
395
396 ============
397 */
398 void SV_AddGravity (edict_t *ent)
399 {
400         float   ent_gravity;
401
402         eval_t  *val;
403
404         val = GETEDICTFIELDVALUE(ent, eval_gravity);
405         if (val!=0 && val->_float)
406                 ent_gravity = val->_float;
407         else
408                 ent_gravity = 1.0;
409         ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
410 }
411
412
413 /*
414 ===============================================================================
415
416 PUSHMOVE
417
418 ===============================================================================
419 */
420
421 /*
422 ============
423 SV_PushEntity
424
425 Does not change the entities velocity at all
426 ============
427 */
428 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
429 {
430         trace_t trace;
431         vec3_t  end;
432
433         VectorAdd (ent->v.origin, push, end);
434
435         if (ent->v.movetype == MOVETYPE_FLYMISSILE)
436                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
437         else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
438         // only clip against bmodels
439                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
440         else
441                 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
442
443         VectorCopy (trace.endpos, ent->v.origin);
444         // FIXME: turn players specially
445         ent->v.angles[1] += trace.fraction * pushangles[1];
446         SV_LinkEdict (ent, true);
447
448         if (trace.ent && (!((int)ent->v.flags & FL_ONGROUND) || ent->v.groundentity != EDICT_TO_PROG(trace.ent)))
449                 SV_Impact (ent, trace.ent);
450         return trace;
451 }
452
453
454 /*
455 ============
456 SV_PushMove
457
458 ============
459 */
460 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
461 void SV_PushMove (edict_t *pusher, float movetime)
462 {
463         int                     i, e, index;
464         edict_t         *check;
465         float           savesolid, movetime2, pushltime;
466         vec3_t          mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
467         int                     num_moved;
468         edict_t         *moved_edict[MAX_EDICTS];
469         vec3_t          moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
470         model_t         *pushermodel;
471         trace_t         trace;
472
473         switch ((int) pusher->v.solid)
474         {
475         // LordHavoc: valid pusher types
476         case SOLID_BSP:
477         case SOLID_BBOX:
478         case SOLID_SLIDEBOX:
479         case SOLID_CORPSE: // LordHavoc: this would be weird...
480                 break;
481         // LordHavoc: no collisions
482         case SOLID_NOT:
483         case SOLID_TRIGGER:
484                 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
485                 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
486                 pusher->v.ltime += movetime;
487                 SV_LinkEdict (pusher, false);
488                 return;
489         default:
490                 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
491         }
492         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])
493         {
494                 pusher->v.ltime += movetime;
495                 return;
496         }
497         index = (int) pusher->v.modelindex;
498         if (index < 1 || index >= MAX_MODELS)
499                 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
500         pushermodel = sv.models[index];
501
502         // LordHavoc: round up by a small epsilon
503         movetime2 = movetime; // + (1.0 / 256.0);
504         VectorScale(pusher->v.velocity, movetime2, move1);
505         VectorScale(pusher->v.avelocity, movetime2, moveangle);
506         if (moveangle[0] || moveangle[2])
507         {
508                 for (i = 0;i < 3;i++)
509                 {
510                         if (move1[i] > 0)
511                         {
512                                 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
513                                 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
514                         }
515                         else
516                         {
517                                 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
518                                 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
519                         }
520                 }
521         }
522         else if (moveangle[1])
523         {
524                 for (i = 0;i < 3;i++)
525                 {
526                         if (move1[i] > 0)
527                         {
528                                 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
529                                 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
530                         }
531                         else
532                         {
533                                 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
534                                 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
535                         }
536                 }
537         }
538         else
539         {
540                 for (i = 0;i < 3;i++)
541                 {
542                         if (move1[i] > 0)
543                         {
544                                 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
545                                 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
546                         }
547                         else
548                         {
549                                 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
550                                 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
551                         }
552                 }
553         }
554
555         VectorNegate (moveangle, a);
556         AngleVectorsFLU (a, forward, left, up);
557
558         VectorCopy (pusher->v.origin, pushorig);
559         VectorCopy (pusher->v.angles, pushang);
560         pushltime = pusher->v.ltime;
561
562 // move the pusher to it's final position
563
564         VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
565         VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
566         pusher->v.ltime += movetime;
567         SV_LinkEdict (pusher, false);
568
569         savesolid = pusher->v.solid;
570
571 // see if any solid entities are inside the final position
572         num_moved = 0;
573         check = NEXT_EDICT(sv.edicts);
574         for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
575         {
576                 if (check->free)
577                         continue;
578                 if (check->v.movetype == MOVETYPE_PUSH
579                  || check->v.movetype == MOVETYPE_NONE
580                  || check->v.movetype == MOVETYPE_FOLLOW
581                  || check->v.movetype == MOVETYPE_NOCLIP)
582                         continue;
583
584                 // if the entity is standing on the pusher, it will definitely be moved
585                 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
586                 {
587                         if (check->v.absmin[0] >= maxs[0]
588                          || check->v.absmax[0] <= mins[0]
589                          || check->v.absmin[1] >= maxs[1]
590                          || check->v.absmax[1] <= mins[1]
591                          || check->v.absmin[2] >= maxs[2]
592                          || check->v.absmax[2] <= mins[2])
593                                 continue;
594
595                         /*
596                         if (forward[0] < 0.999f) // quick way to check if any rotation is used
597                         {
598                                 VectorSubtract (check->v.origin, pusher->v.origin, org);
599                                 org2[0] = DotProduct (org, forward);
600                                 org2[1] = DotProduct (org, left);
601                                 org2[2] = DotProduct (org, up);
602                                 //VectorSubtract (org2, org, move);
603                                 //VectorAdd (move, move1, move);
604                                 //VectorSubtract(check->v.origin, move, a);
605                                 a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0];
606                                 a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1];
607                                 a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2];
608                         }
609                         else
610                                 VectorSubtract (check->v.origin, move1, a);
611
612                         trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin);
613                         if (trace.fraction == 1 && !trace.startsolid)
614                                 continue;
615                         */
616                         trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
617                         if (!trace.startsolid)
618                                 continue;
619                         /*
620                         // see if the ent's bbox is inside the pusher's final position
621                         if (!SV_TestEntityPosition (check))
622                                 continue;
623                         */
624                 }
625
626                 if (forward[0] < 0.999f) // quick way to check if any rotation is used
627                 {
628                         VectorSubtract (check->v.origin, pusher->v.origin, org);
629                         org2[0] = DotProduct (org, forward);
630                         org2[1] = DotProduct (org, left);
631                         org2[2] = DotProduct (org, up);
632                         VectorSubtract (org2, org, move);
633                         VectorAdd (move, move1, move);
634                 }
635                 else
636                         VectorCopy (move1, move);
637
638                 // LordHavoc: debugging
639                 //VectorAdd(entorig, move, org2);
640                 //CL_RocketTrail2 (entorig, org2, 238, NULL);
641
642                 // remove the onground flag for non-players
643                 if (check->v.movetype != MOVETYPE_WALK)
644                         check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
645
646                 //VectorCopy (check->v.origin, entorig);
647                 //VectorCopy (check->v.angles, entang);
648                 VectorCopy (check->v.origin, moved_from[num_moved]);
649                 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
650                 moved_edict[num_moved++] = check;
651
652                 // try moving the contacted entity
653                 pusher->v.solid = SOLID_NOT;
654                 trace = SV_PushEntity (check, move, moveangle);
655                 pusher->v.solid = savesolid; // was SOLID_BSP
656
657                 // if it is still inside the pusher, block
658                 // LordHavoc: cleanup - check trace.fraction and startsolid
659                 if (/*trace.fraction != 1 || trace.startsolid || */SV_TestEntityPosition (check))
660                 {
661                         // fail the move
662                         if (check->v.mins[0] == check->v.maxs[0])
663                                 continue;
664                         if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
665                         {
666                                 // corpse
667                                 check->v.mins[0] = check->v.mins[1] = 0;
668                                 VectorCopy (check->v.mins, check->v.maxs);
669                                 continue;
670                         }
671
672                         /*
673                         VectorCopy (entorig, check->v.origin);
674                         VectorCopy (entang, check->v.angles);
675                         SV_LinkEdict (check, true);
676                         */
677
678                         VectorCopy (pushorig, pusher->v.origin);
679                         VectorCopy (pushang, pusher->v.angles);
680                         pusher->v.ltime = pushltime;
681                         SV_LinkEdict (pusher, false);
682
683                         // move back any entities we already moved
684                         //num_moved--; // LordHavoc: pop off check, because it was already restored
685                         for (i=0 ; i<num_moved ; i++)
686                         {
687                                 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
688                                 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
689                                 SV_LinkEdict (moved_edict[i], false);
690                         }
691
692                         // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
693                         if (pusher->v.blocked)
694                         {
695                                 pr_global_struct->self = EDICT_TO_PROG(pusher);
696                                 pr_global_struct->other = EDICT_TO_PROG(check);
697                                 PR_ExecuteProgram (pusher->v.blocked, "");
698                         }
699                         return;
700                 }
701         }
702 }
703
704 /*
705 ================
706 SV_Physics_Pusher
707
708 ================
709 */
710 void SV_Physics_Pusher (edict_t *ent)
711 {
712         float   thinktime;
713         float   oldltime;
714         float   movetime;
715
716         oldltime = ent->v.ltime;
717
718         thinktime = ent->v.nextthink;
719         if (thinktime < ent->v.ltime + sv.frametime)
720         {
721                 movetime = thinktime - ent->v.ltime;
722                 if (movetime < 0)
723                         movetime = 0;
724         }
725         else
726                 movetime = sv.frametime;
727
728         if (movetime)
729                 SV_PushMove (ent, movetime);    // advances ent->v.ltime if not blocked
730
731         if (thinktime > oldltime && thinktime <= ent->v.ltime)
732         {
733                 ent->v.nextthink = 0;
734                 pr_global_struct->time = sv.time;
735                 pr_global_struct->self = EDICT_TO_PROG(ent);
736                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
737                 PR_ExecuteProgram (ent->v.think, "NULL think function");
738                 if (ent->free)
739                         return;
740         }
741
742 }
743
744
745 /*
746 ===============================================================================
747
748 CLIENT MOVEMENT
749
750 ===============================================================================
751 */
752
753 /*
754 =============
755 SV_CheckStuck
756
757 This is a big hack to try and fix the rare case of getting stuck in the world
758 clipping hull.
759 =============
760 */
761 void SV_CheckStuck (edict_t *ent)
762 {
763         int             i, j;
764         int             z;
765         vec3_t  org;
766
767         if (!SV_TestEntityPosition(ent))
768         {
769                 VectorCopy (ent->v.origin, ent->v.oldorigin);
770                 return;
771         }
772
773         VectorCopy (ent->v.origin, org);
774         VectorCopy (ent->v.oldorigin, ent->v.origin);
775         if (!SV_TestEntityPosition(ent))
776         {
777                 Con_DPrintf ("Unstuck.\n");
778                 SV_LinkEdict (ent, true);
779                 return;
780         }
781         
782         for (z=0 ; z< 18 ; z++)
783                 for (i=-1 ; i <= 1 ; i++)
784                         for (j=-1 ; j <= 1 ; j++)
785                         {
786                                 ent->v.origin[0] = org[0] + i;
787                                 ent->v.origin[1] = org[1] + j;
788                                 ent->v.origin[2] = org[2] + z;
789                                 if (!SV_TestEntityPosition(ent))
790                                 {
791                                         Con_DPrintf ("Unstuck.\n");
792                                         SV_LinkEdict (ent, true);
793                                         return;
794                                 }
795                         }
796                         
797         VectorCopy (org, ent->v.origin);
798         Con_DPrintf ("player is stuck.\n");
799 }
800
801
802 /*
803 =============
804 SV_CheckWater
805 =============
806 */
807 qboolean SV_CheckWater (edict_t *ent)
808 {
809         vec3_t  point;
810         int             cont;
811
812         point[0] = ent->v.origin[0];
813         point[1] = ent->v.origin[1];
814         point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
815         
816         ent->v.waterlevel = 0;
817         ent->v.watertype = CONTENTS_EMPTY;
818         cont = SV_PointContents (point);
819         if (cont <= CONTENTS_WATER)
820         {
821                 ent->v.watertype = cont;
822                 ent->v.waterlevel = 1;
823                 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
824                 cont = SV_PointContents (point);
825                 if (cont <= CONTENTS_WATER)
826                 {
827                         ent->v.waterlevel = 2;
828                         point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
829                         cont = SV_PointContents (point);
830                         if (cont <= CONTENTS_WATER)
831                                 ent->v.waterlevel = 3;
832                 }
833         }
834
835         return ent->v.waterlevel > 1;
836 }
837
838 /*
839 ============
840 SV_WallFriction
841
842 ============
843 */
844 void SV_WallFriction (edict_t *ent, trace_t *trace)
845 {
846         vec3_t          forward;
847         float           d, i;
848         vec3_t          into, side;
849
850         AngleVectors (ent->v.v_angle, forward, NULL, NULL);
851         d = DotProduct (trace->plane.normal, forward);
852         
853         d += 0.5;
854         if (d >= 0)
855                 return;
856
857 // cut the tangential velocity
858         i = DotProduct (trace->plane.normal, ent->v.velocity);
859         VectorScale (trace->plane.normal, i, into);
860         VectorSubtract (ent->v.velocity, into, side);
861         
862         ent->v.velocity[0] = side[0] * (1 + d);
863         ent->v.velocity[1] = side[1] * (1 + d);
864 }
865
866 /*
867 =====================
868 SV_TryUnstick
869
870 Player has come to a dead stop, possibly due to the problem with limited
871 float precision at some angle joins in the BSP hull.
872
873 Try fixing by pushing one pixel in each direction.
874
875 This is a hack, but in the interest of good gameplay...
876 ======================
877 */
878 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
879 {
880         int             i;
881         vec3_t  oldorg;
882         vec3_t  dir;
883         int             clip;
884         trace_t steptrace;
885
886         VectorCopy (ent->v.origin, oldorg);
887         VectorClear (dir);
888
889         for (i=0 ; i<8 ; i++)
890         {
891 // try pushing a little in an axial direction
892                 switch (i)
893                 {
894                         case 0: dir[0] = 2; dir[1] = 0; break;
895                         case 1: dir[0] = 0; dir[1] = 2; break;
896                         case 2: dir[0] = -2; dir[1] = 0; break;
897                         case 3: dir[0] = 0; dir[1] = -2; break;
898                         case 4: dir[0] = 2; dir[1] = 2; break;
899                         case 5: dir[0] = -2; dir[1] = 2; break;
900                         case 6: dir[0] = 2; dir[1] = -2; break;
901                         case 7: dir[0] = -2; dir[1] = -2; break;
902                 }
903
904                 SV_PushEntity (ent, dir, vec3_origin);
905
906 // retry the original move
907                 ent->v.velocity[0] = oldvel[0];
908                 ent->v.velocity[1] = oldvel[1];
909                 ent->v.velocity[2] = 0;
910                 clip = SV_FlyMove (ent, 0.1, &steptrace);
911
912                 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
913                 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
914                 {
915 //Con_DPrintf ("unstuck!\n");
916                         return clip;
917                 }
918
919 // go back to the original pos and try again
920                 VectorCopy (oldorg, ent->v.origin);
921         }
922         
923         VectorClear (ent->v.velocity);
924         return 7;               // still not moving
925 }
926
927 /*
928 =====================
929 SV_WalkMove
930
931 Only used by players
932 ======================
933 */
934 #define STEPSIZE        18
935 void SV_WalkMove (edict_t *ent)
936 {
937         vec3_t          upmove, downmove;
938         vec3_t          oldorg, oldvel;
939         vec3_t          nosteporg, nostepvel;
940         int                     clip;
941         int                     oldonground;
942         trace_t         steptrace, downtrace;
943
944 //
945 // do a regular slide move unless it looks like you ran into a step
946 //
947         oldonground = (int)ent->v.flags & FL_ONGROUND;
948         ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
949
950         VectorCopy (ent->v.origin, oldorg);
951         VectorCopy (ent->v.velocity, oldvel);
952
953         clip = SV_FlyMove (ent, sv.frametime, &steptrace);
954
955         if ( !(clip & 2) )
956                 return;         // move didn't block on a step
957
958         if (!oldonground && ent->v.waterlevel == 0)
959                 return;         // don't stair up while jumping
960
961         if (ent->v.movetype != MOVETYPE_WALK)
962                 return;         // gibbed by a trigger
963
964         if (sv_nostep.integer)
965                 return;
966
967         if ( (int)sv_player->v.flags & FL_WATERJUMP )
968                 return;
969
970         VectorCopy (ent->v.origin, nosteporg);
971         VectorCopy (ent->v.velocity, nostepvel);
972
973 //
974 // try moving up and forward to go up a step
975 //
976         VectorCopy (oldorg, ent->v.origin);     // back to start pos
977
978         VectorClear (upmove);
979         VectorClear (downmove);
980         upmove[2] = STEPSIZE;
981         downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
982
983 // move up
984         SV_PushEntity (ent, upmove, vec3_origin);       // FIXME: don't link?
985
986 // move forward
987         ent->v.velocity[0] = oldvel[0];
988         ent->v. velocity[1] = oldvel[1];
989         ent->v. velocity[2] = 0;
990         clip = SV_FlyMove (ent, sv.frametime, &steptrace);
991
992 // check for stuckness, possibly due to the limited precision of floats
993 // in the clipping hulls
994         if (clip)
995         {
996                 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
997                 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
998                 {       // stepping up didn't make any progress
999                         clip = SV_TryUnstick (ent, oldvel);
1000                 }
1001         }
1002
1003 // extra friction based on view angle
1004         if ( clip & 2 )
1005                 SV_WallFriction (ent, &steptrace);
1006
1007 // move down
1008         downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
1009
1010         if (downtrace.plane.normal[2] > 0.7)
1011         {
1012                 if (ent->v.solid == SOLID_BSP)
1013                 {
1014                         ent->v.flags =  (int)ent->v.flags | FL_ONGROUND;
1015                         ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1016                 }
1017         }
1018         else
1019         {
1020 // if the push down didn't end up on good ground, use the move without
1021 // the step up.  This happens near wall / slope combinations, and can
1022 // cause the player to hop up higher on a slope too steep to climb
1023                 VectorCopy (nosteporg, ent->v.origin);
1024                 VectorCopy (nostepvel, ent->v.velocity);
1025         }
1026 }
1027
1028
1029 /*
1030 ================
1031 SV_Physics_Client
1032
1033 Player character actions
1034 ================
1035 */
1036 void SV_Physics_Client (edict_t *ent, int num)
1037 {
1038         if ( ! svs.clients[num-1].active )
1039                 return;         // unconnected slot
1040
1041 //
1042 // call standard client pre-think
1043 //
1044         pr_global_struct->time = sv.time;
1045         pr_global_struct->self = EDICT_TO_PROG(ent);
1046         PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1047
1048 //
1049 // do a move
1050 //
1051         SV_CheckVelocity (ent);
1052
1053 //
1054 // decide which move function to call
1055 //
1056         switch ((int)ent->v.movetype)
1057         {
1058         case MOVETYPE_NONE:
1059                 if (!SV_RunThink (ent))
1060                         return;
1061                 break;
1062
1063         case MOVETYPE_WALK:
1064                 if (!SV_RunThink (ent))
1065                         return;
1066                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1067                         SV_AddGravity (ent);
1068                 SV_CheckStuck (ent);
1069                 SV_WalkMove (ent);
1070                 break;
1071
1072         case MOVETYPE_TOSS:
1073         case MOVETYPE_BOUNCE:
1074                 SV_Physics_Toss (ent);
1075                 break;
1076
1077         case MOVETYPE_FLY:
1078                 if (!SV_RunThink (ent))
1079                         return;
1080                 SV_CheckWater (ent);
1081                 SV_FlyMove (ent, sv.frametime, NULL);
1082                 break;
1083
1084         case MOVETYPE_NOCLIP:
1085                 if (!SV_RunThink (ent))
1086                         return;
1087                 SV_CheckWater (ent);
1088                 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1089                 break;
1090
1091         default:
1092                 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1093         }
1094
1095 //
1096 // call standard player post-think
1097 //
1098         SV_LinkEdict (ent, true);
1099
1100         pr_global_struct->time = sv.time;
1101         pr_global_struct->self = EDICT_TO_PROG(ent);
1102         PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1103 }
1104
1105 //============================================================================
1106
1107 /*
1108 =============
1109 SV_Physics_None
1110
1111 Non moving objects can only think
1112 =============
1113 */
1114 // LordHavoc: inlined manually because it was a real time waster
1115 /*
1116 void SV_Physics_None (edict_t *ent)
1117 {
1118 // regular thinking
1119         SV_RunThink (ent);
1120 }
1121 */
1122
1123 /*
1124 =============
1125 SV_Physics_Follow
1126
1127 Entities that are "stuck" to another entity
1128 =============
1129 */
1130 void SV_Physics_Follow (edict_t *ent)
1131 {
1132         vec3_t vf, vr, vu, angles, v;
1133         edict_t *e;
1134 // regular thinking
1135         if (!SV_RunThink (ent))
1136                 return;
1137         // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1138         e = PROG_TO_EDICT(ent->v.aiment);
1139         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])
1140         {
1141                 // quick case for no rotation
1142                 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1143         }
1144         else
1145         {
1146                 angles[0] = -ent->v.punchangle[0];
1147                 angles[1] =  ent->v.punchangle[1];
1148                 angles[2] =  ent->v.punchangle[2];
1149                 AngleVectors (angles, vf, vr, vu);
1150                 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1151                 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1152                 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1153                 angles[0] = -e->v.angles[0];
1154                 angles[1] =  e->v.angles[1];
1155                 angles[2] =  e->v.angles[2];
1156                 AngleVectors (angles, vf, vr, vu);
1157                 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1158                 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1159                 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1160                 /*
1161                 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];
1162                 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];
1163                 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];
1164                 */
1165         }
1166         VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1167 //      VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1168         SV_LinkEdict (ent, true);
1169 }
1170
1171 /*
1172 =============
1173 SV_Physics_Noclip
1174
1175 A moving object that doesn't obey physics
1176 =============
1177 */
1178 void SV_Physics_Noclip (edict_t *ent)
1179 {
1180 // regular thinking
1181         if (!SV_RunThink (ent))
1182                 return;
1183
1184         VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1185         VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1186
1187         SV_LinkEdict (ent, false);
1188 }
1189
1190 /*
1191 ==============================================================================
1192
1193 TOSS / BOUNCE
1194
1195 ==============================================================================
1196 */
1197
1198 /*
1199 =============
1200 SV_CheckWaterTransition
1201
1202 =============
1203 */
1204 void SV_CheckWaterTransition (edict_t *ent)
1205 {
1206         int             cont;
1207         cont = SV_PointContents (ent->v.origin);
1208         if (!ent->v.watertype)
1209         {       // just spawned here
1210                 ent->v.watertype = cont;
1211                 ent->v.waterlevel = 1;
1212                 return;
1213         }
1214
1215         if (cont <= CONTENTS_WATER)
1216         {
1217                 if (ent->v.watertype == CONTENTS_EMPTY)
1218                 {       // just crossed into water
1219                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1220                 }
1221                 ent->v.watertype = cont;
1222                 ent->v.waterlevel = 1;
1223         }
1224         else
1225         {
1226                 if (ent->v.watertype != CONTENTS_EMPTY)
1227                 {       // just crossed into water
1228                         SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1229                 }
1230                 ent->v.watertype = CONTENTS_EMPTY;
1231                 ent->v.waterlevel = cont;
1232         }
1233 }
1234
1235 /*
1236 =============
1237 SV_Physics_Toss
1238
1239 Toss, bounce, and fly movement.  When onground, do nothing.
1240 =============
1241 */
1242 void SV_Physics_Toss (edict_t *ent)
1243 {
1244         trace_t trace;
1245         vec3_t  move;
1246         edict_t *groundentity;
1247         //edict_t *groundentity;
1248         // regular thinking
1249         if (!SV_RunThink (ent))
1250                 return;
1251
1252 // if onground, return without moving
1253         if ((int)ent->v.flags & FL_ONGROUND)
1254         {
1255                 if (ent->v.groundentity == 0)
1256                         return;
1257                 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1258                 if (groundentity != NULL && groundentity->v.solid == SOLID_BSP)
1259                         ent->suspendedinairflag = true;
1260                 else if (ent->suspendedinairflag && (groundentity == NULL || groundentity->v.solid != SOLID_BSP))
1261                 {
1262                         // leave it suspended in the air
1263                         ent->v.groundentity = 0;
1264                         return;
1265                 }
1266         }
1267         ent->suspendedinairflag = false;
1268
1269         /*
1270         if ( ((int)ent->v.flags & FL_ONGROUND) )
1271         {
1272                 // LordHavoc: fall if the groundentity was removed
1273                 if (ent->v.groundentity)
1274                 {
1275                         groundentity = PROG_TO_EDICT(ent->v.groundentity);
1276                         if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1277                                 return;
1278                 }
1279         }
1280         */
1281
1282         SV_CheckVelocity (ent);
1283
1284 // add gravity
1285         if (ent->v.movetype != MOVETYPE_FLY
1286          && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1287          && ent->v.movetype != MOVETYPE_FLYMISSILE)
1288                 SV_AddGravity (ent);
1289
1290 // move angles
1291         VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1292
1293 // move origin
1294         VectorScale (ent->v.velocity, sv.frametime, move);
1295         trace = SV_PushEntity (ent, move, vec3_origin);
1296         if (ent->free)
1297                 return;
1298         if (trace.fraction == 1)
1299                 return;
1300
1301         if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1302         {
1303                 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 2.0);
1304                 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1305         }
1306         else if (ent->v.movetype == MOVETYPE_BOUNCE)
1307         {
1308                 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
1309                 // LordHavoc: fixed grenades not bouncing when fired down a slope
1310                 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1311                 //if (trace.plane.normal[2] > 0.7 && ent->v.velocity[2] < 60)
1312                 {
1313                         ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1314                         ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1315                         VectorClear (ent->v.velocity);
1316                         VectorClear (ent->v.avelocity);
1317                 }
1318                 else
1319                         ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1320         }
1321         else
1322         {
1323                 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0);
1324                 if (trace.plane.normal[2] > 0.7)
1325                 {
1326                         ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1327                         ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1328                         VectorClear (ent->v.velocity);
1329                         VectorClear (ent->v.avelocity);
1330                 }
1331                 else
1332                         ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1333         }
1334
1335 // check for in water
1336         SV_CheckWaterTransition (ent);
1337 }
1338
1339 /*
1340 ===============================================================================
1341
1342 STEPPING MOVEMENT
1343
1344 ===============================================================================
1345 */
1346
1347 /*
1348 =============
1349 SV_Physics_Step
1350
1351 Monsters freefall when they don't have a ground entity, otherwise
1352 all movement is done with discrete steps.
1353
1354 This is also used for objects that have become still on the ground, but
1355 will fall if the floor is pulled out from under them.
1356 =============
1357 */
1358 void SV_Physics_Step (edict_t *ent)
1359 {
1360         int flags, fall, hitsound;
1361
1362         // freefall if not fly/swim
1363         fall = true;
1364         flags = (int)ent->v.flags;
1365         if (flags & (FL_FLY | FL_SWIM))
1366         {
1367                 if (flags & FL_FLY)
1368                         fall = false;
1369                 else if ((flags & FL_SWIM) && SV_PointContents(ent->v.origin) != CONTENTS_EMPTY)
1370                         fall = false;
1371         }
1372         if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
1373                 fall = false;
1374
1375         if (fall)
1376         {
1377                 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1378                 {
1379                         hitsound = true;
1380                         if (flags & FL_ONGROUND)
1381                                 hitsound = false;
1382                 }
1383                 else
1384                         hitsound = false;
1385
1386                 SV_AddGravity (ent);
1387                 SV_CheckVelocity (ent);
1388                 SV_FlyMove (ent, sv.frametime, NULL);
1389                 SV_LinkEdict (ent, false);
1390
1391                 // just hit ground
1392                 if ((int)ent->v.flags & FL_ONGROUND)
1393                 {
1394                         VectorClear(ent->v.velocity);
1395                         if (hitsound)
1396                                 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1397                 }
1398         }
1399
1400 // regular thinking
1401         SV_RunThink (ent);
1402
1403         SV_CheckWaterTransition (ent);
1404 }
1405
1406 //============================================================================
1407
1408 /*
1409 ================
1410 SV_Physics
1411
1412 ================
1413 */
1414 void SV_Physics (void)
1415 {
1416         int             i;
1417         edict_t *ent;
1418
1419 // let the progs know that a new frame has started
1420         pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1421         pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1422         pr_global_struct->time = sv.time;
1423         PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1424
1425 //SV_CheckAllEnts ();
1426
1427 //
1428 // treat each object in turn
1429 //
1430         ent = sv.edicts;
1431         for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1432         {
1433                 if (ent->free)
1434                         continue;
1435
1436                 if (pr_global_struct->force_retouch)
1437                         SV_LinkEdict (ent, true);       // force retouch even for stationary
1438
1439                 if (i > 0 && i <= svs.maxclients)
1440                 {
1441                         SV_Physics_Client (ent, i);
1442                         continue;
1443                 }
1444
1445                 switch ((int) ent->v.movetype)
1446                 {
1447                 case MOVETYPE_PUSH:
1448                         SV_Physics_Pusher (ent);
1449                         break;
1450                 case MOVETYPE_NONE:
1451 //                      SV_Physics_None (ent);
1452                         // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1453                         if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1454                                 SV_RunThink (ent);
1455                         break;
1456                 case MOVETYPE_FOLLOW:
1457                         SV_Physics_Follow (ent);
1458                         break;
1459                 case MOVETYPE_NOCLIP:
1460                         SV_Physics_Noclip (ent);
1461                         break;
1462                 case MOVETYPE_STEP:
1463                         SV_Physics_Step (ent);
1464                         break;
1465                 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1466                 case MOVETYPE_WALK:
1467                         if (SV_RunThink (ent))
1468                         {
1469                                 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1470                                         SV_AddGravity (ent);
1471                                 SV_CheckStuck (ent);
1472                                 SV_WalkMove (ent);
1473                                 SV_LinkEdict (ent, true);
1474                         }
1475                         break;
1476                 case MOVETYPE_TOSS:
1477                 case MOVETYPE_BOUNCE:
1478                 case MOVETYPE_BOUNCEMISSILE:
1479                 case MOVETYPE_FLY:
1480                 case MOVETYPE_FLYMISSILE:
1481                         SV_Physics_Toss (ent);
1482                         break;
1483                 default:
1484                         Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1485                         break;
1486                 }
1487         }
1488
1489         if (pr_global_struct->force_retouch)
1490                 pr_global_struct->force_retouch--;
1491
1492         // LordHavoc: endframe support
1493         if (EndFrameQC)
1494         {
1495                 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1496                 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1497                 pr_global_struct->time = sv.time;
1498                 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1499         }
1500
1501         sv.time += sv.frametime;
1502 }
1503
1504
1505 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1506 {
1507         int i;
1508         edict_t tempent, *tent;
1509         trace_t trace;
1510         vec3_t  move;
1511         vec3_t  end;
1512         float   gravity, savesolid;
1513         eval_t  *val;
1514
1515         memcpy(&tempent, tossent, sizeof(edict_t));
1516         tent = &tempent;
1517         savesolid = tossent->v.solid;
1518         tossent->v.solid = SOLID_NOT;
1519
1520         // this has to fetch the field from the original edict, since our copy is truncated
1521         val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1522         if (val != NULL && val->_float != 0)
1523                 gravity = val->_float;
1524         else
1525                 gravity = 1.0;
1526         gravity *= sv_gravity.value * 0.05;
1527
1528         for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1529         {
1530                 SV_CheckVelocity (tent);
1531                 tent->v.velocity[2] -= gravity;
1532                 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1533                 VectorScale (tent->v.velocity, 0.05, move);
1534                 VectorAdd (tent->v.origin, move, end);
1535                 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1536                 VectorCopy (trace.endpos, tent->v.origin);
1537
1538                 if (trace.fraction < 1 && trace.ent)
1539                         if (trace.ent != ignore)
1540                                 break;
1541         }
1542         tossent->v.solid = savesolid;
1543         trace.fraction = 0; // not relevant
1544         return trace;
1545 }