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 switch ((int) pusher->v.solid)
603 // LordHavoc: valid pusher types
607 case SOLID_CORPSE: // LordHavoc: this would be weird...
609 // LordHavoc: no collisions
612 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
613 pusher->v.ltime += movetime;
614 SV_LinkEdict (pusher, false);
617 Host_Error("SV_PushRotate: unrecognized solid type %f\n", pusher->v.solid);
619 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
621 pusher->v.ltime += movetime;
625 for (i=0 ; i<3 ; i++)
626 amove[i] = pusher->v.avelocity[i] * movetime;
628 VectorSubtract (vec3_origin, amove, a);
629 AngleVectors (a, forward, right, up);
631 VectorCopy (pusher->v.origin, pushorigin);
632 VectorCopy (pusher->v.angles, pushangles);
634 // move the pusher to it's final position
636 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
637 pusher->v.ltime += movetime;
638 SV_LinkEdict (pusher, false);
641 // see if any solid entities are inside the final position
643 check = NEXT_EDICT(sv.edicts);
644 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
648 if (check->v.movetype == MOVETYPE_PUSH
649 || check->v.movetype == MOVETYPE_NONE
650 || check->v.movetype == MOVETYPE_FOLLOW
651 || check->v.movetype == MOVETYPE_NOCLIP)
654 // if the entity is standing on the pusher, it will definately be moved
655 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
657 if (check->v.absmin[0] >= pusher->v.absmax[0]
658 || check->v.absmin[1] >= pusher->v.absmax[1]
659 || check->v.absmin[2] >= pusher->v.absmax[2]
660 || check->v.absmax[0] <= pusher->v.absmin[0]
661 || check->v.absmax[1] <= pusher->v.absmin[1]
662 || check->v.absmax[2] <= pusher->v.absmin[2])
665 // see if the ent's bbox is inside the pusher's final position
666 if (!SV_TestEntityPosition (check))
670 // remove the onground flag for non-players
671 if (check->v.movetype != MOVETYPE_WALK)
672 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
674 VectorCopy (check->v.origin, entorigin);
675 VectorCopy (check->v.origin, moved_from[num_moved]);
676 VectorCopy (check->v.angles, entangles);
677 VectorCopy (check->v.angles, angled_from[num_moved]);
678 moved_edict[num_moved] = check;
681 // calculate destination position
682 VectorSubtract (check->v.origin, pusher->v.origin, org);
683 org2[0] = DotProduct (org, forward);
684 org2[1] = -DotProduct (org, right);
685 org2[2] = DotProduct (org, up);
686 VectorSubtract (org2, org, move);
688 // try moving the contacted entity
689 savesolid = pusher->v.solid; // LordHavoc: restore to correct solid type
690 pusher->v.solid = SOLID_NOT;
691 SV_PushEntity (check, move);
692 pusher->v.solid = savesolid; // LordHavoc: restore to correct solid type
694 VectorAdd (check->v.angles, amove, check->v.angles);
696 // if it is still inside the pusher, block
697 if (SV_TestEntityPosition (check))
699 if (check->v.mins[0] == check->v.maxs[0])
701 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
703 check->v.mins[0] = check->v.mins[1] = 0;
704 VectorCopy (check->v.mins, check->v.maxs);
708 VectorCopy (entorigin, check->v.origin);
709 VectorCopy (entangles, check->v.angles);
710 SV_LinkEdict (check, true);
712 VectorCopy (pushorigin, pusher->v.origin);
713 VectorCopy (pushangles, pusher->v.angles);
714 SV_LinkEdict (pusher, false);
715 pusher->v.ltime -= movetime;
717 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
718 if (pusher->v.blocked)
720 pr_global_struct->self = EDICT_TO_PROG(pusher);
721 pr_global_struct->other = EDICT_TO_PROG(check);
722 PR_ExecuteProgram (pusher->v.blocked);
725 // move back any entities we already moved
726 num_moved--; // LordHavoc: pop off check, because it was already restored
727 for (i=0 ; i<num_moved ; i++)
729 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
730 VectorCopy (angled_from[i], moved_edict[i]->v.angles);
731 SV_LinkEdict (moved_edict[i], false);
744 void SV_Physics_Pusher (edict_t *ent)
750 oldltime = ent->v.ltime;
752 thinktime = ent->v.nextthink;
753 if (thinktime < ent->v.ltime + host_frametime)
755 movetime = thinktime - ent->v.ltime;
760 movetime = host_frametime;
764 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
765 SV_PushRotate (ent, movetime);
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, vr, vu, angles;
1169 if (!SV_RunThink (ent))
1171 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1172 e = PROG_TO_EDICT(ent->v.aiment);
1173 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])
1175 // quick case for no rotation
1176 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1180 angles[0] = -(e->v.angles[0] - ent->v.punchangle[0]);
1181 angles[1] = e->v.angles[1] - ent->v.punchangle[1];
1182 angles[2] = e->v.angles[2] - ent->v.punchangle[2];
1183 AngleVectors (angles, vf, vr, vu);
1184 ent->v.origin[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0] + e->v.origin[0];
1185 ent->v.origin[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1] + e->v.origin[1];
1186 ent->v.origin[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2] + e->v.origin[2];
1188 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];
1189 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];
1190 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];
1193 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1194 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1195 SV_LinkEdict (ent, true);
1202 A moving object that doesn't obey physics
1205 void SV_Physics_Noclip (edict_t *ent)
1208 if (!SV_RunThink (ent))
1211 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1212 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1214 SV_LinkEdict (ent, false);
1218 ==============================================================================
1222 ==============================================================================
1227 SV_CheckWaterTransition
1231 void SV_CheckWaterTransition (edict_t *ent)
1234 cont = SV_PointContents (ent->v.origin);
1235 if (!ent->v.watertype)
1236 { // just spawned here
1237 ent->v.watertype = cont;
1238 ent->v.waterlevel = 1;
1242 if (cont <= CONTENTS_WATER)
1244 if (ent->v.watertype == CONTENTS_EMPTY)
1245 { // just crossed into water
1246 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1248 ent->v.watertype = cont;
1249 ent->v.waterlevel = 1;
1253 if (ent->v.watertype != CONTENTS_EMPTY)
1254 { // just crossed into water
1255 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1257 ent->v.watertype = CONTENTS_EMPTY;
1258 ent->v.waterlevel = cont;
1266 Toss, bounce, and fly movement. When onground, do nothing.
1269 void SV_Physics_Toss (edict_t *ent)
1275 if (!SV_RunThink (ent))
1278 // if onground, return without moving
1279 if ( ((int)ent->v.flags & FL_ONGROUND) )
1282 SV_CheckVelocity (ent);
1285 if (ent->v.movetype != MOVETYPE_FLY
1286 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1287 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1288 SV_AddGravity (ent);
1291 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1294 VectorScale (ent->v.velocity, host_frametime, move);
1295 trace = SV_PushEntity (ent, move);
1296 if (trace.fraction == 1)
1301 if (ent->v.movetype == MOVETYPE_BOUNCE)
1303 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1308 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1310 // stop if on ground
1311 if (trace.plane.normal[2] > 0.7)
1313 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1315 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1316 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1317 VectorCopy (vec3_origin, ent->v.velocity);
1318 VectorCopy (vec3_origin, ent->v.avelocity);
1322 // check for in water
1323 SV_CheckWaterTransition (ent);
1327 ===============================================================================
1331 ===============================================================================
1338 Monsters freefall when they don't have a ground entity, otherwise
1339 all movement is done with discrete steps.
1341 This is also used for objects that have become still on the ground, but
1342 will fall if the floor is pulled out from under them.
1345 void SV_Physics_Step (edict_t *ent)
1349 // freefall if not onground
1350 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1352 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1357 SV_AddGravity (ent);
1358 SV_CheckVelocity (ent);
1359 SV_FlyMove (ent, host_frametime, NULL);
1360 SV_LinkEdict (ent, true);
1362 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1365 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1372 SV_CheckWaterTransition (ent);
1375 //============================================================================
1383 extern dfunction_t *EndFrameQC;
1384 void SV_Physics (void)
1389 // let the progs know that a new frame has started
1390 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1391 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1392 pr_global_struct->time = sv.time;
1393 PR_ExecuteProgram (pr_global_struct->StartFrame);
1395 //SV_CheckAllEnts ();
1398 // treat each object in turn
1401 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1406 if (pr_global_struct->force_retouch)
1407 SV_LinkEdict (ent, true); // force retouch even for stationary
1409 if (i > 0 && i <= svs.maxclients)
1411 SV_Physics_Client (ent, i);
1415 switch ((int) ent->v.movetype)
1418 SV_Physics_Pusher (ent);
1421 SV_Physics_None (ent);
1423 case MOVETYPE_FOLLOW:
1424 SV_Physics_Follow (ent);
1426 case MOVETYPE_NOCLIP:
1427 SV_Physics_Noclip (ent);
1430 SV_Physics_Step (ent);
1432 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1434 if (SV_RunThink (ent))
1436 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1437 SV_AddGravity (ent);
1438 SV_CheckStuck (ent);
1443 case MOVETYPE_BOUNCE:
1444 case MOVETYPE_BOUNCEMISSILE:
1446 case MOVETYPE_FLYMISSILE:
1447 SV_Physics_Toss (ent);
1450 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1455 if (pr_global_struct->force_retouch)
1456 pr_global_struct->force_retouch--;
1458 // LordHavoc: endframe support
1461 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1462 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1463 pr_global_struct->time = sv.time;
1464 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));
1467 sv.time += host_frametime;
1471 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1474 edict_t tempent, *tent;
1478 double save_frametime;
1480 save_frametime = host_frametime;
1481 host_frametime = 0.05;
1483 memcpy(&tempent, ent, sizeof(edict_t));
1486 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1488 SV_CheckVelocity (tent);
1489 SV_AddGravity (tent);
1490 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1491 VectorScale (tent->v.velocity, host_frametime, move);
1492 VectorAdd (tent->v.origin, move, end);
1493 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1494 VectorCopy (trace.endpos, tent->v.origin);
1497 if (trace.ent != ignore)
1500 host_frametime = save_frametime;