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;
110 // LordHavoc: maxvelocity fix, see below
112 if (ent->v.velocity[i] > sv_maxvelocity.value)
113 ent->v.velocity[i] = sv_maxvelocity.value;
114 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
115 ent->v.velocity[i] = -sv_maxvelocity.value;
119 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
120 wishspeed = DotProduct(ent->v.velocity, ent->v.velocity);
121 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
123 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
124 ent->v.velocity[0] *= wishspeed;
125 ent->v.velocity[1] *= wishspeed;
126 ent->v.velocity[2] *= wishspeed;
134 Runs thinking code if time. There is some play in the exact time the think
135 function will be called, because it is called before any movement is done
136 in a frame. Not used for pushmove objects, because they must be exact.
137 Returns false if the entity removed itself.
140 qboolean SV_RunThink (edict_t *ent)
144 thinktime = ent->v.nextthink;
145 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
148 if (thinktime < sv.time)
149 thinktime = sv.time; // don't let things stay in the past.
150 // it is possible to start that way
151 // by a trigger with a local time.
152 ent->v.nextthink = 0;
153 pr_global_struct->time = thinktime;
154 pr_global_struct->self = EDICT_TO_PROG(ent);
155 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
156 PR_ExecuteProgram (ent->v.think, "NULL think function");
164 Two entities have touched, so run their touch functions
167 void SV_Impact (edict_t *e1, edict_t *e2)
169 int old_self, old_other;
171 old_self = pr_global_struct->self;
172 old_other = pr_global_struct->other;
174 pr_global_struct->time = sv.time;
175 if (e1->v.touch && e1->v.solid != SOLID_NOT)
177 pr_global_struct->self = EDICT_TO_PROG(e1);
178 pr_global_struct->other = EDICT_TO_PROG(e2);
179 PR_ExecuteProgram (e1->v.touch, "");
182 if (e2->v.touch && e2->v.solid != SOLID_NOT)
184 pr_global_struct->self = EDICT_TO_PROG(e2);
185 pr_global_struct->other = EDICT_TO_PROG(e1);
186 PR_ExecuteProgram (e2->v.touch, "");
189 pr_global_struct->self = old_self;
190 pr_global_struct->other = old_other;
198 Slide off of the impacting object
199 returns the blocked flags (1 = floor, 2 = step / wall)
202 #define STOP_EPSILON 0.1
204 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
212 blocked |= 1; // floor
214 blocked |= 2; // step
216 backoff = DotProduct (in, normal) * overbounce;
218 for (i=0 ; i<3 ; i++)
220 change = normal[i]*backoff;
221 out[i] = in[i] - change;
222 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
234 The basic solid body movement clip that slides along multiple planes
235 Returns the clipflags if the velocity was modified (hit something solid)
239 If steptrace is not NULL, the trace of any vertical wall hit will be stored
242 // LordHavoc: increased from 5 to 20
243 #define MAX_CLIP_PLANES 20
244 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
246 int bumpcount, numbumps;
250 vec3_t planes[MAX_CLIP_PLANES];
251 vec3_t primal_velocity, original_velocity, new_velocity;
261 VectorCopy (ent->v.velocity, original_velocity);
262 VectorCopy (ent->v.velocity, primal_velocity);
267 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
269 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
272 for (i=0 ; i<3 ; i++)
273 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
275 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
279 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
280 // entity is trapped in another solid
281 VectorClear(ent->v.velocity);
285 if (trace.fraction > 0)
286 { // actually covered some distance
287 VectorCopy (trace.endpos, ent->v.origin);
288 VectorCopy (ent->v.velocity, original_velocity);
292 if (trace.fraction == 1)
293 break; // moved the entire distance
296 Host_Error ("SV_FlyMove: !trace.ent");
298 if ((int) ent->v.flags & FL_ONGROUND)
300 if (ent->v.groundentity == EDICT_TO_PROG(trace.ent))
304 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
311 if (trace.plane.normal[2] > 0.7)
313 blocked |= 1; // floor
314 //if (trace.ent->v.solid == SOLID_BSP)
316 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
317 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
320 if (!trace.plane.normal[2])
322 blocked |= 2; // step
324 *steptrace = trace; // save for player extrafriction
328 // run the impact function
331 SV_Impact (ent, trace.ent);
333 break; // removed by the impact function
336 time_left -= time_left * trace.fraction;
338 // cliped to another plane
339 if (numplanes >= MAX_CLIP_PLANES)
340 { // this shouldn't really happen
341 VectorClear(ent->v.velocity);
345 VectorCopy (trace.plane.normal, planes[numplanes]);
349 // modify original_velocity so it parallels all of the clip planes
351 for (i=0 ; i<numplanes ; i++)
353 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
354 for (j=0 ; j<numplanes ; j++)
357 if (DotProduct (new_velocity, planes[j]) < 0)
365 { // go along this plane
366 VectorCopy (new_velocity, ent->v.velocity);
369 { // go along the crease
372 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
373 VectorClear(ent->v.velocity);
376 CrossProduct (planes[0], planes[1], dir);
377 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
378 VectorNormalize(dir);
379 d = DotProduct (dir, ent->v.velocity);
380 VectorScale (dir, d, ent->v.velocity);
384 // if original velocity is against the original velocity, stop dead
385 // to avoid tiny occilations in sloping corners
387 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
389 VectorClear(ent->v.velocity);
404 void SV_AddGravity (edict_t *ent)
410 val = GETEDICTFIELDVALUE(ent, eval_gravity);
411 if (val!=0 && val->_float)
412 ent_gravity = val->_float;
415 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
420 ===============================================================================
424 ===============================================================================
431 Does not change the entities velocity at all
434 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
439 VectorAdd (ent->v.origin, push, end);
441 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
442 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
443 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
444 // only clip against bmodels
445 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
447 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
449 VectorCopy (trace.endpos, ent->v.origin);
450 // FIXME: turn players specially
451 ent->v.angles[1] += trace.fraction * pushangles[1];
452 SV_LinkEdict (ent, true);
454 if (trace.ent && (!((int)ent->v.flags & FL_ONGROUND) || ent->v.groundentity != EDICT_TO_PROG(trace.ent)))
455 SV_Impact (ent, trace.ent);
466 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
467 void SV_PushMove (edict_t *pusher, float movetime)
471 float savesolid, movetime2, pushltime;
472 vec3_t mins, maxs, move, move1, moveangle, /*entorig, entang, */pushorig, pushang, a, forward, left, up, org, org2;
474 edict_t *moved_edict[MAX_EDICTS];
475 vec3_t moved_from[MAX_EDICTS], moved_fromangles[MAX_EDICTS];
476 model_t *pushermodel;
479 switch ((int) pusher->v.solid)
481 // LordHavoc: valid pusher types
485 case SOLID_CORPSE: // LordHavoc: this would be weird...
487 // LordHavoc: no collisions
490 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
491 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
492 pusher->v.ltime += movetime;
493 SV_LinkEdict (pusher, false);
496 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v.solid);
498 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])
500 pusher->v.ltime += movetime;
503 index = (int) pusher->v.modelindex;
504 if (index < 1 || index >= MAX_MODELS)
505 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v.modelindex);
506 pushermodel = sv.models[index];
508 // LordHavoc: round up by a small epsilon
509 movetime2 = movetime; // + (1.0 / 256.0);
510 VectorScale(pusher->v.velocity, movetime2, move1);
511 VectorScale(pusher->v.avelocity, movetime2, moveangle);
512 if (moveangle[0] || moveangle[2])
514 for (i = 0;i < 3;i++)
518 mins[i] = pushermodel->rotatedmins[i] + pusher->v.origin[i] - 1;
519 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
523 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v.origin[i] - 1;
524 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v.origin[i] + 1;
528 else if (moveangle[1])
530 for (i = 0;i < 3;i++)
534 mins[i] = pushermodel->yawmins[i] + pusher->v.origin[i] - 1;
535 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
539 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v.origin[i] - 1;
540 maxs[i] = pushermodel->yawmaxs[i] + pusher->v.origin[i] + 1;
546 for (i = 0;i < 3;i++)
550 mins[i] = pushermodel->normalmins[i] + pusher->v.origin[i] - 1;
551 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v.origin[i] + 1;
555 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v.origin[i] - 1;
556 maxs[i] = pushermodel->normalmaxs[i] + pusher->v.origin[i] + 1;
561 VectorNegate (moveangle, a);
562 AngleVectorsFLU (a, forward, left, up);
564 VectorCopy (pusher->v.origin, pushorig);
565 VectorCopy (pusher->v.angles, pushang);
566 pushltime = pusher->v.ltime;
568 // move the pusher to it's final position
570 VectorMA (pusher->v.origin, movetime, pusher->v.velocity, pusher->v.origin);
571 VectorMA (pusher->v.angles, movetime, pusher->v.avelocity, pusher->v.angles);
572 pusher->v.ltime += movetime;
573 SV_LinkEdict (pusher, false);
575 savesolid = pusher->v.solid;
577 // see if any solid entities are inside the final position
579 check = NEXT_EDICT(sv.edicts);
580 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
584 if (check->v.movetype == MOVETYPE_PUSH
585 || check->v.movetype == MOVETYPE_NONE
586 || check->v.movetype == MOVETYPE_FOLLOW
587 || check->v.movetype == MOVETYPE_NOCLIP)
590 // if the entity is standing on the pusher, it will definitely be moved
591 if (!(((int)check->v.flags & FL_ONGROUND) && PROG_TO_EDICT(check->v.groundentity) == pusher))
593 if (check->v.absmin[0] >= maxs[0]
594 || check->v.absmax[0] <= mins[0]
595 || check->v.absmin[1] >= maxs[1]
596 || check->v.absmax[1] <= mins[1]
597 || check->v.absmin[2] >= maxs[2]
598 || check->v.absmax[2] <= mins[2])
602 if (forward[0] < 0.999f) // quick way to check if any rotation is used
604 VectorSubtract (check->v.origin, pusher->v.origin, org);
605 org2[0] = DotProduct (org, forward);
606 org2[1] = DotProduct (org, left);
607 org2[2] = DotProduct (org, up);
608 //VectorSubtract (org2, org, move);
609 //VectorAdd (move, move1, move);
610 //VectorSubtract(check->v.origin, move, a);
611 a[0] = check->v.origin[0] + (org[0] - org2[0]) - move1[0];
612 a[1] = check->v.origin[1] + (org[1] - org2[1]) - move1[1];
613 a[2] = check->v.origin[2] + (org[2] - org2[2]) - move1[2];
616 VectorSubtract (check->v.origin, move1, a);
618 trace = SV_ClipMoveToEntity (pusher, a, check->v.mins, check->v.maxs, check->v.origin);
619 if (trace.fraction == 1 && !trace.startsolid)
622 trace = SV_ClipMoveToEntity (pusher, check->v.origin, check->v.mins, check->v.maxs, check->v.origin);
623 if (!trace.startsolid)
626 // see if the ent's bbox is inside the pusher's final position
627 if (!SV_TestEntityPosition (check))
632 if (forward[0] < 0.999f) // quick way to check if any rotation is used
634 VectorSubtract (check->v.origin, pusher->v.origin, org);
635 org2[0] = DotProduct (org, forward);
636 org2[1] = DotProduct (org, left);
637 org2[2] = DotProduct (org, up);
638 VectorSubtract (org2, org, move);
639 VectorAdd (move, move1, move);
642 VectorCopy (move1, move);
644 // LordHavoc: debugging
645 //VectorAdd(entorig, move, org2);
646 //CL_RocketTrail2 (entorig, org2, 238, NULL);
648 // remove the onground flag for non-players
649 if (check->v.movetype != MOVETYPE_WALK)
650 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
652 //VectorCopy (check->v.origin, entorig);
653 //VectorCopy (check->v.angles, entang);
654 VectorCopy (check->v.origin, moved_from[num_moved]);
655 VectorCopy (check->v.angles, moved_fromangles[num_moved]);
656 moved_edict[num_moved++] = check;
658 // try moving the contacted entity
659 pusher->v.solid = SOLID_NOT;
660 trace = SV_PushEntity (check, move, moveangle);
661 pusher->v.solid = savesolid; // was SOLID_BSP
663 // if it is still inside the pusher, block
664 // LordHavoc: cleanup - check trace.fraction and startsolid
665 if (/*trace.fraction != 1 || trace.startsolid || */SV_TestEntityPosition (check))
668 if (check->v.mins[0] == check->v.maxs[0])
670 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
673 check->v.mins[0] = check->v.mins[1] = 0;
674 VectorCopy (check->v.mins, check->v.maxs);
679 VectorCopy (entorig, check->v.origin);
680 VectorCopy (entang, check->v.angles);
681 SV_LinkEdict (check, true);
684 VectorCopy (pushorig, pusher->v.origin);
685 VectorCopy (pushang, pusher->v.angles);
686 pusher->v.ltime = pushltime;
687 SV_LinkEdict (pusher, false);
689 // move back any entities we already moved
690 //num_moved--; // LordHavoc: pop off check, because it was already restored
691 for (i=0 ; i<num_moved ; i++)
693 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
694 VectorCopy (moved_fromangles[i], moved_edict[i]->v.angles);
695 SV_LinkEdict (moved_edict[i], false);
698 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
699 if (pusher->v.blocked)
701 pr_global_struct->self = EDICT_TO_PROG(pusher);
702 pr_global_struct->other = EDICT_TO_PROG(check);
703 PR_ExecuteProgram (pusher->v.blocked, "");
716 void SV_Physics_Pusher (edict_t *ent)
722 oldltime = ent->v.ltime;
724 thinktime = ent->v.nextthink;
725 if (thinktime < ent->v.ltime + sv.frametime)
727 movetime = thinktime - ent->v.ltime;
732 movetime = sv.frametime;
735 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
737 if (thinktime > oldltime && thinktime <= ent->v.ltime)
739 ent->v.nextthink = 0;
740 pr_global_struct->time = sv.time;
741 pr_global_struct->self = EDICT_TO_PROG(ent);
742 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
743 PR_ExecuteProgram (ent->v.think, "NULL think function");
752 ===============================================================================
756 ===============================================================================
763 This is a big hack to try and fix the rare case of getting stuck in the world
767 void SV_CheckStuck (edict_t *ent)
773 if (!SV_TestEntityPosition(ent))
775 VectorCopy (ent->v.origin, ent->v.oldorigin);
779 VectorCopy (ent->v.origin, org);
780 VectorCopy (ent->v.oldorigin, ent->v.origin);
781 if (!SV_TestEntityPosition(ent))
783 Con_DPrintf ("Unstuck.\n");
784 SV_LinkEdict (ent, true);
788 for (z=0 ; z< 18 ; z++)
789 for (i=-1 ; i <= 1 ; i++)
790 for (j=-1 ; j <= 1 ; j++)
792 ent->v.origin[0] = org[0] + i;
793 ent->v.origin[1] = org[1] + j;
794 ent->v.origin[2] = org[2] + z;
795 if (!SV_TestEntityPosition(ent))
797 Con_DPrintf ("Unstuck.\n");
798 SV_LinkEdict (ent, true);
803 VectorCopy (org, ent->v.origin);
804 Con_DPrintf ("player is stuck.\n");
813 qboolean SV_CheckWater (edict_t *ent)
818 point[0] = ent->v.origin[0];
819 point[1] = ent->v.origin[1];
820 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
822 ent->v.waterlevel = 0;
823 ent->v.watertype = CONTENTS_EMPTY;
824 cont = SV_PointContents (point);
825 if (cont <= CONTENTS_WATER)
827 ent->v.watertype = cont;
828 ent->v.waterlevel = 1;
829 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
830 cont = SV_PointContents (point);
831 if (cont <= CONTENTS_WATER)
833 ent->v.waterlevel = 2;
834 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
835 cont = SV_PointContents (point);
836 if (cont <= CONTENTS_WATER)
837 ent->v.waterlevel = 3;
841 return ent->v.waterlevel > 1;
850 void SV_WallFriction (edict_t *ent, trace_t *trace)
856 AngleVectors (ent->v.v_angle, forward, NULL, NULL);
857 d = DotProduct (trace->plane.normal, forward);
863 // cut the tangential velocity
864 i = DotProduct (trace->plane.normal, ent->v.velocity);
865 VectorScale (trace->plane.normal, i, into);
866 VectorSubtract (ent->v.velocity, into, side);
868 ent->v.velocity[0] = side[0] * (1 + d);
869 ent->v.velocity[1] = side[1] * (1 + d);
873 =====================
876 Player has come to a dead stop, possibly due to the problem with limited
877 float precision at some angle joins in the BSP hull.
879 Try fixing by pushing one pixel in each direction.
881 This is a hack, but in the interest of good gameplay...
882 ======================
884 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
892 VectorCopy (ent->v.origin, oldorg);
895 for (i=0 ; i<8 ; i++)
897 // try pushing a little in an axial direction
900 case 0: dir[0] = 2; dir[1] = 0; break;
901 case 1: dir[0] = 0; dir[1] = 2; break;
902 case 2: dir[0] = -2; dir[1] = 0; break;
903 case 3: dir[0] = 0; dir[1] = -2; break;
904 case 4: dir[0] = 2; dir[1] = 2; break;
905 case 5: dir[0] = -2; dir[1] = 2; break;
906 case 6: dir[0] = 2; dir[1] = -2; break;
907 case 7: dir[0] = -2; dir[1] = -2; break;
910 SV_PushEntity (ent, dir, vec3_origin);
912 // retry the original move
913 ent->v.velocity[0] = oldvel[0];
914 ent->v.velocity[1] = oldvel[1];
915 ent->v.velocity[2] = 0;
916 clip = SV_FlyMove (ent, 0.1, &steptrace);
918 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
919 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
921 //Con_DPrintf ("unstuck!\n");
925 // go back to the original pos and try again
926 VectorCopy (oldorg, ent->v.origin);
929 VectorClear (ent->v.velocity);
930 return 7; // still not moving
934 =====================
938 ======================
940 void SV_WalkMove (edict_t *ent)
942 vec3_t upmove, downmove;
943 vec3_t oldorg, oldvel;
944 vec3_t nosteporg, nostepvel;
947 trace_t steptrace, downtrace;
950 // do a regular slide move unless it looks like you ran into a step
952 oldonground = (int)ent->v.flags & FL_ONGROUND;
953 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
955 VectorCopy (ent->v.origin, oldorg);
956 VectorCopy (ent->v.velocity, oldvel);
958 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
961 return; // move didn't block on a step
963 if (!oldonground && ent->v.waterlevel == 0)
964 return; // don't stair up while jumping
966 if (ent->v.movetype != MOVETYPE_WALK)
967 return; // gibbed by a trigger
969 if (sv_nostep.integer)
972 if ( (int)sv_player->v.flags & FL_WATERJUMP )
975 VectorCopy (ent->v.origin, nosteporg);
976 VectorCopy (ent->v.velocity, nostepvel);
979 // try moving up and forward to go up a step
981 VectorCopy (oldorg, ent->v.origin); // back to start pos
983 VectorClear (upmove);
984 VectorClear (downmove);
985 upmove[2] = sv_stepheight.value;
986 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
989 SV_PushEntity (ent, upmove, vec3_origin); // FIXME: don't link?
992 ent->v.velocity[0] = oldvel[0];
993 ent->v. velocity[1] = oldvel[1];
994 ent->v. velocity[2] = 0;
995 clip = SV_FlyMove (ent, sv.frametime, &steptrace);
997 // check for stuckness, possibly due to the limited precision of floats
998 // in the clipping hulls
1001 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1002 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1003 { // stepping up didn't make any progress
1004 clip = SV_TryUnstick (ent, oldvel);
1008 // extra friction based on view angle
1010 SV_WallFriction (ent, &steptrace);
1013 downtrace = SV_PushEntity (ent, downmove, vec3_origin); // FIXME: don't link?
1015 if (downtrace.plane.normal[2] > 0.7)
1017 if (ent->v.solid == SOLID_BSP)
1019 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1020 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1025 // if the push down didn't end up on good ground, use the move without
1026 // the step up. This happens near wall / slope combinations, and can
1027 // cause the player to hop up higher on a slope too steep to climb
1028 VectorCopy (nosteporg, ent->v.origin);
1029 VectorCopy (nostepvel, ent->v.velocity);
1038 Player character actions
1041 void SV_Physics_Client (edict_t *ent, int num)
1043 if ( ! svs.clients[num-1].active )
1044 return; // unconnected slot
1047 // call standard client pre-think
1049 pr_global_struct->time = sv.time;
1050 pr_global_struct->self = EDICT_TO_PROG(ent);
1051 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1056 SV_CheckVelocity (ent);
1059 // decide which move function to call
1061 switch ((int)ent->v.movetype)
1064 if (!SV_RunThink (ent))
1069 if (!SV_RunThink (ent))
1071 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1072 SV_AddGravity (ent);
1073 SV_CheckStuck (ent);
1078 case MOVETYPE_BOUNCE:
1079 SV_Physics_Toss (ent);
1083 if (!SV_RunThink (ent))
1085 SV_CheckWater (ent);
1086 SV_FlyMove (ent, sv.frametime, NULL);
1089 case MOVETYPE_NOCLIP:
1090 if (!SV_RunThink (ent))
1092 SV_CheckWater (ent);
1093 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1097 Host_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1101 // call standard player post-think
1103 SV_LinkEdict (ent, true);
1105 pr_global_struct->time = sv.time;
1106 pr_global_struct->self = EDICT_TO_PROG(ent);
1107 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1110 //============================================================================
1116 Non moving objects can only think
1119 // LordHavoc: inlined manually because it was a real time waster
1121 void SV_Physics_None (edict_t *ent)
1132 Entities that are "stuck" to another entity
1135 void SV_Physics_Follow (edict_t *ent)
1137 vec3_t vf, vr, vu, angles, v;
1140 if (!SV_RunThink (ent))
1142 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1143 e = PROG_TO_EDICT(ent->v.aiment);
1144 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])
1146 // quick case for no rotation
1147 VectorAdd(e->v.origin, ent->v.view_ofs, ent->v.origin);
1151 angles[0] = -ent->v.punchangle[0];
1152 angles[1] = ent->v.punchangle[1];
1153 angles[2] = ent->v.punchangle[2];
1154 AngleVectors (angles, vf, vr, vu);
1155 v[0] = ent->v.view_ofs[0] * vf[0] + ent->v.view_ofs[1] * vr[0] + ent->v.view_ofs[2] * vu[0];
1156 v[1] = ent->v.view_ofs[0] * vf[1] + ent->v.view_ofs[1] * vr[1] + ent->v.view_ofs[2] * vu[1];
1157 v[2] = ent->v.view_ofs[0] * vf[2] + ent->v.view_ofs[1] * vr[2] + ent->v.view_ofs[2] * vu[2];
1158 angles[0] = -e->v.angles[0];
1159 angles[1] = e->v.angles[1];
1160 angles[2] = e->v.angles[2];
1161 AngleVectors (angles, vf, vr, vu);
1162 ent->v.origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v.origin[0];
1163 ent->v.origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v.origin[1];
1164 ent->v.origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v.origin[2];
1166 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];
1167 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];
1168 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];
1171 VectorAdd (e->v.angles, ent->v.v_angle, ent->v.angles);
1172 // VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1173 SV_LinkEdict (ent, true);
1180 A moving object that doesn't obey physics
1183 void SV_Physics_Noclip (edict_t *ent)
1186 if (!SV_RunThink (ent))
1189 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1190 VectorMA (ent->v.origin, sv.frametime, ent->v.velocity, ent->v.origin);
1192 SV_LinkEdict (ent, false);
1196 ==============================================================================
1200 ==============================================================================
1205 SV_CheckWaterTransition
1209 void SV_CheckWaterTransition (edict_t *ent)
1212 cont = SV_PointContents (ent->v.origin);
1213 if (!ent->v.watertype)
1214 { // just spawned here
1215 ent->v.watertype = cont;
1216 ent->v.waterlevel = 1;
1220 if (cont <= CONTENTS_WATER)
1222 if (ent->v.watertype == CONTENTS_EMPTY)
1223 { // just crossed into water
1224 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1226 ent->v.watertype = cont;
1227 ent->v.waterlevel = 1;
1231 if (ent->v.watertype != CONTENTS_EMPTY)
1232 { // just crossed into water
1233 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1235 ent->v.watertype = CONTENTS_EMPTY;
1236 ent->v.waterlevel = cont;
1244 Toss, bounce, and fly movement. When onground, do nothing.
1247 void SV_Physics_Toss (edict_t *ent)
1251 edict_t *groundentity;
1252 //edict_t *groundentity;
1254 if (!SV_RunThink (ent))
1257 // if onground, return without moving
1258 if ((int)ent->v.flags & FL_ONGROUND)
1260 if (ent->v.groundentity == 0)
1262 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1263 if (groundentity != NULL && groundentity->v.solid == SOLID_BSP)
1264 ent->suspendedinairflag = true;
1265 else if (ent->suspendedinairflag && (groundentity == NULL || groundentity->free))
1267 // leave it suspended in the air
1268 ent->v.groundentity = 0;
1269 ent->suspendedinairflag = false;
1273 ent->suspendedinairflag = false;
1276 if ( ((int)ent->v.flags & FL_ONGROUND) )
1278 // LordHavoc: fall if the groundentity was removed
1279 if (ent->v.groundentity)
1281 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1282 if (groundentity && groundentity->v.solid != SOLID_NOT && groundentity->v.solid != SOLID_TRIGGER)
1288 SV_CheckVelocity (ent);
1291 if (ent->v.movetype != MOVETYPE_FLY
1292 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE // LordHavoc: enabled MOVETYPE_BOUNCEMISSILE
1293 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1294 SV_AddGravity (ent);
1297 VectorMA (ent->v.angles, sv.frametime, ent->v.avelocity, ent->v.angles);
1300 VectorScale (ent->v.velocity, sv.frametime, move);
1301 trace = SV_PushEntity (ent, move, vec3_origin);
1304 if (trace.fraction == 1)
1307 if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1309 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 2.0);
1310 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1312 else if (ent->v.movetype == MOVETYPE_BOUNCE)
1314 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.5);
1315 // LordHavoc: fixed grenades not bouncing when fired down a slope
1316 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v.velocity) < 60)
1317 //if (trace.plane.normal[2] > 0.7 && ent->v.velocity[2] < 60)
1319 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1320 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1321 VectorClear (ent->v.velocity);
1322 VectorClear (ent->v.avelocity);
1325 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1329 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, 1.0);
1330 if (trace.plane.normal[2] > 0.7)
1332 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1333 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1334 VectorClear (ent->v.velocity);
1335 VectorClear (ent->v.avelocity);
1338 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1341 // check for in water
1342 SV_CheckWaterTransition (ent);
1346 ===============================================================================
1350 ===============================================================================
1357 Monsters freefall when they don't have a ground entity, otherwise
1358 all movement is done with discrete steps.
1360 This is also used for objects that have become still on the ground, but
1361 will fall if the floor is pulled out from under them.
1364 void SV_Physics_Step (edict_t *ent)
1366 int flags, fall, hitsound;
1368 // freefall if not fly/swim
1370 flags = (int)ent->v.flags;
1371 if (flags & (FL_FLY | FL_SWIM))
1375 else if ((flags & FL_SWIM) && SV_PointContents(ent->v.origin) != CONTENTS_EMPTY)
1378 if (fall && (flags & FL_ONGROUND) && ent->v.groundentity == 0)
1383 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1386 if (flags & FL_ONGROUND)
1392 SV_AddGravity (ent);
1393 SV_CheckVelocity (ent);
1394 SV_FlyMove (ent, sv.frametime, NULL);
1395 SV_LinkEdict (ent, false);
1398 if ((int)ent->v.flags & FL_ONGROUND)
1400 VectorClear(ent->v.velocity);
1402 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1409 SV_CheckWaterTransition (ent);
1412 //============================================================================
1420 void SV_Physics (void)
1425 // let the progs know that a new frame has started
1426 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1427 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1428 pr_global_struct->time = sv.time;
1429 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1431 //SV_CheckAllEnts ();
1434 // treat each object in turn
1437 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1442 if (pr_global_struct->force_retouch)
1443 SV_LinkEdict (ent, true); // force retouch even for stationary
1445 if (i > 0 && i <= svs.maxclients)
1447 SV_Physics_Client (ent, i);
1451 switch ((int) ent->v.movetype)
1454 SV_Physics_Pusher (ent);
1457 // SV_Physics_None (ent);
1458 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1459 if (ent->v.nextthink > 0 && ent->v.nextthink <= sv.time + sv.frametime)
1462 case MOVETYPE_FOLLOW:
1463 SV_Physics_Follow (ent);
1465 case MOVETYPE_NOCLIP:
1466 SV_Physics_Noclip (ent);
1469 SV_Physics_Step (ent);
1471 // LordHavoc: added support for MOVETYPE_WALK on normal entities! :)
1473 if (SV_RunThink (ent))
1475 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1476 SV_AddGravity (ent);
1477 SV_CheckStuck (ent);
1479 SV_LinkEdict (ent, true);
1483 case MOVETYPE_BOUNCE:
1484 case MOVETYPE_BOUNCEMISSILE:
1486 case MOVETYPE_FLYMISSILE:
1487 SV_Physics_Toss (ent);
1490 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1495 if (pr_global_struct->force_retouch)
1496 pr_global_struct->force_retouch--;
1498 // LordHavoc: endframe support
1501 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1502 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1503 pr_global_struct->time = sv.time;
1504 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1507 sv.time += sv.frametime;
1511 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1514 edict_t tempent, *tent;
1518 float gravity, savesolid;
1521 memcpy(&tempent, tossent, sizeof(edict_t));
1523 savesolid = tossent->v.solid;
1524 tossent->v.solid = SOLID_NOT;
1526 // this has to fetch the field from the original edict, since our copy is truncated
1527 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1528 if (val != NULL && val->_float != 0)
1529 gravity = val->_float;
1532 gravity *= sv_gravity.value * 0.05;
1534 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1536 SV_CheckVelocity (tent);
1537 tent->v.velocity[2] -= gravity;
1538 VectorMA (tent->v.angles, 0.05, tent->v.avelocity, tent->v.angles);
1539 VectorScale (tent->v.velocity, 0.05, move);
1540 VectorAdd (tent->v.origin, move, end);
1541 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1542 VectorCopy (trace.endpos, tent->v.origin);
1544 if (trace.fraction < 1 && trace.ent)
1545 if (trace.ent != ignore)
1548 tossent->v.solid = savesolid;
1549 trace.fraction = 0; // not relevant