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 = {CVAR_NOTIFY, "sv_stopspeed","100"};
44 cvar_t sv_gravity = {CVAR_NOTIFY, "sv_gravity","800"};
45 cvar_t sv_maxvelocity = {CVAR_NOTIFY, "sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {CVAR_NOTIFY, "sv_nostep","0"};
47 cvar_t sv_stepheight = {CVAR_NOTIFY, "sv_stepheight", "18"};
48 cvar_t sv_jumpstep = {CVAR_NOTIFY, "sv_jumpstep", "1"};
49 cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1"};
50 cvar_t sv_newflymove = {CVAR_NOTIFY, "sv_newflymove", "1"};
51 cvar_t sv_freezenonclients = {CVAR_NOTIFY, "sv_freezenonclients", "0"};
53 #define MOVE_EPSILON 0.01
55 void SV_Physics_Toss (edict_t *ent);
57 void SV_Phys_Init (void)
59 Cvar_RegisterVariable(&sv_stepheight);
60 Cvar_RegisterVariable(&sv_jumpstep);
61 Cvar_RegisterVariable(&sv_wallfriction);
62 Cvar_RegisterVariable(&sv_newflymove);
63 Cvar_RegisterVariable(&sv_freezenonclients);
71 void SV_CheckAllEnts (void)
76 // see if any solid entities are inside the final position
77 check = NEXT_EDICT(sv.edicts);
78 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
82 if (check->v->movetype == MOVETYPE_PUSH
83 || check->v->movetype == MOVETYPE_NONE
84 || check->v->movetype == MOVETYPE_FOLLOW
85 || check->v->movetype == MOVETYPE_NOCLIP)
88 if (SV_TestEntityPosition (check))
89 Con_Printf ("entity in invalid position\n");
98 void SV_CheckVelocity (edict_t *ent)
106 for (i=0 ; i<3 ; i++)
108 if (IS_NAN(ent->v->velocity[i]))
110 Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname));
111 ent->v->velocity[i] = 0;
113 if (IS_NAN(ent->v->origin[i]))
115 Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v->classname));
116 ent->v->origin[i] = 0;
120 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
121 wishspeed = DotProduct(ent->v->velocity, ent->v->velocity);
122 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
124 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
125 ent->v->velocity[0] *= wishspeed;
126 ent->v->velocity[1] *= wishspeed;
127 ent->v->velocity[2] *= wishspeed;
135 Runs thinking code if time. There is some play in the exact time the think
136 function will be called, because it is called before any movement is done
137 in a frame. Not used for pushmove objects, because they must be exact.
138 Returns false if the entity removed itself.
141 qboolean SV_RunThink (edict_t *ent)
145 thinktime = ent->v->nextthink;
146 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
149 // don't let things stay in the past.
150 // it is possible to start that way by a trigger with a local time.
151 if (thinktime < sv.time)
154 ent->v->nextthink = 0;
155 pr_global_struct->time = thinktime;
156 pr_global_struct->self = EDICT_TO_PROG(ent);
157 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
158 PR_ExecuteProgram (ent->v->think, "NULL think function");
159 return !ent->e->free;
166 Two entities have touched, so run their touch functions
169 void SV_Impact (edict_t *e1, edict_t *e2)
171 int old_self, old_other;
173 old_self = pr_global_struct->self;
174 old_other = pr_global_struct->other;
176 pr_global_struct->time = sv.time;
177 if (e1->v->touch && e1->v->solid != SOLID_NOT)
179 pr_global_struct->self = EDICT_TO_PROG(e1);
180 pr_global_struct->other = EDICT_TO_PROG(e2);
181 PR_ExecuteProgram (e1->v->touch, "");
184 if (e2->v->touch && e2->v->solid != SOLID_NOT)
186 pr_global_struct->self = EDICT_TO_PROG(e2);
187 pr_global_struct->other = EDICT_TO_PROG(e1);
188 PR_ExecuteProgram (e2->v->touch, "");
191 pr_global_struct->self = old_self;
192 pr_global_struct->other = old_other;
200 Slide off of the impacting object
201 returns the blocked flags (1 = floor, 2 = step / wall)
204 #define STOP_EPSILON 0.1
205 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
210 backoff = -DotProduct (in, normal) * overbounce;
211 VectorMA(in, backoff, normal, out);
213 for (i = 0;i < 3;i++)
214 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
223 The basic solid body movement clip that slides along multiple planes
224 Returns the clipflags if the velocity was modified (hit something solid)
228 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
231 // LordHavoc: increased from 5 to 20
232 #define MAX_CLIP_PLANES 20
233 int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
235 int blocked, bumpcount;
236 edict_t *hackongroundentity;
237 hackongroundentity = NULL;
238 if (sv_newflymove.integer)
241 vec3_t end, primal_velocity;
245 VectorCopy (ent->v->velocity, primal_velocity);
247 for (bumpcount = 0;bumpcount < 8;bumpcount++)
249 //Con_Printf("entity %i bump %i: blocked %i velocity %f %f %f\n", ent - sv.edicts, bumpcount, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]);
250 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
253 VectorMA(ent->v->origin, time, ent->v->velocity, end);
254 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
255 //Con_Printf("trace %f %f %f : %f : %f %f %f\n", trace.endpos[0], trace.endpos[1], trace.endpos[2], trace.fraction, trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
258 if (trace.startsolid)
260 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
261 // entity is trapped in another solid
262 VectorClear(ent->v->velocity);
267 if (trace.fraction >= 0.001)
269 // actually covered some distance
270 VectorCopy (trace.endpos, ent->v->origin);
273 // break if it moved the entire distance
274 if (trace.fraction == 1)
278 Host_Error ("SV_FlyMove: !trace.ent");
280 if ((int) ent->v->flags & FL_ONGROUND)
282 if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
286 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
293 if (trace.plane.normal[2])
295 if (trace.plane.normal[2] > 0.7)
299 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
300 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
302 else if (trace.fraction < 0.001)
303 hackongroundentity = trace.ent;
309 // save the trace for player extrafriction
311 VectorCopy(trace.plane.normal, stepnormal);
314 // run the impact function
317 SV_Impact (ent, trace.ent);
319 // break if removed by the impact function
324 time *= 1 - trace.fraction;
326 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1);
328 // if original velocity is against the original velocity,
329 // stop dead to avoid tiny occilations in sloping corners
330 if (DotProduct (ent->v->velocity, primal_velocity) < 0)
332 VectorClear(ent->v->velocity);
339 int i, j, impact, numplanes;
341 vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
345 VectorCopy (ent->v->velocity, original_velocity);
346 VectorCopy (ent->v->velocity, primal_velocity);
351 for (bumpcount = 0;bumpcount < 8;bumpcount++)
353 //Con_Printf("entity %i bump %i: blocked %i velocity %f %f %f\n", ent - sv.edicts, bumpcount, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]);
354 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
357 for (i=0 ; i<3 ; i++)
358 end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i];
360 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
363 if (trace.startsolid)
365 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
366 // entity is trapped in another solid
367 VectorClear(ent->v->velocity);
372 if (trace.fraction > 0)
374 // actually covered some distance
375 VectorCopy (trace.endpos, ent->v->origin);
376 VectorCopy (ent->v->velocity, original_velocity);
380 // break if it moved the entire distance
381 if (trace.fraction == 1)
385 Host_Error ("SV_FlyMove: !trace.ent");
387 if ((int) ent->v->flags & FL_ONGROUND)
389 if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
393 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
400 if (trace.plane.normal[2])
402 if (trace.plane.normal[2] > 0.7)
406 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
407 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
409 else if (trace.fraction < 0.001)
410 hackongroundentity = trace.ent;
416 // save the trace for player extrafriction
418 VectorCopy(trace.plane.normal, stepnormal);
421 // run the impact function
424 SV_Impact (ent, trace.ent);
426 // break if removed by the impact function
432 time_left -= time_left * trace.fraction;
434 // clipped to another plane
435 if (numplanes >= MAX_CLIP_PLANES)
437 // this shouldn't really happen
438 VectorClear(ent->v->velocity);
443 VectorCopy (trace.plane.normal, planes[numplanes]);
446 // modify original_velocity so it parallels all of the clip planes
447 for (i=0 ; i<numplanes ; i++)
449 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
450 for (j=0 ; j<numplanes ; j++)
454 if (DotProduct (new_velocity, planes[j]) < 0)
463 // go along this plane
464 VectorCopy (new_velocity, ent->v->velocity);
468 // go along the crease
471 VectorClear(ent->v->velocity);
475 CrossProduct (planes[0], planes[1], dir);
476 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
477 VectorNormalize(dir);
478 d = DotProduct (dir, ent->v->velocity);
479 VectorScale (dir, d, ent->v->velocity);
482 // if original velocity is against the original velocity,
483 // stop dead to avoid tiny occilations in sloping corners
484 if (DotProduct (ent->v->velocity, primal_velocity) <= 0)
486 VectorClear(ent->v->velocity);
492 //Con_Printf("entity %i final: blocked %i velocity %f %f %f\n", ent - sv.edicts, blocked, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2]);
495 // FIXME: this doesn't work well at all, find another solution
496 // if player is ontop of a non-onground floor and made no progress,
497 // set onground anyway (this tends to happen if standing in a wedge)
498 if (bumpcount == 8 && hackongroundentity)
501 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
502 ent->v->groundentity = EDICT_TO_PROG(hackongroundentity);
507 if ((blocked & 1) == 0 && bumpcount > 1)
509 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
510 // flag ONGROUND if there's ground under it
511 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
524 void SV_AddGravity (edict_t *ent)
529 val = GETEDICTFIELDVALUE(ent, eval_gravity);
530 if (val!=0 && val->_float)
531 ent_gravity = val->_float;
534 ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
539 ===============================================================================
543 ===============================================================================
550 Does not change the entities velocity at all
553 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
558 VectorAdd (ent->v->origin, push, end);
560 if (ent->v->movetype == MOVETYPE_FLYMISSILE)
561 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE, ent);
562 else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
563 // only clip against bmodels
564 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, ent);
566 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
568 VectorCopy (trace.endpos, ent->v->origin);
569 // FIXME: turn players specially
570 ent->v->angles[1] += trace.fraction * pushangles[1];
571 SV_LinkEdict (ent, true);
573 if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
574 SV_Impact (ent, trace.ent);
585 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
586 void SV_PushMove (edict_t *pusher, float movetime)
590 float savesolid, movetime2, pushltime;
591 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
593 model_t *pushermodel;
595 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])
597 pusher->v->ltime += movetime;
601 switch ((int) pusher->v->solid)
603 // LordHavoc: valid pusher types
607 case SOLID_CORPSE: // LordHavoc: this would be weird...
609 // LordHavoc: no collisions
612 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
613 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
614 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
615 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
616 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
617 pusher->v->ltime += movetime;
618 SV_LinkEdict (pusher, false);
621 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
623 index = (int) pusher->v->modelindex;
624 if (index < 1 || index >= MAX_MODELS)
625 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
626 pushermodel = sv.models[index];
628 movetime2 = movetime;
629 VectorScale(pusher->v->velocity, movetime2, move1);
630 VectorScale(pusher->v->avelocity, movetime2, moveangle);
631 if (moveangle[0] || moveangle[2])
633 for (i = 0;i < 3;i++)
637 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
638 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
642 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
643 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
647 else if (moveangle[1])
649 for (i = 0;i < 3;i++)
653 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
654 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
658 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
659 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
665 for (i = 0;i < 3;i++)
669 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
670 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
674 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
675 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
680 VectorNegate (moveangle, a);
681 AngleVectorsFLU (a, forward, left, up);
683 VectorCopy (pusher->v->origin, pushorig);
684 VectorCopy (pusher->v->angles, pushang);
685 pushltime = pusher->v->ltime;
687 // move the pusher to it's final position
689 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
690 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
691 pusher->v->ltime += movetime;
692 SV_LinkEdict (pusher, false);
694 savesolid = pusher->v->solid;
696 // see if any solid entities are inside the final position
698 check = NEXT_EDICT(sv.edicts);
699 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
703 if (check->v->movetype == MOVETYPE_PUSH
704 || check->v->movetype == MOVETYPE_NONE
705 || check->v->movetype == MOVETYPE_FOLLOW
706 || check->v->movetype == MOVETYPE_NOCLIP
707 || check->v->movetype == MOVETYPE_FAKEPUSH)
710 // if the entity is standing on the pusher, it will definitely be moved
711 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
713 if (check->v->absmin[0] >= maxs[0]
714 || check->v->absmax[0] <= mins[0]
715 || check->v->absmin[1] >= maxs[1]
716 || check->v->absmax[1] <= mins[1]
717 || check->v->absmin[2] >= maxs[2]
718 || check->v->absmax[2] <= mins[2])
721 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
725 if (forward[0] != 1) // quick way to check if any rotation is used
727 VectorSubtract (check->v->origin, pusher->v->origin, org);
728 org2[0] = DotProduct (org, forward);
729 org2[1] = DotProduct (org, left);
730 org2[2] = DotProduct (org, up);
731 VectorSubtract (org2, org, move);
732 VectorAdd (move, move1, move);
735 VectorCopy (move1, move);
737 // remove the onground flag for non-players
738 if (check->v->movetype != MOVETYPE_WALK)
739 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
741 VectorCopy (check->v->origin, check->e->moved_from);
742 VectorCopy (check->v->angles, check->e->moved_fromangles);
743 sv.moved_edicts[num_moved++] = check;
745 // try moving the contacted entity
746 pusher->v->solid = SOLID_NOT;
747 SV_PushEntity (check, move, moveangle);
748 pusher->v->solid = savesolid; // was SOLID_BSP
750 // if it is still inside the pusher, block
751 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
753 // try moving the contacted entity a tiny bit further to account for precision errors
754 pusher->v->solid = SOLID_NOT;
755 VectorScale(move, 0.1, move);
756 SV_PushEntity (check, move, vec3_origin);
757 pusher->v->solid = savesolid;
758 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
760 // still inside pusher, so it's really blocked
763 if (check->v->mins[0] == check->v->maxs[0])
765 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
768 check->v->mins[0] = check->v->mins[1] = 0;
769 VectorCopy (check->v->mins, check->v->maxs);
773 VectorCopy (pushorig, pusher->v->origin);
774 VectorCopy (pushang, pusher->v->angles);
775 pusher->v->ltime = pushltime;
776 SV_LinkEdict (pusher, false);
778 // move back any entities we already moved
779 for (i = 0;i < num_moved;i++)
781 ed = sv.moved_edicts[i];
782 VectorCopy (ed->e->moved_from, ed->v->origin);
783 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
784 SV_LinkEdict (ed, false);
787 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
788 if (pusher->v->blocked)
790 pr_global_struct->self = EDICT_TO_PROG(pusher);
791 pr_global_struct->other = EDICT_TO_PROG(check);
792 PR_ExecuteProgram (pusher->v->blocked, "");
798 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
799 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
800 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
809 void SV_Physics_Pusher (edict_t *ent)
811 float thinktime, oldltime, movetime;
813 oldltime = ent->v->ltime;
815 thinktime = ent->v->nextthink;
816 if (thinktime < ent->v->ltime + sv.frametime)
818 movetime = thinktime - ent->v->ltime;
823 movetime = sv.frametime;
826 // advances ent->v->ltime if not blocked
827 SV_PushMove (ent, movetime);
829 if (thinktime > oldltime && thinktime <= ent->v->ltime)
831 ent->v->nextthink = 0;
832 pr_global_struct->time = sv.time;
833 pr_global_struct->self = EDICT_TO_PROG(ent);
834 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
835 PR_ExecuteProgram (ent->v->think, "NULL think function");
841 ===============================================================================
845 ===============================================================================
852 This is a big hack to try and fix the rare case of getting stuck in the world
856 void SV_CheckStuck (edict_t *ent)
861 if (!SV_TestEntityPosition(ent))
863 VectorCopy (ent->v->origin, ent->v->oldorigin);
867 VectorCopy (ent->v->origin, org);
868 VectorCopy (ent->v->oldorigin, ent->v->origin);
869 if (!SV_TestEntityPosition(ent))
871 Con_DPrintf ("Unstuck.\n");
872 SV_LinkEdict (ent, true);
876 for (z=0 ; z< 18 ; z++)
877 for (i=-1 ; i <= 1 ; i++)
878 for (j=-1 ; j <= 1 ; j++)
880 ent->v->origin[0] = org[0] + i;
881 ent->v->origin[1] = org[1] + j;
882 ent->v->origin[2] = org[2] + z;
883 if (!SV_TestEntityPosition(ent))
885 Con_DPrintf ("Unstuck.\n");
886 SV_LinkEdict (ent, true);
891 VectorCopy (org, ent->v->origin);
892 Con_DPrintf ("player is stuck.\n");
901 qboolean SV_CheckWater (edict_t *ent)
906 point[0] = ent->v->origin[0];
907 point[1] = ent->v->origin[1];
908 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
910 ent->v->waterlevel = 0;
911 ent->v->watertype = CONTENTS_EMPTY;
912 cont = SV_PointQ1Contents(point);
913 if (cont <= CONTENTS_WATER)
915 ent->v->watertype = cont;
916 ent->v->waterlevel = 1;
917 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
918 cont = SV_PointQ1Contents(point);
919 if (cont <= CONTENTS_WATER)
921 ent->v->waterlevel = 2;
922 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
923 cont = SV_PointQ1Contents(point);
924 if (cont <= CONTENTS_WATER)
925 ent->v->waterlevel = 3;
929 return ent->v->waterlevel > 1;
938 void SV_WallFriction (edict_t *ent, float *stepnormal)
941 vec3_t forward, into, side;
943 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
944 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
946 // cut the tangential velocity
947 i = DotProduct (stepnormal, ent->v->velocity);
948 VectorScale (stepnormal, i, into);
949 VectorSubtract (ent->v->velocity, into, side);
950 ent->v->velocity[0] = side[0] * (1 + d);
951 ent->v->velocity[1] = side[1] * (1 + d);
956 =====================
959 Player has come to a dead stop, possibly due to the problem with limited
960 float precision at some angle joins in the BSP hull.
962 Try fixing by pushing one pixel in each direction.
964 This is a hack, but in the interest of good gameplay...
965 ======================
967 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
972 VectorCopy (ent->v->origin, oldorg);
975 for (i=0 ; i<8 ; i++)
977 // try pushing a little in an axial direction
980 case 0: dir[0] = 2; dir[1] = 0; break;
981 case 1: dir[0] = 0; dir[1] = 2; break;
982 case 2: dir[0] = -2; dir[1] = 0; break;
983 case 3: dir[0] = 0; dir[1] = -2; break;
984 case 4: dir[0] = 2; dir[1] = 2; break;
985 case 5: dir[0] = -2; dir[1] = 2; break;
986 case 6: dir[0] = 2; dir[1] = -2; break;
987 case 7: dir[0] = -2; dir[1] = -2; break;
990 SV_PushEntity (ent, dir, vec3_origin);
992 // retry the original move
993 ent->v->velocity[0] = oldvel[0];
994 ent->v->velocity[1] = oldvel[1];
995 ent->v->velocity[2] = 0;
996 clip = SV_FlyMove (ent, 0.1, NULL);
998 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
999 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
1001 Con_DPrintf("TryUnstick - success.\n");
1005 // go back to the original pos and try again
1006 VectorCopy (oldorg, ent->v->origin);
1010 VectorClear (ent->v->velocity);
1011 Con_DPrintf("TryUnstick - failure.\n");
1016 =====================
1019 Only used by players
1020 ======================
1022 void SV_WalkMove (edict_t *ent)
1024 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
1025 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal, originalmove_origin, originalmove_velocity;
1028 SV_CheckVelocity(ent);
1030 // do a regular slide move unless it looks like you ran into a step
1031 oldonground = (int)ent->v->flags & FL_ONGROUND;
1032 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1034 VectorCopy (ent->v->origin, oldorg);
1035 VectorCopy (ent->v->velocity, oldvel);
1037 clip = SV_FlyMove (ent, sv.frametime, NULL);
1038 VectorCopy(ent->v->origin, originalmove_origin);
1039 VectorCopy(ent->v->velocity, originalmove_velocity);
1040 originalmove_clip = clip;
1041 originalmove_flags = (int)ent->v->flags;
1042 originalmove_groundentity = ent->v->groundentity;
1044 SV_CheckVelocity(ent);
1046 // if move didn't block on a step, return
1050 // if move was not trying to move into the step, return
1051 if (fabs(oldvel[0]) < 0.03125 && fabs(oldvel[1]) < 0.03125)
1054 if (ent->v->movetype != MOVETYPE_FLY)
1056 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
1057 // don't stair up while jumping
1060 if (ent->v->movetype != MOVETYPE_WALK)
1061 // gibbed by a trigger
1065 SV_CheckVelocity(ent);
1067 if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP )
1070 VectorCopy (ent->v->origin, nosteporg);
1071 VectorCopy (ent->v->velocity, nostepvel);
1073 // try moving up and forward to go up a step
1074 // back to start pos
1075 VectorCopy (oldorg, ent->v->origin);
1077 VectorClear (upmove);
1078 VectorClear (downmove);
1079 upmove[2] = sv_stepheight.value;
1080 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
1083 // FIXME: don't link?
1084 SV_PushEntity(ent, upmove, vec3_origin);
1087 ent->v->velocity[0] = oldvel[0];
1088 ent->v->velocity[1] = oldvel[1];
1089 ent->v->velocity[2] = 0;
1090 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1091 ent->v->velocity[2] += oldvel[2];
1093 // check for stuckness, possibly due to the limited precision of floats
1094 // in the clipping hulls
1096 && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
1097 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
1099 // stepping up didn't make any progress, revert to original move
1100 VectorCopy(originalmove_origin, ent->v->origin);
1101 VectorCopy(originalmove_velocity, ent->v->velocity);
1102 clip = originalmove_clip;
1103 ent->v->flags = originalmove_flags;
1104 ent->v->groundentity = originalmove_groundentity;
1105 // now try to unstick if needed
1106 //clip = SV_TryUnstick (ent, oldvel);
1110 // extra friction based on view angle
1111 if (clip & 2 && sv_wallfriction.integer)
1112 SV_WallFriction (ent, stepnormal);
1115 // FIXME: don't link?
1116 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
1118 if (downtrace.plane.normal[2] > 0.7)
1120 // LordHavoc: disabled this so you can walk on monsters/players
1121 //if (ent->v->solid == SOLID_BSP)
1123 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1124 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1129 // if the push down didn't end up on good ground, use the move without
1130 // the step up. This happens near wall / slope combinations, and can
1131 // cause the player to hop up higher on a slope too steep to climb
1132 VectorCopy (nosteporg, ent->v->origin);
1133 VectorCopy (nostepvel, ent->v->velocity);
1136 SV_CheckVelocity(ent);
1139 //============================================================================
1145 Entities that are "stuck" to another entity
1148 void SV_Physics_Follow (edict_t *ent)
1150 vec3_t vf, vr, vu, angles, v;
1154 if (!SV_RunThink (ent))
1157 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1158 e = PROG_TO_EDICT(ent->v->aiment);
1159 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])
1161 // quick case for no rotation
1162 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1166 angles[0] = -ent->v->punchangle[0];
1167 angles[1] = ent->v->punchangle[1];
1168 angles[2] = ent->v->punchangle[2];
1169 AngleVectors (angles, vf, vr, vu);
1170 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1171 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1172 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1173 angles[0] = -e->v->angles[0];
1174 angles[1] = e->v->angles[1];
1175 angles[2] = e->v->angles[2];
1176 AngleVectors (angles, vf, vr, vu);
1177 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1178 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1179 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1181 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1182 SV_LinkEdict (ent, true);
1186 ==============================================================================
1190 ==============================================================================
1195 SV_CheckWaterTransition
1199 void SV_CheckWaterTransition (edict_t *ent)
1202 cont = SV_PointQ1Contents(ent->v->origin);
1203 if (!ent->v->watertype)
1205 // just spawned here
1206 ent->v->watertype = cont;
1207 ent->v->waterlevel = 1;
1211 // check if the entity crossed into or out of water
1212 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1213 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1215 if (cont <= CONTENTS_WATER)
1217 ent->v->watertype = cont;
1218 ent->v->waterlevel = 1;
1222 ent->v->watertype = CONTENTS_EMPTY;
1223 ent->v->waterlevel = 0;
1231 Toss, bounce, and fly movement. When onground, do nothing.
1234 void SV_Physics_Toss (edict_t *ent)
1238 edict_t *groundentity;
1241 if (!SV_RunThink (ent))
1244 // if onground, return without moving
1245 if ((int)ent->v->flags & FL_ONGROUND)
1247 if (ent->v->groundentity == 0)
1249 // if ent was supported by a brush model on previous frame,
1250 // and groundentity is now freed, set groundentity to 0 (floating)
1251 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1252 if (groundentity->v->solid == SOLID_BSP)
1254 ent->e->suspendedinairflag = true;
1257 else if (ent->e->suspendedinairflag && groundentity->e->free)
1259 // leave it suspended in the air
1260 ent->v->groundentity = 0;
1261 ent->e->suspendedinairflag = false;
1265 ent->e->suspendedinairflag = false;
1267 SV_CheckVelocity (ent);
1270 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1271 SV_AddGravity (ent);
1274 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1277 VectorScale (ent->v->velocity, sv.frametime, move);
1278 trace = SV_PushEntity (ent, move, vec3_origin);
1282 if (trace.fraction < 1)
1284 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1286 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1287 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1289 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1292 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1293 // LordHavoc: fixed grenades not bouncing when fired down a slope
1294 d = DotProduct(trace.plane.normal, ent->v->velocity);
1295 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1297 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1298 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1299 VectorClear (ent->v->velocity);
1300 VectorClear (ent->v->avelocity);
1303 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1307 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1308 if (trace.plane.normal[2] > 0.7)
1310 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1311 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1312 VectorClear (ent->v->velocity);
1313 VectorClear (ent->v->avelocity);
1316 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1320 // check for in water
1321 SV_CheckWaterTransition (ent);
1325 ===============================================================================
1329 ===============================================================================
1336 Monsters freefall when they don't have a ground entity, otherwise
1337 all movement is done with discrete steps.
1339 This is also used for objects that have become still on the ground, but
1340 will fall if the floor is pulled out from under them.
1343 void SV_Physics_Step (edict_t *ent)
1345 // freefall if not onground/fly/swim
1346 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1348 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1351 SV_CheckVelocity(ent);
1352 SV_FlyMove(ent, sv.frametime, NULL);
1353 SV_LinkEdict(ent, true);
1356 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1357 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1363 SV_CheckWaterTransition(ent);
1366 //============================================================================
1374 void SV_Physics (void)
1379 // let the progs know that a new frame has started
1380 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1381 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1382 pr_global_struct->time = sv.time;
1383 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1386 // treat each object in turn
1389 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1394 if (pr_global_struct->force_retouch)
1395 SV_LinkEdict (ent, true); // force retouch even for stationary
1397 if (i <= svs.maxclients)
1401 if (!svs.clients[i-1].spawned)
1404 // call standard client pre-think
1405 SV_CheckVelocity (ent);
1406 pr_global_struct->time = sv.time;
1407 pr_global_struct->self = EDICT_TO_PROG(ent);
1408 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1409 SV_CheckVelocity (ent);
1412 else if (sv_freezenonclients.integer)
1415 // LordHavoc: merged client and normal entity physics
1416 switch ((int) ent->v->movetype)
1419 case MOVETYPE_FAKEPUSH:
1420 SV_Physics_Pusher (ent);
1423 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1424 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1427 case MOVETYPE_FOLLOW:
1428 SV_Physics_Follow (ent);
1430 case MOVETYPE_NOCLIP:
1431 if (SV_RunThink(ent))
1434 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1435 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1437 // relink normal entities here, players always get relinked so don't relink twice
1438 if (!(i > 0 && i <= svs.maxclients))
1439 SV_LinkEdict(ent, false);
1442 SV_Physics_Step (ent);
1445 if (SV_RunThink (ent))
1447 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1448 SV_AddGravity (ent);
1449 SV_CheckStuck (ent);
1451 // relink normal entities here, players always get relinked so don't relink twice
1452 if (!(i > 0 && i <= svs.maxclients))
1453 SV_LinkEdict (ent, true);
1457 case MOVETYPE_BOUNCE:
1458 case MOVETYPE_BOUNCEMISSILE:
1459 case MOVETYPE_FLYMISSILE:
1460 SV_Physics_Toss (ent);
1463 if (i > 0 && i <= svs.maxclients)
1465 if (SV_RunThink (ent))
1467 SV_CheckWater (ent);
1472 SV_Physics_Toss (ent);
1475 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1479 if (i <= svs.maxclients && i > 0 && !ent->e->free)
1481 SV_CheckVelocity (ent);
1483 // call standard player post-think
1484 SV_LinkEdict (ent, true);
1486 SV_CheckVelocity (ent);
1488 pr_global_struct->time = sv.time;
1489 pr_global_struct->self = EDICT_TO_PROG(ent);
1490 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1494 if (pr_global_struct->force_retouch)
1495 pr_global_struct->force_retouch--;
1497 // LordHavoc: endframe support
1500 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1501 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1502 pr_global_struct->time = sv.time;
1503 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1506 if (!sv_freezenonclients.integer)
1507 sv.time += sv.frametime;
1511 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1514 float gravity, savesolid;
1516 edict_t tempent, *tent;
1521 // copy the vars over
1522 memcpy(&vars, tossent->v, sizeof(entvars_t));
1523 // set up the temp entity to point to the copied vars
1527 savesolid = tossent->v->solid;
1528 tossent->v->solid = SOLID_NOT;
1530 // this has to fetch the field from the original edict, since our copy is truncated
1531 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1532 if (val != NULL && val->_float != 0)
1533 gravity = val->_float;
1536 gravity *= sv_gravity.value * 0.05;
1538 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1540 SV_CheckVelocity (tent);
1541 tent->v->velocity[2] -= gravity;
1542 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1543 VectorScale (tent->v->velocity, 0.05, move);
1544 VectorAdd (tent->v->origin, move, end);
1545 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1546 VectorCopy (trace.endpos, tent->v->origin);
1548 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1551 tossent->v->solid = savesolid;
1552 trace.fraction = 0; // not relevant