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 = {"sv_friction","4",false,true};
43 cvar_t sv_stopspeed = {"sv_stopspeed","100"};
44 cvar_t sv_gravity = {"sv_gravity","800",false,true};
45 cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {"sv_nostep","0"};
48 static vec3_t vec_origin = {0.0, 0.0, 0.0};
50 #define MOVE_EPSILON 0.01
52 void SV_Physics_Toss (edict_t *ent);
59 void SV_CheckAllEnts (void)
64 // see if any solid entities are inside the final position
65 check = NEXT_EDICT(sv.edicts);
66 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
70 if (check->v.movetype == MOVETYPE_PUSH
71 || check->v.movetype == MOVETYPE_NONE
72 || check->v.movetype == MOVETYPE_FOLLOW
73 || check->v.movetype == MOVETYPE_NOCLIP)
76 if (SV_TestEntityPosition (check))
77 Con_Printf ("entity in invalid position\n");
86 void SV_CheckVelocity (edict_t *ent)
96 if (IS_NAN(ent->v.velocity[i]))
98 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
99 ent->v.velocity[i] = 0;
101 if (IS_NAN(ent->v.origin[i]))
103 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
104 ent->v.origin[i] = 0;
106 // LordHavoc: maxvelocity fix, see below
108 if (ent->v.velocity[i] > sv_maxvelocity.value)
109 ent->v.velocity[i] = sv_maxvelocity.value;
110 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
111 ent->v.velocity[i] = -sv_maxvelocity.value;
115 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
116 wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
117 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
119 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
120 ent->v.velocity[0] *= wishspeed;
121 ent->v.velocity[1] *= wishspeed;
122 ent->v.velocity[2] *= wishspeed;
123 wishspeed = sv_maxvelocity.value;
131 Runs thinking code if time. There is some play in the exact time the think
132 function will be called, because it is called before any movement is done
133 in a frame. Not used for pushmove objects, because they must be exact.
134 Returns false if the entity removed itself.
137 qboolean SV_RunThink (edict_t *ent)
141 thinktime = ent->v.nextthink;
142 if (thinktime <= 0 || thinktime > sv.time + host_frametime)
145 if (thinktime < sv.time)
146 thinktime = sv.time; // don't let things stay in the past.
147 // it is possible to start that way
148 // by a trigger with a local time.
149 ent->v.nextthink = 0;
150 pr_global_struct->time = thinktime;
151 pr_global_struct->self = EDICT_TO_PROG(ent);
152 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
153 PR_ExecuteProgram (ent->v.think);
161 Two entities have touched, so run their touch functions
164 void SV_Impact (edict_t *e1, edict_t *e2)
166 int old_self, old_other;
168 old_self = pr_global_struct->self;
169 old_other = pr_global_struct->other;
171 pr_global_struct->time = sv.time;
172 if (e1->v.touch && e1->v.solid != SOLID_NOT)
174 pr_global_struct->self = EDICT_TO_PROG(e1);
175 pr_global_struct->other = EDICT_TO_PROG(e2);
176 PR_ExecuteProgram (e1->v.touch);
179 if (e2->v.touch && e2->v.solid != SOLID_NOT)
181 pr_global_struct->self = EDICT_TO_PROG(e2);
182 pr_global_struct->other = EDICT_TO_PROG(e1);
183 PR_ExecuteProgram (e2->v.touch);
186 pr_global_struct->self = old_self;
187 pr_global_struct->other = old_other;
195 Slide off of the impacting object
196 returns the blocked flags (1 = floor, 2 = step / wall)
199 #define STOP_EPSILON 0.1
201 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
209 blocked |= 1; // floor
211 blocked |= 2; // step
213 backoff = DotProduct (in, normal) * overbounce;
215 for (i=0 ; i<3 ; i++)
217 change = normal[i]*backoff;
218 out[i] = in[i] - change;
219 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
231 The basic solid body movement clip that slides along multiple planes
232 Returns the clipflags if the velocity was modified (hit something solid)
236 If steptrace is not NULL, the trace of any vertical wall hit will be stored
239 #define MAX_CLIP_PLANES 5
240 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
242 int bumpcount, numbumps;
246 vec3_t planes[MAX_CLIP_PLANES];
247 vec3_t primal_velocity, original_velocity, new_velocity;
257 VectorCopy (ent->v.velocity, original_velocity);
258 VectorCopy (ent->v.velocity, primal_velocity);
263 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
265 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
268 for (i=0 ; i<3 ; i++)
269 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
271 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
274 { // entity is trapped in another solid
275 VectorCopy (vec3_origin, ent->v.velocity);
279 if (trace.fraction > 0)
280 { // actually covered some distance
281 VectorCopy (trace.endpos, ent->v.origin);
282 VectorCopy (ent->v.velocity, original_velocity);
286 if (trace.fraction == 1)
287 break; // moved the entire distance
290 Host_Error ("SV_FlyMove: !trace.ent");
292 if (trace.plane.normal[2] > 0.7)
294 blocked |= 1; // floor
295 if (trace.ent->v.solid == SOLID_BSP)
297 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
298 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
301 if (!trace.plane.normal[2])
303 blocked |= 2; // step
305 *steptrace = trace; // save for player extrafriction
309 // run the impact function
311 SV_Impact (ent, trace.ent);
313 break; // removed by the impact function
316 time_left -= time_left * trace.fraction;
318 // cliped to another plane
319 if (numplanes >= MAX_CLIP_PLANES)
320 { // this shouldn't really happen
321 VectorCopy (vec3_origin, ent->v.velocity);
325 VectorCopy (trace.plane.normal, planes[numplanes]);
329 // modify original_velocity so it parallels all of the clip planes
331 for (i=0 ; i<numplanes ; i++)
333 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
334 for (j=0 ; j<numplanes ; j++)
337 if (DotProduct (new_velocity, planes[j]) < 0)
345 { // go along this plane
346 VectorCopy (new_velocity, ent->v.velocity);
349 { // go along the crease
352 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
353 VectorCopy (vec3_origin, ent->v.velocity);
356 CrossProduct (planes[0], planes[1], dir);
357 d = DotProduct (dir, ent->v.velocity);
358 VectorScale (dir, d, ent->v.velocity);
362 // if original velocity is against the original velocity, stop dead
363 // to avoid tiny occilations in sloping corners
365 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
367 VectorCopy (vec3_origin, ent->v.velocity);
382 void SV_AddGravity (edict_t *ent)
388 val = GETEDICTFIELDVALUE(ent, eval_gravity);
389 if (val!=0 && val->_float)
390 ent_gravity = val->_float;
393 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
398 ===============================================================================
402 ===============================================================================
409 Does not change the entities velocity at all
412 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
417 VectorAdd (ent->v.origin, push, end);
419 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
420 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
421 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
422 // only clip against bmodels
423 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
425 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
427 VectorCopy (trace.endpos, ent->v.origin);
428 SV_LinkEdict (ent, true);
431 SV_Impact (ent, trace.ent);
443 void SV_PushMove (edict_t *pusher, float movetime)
446 edict_t *check, *block;
447 vec3_t mins, maxs, move;
448 vec3_t entorig, pushorig;
450 edict_t *moved_edict[MAX_EDICTS];
451 vec3_t moved_from[MAX_EDICTS];
454 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
456 pusher->v.ltime += movetime;
460 for (i=0 ; i<3 ; i++)
462 move[i] = pusher->v.velocity[i] * movetime;
463 mins[i] = pusher->v.absmin[i] + move[i];
464 maxs[i] = pusher->v.absmax[i] + move[i];
467 VectorCopy (pusher->v.origin, pushorig);
469 // move the pusher to it's final position
471 VectorAdd (pusher->v.origin, move, pusher->v.origin);
472 pusher->v.ltime += movetime;
473 SV_LinkEdict (pusher, false);
476 // see if any solid entities are inside the final position
478 check = NEXT_EDICT(sv.edicts);
479 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
483 if (check->v.movetype == MOVETYPE_PUSH
484 || check->v.movetype == MOVETYPE_NONE
485 || check->v.movetype == MOVETYPE_FOLLOW
486 || check->v.movetype == MOVETYPE_NOCLIP)
489 // if the entity is standing on the pusher, it will definitely be moved
490 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
492 if (check->v.absmin[0] >= maxs[0]
493 || check->v.absmin[1] >= maxs[1]
494 || check->v.absmin[2] >= maxs[2]
495 || check->v.absmax[0] <= mins[0]
496 || check->v.absmax[1] <= mins[1]
497 || check->v.absmax[2] <= mins[2])
500 // see if the ent's bbox is inside the pusher's final position
501 if (!SV_TestEntityPosition (check))
505 // remove the onground flag for non-players
506 if (check->v.movetype != MOVETYPE_WALK)
507 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
509 VectorCopy (check->v.origin, entorig);
510 VectorCopy (check->v.origin, moved_from[num_moved]);
511 moved_edict[num_moved] = check;
514 // LordHavoc: pusher fixes (teleport train bug, etc)
515 savesolid = pusher->v.solid;
516 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
518 // try moving the contacted entity
519 pusher->v.solid = SOLID_NOT;
520 SV_PushEntity (check, move);
521 pusher->v.solid = savesolid; // was SOLID_BSP
523 // if it is still inside the pusher, block
524 if (block = SV_TestEntityPosition (check))
526 if (check->v.mins[0] == check->v.maxs[0])
528 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
530 check->v.mins[0] = check->v.mins[1] = 0;
531 VectorCopy (check->v.mins, check->v.maxs);
535 VectorCopy (entorig, check->v.origin);
536 SV_LinkEdict (check, true);
538 VectorCopy (pushorig, pusher->v.origin);
539 SV_LinkEdict (pusher, false);
540 pusher->v.ltime -= movetime;
542 // if the pusher has a "blocked" function, call it
543 // otherwise, just stay in place until the obstacle is gone
544 if (pusher->v.blocked)
546 pr_global_struct->self = EDICT_TO_PROG(pusher);
547 pr_global_struct->other = EDICT_TO_PROG(check);
548 PR_ExecuteProgram (pusher->v.blocked);
551 // move back any entities we already moved
552 for (i=0 ; i<num_moved ; i++)
554 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
555 SV_LinkEdict (moved_edict[i], false);
571 void SV_PushRotate (edict_t *pusher, float movetime)
574 edict_t *check, *block;
575 vec3_t move, a, amove;
576 vec3_t entorig, pushorig;
578 edict_t *moved_edict[MAX_EDICTS];
579 vec3_t moved_from[MAX_EDICTS];
581 vec3_t forward, right, up;
584 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
586 pusher->v.ltime += movetime;
590 for (i=0 ; i<3 ; i++)
591 amove[i] = pusher->v.avelocity[i] * movetime;
593 VectorSubtract (vec3_origin, amove, a);
594 AngleVectors (a, forward, right, up);
596 VectorCopy (pusher->v.angles, pushorig);
598 // move the pusher to it's final position
600 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
601 pusher->v.ltime += movetime;
602 SV_LinkEdict (pusher, false);
605 // see if any solid entities are inside the final position
607 check = NEXT_EDICT(sv.edicts);
608 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
612 if (check->v.movetype == MOVETYPE_PUSH
613 || check->v.movetype == MOVETYPE_NONE
614 || check->v.movetype == MOVETYPE_FOLLOW
615 || check->v.movetype == MOVETYPE_NOCLIP)
618 // if the entity is standing on the pusher, it will definately be moved
619 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
620 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
622 if ( check->v.absmin[0] >= pusher->v.absmax[0]
623 || check->v.absmin[1] >= pusher->v.absmax[1]
624 || check->v.absmin[2] >= pusher->v.absmax[2]
625 || check->v.absmax[0] <= pusher->v.absmin[0]
626 || check->v.absmax[1] <= pusher->v.absmin[1]
627 || check->v.absmax[2] <= pusher->v.absmin[2] )
630 // see if the ent's bbox is inside the pusher's final position
631 if (!SV_TestEntityPosition (check))
635 // remove the onground flag for non-players
636 if (check->v.movetype != MOVETYPE_WALK)
637 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
639 VectorCopy (check->v.origin, entorig);
640 VectorCopy (check->v.origin, moved_from[num_moved]);
641 moved_edict[num_moved] = check;
644 // calculate destination position
645 VectorSubtract (check->v.origin, pusher->v.origin, org);
646 org2[0] = DotProduct (org, forward);
647 org2[1] = -DotProduct (org, right);
648 org2[2] = DotProduct (org, up);
649 VectorSubtract (org2, org, move);
651 // try moving the contacted entity
652 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
653 pusher->v.solid = SOLID_NOT;
654 SV_PushEntity (check, move);
655 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
657 // if it is still inside the pusher, block
658 block = SV_TestEntityPosition (check);
661 if (check->v.mins[0] == check->v.maxs[0])
663 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
665 check->v.mins[0] = check->v.mins[1] = 0;
666 VectorCopy (check->v.mins, check->v.maxs);
670 VectorCopy (entorig, check->v.origin);
671 SV_LinkEdict (check, true);
673 VectorCopy (pushorig, pusher->v.angles);
674 SV_LinkEdict (pusher, false);
675 pusher->v.ltime -= movetime;
677 // if the pusher has a "blocked" function, call it
678 // otherwise, just stay in place until the obstacle is gone
679 if (pusher->v.blocked)
681 pr_global_struct->self = EDICT_TO_PROG(pusher);
682 pr_global_struct->other = EDICT_TO_PROG(check);
683 PR_ExecuteProgram (pusher->v.blocked);
686 // move back any entities we already moved
687 for (i=0 ; i<num_moved ; i++)
689 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
690 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
691 SV_LinkEdict (moved_edict[i], false);
697 VectorAdd (check->v.angles, amove, check->v.angles);
711 void SV_Physics_Pusher (edict_t *ent)
717 oldltime = ent->v.ltime;
719 thinktime = ent->v.nextthink;
720 if (thinktime < ent->v.ltime + host_frametime)
722 movetime = thinktime - ent->v.ltime;
727 movetime = host_frametime;
731 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
732 SV_PushRotate (ent, movetime);
734 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
737 if (thinktime > oldltime && thinktime <= ent->v.ltime)
739 ent->v.nextthink = 0;
740 pr_global_struct->time = sv.time;
741 pr_global_struct->self = EDICT_TO_PROG(ent);
742 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
743 PR_ExecuteProgram (ent->v.think);
752 ===============================================================================
756 ===============================================================================
763 This is a big hack to try and fix the rare case of getting stuck in the world
767 void SV_CheckStuck (edict_t *ent)
773 if (!SV_TestEntityPosition(ent))
775 VectorCopy (ent->v.origin, ent->v.oldorigin);
779 VectorCopy (ent->v.origin, org);
780 VectorCopy (ent->v.oldorigin, ent->v.origin);
781 if (!SV_TestEntityPosition(ent))
783 Con_DPrintf ("Unstuck.\n");
784 SV_LinkEdict (ent, true);
788 for (z=0 ; z< 18 ; z++)
789 for (i=-1 ; i <= 1 ; i++)
790 for (j=-1 ; j <= 1 ; j++)
792 ent->v.origin[0] = org[0] + i;
793 ent->v.origin[1] = org[1] + j;
794 ent->v.origin[2] = org[2] + z;
795 if (!SV_TestEntityPosition(ent))
797 Con_DPrintf ("Unstuck.\n");
798 SV_LinkEdict (ent, true);
803 VectorCopy (org, ent->v.origin);
804 Con_DPrintf ("player is stuck.\n");
813 qboolean SV_CheckWater (edict_t *ent)
818 point[0] = ent->v.origin[0];
819 point[1] = ent->v.origin[1];
820 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
822 ent->v.waterlevel = 0;
823 ent->v.watertype = CONTENTS_EMPTY;
824 cont = SV_PointContents (point);
825 if (cont <= CONTENTS_WATER)
827 ent->v.watertype = cont;
828 ent->v.waterlevel = 1;
829 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
830 cont = SV_PointContents (point);
831 if (cont <= CONTENTS_WATER)
833 ent->v.waterlevel = 2;
834 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
835 cont = SV_PointContents (point);
836 if (cont <= CONTENTS_WATER)
837 ent->v.waterlevel = 3;
841 return ent->v.waterlevel > 1;
850 void SV_WallFriction (edict_t *ent, trace_t *trace)
852 vec3_t forward, right, up;
856 AngleVectors (ent->v.v_angle, forward, right, up);
857 d = DotProduct (trace->plane.normal, forward);
863 // cut the tangential velocity
864 i = DotProduct (trace->plane.normal, ent->v.velocity);
865 VectorScale (trace->plane.normal, i, into);
866 VectorSubtract (ent->v.velocity, into, side);
868 ent->v.velocity[0] = side[0] * (1 + d);
869 ent->v.velocity[1] = side[1] * (1 + d);
873 =====================
876 Player has come to a dead stop, possibly due to the problem with limited
877 float precision at some angle joins in the BSP hull.
879 Try fixing by pushing one pixel in each direction.
881 This is a hack, but in the interest of good gameplay...
882 ======================
884 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
892 VectorCopy (ent->v.origin, oldorg);
893 VectorCopy (vec3_origin, dir);
895 for (i=0 ; i<8 ; i++)
897 // try pushing a little in an axial direction
900 case 0: dir[0] = 2; dir[1] = 0; break;
901 case 1: dir[0] = 0; dir[1] = 2; break;
902 case 2: dir[0] = -2; dir[1] = 0; break;
903 case 3: dir[0] = 0; dir[1] = -2; break;
904 case 4: dir[0] = 2; dir[1] = 2; break;
905 case 5: dir[0] = -2; dir[1] = 2; break;
906 case 6: dir[0] = 2; dir[1] = -2; break;
907 case 7: dir[0] = -2; dir[1] = -2; break;
910 SV_PushEntity (ent, dir);
912 // retry the original move
913 ent->v.velocity[0] = oldvel[0];
914 ent->v. velocity[1] = oldvel[1];
915 ent->v. velocity[2] = 0;
916 clip = SV_FlyMove (ent, 0.1, &steptrace);
918 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
919 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
921 //Con_DPrintf ("unstuck!\n");
925 // go back to the original pos and try again
926 VectorCopy (oldorg, ent->v.origin);
929 VectorCopy (vec3_origin, ent->v.velocity);
930 return 7; // still not moving
934 =====================
938 ======================
941 void SV_WalkMove (edict_t *ent)
943 vec3_t upmove, downmove;
944 vec3_t oldorg, oldvel;
945 vec3_t nosteporg, nostepvel;
948 trace_t steptrace, downtrace;
951 // do a regular slide move unless it looks like you ran into a step
953 oldonground = (int)ent->v.flags & FL_ONGROUND;
954 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
956 VectorCopy (ent->v.origin, oldorg);
957 VectorCopy (ent->v.velocity, oldvel);
959 clip = SV_FlyMove (ent, host_frametime, &steptrace);
962 return; // move didn't block on a step
964 if (!oldonground && ent->v.waterlevel == 0)
965 return; // don't stair up while jumping
967 if (ent->v.movetype != MOVETYPE_WALK)
968 return; // gibbed by a trigger
973 if ( (int)sv_player->v.flags & FL_WATERJUMP )
976 VectorCopy (ent->v.origin, nosteporg);
977 VectorCopy (ent->v.velocity, nostepvel);
980 // try moving up and forward to go up a step
982 VectorCopy (oldorg, ent->v.origin); // back to start pos
984 VectorCopy (vec3_origin, upmove);
985 VectorCopy (vec3_origin, downmove);
986 upmove[2] = STEPSIZE;
987 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
990 SV_PushEntity (ent, upmove); // FIXME: don't link?
993 ent->v.velocity[0] = oldvel[0];
994 ent->v. velocity[1] = oldvel[1];
995 ent->v. velocity[2] = 0;
996 clip = SV_FlyMove (ent, host_frametime, &steptrace);
998 // check for stuckness, possibly due to the limited precision of floats
999 // in the clipping hulls
1002 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1003 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1004 { // stepping up didn't make any progress
1005 clip = SV_TryUnstick (ent, oldvel);
1009 // extra friction based on view angle
1011 SV_WallFriction (ent, &steptrace);
1014 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1016 if (downtrace.plane.normal[2] > 0.7)
1018 if (ent->v.solid == SOLID_BSP)
1020 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1021 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1026 // if the push down didn't end up on good ground, use the move without
1027 // the step up. This happens near wall / slope combinations, and can
1028 // cause the player to hop up higher on a slope too steep to climb
1029 VectorCopy (nosteporg, ent->v.origin);
1030 VectorCopy (nostepvel, ent->v.velocity);
1039 Player character actions
1042 void SV_Physics_Client (edict_t *ent, int num)
1044 if ( ! svs.clients[num-1].active )
1045 return; // unconnected slot
1048 // call standard client pre-think
1050 pr_global_struct->time = sv.time;
1051 pr_global_struct->self = EDICT_TO_PROG(ent);
1052 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1057 SV_CheckVelocity (ent);
1060 // decide which move function to call
1062 switch ((int)ent->v.movetype)
1065 if (!SV_RunThink (ent))
1070 if (!SV_RunThink (ent))
1072 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1073 SV_AddGravity (ent);
1074 SV_CheckStuck (ent);
1079 case MOVETYPE_BOUNCE:
1080 SV_Physics_Toss (ent);
1084 if (!SV_RunThink (ent))
1086 SV_FlyMove (ent, host_frametime, NULL);
1089 case MOVETYPE_NOCLIP:
1090 if (!SV_RunThink (ent))
1092 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1096 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1100 // call standard player post-think
1102 SV_LinkEdict (ent, true);
1104 pr_global_struct->time = sv.time;
1105 pr_global_struct->self = EDICT_TO_PROG(ent);
1106 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1109 //============================================================================
1115 Non moving objects can only think
1118 void SV_Physics_None (edict_t *ent)
1128 Entities that are "stuck" to another entity
1131 void SV_Physics_Follow (edict_t *ent)
1133 vec3_t vf, vu, vr, angles;
1137 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1138 e = PROG_TO_EDICT(ent->v.aiment);
1139 angles[0] = -e->v.angles[0];
1140 angles[1] = e->v.angles[1];
1141 angles[2] = e->v.angles[2];
1142 AngleVectors (angles, vf, vr, vu);
1143 VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin);
1144 VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin);
1145 VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin);
1146 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1147 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1148 SV_LinkEdict (ent, true);
1155 A moving object that doesn't obey physics
1158 void SV_Physics_Noclip (edict_t *ent)
1161 if (!SV_RunThink (ent))
1164 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1165 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1167 SV_LinkEdict (ent, false);
1171 ==============================================================================
1175 ==============================================================================
1180 SV_CheckWaterTransition
1184 void SV_CheckWaterTransition (edict_t *ent)
1187 cont = SV_PointContents (ent->v.origin);
1188 if (!ent->v.watertype)
1189 { // just spawned here
1190 ent->v.watertype = cont;
1191 ent->v.waterlevel = 1;
1195 if (cont <= CONTENTS_WATER)
1197 if (ent->v.watertype == CONTENTS_EMPTY)
1198 { // just crossed into water
1199 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1201 ent->v.watertype = cont;
1202 ent->v.waterlevel = 1;
1206 if (ent->v.watertype != CONTENTS_EMPTY)
1207 { // just crossed into water
1208 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1210 ent->v.watertype = CONTENTS_EMPTY;
1211 ent->v.waterlevel = cont;
1219 Toss, bounce, and fly movement. When onground, do nothing.
1222 void SV_Physics_Toss (edict_t *ent)
1228 if (!SV_RunThink (ent))
1231 // if onground, return without moving
1232 if ( ((int)ent->v.flags & FL_ONGROUND) )
1235 SV_CheckVelocity (ent);
1238 if (ent->v.movetype != MOVETYPE_FLY
1239 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1240 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1241 SV_AddGravity (ent);
1244 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1247 VectorScale (ent->v.velocity, host_frametime, move);
1248 trace = SV_PushEntity (ent, move);
1249 if (trace.fraction == 1)
1254 if (ent->v.movetype == MOVETYPE_BOUNCE)
1256 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1261 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1263 // stop if on ground
1264 if (trace.plane.normal[2] > 0.7)
1266 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1268 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1269 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1270 VectorCopy (vec3_origin, ent->v.velocity);
1271 VectorCopy (vec3_origin, ent->v.avelocity);
1275 // check for in water
1276 SV_CheckWaterTransition (ent);
1280 ===============================================================================
1284 ===============================================================================
1291 Monsters freefall when they don't have a ground entity, otherwise
1292 all movement is done with discrete steps.
1294 This is also used for objects that have become still on the ground, but
1295 will fall if the floor is pulled out from under them.
1298 void SV_Physics_Step (edict_t *ent)
1302 // freefall if not onground
1303 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1305 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1310 SV_AddGravity (ent);
1311 SV_CheckVelocity (ent);
1312 SV_FlyMove (ent, host_frametime, NULL);
1313 SV_LinkEdict (ent, true);
1315 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1318 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1325 SV_CheckWaterTransition (ent);
1328 //============================================================================
1336 extern dfunction_t *EndFrameQC;
1337 void SV_Physics (void)
1342 // let the progs know that a new frame has started
1343 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1344 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1345 pr_global_struct->time = sv.time;
1346 PR_ExecuteProgram (pr_global_struct->StartFrame);
1348 //SV_CheckAllEnts ();
1351 // treat each object in turn
1354 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1359 if (pr_global_struct->force_retouch)
1361 SV_LinkEdict (ent, true); // force retouch even for stationary
1364 if (i > 0 && i <= svs.maxclients)
1365 SV_Physics_Client (ent, i);
1366 else if (ent->v.movetype == MOVETYPE_PUSH)
1367 SV_Physics_Pusher (ent);
1368 else if (ent->v.movetype == MOVETYPE_NONE)
1369 SV_Physics_None (ent);
1370 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1371 SV_Physics_Follow (ent);
1372 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1373 SV_Physics_Noclip (ent);
1374 else if (ent->v.movetype == MOVETYPE_STEP)
1375 SV_Physics_Step (ent);
1376 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1377 else if (ent->v.movetype == MOVETYPE_WALK)
1379 if (SV_RunThink (ent))
1381 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1382 SV_AddGravity (ent);
1383 SV_CheckStuck (ent);
1387 else if (ent->v.movetype == MOVETYPE_TOSS
1388 || ent->v.movetype == MOVETYPE_BOUNCE
1389 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1390 || ent->v.movetype == MOVETYPE_FLY
1391 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1392 SV_Physics_Toss (ent);
1394 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1397 if (pr_global_struct->force_retouch)
1398 pr_global_struct->force_retouch--;
1400 // LordHavoc: endframe support
1403 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1404 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1405 pr_global_struct->time = sv.time;
1406 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1409 sv.time += host_frametime;
1413 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1416 edict_t tempent, *tent;
1420 double save_frametime;
1422 save_frametime = host_frametime;
1423 host_frametime = 0.05;
1425 memcpy(&tempent, ent, sizeof(edict_t));
1428 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1430 SV_CheckVelocity (tent);
1431 SV_AddGravity (tent);
1432 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1433 VectorScale (tent->v.velocity, host_frametime, move);
1434 VectorAdd (tent->v.origin, move, end);
1435 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1436 VectorCopy (trace.endpos, tent->v.origin);
1439 if (trace.ent != ignore)
1442 host_frametime = save_frametime;