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;
128 Runs thinking code if time. There is some play in the exact time the think
129 function will be called, because it is called before any movement is done
130 in a frame. Not used for pushmove objects, because they must be exact.
131 Returns false if the entity removed itself.
134 qboolean SV_RunThink (edict_t *ent)
138 thinktime = ent->v.nextthink;
139 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
142 if (thinktime < sv.time)
143 thinktime = sv.time; // don't let things stay in the past.
144 // it is possible to start that way
145 // by a trigger with a local time.
146 ent->v.nextthink = 0;
147 pr_global_struct->time = thinktime;
148 pr_global_struct->self = EDICT_TO_PROG(ent);
149 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
150 PR_ExecuteProgram (ent->v.think, "NULL think function");
158 Two entities have touched, so run their touch functions
161 void SV_Impact (edict_t *e1, edict_t *e2)
163 int old_self, old_other;
165 old_self = pr_global_struct->self;
166 old_other = pr_global_struct->other;
168 pr_global_struct->time = sv.time;
169 if (e1->v.touch && e1->v.solid != SOLID_NOT)
171 pr_global_struct->self = EDICT_TO_PROG(e1);
172 pr_global_struct->other = EDICT_TO_PROG(e2);
173 PR_ExecuteProgram (e1->v.touch, "");
176 if (e2->v.touch && e2->v.solid != SOLID_NOT)
178 pr_global_struct->self = EDICT_TO_PROG(e2);
179 pr_global_struct->other = EDICT_TO_PROG(e1);
180 PR_ExecuteProgram (e2->v.touch, "");
183 pr_global_struct->self = old_self;
184 pr_global_struct->other = old_other;
192 Slide off of the impacting object
193 returns the blocked flags (1 = floor, 2 = step / wall)
196 #define STOP_EPSILON 0.1
198 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
206 blocked |= 1; // floor
208 blocked |= 2; // step
210 backoff = DotProduct (in, normal) * overbounce;
212 for (i=0 ; i<3 ; i++)
214 change = normal[i]*backoff;
215 out[i] = in[i] - change;
216 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
228 The basic solid body movement clip that slides along multiple planes
229 Returns the clipflags if the velocity was modified (hit something solid)
233 If steptrace is not NULL, the trace of any vertical wall hit will be stored
236 // LordHavoc: increased from 5 to 20, to partially fix angled corner sticking
237 // (example - start.bsp hall to e4, leading to the pool there are two
238 // angled corners, which you could get stuck on, now they are just a one
240 #define MAX_CLIP_PLANES 20
241 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
243 int bumpcount, numbumps;
247 vec3_t planes[MAX_CLIP_PLANES];
248 vec3_t primal_velocity, original_velocity, new_velocity;
258 VectorCopy (ent->v.velocity, original_velocity);
259 VectorCopy (ent->v.velocity, primal_velocity);
264 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
266 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
269 for (i=0 ; i<3 ; i++)
270 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
272 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
275 { // entity is trapped in another solid
276 VectorClear(ent->v.velocity);
280 if (trace.fraction > 0)
281 { // actually covered some distance
282 VectorCopy (trace.endpos, ent->v.origin);
283 VectorCopy (ent->v.velocity, original_velocity);
287 if (trace.fraction == 1)
288 break; // moved the entire distance
291 Host_Error ("SV_FlyMove: !trace.ent");
293 if (trace.plane.normal[2] > 0.7)
295 blocked |= 1; // floor
296 if (trace.ent->v.solid == SOLID_BSP)
298 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
299 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
302 if (!trace.plane.normal[2])
304 blocked |= 2; // step
306 *steptrace = trace; // save for player extrafriction
310 // run the impact function
312 SV_Impact (ent, trace.ent);
314 break; // removed by the impact function
317 time_left -= time_left * trace.fraction;
319 // cliped to another plane
320 if (numplanes >= MAX_CLIP_PLANES)
321 { // this shouldn't really happen
322 VectorClear(ent->v.velocity);
326 VectorCopy (trace.plane.normal, planes[numplanes]);
330 // modify original_velocity so it parallels all of the clip planes
332 for (i=0 ; i<numplanes ; i++)
334 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
335 for (j=0 ; j<numplanes ; j++)
338 if (DotProduct (new_velocity, planes[j]) < 0)
346 { // go along this plane
347 VectorCopy (new_velocity, ent->v.velocity);
350 { // go along the crease
353 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
354 VectorClear(ent->v.velocity);
357 CrossProduct (planes[0], planes[1], dir);
358 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
359 VectorNormalize(dir);
360 d = DotProduct (dir, ent->v.velocity);
361 VectorScale (dir, d, ent->v.velocity);
365 // if original velocity is against the original velocity, stop dead
366 // to avoid tiny occilations in sloping corners
368 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
370 VectorClear(ent->v.velocity);
385 void SV_AddGravity (edict_t *ent)
391 val = GETEDICTFIELDVALUE(ent, eval_gravity);
392 if (val!=0 && val->_float)
393 ent_gravity = val->_float;
396 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
401 ===============================================================================
405 ===============================================================================
412 Does not change the entities velocity at all
415 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
420 VectorAdd (ent->v.origin, push, end);
422 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
423 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
424 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
425 // only clip against bmodels
426 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
428 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
430 VectorCopy (trace.endpos, ent->v.origin);
431 SV_LinkEdict (ent, true);
434 SV_Impact (ent, trace.ent);
446 void SV_PushMove (edict_t *pusher, float movetime)
450 vec3_t mins, maxs, move;
451 vec3_t entorig, pushorig;
453 edict_t *moved_edict[MAX_EDICTS];
454 vec3_t moved_from[MAX_EDICTS];
457 switch ((int) pusher->v.solid)
459 // LordHavoc: valid pusher types
463 case SOLID_CORPSE: // LordHavoc: this would be weird...
465 // LordHavoc: no collisions
468 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
469 pusher->v.ltime += movetime;
470 SV_LinkEdict (pusher, false);
473 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
475 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
477 pusher->v.ltime += movetime;
481 for (i=0 ; i<3 ; i++)
483 move[i] = pusher->v.velocity[i] * movetime;
484 mins[i] = pusher->v.absmin[i] + move[i];
485 maxs[i] = pusher->v.absmax[i] + move[i];
488 VectorCopy (pusher->v.origin, pushorig);
490 // move the pusher to it's final position
492 VectorAdd (pusher->v.origin, move, pusher->v.origin);
493 pusher->v.ltime += movetime;
494 SV_LinkEdict (pusher, false);
497 // see if any solid entities are inside the final position
499 check = NEXT_EDICT(sv.edicts);
500 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
504 if (check->v.movetype == MOVETYPE_PUSH
505 || check->v.movetype == MOVETYPE_NONE
506 || check->v.movetype == MOVETYPE_FOLLOW
507 || check->v.movetype == MOVETYPE_NOCLIP)
510 // if the entity is standing on the pusher, it will definitely be moved
511 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
513 if (check->v.absmin[0] >= maxs[0]
514 || check->v.absmin[1] >= maxs[1]
515 || check->v.absmin[2] >= maxs[2]
516 || check->v.absmax[0] <= mins[0]
517 || check->v.absmax[1] <= mins[1]
518 || check->v.absmax[2] <= mins[2])
521 // see if the ent's bbox is inside the pusher's final position
522 if (!SV_TestEntityPosition (check))
526 // remove the onground flag for non-players
527 if (check->v.movetype != MOVETYPE_WALK)
528 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
530 VectorCopy (check->v.origin, entorig);
531 VectorCopy (check->v.origin, moved_from[num_moved]);
532 moved_edict[num_moved] = check;
535 // LordHavoc: pusher fixes (teleport train bug, etc)
536 savesolid = pusher->v.solid;
537 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
539 // try moving the contacted entity
540 pusher->v.solid = SOLID_NOT;
541 SV_PushEntity (check, move);
542 pusher->v.solid = savesolid; // was SOLID_BSP
544 // if it is still inside the pusher, block
545 if (SV_TestEntityPosition (check))
547 if (check->v.mins[0] == check->v.maxs[0])
549 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
551 check->v.mins[0] = check->v.mins[1] = 0;
552 VectorCopy (check->v.mins, check->v.maxs);
556 VectorCopy (entorig, check->v.origin);
557 SV_LinkEdict (check, true);
559 VectorCopy (pushorig, pusher->v.origin);
560 SV_LinkEdict (pusher, false);
561 pusher->v.ltime -= movetime;
563 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
564 if (pusher->v.blocked)
566 pr_global_struct->self = EDICT_TO_PROG(pusher);
567 pr_global_struct->other = EDICT_TO_PROG(check);
568 PR_ExecuteProgram (pusher->v.blocked, "");
571 // move back any entities we already moved
572 num_moved--; // LordHavoc: pop off check, because it was already restored
573 for (i=0 ; i<num_moved ; i++)
575 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
576 SV_LinkEdict (moved_edict[i], false);
592 void SV_PushRotate (edict_t *pusher, float movetime)
596 vec3_t move, a, amove;
597 vec3_t entorigin, entangles, pushorigin, pushangles;
599 edict_t *moved_edict[MAX_EDICTS];
600 vec3_t moved_from[MAX_EDICTS];
601 vec3_t angled_from[MAX_EDICTS];
603 vec3_t forward, right, up;
606 switch ((int) pusher->v.solid)
608 // LordHavoc: valid pusher types
612 case SOLID_CORPSE: // LordHavoc: this would be weird...
614 // LordHavoc: no collisions
617 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
618 pusher->v.ltime += movetime;
619 SV_LinkEdict (pusher, false);
622 Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
624 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
626 pusher->v.ltime += movetime;
630 for (i=0 ; i<3 ; i++)
631 amove[i] = pusher->v.avelocity[i] * movetime;
633 VectorNegate (amove, a);
634 AngleVectors (a, forward, right, up);
636 VectorCopy (pusher->v.origin, pushorigin);
637 VectorCopy (pusher->v.angles, pushangles);
639 // move the pusher to it's final position
641 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
642 pusher->v.ltime += movetime;
643 SV_LinkEdict (pusher, false);
646 // see if any solid entities are inside the final position
648 check = NEXT_EDICT(sv.edicts);
649 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
653 if (check->v.movetype == MOVETYPE_PUSH
654 || check->v.movetype == MOVETYPE_NONE
655 || check->v.movetype == MOVETYPE_FOLLOW
656 || check->v.movetype == MOVETYPE_NOCLIP)
659 // if the entity is standing on the pusher, it will definately be moved
660 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
662 if (check->v.absmin[0] >= pusher->v.absmax[0]
663 || check->v.absmin[1] >= pusher->v.absmax[1]
664 || check->v.absmin[2] >= pusher->v.absmax[2]
665 || check->v.absmax[0] <= pusher->v.absmin[0]
666 || check->v.absmax[1] <= pusher->v.absmin[1]
667 || check->v.absmax[2] <= pusher->v.absmin[2])
670 // see if the ent's bbox is inside the pusher's final position
671 if (!SV_TestEntityPosition (check))
675 // remove the onground flag for non-players
676 if (check->v.movetype != MOVETYPE_WALK)
677 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
679 VectorCopy (check->v.origin, entorigin);
680 VectorCopy (check->v.origin, moved_from[num_moved]);
681 VectorCopy (check->v.angles, entangles);
682 VectorCopy (check->v.angles, angled_from[num_moved]);
683 moved_edict[num_moved] = check;
686 // calculate destination position
687 VectorSubtract (check->v.origin, pusher->v.origin, org);
688 org2[0] = DotProduct (org, forward);
689 org2[1] = -DotProduct (org, right);
690 org2[2] = DotProduct (org, up);
691 VectorSubtract (org2, org, move);
693 // try moving the contacted entity
694 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
695 pusher->v.solid = SOLID_NOT;
696 SV_PushEntity (check, move);
697 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
699 VectorAdd (check->v.angles, amove, check->v.angles);
701 // if it is still inside the pusher, block
702 if (SV_TestEntityPosition (check))
704 if (check->v.mins[0] == check->v.maxs[0])
706 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
708 check->v.mins[0] = check->v.mins[1] = 0;
709 VectorCopy (check->v.mins, check->v.maxs);
713 VectorCopy (entorigin, check->v.origin);
714 VectorCopy (entangles, check->v.angles);
715 SV_LinkEdict (check, true);
717 VectorCopy (pushorigin, pusher->v.origin);
718 VectorCopy (pushangles, pusher->v.angles);
719 SV_LinkEdict (pusher, false);
720 pusher->v.ltime -= movetime;
722 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
723 if (pusher->v.blocked)
725 pr_global_struct->self = EDICT_TO_PROG(pusher);
726 pr_global_struct->other = EDICT_TO_PROG(check);
727 PR_ExecuteProgram (pusher->v.blocked, "");
730 // move back any entities we already moved
731 num_moved--; // LordHavoc: pop off check, because it was already restored
732 for (i=0 ; i<num_moved ; i++)
734 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
735 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
736 SV_LinkEdict (moved_edict[i], false);
749 void SV_Physics_Pusher (edict_t *ent)
755 oldltime = ent->v.ltime;
757 thinktime = ent->v.nextthink;
758 if (thinktime < ent->v.ltime + sv.frametime)
760 movetime = thinktime - ent->v.ltime;
765 movetime = sv.frametime;
769 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
770 SV_PushRotate (ent, movetime);
772 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
775 if (thinktime > oldltime && thinktime <= ent->v.ltime)
777 ent->v.nextthink = 0;
778 pr_global_struct->time = sv.time;
779 pr_global_struct->self = EDICT_TO_PROG(ent);
780 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
781 PR_ExecuteProgram (ent->v.think, "NULL think function");
790 ===============================================================================
794 ===============================================================================
801 This is a big hack to try and fix the rare case of getting stuck in the world
805 void SV_CheckStuck (edict_t *ent)
811 if (!SV_TestEntityPosition(ent))
813 VectorCopy (ent->v.origin, ent->v.oldorigin);
817 VectorCopy (ent->v.origin, org);
818 VectorCopy (ent->v.oldorigin, ent->v.origin);
819 if (!SV_TestEntityPosition(ent))
821 Con_DPrintf ("Unstuck.\n");
822 SV_LinkEdict (ent, true);
826 for (z=0 ; z< 18 ; z++)
827 for (i=-1 ; i <= 1 ; i++)
828 for (j=-1 ; j <= 1 ; j++)
830 ent->v.origin[0] = org[0] + i;
831 ent->v.origin[1] = org[1] + j;
832 ent->v.origin[2] = org[2] + z;
833 if (!SV_TestEntityPosition(ent))
835 Con_DPrintf ("Unstuck.\n");
836 SV_LinkEdict (ent, true);
841 VectorCopy (org, ent->v.origin);
842 Con_DPrintf ("player is stuck.\n");
851 qboolean SV_CheckWater (edict_t *ent)
856 point[0] = ent->v.origin[0];
857 point[1] = ent->v.origin[1];
858 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
860 ent->v.waterlevel = 0;
861 ent->v.watertype = CONTENTS_EMPTY;
862 cont = SV_PointContents (point);
863 if (cont <= CONTENTS_WATER)
865 ent->v.watertype = cont;
866 ent->v.waterlevel = 1;
867 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
868 cont = SV_PointContents (point);
869 if (cont <= CONTENTS_WATER)
871 ent->v.waterlevel = 2;
872 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
873 cont = SV_PointContents (point);
874 if (cont <= CONTENTS_WATER)
875 ent->v.waterlevel = 3;
879 return ent->v.waterlevel > 1;
888 void SV_WallFriction (edict_t *ent, trace_t *trace)
894 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
895 d = DotProduct (trace->plane.normal, forward);
901 // cut the tangential velocity
902 i = DotProduct (trace->plane.normal, ent->v.velocity);
903 VectorScale (trace->plane.normal, i, into);
904 VectorSubtract (ent->v.velocity, into, side);
906 ent->v.velocity[0] = side[0] * (1 + d);
907 ent->v.velocity[1] = side[1] * (1 + d);
911 =====================
914 Player has come to a dead stop, possibly due to the problem with limited
915 float precision at some angle joins in the BSP hull.
917 Try fixing by pushing one pixel in each direction.
919 This is a hack, but in the interest of good gameplay...
920 ======================
922 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
930 VectorCopy (ent->v.origin, oldorg);
933 for (i=0 ; i<8 ; i++)
935 // try pushing a little in an axial direction
938 case 0: dir[0] = 2; dir[1] = 0; break;
939 case 1: dir[0] = 0; dir[1] = 2; break;
940 case 2: dir[0] = -2; dir[1] = 0; break;
941 case 3: dir[0] = 0; dir[1] = -2; break;
942 case 4: dir[0] = 2; dir[1] = 2; break;
943 case 5: dir[0] = -2; dir[1] = 2; break;
944 case 6: dir[0] = 2; dir[1] = -2; break;
945 case 7: dir[0] = -2; dir[1] = -2; break;
948 SV_PushEntity (ent, dir);
950 // retry the original move
951 ent->v.velocity[0] = oldvel[0];
952 ent->v.velocity[1] = oldvel[1];
953 ent->v.velocity[2] = 0;
954 clip = SV_FlyMove (ent, 0.1, &steptrace);
956 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
957 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
959 //Con_DPrintf ("unstuck!\n");
963 // go back to the original pos and try again
964 VectorCopy (oldorg, ent->v.origin);
967 VectorClear (ent->v.velocity);
968 return 7; // still not moving
972 =====================
976 ======================
979 void SV_WalkMove (edict_t *ent)
981 vec3_t upmove, downmove;
982 vec3_t oldorg, oldvel;
983 vec3_t nosteporg, nostepvel;
986 trace_t steptrace, downtrace;
989 // do a regular slide move unless it looks like you ran into a step
991 oldonground = (int)ent->v.flags & FL_ONGROUND;
992 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
994 VectorCopy (ent->v.origin, oldorg);
995 VectorCopy (ent->v.velocity, oldvel);
997 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
1000 return; // move didn't block on a step
1002 if (!oldonground && ent->v.waterlevel == 0)
1003 return; // don't stair up while jumping
1005 if (ent->v.movetype != MOVETYPE_WALK)
1006 return; // gibbed by a trigger
1008 if (sv_nostep.integer)
1011 if ( (int)sv_player->v.flags & FL_WATERJUMP )
1014 VectorCopy (ent->v.origin, nosteporg);
1015 VectorCopy (ent->v.velocity, nostepvel);
1018 // try moving up and forward to go up a step
1020 VectorCopy (oldorg, ent->v.origin); // back to start pos
1022 VectorClear (upmove);
1023 VectorClear (downmove);
1024 upmove[2] = STEPSIZE;
1025 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
1028 SV_PushEntity (ent, upmove); // FIXME: don't link?
1031 ent->v.velocity[0] = oldvel[0];
1032 ent->v. velocity[1] = oldvel[1];
1033 ent->v. velocity[2] = 0;
1034 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
1036 // check for stuckness, possibly due to the limited precision of floats
1037 // in the clipping hulls
1040 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1041 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1042 { // stepping up didn't make any progress
1043 clip = SV_TryUnstick (ent, oldvel);
1047 // extra friction based on view angle
1049 SV_WallFriction (ent, &steptrace);
1052 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1054 if (downtrace.plane.normal[2] > 0.7)
1056 if (ent->v.solid == SOLID_BSP)
1058 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1059 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1064 // if the push down didn't end up on good ground, use the move without
1065 // the step up. This happens near wall / slope combinations, and can
1066 // cause the player to hop up higher on a slope too steep to climb
1067 VectorCopy (nosteporg, ent->v.origin);
1068 VectorCopy (nostepvel, ent->v.velocity);
1077 Player character actions
1080 void SV_Physics_Client (edict_t *ent, int num)
1082 if ( ! svs.clients[num-1].active )
1083 return; // unconnected slot
1086 // call standard client pre-think
1088 pr_global_struct->time = sv.time;
1089 pr_global_struct->self = EDICT_TO_PROG(ent);
1090 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1095 SV_CheckVelocity (ent);
1098 // decide which move function to call
1100 switch ((int)ent->v.movetype)
1103 if (!SV_RunThink (ent))
1108 if (!SV_RunThink (ent))
1110 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1111 SV_AddGravity (ent);
1112 SV_CheckStuck (ent);
1117 case MOVETYPE_BOUNCE:
1118 SV_Physics_Toss (ent);
1122 if (!SV_RunThink (ent))
1124 SV_CheckWater (ent);
1125 SV_FlyMove (ent, sv.frametime, NULL);
1128 case MOVETYPE_NOCLIP:
1129 if (!SV_RunThink (ent))
1131 SV_CheckWater (ent);
1132 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1136 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1140 // call standard player post-think
1142 SV_LinkEdict (ent, true);
1144 pr_global_struct->time = sv.time;
1145 pr_global_struct->self = EDICT_TO_PROG(ent);
1146 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1149 //============================================================================
1155 Non moving objects can only think
1158 // LordHavoc: inlined manually because it was a real time waster
1160 void SV_Physics_None (edict_t *ent)
1171 Entities that are "stuck" to another entity
1174 void SV_Physics_Follow (edict_t *ent)
1176 vec3_t vf, vr, vu, angles, v;
1179 if (!SV_RunThink (ent))
1181 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1182 e = PROG_TO_EDICT(ent->v.aiment);
1183 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])
1185 // quick case for no rotation
1186 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1190 angles[0] = -ent->v.punchangle[0];
1191 angles[1] = ent->v.punchangle[1];
1192 angles[2] = ent->v.punchangle[2];
1193 AngleVectors (angles, vf, vr, vu);
1194 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1195 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1196 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1197 angles[0] = -e->v.angles[0];
1198 angles[1] = e->v.angles[1];
1199 angles[2] = e->v.angles[2];
1200 AngleVectors (angles, vf, vr, vu);
1201 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1202 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1203 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1205 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];
1206 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];
1207 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];
1210 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1211 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1212 SV_LinkEdict (ent, true);
1219 A moving object that doesn't obey physics
1222 void SV_Physics_Noclip (edict_t *ent)
1225 if (!SV_RunThink (ent))
1228 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1229 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1231 SV_LinkEdict (ent, false);
1235 ==============================================================================
1239 ==============================================================================
1244 SV_CheckWaterTransition
1248 void SV_CheckWaterTransition (edict_t *ent)
1251 cont = SV_PointContents (ent->v.origin);
1252 if (!ent->v.watertype)
1253 { // just spawned here
1254 ent->v.watertype = cont;
1255 ent->v.waterlevel = 1;
1259 if (cont <= CONTENTS_WATER)
1261 if (ent->v.watertype == CONTENTS_EMPTY)
1262 { // just crossed into water
1263 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1265 ent->v.watertype = cont;
1266 ent->v.waterlevel = 1;
1270 if (ent->v.watertype != CONTENTS_EMPTY)
1271 { // just crossed into water
1272 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1274 ent->v.watertype = CONTENTS_EMPTY;
1275 ent->v.waterlevel = cont;
1283 Toss, bounce, and fly movement. When onground, do nothing.
1286 void SV_Physics_Toss (edict_t *ent)
1291 edict_t *groundentity;
1293 if (!SV_RunThink (ent))
1296 // if onground, return without moving
1297 if ( ((int)ent->v.flags & FL_ONGROUND) )
1299 // LordHavoc: fall if the groundentity was removed
1300 if (ent->v.groundentity)
1302 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1303 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1307 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1309 SV_CheckVelocity (ent);
1312 if (ent->v.movetype != MOVETYPE_FLY
1313 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1314 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1315 SV_AddGravity (ent);
1318 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1321 VectorScale (ent->v.velocity, sv.frametime, move);
1322 trace = SV_PushEntity (ent, move);
1323 if (trace.fraction == 1)
1328 if (ent->v.movetype == MOVETYPE_BOUNCE)
1330 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1335 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1337 // stop if on ground
1338 if (trace.plane.normal[2] > 0.7)
1340 // LordHavoc: fixed grenades not bouncing when fired down a slope
1341 if (fabs(ent->v.velocity[2]) < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1342 //if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1344 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1345 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1346 VectorClear (ent->v.velocity);
1347 VectorClear (ent->v.avelocity);
1350 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1353 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1355 // check for in water
1356 SV_CheckWaterTransition (ent);
1360 ===============================================================================
1364 ===============================================================================
1371 Monsters freefall when they don't have a ground entity, otherwise
1372 all movement is done with discrete steps.
1374 This is also used for objects that have become still on the ground, but
1375 will fall if the floor is pulled out from under them.
1378 void SV_Physics_Step (edict_t *ent)
1382 // freefall if not onground
1383 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1385 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1390 SV_AddGravity (ent);
1391 SV_CheckVelocity (ent);
1392 SV_FlyMove (ent, sv.frametime, NULL);
1393 SV_LinkEdict (ent, true);
1395 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1398 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1405 SV_CheckWaterTransition (ent);
1408 //============================================================================
1416 void SV_Physics (void)
1421 // let the progs know that a new frame has started
1422 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1423 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1424 pr_global_struct->time = sv.time;
1425 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1427 //SV_CheckAllEnts ();
1430 // treat each object in turn
1433 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1438 if (pr_global_struct->force_retouch)
1439 SV_LinkEdict (ent, true); // force retouch even for stationary
1441 if (i > 0 && i <= svs.maxclients)
1443 SV_Physics_Client (ent, i);
1447 switch ((int) ent->v.movetype)
1450 SV_Physics_Pusher (ent);
1453 // SV_Physics_None (ent);
1454 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1455 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1458 case MOVETYPE_FOLLOW:
1459 SV_Physics_Follow (ent);
1461 case MOVETYPE_NOCLIP:
1462 SV_Physics_Noclip (ent);
1465 SV_Physics_Step (ent);
1467 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1469 if (SV_RunThink (ent))
1471 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1472 SV_AddGravity (ent);
1473 SV_CheckStuck (ent);
1475 SV_LinkEdict (ent, true);
1479 case MOVETYPE_BOUNCE:
1480 case MOVETYPE_BOUNCEMISSILE:
1482 case MOVETYPE_FLYMISSILE:
1483 SV_Physics_Toss (ent);
1486 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1491 if (pr_global_struct->force_retouch)
1492 pr_global_struct->force_retouch--;
1494 // LordHavoc: endframe support
1497 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1498 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1499 pr_global_struct->time = sv.time;
1500 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1503 sv.time += sv.frametime;
1507 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1510 edict_t tempent, *tent;
1514 float gravity, savesolid;
1517 memcpy(&tempent, tossent, sizeof(edict_t));
1519 savesolid = tossent->v.solid;
1520 tossent->v.solid = SOLID_NOT;
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;
1528 gravity *= sv_gravity.value * 0.05;
1530 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
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);
1540 if (trace.fraction < 1 && trace.ent)
1541 if (trace.ent != ignore)
1544 tossent->v.solid = savesolid;
1545 trace.fraction = 0; // not relevant