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 (trace.plane.normal[2] > 0.7)
292 blocked |= 1; // floor
293 if (trace.ent->v.solid == SOLID_BSP)
295 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
296 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
299 if (!trace.plane.normal[2])
301 blocked |= 2; // step
303 *steptrace = trace; // save for player extrafriction
307 // run the impact function
309 SV_Impact (ent, trace.ent);
311 break; // removed by the impact function
314 time_left -= time_left * trace.fraction;
316 // cliped to another plane
317 if (numplanes >= MAX_CLIP_PLANES)
318 { // this shouldn't really happen
319 VectorClear(ent->v.velocity);
323 VectorCopy (trace.plane.normal, planes[numplanes]);
327 // modify original_velocity so it parallels all of the clip planes
329 for (i=0 ; i<numplanes ; i++)
331 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
332 for (j=0 ; j<numplanes ; j++)
335 if (DotProduct (new_velocity, planes[j]) < 0)
343 { // go along this plane
344 VectorCopy (new_velocity, ent->v.velocity);
347 { // go along the crease
350 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
351 VectorClear(ent->v.velocity);
354 CrossProduct (planes[0], planes[1], dir);
355 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
356 VectorNormalize(dir);
357 d = DotProduct (dir, ent->v.velocity);
358 VectorScale (dir, d, ent->v.velocity);
362 // if original velocity is against the original velocity, stop dead
363 // to avoid tiny occilations in sloping corners
365 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
367 VectorClear(ent->v.velocity);
382 void SV_AddGravity (edict_t *ent)
388 val = GETEDICTFIELDVALUE(ent, eval_gravity);
389 if (val!=0 && val->_float)
390 ent_gravity = val->_float;
393 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
398 ===============================================================================
402 ===============================================================================
409 Does not change the entities velocity at all
412 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
417 VectorAdd (ent->v.origin, push, end);
419 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
420 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
421 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
422 // only clip against bmodels
423 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
425 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
427 VectorCopy (trace.endpos, ent->v.origin);
428 // FIXME: turn players specially
429 ent->v.angles[1] += trace.fraction * pushangles[1];
430 SV_LinkEdict (ent, true);
433 SV_Impact (ent, trace.ent);
444 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
445 void SV_PushMove (edict_t *pusher, float movetime)
449 float savesolid, movetime2, pushltime;
450 vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
452 edict_t *moved_edict[MAX_EDICTS];
453 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
454 model_t *pushermodel;
457 switch ((int) pusher->v.solid)
459 // LordHavoc: valid pusher types
463 case SOLID_CORPSE: // LordHavoc: this would be weird...
465 // LordHavoc: no collisions
468 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
469 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
470 pusher->v.ltime += movetime;
471 SV_LinkEdict (pusher, false);
474 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
476 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])
478 pusher->v.ltime += movetime;
481 index = (int) pusher->v.modelindex;
482 if (index < 1 || index >= MAX_MODELS)
483 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
484 pushermodel = sv.models[index];
486 // LordHavoc: round up by a small epsilon
487 movetime2 = movetime; // + (1.0 / 256.0);
488 VectorScale(pusher->v.velocity, movetime2, move1);
489 VectorScale(pusher->v.avelocity, movetime2, moveangle);
490 if (moveangle[0] || moveangle[2])
492 for (i = 0;i < 3;i++)
496 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
497 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
501 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
502 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
506 else if (moveangle[1])
508 for (i = 0;i < 3;i++)
512 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
513 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
517 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
518 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
524 for (i = 0;i < 3;i++)
528 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
529 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
533 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
534 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
539 VectorNegate (moveangle, a);
540 AngleVectorsFLU (a, forward, left, up);
542 VectorCopy (pusher->v.origin, pushorig);
543 VectorCopy (pusher->v.angles, pushang);
544 pushltime = pusher->v.ltime;
546 // move the pusher to it's final position
548 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
549 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
550 pusher->v.ltime += movetime;
551 SV_LinkEdict (pusher, false);
553 savesolid = pusher->v.solid;
555 // see if any solid entities are inside the final position
557 check = NEXT_EDICT(sv.edicts);
558 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
562 if (check->v.movetype == MOVETYPE_PUSH
563 || check->v.movetype == MOVETYPE_NONE
564 || check->v.movetype == MOVETYPE_FOLLOW
565 || check->v.movetype == MOVETYPE_NOCLIP)
568 // if the entity is standing on the pusher, it will definitely be moved
569 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
571 if (check->v.absmin[0] >= maxs[0]
572 || check->v.absmax[0] <= mins[0]
573 || check->v.absmin[1] >= maxs[1]
574 || check->v.absmax[1] <= mins[1]
575 || check->v.absmin[2] >= maxs[2]
576 || check->v.absmax[2] <= mins[2])
580 if (forward[0] < 0.999f) // quick way to check if any rotation is used
582 VectorSubtract (check->v.origin, pusher->v.origin, org);
583 org2[0] = DotProduct (org, forward);
584 org2[1] = DotProduct (org, left);
585 org2[2] = DotProduct (org, up);
586 //VectorSubtract (org2, org, move);
587 //VectorAdd (move, move1, move);
588 //VectorSubtract(check->v.origin, move, a);
589 a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0];
590 a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1];
591 a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2];
594 VectorSubtract (check->v.origin, move1, a);
596 trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin);
597 if (trace.fraction == 1 && !trace.startsolid)
600 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
601 if (!trace.startsolid)
604 // see if the ent's bbox is inside the pusher's final position
605 if (!SV_TestEntityPosition (check))
610 if (forward[0] < 0.999f) // quick way to check if any rotation is used
612 VectorSubtract (check->v.origin, pusher->v.origin, org);
613 org2[0] = DotProduct (org, forward);
614 org2[1] = DotProduct (org, left);
615 org2[2] = DotProduct (org, up);
616 VectorSubtract (org2, org, move);
617 VectorAdd (move, move1, move);
620 VectorCopy (move1, move);
622 // LordHavoc: debugging
623 //VectorAdd(entorig, move, org2);
624 //CL_RocketTrail2 (entorig, org2, 238, NULL);
626 // remove the onground flag for non-players
627 if (check->v.movetype != MOVETYPE_WALK)
628 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
630 //VectorCopy (check->v.origin, entorig);
631 //VectorCopy (check->v.angles, entang);
632 VectorCopy (check->v.origin, moved_from[num_moved]);
633 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
634 moved_edict[num_moved++] = check;
636 // try moving the contacted entity
637 pusher->v.solid = SOLID_NOT;
638 trace = SV_PushEntity (check, move, moveangle);
639 pusher->v.solid = savesolid; // was SOLID_BSP
641 // if it is still inside the pusher, block
642 // LordHavoc: cleanup - check trace.fraction and startsolid
643 if (/*trace.fraction != 1 || trace.startsolid || */SV_TestEntityPosition (check))
646 if (check->v.mins[0] == check->v.maxs[0])
648 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
651 check->v.mins[0] = check->v.mins[1] = 0;
652 VectorCopy (check->v.mins, check->v.maxs);
657 VectorCopy (entorig, check->v.origin);
658 VectorCopy (entang, check->v.angles);
659 SV_LinkEdict (check, true);
662 VectorCopy (pushorig, pusher->v.origin);
663 VectorCopy (pushang, pusher->v.angles);
664 pusher->v.ltime = pushltime;
665 SV_LinkEdict (pusher, false);
667 // move back any entities we already moved
668 //num_moved--; // LordHavoc: pop off check, because it was already restored
669 for (i=0 ; i<num_moved ; i++)
671 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
672 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
673 SV_LinkEdict (moved_edict[i], false);
676 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
677 if (pusher->v.blocked)
679 pr_global_struct->self = EDICT_TO_PROG(pusher);
680 pr_global_struct->other = EDICT_TO_PROG(check);
681 PR_ExecuteProgram (pusher->v.blocked, "");
694 void SV_Physics_Pusher (edict_t *ent)
700 oldltime = ent->v.ltime;
702 thinktime = ent->v.nextthink;
703 if (thinktime < ent->v.ltime + sv.frametime)
705 movetime = thinktime - ent->v.ltime;
710 movetime = sv.frametime;
713 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
715 if (thinktime > oldltime && thinktime <= ent->v.ltime)
717 ent->v.nextthink = 0;
718 pr_global_struct->time = sv.time;
719 pr_global_struct->self = EDICT_TO_PROG(ent);
720 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
721 PR_ExecuteProgram (ent->v.think, "NULL think function");
730 ===============================================================================
734 ===============================================================================
741 This is a big hack to try and fix the rare case of getting stuck in the world
745 void SV_CheckStuck (edict_t *ent)
751 if (!SV_TestEntityPosition(ent))
753 VectorCopy (ent->v.origin, ent->v.oldorigin);
757 VectorCopy (ent->v.origin, org);
758 VectorCopy (ent->v.oldorigin, ent->v.origin);
759 if (!SV_TestEntityPosition(ent))
761 Con_DPrintf ("Unstuck.\n");
762 SV_LinkEdict (ent, true);
766 for (z=0 ; z< 18 ; z++)
767 for (i=-1 ; i <= 1 ; i++)
768 for (j=-1 ; j <= 1 ; j++)
770 ent->v.origin[0] = org[0] + i;
771 ent->v.origin[1] = org[1] + j;
772 ent->v.origin[2] = org[2] + z;
773 if (!SV_TestEntityPosition(ent))
775 Con_DPrintf ("Unstuck.\n");
776 SV_LinkEdict (ent, true);
781 VectorCopy (org, ent->v.origin);
782 Con_DPrintf ("player is stuck.\n");
791 qboolean SV_CheckWater (edict_t *ent)
796 point[0] = ent->v.origin[0];
797 point[1] = ent->v.origin[1];
798 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
800 ent->v.waterlevel = 0;
801 ent->v.watertype = CONTENTS_EMPTY;
802 cont = SV_PointContents (point);
803 if (cont <= CONTENTS_WATER)
805 ent->v.watertype = cont;
806 ent->v.waterlevel = 1;
807 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
808 cont = SV_PointContents (point);
809 if (cont <= CONTENTS_WATER)
811 ent->v.waterlevel = 2;
812 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
813 cont = SV_PointContents (point);
814 if (cont <= CONTENTS_WATER)
815 ent->v.waterlevel = 3;
819 return ent->v.waterlevel > 1;
828 void SV_WallFriction (edict_t *ent, trace_t *trace)
834 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
835 d = DotProduct (trace->plane.normal, forward);
841 // cut the tangential velocity
842 i = DotProduct (trace->plane.normal, ent->v.velocity);
843 VectorScale (trace->plane.normal, i, into);
844 VectorSubtract (ent->v.velocity, into, side);
846 ent->v.velocity[0] = side[0] * (1 + d);
847 ent->v.velocity[1] = side[1] * (1 + d);
851 =====================
854 Player has come to a dead stop, possibly due to the problem with limited
855 float precision at some angle joins in the BSP hull.
857 Try fixing by pushing one pixel in each direction.
859 This is a hack, but in the interest of good gameplay...
860 ======================
862 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
870 VectorCopy (ent->v.origin, oldorg);
873 for (i=0 ; i<8 ; i++)
875 // try pushing a little in an axial direction
878 case 0: dir[0] = 2; dir[1] = 0; break;
879 case 1: dir[0] = 0; dir[1] = 2; break;
880 case 2: dir[0] = -2; dir[1] = 0; break;
881 case 3: dir[0] = 0; dir[1] = -2; break;
882 case 4: dir[0] = 2; dir[1] = 2; break;
883 case 5: dir[0] = -2; dir[1] = 2; break;
884 case 6: dir[0] = 2; dir[1] = -2; break;
885 case 7: dir[0] = -2; dir[1] = -2; break;
888 SV_PushEntity (ent, dir, vec3_origin);
890 // retry the original move
891 ent->v.velocity[0] = oldvel[0];
892 ent->v.velocity[1] = oldvel[1];
893 ent->v.velocity[2] = 0;
894 clip = SV_FlyMove (ent, 0.1, &steptrace);
896 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
897 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
899 //Con_DPrintf ("unstuck!\n");
903 // go back to the original pos and try again
904 VectorCopy (oldorg, ent->v.origin);
907 VectorClear (ent->v.velocity);
908 return 7; // still not moving
912 =====================
916 ======================
919 void SV_WalkMove (edict_t *ent)
921 vec3_t upmove, downmove;
922 vec3_t oldorg, oldvel;
923 vec3_t nosteporg, nostepvel;
926 trace_t steptrace, downtrace;
929 // do a regular slide move unless it looks like you ran into a step
931 oldonground = (int)ent->v.flags & FL_ONGROUND;
932 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
934 VectorCopy (ent->v.origin, oldorg);
935 VectorCopy (ent->v.velocity, oldvel);
937 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
940 return; // move didn't block on a step
942 if (!oldonground && ent->v.waterlevel == 0)
943 return; // don't stair up while jumping
945 if (ent->v.movetype != MOVETYPE_WALK)
946 return; // gibbed by a trigger
948 if (sv_nostep.integer)
951 if ( (int)sv_player->v.flags & FL_WATERJUMP )
954 VectorCopy (ent->v.origin, nosteporg);
955 VectorCopy (ent->v.velocity, nostepvel);
958 // try moving up and forward to go up a step
960 VectorCopy (oldorg, ent->v.origin); // back to start pos
962 VectorClear (upmove);
963 VectorClear (downmove);
964 upmove[2] = STEPSIZE;
965 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
968 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
971 ent->v.velocity[0] = oldvel[0];
972 ent->v. velocity[1] = oldvel[1];
973 ent->v. velocity[2] = 0;
974 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
976 // check for stuckness, possibly due to the limited precision of floats
977 // in the clipping hulls
980 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
981 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
982 { // stepping up didn't make any progress
983 clip = SV_TryUnstick (ent, oldvel);
987 // extra friction based on view angle
989 SV_WallFriction (ent, &steptrace);
992 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
994 if (downtrace.plane.normal[2] > 0.7)
996 if (ent->v.solid == SOLID_BSP)
998 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
999 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1004 // if the push down didn't end up on good ground, use the move without
1005 // the step up. This happens near wall / slope combinations, and can
1006 // cause the player to hop up higher on a slope too steep to climb
1007 VectorCopy (nosteporg, ent->v.origin);
1008 VectorCopy (nostepvel, ent->v.velocity);
1017 Player character actions
1020 void SV_Physics_Client (edict_t *ent, int num)
1022 if ( ! svs.clients[num-1].active )
1023 return; // unconnected slot
1026 // call standard client pre-think
1028 pr_global_struct->time = sv.time;
1029 pr_global_struct->self = EDICT_TO_PROG(ent);
1030 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1035 SV_CheckVelocity (ent);
1038 // decide which move function to call
1040 switch ((int)ent->v.movetype)
1043 if (!SV_RunThink (ent))
1048 if (!SV_RunThink (ent))
1050 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1051 SV_AddGravity (ent);
1052 SV_CheckStuck (ent);
1057 case MOVETYPE_BOUNCE:
1058 SV_Physics_Toss (ent);
1062 if (!SV_RunThink (ent))
1064 SV_CheckWater (ent);
1065 SV_FlyMove (ent, sv.frametime, NULL);
1068 case MOVETYPE_NOCLIP:
1069 if (!SV_RunThink (ent))
1071 SV_CheckWater (ent);
1072 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1076 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1080 // call standard player post-think
1082 SV_LinkEdict (ent, true);
1084 pr_global_struct->time = sv.time;
1085 pr_global_struct->self = EDICT_TO_PROG(ent);
1086 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1089 //============================================================================
1095 Non moving objects can only think
1098 // LordHavoc: inlined manually because it was a real time waster
1100 void SV_Physics_None (edict_t *ent)
1111 Entities that are "stuck" to another entity
1114 void SV_Physics_Follow (edict_t *ent)
1116 vec3_t vf, vr, vu, angles, v;
1119 if (!SV_RunThink (ent))
1121 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1122 e = PROG_TO_EDICT(ent->v.aiment);
1123 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])
1125 // quick case for no rotation
1126 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1130 angles[0] = -ent->v.punchangle[0];
1131 angles[1] = ent->v.punchangle[1];
1132 angles[2] = ent->v.punchangle[2];
1133 AngleVectors (angles, vf, vr, vu);
1134 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1135 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1136 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1137 angles[0] = -e->v.angles[0];
1138 angles[1] = e->v.angles[1];
1139 angles[2] = e->v.angles[2];
1140 AngleVectors (angles, vf, vr, vu);
1141 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1142 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1143 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1145 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];
1146 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];
1147 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];
1150 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1151 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1152 SV_LinkEdict (ent, true);
1159 A moving object that doesn't obey physics
1162 void SV_Physics_Noclip (edict_t *ent)
1165 if (!SV_RunThink (ent))
1168 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1169 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1171 SV_LinkEdict (ent, false);
1175 ==============================================================================
1179 ==============================================================================
1184 SV_CheckWaterTransition
1188 void SV_CheckWaterTransition (edict_t *ent)
1191 cont = SV_PointContents (ent->v.origin);
1192 if (!ent->v.watertype)
1193 { // just spawned here
1194 ent->v.watertype = cont;
1195 ent->v.waterlevel = 1;
1199 if (cont <= CONTENTS_WATER)
1201 if (ent->v.watertype == CONTENTS_EMPTY)
1202 { // just crossed into water
1203 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1205 ent->v.watertype = cont;
1206 ent->v.waterlevel = 1;
1210 if (ent->v.watertype != CONTENTS_EMPTY)
1211 { // just crossed into water
1212 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1214 ent->v.watertype = CONTENTS_EMPTY;
1215 ent->v.waterlevel = cont;
1223 Toss, bounce, and fly movement. When onground, do nothing.
1226 void SV_Physics_Toss (edict_t *ent)
1231 edict_t *groundentity;
1233 if (!SV_RunThink (ent))
1236 // if onground, return without moving
1237 if ( ((int)ent->v.flags & FL_ONGROUND) )
1239 // LordHavoc: fall if the groundentity was removed
1240 if (ent->v.groundentity)
1242 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1243 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1247 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1249 SV_CheckVelocity (ent);
1252 if (ent->v.movetype != MOVETYPE_FLY
1253 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1254 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1255 SV_AddGravity (ent);
1258 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1261 VectorScale (ent->v.velocity, sv.frametime, move);
1262 trace = SV_PushEntity (ent, move, vec3_origin);
1263 if (trace.fraction == 1)
1268 if (ent->v.movetype == MOVETYPE_BOUNCE)
1270 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1275 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1277 // stop if on ground
1278 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1279 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1280 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1282 if (trace.plane.normal[2] > 0.7)
1284 // LordHavoc: fixed grenades not bouncing when fired down a slope
1285 if (DotProduct(trace.plane.normal, ent->v.velocity) < 100)
1286 //if (ent->v.velocity[2] < 60)
1288 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1289 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1290 VectorClear (ent->v.velocity);
1291 VectorClear (ent->v.avelocity);
1294 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1297 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1301 if (trace.plane.normal[2] > 0.7)
1303 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1304 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1305 VectorClear (ent->v.velocity);
1306 VectorClear (ent->v.avelocity);
1309 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1312 // check for in water
1313 SV_CheckWaterTransition (ent);
1317 ===============================================================================
1321 ===============================================================================
1328 Monsters freefall when they don't have a ground entity, otherwise
1329 all movement is done with discrete steps.
1331 This is also used for objects that have become still on the ground, but
1332 will fall if the floor is pulled out from under them.
1335 void SV_Physics_Step (edict_t *ent)
1339 // freefall if not onground
1340 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1342 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1347 SV_AddGravity (ent);
1348 SV_CheckVelocity (ent);
1349 SV_FlyMove (ent, sv.frametime, NULL);
1350 SV_LinkEdict (ent, true);
1352 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1355 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1362 SV_CheckWaterTransition (ent);
1365 //============================================================================
1373 void SV_Physics (void)
1378 // let the progs know that a new frame has started
1379 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1380 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1381 pr_global_struct->time = sv.time;
1382 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1384 //SV_CheckAllEnts ();
1387 // treat each object in turn
1390 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1395 if (pr_global_struct->force_retouch)
1396 SV_LinkEdict (ent, true); // force retouch even for stationary
1398 if (i > 0 && i <= svs.maxclients)
1400 SV_Physics_Client (ent, i);
1404 switch ((int) ent->v.movetype)
1407 SV_Physics_Pusher (ent);
1410 // SV_Physics_None (ent);
1411 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1412 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1415 case MOVETYPE_FOLLOW:
1416 SV_Physics_Follow (ent);
1418 case MOVETYPE_NOCLIP:
1419 SV_Physics_Noclip (ent);
1422 SV_Physics_Step (ent);
1424 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1426 if (SV_RunThink (ent))
1428 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1429 SV_AddGravity (ent);
1430 SV_CheckStuck (ent);
1432 SV_LinkEdict (ent, true);
1436 case MOVETYPE_BOUNCE:
1437 case MOVETYPE_BOUNCEMISSILE:
1439 case MOVETYPE_FLYMISSILE:
1440 SV_Physics_Toss (ent);
1443 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1448 if (pr_global_struct->force_retouch)
1449 pr_global_struct->force_retouch--;
1451 // LordHavoc: endframe support
1454 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1455 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1456 pr_global_struct->time = sv.time;
1457 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1460 sv.time += sv.frametime;
1464 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1467 edict_t tempent, *tent;
1471 float gravity, savesolid;
1474 memcpy(&tempent, tossent, sizeof(edict_t));
1476 savesolid = tossent->v.solid;
1477 tossent->v.solid = SOLID_NOT;
1479 // this has to fetch the field from the original edict, since our copy is truncated
1480 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1481 if (val != NULL && val->_float != 0)
1482 gravity = val->_float;
1485 gravity *= sv_gravity.value * 0.05;
1487 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1489 SV_CheckVelocity (tent);
1490 tent->v.velocity[2] -= gravity;
1491 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1492 VectorScale (tent->v.velocity, 0.05, move);
1493 VectorAdd (tent->v.origin, move, end);
1494 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1495 VectorCopy (trace.endpos, tent->v.origin);
1497 if (trace.fraction < 1 && trace.ent)
1498 if (trace.ent != ignore)
1501 tossent->v.solid = savesolid;
1502 trace.fraction = 0; // not relevant