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