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"};
47 cvar_t sv_stepheight = {0, "sv_stepheight", "18"};
49 #define MOVE_EPSILON 0.01
51 void SV_Physics_Toss (edict_t *ent);
53 void SV_Phys_Init (void)
55 Cvar_RegisterVariable(&sv_stepheight);
63 void SV_CheckAllEnts (void)
68 // see if any solid entities are inside the final position
69 check = NEXT_EDICT(sv.edicts);
70 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
74 if (check->v.movetype == MOVETYPE_PUSH
75 || check->v.movetype == MOVETYPE_NONE
76 || check->v.movetype == MOVETYPE_FOLLOW
77 || check->v.movetype == MOVETYPE_NOCLIP)
80 if (SV_TestEntityPosition (check))
81 Con_Printf ("entity in invalid position\n");
90 void SV_CheckVelocity (edict_t *ent)
100 if (IS_NAN(ent->v.velocity[i]))
102 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
103 ent->v.velocity[i] = 0;
105 if (IS_NAN(ent->v.origin[i]))
107 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
108 ent->v.origin[i] = 0;
112 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
113 wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
114 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
116 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
117 ent->v.velocity[0] *= wishspeed;
118 ent->v.velocity[1] *= wishspeed;
119 ent->v.velocity[2] *= wishspeed;
127 Runs thinking code if time. There is some play in the exact time the think
128 function will be called, because it is called before any movement is done
129 in a frame. Not used for pushmove objects, because they must be exact.
130 Returns false if the entity removed itself.
133 qboolean SV_RunThink (edict_t *ent)
137 thinktime = ent->v.nextthink;
138 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
141 if (thinktime < sv.time)
142 thinktime = sv.time; // don't let things stay in the past.
143 // it is possible to start that way
144 // by a trigger with a local time.
145 ent->v.nextthink = 0;
146 pr_global_struct->time = thinktime;
147 pr_global_struct->self = EDICT_TO_PROG(ent);
148 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
149 PR_ExecuteProgram (ent->v.think, "NULL think function");
157 Two entities have touched, so run their touch functions
160 void SV_Impact (edict_t *e1, edict_t *e2)
162 int old_self, old_other;
164 old_self = pr_global_struct->self;
165 old_other = pr_global_struct->other;
167 pr_global_struct->time = sv.time;
168 if (e1->v.touch && e1->v.solid != SOLID_NOT)
170 pr_global_struct->self = EDICT_TO_PROG(e1);
171 pr_global_struct->other = EDICT_TO_PROG(e2);
172 PR_ExecuteProgram (e1->v.touch, "");
175 if (e2->v.touch && e2->v.solid != SOLID_NOT)
177 pr_global_struct->self = EDICT_TO_PROG(e2);
178 pr_global_struct->other = EDICT_TO_PROG(e1);
179 PR_ExecuteProgram (e2->v.touch, "");
182 pr_global_struct->self = old_self;
183 pr_global_struct->other = old_other;
191 Slide off of the impacting object
192 returns the blocked flags (1 = floor, 2 = step / wall)
195 #define STOP_EPSILON 0.1
197 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
205 blocked |= 1; // floor
207 blocked |= 2; // step
209 backoff = DotProduct (in, normal) * overbounce;
211 for (i=0 ; i<3 ; i++)
213 change = normal[i]*backoff;
214 out[i] = in[i] - change;
215 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
227 The basic solid body movement clip that slides along multiple planes
228 Returns the clipflags if the velocity was modified (hit something solid)
232 If steptrace is not NULL, the trace of any vertical wall hit will be stored
235 // LordHavoc: increased from 5 to 20
236 #define MAX_CLIP_PLANES 20
237 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
239 int bumpcount, numbumps;
243 vec3_t planes[MAX_CLIP_PLANES];
244 vec3_t primal_velocity, original_velocity, new_velocity;
254 VectorCopy (ent->v.velocity, original_velocity);
255 VectorCopy (ent->v.velocity, primal_velocity);
260 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
262 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
265 for (i=0 ; i<3 ; i++)
266 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
268 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
272 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
273 // entity is trapped in another solid
274 VectorClear(ent->v.velocity);
278 if (trace.fraction > 0)
279 { // actually covered some distance
280 VectorCopy (trace.endpos, ent->v.origin);
281 VectorCopy (ent->v.velocity, original_velocity);
285 if (trace.fraction == 1)
286 break; // moved the entire distance
289 Host_Error ("SV_FlyMove: !trace.ent");
291 if ((int) ent->v.flags & FL_ONGROUND)
293 if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
297 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
304 if (trace.plane.normal[2] > 0.7)
306 blocked |= 1; // floor
307 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
308 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
310 if (!trace.plane.normal[2])
312 blocked |= 2; // step
314 *steptrace = trace; // save for player extrafriction
318 // run the impact function
321 SV_Impact (ent, trace.ent);
323 break; // removed by the impact function
326 time_left -= time_left * trace.fraction;
328 // cliped to another plane
329 if (numplanes >= MAX_CLIP_PLANES)
330 { // this shouldn't really happen
331 VectorClear(ent->v.velocity);
335 VectorCopy (trace.plane.normal, planes[numplanes]);
339 // modify original_velocity so it parallels all of the clip planes
341 for (i=0 ; i<numplanes ; i++)
343 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
344 for (j=0 ; j<numplanes ; j++)
347 if (DotProduct (new_velocity, planes[j]) < 0)
355 { // go along this plane
356 VectorCopy (new_velocity, ent->v.velocity);
359 { // go along the crease
362 VectorClear(ent->v.velocity);
365 CrossProduct (planes[0], planes[1], dir);
366 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
367 VectorNormalize(dir);
368 d = DotProduct (dir, ent->v.velocity);
369 VectorScale (dir, d, ent->v.velocity);
373 // if original velocity is against the original velocity, stop dead
374 // to avoid tiny occilations in sloping corners
376 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
378 VectorClear(ent->v.velocity);
393 void SV_AddGravity (edict_t *ent)
399 val = GETEDICTFIELDVALUE(ent, eval_gravity);
400 if (val!=0 && val->_float)
401 ent_gravity = val->_float;
404 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
409 ===============================================================================
413 ===============================================================================
420 Does not change the entities velocity at all
423 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
428 VectorAdd (ent->v.origin, push, end);
430 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
431 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
432 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
433 // only clip against bmodels
434 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
436 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
438 VectorCopy (trace.endpos, ent->v.origin);
439 // FIXME: turn players specially
440 ent->v.angles[1] += trace.fraction * pushangles[1];
441 SV_LinkEdict (ent, true);
443 if (trace.ent && (!((int)ent->v.flags & FL_ONGROUND) || ent->v.groundentity != EDICT_TO_PROG(trace.ent)))
444 SV_Impact (ent, trace.ent);
455 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
456 void SV_PushMove (edict_t *pusher, float movetime)
460 float savesolid, movetime2, pushltime;
461 vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
463 edict_t *moved_edict[MAX_EDICTS];
464 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
465 model_t *pushermodel;
468 switch ((int) pusher->v.solid)
470 // LordHavoc: valid pusher types
474 case SOLID_CORPSE: // LordHavoc: this would be weird...
476 // LordHavoc: no collisions
479 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
480 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
481 pusher->v.ltime += movetime;
482 SV_LinkEdict (pusher, false);
485 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
487 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])
489 pusher->v.ltime += movetime;
492 index = (int) pusher->v.modelindex;
493 if (index < 1 || index >= MAX_MODELS)
494 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
495 pushermodel = sv.models[index];
497 movetime2 = movetime;
498 VectorScale(pusher->v.velocity, movetime2, move1);
499 VectorScale(pusher->v.avelocity, movetime2, moveangle);
500 if (moveangle[0] || moveangle[2])
502 for (i = 0;i < 3;i++)
506 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
507 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
511 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
512 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
516 else if (moveangle[1])
518 for (i = 0;i < 3;i++)
522 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
523 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
527 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
528 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
534 for (i = 0;i < 3;i++)
538 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
539 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
543 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
544 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
549 VectorNegate (moveangle, a);
550 AngleVectorsFLU (a, forward, left, up);
552 VectorCopy (pusher->v.origin, pushorig);
553 VectorCopy (pusher->v.angles, pushang);
554 pushltime = pusher->v.ltime;
556 // move the pusher to it's final position
558 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
559 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
560 pusher->v.ltime += movetime;
561 SV_LinkEdict (pusher, false);
563 savesolid = pusher->v.solid;
565 // see if any solid entities are inside the final position
567 check = NEXT_EDICT(sv.edicts);
568 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
572 if (check->v.movetype == MOVETYPE_PUSH
573 || check->v.movetype == MOVETYPE_NONE
574 || check->v.movetype == MOVETYPE_FOLLOW
575 || check->v.movetype == MOVETYPE_NOCLIP)
578 // if the entity is standing on the pusher, it will definitely be moved
579 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
581 if (check->v.absmin[0] >= maxs[0]
582 || check->v.absmax[0] <= mins[0]
583 || check->v.absmin[1] >= maxs[1]
584 || check->v.absmax[1] <= mins[1]
585 || check->v.absmin[2] >= maxs[2]
586 || check->v.absmax[2] <= mins[2])
589 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
590 if (!trace.startsolid)
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);
604 VectorCopy (move1, move);
606 // remove the onground flag for non-players
607 if (check->v.movetype != MOVETYPE_WALK)
608 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
610 VectorCopy (check->v.origin, moved_from[num_moved]);
611 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
612 moved_edict[num_moved++] = check;
614 // try moving the contacted entity
615 pusher->v.solid = SOLID_NOT;
616 trace = SV_PushEntity (check, move, moveangle);
617 pusher->v.solid = savesolid; // was SOLID_BSP
619 // if it is still inside the pusher, block
620 if (SV_TestEntityPosition (check))
623 if (check->v.mins[0] == check->v.maxs[0])
625 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
628 check->v.mins[0] = check->v.mins[1] = 0;
629 VectorCopy (check->v.mins, check->v.maxs);
633 VectorCopy (pushorig, pusher->v.origin);
634 VectorCopy (pushang, pusher->v.angles);
635 pusher->v.ltime = pushltime;
636 SV_LinkEdict (pusher, false);
638 // move back any entities we already moved
639 for (i=0 ; i<num_moved ; i++)
641 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
642 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
643 SV_LinkEdict (moved_edict[i], false);
646 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
647 if (pusher->v.blocked)
649 pr_global_struct->self = EDICT_TO_PROG(pusher);
650 pr_global_struct->other = EDICT_TO_PROG(check);
651 PR_ExecuteProgram (pusher->v.blocked, "");
664 void SV_Physics_Pusher (edict_t *ent)
670 oldltime = ent->v.ltime;
672 thinktime = ent->v.nextthink;
673 if (thinktime < ent->v.ltime + sv.frametime)
675 movetime = thinktime - ent->v.ltime;
680 movetime = sv.frametime;
683 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
685 if (thinktime > oldltime && thinktime <= ent->v.ltime)
687 ent->v.nextthink = 0;
688 pr_global_struct->time = sv.time;
689 pr_global_struct->self = EDICT_TO_PROG(ent);
690 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
691 PR_ExecuteProgram (ent->v.think, "NULL think function");
700 ===============================================================================
704 ===============================================================================
711 This is a big hack to try and fix the rare case of getting stuck in the world
715 void SV_CheckStuck (edict_t *ent)
721 if (!SV_TestEntityPosition(ent))
723 VectorCopy (ent->v.origin, ent->v.oldorigin);
727 VectorCopy (ent->v.origin, org);
728 VectorCopy (ent->v.oldorigin, ent->v.origin);
729 if (!SV_TestEntityPosition(ent))
731 Con_DPrintf ("Unstuck.\n");
732 SV_LinkEdict (ent, true);
736 for (z=0 ; z< 18 ; z++)
737 for (i=-1 ; i <= 1 ; i++)
738 for (j=-1 ; j <= 1 ; j++)
740 ent->v.origin[0] = org[0] + i;
741 ent->v.origin[1] = org[1] + j;
742 ent->v.origin[2] = org[2] + z;
743 if (!SV_TestEntityPosition(ent))
745 Con_DPrintf ("Unstuck.\n");
746 SV_LinkEdict (ent, true);
751 VectorCopy (org, ent->v.origin);
752 Con_DPrintf ("player is stuck.\n");
761 qboolean SV_CheckWater (edict_t *ent)
766 point[0] = ent->v.origin[0];
767 point[1] = ent->v.origin[1];
768 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
770 ent->v.waterlevel = 0;
771 ent->v.watertype = CONTENTS_EMPTY;
772 cont = SV_PointContents (point);
773 if (cont <= CONTENTS_WATER)
775 ent->v.watertype = cont;
776 ent->v.waterlevel = 1;
777 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
778 cont = SV_PointContents (point);
779 if (cont <= CONTENTS_WATER)
781 ent->v.waterlevel = 2;
782 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
783 cont = SV_PointContents (point);
784 if (cont <= CONTENTS_WATER)
785 ent->v.waterlevel = 3;
789 return ent->v.waterlevel > 1;
798 void SV_WallFriction (edict_t *ent, trace_t *trace)
804 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
805 d = DotProduct (trace->plane.normal, forward);
811 // cut the tangential velocity
812 i = DotProduct (trace->plane.normal, ent->v.velocity);
813 VectorScale (trace->plane.normal, i, into);
814 VectorSubtract (ent->v.velocity, into, side);
816 ent->v.velocity[0] = side[0] * (1 + d);
817 ent->v.velocity[1] = side[1] * (1 + d);
821 =====================
824 Player has come to a dead stop, possibly due to the problem with limited
825 float precision at some angle joins in the BSP hull.
827 Try fixing by pushing one pixel in each direction.
829 This is a hack, but in the interest of good gameplay...
830 ======================
832 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
840 VectorCopy (ent->v.origin, oldorg);
843 for (i=0 ; i<8 ; i++)
845 // try pushing a little in an axial direction
848 case 0: dir[0] = 2; dir[1] = 0; break;
849 case 1: dir[0] = 0; dir[1] = 2; break;
850 case 2: dir[0] = -2; dir[1] = 0; break;
851 case 3: dir[0] = 0; dir[1] = -2; break;
852 case 4: dir[0] = 2; dir[1] = 2; break;
853 case 5: dir[0] = -2; dir[1] = 2; break;
854 case 6: dir[0] = 2; dir[1] = -2; break;
855 case 7: dir[0] = -2; dir[1] = -2; break;
858 SV_PushEntity (ent, dir, vec3_origin);
860 // retry the original move
861 ent->v.velocity[0] = oldvel[0];
862 ent->v.velocity[1] = oldvel[1];
863 ent->v.velocity[2] = 0;
864 clip = SV_FlyMove (ent, 0.1, &steptrace);
866 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
867 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
872 // go back to the original pos and try again
873 VectorCopy (oldorg, ent->v.origin);
876 VectorClear (ent->v.velocity);
877 return 7; // still not moving
881 =====================
885 ======================
887 void SV_WalkMove (edict_t *ent)
889 vec3_t upmove, downmove;
890 vec3_t oldorg, oldvel;
891 vec3_t nosteporg, nostepvel;
894 trace_t steptrace, downtrace;
897 // do a regular slide move unless it looks like you ran into a step
899 oldonground = (int)ent->v.flags & FL_ONGROUND;
900 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
902 VectorCopy (ent->v.origin, oldorg);
903 VectorCopy (ent->v.velocity, oldvel);
905 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
908 return; // move didn't block on a step
910 if (!oldonground && ent->v.waterlevel == 0)
911 return; // don't stair up while jumping
913 if (ent->v.movetype != MOVETYPE_WALK)
914 return; // gibbed by a trigger
916 if (sv_nostep.integer)
919 if ( (int)sv_player->v.flags & FL_WATERJUMP )
922 VectorCopy (ent->v.origin, nosteporg);
923 VectorCopy (ent->v.velocity, nostepvel);
926 // try moving up and forward to go up a step
928 VectorCopy (oldorg, ent->v.origin); // back to start pos
930 VectorClear (upmove);
931 VectorClear (downmove);
932 upmove[2] = sv_stepheight.value;
933 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
936 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
939 ent->v.velocity[0] = oldvel[0];
940 ent->v. velocity[1] = oldvel[1];
941 ent->v. velocity[2] = 0;
942 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
944 // check for stuckness, possibly due to the limited precision of floats
945 // in the clipping hulls
948 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
949 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
950 { // stepping up didn't make any progress
951 clip = SV_TryUnstick (ent, oldvel);
955 // extra friction based on view angle
957 SV_WallFriction (ent, &steptrace);
960 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
962 if (downtrace.plane.normal[2] > 0.7)
964 if (ent->v.solid == SOLID_BSP)
966 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
967 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
972 // if the push down didn't end up on good ground, use the move without
973 // the step up. This happens near wall / slope combinations, and can
974 // cause the player to hop up higher on a slope too steep to climb
975 VectorCopy (nosteporg, ent->v.origin);
976 VectorCopy (nostepvel, ent->v.velocity);
985 Player character actions
988 void SV_Physics_Client (edict_t *ent, int num)
990 if ( ! svs.clients[num-1].active )
991 return; // unconnected slot
994 // call standard client pre-think
996 pr_global_struct->time = sv.time;
997 pr_global_struct->self = EDICT_TO_PROG(ent);
998 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1003 SV_CheckVelocity (ent);
1006 // decide which move function to call
1008 switch ((int)ent->v.movetype)
1011 if (!SV_RunThink (ent))
1016 if (!SV_RunThink (ent))
1018 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1019 SV_AddGravity (ent);
1020 SV_CheckStuck (ent);
1025 case MOVETYPE_BOUNCE:
1026 SV_Physics_Toss (ent);
1030 if (!SV_RunThink (ent))
1032 SV_CheckWater (ent);
1033 SV_FlyMove (ent, sv.frametime, NULL);
1036 case MOVETYPE_NOCLIP:
1037 if (!SV_RunThink (ent))
1039 SV_CheckWater (ent);
1040 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1044 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1048 // call standard player post-think
1050 SV_LinkEdict (ent, true);
1052 pr_global_struct->time = sv.time;
1053 pr_global_struct->self = EDICT_TO_PROG(ent);
1054 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1057 //============================================================================
1063 Entities that are "stuck" to another entity
1066 void SV_Physics_Follow (edict_t *ent)
1068 vec3_t vf, vr, vu, angles, v;
1071 if (!SV_RunThink (ent))
1073 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1074 e = PROG_TO_EDICT(ent->v.aiment);
1075 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])
1077 // quick case for no rotation
1078 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1082 angles[0] = -ent->v.punchangle[0];
1083 angles[1] = ent->v.punchangle[1];
1084 angles[2] = ent->v.punchangle[2];
1085 AngleVectors (angles, vf, vr, vu);
1086 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1087 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1088 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1089 angles[0] = -e->v.angles[0];
1090 angles[1] = e->v.angles[1];
1091 angles[2] = e->v.angles[2];
1092 AngleVectors (angles, vf, vr, vu);
1093 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1094 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1095 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1097 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1098 SV_LinkEdict (ent, true);
1105 A moving object that doesn't obey physics
1108 void SV_Physics_Noclip (edict_t *ent)
1111 if (!SV_RunThink (ent))
1114 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1115 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1117 SV_LinkEdict (ent, false);
1121 ==============================================================================
1125 ==============================================================================
1130 SV_CheckWaterTransition
1134 void SV_CheckWaterTransition (edict_t *ent)
1137 cont = SV_PointContents (ent->v.origin);
1138 if (!ent->v.watertype)
1139 { // just spawned here
1140 ent->v.watertype = cont;
1141 ent->v.waterlevel = 1;
1145 if (cont <= CONTENTS_WATER)
1147 if (ent->v.watertype == CONTENTS_EMPTY)
1148 { // just crossed into water
1149 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1151 ent->v.watertype = cont;
1152 ent->v.waterlevel = 1;
1156 if (ent->v.watertype != CONTENTS_EMPTY)
1157 { // just crossed into water
1158 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1160 ent->v.watertype = CONTENTS_EMPTY;
1161 ent->v.waterlevel = cont;
1169 Toss, bounce, and fly movement. When onground, do nothing.
1172 void SV_Physics_Toss (edict_t *ent)
1176 edict_t *groundentity;
1179 if (!SV_RunThink (ent))
1182 // if onground, return without moving
1183 if ((int)ent->v.flags & FL_ONGROUND)
1185 if (ent->v.groundentity == 0)
1187 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1188 if (groundentity != NULL && groundentity->v.solid == SOLID_BSP)
1189 ent->suspendedinairflag = true;
1190 else if (ent->suspendedinairflag && (groundentity == NULL || groundentity->free))
1192 // leave it suspended in the air
1193 ent->v.groundentity = 0;
1194 ent->suspendedinairflag = false;
1198 ent->suspendedinairflag = false;
1200 SV_CheckVelocity (ent);
1203 if (ent->v.movetype != MOVETYPE_FLY
1204 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1205 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1206 SV_AddGravity (ent);
1209 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1212 VectorScale (ent->v.velocity, sv.frametime, move);
1213 trace = SV_PushEntity (ent, move, vec3_origin);
1216 if (trace.fraction == 1)
1219 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1221 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 2.0);
1222 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1224 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1226 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
1227 // LordHavoc: fixed grenades not bouncing when fired down a slope
1228 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1230 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1231 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1232 VectorClear (ent->v.velocity);
1233 VectorClear (ent->v.avelocity);
1236 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1240 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0);
1241 if (trace.plane.normal[2] > 0.7)
1243 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1244 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1245 VectorClear (ent->v.velocity);
1246 VectorClear (ent->v.avelocity);
1249 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1252 // check for in water
1253 SV_CheckWaterTransition (ent);
1257 ===============================================================================
1261 ===============================================================================
1268 Monsters freefall when they don't have a ground entity, otherwise
1269 all movement is done with discrete steps.
1271 This is also used for objects that have become still on the ground, but
1272 will fall if the floor is pulled out from under them.
1275 void SV_Physics_Step (edict_t *ent)
1277 int flags, fall, hitsound;
1279 // freefall if not fly/swim
1281 flags = (int)ent->v.flags;
1282 if (flags & (FL_FLY | FL_SWIM))
1286 else if ((flags & FL_SWIM) && SV_PointContents(ent->v.origin) != CONTENTS_EMPTY)
1289 if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
1294 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1297 if (flags & FL_ONGROUND)
1303 SV_AddGravity (ent);
1304 SV_CheckVelocity (ent);
1305 SV_FlyMove (ent, sv.frametime, NULL);
1306 SV_LinkEdict (ent, false);
1309 if ((int)ent->v.flags & FL_ONGROUND)
1311 VectorClear(ent->v.velocity);
1313 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1320 SV_CheckWaterTransition (ent);
1323 //============================================================================
1331 void SV_Physics (void)
1336 // let the progs know that a new frame has started
1337 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1338 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1339 pr_global_struct->time = sv.time;
1340 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1343 // treat each object in turn
1346 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1351 if (pr_global_struct->force_retouch)
1352 SV_LinkEdict (ent, true); // force retouch even for stationary
1354 if (i > 0 && i <= svs.maxclients)
1356 SV_Physics_Client (ent, i);
1360 switch ((int) ent->v.movetype)
1363 SV_Physics_Pusher (ent);
1366 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1367 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1370 case MOVETYPE_FOLLOW:
1371 SV_Physics_Follow (ent);
1373 case MOVETYPE_NOCLIP:
1374 SV_Physics_Noclip (ent);
1377 SV_Physics_Step (ent);
1379 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1381 if (SV_RunThink (ent))
1383 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1384 SV_AddGravity (ent);
1385 SV_CheckStuck (ent);
1387 SV_LinkEdict (ent, true);
1391 case MOVETYPE_BOUNCE:
1392 case MOVETYPE_BOUNCEMISSILE:
1394 case MOVETYPE_FLYMISSILE:
1395 SV_Physics_Toss (ent);
1398 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1403 if (pr_global_struct->force_retouch)
1404 pr_global_struct->force_retouch--;
1406 // LordHavoc: endframe support
1409 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1410 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1411 pr_global_struct->time = sv.time;
1412 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1415 sv.time += sv.frametime;
1419 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1422 edict_t tempent, *tent;
1426 float gravity, savesolid;
1429 memcpy(&tempent, tossent, sizeof(edict_t));
1431 savesolid = tossent->v.solid;
1432 tossent->v.solid = SOLID_NOT;
1434 // this has to fetch the field from the original edict, since our copy is truncated
1435 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1436 if (val != NULL && val->_float != 0)
1437 gravity = val->_float;
1440 gravity *= sv_gravity.value * 0.05;
1442 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1444 SV_CheckVelocity (tent);
1445 tent->v.velocity[2] -= gravity;
1446 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1447 VectorScale (tent->v.velocity, 0.05, move);
1448 VectorAdd (tent->v.origin, move, end);
1449 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1450 VectorCopy (trace.endpos, tent->v.origin);
1452 if (trace.fraction < 1 && trace.ent)
1453 if (trace.ent != ignore)
1456 tossent->v.solid = savesolid;
1457 trace.fraction = 0; // not relevant