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);
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;
456 switch ((int) pusher->v.solid)
458 // LordHavoc: valid pusher types
462 case SOLID_CORPSE: // LordHavoc: this would be weird...
464 // LordHavoc: no collisions
467 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
468 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
469 pusher->v.ltime += movetime;
470 SV_LinkEdict (pusher, false);
473 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
475 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])
477 pusher->v.ltime += movetime;
480 index = (int) pusher->v.modelindex;
481 if (index < 1 || index >= MAX_MODELS)
482 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
483 pushermodel = sv.models[index];
485 // LordHavoc: round up by a small epsilon
486 movetime2 = movetime; // + (1.0 / 256.0);
487 for (i = 0;i < 3;i++)
489 move1[i] = pusher->v.velocity[i] * movetime2;
490 moveangle[i] = pusher->v.avelocity[i] * movetime2;
492 if (moveangle[0] || moveangle[2])
494 for (i = 0;i < 3;i++)
496 mins[i] = pushermodel->rotatedmins[i] + move1[i] - 32;
497 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + 32;
500 else if (moveangle[1])
502 for (i = 0;i < 3;i++)
504 mins[i] = pushermodel->yawmins[i] + move1[i] - 32;
505 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + 32;
510 for (i = 0;i < 3;i++)
512 mins[i] = pushermodel->normalmins[i] + move1[i] - 32;
513 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + 32;
517 VectorNegate (moveangle, a);
518 AngleVectorsFLU (a, forward, left, up);
520 VectorCopy (pusher->v.origin, pushorig);
521 VectorCopy (pusher->v.angles, pushang);
522 pushltime = pusher->v.ltime;
524 // move the pusher to it's final position
526 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
527 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
528 pusher->v.ltime += movetime;
529 SV_LinkEdict (pusher, false);
531 savesolid = pusher->v.solid;
533 // see if any solid entities are inside the final position
535 check = NEXT_EDICT(sv.edicts);
536 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
540 if (check->v.movetype == MOVETYPE_PUSH
541 || check->v.movetype == MOVETYPE_NONE
542 || check->v.movetype == MOVETYPE_FOLLOW
543 || check->v.movetype == MOVETYPE_NOCLIP)
546 // if the entity is standing on the pusher, it will definitely be moved
547 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
549 if (check->v.absmin[0] >= maxs[0]
550 || check->v.absmin[1] >= maxs[1]
551 || check->v.absmin[2] >= maxs[2]
552 || check->v.absmax[0] <= mins[0]
553 || check->v.absmax[1] <= mins[1]
554 || check->v.absmax[2] <= mins[2])
557 // see if the ent's bbox is inside the pusher's final position
558 if (!SV_TestEntityPosition (check))
562 // remove the onground flag for non-players
563 if (check->v.movetype != MOVETYPE_WALK)
564 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
566 VectorCopy (check->v.origin, entorig);
567 VectorCopy (check->v.angles, entang);
568 VectorCopy (check->v.origin, moved_from[num_moved]);
569 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
570 moved_edict[num_moved] = check;
573 if (forward[0] > 0.999f) // quick way to check if any rotation is used
575 VectorSubtract (check->v.origin, pusher->v.origin, org);
576 org2[0] = DotProduct (org, forward);
577 org2[1] = DotProduct (org, left);
578 org2[2] = DotProduct (org, up);
579 VectorSubtract (org2, org, move);
580 VectorAdd (move, move1, move);
583 VectorCopy (move1, move);
585 // LordHavoc: debugging
586 //VectorAdd(entorig, move, org2);
587 //CL_RocketTrail2 (entorig, org2, 238, NULL);
589 // try moving the contacted entity
590 pusher->v.solid = SOLID_NOT;
591 SV_PushEntity (check, move, moveangle);
592 pusher->v.solid = savesolid; // was SOLID_BSP
594 // if it is still inside the pusher, block
595 if (SV_TestEntityPosition (check))
598 if (check->v.mins[0] == check->v.maxs[0])
600 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
603 check->v.mins[0] = check->v.mins[1] = 0;
604 VectorCopy (check->v.mins, check->v.maxs);
608 VectorCopy (entorig, check->v.origin);
609 VectorCopy (entang, check->v.angles);
610 SV_LinkEdict (check, true);
612 VectorCopy (pushorig, pusher->v.origin);
613 VectorCopy (pushang, pusher->v.angles);
614 pusher->v.ltime = pushltime;
615 SV_LinkEdict (pusher, false);
617 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
618 if (pusher->v.blocked)
620 pr_global_struct->self = EDICT_TO_PROG(pusher);
621 pr_global_struct->other = EDICT_TO_PROG(check);
622 PR_ExecuteProgram (pusher->v.blocked, "");
625 // move back any entities we already moved
626 num_moved--; // LordHavoc: pop off check, because it was already restored
627 for (i=0 ; i<num_moved ; i++)
629 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
630 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
631 SV_LinkEdict (moved_edict[i], false);
644 void SV_Physics_Pusher (edict_t *ent)
650 oldltime = ent->v.ltime;
652 thinktime = ent->v.nextthink;
653 if (thinktime < ent->v.ltime + sv.frametime)
655 movetime = thinktime - ent->v.ltime;
660 movetime = sv.frametime;
663 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
665 if (thinktime > oldltime && thinktime <= ent->v.ltime)
667 ent->v.nextthink = 0;
668 pr_global_struct->time = sv.time;
669 pr_global_struct->self = EDICT_TO_PROG(ent);
670 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
671 PR_ExecuteProgram (ent->v.think, "NULL think function");
680 ===============================================================================
684 ===============================================================================
691 This is a big hack to try and fix the rare case of getting stuck in the world
695 void SV_CheckStuck (edict_t *ent)
701 if (!SV_TestEntityPosition(ent))
703 VectorCopy (ent->v.origin, ent->v.oldorigin);
707 VectorCopy (ent->v.origin, org);
708 VectorCopy (ent->v.oldorigin, ent->v.origin);
709 if (!SV_TestEntityPosition(ent))
711 Con_DPrintf ("Unstuck.\n");
712 SV_LinkEdict (ent, true);
716 for (z=0 ; z< 18 ; z++)
717 for (i=-1 ; i <= 1 ; i++)
718 for (j=-1 ; j <= 1 ; j++)
720 ent->v.origin[0] = org[0] + i;
721 ent->v.origin[1] = org[1] + j;
722 ent->v.origin[2] = org[2] + z;
723 if (!SV_TestEntityPosition(ent))
725 Con_DPrintf ("Unstuck.\n");
726 SV_LinkEdict (ent, true);
731 VectorCopy (org, ent->v.origin);
732 Con_DPrintf ("player is stuck.\n");
741 qboolean SV_CheckWater (edict_t *ent)
746 point[0] = ent->v.origin[0];
747 point[1] = ent->v.origin[1];
748 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
750 ent->v.waterlevel = 0;
751 ent->v.watertype = CONTENTS_EMPTY;
752 cont = SV_PointContents (point);
753 if (cont <= CONTENTS_WATER)
755 ent->v.watertype = cont;
756 ent->v.waterlevel = 1;
757 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
758 cont = SV_PointContents (point);
759 if (cont <= CONTENTS_WATER)
761 ent->v.waterlevel = 2;
762 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
763 cont = SV_PointContents (point);
764 if (cont <= CONTENTS_WATER)
765 ent->v.waterlevel = 3;
769 return ent->v.waterlevel > 1;
778 void SV_WallFriction (edict_t *ent, trace_t *trace)
784 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
785 d = DotProduct (trace->plane.normal, forward);
791 // cut the tangential velocity
792 i = DotProduct (trace->plane.normal, ent->v.velocity);
793 VectorScale (trace->plane.normal, i, into);
794 VectorSubtract (ent->v.velocity, into, side);
796 ent->v.velocity[0] = side[0] * (1 + d);
797 ent->v.velocity[1] = side[1] * (1 + d);
801 =====================
804 Player has come to a dead stop, possibly due to the problem with limited
805 float precision at some angle joins in the BSP hull.
807 Try fixing by pushing one pixel in each direction.
809 This is a hack, but in the interest of good gameplay...
810 ======================
812 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
820 VectorCopy (ent->v.origin, oldorg);
823 for (i=0 ; i<8 ; i++)
825 // try pushing a little in an axial direction
828 case 0: dir[0] = 2; dir[1] = 0; break;
829 case 1: dir[0] = 0; dir[1] = 2; break;
830 case 2: dir[0] = -2; dir[1] = 0; break;
831 case 3: dir[0] = 0; dir[1] = -2; break;
832 case 4: dir[0] = 2; dir[1] = 2; break;
833 case 5: dir[0] = -2; dir[1] = 2; break;
834 case 6: dir[0] = 2; dir[1] = -2; break;
835 case 7: dir[0] = -2; dir[1] = -2; break;
838 SV_PushEntity (ent, dir, vec3_origin);
840 // retry the original move
841 ent->v.velocity[0] = oldvel[0];
842 ent->v.velocity[1] = oldvel[1];
843 ent->v.velocity[2] = 0;
844 clip = SV_FlyMove (ent, 0.1, &steptrace);
846 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
847 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
849 //Con_DPrintf ("unstuck!\n");
853 // go back to the original pos and try again
854 VectorCopy (oldorg, ent->v.origin);
857 VectorClear (ent->v.velocity);
858 return 7; // still not moving
862 =====================
866 ======================
869 void SV_WalkMove (edict_t *ent)
871 vec3_t upmove, downmove;
872 vec3_t oldorg, oldvel;
873 vec3_t nosteporg, nostepvel;
876 trace_t steptrace, downtrace;
879 // do a regular slide move unless it looks like you ran into a step
881 oldonground = (int)ent->v.flags & FL_ONGROUND;
882 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
884 VectorCopy (ent->v.origin, oldorg);
885 VectorCopy (ent->v.velocity, oldvel);
887 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
890 return; // move didn't block on a step
892 if (!oldonground && ent->v.waterlevel == 0)
893 return; // don't stair up while jumping
895 if (ent->v.movetype != MOVETYPE_WALK)
896 return; // gibbed by a trigger
898 if (sv_nostep.integer)
901 if ( (int)sv_player->v.flags & FL_WATERJUMP )
904 VectorCopy (ent->v.origin, nosteporg);
905 VectorCopy (ent->v.velocity, nostepvel);
908 // try moving up and forward to go up a step
910 VectorCopy (oldorg, ent->v.origin); // back to start pos
912 VectorClear (upmove);
913 VectorClear (downmove);
914 upmove[2] = STEPSIZE;
915 downmove[2] = -STEPSIZE + oldvel[2]*sv.frametime;
918 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
921 ent->v.velocity[0] = oldvel[0];
922 ent->v. velocity[1] = oldvel[1];
923 ent->v. velocity[2] = 0;
924 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
926 // check for stuckness, possibly due to the limited precision of floats
927 // in the clipping hulls
930 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
931 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
932 { // stepping up didn't make any progress
933 clip = SV_TryUnstick (ent, oldvel);
937 // extra friction based on view angle
939 SV_WallFriction (ent, &steptrace);
942 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
944 if (downtrace.plane.normal[2] > 0.7)
946 if (ent->v.solid == SOLID_BSP)
948 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
949 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
954 // if the push down didn't end up on good ground, use the move without
955 // the step up. This happens near wall / slope combinations, and can
956 // cause the player to hop up higher on a slope too steep to climb
957 VectorCopy (nosteporg, ent->v.origin);
958 VectorCopy (nostepvel, ent->v.velocity);
967 Player character actions
970 void SV_Physics_Client (edict_t *ent, int num)
972 if ( ! svs.clients[num-1].active )
973 return; // unconnected slot
976 // call standard client pre-think
978 pr_global_struct->time = sv.time;
979 pr_global_struct->self = EDICT_TO_PROG(ent);
980 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
985 SV_CheckVelocity (ent);
988 // decide which move function to call
990 switch ((int)ent->v.movetype)
993 if (!SV_RunThink (ent))
998 if (!SV_RunThink (ent))
1000 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1001 SV_AddGravity (ent);
1002 SV_CheckStuck (ent);
1007 case MOVETYPE_BOUNCE:
1008 SV_Physics_Toss (ent);
1012 if (!SV_RunThink (ent))
1014 SV_CheckWater (ent);
1015 SV_FlyMove (ent, sv.frametime, NULL);
1018 case MOVETYPE_NOCLIP:
1019 if (!SV_RunThink (ent))
1021 SV_CheckWater (ent);
1022 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1026 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1030 // call standard player post-think
1032 SV_LinkEdict (ent, true);
1034 pr_global_struct->time = sv.time;
1035 pr_global_struct->self = EDICT_TO_PROG(ent);
1036 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1039 //============================================================================
1045 Non moving objects can only think
1048 // LordHavoc: inlined manually because it was a real time waster
1050 void SV_Physics_None (edict_t *ent)
1061 Entities that are "stuck" to another entity
1064 void SV_Physics_Follow (edict_t *ent)
1066 vec3_t vf, vr, vu, angles, v;
1069 if (!SV_RunThink (ent))
1071 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1072 e = PROG_TO_EDICT(ent->v.aiment);
1073 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])
1075 // quick case for no rotation
1076 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1080 angles[0] = -ent->v.punchangle[0];
1081 angles[1] = ent->v.punchangle[1];
1082 angles[2] = ent->v.punchangle[2];
1083 AngleVectors (angles, vf, vr, vu);
1084 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1085 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1086 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1087 angles[0] = -e->v.angles[0];
1088 angles[1] = e->v.angles[1];
1089 angles[2] = e->v.angles[2];
1090 AngleVectors (angles, vf, vr, vu);
1091 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1092 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1093 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1095 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];
1096 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];
1097 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];
1100 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1101 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1102 SV_LinkEdict (ent, true);
1109 A moving object that doesn't obey physics
1112 void SV_Physics_Noclip (edict_t *ent)
1115 if (!SV_RunThink (ent))
1118 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1119 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1121 SV_LinkEdict (ent, false);
1125 ==============================================================================
1129 ==============================================================================
1134 SV_CheckWaterTransition
1138 void SV_CheckWaterTransition (edict_t *ent)
1141 cont = SV_PointContents (ent->v.origin);
1142 if (!ent->v.watertype)
1143 { // just spawned here
1144 ent->v.watertype = cont;
1145 ent->v.waterlevel = 1;
1149 if (cont <= CONTENTS_WATER)
1151 if (ent->v.watertype == CONTENTS_EMPTY)
1152 { // just crossed into water
1153 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1155 ent->v.watertype = cont;
1156 ent->v.waterlevel = 1;
1160 if (ent->v.watertype != CONTENTS_EMPTY)
1161 { // just crossed into water
1162 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1164 ent->v.watertype = CONTENTS_EMPTY;
1165 ent->v.waterlevel = cont;
1173 Toss, bounce, and fly movement. When onground, do nothing.
1176 void SV_Physics_Toss (edict_t *ent)
1181 edict_t *groundentity;
1183 if (!SV_RunThink (ent))
1186 // if onground, return without moving
1187 if ( ((int)ent->v.flags & FL_ONGROUND) )
1189 // LordHavoc: fall if the groundentity was removed
1190 if (ent->v.groundentity)
1192 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1193 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1197 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1199 SV_CheckVelocity (ent);
1202 if (ent->v.movetype != MOVETYPE_FLY
1203 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1204 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1205 SV_AddGravity (ent);
1208 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1211 VectorScale (ent->v.velocity, sv.frametime, move);
1212 trace = SV_PushEntity (ent, move, vec3_origin);
1213 if (trace.fraction == 1)
1218 if (ent->v.movetype == MOVETYPE_BOUNCE)
1220 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1225 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1227 // stop if on ground
1228 if (trace.plane.normal[2] > 0.7)
1230 // LordHavoc: fixed grenades not bouncing when fired down a slope
1231 if (fabs(ent->v.velocity[2]) < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1232 //if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1234 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1235 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1236 VectorClear (ent->v.velocity);
1237 VectorClear (ent->v.avelocity);
1240 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1243 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1245 // check for in water
1246 SV_CheckWaterTransition (ent);
1250 ===============================================================================
1254 ===============================================================================
1261 Monsters freefall when they don't have a ground entity, otherwise
1262 all movement is done with discrete steps.
1264 This is also used for objects that have become still on the ground, but
1265 will fall if the floor is pulled out from under them.
1268 void SV_Physics_Step (edict_t *ent)
1272 // freefall if not onground
1273 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1275 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1280 SV_AddGravity (ent);
1281 SV_CheckVelocity (ent);
1282 SV_FlyMove (ent, sv.frametime, NULL);
1283 SV_LinkEdict (ent, true);
1285 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1288 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1295 SV_CheckWaterTransition (ent);
1298 //============================================================================
1306 void SV_Physics (void)
1311 // let the progs know that a new frame has started
1312 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1313 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1314 pr_global_struct->time = sv.time;
1315 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1317 //SV_CheckAllEnts ();
1320 // treat each object in turn
1323 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1328 if (pr_global_struct->force_retouch)
1329 SV_LinkEdict (ent, true); // force retouch even for stationary
1331 if (i > 0 && i <= svs.maxclients)
1333 SV_Physics_Client (ent, i);
1337 switch ((int) ent->v.movetype)
1340 SV_Physics_Pusher (ent);
1343 // SV_Physics_None (ent);
1344 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1345 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1348 case MOVETYPE_FOLLOW:
1349 SV_Physics_Follow (ent);
1351 case MOVETYPE_NOCLIP:
1352 SV_Physics_Noclip (ent);
1355 SV_Physics_Step (ent);
1357 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1359 if (SV_RunThink (ent))
1361 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1362 SV_AddGravity (ent);
1363 SV_CheckStuck (ent);
1365 SV_LinkEdict (ent, true);
1369 case MOVETYPE_BOUNCE:
1370 case MOVETYPE_BOUNCEMISSILE:
1372 case MOVETYPE_FLYMISSILE:
1373 SV_Physics_Toss (ent);
1376 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1381 if (pr_global_struct->force_retouch)
1382 pr_global_struct->force_retouch--;
1384 // LordHavoc: endframe support
1387 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1388 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1389 pr_global_struct->time = sv.time;
1390 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1393 sv.time += sv.frametime;
1397 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1400 edict_t tempent, *tent;
1404 float gravity, savesolid;
1407 memcpy(&tempent, tossent, sizeof(edict_t));
1409 savesolid = tossent->v.solid;
1410 tossent->v.solid = SOLID_NOT;
1412 // this has to fetch the field from the original edict, since our copy is truncated
1413 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1414 if (val != NULL && val->_float != 0)
1415 gravity = val->_float;
1418 gravity *= sv_gravity.value * 0.05;
1420 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1422 SV_CheckVelocity (tent);
1423 tent->v.velocity[2] -= gravity;
1424 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1425 VectorScale (tent->v.velocity, 0.05, move);
1426 VectorAdd (tent->v.origin, move, end);
1427 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1428 VectorCopy (trace.endpos, tent->v.origin);
1430 if (trace.fraction < 1 && trace.ent)
1431 if (trace.ent != ignore)
1434 tossent->v.solid = savesolid;
1435 trace.fraction = 0; // not relevant