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_Print("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, "QC function self.think is missing");
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, "QC function self.touch is missing");
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, "QC function self.touch is missing");
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 int i, j, impact, numplanes;
239 vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
242 VectorCopy(ent->v->velocity, original_velocity);
243 VectorCopy(ent->v->velocity, primal_velocity);
246 hackongroundentity = NULL;
247 for (bumpcount = 0;bumpcount < 8;bumpcount++)
249 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
252 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
253 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
255 //if (trace.fraction < 0.002)
260 VectorCopy(ent->v->origin, start);
261 start[2] += 3;//0.03125;
262 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
263 end[2] += 3;//0.03125;
264 testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
265 if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->v->velocity) < DotProduct(testtrace.plane.normal, ent->v->velocity)))
267 Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction);
273 for (i = 0;i < numplanes;i++)
275 VectorCopy(ent->v->origin, start);
276 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
277 VectorMA(start, 3, planes[i], start);
278 VectorMA(end, 3, planes[i], end);
279 testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
280 if (trace.fraction < testtrace.fraction)
283 VectorCopy(start, ent->v->origin);
288 // VectorAdd(ent->v->origin, planes[j], start);
294 Con_Printf("entity %i bump %i: velocity %f %f %f trace %f", ent - sv.edicts, bumpcount, ent->v->velocity[0], ent->v->velocity[1], ent->v->velocity[2], trace.fraction);
295 if (trace.fraction < 1)
296 Con_Printf(" : %f %f %f", trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
301 if (trace.startsolid)
303 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
304 // entity is trapped in another solid
305 VectorClear(ent->v->velocity);
310 // break if it moved the entire distance
311 if (trace.fraction == 1)
313 VectorCopy(trace.endpos, ent->v->origin);
318 Host_Error("SV_FlyMove: !trace.ent");
320 if ((int) ent->v->flags & FL_ONGROUND)
322 if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
326 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
333 if (trace.plane.normal[2])
335 if (trace.plane.normal[2] > 0.7)
339 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
340 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
342 else if (trace.fraction < 0.001)
343 hackongroundentity = trace.ent;
349 // save the trace for player extrafriction
351 VectorCopy(trace.plane.normal, stepnormal);
354 if (trace.fraction >= 0.001)
356 // actually covered some distance
357 VectorCopy(trace.endpos, ent->v->origin);
358 VectorCopy(ent->v->velocity, original_velocity);
362 // run the impact function
365 SV_Impact(ent, trace.ent);
367 // break if removed by the impact function
372 time_left *= 1 - trace.fraction;
374 // clipped to another plane
375 if (numplanes >= MAX_CLIP_PLANES)
377 // this shouldn't really happen
378 VectorClear(ent->v->velocity);
384 for (i = 0;i < numplanes;i++)
385 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
389 VectorAdd(ent->v->velocity, trace.plane.normal, ent->v->velocity);
394 VectorCopy(trace.plane.normal, planes[numplanes]);
397 if (sv_newflymove.integer)
398 ClipVelocity(ent->v->velocity, trace.plane.normal, ent->v->velocity, 1);
401 // modify original_velocity so it parallels all of the clip planes
402 for (i = 0;i < numplanes;i++)
404 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
405 for (j = 0;j < numplanes;j++)
410 if (DotProduct(new_velocity, planes[j]) < 0)
420 // go along this plane
421 VectorCopy(new_velocity, ent->v->velocity);
425 // go along the crease
428 VectorClear(ent->v->velocity);
432 CrossProduct(planes[0], planes[1], dir);
433 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
434 VectorNormalize(dir);
435 d = DotProduct(dir, ent->v->velocity);
436 VectorScale(dir, d, ent->v->velocity);
440 // if original velocity is against the original velocity,
441 // stop dead to avoid tiny occilations in sloping corners
442 if (DotProduct(ent->v->velocity, primal_velocity) <= 0)
444 VectorClear(ent->v->velocity);
449 //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]);
452 // FIXME: this doesn't work well at all, find another solution
453 // if player is ontop of a non-onground floor and made no progress,
454 // set onground anyway (this tends to happen if standing in a wedge)
455 if (bumpcount == 8 && hackongroundentity)
458 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
459 ent->v->groundentity = EDICT_TO_PROG(hackongroundentity);
464 if ((blocked & 1) == 0 && bumpcount > 1)
466 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
467 // flag ONGROUND if there's ground under it
468 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
474 int SV_SetOnGround (edict_t *ent)
478 if ((int)ent->v->flags & FL_ONGROUND)
480 VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1);
481 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
482 if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7)
484 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
485 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
497 void SV_AddGravity (edict_t *ent)
502 val = GETEDICTFIELDVALUE(ent, eval_gravity);
503 if (val!=0 && val->_float)
504 ent_gravity = val->_float;
507 ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
512 ===============================================================================
516 ===============================================================================
523 Does not change the entities velocity at all
526 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
532 VectorAdd (ent->v->origin, push, end);
534 if (ent->v->movetype == MOVETYPE_FLYMISSILE)
536 else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
537 type = MOVE_NOMONSTERS; // only clip against bmodels
541 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent);
543 VectorCopy (trace.endpos, ent->v->origin);
544 SV_LinkEdict (ent, true);
546 if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
547 SV_Impact (ent, trace.ent);
558 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
559 void SV_PushMove (edict_t *pusher, float movetime)
563 float savesolid, movetime2, pushltime;
564 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
566 int numcheckentities;
567 static edict_t *checkentities[MAX_EDICTS];
568 model_t *pushermodel;
571 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])
573 pusher->v->ltime += movetime;
577 switch ((int) pusher->v->solid)
579 // LordHavoc: valid pusher types
583 case SOLID_CORPSE: // LordHavoc: this would be weird...
585 // LordHavoc: no collisions
588 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
589 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
590 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
591 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
592 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
593 pusher->v->ltime += movetime;
594 SV_LinkEdict (pusher, false);
597 Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
600 index = (int) pusher->v->modelindex;
601 if (index < 1 || index >= MAX_MODELS)
603 Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
606 pushermodel = sv.models[index];
608 movetime2 = movetime;
609 VectorScale(pusher->v->velocity, movetime2, move1);
610 VectorScale(pusher->v->avelocity, movetime2, moveangle);
611 if (moveangle[0] || moveangle[2])
613 for (i = 0;i < 3;i++)
617 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
618 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
622 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
623 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
627 else if (moveangle[1])
629 for (i = 0;i < 3;i++)
633 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
634 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
638 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
639 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
645 for (i = 0;i < 3;i++)
649 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
650 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
654 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
655 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
660 VectorNegate (moveangle, a);
661 AngleVectorsFLU (a, forward, left, up);
663 VectorCopy (pusher->v->origin, pushorig);
664 VectorCopy (pusher->v->angles, pushang);
665 pushltime = pusher->v->ltime;
667 // move the pusher to it's final position
669 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
670 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
671 pusher->v->ltime += movetime;
672 SV_LinkEdict (pusher, false);
674 savesolid = pusher->v->solid;
676 // see if any solid entities are inside the final position
679 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
680 for (e = 0;e < numcheckentities;e++)
682 check = checkentities[e];
683 if (check->v->movetype == MOVETYPE_PUSH
684 || check->v->movetype == MOVETYPE_NONE
685 || check->v->movetype == MOVETYPE_FOLLOW
686 || check->v->movetype == MOVETYPE_NOCLIP
687 || check->v->movetype == MOVETYPE_FAKEPUSH)
690 // if the entity is standing on the pusher, it will definitely be moved
691 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
692 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
695 if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used
697 VectorSubtract (check->v->origin, pusher->v->origin, org);
698 org2[0] = DotProduct (org, forward);
699 org2[1] = DotProduct (org, left);
700 org2[2] = DotProduct (org, up);
701 VectorSubtract (org2, org, move);
702 VectorAdd (move, move1, move);
705 VectorCopy (move1, move);
707 // remove the onground flag for non-players
708 if (check->v->movetype != MOVETYPE_WALK)
709 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
711 VectorCopy (check->v->origin, check->e->moved_from);
712 VectorCopy (check->v->angles, check->e->moved_fromangles);
713 sv.moved_edicts[num_moved++] = check;
715 // try moving the contacted entity
716 pusher->v->solid = SOLID_NOT;
717 trace = SV_PushEntity (check, move);
718 // FIXME: turn players specially
719 check->v->angles[1] += trace.fraction * moveangle[1];
720 pusher->v->solid = savesolid; // was SOLID_BSP
722 // if it is still inside the pusher, block
723 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
725 // try moving the contacted entity a tiny bit further to account for precision errors
726 pusher->v->solid = SOLID_NOT;
727 VectorScale(move, 0.1, move);
728 SV_PushEntity (check, move);
729 pusher->v->solid = savesolid;
730 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
732 // still inside pusher, so it's really blocked
735 if (check->v->mins[0] == check->v->maxs[0])
737 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
740 check->v->mins[0] = check->v->mins[1] = 0;
741 VectorCopy (check->v->mins, check->v->maxs);
745 VectorCopy (pushorig, pusher->v->origin);
746 VectorCopy (pushang, pusher->v->angles);
747 pusher->v->ltime = pushltime;
748 SV_LinkEdict (pusher, false);
750 // move back any entities we already moved
751 for (i = 0;i < num_moved;i++)
753 ed = sv.moved_edicts[i];
754 VectorCopy (ed->e->moved_from, ed->v->origin);
755 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
756 SV_LinkEdict (ed, false);
759 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
760 if (pusher->v->blocked)
762 pr_global_struct->self = EDICT_TO_PROG(pusher);
763 pr_global_struct->other = EDICT_TO_PROG(check);
764 PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing");
770 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
771 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
772 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
781 void SV_Physics_Pusher (edict_t *ent)
783 float thinktime, oldltime, movetime;
785 oldltime = ent->v->ltime;
787 thinktime = ent->v->nextthink;
788 if (thinktime < ent->v->ltime + sv.frametime)
790 movetime = thinktime - ent->v->ltime;
795 movetime = sv.frametime;
798 // advances ent->v->ltime if not blocked
799 SV_PushMove (ent, movetime);
801 if (thinktime > oldltime && thinktime <= ent->v->ltime)
803 ent->v->nextthink = 0;
804 pr_global_struct->time = sv.time;
805 pr_global_struct->self = EDICT_TO_PROG(ent);
806 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
807 PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
813 ===============================================================================
817 ===============================================================================
824 This is a big hack to try and fix the rare case of getting stuck in the world
828 void SV_CheckStuck (edict_t *ent)
833 if (!SV_TestEntityPosition(ent))
835 VectorCopy (ent->v->origin, ent->v->oldorigin);
839 VectorCopy (ent->v->origin, org);
840 VectorCopy (ent->v->oldorigin, ent->v->origin);
841 if (!SV_TestEntityPosition(ent))
843 Con_DPrint("Unstuck.\n");
844 SV_LinkEdict (ent, true);
848 for (z=0 ; z< 18 ; z++)
849 for (i=-1 ; i <= 1 ; i++)
850 for (j=-1 ; j <= 1 ; j++)
852 ent->v->origin[0] = org[0] + i;
853 ent->v->origin[1] = org[1] + j;
854 ent->v->origin[2] = org[2] + z;
855 if (!SV_TestEntityPosition(ent))
857 Con_DPrint("Unstuck.\n");
858 SV_LinkEdict (ent, true);
863 VectorCopy (org, ent->v->origin);
864 Con_DPrint("player is stuck.\n");
873 qboolean SV_CheckWater (edict_t *ent)
878 point[0] = ent->v->origin[0];
879 point[1] = ent->v->origin[1];
880 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
882 ent->v->waterlevel = 0;
883 ent->v->watertype = CONTENTS_EMPTY;
884 cont = SV_PointSuperContents(point);
885 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
887 ent->v->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
888 ent->v->waterlevel = 1;
889 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
890 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
892 ent->v->waterlevel = 2;
893 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
894 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
895 ent->v->waterlevel = 3;
899 return ent->v->waterlevel > 1;
908 void SV_WallFriction (edict_t *ent, float *stepnormal)
911 vec3_t forward, into, side;
913 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
914 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
916 // cut the tangential velocity
917 i = DotProduct (stepnormal, ent->v->velocity);
918 VectorScale (stepnormal, i, into);
919 VectorSubtract (ent->v->velocity, into, side);
920 ent->v->velocity[0] = side[0] * (1 + d);
921 ent->v->velocity[1] = side[1] * (1 + d);
926 =====================
929 Player has come to a dead stop, possibly due to the problem with limited
930 float precision at some angle joins in the BSP hull.
932 Try fixing by pushing one pixel in each direction.
934 This is a hack, but in the interest of good gameplay...
935 ======================
937 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
942 VectorCopy (ent->v->origin, oldorg);
945 for (i=0 ; i<8 ; i++)
947 // try pushing a little in an axial direction
950 case 0: dir[0] = 2; dir[1] = 0; break;
951 case 1: dir[0] = 0; dir[1] = 2; break;
952 case 2: dir[0] = -2; dir[1] = 0; break;
953 case 3: dir[0] = 0; dir[1] = -2; break;
954 case 4: dir[0] = 2; dir[1] = 2; break;
955 case 5: dir[0] = -2; dir[1] = 2; break;
956 case 6: dir[0] = 2; dir[1] = -2; break;
957 case 7: dir[0] = -2; dir[1] = -2; break;
960 SV_PushEntity (ent, dir);
962 // retry the original move
963 ent->v->velocity[0] = oldvel[0];
964 ent->v->velocity[1] = oldvel[1];
965 ent->v->velocity[2] = 0;
966 clip = SV_FlyMove (ent, 0.1, NULL);
968 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
969 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
971 Con_DPrint("TryUnstick - success.\n");
975 // go back to the original pos and try again
976 VectorCopy (oldorg, ent->v->origin);
980 VectorClear (ent->v->velocity);
981 Con_DPrint("TryUnstick - failure.\n");
986 =====================
990 ======================
992 void SV_WalkMove (edict_t *ent)
994 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
995 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
998 SV_CheckVelocity(ent);
1000 // do a regular slide move unless it looks like you ran into a step
1001 oldonground = (int)ent->v->flags & FL_ONGROUND;
1002 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1004 VectorCopy (ent->v->origin, start_origin);
1005 VectorCopy (ent->v->velocity, start_velocity);
1007 clip = SV_FlyMove (ent, sv.frametime, NULL);
1009 SV_SetOnGround (ent);
1010 SV_CheckVelocity(ent);
1012 VectorCopy(ent->v->origin, originalmove_origin);
1013 VectorCopy(ent->v->velocity, originalmove_velocity);
1014 originalmove_clip = clip;
1015 originalmove_flags = (int)ent->v->flags;
1016 originalmove_groundentity = ent->v->groundentity;
1018 if ((int)ent->v->flags & FL_WATERJUMP)
1021 if (sv_nostep.integer)
1024 // if move didn't block on a step, return
1027 // if move was not trying to move into the step, return
1028 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
1031 if (ent->v->movetype != MOVETYPE_FLY)
1033 // return if gibbed by a trigger
1034 if (ent->v->movetype != MOVETYPE_WALK)
1037 // only step up while jumping if that is enabled
1038 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
1039 if (!oldonground && ent->v->waterlevel == 0)
1043 // try moving up and forward to go up a step
1044 // back to start pos
1045 VectorCopy (start_origin, ent->v->origin);
1046 VectorCopy (start_velocity, ent->v->velocity);
1049 VectorClear (upmove);
1050 upmove[2] = sv_stepheight.value;
1051 // FIXME: don't link?
1052 SV_PushEntity(ent, upmove);
1055 ent->v->velocity[2] = 0;
1056 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1057 ent->v->velocity[2] += start_velocity[2];
1059 SV_CheckVelocity(ent);
1061 // check for stuckness, possibly due to the limited precision of floats
1062 // in the clipping hulls
1064 && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
1065 && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
1067 //Con_Printf("wall\n");
1068 // stepping up didn't make any progress, revert to original move
1069 VectorCopy(originalmove_origin, ent->v->origin);
1070 VectorCopy(originalmove_velocity, ent->v->velocity);
1071 //clip = originalmove_clip;
1072 ent->v->flags = originalmove_flags;
1073 ent->v->groundentity = originalmove_groundentity;
1074 // now try to unstick if needed
1075 //clip = SV_TryUnstick (ent, oldvel);
1079 //Con_Printf("step - ");
1081 // extra friction based on view angle
1082 if (clip & 2 && sv_wallfriction.integer)
1083 SV_WallFriction (ent, stepnormal);
1085 // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
1086 else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
1090 VectorClear (downmove);
1091 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
1092 // FIXME: don't link?
1093 downtrace = SV_PushEntity (ent, downmove);
1095 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
1097 // LordHavoc: disabled this check so you can walk on monsters/players
1098 //if (ent->v->solid == SOLID_BSP)
1100 //Con_Printf("onground\n");
1101 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1102 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1107 //Con_Printf("slope\n");
1108 // if the push down didn't end up on good ground, use the move without
1109 // the step up. This happens near wall / slope combinations, and can
1110 // cause the player to hop up higher on a slope too steep to climb
1111 VectorCopy(originalmove_origin, ent->v->origin);
1112 VectorCopy(originalmove_velocity, ent->v->velocity);
1113 //clip = originalmove_clip;
1114 ent->v->flags = originalmove_flags;
1115 ent->v->groundentity = originalmove_groundentity;
1118 SV_SetOnGround (ent);
1119 SV_CheckVelocity(ent);
1122 //============================================================================
1128 Entities that are "stuck" to another entity
1131 void SV_Physics_Follow (edict_t *ent)
1133 vec3_t vf, vr, vu, angles, v;
1137 if (!SV_RunThink (ent))
1140 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1141 e = PROG_TO_EDICT(ent->v->aiment);
1142 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])
1144 // quick case for no rotation
1145 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1149 angles[0] = -ent->v->punchangle[0];
1150 angles[1] = ent->v->punchangle[1];
1151 angles[2] = ent->v->punchangle[2];
1152 AngleVectors (angles, vf, vr, vu);
1153 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1154 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1155 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1156 angles[0] = -e->v->angles[0];
1157 angles[1] = e->v->angles[1];
1158 angles[2] = e->v->angles[2];
1159 AngleVectors (angles, vf, vr, vu);
1160 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1161 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1162 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1164 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1165 SV_LinkEdict (ent, true);
1169 ==============================================================================
1173 ==============================================================================
1178 SV_CheckWaterTransition
1182 void SV_CheckWaterTransition (edict_t *ent)
1185 cont = SV_PointQ1Contents(ent->v->origin);
1186 if (!ent->v->watertype)
1188 // just spawned here
1189 ent->v->watertype = cont;
1190 ent->v->waterlevel = 1;
1194 // check if the entity crossed into or out of water
1195 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1196 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1198 if (cont <= CONTENTS_WATER)
1200 ent->v->watertype = cont;
1201 ent->v->waterlevel = 1;
1205 ent->v->watertype = CONTENTS_EMPTY;
1206 ent->v->waterlevel = 0;
1214 Toss, bounce, and fly movement. When onground, do nothing.
1217 void SV_Physics_Toss (edict_t *ent)
1221 edict_t *groundentity;
1223 // don't stick to ground if onground and moving upward
1224 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1225 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1227 // if onground, return without moving
1228 if ((int)ent->v->flags & FL_ONGROUND)
1230 if (!sv_gameplayfix_noairborncorpse.integer)
1232 if (ent->v->groundentity == 0)
1234 // if ent was supported by a brush model on previous frame,
1235 // and groundentity is now freed, set groundentity to 0 (floating)
1236 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1237 if (groundentity->v->solid == SOLID_BSP)
1239 ent->e->suspendedinairflag = true;
1242 else if (ent->e->suspendedinairflag && groundentity->e->free)
1244 // leave it suspended in the air
1245 ent->v->groundentity = 0;
1246 ent->e->suspendedinairflag = false;
1250 ent->e->suspendedinairflag = false;
1252 SV_CheckVelocity (ent);
1255 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1256 SV_AddGravity (ent);
1259 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1262 VectorScale (ent->v->velocity, sv.frametime, move);
1263 trace = SV_PushEntity (ent, move);
1267 if (trace.fraction < 1)
1269 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1271 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1272 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1274 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1277 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1278 // LordHavoc: fixed grenades not bouncing when fired down a slope
1279 if (sv_gameplayfix_grenadebouncedownslopes.integer)
1281 d = DotProduct(trace.plane.normal, ent->v->velocity);
1282 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1284 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1285 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1286 VectorClear (ent->v->velocity);
1287 VectorClear (ent->v->avelocity);
1290 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1294 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
1296 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1297 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1298 VectorClear (ent->v->velocity);
1299 VectorClear (ent->v->avelocity);
1302 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 // don't stick to ground if onground and moving upward
1346 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1347 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1349 // freefall if not onground/fly/swim
1350 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1352 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1355 SV_CheckVelocity(ent);
1356 SV_FlyMove(ent, sv.frametime, NULL);
1357 SV_LinkEdict(ent, true);
1360 if (hitsound && (int)ent->v->flags & FL_ONGROUND && gamemode != GAME_NEXUIZ)
1361 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1367 SV_CheckWaterTransition(ent);
1370 //============================================================================
1378 void SV_Physics (void)
1380 int i, newnum_edicts;
1382 qbyte runmove[MAX_EDICTS];
1384 // let the progs know that a new frame has started
1385 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1386 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1387 pr_global_struct->time = sv.time;
1388 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1391 for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1392 if ((runmove[i] = !ent->e->free))
1393 newnum_edicts = i + 1;
1394 sv.num_edicts = max(svs.maxclients + 1, newnum_edicts);
1397 // treat each object in turn
1400 for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1405 if (pr_global_struct->force_retouch)
1406 SV_LinkEdict (ent, true); // force retouch even for stationary
1408 if (i >= 1 && i <= svs.maxclients)
1410 // don't do physics on disconnected clients, FrikBot relies on this
1411 if (!svs.clients[i-1].spawned)
1414 // call standard client pre-think
1415 SV_CheckVelocity (ent);
1416 pr_global_struct->time = sv.time;
1417 pr_global_struct->self = EDICT_TO_PROG(ent);
1418 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1419 SV_CheckVelocity (ent);
1421 else if (sv_freezenonclients.integer)
1424 // LordHavoc: merged client and normal entity physics
1425 switch ((int) ent->v->movetype)
1428 case MOVETYPE_FAKEPUSH:
1429 SV_Physics_Pusher (ent);
1432 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1433 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1436 case MOVETYPE_FOLLOW:
1437 SV_Physics_Follow (ent);
1439 case MOVETYPE_NOCLIP:
1440 if (SV_RunThink(ent))
1443 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1444 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1446 // relink normal entities here, players always get relinked so don't relink twice
1447 if (!(i > 0 && i <= svs.maxclients))
1448 SV_LinkEdict(ent, false);
1451 SV_Physics_Step (ent);
1454 if (SV_RunThink (ent))
1456 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1457 SV_AddGravity (ent);
1458 SV_CheckStuck (ent);
1460 // relink normal entities here, players always get relinked so don't relink twice
1461 if (!(i > 0 && i <= svs.maxclients))
1462 SV_LinkEdict (ent, true);
1466 case MOVETYPE_BOUNCE:
1467 case MOVETYPE_BOUNCEMISSILE:
1468 case MOVETYPE_FLYMISSILE:
1470 if (SV_RunThink (ent) && runmove[i])
1471 SV_Physics_Toss (ent);
1474 if (SV_RunThink (ent) && runmove[i])
1476 if (i > 0 && i <= svs.maxclients)
1478 SV_CheckWater (ent);
1482 SV_Physics_Toss (ent);
1486 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1490 if (i >= 1 && i <= svs.maxclients)
1492 SV_CheckVelocity (ent);
1494 // call standard player post-think
1495 SV_LinkEdict (ent, true);
1497 SV_CheckVelocity (ent);
1499 pr_global_struct->time = sv.time;
1500 pr_global_struct->self = EDICT_TO_PROG(ent);
1501 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1505 if (pr_global_struct->force_retouch > 0)
1506 pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);
1508 // LordHavoc: endframe support
1511 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1512 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1513 pr_global_struct->time = sv.time;
1514 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1517 if (!sv_freezenonclients.integer)
1518 sv.time += sv.frametime;
1522 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1525 float gravity, savesolid;
1527 edict_t tempent, *tent;
1532 // copy the vars over
1533 memcpy(&vars, tossent->v, sizeof(entvars_t));
1534 // set up the temp entity to point to the copied vars
1538 savesolid = tossent->v->solid;
1539 tossent->v->solid = SOLID_NOT;
1541 // this has to fetch the field from the original edict, since our copy is truncated
1542 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1543 if (val != NULL && val->_float != 0)
1544 gravity = val->_float;
1547 gravity *= sv_gravity.value * 0.05;
1549 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1551 SV_CheckVelocity (tent);
1552 tent->v->velocity[2] -= gravity;
1553 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1554 VectorScale (tent->v->velocity, 0.05, move);
1555 VectorAdd (tent->v->origin, move, end);
1556 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1557 VectorCopy (trace.endpos, tent->v->origin);
1559 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1562 tossent->v->solid = savesolid;
1563 trace.fraction = 0; // not relevant