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))
626 // try moving the contacted entity a tiny bit further to account for precision errors
627 pusher->v->solid = SOLID_NOT;
628 VectorScale(move, 0.1, move);
629 trace = SV_PushEntity (check, move, vec3_origin);
630 pusher->v->solid = savesolid;
631 if (SV_TestEntityPosition (check))
633 // still inside pusher, so it's really blocked
636 if (check->v->mins[0] == check->v->maxs[0])
638 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
641 check->v->mins[0] = check->v->mins[1] = 0;
642 VectorCopy (check->v->mins, check->v->maxs);
646 VectorCopy (pushorig, pusher->v->origin);
647 VectorCopy (pushang, pusher->v->angles);
648 pusher->v->ltime = pushltime;
649 SV_LinkEdict (pusher, false);
651 // move back any entities we already moved
652 for (i=0 ; i<num_moved ; i++)
654 VectorCopy (moved_from[i], moved_edict[i]->v->origin);
655 VectorCopy (moved_fromangles[i], moved_edict[i]->v->angles);
656 SV_LinkEdict (moved_edict[i], false);
659 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
660 if (pusher->v->blocked)
662 pr_global_struct->self = EDICT_TO_PROG(pusher);
663 pr_global_struct->other = EDICT_TO_PROG(check);
664 PR_ExecuteProgram (pusher->v->blocked, "");
678 void SV_Physics_Pusher (edict_t *ent)
680 float thinktime, oldltime, movetime;
682 oldltime = ent->v->ltime;
684 thinktime = ent->v->nextthink;
685 if (thinktime < ent->v->ltime + sv.frametime)
687 movetime = thinktime - ent->v->ltime;
692 movetime = sv.frametime;
695 // advances ent->v->ltime if not blocked
696 SV_PushMove (ent, movetime);
698 if (thinktime > oldltime && thinktime <= ent->v->ltime)
700 ent->v->nextthink = 0;
701 pr_global_struct->time = sv.time;
702 pr_global_struct->self = EDICT_TO_PROG(ent);
703 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
704 PR_ExecuteProgram (ent->v->think, "NULL think function");
713 ===============================================================================
717 ===============================================================================
724 This is a big hack to try and fix the rare case of getting stuck in the world
728 void SV_CheckStuck (edict_t *ent)
733 if (!SV_TestEntityPosition(ent))
735 VectorCopy (ent->v->origin, ent->v->oldorigin);
739 VectorCopy (ent->v->origin, org);
740 VectorCopy (ent->v->oldorigin, ent->v->origin);
741 if (!SV_TestEntityPosition(ent))
743 Con_DPrintf ("Unstuck.\n");
744 SV_LinkEdict (ent, true);
748 for (z=0 ; z< 18 ; z++)
749 for (i=-1 ; i <= 1 ; i++)
750 for (j=-1 ; j <= 1 ; j++)
752 ent->v->origin[0] = org[0] + i;
753 ent->v->origin[1] = org[1] + j;
754 ent->v->origin[2] = org[2] + z;
755 if (!SV_TestEntityPosition(ent))
757 Con_DPrintf ("Unstuck.\n");
758 SV_LinkEdict (ent, true);
763 VectorCopy (org, ent->v->origin);
764 Con_DPrintf ("player is stuck.\n");
773 qboolean SV_CheckWater (edict_t *ent)
778 point[0] = ent->v->origin[0];
779 point[1] = ent->v->origin[1];
780 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
782 ent->v->waterlevel = 0;
783 ent->v->watertype = CONTENTS_EMPTY;
784 cont = Mod_PointContents(point, sv.worldmodel);
785 if (cont <= CONTENTS_WATER)
787 ent->v->watertype = cont;
788 ent->v->waterlevel = 1;
789 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
790 cont = Mod_PointContents(point, sv.worldmodel);
791 if (cont <= CONTENTS_WATER)
793 ent->v->waterlevel = 2;
794 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
795 cont = Mod_PointContents(point, sv.worldmodel);
796 if (cont <= CONTENTS_WATER)
797 ent->v->waterlevel = 3;
801 return ent->v->waterlevel > 1;
810 void SV_WallFriction (edict_t *ent, trace_t *trace)
813 vec3_t forward, into, side;
815 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
816 d = DotProduct (trace->plane.normal, forward);
822 // cut the tangential velocity
823 i = DotProduct (trace->plane.normal, ent->v->velocity);
824 VectorScale (trace->plane.normal, i, into);
825 VectorSubtract (ent->v->velocity, into, side);
827 ent->v->velocity[0] = side[0] * (1 + d);
828 ent->v->velocity[1] = side[1] * (1 + d);
832 =====================
835 Player has come to a dead stop, possibly due to the problem with limited
836 float precision at some angle joins in the BSP hull.
838 Try fixing by pushing one pixel in each direction.
840 This is a hack, but in the interest of good gameplay...
841 ======================
843 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
849 VectorCopy (ent->v->origin, oldorg);
852 for (i=0 ; i<8 ; i++)
854 // try pushing a little in an axial direction
857 case 0: dir[0] = 2; dir[1] = 0; break;
858 case 1: dir[0] = 0; dir[1] = 2; break;
859 case 2: dir[0] = -2; dir[1] = 0; break;
860 case 3: dir[0] = 0; dir[1] = -2; break;
861 case 4: dir[0] = 2; dir[1] = 2; break;
862 case 5: dir[0] = -2; dir[1] = 2; break;
863 case 6: dir[0] = 2; dir[1] = -2; break;
864 case 7: dir[0] = -2; dir[1] = -2; break;
867 SV_PushEntity (ent, dir, vec3_origin);
869 // retry the original move
870 ent->v->velocity[0] = oldvel[0];
871 ent->v->velocity[1] = oldvel[1];
872 ent->v->velocity[2] = 0;
873 clip = SV_FlyMove (ent, 0.1, &steptrace);
875 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
876 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
879 // go back to the original pos and try again
880 VectorCopy (oldorg, ent->v->origin);
884 VectorClear (ent->v->velocity);
889 =====================
893 ======================
895 void SV_WalkMove (edict_t *ent)
897 int clip, oldonground;
898 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel;
899 trace_t steptrace, downtrace;
901 // do a regular slide move unless it looks like you ran into a step
902 oldonground = (int)ent->v->flags & FL_ONGROUND;
903 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
905 VectorCopy (ent->v->origin, oldorg);
906 VectorCopy (ent->v->velocity, oldvel);
908 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
910 // if move didn't block on a step, return
914 if (ent->v->movetype != MOVETYPE_FLY)
916 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
917 // don't stair up while jumping
920 if (ent->v->movetype != MOVETYPE_WALK)
921 // gibbed by a trigger
925 if (sv_nostep.integer)
928 if ( (int)sv_player->v->flags & FL_WATERJUMP )
931 VectorCopy (ent->v->origin, nosteporg);
932 VectorCopy (ent->v->velocity, nostepvel);
934 // try moving up and forward to go up a step
936 VectorCopy (oldorg, ent->v->origin);
938 VectorClear (upmove);
939 VectorClear (downmove);
940 upmove[2] = sv_stepheight.value;
941 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
944 // FIXME: don't link?
945 SV_PushEntity (ent, upmove, vec3_origin);
948 ent->v->velocity[0] = oldvel[0];
949 ent->v->velocity[1] = oldvel[1];
950 ent->v->velocity[2] = 0;
951 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
952 ent->v->velocity[2] += oldvel[2];
954 // check for stuckness, possibly due to the limited precision of floats
955 // in the clipping hulls
957 && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
958 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
959 // stepping up didn't make any progress
960 clip = SV_TryUnstick (ent, oldvel);
962 // extra friction based on view angle
963 if (clip & 2 && sv_wallfriction.integer)
964 SV_WallFriction (ent, &steptrace);
967 // FIXME: don't link?
968 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
970 if (downtrace.plane.normal[2] > 0.7)
972 // LordHavoc: disabled this so you can walk on monsters/players
973 //if (ent->v->solid == SOLID_BSP)
975 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
976 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
981 // if the push down didn't end up on good ground, use the move without
982 // the step up. This happens near wall / slope combinations, and can
983 // cause the player to hop up higher on a slope too steep to climb
984 VectorCopy (nosteporg, ent->v->origin);
985 VectorCopy (nostepvel, ent->v->velocity);
994 Player character actions
997 void SV_Physics_Client (edict_t *ent, int num)
999 if (!svs.clients[num-1].active)
1000 return; // unconnected slot
1002 // call standard client pre-think
1003 pr_global_struct->time = sv.time;
1004 pr_global_struct->self = EDICT_TO_PROG(ent);
1005 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1008 SV_CheckVelocity (ent);
1010 // decide which move function to call
1011 switch ((int)ent->v->movetype)
1014 if (!SV_RunThink (ent))
1019 if (!SV_RunThink (ent))
1021 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1022 SV_AddGravity (ent);
1023 SV_CheckStuck (ent);
1028 case MOVETYPE_BOUNCE:
1029 SV_Physics_Toss (ent);
1033 if (!SV_RunThink (ent))
1035 SV_CheckWater (ent);
1036 //SV_FlyMove (ent, sv.frametime, NULL);
1040 case MOVETYPE_NOCLIP:
1041 if (!SV_RunThink (ent))
1043 SV_CheckWater (ent);
1044 VectorMA (ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1045 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1049 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v->movetype);
1052 // call standard player post-think
1053 SV_LinkEdict (ent, true);
1055 pr_global_struct->time = sv.time;
1056 pr_global_struct->self = EDICT_TO_PROG(ent);
1057 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1060 //============================================================================
1066 Entities that are "stuck" to another entity
1069 void SV_Physics_Follow (edict_t *ent)
1071 vec3_t vf, vr, vu, angles, v;
1075 if (!SV_RunThink (ent))
1078 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1079 e = PROG_TO_EDICT(ent->v->aiment);
1080 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])
1082 // quick case for no rotation
1083 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1087 angles[0] = -ent->v->punchangle[0];
1088 angles[1] = ent->v->punchangle[1];
1089 angles[2] = ent->v->punchangle[2];
1090 AngleVectors (angles, vf, vr, vu);
1091 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1092 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1093 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1094 angles[0] = -e->v->angles[0];
1095 angles[1] = e->v->angles[1];
1096 angles[2] = e->v->angles[2];
1097 AngleVectors (angles, vf, vr, vu);
1098 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1099 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1100 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1102 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1103 SV_LinkEdict (ent, true);
1110 A moving object that doesn't obey physics
1113 void SV_Physics_Noclip (edict_t *ent)
1116 if (!SV_RunThink (ent))
1119 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1120 VectorMA (ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1122 SV_LinkEdict (ent, false);
1126 ==============================================================================
1130 ==============================================================================
1135 SV_CheckWaterTransition
1139 void SV_CheckWaterTransition (edict_t *ent)
1142 cont = Mod_PointContents(ent->v->origin, sv.worldmodel);
1143 if (!ent->v->watertype)
1145 // just spawned here
1146 ent->v->watertype = cont;
1147 ent->v->waterlevel = 1;
1151 if (cont <= CONTENTS_WATER)
1153 if (ent->v->watertype == CONTENTS_EMPTY && cont != CONTENTS_LAVA)
1154 // just crossed into water
1155 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1157 ent->v->watertype = cont;
1158 ent->v->waterlevel = 1;
1162 if (ent->v->watertype != CONTENTS_EMPTY && ent->v->watertype != CONTENTS_LAVA)
1163 // just crossed into water
1164 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1166 ent->v->watertype = CONTENTS_EMPTY;
1167 ent->v->waterlevel = cont;
1175 Toss, bounce, and fly movement. When onground, do nothing.
1178 void SV_Physics_Toss (edict_t *ent)
1182 edict_t *groundentity;
1185 if (!SV_RunThink (ent))
1188 // if onground, return without moving
1189 if ((int)ent->v->flags & FL_ONGROUND)
1191 VectorClear(ent->v->velocity);
1192 if (ent->v->groundentity == 0)
1194 // if ent was supported by a brush model on previous frame,
1195 // and groundentity is now freed, set groundentity to 0 (floating)
1196 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1197 if (groundentity->v->solid == SOLID_BSP)
1199 ent->suspendedinairflag = true;
1202 else if (ent->suspendedinairflag && groundentity->free)
1204 // leave it suspended in the air
1205 ent->v->groundentity = 0;
1206 ent->suspendedinairflag = false;
1210 ent->suspendedinairflag = false;
1212 SV_CheckVelocity (ent);
1215 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1216 SV_AddGravity (ent);
1219 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1222 VectorScale (ent->v->velocity, sv.frametime, move);
1223 trace = SV_PushEntity (ent, move, vec3_origin);
1227 if (trace.fraction < 1)
1229 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1231 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1232 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1234 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1236 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1237 // LordHavoc: fixed grenades not bouncing when fired down a slope
1238 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v->velocity) < 60)
1240 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1241 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1242 VectorClear (ent->v->velocity);
1243 VectorClear (ent->v->avelocity);
1246 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1250 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1251 if (trace.plane.normal[2] > 0.7)
1253 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1254 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1255 VectorClear (ent->v->velocity);
1256 VectorClear (ent->v->avelocity);
1259 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1263 // check for in water
1264 SV_CheckWaterTransition (ent);
1268 ===============================================================================
1272 ===============================================================================
1279 Monsters freefall when they don't have a ground entity, otherwise
1280 all movement is done with discrete steps.
1282 This is also used for objects that have become still on the ground, but
1283 will fall if the floor is pulled out from under them.
1286 void SV_Physics_Step (edict_t *ent)
1288 int flags, fall, hitsound;
1290 // freefall if not fly/swim
1292 flags = (int)ent->v->flags;
1293 if (flags & (FL_FLY | FL_SWIM))
1297 else if ((flags & FL_SWIM) && Mod_PointContents(ent->v->origin, sv.worldmodel) != CONTENTS_EMPTY)
1300 if (fall && (flags & FL_ONGROUND) && ent->v->groundentity == 0)
1305 if (ent->v->velocity[2] < sv_gravity.value*-0.1)
1308 if (flags & FL_ONGROUND)
1314 SV_AddGravity (ent);
1315 SV_CheckVelocity (ent);
1316 SV_FlyMove (ent, sv.frametime, NULL);
1317 SV_LinkEdict (ent, false);
1320 if ((int)ent->v->flags & FL_ONGROUND)
1322 VectorClear(ent->v->velocity);
1324 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1331 SV_CheckWaterTransition (ent);
1334 //============================================================================
1342 void SV_Physics (void)
1347 // let the progs know that a new frame has started
1348 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1349 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1350 pr_global_struct->time = sv.time;
1351 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1354 // treat each object in turn
1357 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1362 if (pr_global_struct->force_retouch)
1363 SV_LinkEdict (ent, true); // force retouch even for stationary
1365 if (i > 0 && i <= svs.maxclients)
1367 SV_Physics_Client (ent, i);
1371 switch ((int) ent->v->movetype)
1374 SV_Physics_Pusher (ent);
1377 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1378 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1381 case MOVETYPE_FOLLOW:
1382 SV_Physics_Follow (ent);
1384 case MOVETYPE_NOCLIP:
1385 SV_Physics_Noclip (ent);
1388 SV_Physics_Step (ent);
1390 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1392 if (SV_RunThink (ent))
1394 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1395 SV_AddGravity (ent);
1396 SV_CheckStuck (ent);
1398 SV_LinkEdict (ent, true);
1402 case MOVETYPE_BOUNCE:
1403 case MOVETYPE_BOUNCEMISSILE:
1405 case MOVETYPE_FLYMISSILE:
1406 SV_Physics_Toss (ent);
1409 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1414 if (pr_global_struct->force_retouch)
1415 pr_global_struct->force_retouch--;
1417 // LordHavoc: endframe support
1420 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1421 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1422 pr_global_struct->time = sv.time;
1423 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1426 sv.time += sv.frametime;
1430 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1433 float gravity, savesolid;
1435 edict_t tempent, *tent;
1439 memcpy(&tempent, tossent, sizeof(edict_t));
1441 savesolid = tossent->v->solid;
1442 tossent->v->solid = SOLID_NOT;
1444 // this has to fetch the field from the original edict, since our copy is truncated
1445 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1446 if (val != NULL && val->_float != 0)
1447 gravity = val->_float;
1450 gravity *= sv_gravity.value * 0.05;
1452 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1454 SV_CheckVelocity (tent);
1455 tent->v->velocity[2] -= gravity;
1456 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1457 VectorScale (tent->v->velocity, 0.05, move);
1458 VectorAdd (tent->v->origin, move, end);
1459 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1460 VectorCopy (trace.endpos, tent->v->origin);
1462 if (trace.fraction < 1 && trace.ent)
1463 if (trace.ent != ignore)
1466 tossent->v->solid = savesolid;
1467 trace.fraction = 0; // not relevant