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 = {0, "sv_stopspeed","100"};
44 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"};
45 cvar_t sv_maxvelocity = {0, "sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {0, "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;
128 Runs thinking code if time. There is some play in the exact time the think
129 function will be called, because it is called before any movement is done
130 in a frame. Not used for pushmove objects, because they must be exact.
131 Returns false if the entity removed itself.
134 qboolean SV_RunThink (edict_t *ent)
138 thinktime = ent->v.nextthink;
139 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
142 if (thinktime < sv.time)
143 thinktime = sv.time; // don't let things stay in the past.
144 // it is possible to start that way
145 // by a trigger with a local time.
146 ent->v.nextthink = 0;
147 pr_global_struct->time = thinktime;
148 pr_global_struct->self = EDICT_TO_PROG(ent);
149 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
150 PR_ExecuteProgram (ent->v.think, "NULL think function");
158 Two entities have touched, so run their touch functions
161 void SV_Impact (edict_t *e1, edict_t *e2)
163 int old_self, old_other;
165 old_self = pr_global_struct->self;
166 old_other = pr_global_struct->other;
168 pr_global_struct->time = sv.time;
169 if (e1->v.touch && e1->v.solid != SOLID_NOT)
171 pr_global_struct->self = EDICT_TO_PROG(e1);
172 pr_global_struct->other = EDICT_TO_PROG(e2);
173 PR_ExecuteProgram (e1->v.touch, "");
176 if (e2->v.touch && e2->v.solid != SOLID_NOT)
178 pr_global_struct->self = EDICT_TO_PROG(e2);
179 pr_global_struct->other = EDICT_TO_PROG(e1);
180 PR_ExecuteProgram (e2->v.touch, "");
183 pr_global_struct->self = old_self;
184 pr_global_struct->other = old_other;
192 Slide off of the impacting object
193 returns the blocked flags (1 = floor, 2 = step / wall)
196 #define STOP_EPSILON 0.1
198 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
206 blocked |= 1; // floor
208 blocked |= 2; // step
210 backoff = DotProduct (in, normal) * overbounce;
212 for (i=0 ; i<3 ; i++)
214 change = normal[i]*backoff;
215 out[i] = in[i] - change;
216 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
228 The basic solid body movement clip that slides along multiple planes
229 Returns the clipflags if the velocity was modified (hit something solid)
233 If steptrace is not NULL, the trace of any vertical wall hit will be stored
236 // LordHavoc: increased from 5 to 20
237 #define MAX_CLIP_PLANES 20
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, MOVE_NORMAL, ent);
273 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
274 // entity is trapped in another solid
275 VectorClear(ent->v.velocity);
279 if (trace.fraction > 0)
280 { // actually covered some distance
281 VectorCopy (trace.endpos, ent->v.origin);
282 VectorCopy (ent->v.velocity, original_velocity);
286 if (trace.fraction == 1)
287 break; // moved the entire distance
290 Host_Error ("SV_FlyMove: !trace.ent");
292 if ((int) ent->v.flags & FL_ONGROUND)
294 if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
298 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
305 if (trace.plane.normal[2] > 0.7)
307 blocked |= 1; // floor
308 //if (trace.ent->v.solid == SOLID_BSP)
310 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
311 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
314 if (!trace.plane.normal[2])
316 blocked |= 2; // step
318 *steptrace = trace; // save for player extrafriction
322 // run the impact function
325 SV_Impact (ent, trace.ent);
327 break; // removed by the impact function
330 time_left -= time_left * trace.fraction;
332 // cliped to another plane
333 if (numplanes >= MAX_CLIP_PLANES)
334 { // this shouldn't really happen
335 VectorClear(ent->v.velocity);
339 VectorCopy (trace.plane.normal, planes[numplanes]);
343 // 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++)
351 if (DotProduct (new_velocity, planes[j]) < 0)
359 { // go along this plane
360 VectorCopy (new_velocity, ent->v.velocity);
363 { // go along the crease
366 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
367 VectorClear(ent->v.velocity);
370 CrossProduct (planes[0], planes[1], dir);
371 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
372 VectorNormalize(dir);
373 d = DotProduct (dir, ent->v.velocity);
374 VectorScale (dir, d, ent->v.velocity);
378 // if original velocity is against the original velocity, stop dead
379 // 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)
404 val = GETEDICTFIELDVALUE(ent, eval_gravity);
405 if (val!=0 && val->_float)
406 ent_gravity = val->_float;
409 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
414 ===============================================================================
418 ===============================================================================
425 Does not change the entities velocity at all
428 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
433 VectorAdd (ent->v.origin, push, end);
435 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
436 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
437 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
438 // only clip against bmodels
439 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
441 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
443 VectorCopy (trace.endpos, ent->v.origin);
444 // FIXME: turn players specially
445 ent->v.angles[1] += trace.fraction * pushangles[1];
446 SV_LinkEdict (ent, true);
448 if (trace.ent && (!((int)ent->v.flags & FL_ONGROUND) || ent->v.groundentity != EDICT_TO_PROG(trace.ent)))
449 SV_Impact (ent, trace.ent);
460 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
461 void SV_PushMove (edict_t *pusher, float movetime)
465 float savesolid, movetime2, pushltime;
466 vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
468 edict_t *moved_edict[MAX_EDICTS];
469 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
470 model_t *pushermodel;
473 switch ((int) pusher->v.solid)
475 // LordHavoc: valid pusher types
479 case SOLID_CORPSE: // LordHavoc: this would be weird...
481 // LordHavoc: no collisions
484 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
485 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
486 pusher->v.ltime += movetime;
487 SV_LinkEdict (pusher, false);
490 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
492 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])
494 pusher->v.ltime += movetime;
497 index = (int) pusher->v.modelindex;
498 if (index < 1 || index >= MAX_MODELS)
499 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
500 pushermodel = sv.models[index];
502 // LordHavoc: round up by a small epsilon
503 movetime2 = movetime; // + (1.0 / 256.0);
504 VectorScale(pusher->v.velocity, movetime2, move1);
505 VectorScale(pusher->v.avelocity, movetime2, moveangle);
506 if (moveangle[0] || moveangle[2])
508 for (i = 0;i < 3;i++)
512 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
513 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
517 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
518 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
522 else if (moveangle[1])
524 for (i = 0;i < 3;i++)
528 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
529 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
533 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
534 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
540 for (i = 0;i < 3;i++)
544 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
545 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
549 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
550 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
555 VectorNegate (moveangle, a);
556 AngleVectorsFLU (a, forward, left, up);
558 VectorCopy (pusher->v.origin, pushorig);
559 VectorCopy (pusher->v.angles, pushang);
560 pushltime = pusher->v.ltime;
562 // move the pusher to it's final position
564 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
565 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
566 pusher->v.ltime += movetime;
567 SV_LinkEdict (pusher, false);
569 savesolid = pusher->v.solid;
571 // see if any solid entities are inside the final position
573 check = NEXT_EDICT(sv.edicts);
574 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
578 if (check->v.movetype == MOVETYPE_PUSH
579 || check->v.movetype == MOVETYPE_NONE
580 || check->v.movetype == MOVETYPE_FOLLOW
581 || check->v.movetype == MOVETYPE_NOCLIP)
584 // if the entity is standing on the pusher, it will definitely be moved
585 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
587 if (check->v.absmin[0] >= maxs[0]
588 || check->v.absmax[0] <= mins[0]
589 || check->v.absmin[1] >= maxs[1]
590 || check->v.absmax[1] <= mins[1]
591 || check->v.absmin[2] >= maxs[2]
592 || check->v.absmax[2] <= mins[2])
596 if (forward[0] < 0.999f) // quick way to check if any rotation is used
598 VectorSubtract (check->v.origin, pusher->v.origin, org);
599 org2[0] = DotProduct (org, forward);
600 org2[1] = DotProduct (org, left);
601 org2[2] = DotProduct (org, up);
602 //VectorSubtract (org2, org, move);
603 //VectorAdd (move, move1, move);
604 //VectorSubtract(check->v.origin, move, a);
605 a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0];
606 a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1];
607 a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2];
610 VectorSubtract (check->v.origin, move1, a);
612 trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin);
613 if (trace.fraction == 1 && !trace.startsolid)
616 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
617 if (!trace.startsolid)
620 // see if the ent's bbox is inside the pusher's final position
621 if (!SV_TestEntityPosition (check))
626 if (forward[0] < 0.999f) // quick way to check if any rotation is used
628 VectorSubtract (check->v.origin, pusher->v.origin, org);
629 org2[0] = DotProduct (org, forward);
630 org2[1] = DotProduct (org, left);
631 org2[2] = DotProduct (org, up);
632 VectorSubtract (org2, org, move);
633 VectorAdd (move, move1, move);
636 VectorCopy (move1, move);
638 // LordHavoc: debugging
639 //VectorAdd(entorig, move, org2);
640 //CL_RocketTrail2 (entorig, org2, 238, NULL);
642 // remove the onground flag for non-players
643 if (check->v.movetype != MOVETYPE_WALK)
644 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
646 //VectorCopy (check->v.origin, entorig);
647 //VectorCopy (check->v.angles, entang);
648 VectorCopy (check->v.origin, moved_from[num_moved]);
649 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
650 moved_edict[num_moved++] = check;
652 // try moving the contacted entity
653 pusher->v.solid = SOLID_NOT;
654 trace = SV_PushEntity (check, move, moveangle);
655 pusher->v.solid = savesolid; // was SOLID_BSP
657 // if it is still inside the pusher, block
658 // LordHavoc: cleanup - check trace.fraction and startsolid
659 if (/*trace.fraction != 1 || trace.startsolid || */SV_TestEntityPosition (check))
662 if (check->v.mins[0] == check->v.maxs[0])
664 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
667 check->v.mins[0] = check->v.mins[1] = 0;
668 VectorCopy (check->v.mins, check->v.maxs);
673 VectorCopy (entorig, check->v.origin);
674 VectorCopy (entang, check->v.angles);
675 SV_LinkEdict (check, true);
678 VectorCopy (pushorig, pusher->v.origin);
679 VectorCopy (pushang, pusher->v.angles);
680 pusher->v.ltime = pushltime;
681 SV_LinkEdict (pusher, false);
683 // move back any entities we already moved
684 //num_moved--; // LordHavoc: pop off check, because it was already restored
685 for (i=0 ; i<num_moved ; i++)
687 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
688 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
689 SV_LinkEdict (moved_edict[i], false);
692 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
693 if (pusher->v.blocked)
695 pr_global_struct->self = EDICT_TO_PROG(pusher);
696 pr_global_struct->other = EDICT_TO_PROG(check);
697 PR_ExecuteProgram (pusher->v.blocked, "");
710 void SV_Physics_Pusher (edict_t *ent)
716 oldltime = ent->v.ltime;
718 thinktime = ent->v.nextthink;
719 if (thinktime < ent->v.ltime + sv.frametime)
721 movetime = thinktime - ent->v.ltime;
726 movetime = sv.frametime;
729 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
731 if (thinktime > oldltime && thinktime <= ent->v.ltime)
733 ent->v.nextthink = 0;
734 pr_global_struct->time = sv.time;
735 pr_global_struct->self = EDICT_TO_PROG(ent);
736 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
737 PR_ExecuteProgram (ent->v.think, "NULL think function");
746 ===============================================================================
750 ===============================================================================
757 This is a big hack to try and fix the rare case of getting stuck in the world
761 void SV_CheckStuck (edict_t *ent)
767 if (!SV_TestEntityPosition(ent))
769 VectorCopy (ent->v.origin, ent->v.oldorigin);
773 VectorCopy (ent->v.origin, org);
774 VectorCopy (ent->v.oldorigin, ent->v.origin);
775 if (!SV_TestEntityPosition(ent))
777 Con_DPrintf ("Unstuck.\n");
778 SV_LinkEdict (ent, true);
782 for (z=0 ; z< 18 ; z++)
783 for (i=-1 ; i <= 1 ; i++)
784 for (j=-1 ; j <= 1 ; j++)
786 ent->v.origin[0] = org[0] + i;
787 ent->v.origin[1] = org[1] + j;
788 ent->v.origin[2] = org[2] + z;
789 if (!SV_TestEntityPosition(ent))
791 Con_DPrintf ("Unstuck.\n");
792 SV_LinkEdict (ent, true);
797 VectorCopy (org, ent->v.origin);
798 Con_DPrintf ("player is stuck.\n");
807 qboolean SV_CheckWater (edict_t *ent)
812 point[0] = ent->v.origin[0];
813 point[1] = ent->v.origin[1];
814 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
816 ent->v.waterlevel = 0;
817 ent->v.watertype = CONTENTS_EMPTY;
818 cont = SV_PointContents (point);
819 if (cont <= CONTENTS_WATER)
821 ent->v.watertype = cont;
822 ent->v.waterlevel = 1;
823 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
824 cont = SV_PointContents (point);
825 if (cont <= CONTENTS_WATER)
827 ent->v.waterlevel = 2;
828 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
829 cont = SV_PointContents (point);
830 if (cont <= CONTENTS_WATER)
831 ent->v.waterlevel = 3;
835 return ent->v.waterlevel > 1;
844 void SV_WallFriction (edict_t *ent, trace_t *trace)
850 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
851 d = DotProduct (trace->plane.normal, forward);
857 // cut the tangential velocity
858 i = DotProduct (trace->plane.normal, ent->v.velocity);
859 VectorScale (trace->plane.normal, i, into);
860 VectorSubtract (ent->v.velocity, into, side);
862 ent->v.velocity[0] = side[0] * (1 + d);
863 ent->v.velocity[1] = side[1] * (1 + d);
867 =====================
870 Player has come to a dead stop, possibly due to the problem with limited
871 float precision at some angle joins in the BSP hull.
873 Try fixing by pushing one pixel in each direction.
875 This is a hack, but in the interest of good gameplay...
876 ======================
878 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
886 VectorCopy (ent->v.origin, oldorg);
889 for (i=0 ; i<8 ; i++)
891 // try pushing a little in an axial direction
894 case 0: dir[0] = 2; dir[1] = 0; break;
895 case 1: dir[0] = 0; dir[1] = 2; break;
896 case 2: dir[0] = -2; dir[1] = 0; break;
897 case 3: dir[0] = 0; dir[1] = -2; break;
898 case 4: dir[0] = 2; dir[1] = 2; break;
899 case 5: dir[0] = -2; dir[1] = 2; break;
900 case 6: dir[0] = 2; dir[1] = -2; break;
901 case 7: dir[0] = -2; dir[1] = -2; break;
904 SV_PushEntity (ent, dir, vec3_origin);
906 // retry the original move
907 ent->v.velocity[0] = oldvel[0];
908 ent->v.velocity[1] = oldvel[1];
909 ent->v.velocity[2] = 0;
910 clip = SV_FlyMove (ent, 0.1, &steptrace);
912 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
913 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
915 //Con_DPrintf ("unstuck!\n");
919 // go back to the original pos and try again
920 VectorCopy (oldorg, ent->v.origin);
923 VectorClear (ent->v.velocity);
924 return 7; // still not moving
928 =====================
932 ======================
935 void SV_WalkMove (edict_t *ent)
937 vec3_t upmove, downmove;
938 vec3_t oldorg, oldvel;
939 vec3_t nosteporg, nostepvel;
942 trace_t steptrace, downtrace;
945 // do a regular slide move unless it looks like you ran into a step
947 oldonground = (int)ent->v.flags & FL_ONGROUND;
948 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
950 VectorCopy (ent->v.origin, oldorg);
951 VectorCopy (ent->v.velocity, oldvel);
953 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
956 return; // move didn't block on a step
958 if (!oldonground && ent->v.waterlevel == 0)
959 return; // don't stair up while jumping
961 if (ent->v.movetype != MOVETYPE_WALK)
962 return; // gibbed by a trigger
964 if (sv_nostep.integer)
967 if ( (int)sv_player->v.flags & FL_WATERJUMP )
970 VectorCopy (ent->v.origin, nosteporg);
971 VectorCopy (ent->v.velocity, nostepvel);
974 // try moving up and forward to go up a step
976 VectorCopy (oldorg, ent->v.origin); // back to start pos
978 VectorClear (upmove);
979 VectorClear (downmove);
980 upmove[2] = STEPSIZE;
981 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
984 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
987 ent->v.velocity[0] = oldvel[0];
988 ent->v. velocity[1] = oldvel[1];
989 ent->v. velocity[2] = 0;
990 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
992 // check for stuckness, possibly due to the limited precision of floats
993 // in the clipping hulls
996 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
997 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
998 { // stepping up didn't make any progress
999 clip = SV_TryUnstick (ent, oldvel);
1003 // extra friction based on view angle
1005 SV_WallFriction (ent, &steptrace);
1008 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
1010 if (downtrace.plane.normal[2] > 0.7)
1012 if (ent->v.solid == SOLID_BSP)
1014 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1015 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1020 // if the push down didn't end up on good ground, use the move without
1021 // the step up. This happens near wall / slope combinations, and can
1022 // cause the player to hop up higher on a slope too steep to climb
1023 VectorCopy (nosteporg, ent->v.origin);
1024 VectorCopy (nostepvel, ent->v.velocity);
1033 Player character actions
1036 void SV_Physics_Client (edict_t *ent, int num)
1038 if ( ! svs.clients[num-1].active )
1039 return; // unconnected slot
1042 // call standard client pre-think
1044 pr_global_struct->time = sv.time;
1045 pr_global_struct->self = EDICT_TO_PROG(ent);
1046 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1051 SV_CheckVelocity (ent);
1054 // decide which move function to call
1056 switch ((int)ent->v.movetype)
1059 if (!SV_RunThink (ent))
1064 if (!SV_RunThink (ent))
1066 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1067 SV_AddGravity (ent);
1068 SV_CheckStuck (ent);
1073 case MOVETYPE_BOUNCE:
1074 SV_Physics_Toss (ent);
1078 if (!SV_RunThink (ent))
1080 SV_CheckWater (ent);
1081 SV_FlyMove (ent, sv.frametime, NULL);
1084 case MOVETYPE_NOCLIP:
1085 if (!SV_RunThink (ent))
1087 SV_CheckWater (ent);
1088 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1092 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1096 // call standard player post-think
1098 SV_LinkEdict (ent, true);
1100 pr_global_struct->time = sv.time;
1101 pr_global_struct->self = EDICT_TO_PROG(ent);
1102 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1105 //============================================================================
1111 Non moving objects can only think
1114 // LordHavoc: inlined manually because it was a real time waster
1116 void SV_Physics_None (edict_t *ent)
1127 Entities that are "stuck" to another entity
1130 void SV_Physics_Follow (edict_t *ent)
1132 vec3_t vf, vr, vu, angles, v;
1135 if (!SV_RunThink (ent))
1137 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1138 e = PROG_TO_EDICT(ent->v.aiment);
1139 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])
1141 // quick case for no rotation
1142 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1146 angles[0] = -ent->v.punchangle[0];
1147 angles[1] = ent->v.punchangle[1];
1148 angles[2] = ent->v.punchangle[2];
1149 AngleVectors (angles, vf, vr, vu);
1150 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1151 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1152 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1153 angles[0] = -e->v.angles[0];
1154 angles[1] = e->v.angles[1];
1155 angles[2] = e->v.angles[2];
1156 AngleVectors (angles, vf, vr, vu);
1157 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1158 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1159 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1161 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];
1162 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];
1163 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];
1166 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1167 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1168 SV_LinkEdict (ent, true);
1175 A moving object that doesn't obey physics
1178 void SV_Physics_Noclip (edict_t *ent)
1181 if (!SV_RunThink (ent))
1184 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1185 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1187 SV_LinkEdict (ent, false);
1191 ==============================================================================
1195 ==============================================================================
1200 SV_CheckWaterTransition
1204 void SV_CheckWaterTransition (edict_t *ent)
1207 cont = SV_PointContents (ent->v.origin);
1208 if (!ent->v.watertype)
1209 { // just spawned here
1210 ent->v.watertype = cont;
1211 ent->v.waterlevel = 1;
1215 if (cont <= CONTENTS_WATER)
1217 if (ent->v.watertype == CONTENTS_EMPTY)
1218 { // just crossed into water
1219 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1221 ent->v.watertype = cont;
1222 ent->v.waterlevel = 1;
1226 if (ent->v.watertype != CONTENTS_EMPTY)
1227 { // just crossed into water
1228 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1230 ent->v.watertype = CONTENTS_EMPTY;
1231 ent->v.waterlevel = cont;
1239 Toss, bounce, and fly movement. When onground, do nothing.
1242 void SV_Physics_Toss (edict_t *ent)
1246 edict_t *groundentity;
1247 //edict_t *groundentity;
1249 if (!SV_RunThink (ent))
1252 // if onground, return without moving
1253 if ((int)ent->v.flags & FL_ONGROUND)
1255 if (ent->v.groundentity == 0)
1257 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1258 if (groundentity != NULL && groundentity->v.solid == SOLID_BSP)
1259 ent->suspendedinairflag = true;
1260 else if (ent->suspendedinairflag && (groundentity == NULL || groundentity->v.solid != SOLID_BSP))
1262 // leave it suspended in the air
1263 ent->v.groundentity = 0;
1267 ent->suspendedinairflag = false;
1270 if ( ((int)ent->v.flags & FL_ONGROUND) )
1272 // LordHavoc: fall if the groundentity was removed
1273 if (ent->v.groundentity)
1275 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1276 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
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, sv.frametime, ent->v.avelocity, ent->v.angles);
1294 VectorScale (ent->v.velocity, sv.frametime, move);
1295 trace = SV_PushEntity (ent, move, vec3_origin);
1298 if (trace.fraction == 1)
1301 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1303 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 2.0);
1304 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1306 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1308 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
1309 // LordHavoc: fixed grenades not bouncing when fired down a slope
1310 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1311 //if (trace.plane.normal[2] > 0.7 && ent->v.velocity[2] < 60)
1313 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1314 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1315 VectorClear (ent->v.velocity);
1316 VectorClear (ent->v.avelocity);
1319 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1323 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0);
1324 if (trace.plane.normal[2] > 0.7)
1326 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1327 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1328 VectorClear (ent->v.velocity);
1329 VectorClear (ent->v.avelocity);
1332 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1335 // check for in water
1336 SV_CheckWaterTransition (ent);
1340 ===============================================================================
1344 ===============================================================================
1351 Monsters freefall when they don't have a ground entity, otherwise
1352 all movement is done with discrete steps.
1354 This is also used for objects that have become still on the ground, but
1355 will fall if the floor is pulled out from under them.
1358 void SV_Physics_Step (edict_t *ent)
1360 int flags, fall, hitsound;
1362 // freefall if not fly/swim
1364 flags = (int)ent->v.flags;
1365 if (flags & (FL_FLY | FL_SWIM))
1369 else if ((flags & FL_SWIM) && SV_PointContents(ent->v.origin) != CONTENTS_EMPTY)
1372 if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
1377 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1380 if (flags & FL_ONGROUND)
1386 SV_AddGravity (ent);
1387 SV_CheckVelocity (ent);
1388 SV_FlyMove (ent, sv.frametime, NULL);
1389 SV_LinkEdict (ent, false);
1392 if ((int)ent->v.flags & FL_ONGROUND)
1394 VectorClear(ent->v.velocity);
1396 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1403 SV_CheckWaterTransition (ent);
1406 //============================================================================
1414 void SV_Physics (void)
1419 // let the progs know that a new frame has started
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 (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1425 //SV_CheckAllEnts ();
1428 // treat each object in turn
1431 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1436 if (pr_global_struct->force_retouch)
1437 SV_LinkEdict (ent, true); // force retouch even for stationary
1439 if (i > 0 && i <= svs.maxclients)
1441 SV_Physics_Client (ent, i);
1445 switch ((int) ent->v.movetype)
1448 SV_Physics_Pusher (ent);
1451 // SV_Physics_None (ent);
1452 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1453 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1456 case MOVETYPE_FOLLOW:
1457 SV_Physics_Follow (ent);
1459 case MOVETYPE_NOCLIP:
1460 SV_Physics_Noclip (ent);
1463 SV_Physics_Step (ent);
1465 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1467 if (SV_RunThink (ent))
1469 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1470 SV_AddGravity (ent);
1471 SV_CheckStuck (ent);
1473 SV_LinkEdict (ent, true);
1477 case MOVETYPE_BOUNCE:
1478 case MOVETYPE_BOUNCEMISSILE:
1480 case MOVETYPE_FLYMISSILE:
1481 SV_Physics_Toss (ent);
1484 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1489 if (pr_global_struct->force_retouch)
1490 pr_global_struct->force_retouch--;
1492 // LordHavoc: endframe support
1495 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1496 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1497 pr_global_struct->time = sv.time;
1498 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1501 sv.time += sv.frametime;
1505 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1508 edict_t tempent, *tent;
1512 float gravity, savesolid;
1515 memcpy(&tempent, tossent, sizeof(edict_t));
1517 savesolid = tossent->v.solid;
1518 tossent->v.solid = SOLID_NOT;
1520 // this has to fetch the field from the original edict, since our copy is truncated
1521 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1522 if (val != NULL && val->_float != 0)
1523 gravity = val->_float;
1526 gravity *= sv_gravity.value * 0.05;
1528 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1530 SV_CheckVelocity (tent);
1531 tent->v.velocity[2] -= gravity;
1532 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1533 VectorScale (tent->v.velocity, 0.05, move);
1534 VectorAdd (tent->v.origin, move, end);
1535 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1536 VectorCopy (trace.endpos, tent->v.origin);
1538 if (trace.fraction < 1 && trace.ent)
1539 if (trace.ent != ignore)
1542 tossent->v.solid = savesolid;
1543 trace.fraction = 0; // not relevant