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 switch ((int) pusher->v.solid)
454 // LordHavoc: valid pusher types
458 case SOLID_CORPSE: // LordHavoc: this would be weird...
460 // LordHavoc: no collisions
463 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
464 pusher->v.ltime += movetime;
465 SV_LinkEdict (pusher, false);
468 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
470 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
472 pusher->v.ltime += movetime;
476 for (i=0 ; i<3 ; i++)
478 move[i] = pusher->v.velocity[i] * movetime;
479 mins[i] = pusher->v.absmin[i] + move[i];
480 maxs[i] = pusher->v.absmax[i] + move[i];
483 VectorCopy (pusher->v.origin, pushorig);
485 // move the pusher to it's final position
487 VectorAdd (pusher->v.origin, move, pusher->v.origin);
488 pusher->v.ltime += movetime;
489 SV_LinkEdict (pusher, false);
492 // see if any solid entities are inside the final position
494 check = NEXT_EDICT(sv.edicts);
495 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
499 if (check->v.movetype == MOVETYPE_PUSH
500 || check->v.movetype == MOVETYPE_NONE
501 || check->v.movetype == MOVETYPE_FOLLOW
502 || check->v.movetype == MOVETYPE_NOCLIP)
505 // if the entity is standing on the pusher, it will definitely be moved
506 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
508 if (check->v.absmin[0] >= maxs[0]
509 || check->v.absmin[1] >= maxs[1]
510 || check->v.absmin[2] >= maxs[2]
511 || check->v.absmax[0] <= mins[0]
512 || check->v.absmax[1] <= mins[1]
513 || check->v.absmax[2] <= mins[2])
516 // see if the ent's bbox is inside the pusher's final position
517 if (!SV_TestEntityPosition (check))
521 // remove the onground flag for non-players
522 if (check->v.movetype != MOVETYPE_WALK)
523 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
525 VectorCopy (check->v.origin, entorig);
526 VectorCopy (check->v.origin, moved_from[num_moved]);
527 moved_edict[num_moved] = check;
530 // LordHavoc: pusher fixes (teleport train bug, etc)
531 savesolid = pusher->v.solid;
532 if (savesolid == SOLID_BSP || savesolid == SOLID_BBOX || savesolid == SOLID_SLIDEBOX)
534 // try moving the contacted entity
535 pusher->v.solid = SOLID_NOT;
536 SV_PushEntity (check, move);
537 pusher->v.solid = savesolid; // was SOLID_BSP
539 // if it is still inside the pusher, block
540 if (SV_TestEntityPosition (check))
542 if (check->v.mins[0] == check->v.maxs[0])
544 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
546 check->v.mins[0] = check->v.mins[1] = 0;
547 VectorCopy (check->v.mins, check->v.maxs);
551 VectorCopy (entorig, check->v.origin);
552 SV_LinkEdict (check, true);
554 VectorCopy (pushorig, pusher->v.origin);
555 SV_LinkEdict (pusher, false);
556 pusher->v.ltime -= movetime;
558 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
559 if (pusher->v.blocked)
561 pr_global_struct->self = EDICT_TO_PROG(pusher);
562 pr_global_struct->other = EDICT_TO_PROG(check);
563 PR_ExecuteProgram (pusher->v.blocked);
566 // move back any entities we already moved
567 num_moved--; // LordHavoc: pop off check, because it was already restored
568 for (i=0 ; i<num_moved ; i++)
570 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
571 SV_LinkEdict (moved_edict[i], false);
587 void SV_PushRotate (edict_t *pusher, float movetime)
591 vec3_t move, a, amove;
592 vec3_t entorigin, entangles, pushorigin, pushangles;
594 edict_t *moved_edict[MAX_EDICTS];
595 vec3_t moved_from[MAX_EDICTS];
596 vec3_t angled_from[MAX_EDICTS];
598 vec3_t forward, right, up;
601 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
603 pusher->v.ltime += movetime;
607 for (i=0 ; i<3 ; i++)
608 amove[i] = pusher->v.avelocity[i] * movetime;
610 VectorSubtract (vec3_origin, amove, a);
611 AngleVectors (a, forward, right, up);
613 VectorCopy (pusher->v.origin, pushorigin);
614 VectorCopy (pusher->v.angles, pushangles);
616 // move the pusher to it's final position
618 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
619 pusher->v.ltime += movetime;
620 SV_LinkEdict (pusher, false);
623 // see if any solid entities are inside the final position
625 check = NEXT_EDICT(sv.edicts);
626 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
630 if (check->v.movetype == MOVETYPE_PUSH
631 || check->v.movetype == MOVETYPE_NONE
632 || check->v.movetype == MOVETYPE_FOLLOW
633 || check->v.movetype == MOVETYPE_NOCLIP)
636 // if the entity is standing on the pusher, it will definately be moved
637 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
639 if (check->v.absmin[0] >= pusher->v.absmax[0]
640 || check->v.absmin[1] >= pusher->v.absmax[1]
641 || check->v.absmin[2] >= pusher->v.absmax[2]
642 || check->v.absmax[0] <= pusher->v.absmin[0]
643 || check->v.absmax[1] <= pusher->v.absmin[1]
644 || check->v.absmax[2] <= pusher->v.absmin[2])
647 // see if the ent's bbox is inside the pusher's final position
648 if (!SV_TestEntityPosition (check))
652 // remove the onground flag for non-players
653 if (check->v.movetype != MOVETYPE_WALK)
654 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
656 VectorCopy (check->v.origin, entorigin);
657 VectorCopy (check->v.origin, moved_from[num_moved]);
658 VectorCopy (check->v.angles, entangles);
659 VectorCopy (check->v.angles, angled_from[num_moved]);
660 moved_edict[num_moved] = check;
663 // calculate destination position
664 VectorSubtract (check->v.origin, pusher->v.origin, org);
665 org2[0] = DotProduct (org, forward);
666 org2[1] = -DotProduct (org, right);
667 org2[2] = DotProduct (org, up);
668 VectorSubtract (org2, org, move);
670 // try moving the contacted entity
671 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
672 pusher->v.solid = SOLID_NOT;
673 SV_PushEntity (check, move);
674 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
676 VectorAdd (check->v.angles, amove, check->v.angles);
678 // if it is still inside the pusher, block
679 if (SV_TestEntityPosition (check))
681 if (check->v.mins[0] == check->v.maxs[0])
683 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
685 check->v.mins[0] = check->v.mins[1] = 0;
686 VectorCopy (check->v.mins, check->v.maxs);
690 VectorCopy (entorigin, check->v.origin);
691 VectorCopy (entangles, check->v.angles);
692 SV_LinkEdict (check, true);
694 VectorCopy (pushorigin, pusher->v.origin);
695 VectorCopy (pushangles, pusher->v.angles);
696 SV_LinkEdict (pusher, false);
697 pusher->v.ltime -= movetime;
699 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
700 if (pusher->v.blocked)
702 pr_global_struct->self = EDICT_TO_PROG(pusher);
703 pr_global_struct->other = EDICT_TO_PROG(check);
704 PR_ExecuteProgram (pusher->v.blocked);
707 // move back any entities we already moved
708 num_moved--; // LordHavoc: pop off check, because it was already restored
709 for (i=0 ; i<num_moved ; i++)
711 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
712 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
713 SV_LinkEdict (moved_edict[i], false);
726 void SV_Physics_Pusher (edict_t *ent)
732 oldltime = ent->v.ltime;
735 thinktime = ent->v.nextthink;
736 if (thinktime < ent->v.ltime + host_frametime)
738 movetime = thinktime - ent->v.ltime;
743 movetime = host_frametime;
747 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
748 SV_PushRotate (ent, movetime);
750 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
753 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
754 SV_PushRotate (ent, host_frametime);
757 thinktime = ent->v.nextthink;
758 if (thinktime < ent->v.ltime + host_frametime)
760 movetime = thinktime - ent->v.ltime;
765 movetime = host_frametime;
767 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
770 if (thinktime > oldltime && thinktime <= ent->v.ltime)
772 ent->v.nextthink = 0;
773 pr_global_struct->time = sv.time;
774 pr_global_struct->self = EDICT_TO_PROG(ent);
775 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
776 PR_ExecuteProgram (ent->v.think);
785 ===============================================================================
789 ===============================================================================
796 This is a big hack to try and fix the rare case of getting stuck in the world
800 void SV_CheckStuck (edict_t *ent)
806 if (!SV_TestEntityPosition(ent))
808 VectorCopy (ent->v.origin, ent->v.oldorigin);
812 VectorCopy (ent->v.origin, org);
813 VectorCopy (ent->v.oldorigin, ent->v.origin);
814 if (!SV_TestEntityPosition(ent))
816 Con_DPrintf ("Unstuck.\n");
817 SV_LinkEdict (ent, true);
821 for (z=0 ; z< 18 ; z++)
822 for (i=-1 ; i <= 1 ; i++)
823 for (j=-1 ; j <= 1 ; j++)
825 ent->v.origin[0] = org[0] + i;
826 ent->v.origin[1] = org[1] + j;
827 ent->v.origin[2] = org[2] + z;
828 if (!SV_TestEntityPosition(ent))
830 Con_DPrintf ("Unstuck.\n");
831 SV_LinkEdict (ent, true);
836 VectorCopy (org, ent->v.origin);
837 Con_DPrintf ("player is stuck.\n");
846 qboolean SV_CheckWater (edict_t *ent)
851 point[0] = ent->v.origin[0];
852 point[1] = ent->v.origin[1];
853 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
855 ent->v.waterlevel = 0;
856 ent->v.watertype = CONTENTS_EMPTY;
857 cont = SV_PointContents (point);
858 if (cont <= CONTENTS_WATER)
860 ent->v.watertype = cont;
861 ent->v.waterlevel = 1;
862 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
863 cont = SV_PointContents (point);
864 if (cont <= CONTENTS_WATER)
866 ent->v.waterlevel = 2;
867 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
868 cont = SV_PointContents (point);
869 if (cont <= CONTENTS_WATER)
870 ent->v.waterlevel = 3;
874 return ent->v.waterlevel > 1;
883 void SV_WallFriction (edict_t *ent, trace_t *trace)
885 vec3_t forward, right, up;
889 AngleVectors (ent->v.v_angle, forward, right, up);
890 d = DotProduct (trace->plane.normal, forward);
896 // cut the tangential velocity
897 i = DotProduct (trace->plane.normal, ent->v.velocity);
898 VectorScale (trace->plane.normal, i, into);
899 VectorSubtract (ent->v.velocity, into, side);
901 ent->v.velocity[0] = side[0] * (1 + d);
902 ent->v.velocity[1] = side[1] * (1 + d);
906 =====================
909 Player has come to a dead stop, possibly due to the problem with limited
910 float precision at some angle joins in the BSP hull.
912 Try fixing by pushing one pixel in each direction.
914 This is a hack, but in the interest of good gameplay...
915 ======================
917 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
925 VectorCopy (ent->v.origin, oldorg);
926 VectorCopy (vec3_origin, dir);
928 for (i=0 ; i<8 ; i++)
930 // try pushing a little in an axial direction
933 case 0: dir[0] = 2; dir[1] = 0; break;
934 case 1: dir[0] = 0; dir[1] = 2; break;
935 case 2: dir[0] = -2; dir[1] = 0; break;
936 case 3: dir[0] = 0; dir[1] = -2; break;
937 case 4: dir[0] = 2; dir[1] = 2; break;
938 case 5: dir[0] = -2; dir[1] = 2; break;
939 case 6: dir[0] = 2; dir[1] = -2; break;
940 case 7: dir[0] = -2; dir[1] = -2; break;
943 SV_PushEntity (ent, dir);
945 // retry the original move
946 ent->v.velocity[0] = oldvel[0];
947 ent->v. velocity[1] = oldvel[1];
948 ent->v. velocity[2] = 0;
949 clip = SV_FlyMove (ent, 0.1, &steptrace);
951 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
952 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
954 //Con_DPrintf ("unstuck!\n");
958 // go back to the original pos and try again
959 VectorCopy (oldorg, ent->v.origin);
962 VectorCopy (vec3_origin, ent->v.velocity);
963 return 7; // still not moving
967 =====================
971 ======================
974 void SV_WalkMove (edict_t *ent)
976 vec3_t upmove, downmove;
977 vec3_t oldorg, oldvel;
978 vec3_t nosteporg, nostepvel;
981 trace_t steptrace, downtrace;
984 // do a regular slide move unless it looks like you ran into a step
986 oldonground = (int)ent->v.flags & FL_ONGROUND;
987 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
989 VectorCopy (ent->v.origin, oldorg);
990 VectorCopy (ent->v.velocity, oldvel);
992 clip = SV_FlyMove (ent, host_frametime, &steptrace);
995 return; // move didn't block on a step
997 if (!oldonground && ent->v.waterlevel == 0)
998 return; // don't stair up while jumping
1000 if (ent->v.movetype != MOVETYPE_WALK)
1001 return; // gibbed by a trigger
1003 if (sv_nostep.value)
1006 if ( (int)sv_player->v.flags & FL_WATERJUMP )
1009 VectorCopy (ent->v.origin, nosteporg);
1010 VectorCopy (ent->v.velocity, nostepvel);
1013 // try moving up and forward to go up a step
1015 VectorCopy (oldorg, ent->v.origin); // back to start pos
1017 VectorCopy (vec3_origin, upmove);
1018 VectorCopy (vec3_origin, downmove);
1019 upmove[2] = STEPSIZE;
1020 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1023 SV_PushEntity (ent, upmove); // FIXME: don't link?
1026 ent->v.velocity[0] = oldvel[0];
1027 ent->v. velocity[1] = oldvel[1];
1028 ent->v. velocity[2] = 0;
1029 clip = SV_FlyMove (ent, host_frametime, &steptrace);
1031 // check for stuckness, possibly due to the limited precision of floats
1032 // in the clipping hulls
1035 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1036 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1037 { // stepping up didn't make any progress
1038 clip = SV_TryUnstick (ent, oldvel);
1042 // extra friction based on view angle
1044 SV_WallFriction (ent, &steptrace);
1047 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1049 if (downtrace.plane.normal[2] > 0.7)
1051 if (ent->v.solid == SOLID_BSP)
1053 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1054 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1059 // if the push down didn't end up on good ground, use the move without
1060 // the step up. This happens near wall / slope combinations, and can
1061 // cause the player to hop up higher on a slope too steep to climb
1062 VectorCopy (nosteporg, ent->v.origin);
1063 VectorCopy (nostepvel, ent->v.velocity);
1072 Player character actions
1075 void SV_Physics_Client (edict_t *ent, int num)
1077 if ( ! svs.clients[num-1].active )
1078 return; // unconnected slot
1081 // call standard client pre-think
1083 pr_global_struct->time = sv.time;
1084 pr_global_struct->self = EDICT_TO_PROG(ent);
1085 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1090 SV_CheckVelocity (ent);
1093 // decide which move function to call
1095 switch ((int)ent->v.movetype)
1098 if (!SV_RunThink (ent))
1103 if (!SV_RunThink (ent))
1105 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1106 SV_AddGravity (ent);
1107 SV_CheckStuck (ent);
1112 case MOVETYPE_BOUNCE:
1113 SV_Physics_Toss (ent);
1117 if (!SV_RunThink (ent))
1119 SV_FlyMove (ent, host_frametime, NULL);
1122 case MOVETYPE_NOCLIP:
1123 if (!SV_RunThink (ent))
1125 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1129 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1133 // call standard player post-think
1135 SV_LinkEdict (ent, true);
1137 pr_global_struct->time = sv.time;
1138 pr_global_struct->self = EDICT_TO_PROG(ent);
1139 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1142 //============================================================================
1148 Non moving objects can only think
1151 void SV_Physics_None (edict_t *ent)
1161 Entities that are "stuck" to another entity
1164 void SV_Physics_Follow (edict_t *ent)
1166 vec3_t vf, vu, vr, angles;
1170 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1171 e = PROG_TO_EDICT(ent->v.aiment);
1172 angles[0] = -e->v.angles[0];
1173 angles[1] = e->v.angles[1];
1174 angles[2] = e->v.angles[2];
1175 AngleVectors (angles, vf, vr, vu);
1176 VectorMA (e->v.origin, ent->v.view_ofs[0], vf, ent->v.origin);
1177 VectorMA (ent->v.origin, ent->v.view_ofs[1], vr, ent->v.origin);
1178 VectorMA (ent->v.origin, ent->v.view_ofs[2], vu, ent->v.origin);
1179 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1180 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1181 SV_LinkEdict (ent, true);
1188 A moving object that doesn't obey physics
1191 void SV_Physics_Noclip (edict_t *ent)
1194 if (!SV_RunThink (ent))
1197 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1198 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1200 SV_LinkEdict (ent, false);
1204 ==============================================================================
1208 ==============================================================================
1213 SV_CheckWaterTransition
1217 void SV_CheckWaterTransition (edict_t *ent)
1220 cont = SV_PointContents (ent->v.origin);
1221 if (!ent->v.watertype)
1222 { // just spawned here
1223 ent->v.watertype = cont;
1224 ent->v.waterlevel = 1;
1228 if (cont <= CONTENTS_WATER)
1230 if (ent->v.watertype == CONTENTS_EMPTY)
1231 { // just crossed into water
1232 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1234 ent->v.watertype = cont;
1235 ent->v.waterlevel = 1;
1239 if (ent->v.watertype != CONTENTS_EMPTY)
1240 { // just crossed into water
1241 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1243 ent->v.watertype = CONTENTS_EMPTY;
1244 ent->v.waterlevel = cont;
1252 Toss, bounce, and fly movement. When onground, do nothing.
1255 void SV_Physics_Toss (edict_t *ent)
1261 if (!SV_RunThink (ent))
1264 // if onground, return without moving
1265 if ( ((int)ent->v.flags & FL_ONGROUND) )
1268 SV_CheckVelocity (ent);
1271 if (ent->v.movetype != MOVETYPE_FLY
1272 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1273 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1274 SV_AddGravity (ent);
1277 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1280 VectorScale (ent->v.velocity, host_frametime, move);
1281 trace = SV_PushEntity (ent, move);
1282 if (trace.fraction == 1)
1287 if (ent->v.movetype == MOVETYPE_BOUNCE)
1289 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1294 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1296 // stop if on ground
1297 if (trace.plane.normal[2] > 0.7)
1299 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1301 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1302 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1303 VectorCopy (vec3_origin, ent->v.velocity);
1304 VectorCopy (vec3_origin, ent->v.avelocity);
1308 // check for in water
1309 SV_CheckWaterTransition (ent);
1313 ===============================================================================
1317 ===============================================================================
1324 Monsters freefall when they don't have a ground entity, otherwise
1325 all movement is done with discrete steps.
1327 This is also used for objects that have become still on the ground, but
1328 will fall if the floor is pulled out from under them.
1331 void SV_Physics_Step (edict_t *ent)
1335 // freefall if not onground
1336 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1338 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1343 SV_AddGravity (ent);
1344 SV_CheckVelocity (ent);
1345 SV_FlyMove (ent, host_frametime, NULL);
1346 SV_LinkEdict (ent, true);
1348 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1351 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1358 SV_CheckWaterTransition (ent);
1361 //============================================================================
1369 extern dfunction_t *EndFrameQC;
1370 void SV_Physics (void)
1375 // let the progs know that a new frame has started
1376 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1377 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1378 pr_global_struct->time = sv.time;
1379 PR_ExecuteProgram (pr_global_struct->StartFrame);
1381 //SV_CheckAllEnts ();
1384 // treat each object in turn
1387 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1392 if (pr_global_struct->force_retouch)
1393 SV_LinkEdict (ent, true); // force retouch even for stationary
1395 if (i > 0 && i <= svs.maxclients)
1397 SV_Physics_Client (ent, i);
1401 switch ((int) ent->v.movetype)
1404 SV_Physics_Pusher (ent);
1407 SV_Physics_None (ent);
1409 case MOVETYPE_FOLLOW:
1410 SV_Physics_Follow (ent);
1412 case MOVETYPE_NOCLIP:
1413 SV_Physics_Noclip (ent);
1416 SV_Physics_Step (ent);
1418 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1420 if (SV_RunThink (ent))
1422 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1423 SV_AddGravity (ent);
1424 SV_CheckStuck (ent);
1429 case MOVETYPE_BOUNCE:
1430 case MOVETYPE_BOUNCEMISSILE:
1432 case MOVETYPE_FLYMISSILE:
1433 SV_Physics_Toss (ent);
1436 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1441 if (pr_global_struct->force_retouch)
1442 pr_global_struct->force_retouch--;
1444 // LordHavoc: endframe support
1447 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1448 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1449 pr_global_struct->time = sv.time;
1450 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1453 sv.time += host_frametime;
1457 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1460 edict_t tempent, *tent;
1464 double save_frametime;
1466 save_frametime = host_frametime;
1467 host_frametime = 0.05;
1469 memcpy(&tempent, ent, sizeof(edict_t));
1472 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1474 SV_CheckVelocity (tent);
1475 SV_AddGravity (tent);
1476 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1477 VectorScale (tent->v.velocity, host_frametime, move);
1478 VectorAdd (tent->v.origin, move, end);
1479 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1480 VectorCopy (trace.endpos, tent->v.origin);
1483 if (trace.ent != ignore)
1486 host_frametime = save_frametime;