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);
272 { // entity is trapped in another solid
273 VectorClear(ent->v.velocity);
277 if (trace.fraction > 0)
278 { // actually covered some distance
279 VectorCopy (trace.endpos, ent->v.origin);
280 VectorCopy (ent->v.velocity, original_velocity);
284 if (trace.fraction == 1)
285 break; // moved the entire distance
288 Host_Error ("SV_FlyMove: !trace.ent");
290 if ((int) ent->v.flags & FL_ONGROUND)
292 if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
296 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
303 if (trace.plane.normal[2] > 0.7)
305 blocked |= 1; // floor
306 //if (trace.ent->v.solid == SOLID_BSP)
308 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
309 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
312 if (!trace.plane.normal[2])
314 blocked |= 2; // step
316 *steptrace = trace; // save for player extrafriction
320 // run the impact function
323 SV_Impact (ent, trace.ent);
325 break; // removed by the impact function
328 time_left -= time_left * trace.fraction;
330 // cliped to another plane
331 if (numplanes >= MAX_CLIP_PLANES)
332 { // this shouldn't really happen
333 VectorClear(ent->v.velocity);
337 VectorCopy (trace.plane.normal, planes[numplanes]);
341 // modify original_velocity so it parallels all of the clip planes
343 for (i=0 ; i<numplanes ; i++)
345 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
346 for (j=0 ; j<numplanes ; j++)
349 if (DotProduct (new_velocity, planes[j]) < 0)
357 { // go along this plane
358 VectorCopy (new_velocity, ent->v.velocity);
361 { // go along the crease
364 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
365 VectorClear(ent->v.velocity);
368 CrossProduct (planes[0], planes[1], dir);
369 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
370 VectorNormalize(dir);
371 d = DotProduct (dir, ent->v.velocity);
372 VectorScale (dir, d, ent->v.velocity);
376 // if original velocity is against the original velocity, stop dead
377 // to avoid tiny occilations in sloping corners
379 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
381 VectorClear(ent->v.velocity);
396 void SV_AddGravity (edict_t *ent)
402 val = GETEDICTFIELDVALUE(ent, eval_gravity);
403 if (val!=0 && val->_float)
404 ent_gravity = val->_float;
407 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
412 ===============================================================================
416 ===============================================================================
423 Does not change the entities velocity at all
426 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
431 VectorAdd (ent->v.origin, push, end);
433 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
434 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
435 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
436 // only clip against bmodels
437 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
439 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
441 VectorCopy (trace.endpos, ent->v.origin);
442 // FIXME: turn players specially
443 ent->v.angles[1] += trace.fraction * pushangles[1];
444 SV_LinkEdict (ent, true);
447 SV_Impact (ent, trace.ent);
458 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
459 void SV_PushMove (edict_t *pusher, float movetime)
463 float savesolid, movetime2, pushltime;
464 vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
466 edict_t *moved_edict[MAX_EDICTS];
467 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
468 model_t *pushermodel;
471 switch ((int) pusher->v.solid)
473 // LordHavoc: valid pusher types
477 case SOLID_CORPSE: // LordHavoc: this would be weird...
479 // LordHavoc: no collisions
482 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
483 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
484 pusher->v.ltime += movetime;
485 SV_LinkEdict (pusher, false);
488 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
490 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])
492 pusher->v.ltime += movetime;
495 index = (int) pusher->v.modelindex;
496 if (index < 1 || index >= MAX_MODELS)
497 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
498 pushermodel = sv.models[index];
500 // LordHavoc: round up by a small epsilon
501 movetime2 = movetime; // + (1.0 / 256.0);
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])
594 if (forward[0] < 0.999f) // quick way to check if any rotation is used
596 VectorSubtract (check->v.origin, pusher->v.origin, org);
597 org2[0] = DotProduct (org, forward);
598 org2[1] = DotProduct (org, left);
599 org2[2] = DotProduct (org, up);
600 //VectorSubtract (org2, org, move);
601 //VectorAdd (move, move1, move);
602 //VectorSubtract(check->v.origin, move, a);
603 a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0];
604 a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1];
605 a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2];
608 VectorSubtract (check->v.origin, move1, a);
610 trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin);
611 if (trace.fraction == 1 && !trace.startsolid)
614 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
615 if (!trace.startsolid)
618 // see if the ent's bbox is inside the pusher's final position
619 if (!SV_TestEntityPosition (check))
624 if (forward[0] < 0.999f) // quick way to check if any rotation is used
626 VectorSubtract (check->v.origin, pusher->v.origin, org);
627 org2[0] = DotProduct (org, forward);
628 org2[1] = DotProduct (org, left);
629 org2[2] = DotProduct (org, up);
630 VectorSubtract (org2, org, move);
631 VectorAdd (move, move1, move);
634 VectorCopy (move1, move);
636 // LordHavoc: debugging
637 //VectorAdd(entorig, move, org2);
638 //CL_RocketTrail2 (entorig, org2, 238, NULL);
640 // remove the onground flag for non-players
641 if (check->v.movetype != MOVETYPE_WALK)
642 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
644 //VectorCopy (check->v.origin, entorig);
645 //VectorCopy (check->v.angles, entang);
646 VectorCopy (check->v.origin, moved_from[num_moved]);
647 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
648 moved_edict[num_moved++] = check;
650 // try moving the contacted entity
651 pusher->v.solid = SOLID_NOT;
652 trace = SV_PushEntity (check, move, moveangle);
653 pusher->v.solid = savesolid; // was SOLID_BSP
655 // if it is still inside the pusher, block
656 // LordHavoc: cleanup - check trace.fraction and startsolid
657 if (/*trace.fraction != 1 || trace.startsolid || */SV_TestEntityPosition (check))
660 if (check->v.mins[0] == check->v.maxs[0])
662 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
665 check->v.mins[0] = check->v.mins[1] = 0;
666 VectorCopy (check->v.mins, check->v.maxs);
671 VectorCopy (entorig, check->v.origin);
672 VectorCopy (entang, check->v.angles);
673 SV_LinkEdict (check, true);
676 VectorCopy (pushorig, pusher->v.origin);
677 VectorCopy (pushang, pusher->v.angles);
678 pusher->v.ltime = pushltime;
679 SV_LinkEdict (pusher, false);
681 // move back any entities we already moved
682 //num_moved--; // LordHavoc: pop off check, because it was already restored
683 for (i=0 ; i<num_moved ; i++)
685 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
686 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
687 SV_LinkEdict (moved_edict[i], false);
690 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
691 if (pusher->v.blocked)
693 pr_global_struct->self = EDICT_TO_PROG(pusher);
694 pr_global_struct->other = EDICT_TO_PROG(check);
695 PR_ExecuteProgram (pusher->v.blocked, "");
708 void SV_Physics_Pusher (edict_t *ent)
714 oldltime = ent->v.ltime;
716 thinktime = ent->v.nextthink;
717 if (thinktime < ent->v.ltime + sv.frametime)
719 movetime = thinktime - ent->v.ltime;
724 movetime = sv.frametime;
727 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
729 if (thinktime > oldltime && thinktime <= ent->v.ltime)
731 ent->v.nextthink = 0;
732 pr_global_struct->time = sv.time;
733 pr_global_struct->self = EDICT_TO_PROG(ent);
734 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
735 PR_ExecuteProgram (ent->v.think, "NULL think function");
744 ===============================================================================
748 ===============================================================================
755 This is a big hack to try and fix the rare case of getting stuck in the world
759 void SV_CheckStuck (edict_t *ent)
765 if (!SV_TestEntityPosition(ent))
767 VectorCopy (ent->v.origin, ent->v.oldorigin);
771 VectorCopy (ent->v.origin, org);
772 VectorCopy (ent->v.oldorigin, ent->v.origin);
773 if (!SV_TestEntityPosition(ent))
775 Con_DPrintf ("Unstuck.\n");
776 SV_LinkEdict (ent, true);
780 for (z=0 ; z< 18 ; z++)
781 for (i=-1 ; i <= 1 ; i++)
782 for (j=-1 ; j <= 1 ; j++)
784 ent->v.origin[0] = org[0] + i;
785 ent->v.origin[1] = org[1] + j;
786 ent->v.origin[2] = org[2] + z;
787 if (!SV_TestEntityPosition(ent))
789 Con_DPrintf ("Unstuck.\n");
790 SV_LinkEdict (ent, true);
795 VectorCopy (org, ent->v.origin);
796 Con_DPrintf ("player is stuck.\n");
805 qboolean SV_CheckWater (edict_t *ent)
810 point[0] = ent->v.origin[0];
811 point[1] = ent->v.origin[1];
812 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
814 ent->v.waterlevel = 0;
815 ent->v.watertype = CONTENTS_EMPTY;
816 cont = SV_PointContents (point);
817 if (cont <= CONTENTS_WATER)
819 ent->v.watertype = cont;
820 ent->v.waterlevel = 1;
821 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
822 cont = SV_PointContents (point);
823 if (cont <= CONTENTS_WATER)
825 ent->v.waterlevel = 2;
826 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
827 cont = SV_PointContents (point);
828 if (cont <= CONTENTS_WATER)
829 ent->v.waterlevel = 3;
833 return ent->v.waterlevel > 1;
842 void SV_WallFriction (edict_t *ent, trace_t *trace)
848 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
849 d = DotProduct (trace->plane.normal, forward);
855 // cut the tangential velocity
856 i = DotProduct (trace->plane.normal, ent->v.velocity);
857 VectorScale (trace->plane.normal, i, into);
858 VectorSubtract (ent->v.velocity, into, side);
860 ent->v.velocity[0] = side[0] * (1 + d);
861 ent->v.velocity[1] = side[1] * (1 + d);
865 =====================
868 Player has come to a dead stop, possibly due to the problem with limited
869 float precision at some angle joins in the BSP hull.
871 Try fixing by pushing one pixel in each direction.
873 This is a hack, but in the interest of good gameplay...
874 ======================
876 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
884 VectorCopy (ent->v.origin, oldorg);
887 for (i=0 ; i<8 ; i++)
889 // try pushing a little in an axial direction
892 case 0: dir[0] = 2; dir[1] = 0; break;
893 case 1: dir[0] = 0; dir[1] = 2; break;
894 case 2: dir[0] = -2; dir[1] = 0; break;
895 case 3: dir[0] = 0; dir[1] = -2; break;
896 case 4: dir[0] = 2; dir[1] = 2; break;
897 case 5: dir[0] = -2; dir[1] = 2; break;
898 case 6: dir[0] = 2; dir[1] = -2; break;
899 case 7: dir[0] = -2; dir[1] = -2; break;
902 SV_PushEntity (ent, dir, vec3_origin);
904 // retry the original move
905 ent->v.velocity[0] = oldvel[0];
906 ent->v.velocity[1] = oldvel[1];
907 ent->v.velocity[2] = 0;
908 clip = SV_FlyMove (ent, 0.1, &steptrace);
910 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
911 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
913 //Con_DPrintf ("unstuck!\n");
917 // go back to the original pos and try again
918 VectorCopy (oldorg, ent->v.origin);
921 VectorClear (ent->v.velocity);
922 return 7; // still not moving
926 =====================
930 ======================
933 void SV_WalkMove (edict_t *ent)
935 vec3_t upmove, downmove;
936 vec3_t oldorg, oldvel;
937 vec3_t nosteporg, nostepvel;
940 trace_t steptrace, downtrace;
943 // do a regular slide move unless it looks like you ran into a step
945 oldonground = (int)ent->v.flags & FL_ONGROUND;
946 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
948 VectorCopy (ent->v.origin, oldorg);
949 VectorCopy (ent->v.velocity, oldvel);
951 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
954 return; // move didn't block on a step
956 if (!oldonground && ent->v.waterlevel == 0)
957 return; // don't stair up while jumping
959 if (ent->v.movetype != MOVETYPE_WALK)
960 return; // gibbed by a trigger
962 if (sv_nostep.integer)
965 if ( (int)sv_player->v.flags & FL_WATERJUMP )
968 VectorCopy (ent->v.origin, nosteporg);
969 VectorCopy (ent->v.velocity, nostepvel);
972 // try moving up and forward to go up a step
974 VectorCopy (oldorg, ent->v.origin); // back to start pos
976 VectorClear (upmove);
977 VectorClear (downmove);
978 upmove[2] = STEPSIZE;
979 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
982 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
985 ent->v.velocity[0] = oldvel[0];
986 ent->v. velocity[1] = oldvel[1];
987 ent->v. velocity[2] = 0;
988 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
990 // check for stuckness, possibly due to the limited precision of floats
991 // in the clipping hulls
994 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
995 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
996 { // stepping up didn't make any progress
997 clip = SV_TryUnstick (ent, oldvel);
1001 // extra friction based on view angle
1003 SV_WallFriction (ent, &steptrace);
1006 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
1008 if (downtrace.plane.normal[2] > 0.7)
1010 if (ent->v.solid == SOLID_BSP)
1012 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1013 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1018 // if the push down didn't end up on good ground, use the move without
1019 // the step up. This happens near wall / slope combinations, and can
1020 // cause the player to hop up higher on a slope too steep to climb
1021 VectorCopy (nosteporg, ent->v.origin);
1022 VectorCopy (nostepvel, ent->v.velocity);
1031 Player character actions
1034 void SV_Physics_Client (edict_t *ent, int num)
1036 if ( ! svs.clients[num-1].active )
1037 return; // unconnected slot
1040 // call standard client pre-think
1042 pr_global_struct->time = sv.time;
1043 pr_global_struct->self = EDICT_TO_PROG(ent);
1044 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1049 SV_CheckVelocity (ent);
1052 // decide which move function to call
1054 switch ((int)ent->v.movetype)
1057 if (!SV_RunThink (ent))
1062 if (!SV_RunThink (ent))
1064 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1065 SV_AddGravity (ent);
1066 SV_CheckStuck (ent);
1071 case MOVETYPE_BOUNCE:
1072 SV_Physics_Toss (ent);
1076 if (!SV_RunThink (ent))
1078 SV_CheckWater (ent);
1079 SV_FlyMove (ent, sv.frametime, NULL);
1082 case MOVETYPE_NOCLIP:
1083 if (!SV_RunThink (ent))
1085 SV_CheckWater (ent);
1086 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1090 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1094 // call standard player post-think
1096 SV_LinkEdict (ent, true);
1098 pr_global_struct->time = sv.time;
1099 pr_global_struct->self = EDICT_TO_PROG(ent);
1100 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1103 //============================================================================
1109 Non moving objects can only think
1112 // LordHavoc: inlined manually because it was a real time waster
1114 void SV_Physics_None (edict_t *ent)
1125 Entities that are "stuck" to another entity
1128 void SV_Physics_Follow (edict_t *ent)
1130 vec3_t vf, vr, vu, angles, v;
1133 if (!SV_RunThink (ent))
1135 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1136 e = PROG_TO_EDICT(ent->v.aiment);
1137 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])
1139 // quick case for no rotation
1140 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1144 angles[0] = -ent->v.punchangle[0];
1145 angles[1] = ent->v.punchangle[1];
1146 angles[2] = ent->v.punchangle[2];
1147 AngleVectors (angles, vf, vr, vu);
1148 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1149 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1150 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1151 angles[0] = -e->v.angles[0];
1152 angles[1] = e->v.angles[1];
1153 angles[2] = e->v.angles[2];
1154 AngleVectors (angles, vf, vr, vu);
1155 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1156 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1157 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1159 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];
1160 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];
1161 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];
1164 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1165 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1166 SV_LinkEdict (ent, true);
1173 A moving object that doesn't obey physics
1176 void SV_Physics_Noclip (edict_t *ent)
1179 if (!SV_RunThink (ent))
1182 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1183 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1185 SV_LinkEdict (ent, false);
1189 ==============================================================================
1193 ==============================================================================
1198 SV_CheckWaterTransition
1202 void SV_CheckWaterTransition (edict_t *ent)
1205 cont = SV_PointContents (ent->v.origin);
1206 if (!ent->v.watertype)
1207 { // just spawned here
1208 ent->v.watertype = cont;
1209 ent->v.waterlevel = 1;
1213 if (cont <= CONTENTS_WATER)
1215 if (ent->v.watertype == CONTENTS_EMPTY)
1216 { // just crossed into water
1217 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1219 ent->v.watertype = cont;
1220 ent->v.waterlevel = 1;
1224 if (ent->v.watertype != CONTENTS_EMPTY)
1225 { // just crossed into water
1226 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1228 ent->v.watertype = CONTENTS_EMPTY;
1229 ent->v.waterlevel = cont;
1237 Toss, bounce, and fly movement. When onground, do nothing.
1240 void SV_Physics_Toss (edict_t *ent)
1245 //edict_t *groundentity;
1247 if (!SV_RunThink (ent))
1250 // if onground, return without moving
1252 if ( ((int)ent->v.flags & FL_ONGROUND) )
1254 // LordHavoc: fall if the groundentity was removed
1255 if (ent->v.groundentity)
1257 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1258 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1264 SV_CheckVelocity (ent);
1267 if (ent->v.movetype != MOVETYPE_FLY
1268 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1269 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1270 SV_AddGravity (ent);
1273 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1276 VectorScale (ent->v.velocity, sv.frametime, move);
1277 trace = SV_PushEntity (ent, move, vec3_origin);
1280 if (trace.fraction == 1)
1283 if (ent->v.movetype == MOVETYPE_BOUNCE)
1285 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1290 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1292 // stop if on ground
1293 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1294 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1295 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1297 // LordHavoc: fixed grenades not bouncing when fired down a slope
1298 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1299 //if (trace.plane.normal[2] > 0.7 && ent->v.velocity[2] < 60)
1301 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1302 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1303 VectorClear (ent->v.velocity);
1304 VectorClear (ent->v.avelocity);
1307 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1311 if (trace.plane.normal[2] > 0.7)
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;
1322 // check for in water
1323 SV_CheckWaterTransition (ent);
1327 ===============================================================================
1331 ===============================================================================
1338 Monsters freefall when they don't have a ground entity, otherwise
1339 all movement is done with discrete steps.
1341 This is also used for objects that have become still on the ground, but
1342 will fall if the floor is pulled out from under them.
1345 void SV_Physics_Step (edict_t *ent)
1349 // freefall if not onground
1350 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1352 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1357 SV_AddGravity (ent);
1358 SV_CheckVelocity (ent);
1359 SV_FlyMove (ent, sv.frametime, NULL);
1360 SV_LinkEdict (ent, true);
1362 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1365 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1372 SV_CheckWaterTransition (ent);
1375 //============================================================================
1383 void SV_Physics (void)
1388 // let the progs know that a new frame has started
1389 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1390 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1391 pr_global_struct->time = sv.time;
1392 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1394 //SV_CheckAllEnts ();
1397 // treat each object in turn
1400 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1405 if (pr_global_struct->force_retouch)
1406 SV_LinkEdict (ent, true); // force retouch even for stationary
1408 if (i > 0 && i <= svs.maxclients)
1410 SV_Physics_Client (ent, i);
1414 switch ((int) ent->v.movetype)
1417 SV_Physics_Pusher (ent);
1420 // SV_Physics_None (ent);
1421 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1422 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1425 case MOVETYPE_FOLLOW:
1426 SV_Physics_Follow (ent);
1428 case MOVETYPE_NOCLIP:
1429 SV_Physics_Noclip (ent);
1432 SV_Physics_Step (ent);
1434 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1436 if (SV_RunThink (ent))
1438 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1439 SV_AddGravity (ent);
1440 SV_CheckStuck (ent);
1442 SV_LinkEdict (ent, true);
1446 case MOVETYPE_BOUNCE:
1447 case MOVETYPE_BOUNCEMISSILE:
1449 case MOVETYPE_FLYMISSILE:
1450 SV_Physics_Toss (ent);
1453 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1458 if (pr_global_struct->force_retouch)
1459 pr_global_struct->force_retouch--;
1461 // LordHavoc: endframe support
1464 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1465 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1466 pr_global_struct->time = sv.time;
1467 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1470 sv.time += sv.frametime;
1474 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1477 edict_t tempent, *tent;
1481 float gravity, savesolid;
1484 memcpy(&tempent, tossent, sizeof(edict_t));
1486 savesolid = tossent->v.solid;
1487 tossent->v.solid = SOLID_NOT;
1489 // this has to fetch the field from the original edict, since our copy is truncated
1490 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1491 if (val != NULL && val->_float != 0)
1492 gravity = val->_float;
1495 gravity *= sv_gravity.value * 0.05;
1497 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1499 SV_CheckVelocity (tent);
1500 tent->v.velocity[2] -= gravity;
1501 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1502 VectorScale (tent->v.velocity, 0.05, move);
1503 VectorAdd (tent->v.origin, move, end);
1504 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1505 VectorCopy (trace.endpos, tent->v.origin);
1507 if (trace.fraction < 1 && trace.ent)
1508 if (trace.ent != ignore)
1511 tossent->v.solid = savesolid;
1512 trace.fraction = 0; // not relevant