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 #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 + host_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);
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 #define MAX_CLIP_PLANES 5
238 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
240 int bumpcount, numbumps;
244 vec3_t planes[MAX_CLIP_PLANES];
245 vec3_t primal_velocity, original_velocity, new_velocity;
255 VectorCopy (ent->v.velocity, original_velocity);
256 VectorCopy (ent->v.velocity, primal_velocity);
261 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
263 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
266 for (i=0 ; i<3 ; i++)
267 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
269 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
272 { // entity is trapped in another solid
273 VectorCopy (vec3_origin, ent->v.velocity);
277 if (trace.fraction > 0)
278 { // actually covered some distance
279 VectorCopy (trace.endpos, ent->v.origin);
280 VectorCopy (ent->v.velocity, original_velocity);
284 if (trace.fraction == 1)
285 break; // moved the entire distance
288 Host_Error ("SV_FlyMove: !trace.ent");
290 if (trace.plane.normal[2] > 0.7)
292 blocked |= 1; // floor
293 if (trace.ent->v.solid == SOLID_BSP)
295 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
296 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
299 if (!trace.plane.normal[2])
301 blocked |= 2; // step
303 *steptrace = trace; // save for player extrafriction
307 // run the impact function
309 SV_Impact (ent, trace.ent);
311 break; // removed by the impact function
314 time_left -= time_left * trace.fraction;
316 // cliped to another plane
317 if (numplanes >= MAX_CLIP_PLANES)
318 { // this shouldn't really happen
319 VectorCopy (vec3_origin, ent->v.velocity);
323 VectorCopy (trace.plane.normal, planes[numplanes]);
327 // modify original_velocity so it parallels all of the clip planes
329 for (i=0 ; i<numplanes ; i++)
331 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
332 for (j=0 ; j<numplanes ; j++)
335 if (DotProduct (new_velocity, planes[j]) < 0)
343 { // go along this plane
344 VectorCopy (new_velocity, ent->v.velocity);
347 { // go along the crease
350 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
351 VectorCopy (vec3_origin, ent->v.velocity);
354 CrossProduct (planes[0], planes[1], dir);
355 d = DotProduct (dir, ent->v.velocity);
356 VectorScale (dir, d, ent->v.velocity);
360 // if original velocity is against the original velocity, stop dead
361 // to avoid tiny occilations in sloping corners
363 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
365 VectorCopy (vec3_origin, ent->v.velocity);
380 void SV_AddGravity (edict_t *ent)
386 val = GETEDICTFIELDVALUE(ent, eval_gravity);
387 if (val!=0 && val->_float)
388 ent_gravity = val->_float;
391 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
396 ===============================================================================
400 ===============================================================================
407 Does not change the entities velocity at all
410 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
415 VectorAdd (ent->v.origin, push, end);
417 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
418 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
419 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
420 // only clip against bmodels
421 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
423 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
425 VectorCopy (trace.endpos, ent->v.origin);
426 SV_LinkEdict (ent, true);
429 SV_Impact (ent, trace.ent);
441 void SV_PushMove (edict_t *pusher, float movetime)
445 vec3_t mins, maxs, move;
446 vec3_t entorig, pushorig;
448 edict_t *moved_edict[MAX_EDICTS];
449 vec3_t moved_from[MAX_EDICTS];
452 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
454 pusher->v.ltime += movetime;
458 for (i=0 ; i<3 ; i++)
460 move[i] = pusher->v.velocity[i] * movetime;
461 mins[i] = pusher->v.absmin[i] + move[i];
462 maxs[i] = pusher->v.absmax[i] + move[i];
465 VectorCopy (pusher->v.origin, pushorig);
467 // move the pusher to it's final position
469 VectorAdd (pusher->v.origin, move, pusher->v.origin);
470 pusher->v.ltime += movetime;
471 SV_LinkEdict (pusher, false);
474 // see if any solid entities are inside the final position
476 check = NEXT_EDICT(sv.edicts);
477 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
481 if (check->v.movetype == MOVETYPE_PUSH
482 || check->v.movetype == MOVETYPE_NONE
483 || check->v.movetype == MOVETYPE_FOLLOW
484 || check->v.movetype == MOVETYPE_NOCLIP)
487 // if the entity is standing on the pusher, it will definitely be moved
488 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
490 if (check->v.absmin[0] >= maxs[0]
491 || check->v.absmin[1] >= maxs[1]
492 || check->v.absmin[2] >= maxs[2]
493 || check->v.absmax[0] <= mins[0]
494 || check->v.absmax[1] <= mins[1]
495 || check->v.absmax[2] <= mins[2])
498 // see if the ent's bbox is inside the pusher's final position
499 if (!SV_TestEntityPosition (check))
503 // remove the onground flag for non-players
504 if (check->v.movetype != MOVETYPE_WALK)
505 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
507 VectorCopy (check->v.origin, entorig);
508 VectorCopy (check->v.origin, moved_from[num_moved]);
509 moved_edict[num_moved] = check;
512 // LordHavoc: pusher fixes (teleport train bug, etc)
513 savesolid = pusher->v.solid;
514 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
516 // try moving the contacted entity
517 pusher->v.solid = SOLID_NOT;
518 SV_PushEntity (check, move);
519 pusher->v.solid = savesolid; // was SOLID_BSP
521 // if it is still inside the pusher, block
522 if (SV_TestEntityPosition (check))
524 if (check->v.mins[0] == check->v.maxs[0])
526 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
528 check->v.mins[0] = check->v.mins[1] = 0;
529 VectorCopy (check->v.mins, check->v.maxs);
533 VectorCopy (entorig, check->v.origin);
534 SV_LinkEdict (check, true);
536 VectorCopy (pushorig, pusher->v.origin);
537 SV_LinkEdict (pusher, false);
538 pusher->v.ltime -= movetime;
540 // if the pusher has a "blocked" function, call it
541 // otherwise, just stay in place until the obstacle is gone
542 if (pusher->v.blocked)
544 pr_global_struct->self = EDICT_TO_PROG(pusher);
545 pr_global_struct->other = EDICT_TO_PROG(check);
546 PR_ExecuteProgram (pusher->v.blocked);
549 // move back any entities we already moved
550 for (i=0 ; i<num_moved ; i++)
552 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
553 SV_LinkEdict (moved_edict[i], false);
569 void SV_PushRotate (edict_t *pusher, float movetime)
573 vec3_t move, a, amove;
574 vec3_t entorig, pushorig;
576 edict_t *moved_edict[MAX_EDICTS];
577 vec3_t moved_from[MAX_EDICTS];
579 vec3_t forward, right, up;
582 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
584 pusher->v.ltime += movetime;
588 for (i=0 ; i<3 ; i++)
589 amove[i] = pusher->v.avelocity[i] * movetime;
591 VectorSubtract (vec3_origin, amove, a);
592 AngleVectors (a, forward, right, up);
594 VectorCopy (pusher->v.angles, pushorig);
596 // move the pusher to it's final position
598 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
599 pusher->v.ltime += movetime;
600 SV_LinkEdict (pusher, false);
603 // see if any solid entities are inside the final position
605 check = NEXT_EDICT(sv.edicts);
606 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
610 if (check->v.movetype == MOVETYPE_PUSH
611 || check->v.movetype == MOVETYPE_NONE
612 || check->v.movetype == MOVETYPE_FOLLOW
613 || check->v.movetype == MOVETYPE_NOCLIP)
616 // if the entity is standing on the pusher, it will definately be moved
617 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
618 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
620 if ( check->v.absmin[0] >= pusher->v.absmax[0]
621 || check->v.absmin[1] >= pusher->v.absmax[1]
622 || check->v.absmin[2] >= pusher->v.absmax[2]
623 || check->v.absmax[0] <= pusher->v.absmin[0]
624 || check->v.absmax[1] <= pusher->v.absmin[1]
625 || check->v.absmax[2] <= pusher->v.absmin[2] )
628 // see if the ent's bbox is inside the pusher's final position
629 if (!SV_TestEntityPosition (check))
633 // remove the onground flag for non-players
634 if (check->v.movetype != MOVETYPE_WALK)
635 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
637 VectorCopy (check->v.origin, entorig);
638 VectorCopy (check->v.origin, moved_from[num_moved]);
639 moved_edict[num_moved] = check;
642 // calculate destination position
643 VectorSubtract (check->v.origin, pusher->v.origin, org);
644 org2[0] = DotProduct (org, forward);
645 org2[1] = -DotProduct (org, right);
646 org2[2] = DotProduct (org, up);
647 VectorSubtract (org2, org, move);
649 // try moving the contacted entity
650 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
651 pusher->v.solid = SOLID_NOT;
652 SV_PushEntity (check, move);
653 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
655 // if it is still inside the pusher, block
656 if (SV_TestEntityPosition (check))
658 if (check->v.mins[0] == check->v.maxs[0])
660 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
662 check->v.mins[0] = check->v.mins[1] = 0;
663 VectorCopy (check->v.mins, check->v.maxs);
667 VectorCopy (entorig, check->v.origin);
668 SV_LinkEdict (check, true);
670 VectorCopy (pushorig, pusher->v.angles);
671 SV_LinkEdict (pusher, false);
672 pusher->v.ltime -= movetime;
674 // if the pusher has a "blocked" function, call it
675 // otherwise, just stay in place until the obstacle is gone
676 if (pusher->v.blocked)
678 pr_global_struct->self = EDICT_TO_PROG(pusher);
679 pr_global_struct->other = EDICT_TO_PROG(check);
680 PR_ExecuteProgram (pusher->v.blocked);
683 // move back any entities we already moved
684 for (i=0 ; i<num_moved ; i++)
686 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
687 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
688 SV_LinkEdict (moved_edict[i], false);
694 VectorAdd (check->v.angles, amove, check->v.angles);
708 void SV_Physics_Pusher (edict_t *ent)
714 oldltime = ent->v.ltime;
716 thinktime = ent->v.nextthink;
717 if (thinktime < ent->v.ltime + host_frametime)
719 movetime = thinktime - ent->v.ltime;
724 movetime = host_frametime;
728 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
729 SV_PushRotate (ent, movetime);
731 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
734 if (thinktime > oldltime && thinktime <= ent->v.ltime)
736 ent->v.nextthink = 0;
737 pr_global_struct->time = sv.time;
738 pr_global_struct->self = EDICT_TO_PROG(ent);
739 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
740 PR_ExecuteProgram (ent->v.think);
749 ===============================================================================
753 ===============================================================================
760 This is a big hack to try and fix the rare case of getting stuck in the world
764 void SV_CheckStuck (edict_t *ent)
770 if (!SV_TestEntityPosition(ent))
772 VectorCopy (ent->v.origin, ent->v.oldorigin);
776 VectorCopy (ent->v.origin, org);
777 VectorCopy (ent->v.oldorigin, ent->v.origin);
778 if (!SV_TestEntityPosition(ent))
780 Con_DPrintf ("Unstuck.\n");
781 SV_LinkEdict (ent, true);
785 for (z=0 ; z< 18 ; z++)
786 for (i=-1 ; i <= 1 ; i++)
787 for (j=-1 ; j <= 1 ; j++)
789 ent->v.origin[0] = org[0] + i;
790 ent->v.origin[1] = org[1] + j;
791 ent->v.origin[2] = org[2] + z;
792 if (!SV_TestEntityPosition(ent))
794 Con_DPrintf ("Unstuck.\n");
795 SV_LinkEdict (ent, true);
800 VectorCopy (org, ent->v.origin);
801 Con_DPrintf ("player is stuck.\n");
810 qboolean SV_CheckWater (edict_t *ent)
815 point[0] = ent->v.origin[0];
816 point[1] = ent->v.origin[1];
817 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
819 ent->v.waterlevel = 0;
820 ent->v.watertype = CONTENTS_EMPTY;
821 cont = SV_PointContents (point);
822 if (cont <= CONTENTS_WATER)
824 ent->v.watertype = cont;
825 ent->v.waterlevel = 1;
826 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
827 cont = SV_PointContents (point);
828 if (cont <= CONTENTS_WATER)
830 ent->v.waterlevel = 2;
831 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
832 cont = SV_PointContents (point);
833 if (cont <= CONTENTS_WATER)
834 ent->v.waterlevel = 3;
838 return ent->v.waterlevel > 1;
847 void SV_WallFriction (edict_t *ent, trace_t *trace)
849 vec3_t forward, right, up;
853 AngleVectors (ent->v.v_angle, forward, right, up);
854 d = DotProduct (trace->plane.normal, forward);
860 // cut the tangential velocity
861 i = DotProduct (trace->plane.normal, ent->v.velocity);
862 VectorScale (trace->plane.normal, i, into);
863 VectorSubtract (ent->v.velocity, into, side);
865 ent->v.velocity[0] = side[0] * (1 + d);
866 ent->v.velocity[1] = side[1] * (1 + d);
870 =====================
873 Player has come to a dead stop, possibly due to the problem with limited
874 float precision at some angle joins in the BSP hull.
876 Try fixing by pushing one pixel in each direction.
878 This is a hack, but in the interest of good gameplay...
879 ======================
881 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
889 VectorCopy (ent->v.origin, oldorg);
890 VectorCopy (vec3_origin, dir);
892 for (i=0 ; i<8 ; i++)
894 // try pushing a little in an axial direction
897 case 0: dir[0] = 2; dir[1] = 0; break;
898 case 1: dir[0] = 0; dir[1] = 2; break;
899 case 2: dir[0] = -2; dir[1] = 0; break;
900 case 3: dir[0] = 0; dir[1] = -2; break;
901 case 4: dir[0] = 2; dir[1] = 2; break;
902 case 5: dir[0] = -2; dir[1] = 2; break;
903 case 6: dir[0] = 2; dir[1] = -2; break;
904 case 7: dir[0] = -2; dir[1] = -2; break;
907 SV_PushEntity (ent, dir);
909 // retry the original move
910 ent->v.velocity[0] = oldvel[0];
911 ent->v. velocity[1] = oldvel[1];
912 ent->v. velocity[2] = 0;
913 clip = SV_FlyMove (ent, 0.1, &steptrace);
915 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
916 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
918 //Con_DPrintf ("unstuck!\n");
922 // go back to the original pos and try again
923 VectorCopy (oldorg, ent->v.origin);
926 VectorCopy (vec3_origin, ent->v.velocity);
927 return 7; // still not moving
931 =====================
935 ======================
938 void SV_WalkMove (edict_t *ent)
940 vec3_t upmove, downmove;
941 vec3_t oldorg, oldvel;
942 vec3_t nosteporg, nostepvel;
945 trace_t steptrace, downtrace;
948 // do a regular slide move unless it looks like you ran into a step
950 oldonground = (int)ent->v.flags & FL_ONGROUND;
951 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
953 VectorCopy (ent->v.origin, oldorg);
954 VectorCopy (ent->v.velocity, oldvel);
956 clip = SV_FlyMove (ent, host_frametime, &steptrace);
959 return; // move didn't block on a step
961 if (!oldonground && ent->v.waterlevel == 0)
962 return; // don't stair up while jumping
964 if (ent->v.movetype != MOVETYPE_WALK)
965 return; // gibbed by a trigger
970 if ( (int)sv_player->v.flags & FL_WATERJUMP )
973 VectorCopy (ent->v.origin, nosteporg);
974 VectorCopy (ent->v.velocity, nostepvel);
977 // try moving up and forward to go up a step
979 VectorCopy (oldorg, ent->v.origin); // back to start pos
981 VectorCopy (vec3_origin, upmove);
982 VectorCopy (vec3_origin, downmove);
983 upmove[2] = STEPSIZE;
984 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
987 SV_PushEntity (ent, upmove); // FIXME: don't link?
990 ent->v.velocity[0] = oldvel[0];
991 ent->v. velocity[1] = oldvel[1];
992 ent->v. velocity[2] = 0;
993 clip = SV_FlyMove (ent, host_frametime, &steptrace);
995 // check for stuckness, possibly due to the limited precision of floats
996 // in the clipping hulls
999 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1000 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1001 { // stepping up didn't make any progress
1002 clip = SV_TryUnstick (ent, oldvel);
1006 // extra friction based on view angle
1008 SV_WallFriction (ent, &steptrace);
1011 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1013 if (downtrace.plane.normal[2] > 0.7)
1015 if (ent->v.solid == SOLID_BSP)
1017 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1018 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1023 // if the push down didn't end up on good ground, use the move without
1024 // the step up. This happens near wall / slope combinations, and can
1025 // cause the player to hop up higher on a slope too steep to climb
1026 VectorCopy (nosteporg, ent->v.origin);
1027 VectorCopy (nostepvel, ent->v.velocity);
1036 Player character actions
1039 void SV_Physics_Client (edict_t *ent, int num)
1041 if ( ! svs.clients[num-1].active )
1042 return; // unconnected slot
1045 // call standard client pre-think
1047 pr_global_struct->time = sv.time;
1048 pr_global_struct->self = EDICT_TO_PROG(ent);
1049 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1054 SV_CheckVelocity (ent);
1057 // decide which move function to call
1059 switch ((int)ent->v.movetype)
1062 if (!SV_RunThink (ent))
1067 if (!SV_RunThink (ent))
1069 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1070 SV_AddGravity (ent);
1071 SV_CheckStuck (ent);
1076 case MOVETYPE_BOUNCE:
1077 SV_Physics_Toss (ent);
1081 if (!SV_RunThink (ent))
1083 SV_FlyMove (ent, host_frametime, NULL);
1086 case MOVETYPE_NOCLIP:
1087 if (!SV_RunThink (ent))
1089 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1093 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1097 // call standard player post-think
1099 SV_LinkEdict (ent, true);
1101 pr_global_struct->time = sv.time;
1102 pr_global_struct->self = EDICT_TO_PROG(ent);
1103 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1106 //============================================================================
1112 Non moving objects can only think
1115 void SV_Physics_None (edict_t *ent)
1125 Entities that are "stuck" to another entity
1128 void SV_Physics_Follow (edict_t *ent)
1130 vec3_t vf, vu, vr, angles;
1134 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1135 e = PROG_TO_EDICT(ent->v.aiment);
1136 angles[0] = -e->v.angles[0];
1137 angles[1] = e->v.angles[1];
1138 angles[2] = e->v.angles[2];
1139 AngleVectors (angles, vf, vr, vu);
1140 VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin);
1141 VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin);
1142 VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin);
1143 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1144 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1145 SV_LinkEdict (ent, true);
1152 A moving object that doesn't obey physics
1155 void SV_Physics_Noclip (edict_t *ent)
1158 if (!SV_RunThink (ent))
1161 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1162 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1164 SV_LinkEdict (ent, false);
1168 ==============================================================================
1172 ==============================================================================
1177 SV_CheckWaterTransition
1181 void SV_CheckWaterTransition (edict_t *ent)
1184 cont = SV_PointContents (ent->v.origin);
1185 if (!ent->v.watertype)
1186 { // just spawned here
1187 ent->v.watertype = cont;
1188 ent->v.waterlevel = 1;
1192 if (cont <= CONTENTS_WATER)
1194 if (ent->v.watertype == CONTENTS_EMPTY)
1195 { // just crossed into water
1196 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1198 ent->v.watertype = cont;
1199 ent->v.waterlevel = 1;
1203 if (ent->v.watertype != CONTENTS_EMPTY)
1204 { // just crossed into water
1205 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1207 ent->v.watertype = CONTENTS_EMPTY;
1208 ent->v.waterlevel = cont;
1216 Toss, bounce, and fly movement. When onground, do nothing.
1219 void SV_Physics_Toss (edict_t *ent)
1225 if (!SV_RunThink (ent))
1228 // if onground, return without moving
1229 if ( ((int)ent->v.flags & FL_ONGROUND) )
1232 SV_CheckVelocity (ent);
1235 if (ent->v.movetype != MOVETYPE_FLY
1236 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1237 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1238 SV_AddGravity (ent);
1241 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1244 VectorScale (ent->v.velocity, host_frametime, move);
1245 trace = SV_PushEntity (ent, move);
1246 if (trace.fraction == 1)
1251 if (ent->v.movetype == MOVETYPE_BOUNCE)
1253 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1258 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1260 // stop if on ground
1261 if (trace.plane.normal[2] > 0.7)
1263 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1265 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1266 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1267 VectorCopy (vec3_origin, ent->v.velocity);
1268 VectorCopy (vec3_origin, ent->v.avelocity);
1272 // check for in water
1273 SV_CheckWaterTransition (ent);
1277 ===============================================================================
1281 ===============================================================================
1288 Monsters freefall when they don't have a ground entity, otherwise
1289 all movement is done with discrete steps.
1291 This is also used for objects that have become still on the ground, but
1292 will fall if the floor is pulled out from under them.
1295 void SV_Physics_Step (edict_t *ent)
1299 // freefall if not onground
1300 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1302 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1307 SV_AddGravity (ent);
1308 SV_CheckVelocity (ent);
1309 SV_FlyMove (ent, host_frametime, NULL);
1310 SV_LinkEdict (ent, true);
1312 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1315 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1322 SV_CheckWaterTransition (ent);
1325 //============================================================================
1333 extern dfunction_t *EndFrameQC;
1334 void SV_Physics (void)
1339 // let the progs know that a new frame has started
1340 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1341 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1342 pr_global_struct->time = sv.time;
1343 PR_ExecuteProgram (pr_global_struct->StartFrame);
1345 //SV_CheckAllEnts ();
1348 // treat each object in turn
1351 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1356 if (pr_global_struct->force_retouch)
1358 SV_LinkEdict (ent, true); // force retouch even for stationary
1361 if (i > 0 && i <= svs.maxclients)
1362 SV_Physics_Client (ent, i);
1363 else if (ent->v.movetype == MOVETYPE_PUSH)
1364 SV_Physics_Pusher (ent);
1365 else if (ent->v.movetype == MOVETYPE_NONE)
1366 SV_Physics_None (ent);
1367 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1368 SV_Physics_Follow (ent);
1369 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1370 SV_Physics_Noclip (ent);
1371 else if (ent->v.movetype == MOVETYPE_STEP)
1372 SV_Physics_Step (ent);
1373 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1374 else if (ent->v.movetype == MOVETYPE_WALK)
1376 if (SV_RunThink (ent))
1378 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1379 SV_AddGravity (ent);
1380 SV_CheckStuck (ent);
1384 else if (ent->v.movetype == MOVETYPE_TOSS
1385 || ent->v.movetype == MOVETYPE_BOUNCE
1386 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1387 || ent->v.movetype == MOVETYPE_FLY
1388 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1389 SV_Physics_Toss (ent);
1391 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1394 if (pr_global_struct->force_retouch)
1395 pr_global_struct->force_retouch--;
1397 // LordHavoc: endframe support
1400 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1401 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1402 pr_global_struct->time = sv.time;
1403 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1406 sv.time += host_frametime;
1410 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1413 edict_t tempent, *tent;
1417 double save_frametime;
1419 save_frametime = host_frametime;
1420 host_frametime = 0.05;
1422 memcpy(&tempent, ent, sizeof(edict_t));
1425 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1427 SV_CheckVelocity (tent);
1428 SV_AddGravity (tent);
1429 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1430 VectorScale (tent->v.velocity, host_frametime, move);
1431 VectorAdd (tent->v.origin, move, end);
1432 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1433 VectorCopy (trace.endpos, tent->v.origin);
1436 if (trace.ent != ignore)
1439 host_frametime = save_frametime;