2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 pushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.
29 onground is set for toss objects when they come to a complete rest. it is set for steping or walking objects
31 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
32 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
33 corpses are SOLID_NOT and MOVETYPE_TOSS
34 crates are SOLID_BBOX and MOVETYPE_TOSS
35 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
36 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
38 solid_edge items only clip against bsp models.
42 cvar_t sv_friction = {CVAR_NOTIFY, "sv_friction","4"};
43 cvar_t sv_stopspeed = {CVAR_NOTIFY, "sv_stopspeed","100"};
44 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"};
45 cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"};
47 cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"};
48 cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"};
49 cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"};
51 #define MOVE_EPSILON 0.01
53 void SV_Physics_Toss (edict_t *ent);
55 void SV_Phys_Init (void)
57 Cvar_RegisterVariable(&sv_stepheight);
58 Cvar_RegisterVariable(&sv_jumpstep);
59 Cvar_RegisterVariable(&sv_wallfriction);
67 void SV_CheckAllEnts (void)
72 // see if any solid entities are inside the final position
73 check = NEXT_EDICT(sv.edicts);
74 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
78 if (check->v.movetype == MOVETYPE_PUSH
79 || check->v.movetype == MOVETYPE_NONE
80 || check->v.movetype == MOVETYPE_FOLLOW
81 || check->v.movetype == MOVETYPE_NOCLIP)
84 if (SV_TestEntityPosition (check))
85 Con_Printf ("entity in invalid position\n");
94 void SV_CheckVelocity (edict_t *ent)
102 for (i=0 ; i<3 ; i++)
104 if (IS_NAN(ent->v.velocity[i]))
106 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
107 ent->v.velocity[i] = 0;
109 if (IS_NAN(ent->v.origin[i]))
111 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
112 ent->v.origin[i] = 0;
116 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
117 wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
118 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
120 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
121 ent->v.velocity[0] *= wishspeed;
122 ent->v.velocity[1] *= wishspeed;
123 ent->v.velocity[2] *= wishspeed;
131 Runs thinking code if time. There is some play in the exact time the think
132 function will be called, because it is called before any movement is done
133 in a frame. Not used for pushmove objects, because they must be exact.
134 Returns false if the entity removed itself.
137 qboolean SV_RunThink (edict_t *ent)
141 thinktime = ent->v.nextthink;
142 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
145 // don't let things stay in the past.
146 // it is possible to start that way by a trigger with a local time.
147 if (thinktime < sv.time)
150 ent->v.nextthink = 0;
151 pr_global_struct->time = thinktime;
152 pr_global_struct->self = EDICT_TO_PROG(ent);
153 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
154 PR_ExecuteProgram (ent->v.think, "NULL think function");
162 Two entities have touched, so run their touch functions
165 void SV_Impact (edict_t *e1, edict_t *e2)
167 int old_self, old_other;
169 old_self = pr_global_struct->self;
170 old_other = pr_global_struct->other;
172 pr_global_struct->time = sv.time;
173 if (e1->v.touch && e1->v.solid != SOLID_NOT)
175 pr_global_struct->self = EDICT_TO_PROG(e1);
176 pr_global_struct->other = EDICT_TO_PROG(e2);
177 PR_ExecuteProgram (e1->v.touch, "");
180 if (e2->v.touch && e2->v.solid != SOLID_NOT)
182 pr_global_struct->self = EDICT_TO_PROG(e2);
183 pr_global_struct->other = EDICT_TO_PROG(e1);
184 PR_ExecuteProgram (e2->v.touch, "");
187 pr_global_struct->self = old_self;
188 pr_global_struct->other = old_other;
196 Slide off of the impacting object
197 returns the blocked flags (1 = floor, 2 = step / wall)
200 #define STOP_EPSILON 0.1
201 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
204 float backoff, change;
207 // flag if it's a floor
210 // flag if it's a step
214 backoff = DotProduct (in, normal) * overbounce;
216 for (i = 0;i < 3;i++)
218 change = normal[i] * backoff;
219 out[i] = in[i] - change;
220 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
232 The basic solid body movement clip that slides along multiple planes
233 Returns the clipflags if the velocity was modified (hit something solid)
237 If steptrace is not NULL, the trace of any vertical wall hit will be stored
240 // LordHavoc: increased from 5 to 20
241 #define MAX_CLIP_PLANES 20
242 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
244 int i, j, blocked, impact, numplanes, bumpcount, numbumps;
246 vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
252 VectorCopy (ent->v.velocity, original_velocity);
253 VectorCopy (ent->v.velocity, primal_velocity);
258 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
260 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
263 for (i=0 ; i<3 ; i++)
264 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
266 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
270 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
271 // entity is trapped in another solid
272 VectorClear(ent->v.velocity);
276 if (trace.fraction > 0)
278 // actually covered some distance
279 VectorCopy (trace.endpos, ent->v.origin);
280 VectorCopy (ent->v.velocity, original_velocity);
284 // break if it moved the entire distance
285 if (trace.fraction == 1)
289 Host_Error ("SV_FlyMove: !trace.ent");
291 if ((int) ent->v.flags & FL_ONGROUND)
293 if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
297 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
304 if (trace.plane.normal[2] > 0.7)
308 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
309 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
311 if (!trace.plane.normal[2])
315 // save the trace for player extrafriction
320 // run the impact function
323 SV_Impact (ent, trace.ent);
325 // break if removed by the impact function
331 time_left -= time_left * trace.fraction;
333 // clipped to another plane
334 if (numplanes >= MAX_CLIP_PLANES)
336 // this shouldn't really happen
337 VectorClear(ent->v.velocity);
341 VectorCopy (trace.plane.normal, planes[numplanes]);
344 // modify original_velocity so it parallels all of the clip planes
345 for (i=0 ; i<numplanes ; i++)
347 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
348 for (j=0 ; j<numplanes ; j++)
352 if (DotProduct (new_velocity, planes[j]) < 0)
361 // go along this plane
362 VectorCopy (new_velocity, ent->v.velocity);
366 // go along the crease
369 VectorClear(ent->v.velocity);
372 CrossProduct (planes[0], planes[1], dir);
373 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
374 VectorNormalize(dir);
375 d = DotProduct (dir, ent->v.velocity);
376 VectorScale (dir, d, ent->v.velocity);
379 // if original velocity is against the original velocity,
380 // stop dead to avoid tiny occilations in sloping corners
381 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
383 VectorClear(ent->v.velocity);
398 void SV_AddGravity (edict_t *ent)
403 val = GETEDICTFIELDVALUE(ent, eval_gravity);
404 if (val!=0 && val->_float)
405 ent_gravity = val->_float;
408 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
413 ===============================================================================
417 ===============================================================================
424 Does not change the entities velocity at all
427 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
432 VectorAdd (ent->v.origin, push, end);
434 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
435 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
436 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
437 // only clip against bmodels
438 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
440 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
442 VectorCopy (trace.endpos, ent->v.origin);
443 // FIXME: turn players specially
444 ent->v.angles[1] += trace.fraction * pushangles[1];
445 SV_LinkEdict (ent, true);
447 if (trace.ent && (!((int)ent->v.flags & FL_ONGROUND) || ent->v.groundentity != EDICT_TO_PROG(trace.ent)))
448 SV_Impact (ent, trace.ent);
459 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
460 void SV_PushMove (edict_t *pusher, float movetime)
464 float savesolid, movetime2, pushltime;
465 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
467 edict_t *moved_edict[MAX_EDICTS];
468 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
469 model_t *pushermodel;
472 switch ((int) pusher->v.solid)
474 // LordHavoc: valid pusher types
478 case SOLID_CORPSE: // LordHavoc: this would be weird...
480 // LordHavoc: no collisions
483 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
484 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
485 pusher->v.ltime += movetime;
486 SV_LinkEdict (pusher, false);
489 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
491 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2] && !pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
493 pusher->v.ltime += movetime;
496 index = (int) pusher->v.modelindex;
497 if (index < 1 || index >= MAX_MODELS)
498 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
499 pushermodel = sv.models[index];
501 movetime2 = movetime;
502 VectorScale(pusher->v.velocity, movetime2, move1);
503 VectorScale(pusher->v.avelocity, movetime2, moveangle);
504 if (moveangle[0] || moveangle[2])
506 for (i = 0;i < 3;i++)
510 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
511 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
515 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
516 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
520 else if (moveangle[1])
522 for (i = 0;i < 3;i++)
526 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
527 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
531 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
532 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
538 for (i = 0;i < 3;i++)
542 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
543 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
547 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
548 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
553 VectorNegate (moveangle, a);
554 AngleVectorsFLU (a, forward, left, up);
556 VectorCopy (pusher->v.origin, pushorig);
557 VectorCopy (pusher->v.angles, pushang);
558 pushltime = pusher->v.ltime;
560 // move the pusher to it's final position
562 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
563 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
564 pusher->v.ltime += movetime;
565 SV_LinkEdict (pusher, false);
567 savesolid = pusher->v.solid;
569 // see if any solid entities are inside the final position
571 check = NEXT_EDICT(sv.edicts);
572 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
576 if (check->v.movetype == MOVETYPE_PUSH
577 || check->v.movetype == MOVETYPE_NONE
578 || check->v.movetype == MOVETYPE_FOLLOW
579 || check->v.movetype == MOVETYPE_NOCLIP)
582 // if the entity is standing on the pusher, it will definitely be moved
583 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
585 if (check->v.absmin[0] >= maxs[0]
586 || check->v.absmax[0] <= mins[0]
587 || check->v.absmin[1] >= maxs[1]
588 || check->v.absmax[1] <= mins[1]
589 || check->v.absmin[2] >= maxs[2]
590 || check->v.absmax[2] <= mins[2])
593 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
594 if (!trace.startsolid)
598 if (forward[0] < 0.999f) // quick way to check if any rotation is used
600 VectorSubtract (check->v.origin, pusher->v.origin, org);
601 org2[0] = DotProduct (org, forward);
602 org2[1] = DotProduct (org, left);
603 org2[2] = DotProduct (org, up);
604 VectorSubtract (org2, org, move);
605 VectorAdd (move, move1, move);
608 VectorCopy (move1, move);
610 // remove the onground flag for non-players
611 if (check->v.movetype != MOVETYPE_WALK)
612 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
614 VectorCopy (check->v.origin, moved_from[num_moved]);
615 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
616 moved_edict[num_moved++] = check;
618 // try moving the contacted entity
619 pusher->v.solid = SOLID_NOT;
620 trace = SV_PushEntity (check, move, moveangle);
621 pusher->v.solid = savesolid; // was SOLID_BSP
623 // if it is still inside the pusher, block
624 if (SV_TestEntityPosition (check))
627 if (check->v.mins[0] == check->v.maxs[0])
629 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
632 check->v.mins[0] = check->v.mins[1] = 0;
633 VectorCopy (check->v.mins, check->v.maxs);
637 VectorCopy (pushorig, pusher->v.origin);
638 VectorCopy (pushang, pusher->v.angles);
639 pusher->v.ltime = pushltime;
640 SV_LinkEdict (pusher, false);
642 // move back any entities we already moved
643 for (i=0 ; i<num_moved ; i++)
645 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
646 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
647 SV_LinkEdict (moved_edict[i], false);
650 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
651 if (pusher->v.blocked)
653 pr_global_struct->self = EDICT_TO_PROG(pusher);
654 pr_global_struct->other = EDICT_TO_PROG(check);
655 PR_ExecuteProgram (pusher->v.blocked, "");
668 void SV_Physics_Pusher (edict_t *ent)
670 float thinktime, oldltime, movetime;
672 oldltime = ent->v.ltime;
674 thinktime = ent->v.nextthink;
675 if (thinktime < ent->v.ltime + sv.frametime)
677 movetime = thinktime - ent->v.ltime;
682 movetime = sv.frametime;
685 // advances ent->v.ltime if not blocked
686 SV_PushMove (ent, movetime);
688 if (thinktime > oldltime && thinktime <= ent->v.ltime)
690 ent->v.nextthink = 0;
691 pr_global_struct->time = sv.time;
692 pr_global_struct->self = EDICT_TO_PROG(ent);
693 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
694 PR_ExecuteProgram (ent->v.think, "NULL think function");
703 ===============================================================================
707 ===============================================================================
714 This is a big hack to try and fix the rare case of getting stuck in the world
718 void SV_CheckStuck (edict_t *ent)
723 if (!SV_TestEntityPosition(ent))
725 VectorCopy (ent->v.origin, ent->v.oldorigin);
729 VectorCopy (ent->v.origin, org);
730 VectorCopy (ent->v.oldorigin, ent->v.origin);
731 if (!SV_TestEntityPosition(ent))
733 Con_DPrintf ("Unstuck.\n");
734 SV_LinkEdict (ent, true);
738 for (z=0 ; z< 18 ; z++)
739 for (i=-1 ; i <= 1 ; i++)
740 for (j=-1 ; j <= 1 ; j++)
742 ent->v.origin[0] = org[0] + i;
743 ent->v.origin[1] = org[1] + j;
744 ent->v.origin[2] = org[2] + z;
745 if (!SV_TestEntityPosition(ent))
747 Con_DPrintf ("Unstuck.\n");
748 SV_LinkEdict (ent, true);
753 VectorCopy (org, ent->v.origin);
754 Con_DPrintf ("player is stuck.\n");
763 qboolean SV_CheckWater (edict_t *ent)
768 point[0] = ent->v.origin[0];
769 point[1] = ent->v.origin[1];
770 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
772 ent->v.waterlevel = 0;
773 ent->v.watertype = CONTENTS_EMPTY;
774 cont = Mod_PointContents(point, sv.worldmodel);
775 if (cont <= CONTENTS_WATER)
777 ent->v.watertype = cont;
778 ent->v.waterlevel = 1;
779 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
780 cont = Mod_PointContents(point, sv.worldmodel);
781 if (cont <= CONTENTS_WATER)
783 ent->v.waterlevel = 2;
784 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
785 cont = Mod_PointContents(point, sv.worldmodel);
786 if (cont <= CONTENTS_WATER)
787 ent->v.waterlevel = 3;
791 return ent->v.waterlevel > 1;
800 void SV_WallFriction (edict_t *ent, trace_t *trace)
803 vec3_t forward, into, side;
805 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
806 d = DotProduct (trace->plane.normal, forward);
812 // cut the tangential velocity
813 i = DotProduct (trace->plane.normal, ent->v.velocity);
814 VectorScale (trace->plane.normal, i, into);
815 VectorSubtract (ent->v.velocity, into, side);
817 ent->v.velocity[0] = side[0] * (1 + d);
818 ent->v.velocity[1] = side[1] * (1 + d);
822 =====================
825 Player has come to a dead stop, possibly due to the problem with limited
826 float precision at some angle joins in the BSP hull.
828 Try fixing by pushing one pixel in each direction.
830 This is a hack, but in the interest of good gameplay...
831 ======================
833 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
839 VectorCopy (ent->v.origin, oldorg);
842 for (i=0 ; i<8 ; i++)
844 // try pushing a little in an axial direction
847 case 0: dir[0] = 2; dir[1] = 0; break;
848 case 1: dir[0] = 0; dir[1] = 2; break;
849 case 2: dir[0] = -2; dir[1] = 0; break;
850 case 3: dir[0] = 0; dir[1] = -2; break;
851 case 4: dir[0] = 2; dir[1] = 2; break;
852 case 5: dir[0] = -2; dir[1] = 2; break;
853 case 6: dir[0] = 2; dir[1] = -2; break;
854 case 7: dir[0] = -2; dir[1] = -2; break;
857 SV_PushEntity (ent, dir, vec3_origin);
859 // retry the original move
860 ent->v.velocity[0] = oldvel[0];
861 ent->v.velocity[1] = oldvel[1];
862 ent->v.velocity[2] = 0;
863 clip = SV_FlyMove (ent, 0.1, &steptrace);
865 if (fabs(oldorg[1] - ent->v.origin[1]) > 4
866 || fabs(oldorg[0] - ent->v.origin[0]) > 4)
869 // go back to the original pos and try again
870 VectorCopy (oldorg, ent->v.origin);
874 VectorClear (ent->v.velocity);
879 =====================
883 ======================
885 void SV_WalkMove (edict_t *ent)
887 int clip, oldonground;
888 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel;
889 trace_t steptrace, downtrace;
891 // do a regular slide move unless it looks like you ran into a step
892 oldonground = (int)ent->v.flags & FL_ONGROUND;
893 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
895 VectorCopy (ent->v.origin, oldorg);
896 VectorCopy (ent->v.velocity, oldvel);
898 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
900 // if move didn't block on a step, return
904 if (ent->v.movetype != MOVETYPE_FLY)
906 if (!oldonground && ent->v.waterlevel == 0 && !sv_jumpstep.integer)
907 // don't stair up while jumping
910 if (ent->v.movetype != MOVETYPE_WALK)
911 // gibbed by a trigger
915 if (sv_nostep.integer)
918 if ( (int)sv_player->v.flags & FL_WATERJUMP )
921 VectorCopy (ent->v.origin, nosteporg);
922 VectorCopy (ent->v.velocity, nostepvel);
924 // try moving up and forward to go up a step
926 VectorCopy (oldorg, ent->v.origin);
928 VectorClear (upmove);
929 VectorClear (downmove);
930 upmove[2] = sv_stepheight.value;
931 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
934 // FIXME: don't link?
935 SV_PushEntity (ent, upmove, vec3_origin);
938 ent->v.velocity[0] = oldvel[0];
939 ent->v.velocity[1] = oldvel[1];
940 ent->v.velocity[2] = 0;
941 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
942 ent->v.velocity[2] += oldvel[2];
944 // check for stuckness, possibly due to the limited precision of floats
945 // in the clipping hulls
947 && fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
948 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125)
949 // stepping up didn't make any progress
950 clip = SV_TryUnstick (ent, oldvel);
952 // extra friction based on view angle
953 if (clip & 2 && sv_wallfriction.integer)
954 SV_WallFriction (ent, &steptrace);
957 // FIXME: don't link?
958 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
960 if (downtrace.plane.normal[2] > 0.7)
962 // LordHavoc: disabled this so you can walk on monsters/players
963 //if (ent->v.solid == SOLID_BSP)
965 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
966 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
971 // if the push down didn't end up on good ground, use the move without
972 // the step up. This happens near wall / slope combinations, and can
973 // cause the player to hop up higher on a slope too steep to climb
974 VectorCopy (nosteporg, ent->v.origin);
975 VectorCopy (nostepvel, ent->v.velocity);
984 Player character actions
987 void SV_Physics_Client (edict_t *ent, int num)
989 if (!svs.clients[num-1].active)
990 return; // unconnected slot
992 // call standard client pre-think
993 pr_global_struct->time = sv.time;
994 pr_global_struct->self = EDICT_TO_PROG(ent);
995 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
998 SV_CheckVelocity (ent);
1000 // decide which move function to call
1001 switch ((int)ent->v.movetype)
1004 if (!SV_RunThink (ent))
1009 if (!SV_RunThink (ent))
1011 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1012 SV_AddGravity (ent);
1013 SV_CheckStuck (ent);
1018 case MOVETYPE_BOUNCE:
1019 SV_Physics_Toss (ent);
1023 if (!SV_RunThink (ent))
1025 SV_CheckWater (ent);
1026 //SV_FlyMove (ent, sv.frametime, NULL);
1030 case MOVETYPE_NOCLIP:
1031 if (!SV_RunThink (ent))
1033 SV_CheckWater (ent);
1034 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1035 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1039 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1042 // call standard player post-think
1043 SV_LinkEdict (ent, true);
1045 pr_global_struct->time = sv.time;
1046 pr_global_struct->self = EDICT_TO_PROG(ent);
1047 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1050 //============================================================================
1056 Entities that are "stuck" to another entity
1059 void SV_Physics_Follow (edict_t *ent)
1061 vec3_t vf, vr, vu, angles, v;
1065 if (!SV_RunThink (ent))
1068 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1069 e = PROG_TO_EDICT(ent->v.aiment);
1070 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])
1072 // quick case for no rotation
1073 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1077 angles[0] = -ent->v.punchangle[0];
1078 angles[1] = ent->v.punchangle[1];
1079 angles[2] = ent->v.punchangle[2];
1080 AngleVectors (angles, vf, vr, vu);
1081 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1082 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1083 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1084 angles[0] = -e->v.angles[0];
1085 angles[1] = e->v.angles[1];
1086 angles[2] = e->v.angles[2];
1087 AngleVectors (angles, vf, vr, vu);
1088 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1089 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1090 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1092 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1093 SV_LinkEdict (ent, true);
1100 A moving object that doesn't obey physics
1103 void SV_Physics_Noclip (edict_t *ent)
1106 if (!SV_RunThink (ent))
1109 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1110 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1112 SV_LinkEdict (ent, false);
1116 ==============================================================================
1120 ==============================================================================
1125 SV_CheckWaterTransition
1129 void SV_CheckWaterTransition (edict_t *ent)
1132 cont = Mod_PointContents(ent->v.origin, sv.worldmodel);
1133 if (!ent->v.watertype)
1135 // just spawned here
1136 ent->v.watertype = cont;
1137 ent->v.waterlevel = 1;
1141 if (cont <= CONTENTS_WATER)
1143 if (ent->v.watertype == CONTENTS_EMPTY && cont != CONTENTS_LAVA)
1144 // just crossed into water
1145 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1147 ent->v.watertype = cont;
1148 ent->v.waterlevel = 1;
1152 if (ent->v.watertype != CONTENTS_EMPTY && ent->v.watertype != CONTENTS_LAVA)
1153 // just crossed into water
1154 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1156 ent->v.watertype = CONTENTS_EMPTY;
1157 ent->v.waterlevel = cont;
1165 Toss, bounce, and fly movement. When onground, do nothing.
1168 void SV_Physics_Toss (edict_t *ent)
1172 edict_t *groundentity;
1175 if (!SV_RunThink (ent))
1178 // if onground, return without moving
1179 if ((int)ent->v.flags & FL_ONGROUND)
1181 VectorClear(ent->v.velocity);
1182 if (ent->v.groundentity == 0)
1184 // if ent was supported by a brush model on previous frame,
1185 // and groundentity is now freed, set groundentity to 0 (floating)
1186 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1187 if (groundentity->v.solid == SOLID_BSP)
1189 ent->suspendedinairflag = true;
1192 else if (ent->suspendedinairflag && groundentity->free)
1194 // leave it suspended in the air
1195 ent->v.groundentity = 0;
1196 ent->suspendedinairflag = false;
1200 ent->suspendedinairflag = false;
1202 SV_CheckVelocity (ent);
1205 if (ent->v.movetype == MOVETYPE_TOSS || ent->v.movetype == MOVETYPE_BOUNCE)
1206 SV_AddGravity (ent);
1209 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1212 VectorScale (ent->v.velocity, sv.frametime, move);
1213 trace = SV_PushEntity (ent, move, vec3_origin);
1217 if (trace.fraction < 1)
1219 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1221 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 2.0);
1222 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1224 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1226 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
1227 // LordHavoc: fixed grenades not bouncing when fired down a slope
1228 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1230 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1231 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1232 VectorClear (ent->v.velocity);
1233 VectorClear (ent->v.avelocity);
1236 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1240 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0);
1241 if (trace.plane.normal[2] > 0.7)
1243 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1244 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1245 VectorClear (ent->v.velocity);
1246 VectorClear (ent->v.avelocity);
1249 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1253 // check for in water
1254 SV_CheckWaterTransition (ent);
1258 ===============================================================================
1262 ===============================================================================
1269 Monsters freefall when they don't have a ground entity, otherwise
1270 all movement is done with discrete steps.
1272 This is also used for objects that have become still on the ground, but
1273 will fall if the floor is pulled out from under them.
1276 void SV_Physics_Step (edict_t *ent)
1278 int flags, fall, hitsound;
1280 // freefall if not fly/swim
1282 flags = (int)ent->v.flags;
1283 if (flags & (FL_FLY | FL_SWIM))
1287 else if ((flags & FL_SWIM) && Mod_PointContents(ent->v.origin, sv.worldmodel) != CONTENTS_EMPTY)
1290 if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
1295 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1298 if (flags & FL_ONGROUND)
1304 SV_AddGravity (ent);
1305 SV_CheckVelocity (ent);
1306 SV_FlyMove (ent, sv.frametime, NULL);
1307 SV_LinkEdict (ent, false);
1310 if ((int)ent->v.flags & FL_ONGROUND)
1312 VectorClear(ent->v.velocity);
1314 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1321 SV_CheckWaterTransition (ent);
1324 //============================================================================
1332 void SV_Physics (void)
1337 // let the progs know that a new frame has started
1338 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1339 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1340 pr_global_struct->time = sv.time;
1341 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1344 // treat each object in turn
1347 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1352 if (pr_global_struct->force_retouch)
1353 SV_LinkEdict (ent, true); // force retouch even for stationary
1355 if (i > 0 && i <= svs.maxclients)
1357 SV_Physics_Client (ent, i);
1361 switch ((int) ent->v.movetype)
1364 SV_Physics_Pusher (ent);
1367 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1368 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1371 case MOVETYPE_FOLLOW:
1372 SV_Physics_Follow (ent);
1374 case MOVETYPE_NOCLIP:
1375 SV_Physics_Noclip (ent);
1378 SV_Physics_Step (ent);
1380 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1382 if (SV_RunThink (ent))
1384 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1385 SV_AddGravity (ent);
1386 SV_CheckStuck (ent);
1388 SV_LinkEdict (ent, true);
1392 case MOVETYPE_BOUNCE:
1393 case MOVETYPE_BOUNCEMISSILE:
1395 case MOVETYPE_FLYMISSILE:
1396 SV_Physics_Toss (ent);
1399 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1404 if (pr_global_struct->force_retouch)
1405 pr_global_struct->force_retouch--;
1407 // LordHavoc: endframe support
1410 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1411 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1412 pr_global_struct->time = sv.time;
1413 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1416 sv.time += sv.frametime;
1420 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1423 float gravity, savesolid;
1425 edict_t tempent, *tent;
1429 memcpy(&tempent, tossent, sizeof(edict_t));
1431 savesolid = tossent->v.solid;
1432 tossent->v.solid = SOLID_NOT;
1434 // this has to fetch the field from the original edict, since our copy is truncated
1435 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1436 if (val != NULL && val->_float != 0)
1437 gravity = val->_float;
1440 gravity *= sv_gravity.value * 0.05;
1442 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1444 SV_CheckVelocity (tent);
1445 tent->v.velocity[2] -= gravity;
1446 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1447 VectorScale (tent->v.velocity, 0.05, move);
1448 VectorAdd (tent->v.origin, move, end);
1449 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1450 VectorCopy (trace.endpos, tent->v.origin);
1452 if (trace.fraction < 1 && trace.ent)
1453 if (trace.ent != ignore)
1456 tossent->v.solid = savesolid;
1457 trace.fraction = 0; // not relevant