2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
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.
29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
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
38 solid_edge items only clip against bsp models.
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"};
48 #define MOVE_EPSILON 0.01
50 void SV_Physics_Toss (edict_t *ent);
57 void SV_CheckAllEnts (void)
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))
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)
74 if (SV_TestEntityPosition (check))
75 Con_Printf ("entity in invalid position\n");
84 void SV_CheckVelocity (edict_t *ent)
94 if (IS_NAN(ent->v.velocity[i]))
96 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
97 ent->v.velocity[i] = 0;
99 if (IS_NAN(ent->v.origin[i]))
101 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
102 ent->v.origin[i] = 0;
104 // LordHavoc: maxvelocity fix, see below
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;
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)
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 wishspeed = sv_maxvelocity.value;
129 Runs thinking code if time. There is some play in the exact time the think
130 function will be called, because it is called before any movement is done
131 in a frame. Not used for pushmove objects, because they must be exact.
132 Returns false if the entity removed itself.
135 qboolean SV_RunThink (edict_t *ent)
139 thinktime = ent->v.nextthink;
140 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
143 if (thinktime < sv.time)
144 thinktime = sv.time; // don't let things stay in the past.
145 // it is possible to start that way
146 // by a trigger with a local time.
147 ent->v.nextthink = 0;
148 pr_global_struct->time = thinktime;
149 pr_global_struct->self = EDICT_TO_PROG(ent);
150 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
151 PR_ExecuteProgram (ent->v.think, "NULL think function");
159 Two entities have touched, so run their touch functions
162 void SV_Impact (edict_t *e1, edict_t *e2)
164 int old_self, old_other;
166 old_self = pr_global_struct->self;
167 old_other = pr_global_struct->other;
169 pr_global_struct->time = sv.time;
170 if (e1->v.touch && e1->v.solid != SOLID_NOT)
172 pr_global_struct->self = EDICT_TO_PROG(e1);
173 pr_global_struct->other = EDICT_TO_PROG(e2);
174 PR_ExecuteProgram (e1->v.touch, "");
177 if (e2->v.touch && e2->v.solid != SOLID_NOT)
179 pr_global_struct->self = EDICT_TO_PROG(e2);
180 pr_global_struct->other = EDICT_TO_PROG(e1);
181 PR_ExecuteProgram (e2->v.touch, "");
184 pr_global_struct->self = old_self;
185 pr_global_struct->other = old_other;
193 Slide off of the impacting object
194 returns the blocked flags (1 = floor, 2 = step / wall)
197 #define STOP_EPSILON 0.1
199 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
207 blocked |= 1; // floor
209 blocked |= 2; // step
211 backoff = DotProduct (in, normal) * overbounce;
213 for (i=0 ; i<3 ; i++)
215 change = normal[i]*backoff;
216 out[i] = in[i] - change;
217 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
229 The basic solid body movement clip that slides along multiple planes
230 Returns the clipflags if the velocity was modified (hit something solid)
234 If steptrace is not NULL, the trace of any vertical wall hit will be stored
237 // LordHavoc: increased from 5 to 20, to partially fix angled corner sticking
238 // (example - start.bsp hall to e4, leading to the pool there are two
239 // angled corners, which you could get stuck on, now they are just a one
241 #define MAX_CLIP_PLANES 20
242 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
244 int bumpcount, numbumps;
248 vec3_t planes[MAX_CLIP_PLANES];
249 vec3_t primal_velocity, original_velocity, new_velocity;
259 VectorCopy (ent->v.velocity, original_velocity);
260 VectorCopy (ent->v.velocity, primal_velocity);
265 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
267 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
270 for (i=0 ; i<3 ; i++)
271 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
273 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
276 { // entity is trapped in another solid
277 VectorClear(ent->v.velocity);
281 if (trace.fraction > 0)
282 { // actually covered some distance
283 VectorCopy (trace.endpos, ent->v.origin);
284 VectorCopy (ent->v.velocity, original_velocity);
288 if (trace.fraction == 1)
289 break; // moved the entire distance
292 Host_Error ("SV_FlyMove: !trace.ent");
294 if (trace.plane.normal[2] > 0.7)
296 blocked |= 1; // floor
297 if (trace.ent->v.solid == SOLID_BSP)
299 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
300 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
303 if (!trace.plane.normal[2])
305 blocked |= 2; // step
307 *steptrace = trace; // save for player extrafriction
311 // run the impact function
313 SV_Impact (ent, trace.ent);
315 break; // removed by the impact function
318 time_left -= time_left * trace.fraction;
320 // cliped to another plane
321 if (numplanes >= MAX_CLIP_PLANES)
322 { // this shouldn't really happen
323 VectorClear(ent->v.velocity);
327 VectorCopy (trace.plane.normal, planes[numplanes]);
331 // modify original_velocity so it parallels all of the clip planes
333 for (i=0 ; i<numplanes ; i++)
335 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
336 for (j=0 ; j<numplanes ; j++)
339 if (DotProduct (new_velocity, planes[j]) < 0)
347 { // go along this plane
348 VectorCopy (new_velocity, ent->v.velocity);
351 { // go along the crease
354 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
355 VectorClear(ent->v.velocity);
358 CrossProduct (planes[0], planes[1], dir);
359 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
360 VectorNormalize(dir);
361 d = DotProduct (dir, ent->v.velocity);
362 VectorScale (dir, d, ent->v.velocity);
366 // if original velocity is against the original velocity, stop dead
367 // to avoid tiny occilations in sloping corners
369 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
371 VectorClear(ent->v.velocity);
386 void SV_AddGravity (edict_t *ent)
392 val = GETEDICTFIELDVALUE(ent, eval_gravity);
393 if (val!=0 && val->_float)
394 ent_gravity = val->_float;
397 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
402 ===============================================================================
406 ===============================================================================
413 Does not change the entities velocity at all
416 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
421 VectorAdd (ent->v.origin, push, end);
423 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
424 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
425 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
426 // only clip against bmodels
427 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
429 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
431 VectorCopy (trace.endpos, ent->v.origin);
432 SV_LinkEdict (ent, true);
435 SV_Impact (ent, trace.ent);
447 void SV_PushMove (edict_t *pusher, float movetime)
451 vec3_t mins, maxs, move;
452 vec3_t entorig, pushorig;
454 edict_t *moved_edict[MAX_EDICTS];
455 vec3_t moved_from[MAX_EDICTS];
458 switch ((int) pusher->v.solid)
460 // LordHavoc: valid pusher types
464 case SOLID_CORPSE: // LordHavoc: this would be weird...
466 // LordHavoc: no collisions
469 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
470 pusher->v.ltime += movetime;
471 SV_LinkEdict (pusher, false);
474 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
476 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
478 pusher->v.ltime += movetime;
482 for (i=0 ; i<3 ; i++)
484 move[i] = pusher->v.velocity[i] * movetime;
485 mins[i] = pusher->v.absmin[i] + move[i];
486 maxs[i] = pusher->v.absmax[i] + move[i];
489 VectorCopy (pusher->v.origin, pushorig);
491 // move the pusher to it's final position
493 VectorAdd (pusher->v.origin, move, pusher->v.origin);
494 pusher->v.ltime += movetime;
495 SV_LinkEdict (pusher, false);
498 // see if any solid entities are inside the final position
500 check = NEXT_EDICT(sv.edicts);
501 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
505 if (check->v.movetype == MOVETYPE_PUSH
506 || check->v.movetype == MOVETYPE_NONE
507 || check->v.movetype == MOVETYPE_FOLLOW
508 || check->v.movetype == MOVETYPE_NOCLIP)
511 // if the entity is standing on the pusher, it will definitely be moved
512 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
514 if (check->v.absmin[0] >= maxs[0]
515 || check->v.absmin[1] >= maxs[1]
516 || check->v.absmin[2] >= maxs[2]
517 || check->v.absmax[0] <= mins[0]
518 || check->v.absmax[1] <= mins[1]
519 || check->v.absmax[2] <= mins[2])
522 // see if the ent's bbox is inside the pusher's final position
523 if (!SV_TestEntityPosition (check))
527 // remove the onground flag for non-players
528 if (check->v.movetype != MOVETYPE_WALK)
529 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
531 VectorCopy (check->v.origin, entorig);
532 VectorCopy (check->v.origin, moved_from[num_moved]);
533 moved_edict[num_moved] = check;
536 // LordHavoc: pusher fixes (teleport train bug, etc)
537 savesolid = pusher->v.solid;
538 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
540 // try moving the contacted entity
541 pusher->v.solid = SOLID_NOT;
542 SV_PushEntity (check, move);
543 pusher->v.solid = savesolid; // was SOLID_BSP
545 // if it is still inside the pusher, block
546 if (SV_TestEntityPosition (check))
548 if (check->v.mins[0] == check->v.maxs[0])
550 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
552 check->v.mins[0] = check->v.mins[1] = 0;
553 VectorCopy (check->v.mins, check->v.maxs);
557 VectorCopy (entorig, check->v.origin);
558 SV_LinkEdict (check, true);
560 VectorCopy (pushorig, pusher->v.origin);
561 SV_LinkEdict (pusher, false);
562 pusher->v.ltime -= movetime;
564 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
565 if (pusher->v.blocked)
567 pr_global_struct->self = EDICT_TO_PROG(pusher);
568 pr_global_struct->other = EDICT_TO_PROG(check);
569 PR_ExecuteProgram (pusher->v.blocked, "");
572 // move back any entities we already moved
573 num_moved--; // LordHavoc: pop off check, because it was already restored
574 for (i=0 ; i<num_moved ; i++)
576 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
577 SV_LinkEdict (moved_edict[i], false);
593 void SV_PushRotate (edict_t *pusher, float movetime)
597 vec3_t move, a, amove;
598 vec3_t entorigin, entangles, pushorigin, pushangles;
600 edict_t *moved_edict[MAX_EDICTS];
601 vec3_t moved_from[MAX_EDICTS];
602 vec3_t angled_from[MAX_EDICTS];
604 vec3_t forward, right, up;
607 switch ((int) pusher->v.solid)
609 // LordHavoc: valid pusher types
613 case SOLID_CORPSE: // LordHavoc: this would be weird...
615 // LordHavoc: no collisions
618 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
619 pusher->v.ltime += movetime;
620 SV_LinkEdict (pusher, false);
623 Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
625 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
627 pusher->v.ltime += movetime;
631 for (i=0 ; i<3 ; i++)
632 amove[i] = pusher->v.avelocity[i] * movetime;
634 VectorNegate (amove, a);
635 AngleVectors (a, forward, right, up);
637 VectorCopy (pusher->v.origin, pushorigin);
638 VectorCopy (pusher->v.angles, pushangles);
640 // move the pusher to it's final position
642 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
643 pusher->v.ltime += movetime;
644 SV_LinkEdict (pusher, false);
647 // see if any solid entities are inside the final position
649 check = NEXT_EDICT(sv.edicts);
650 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
654 if (check->v.movetype == MOVETYPE_PUSH
655 || check->v.movetype == MOVETYPE_NONE
656 || check->v.movetype == MOVETYPE_FOLLOW
657 || check->v.movetype == MOVETYPE_NOCLIP)
660 // if the entity is standing on the pusher, it will definately be moved
661 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
663 if (check->v.absmin[0] >= pusher->v.absmax[0]
664 || check->v.absmin[1] >= pusher->v.absmax[1]
665 || check->v.absmin[2] >= pusher->v.absmax[2]
666 || check->v.absmax[0] <= pusher->v.absmin[0]
667 || check->v.absmax[1] <= pusher->v.absmin[1]
668 || check->v.absmax[2] <= pusher->v.absmin[2])
671 // see if the ent's bbox is inside the pusher's final position
672 if (!SV_TestEntityPosition (check))
676 // remove the onground flag for non-players
677 if (check->v.movetype != MOVETYPE_WALK)
678 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
680 VectorCopy (check->v.origin, entorigin);
681 VectorCopy (check->v.origin, moved_from[num_moved]);
682 VectorCopy (check->v.angles, entangles);
683 VectorCopy (check->v.angles, angled_from[num_moved]);
684 moved_edict[num_moved] = check;
687 // calculate destination position
688 VectorSubtract (check->v.origin, pusher->v.origin, org);
689 org2[0] = DotProduct (org, forward);
690 org2[1] = -DotProduct (org, right);
691 org2[2] = DotProduct (org, up);
692 VectorSubtract (org2, org, move);
694 // try moving the contacted entity
695 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
696 pusher->v.solid = SOLID_NOT;
697 SV_PushEntity (check, move);
698 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
700 VectorAdd (check->v.angles, amove, check->v.angles);
702 // if it is still inside the pusher, block
703 if (SV_TestEntityPosition (check))
705 if (check->v.mins[0] == check->v.maxs[0])
707 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
709 check->v.mins[0] = check->v.mins[1] = 0;
710 VectorCopy (check->v.mins, check->v.maxs);
714 VectorCopy (entorigin, check->v.origin);
715 VectorCopy (entangles, check->v.angles);
716 SV_LinkEdict (check, true);
718 VectorCopy (pushorigin, pusher->v.origin);
719 VectorCopy (pushangles, pusher->v.angles);
720 SV_LinkEdict (pusher, false);
721 pusher->v.ltime -= movetime;
723 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
724 if (pusher->v.blocked)
726 pr_global_struct->self = EDICT_TO_PROG(pusher);
727 pr_global_struct->other = EDICT_TO_PROG(check);
728 PR_ExecuteProgram (pusher->v.blocked, "");
731 // move back any entities we already moved
732 num_moved--; // LordHavoc: pop off check, because it was already restored
733 for (i=0 ; i<num_moved ; i++)
735 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
736 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
737 SV_LinkEdict (moved_edict[i], false);
750 void SV_Physics_Pusher (edict_t *ent)
756 oldltime = ent->v.ltime;
758 thinktime = ent->v.nextthink;
759 if (thinktime < ent->v.ltime + sv.frametime)
761 movetime = thinktime - ent->v.ltime;
766 movetime = sv.frametime;
770 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
771 SV_PushRotate (ent, movetime);
773 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
776 if (thinktime > oldltime && thinktime <= ent->v.ltime)
778 ent->v.nextthink = 0;
779 pr_global_struct->time = sv.time;
780 pr_global_struct->self = EDICT_TO_PROG(ent);
781 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
782 PR_ExecuteProgram (ent->v.think, "NULL think function");
791 ===============================================================================
795 ===============================================================================
802 This is a big hack to try and fix the rare case of getting stuck in the world
806 void SV_CheckStuck (edict_t *ent)
812 if (!SV_TestEntityPosition(ent))
814 VectorCopy (ent->v.origin, ent->v.oldorigin);
818 VectorCopy (ent->v.origin, org);
819 VectorCopy (ent->v.oldorigin, ent->v.origin);
820 if (!SV_TestEntityPosition(ent))
822 Con_DPrintf ("Unstuck.\n");
823 SV_LinkEdict (ent, true);
827 for (z=0 ; z< 18 ; z++)
828 for (i=-1 ; i <= 1 ; i++)
829 for (j=-1 ; j <= 1 ; j++)
831 ent->v.origin[0] = org[0] + i;
832 ent->v.origin[1] = org[1] + j;
833 ent->v.origin[2] = org[2] + z;
834 if (!SV_TestEntityPosition(ent))
836 Con_DPrintf ("Unstuck.\n");
837 SV_LinkEdict (ent, true);
842 VectorCopy (org, ent->v.origin);
843 Con_DPrintf ("player is stuck.\n");
852 qboolean SV_CheckWater (edict_t *ent)
857 point[0] = ent->v.origin[0];
858 point[1] = ent->v.origin[1];
859 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
861 ent->v.waterlevel = 0;
862 ent->v.watertype = CONTENTS_EMPTY;
863 cont = SV_PointContents (point);
864 if (cont <= CONTENTS_WATER)
866 ent->v.watertype = cont;
867 ent->v.waterlevel = 1;
868 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
869 cont = SV_PointContents (point);
870 if (cont <= CONTENTS_WATER)
872 ent->v.waterlevel = 2;
873 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
874 cont = SV_PointContents (point);
875 if (cont <= CONTENTS_WATER)
876 ent->v.waterlevel = 3;
880 return ent->v.waterlevel > 1;
889 void SV_WallFriction (edict_t *ent, trace_t *trace)
895 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
896 d = DotProduct (trace->plane.normal, forward);
902 // cut the tangential velocity
903 i = DotProduct (trace->plane.normal, ent->v.velocity);
904 VectorScale (trace->plane.normal, i, into);
905 VectorSubtract (ent->v.velocity, into, side);
907 ent->v.velocity[0] = side[0] * (1 + d);
908 ent->v.velocity[1] = side[1] * (1 + d);
912 =====================
915 Player has come to a dead stop, possibly due to the problem with limited
916 float precision at some angle joins in the BSP hull.
918 Try fixing by pushing one pixel in each direction.
920 This is a hack, but in the interest of good gameplay...
921 ======================
923 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
931 VectorCopy (ent->v.origin, oldorg);
934 for (i=0 ; i<8 ; i++)
936 // try pushing a little in an axial direction
939 case 0: dir[0] = 2; dir[1] = 0; break;
940 case 1: dir[0] = 0; dir[1] = 2; break;
941 case 2: dir[0] = -2; dir[1] = 0; break;
942 case 3: dir[0] = 0; dir[1] = -2; break;
943 case 4: dir[0] = 2; dir[1] = 2; break;
944 case 5: dir[0] = -2; dir[1] = 2; break;
945 case 6: dir[0] = 2; dir[1] = -2; break;
946 case 7: dir[0] = -2; dir[1] = -2; break;
949 SV_PushEntity (ent, dir);
951 // retry the original move
952 ent->v.velocity[0] = oldvel[0];
953 ent->v.velocity[1] = oldvel[1];
954 ent->v.velocity[2] = 0;
955 clip = SV_FlyMove (ent, 0.1, &steptrace);
957 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
958 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
960 //Con_DPrintf ("unstuck!\n");
964 // go back to the original pos and try again
965 VectorCopy (oldorg, ent->v.origin);
968 VectorClear (ent->v.velocity);
969 return 7; // still not moving
973 =====================
977 ======================
980 void SV_WalkMove (edict_t *ent)
982 vec3_t upmove, downmove;
983 vec3_t oldorg, oldvel;
984 vec3_t nosteporg, nostepvel;
987 trace_t steptrace, downtrace;
990 // do a regular slide move unless it looks like you ran into a step
992 oldonground = (int)ent->v.flags & FL_ONGROUND;
993 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
995 VectorCopy (ent->v.origin, oldorg);
996 VectorCopy (ent->v.velocity, oldvel);
998 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
1001 return; // move didn't block on a step
1003 if (!oldonground && ent->v.waterlevel == 0)
1004 return; // don't stair up while jumping
1006 if (ent->v.movetype != MOVETYPE_WALK)
1007 return; // gibbed by a trigger
1009 if (sv_nostep.integer)
1012 if ( (int)sv_player->v.flags & FL_WATERJUMP )
1015 VectorCopy (ent->v.origin, nosteporg);
1016 VectorCopy (ent->v.velocity, nostepvel);
1019 // try moving up and forward to go up a step
1021 VectorCopy (oldorg, ent->v.origin); // back to start pos
1023 VectorClear (upmove);
1024 VectorClear (downmove);
1025 upmove[2] = STEPSIZE;
1026 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
1029 SV_PushEntity (ent, upmove); // FIXME: don't link?
1032 ent->v.velocity[0] = oldvel[0];
1033 ent->v. velocity[1] = oldvel[1];
1034 ent->v. velocity[2] = 0;
1035 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
1037 // check for stuckness, possibly due to the limited precision of floats
1038 // in the clipping hulls
1041 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1042 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1043 { // stepping up didn't make any progress
1044 clip = SV_TryUnstick (ent, oldvel);
1048 // extra friction based on view angle
1050 SV_WallFriction (ent, &steptrace);
1053 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1055 if (downtrace.plane.normal[2] > 0.7)
1057 if (ent->v.solid == SOLID_BSP)
1059 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1060 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1065 // if the push down didn't end up on good ground, use the move without
1066 // the step up. This happens near wall / slope combinations, and can
1067 // cause the player to hop up higher on a slope too steep to climb
1068 VectorCopy (nosteporg, ent->v.origin);
1069 VectorCopy (nostepvel, ent->v.velocity);
1078 Player character actions
1081 void SV_Physics_Client (edict_t *ent, int num)
1083 if ( ! svs.clients[num-1].active )
1084 return; // unconnected slot
1087 // call standard client pre-think
1089 pr_global_struct->time = sv.time;
1090 pr_global_struct->self = EDICT_TO_PROG(ent);
1091 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1096 SV_CheckVelocity (ent);
1099 // decide which move function to call
1101 switch ((int)ent->v.movetype)
1104 if (!SV_RunThink (ent))
1109 if (!SV_RunThink (ent))
1111 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1112 SV_AddGravity (ent);
1113 SV_CheckStuck (ent);
1118 case MOVETYPE_BOUNCE:
1119 SV_Physics_Toss (ent);
1123 if (!SV_RunThink (ent))
1125 SV_CheckWater (ent);
1126 SV_FlyMove (ent, sv.frametime, NULL);
1129 case MOVETYPE_NOCLIP:
1130 if (!SV_RunThink (ent))
1132 SV_CheckWater (ent);
1133 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1137 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1141 // call standard player post-think
1143 SV_LinkEdict (ent, true);
1145 pr_global_struct->time = sv.time;
1146 pr_global_struct->self = EDICT_TO_PROG(ent);
1147 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1150 //============================================================================
1156 Non moving objects can only think
1159 // LordHavoc: inlined manually because it was a real time waster
1161 void SV_Physics_None (edict_t *ent)
1172 Entities that are "stuck" to another entity
1175 void SV_Physics_Follow (edict_t *ent)
1177 vec3_t vf, vr, vu, angles, v;
1180 if (!SV_RunThink (ent))
1182 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1183 e = PROG_TO_EDICT(ent->v.aiment);
1184 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])
1186 // quick case for no rotation
1187 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1191 angles[0] = -ent->v.punchangle[0];
1192 angles[1] = ent->v.punchangle[1];
1193 angles[2] = ent->v.punchangle[2];
1194 AngleVectors (angles, vf, vr, vu);
1195 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1196 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1197 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1198 angles[0] = -e->v.angles[0];
1199 angles[1] = e->v.angles[1];
1200 angles[2] = e->v.angles[2];
1201 AngleVectors (angles, vf, vr, vu);
1202 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1203 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1204 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1206 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];
1207 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];
1208 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];
1211 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1212 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1213 SV_LinkEdict (ent, true);
1220 A moving object that doesn't obey physics
1223 void SV_Physics_Noclip (edict_t *ent)
1226 if (!SV_RunThink (ent))
1229 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1230 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1232 SV_LinkEdict (ent, false);
1236 ==============================================================================
1240 ==============================================================================
1245 SV_CheckWaterTransition
1249 void SV_CheckWaterTransition (edict_t *ent)
1252 cont = SV_PointContents (ent->v.origin);
1253 if (!ent->v.watertype)
1254 { // just spawned here
1255 ent->v.watertype = cont;
1256 ent->v.waterlevel = 1;
1260 if (cont <= CONTENTS_WATER)
1262 if (ent->v.watertype == CONTENTS_EMPTY)
1263 { // just crossed into water
1264 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1266 ent->v.watertype = cont;
1267 ent->v.waterlevel = 1;
1271 if (ent->v.watertype != CONTENTS_EMPTY)
1272 { // just crossed into water
1273 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1275 ent->v.watertype = CONTENTS_EMPTY;
1276 ent->v.waterlevel = cont;
1284 Toss, bounce, and fly movement. When onground, do nothing.
1287 void SV_Physics_Toss (edict_t *ent)
1292 edict_t *groundentity;
1294 if (!SV_RunThink (ent))
1297 // if onground, return without moving
1298 if ( ((int)ent->v.flags & FL_ONGROUND) )
1300 // LordHavoc: fall if the groundentity was removed
1301 if (ent->v.groundentity)
1303 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1304 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1308 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1310 SV_CheckVelocity (ent);
1313 if (ent->v.movetype != MOVETYPE_FLY
1314 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1315 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1316 SV_AddGravity (ent);
1319 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1322 VectorScale (ent->v.velocity, sv.frametime, move);
1323 trace = SV_PushEntity (ent, move);
1324 if (trace.fraction == 1)
1329 if (ent->v.movetype == MOVETYPE_BOUNCE)
1331 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1336 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1338 // stop if on ground
1339 if (trace.plane.normal[2] > 0.7)
1341 // LordHavoc: fixed grenades not bouncing when fired down a slope
1342 if (fabs(ent->v.velocity[2]) < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1343 //if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1345 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1346 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1347 VectorClear (ent->v.velocity);
1348 VectorClear (ent->v.avelocity);
1351 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1354 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1356 // check for in water
1357 SV_CheckWaterTransition (ent);
1361 ===============================================================================
1365 ===============================================================================
1372 Monsters freefall when they don't have a ground entity, otherwise
1373 all movement is done with discrete steps.
1375 This is also used for objects that have become still on the ground, but
1376 will fall if the floor is pulled out from under them.
1379 void SV_Physics_Step (edict_t *ent)
1383 // freefall if not onground
1384 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1386 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1391 SV_AddGravity (ent);
1392 SV_CheckVelocity (ent);
1393 SV_FlyMove (ent, sv.frametime, NULL);
1394 SV_LinkEdict (ent, true);
1396 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1399 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1406 SV_CheckWaterTransition (ent);
1409 //============================================================================
1417 void SV_Physics (void)
1422 // let the progs know that a new frame has started
1423 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1424 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1425 pr_global_struct->time = sv.time;
1426 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1428 //SV_CheckAllEnts ();
1431 // treat each object in turn
1434 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1439 if (pr_global_struct->force_retouch)
1440 SV_LinkEdict (ent, true); // force retouch even for stationary
1442 if (i > 0 && i <= svs.maxclients)
1444 SV_Physics_Client (ent, i);
1448 switch ((int) ent->v.movetype)
1451 SV_Physics_Pusher (ent);
1454 // SV_Physics_None (ent);
1455 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1456 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1459 case MOVETYPE_FOLLOW:
1460 SV_Physics_Follow (ent);
1462 case MOVETYPE_NOCLIP:
1463 SV_Physics_Noclip (ent);
1466 SV_Physics_Step (ent);
1468 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1470 if (SV_RunThink (ent))
1472 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1473 SV_AddGravity (ent);
1474 SV_CheckStuck (ent);
1476 SV_LinkEdict (ent, true);
1480 case MOVETYPE_BOUNCE:
1481 case MOVETYPE_BOUNCEMISSILE:
1483 case MOVETYPE_FLYMISSILE:
1484 SV_Physics_Toss (ent);
1487 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1492 if (pr_global_struct->force_retouch)
1493 pr_global_struct->force_retouch--;
1495 // LordHavoc: endframe support
1498 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1499 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1500 pr_global_struct->time = sv.time;
1501 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1504 sv.time += sv.frametime;
1508 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1511 edict_t tempent, *tent;
1516 memcpy(&tempent, ent, sizeof(edict_t));
1519 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1521 SV_CheckVelocity (tent);
1522 SV_AddGravity (tent);
1523 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1524 VectorScale (tent->v.velocity, 0.05, move);
1525 VectorAdd (tent->v.origin, move, end);
1526 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1527 VectorCopy (trace.endpos, tent->v.origin);
1530 if (trace.ent != ignore)
1533 trace.fraction = 0; // not relevant