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", "0"};
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 32
232 #define MAX_CLIP_PLANES 32
233 int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
235 int blocked, bumpcount;
236 int i, j, impact, numplanes;
238 vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
241 VectorCopy(ent->v->velocity, original_velocity);
242 VectorCopy(ent->v->velocity, primal_velocity);
245 for (bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
247 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
250 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
251 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
253 //if (trace.fraction < 0.002)
258 VectorCopy(ent->v->origin, start);
259 start[2] += 3;//0.03125;
260 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
261 end[2] += 3;//0.03125;
262 testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
263 if (trace.fraction < testtrace.fraction && !testtrace.startsolid && (testtrace.fraction == 1 || DotProduct(trace.plane.normal, ent->v->velocity) < DotProduct(testtrace.plane.normal, ent->v->velocity)))
265 Con_Printf("got further (new %f > old %f)\n", testtrace.fraction, trace.fraction);
271 for (i = 0;i < numplanes;i++)
273 VectorCopy(ent->v->origin, start);
274 VectorMA(ent->v->origin, time_left, ent->v->velocity, end);
275 VectorMA(start, 3, planes[i], start);
276 VectorMA(end, 3, planes[i], end);
277 testtrace = SV_Move(start, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
278 if (trace.fraction < testtrace.fraction)
281 VectorCopy(start, ent->v->origin);
286 // VectorAdd(ent->v->origin, planes[j], start);
292 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);
293 if (trace.fraction < 1)
294 Con_Printf(" : %f %f %f", trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
299 if (trace.startsolid)
301 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
302 // entity is trapped in another solid
303 VectorClear(ent->v->velocity);
308 // break if it moved the entire distance
309 if (trace.fraction == 1)
311 VectorCopy(trace.endpos, ent->v->origin);
316 Host_Error("SV_FlyMove: !trace.ent");
318 if (((int) ent->v->flags & FL_ONGROUND) && ent->v->groundentity == EDICT_TO_PROG(trace.ent))
322 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
326 if (trace.plane.normal[2])
328 if (trace.plane.normal[2] > 0.7)
332 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
333 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
340 // save the trace for player extrafriction
342 VectorCopy(trace.plane.normal, stepnormal);
345 if (trace.fraction >= 0.001)
347 // actually covered some distance
348 VectorCopy(trace.endpos, ent->v->origin);
349 VectorCopy(ent->v->velocity, original_velocity);
353 // run the impact function
356 SV_Impact(ent, trace.ent);
358 // break if removed by the impact function
363 time_left *= 1 - trace.fraction;
365 // clipped to another plane
366 if (numplanes >= MAX_CLIP_PLANES)
368 // this shouldn't really happen
369 VectorClear(ent->v->velocity);
375 for (i = 0;i < numplanes;i++)
376 if (DotProduct(trace.plane.normal, planes[i]) > 0.99)
380 VectorAdd(ent->v->velocity, trace.plane.normal, ent->v->velocity);
385 VectorCopy(trace.plane.normal, planes[numplanes]);
388 if (sv_newflymove.integer)
389 ClipVelocity(ent->v->velocity, trace.plane.normal, ent->v->velocity, 1);
392 // modify original_velocity so it parallels all of the clip planes
393 for (i = 0;i < numplanes;i++)
395 ClipVelocity(original_velocity, planes[i], new_velocity, 1);
396 for (j = 0;j < numplanes;j++)
401 if (DotProduct(new_velocity, planes[j]) < 0)
411 // go along this plane
412 VectorCopy(new_velocity, ent->v->velocity);
416 // go along the crease
419 VectorClear(ent->v->velocity);
423 CrossProduct(planes[0], planes[1], dir);
424 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
425 VectorNormalize(dir);
426 d = DotProduct(dir, ent->v->velocity);
427 VectorScale(dir, d, ent->v->velocity);
431 // if current velocity is against the original velocity,
432 // stop dead to avoid tiny occilations in sloping corners
433 if (DotProduct(ent->v->velocity, primal_velocity) <= 0)
435 VectorClear(ent->v->velocity);
440 //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]);
443 if ((blocked & 1) == 0 && bumpcount > 1)
445 // LordHavoc: fix the 'fall to your death in a wedge corner' glitch
446 // flag ONGROUND if there's ground under it
447 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
453 int SV_SetOnGround (edict_t *ent)
457 if ((int)ent->v->flags & FL_ONGROUND)
459 VectorSet(end, ent->v->origin[0], ent->v->origin[1], ent->v->origin[2] - 1);
460 trace = SV_Move(ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
461 if (trace.fraction < 1 && trace.plane.normal[2] >= 0.7)
463 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
464 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
476 void SV_AddGravity (edict_t *ent)
481 val = GETEDICTFIELDVALUE(ent, eval_gravity);
482 if (val!=0 && val->_float)
483 ent_gravity = val->_float;
486 ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
491 ===============================================================================
495 ===============================================================================
502 Does not change the entities velocity at all
505 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
511 VectorAdd (ent->v->origin, push, end);
513 if (ent->v->movetype == MOVETYPE_FLYMISSILE)
515 else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
516 type = MOVE_NOMONSTERS; // only clip against bmodels
520 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, type, ent);
522 VectorCopy (trace.endpos, ent->v->origin);
523 SV_LinkEdict (ent, true);
525 if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
526 SV_Impact (ent, trace.ent);
537 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
538 void SV_PushMove (edict_t *pusher, float movetime)
542 float savesolid, movetime2, pushltime;
543 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
545 int numcheckentities;
546 static edict_t *checkentities[MAX_EDICTS];
547 model_t *pushermodel;
550 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])
552 pusher->v->ltime += movetime;
556 switch ((int) pusher->v->solid)
558 // LordHavoc: valid pusher types
562 case SOLID_CORPSE: // LordHavoc: this would be weird...
564 // LordHavoc: no collisions
567 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
568 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
569 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
570 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
571 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
572 pusher->v->ltime += movetime;
573 SV_LinkEdict (pusher, false);
576 Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
579 index = (int) pusher->v->modelindex;
580 if (index < 1 || index >= MAX_MODELS)
582 Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
585 pushermodel = sv.models[index];
587 movetime2 = movetime;
588 VectorScale(pusher->v->velocity, movetime2, move1);
589 VectorScale(pusher->v->avelocity, movetime2, moveangle);
590 if (moveangle[0] || moveangle[2])
592 for (i = 0;i < 3;i++)
596 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
597 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
601 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
602 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
606 else if (moveangle[1])
608 for (i = 0;i < 3;i++)
612 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
613 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
617 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
618 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
624 for (i = 0;i < 3;i++)
628 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
629 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
633 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
634 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
639 VectorNegate (moveangle, a);
640 AngleVectorsFLU (a, forward, left, up);
642 VectorCopy (pusher->v->origin, pushorig);
643 VectorCopy (pusher->v->angles, pushang);
644 pushltime = pusher->v->ltime;
646 // move the pusher to it's final position
648 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
649 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
650 pusher->v->ltime += movetime;
651 SV_LinkEdict (pusher, false);
653 savesolid = pusher->v->solid;
655 // see if any solid entities are inside the final position
658 numcheckentities = SV_EntitiesInBox(mins, maxs, MAX_EDICTS, checkentities);
659 for (e = 0;e < numcheckentities;e++)
661 check = checkentities[e];
662 if (check->v->movetype == MOVETYPE_PUSH
663 || check->v->movetype == MOVETYPE_NONE
664 || check->v->movetype == MOVETYPE_FOLLOW
665 || check->v->movetype == MOVETYPE_NOCLIP
666 || check->v->movetype == MOVETYPE_FAKEPUSH)
669 // if the entity is standing on the pusher, it will definitely be moved
670 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
671 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
674 if (forward[0] != 1 || left[1] != 1) // quick way to check if any rotation is used
676 VectorSubtract (check->v->origin, pusher->v->origin, org);
677 org2[0] = DotProduct (org, forward);
678 org2[1] = DotProduct (org, left);
679 org2[2] = DotProduct (org, up);
680 VectorSubtract (org2, org, move);
681 VectorAdd (move, move1, move);
684 VectorCopy (move1, move);
686 // remove the onground flag for non-players
687 if (check->v->movetype != MOVETYPE_WALK)
688 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
690 VectorCopy (check->v->origin, check->e->moved_from);
691 VectorCopy (check->v->angles, check->e->moved_fromangles);
692 sv.moved_edicts[num_moved++] = check;
694 // try moving the contacted entity
695 pusher->v->solid = SOLID_NOT;
696 trace = SV_PushEntity (check, move);
697 // FIXME: turn players specially
698 check->v->angles[1] += trace.fraction * moveangle[1];
699 pusher->v->solid = savesolid; // was SOLID_BSP
701 // if it is still inside the pusher, block
702 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
704 // try moving the contacted entity a tiny bit further to account for precision errors
705 pusher->v->solid = SOLID_NOT;
706 VectorScale(move, 0.1, move);
707 SV_PushEntity (check, move);
708 pusher->v->solid = savesolid;
709 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
711 // still inside pusher, so it's really blocked
714 if (check->v->mins[0] == check->v->maxs[0])
716 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
719 check->v->mins[0] = check->v->mins[1] = 0;
720 VectorCopy (check->v->mins, check->v->maxs);
724 VectorCopy (pushorig, pusher->v->origin);
725 VectorCopy (pushang, pusher->v->angles);
726 pusher->v->ltime = pushltime;
727 SV_LinkEdict (pusher, false);
729 // move back any entities we already moved
730 for (i = 0;i < num_moved;i++)
732 ed = sv.moved_edicts[i];
733 VectorCopy (ed->e->moved_from, ed->v->origin);
734 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
735 SV_LinkEdict (ed, false);
738 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
739 if (pusher->v->blocked)
741 pr_global_struct->self = EDICT_TO_PROG(pusher);
742 pr_global_struct->other = EDICT_TO_PROG(check);
743 PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing");
749 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
750 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
751 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
760 void SV_Physics_Pusher (edict_t *ent)
762 float thinktime, oldltime, movetime;
764 oldltime = ent->v->ltime;
766 thinktime = ent->v->nextthink;
767 if (thinktime < ent->v->ltime + sv.frametime)
769 movetime = thinktime - ent->v->ltime;
774 movetime = sv.frametime;
777 // advances ent->v->ltime if not blocked
778 SV_PushMove (ent, movetime);
780 if (thinktime > oldltime && thinktime <= ent->v->ltime)
782 ent->v->nextthink = 0;
783 pr_global_struct->time = sv.time;
784 pr_global_struct->self = EDICT_TO_PROG(ent);
785 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
786 PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
792 ===============================================================================
796 ===============================================================================
803 This is a big hack to try and fix the rare case of getting stuck in the world
807 void SV_CheckStuck (edict_t *ent)
812 if (!SV_TestEntityPosition(ent))
814 VectorCopy (ent->v->origin, ent->v->oldorigin);
818 VectorCopy (ent->v->origin, org);
819 VectorCopy (ent->v->oldorigin, ent->v->origin);
820 if (!SV_TestEntityPosition(ent))
822 Con_DPrint("Unstuck.\n");
823 SV_LinkEdict (ent, true);
827 for (z=0 ; z< 18 ; z++)
828 for (i=-1 ; i <= 1 ; i++)
829 for (j=-1 ; j <= 1 ; j++)
831 ent->v->origin[0] = org[0] + i;
832 ent->v->origin[1] = org[1] + j;
833 ent->v->origin[2] = org[2] + z;
834 if (!SV_TestEntityPosition(ent))
836 Con_DPrint("Unstuck.\n");
837 SV_LinkEdict (ent, true);
842 VectorCopy (org, ent->v->origin);
843 Con_DPrint("player is stuck.\n");
852 qboolean SV_CheckWater (edict_t *ent)
857 point[0] = ent->v->origin[0];
858 point[1] = ent->v->origin[1];
859 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
861 ent->v->waterlevel = 0;
862 ent->v->watertype = CONTENTS_EMPTY;
863 cont = SV_PointSuperContents(point);
864 if (cont & (SUPERCONTENTS_LIQUIDSMASK))
866 ent->v->watertype = Mod_Q1BSP_NativeContentsFromSuperContents(NULL, cont);
867 ent->v->waterlevel = 1;
868 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
869 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
871 ent->v->waterlevel = 2;
872 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
873 if (SV_PointSuperContents(point) & (SUPERCONTENTS_LIQUIDSMASK))
874 ent->v->waterlevel = 3;
878 return ent->v->waterlevel > 1;
887 void SV_WallFriction (edict_t *ent, float *stepnormal)
890 vec3_t forward, into, side;
892 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
893 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
895 // cut the tangential velocity
896 i = DotProduct (stepnormal, ent->v->velocity);
897 VectorScale (stepnormal, i, into);
898 VectorSubtract (ent->v->velocity, into, side);
899 ent->v->velocity[0] = side[0] * (1 + d);
900 ent->v->velocity[1] = side[1] * (1 + d);
905 =====================
908 Player has come to a dead stop, possibly due to the problem with limited
909 float precision at some angle joins in the BSP hull.
911 Try fixing by pushing one pixel in each direction.
913 This is a hack, but in the interest of good gameplay...
914 ======================
916 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
921 VectorCopy (ent->v->origin, oldorg);
924 for (i=0 ; i<8 ; i++)
926 // try pushing a little in an axial direction
929 case 0: dir[0] = 2; dir[1] = 0; break;
930 case 1: dir[0] = 0; dir[1] = 2; break;
931 case 2: dir[0] = -2; dir[1] = 0; break;
932 case 3: dir[0] = 0; dir[1] = -2; break;
933 case 4: dir[0] = 2; dir[1] = 2; break;
934 case 5: dir[0] = -2; dir[1] = 2; break;
935 case 6: dir[0] = 2; dir[1] = -2; break;
936 case 7: dir[0] = -2; dir[1] = -2; break;
939 SV_PushEntity (ent, dir);
941 // retry the original move
942 ent->v->velocity[0] = oldvel[0];
943 ent->v->velocity[1] = oldvel[1];
944 ent->v->velocity[2] = 0;
945 clip = SV_FlyMove (ent, 0.1, NULL);
947 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
948 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
950 Con_DPrint("TryUnstick - success.\n");
954 // go back to the original pos and try again
955 VectorCopy (oldorg, ent->v->origin);
959 VectorClear (ent->v->velocity);
960 Con_DPrint("TryUnstick - failure.\n");
965 =====================
969 ======================
971 void SV_WalkMove (edict_t *ent)
973 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
974 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
977 SV_CheckVelocity(ent);
979 // do a regular slide move unless it looks like you ran into a step
980 oldonground = (int)ent->v->flags & FL_ONGROUND;
981 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
983 VectorCopy (ent->v->origin, start_origin);
984 VectorCopy (ent->v->velocity, start_velocity);
986 clip = SV_FlyMove (ent, sv.frametime, NULL);
988 SV_SetOnGround (ent);
989 SV_CheckVelocity(ent);
991 VectorCopy(ent->v->origin, originalmove_origin);
992 VectorCopy(ent->v->velocity, originalmove_velocity);
993 originalmove_clip = clip;
994 originalmove_flags = (int)ent->v->flags;
995 originalmove_groundentity = ent->v->groundentity;
997 if ((int)ent->v->flags & FL_WATERJUMP)
1000 if (sv_nostep.integer)
1003 // if move didn't block on a step, return
1006 // if move was not trying to move into the step, return
1007 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
1010 if (ent->v->movetype != MOVETYPE_FLY)
1012 // return if gibbed by a trigger
1013 if (ent->v->movetype != MOVETYPE_WALK)
1016 // only step up while jumping if that is enabled
1017 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
1018 if (!oldonground && ent->v->waterlevel == 0)
1022 // try moving up and forward to go up a step
1023 // back to start pos
1024 VectorCopy (start_origin, ent->v->origin);
1025 VectorCopy (start_velocity, ent->v->velocity);
1028 VectorClear (upmove);
1029 upmove[2] = sv_stepheight.value;
1030 // FIXME: don't link?
1031 SV_PushEntity(ent, upmove);
1034 ent->v->velocity[2] = 0;
1035 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1036 ent->v->velocity[2] += start_velocity[2];
1038 SV_CheckVelocity(ent);
1040 // check for stuckness, possibly due to the limited precision of floats
1041 // in the clipping hulls
1043 && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
1044 && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
1046 //Con_Printf("wall\n");
1047 // stepping up didn't make any progress, revert to original move
1048 VectorCopy(originalmove_origin, ent->v->origin);
1049 VectorCopy(originalmove_velocity, ent->v->velocity);
1050 //clip = originalmove_clip;
1051 ent->v->flags = originalmove_flags;
1052 ent->v->groundentity = originalmove_groundentity;
1053 // now try to unstick if needed
1054 //clip = SV_TryUnstick (ent, oldvel);
1058 //Con_Printf("step - ");
1060 // extra friction based on view angle
1061 if (clip & 2 && sv_wallfriction.integer)
1062 SV_WallFriction (ent, stepnormal);
1064 // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
1065 else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
1069 VectorClear (downmove);
1070 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
1071 // FIXME: don't link?
1072 downtrace = SV_PushEntity (ent, downmove);
1074 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
1076 // LordHavoc: disabled this check so you can walk on monsters/players
1077 //if (ent->v->solid == SOLID_BSP)
1079 //Con_Printf("onground\n");
1080 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1081 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1086 //Con_Printf("slope\n");
1087 // if the push down didn't end up on good ground, use the move without
1088 // the step up. This happens near wall / slope combinations, and can
1089 // cause the player to hop up higher on a slope too steep to climb
1090 VectorCopy(originalmove_origin, ent->v->origin);
1091 VectorCopy(originalmove_velocity, ent->v->velocity);
1092 //clip = originalmove_clip;
1093 ent->v->flags = originalmove_flags;
1094 ent->v->groundentity = originalmove_groundentity;
1097 SV_SetOnGround (ent);
1098 SV_CheckVelocity(ent);
1101 //============================================================================
1107 Entities that are "stuck" to another entity
1110 void SV_Physics_Follow (edict_t *ent)
1112 vec3_t vf, vr, vu, angles, v;
1116 if (!SV_RunThink (ent))
1119 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1120 e = PROG_TO_EDICT(ent->v->aiment);
1121 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])
1123 // quick case for no rotation
1124 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1128 angles[0] = -ent->v->punchangle[0];
1129 angles[1] = ent->v->punchangle[1];
1130 angles[2] = ent->v->punchangle[2];
1131 AngleVectors (angles, vf, vr, vu);
1132 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1133 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1134 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1135 angles[0] = -e->v->angles[0];
1136 angles[1] = e->v->angles[1];
1137 angles[2] = e->v->angles[2];
1138 AngleVectors (angles, vf, vr, vu);
1139 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1140 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1141 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1143 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1144 SV_LinkEdict (ent, true);
1148 ==============================================================================
1152 ==============================================================================
1157 SV_CheckWaterTransition
1161 void SV_CheckWaterTransition (edict_t *ent)
1164 cont = SV_PointQ1Contents(ent->v->origin);
1165 if (!ent->v->watertype)
1167 // just spawned here
1168 ent->v->watertype = cont;
1169 ent->v->waterlevel = 1;
1173 // check if the entity crossed into or out of water
1174 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1175 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1177 if (cont <= CONTENTS_WATER)
1179 ent->v->watertype = cont;
1180 ent->v->waterlevel = 1;
1184 ent->v->watertype = CONTENTS_EMPTY;
1185 ent->v->waterlevel = 0;
1193 Toss, bounce, and fly movement. When onground, do nothing.
1196 void SV_Physics_Toss (edict_t *ent)
1200 edict_t *groundentity;
1202 // don't stick to ground if onground and moving upward
1203 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1204 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1206 // if onground, return without moving
1207 if ((int)ent->v->flags & FL_ONGROUND)
1209 if (!sv_gameplayfix_noairborncorpse.integer)
1211 if (ent->v->groundentity == 0)
1213 // if ent was supported by a brush model on previous frame,
1214 // and groundentity is now freed, set groundentity to 0 (floating)
1215 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1216 if (groundentity->v->solid == SOLID_BSP)
1218 ent->e->suspendedinairflag = true;
1221 else if (ent->e->suspendedinairflag && groundentity->e->free)
1223 // leave it suspended in the air
1224 ent->v->groundentity = 0;
1225 ent->e->suspendedinairflag = false;
1229 ent->e->suspendedinairflag = false;
1231 SV_CheckVelocity (ent);
1234 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1235 SV_AddGravity (ent);
1238 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1241 VectorScale (ent->v->velocity, sv.frametime, move);
1242 trace = SV_PushEntity (ent, move);
1246 if (trace.fraction < 1)
1248 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1250 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1251 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1253 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1256 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1257 // LordHavoc: fixed grenades not bouncing when fired down a slope
1258 if (sv_gameplayfix_grenadebouncedownslopes.integer)
1260 d = DotProduct(trace.plane.normal, ent->v->velocity);
1261 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1263 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1264 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1265 VectorClear (ent->v->velocity);
1266 VectorClear (ent->v->avelocity);
1269 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1273 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
1275 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1276 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1277 VectorClear (ent->v->velocity);
1278 VectorClear (ent->v->avelocity);
1281 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1286 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1287 if (trace.plane.normal[2] > 0.7)
1289 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1290 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1291 VectorClear (ent->v->velocity);
1292 VectorClear (ent->v->avelocity);
1295 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1299 // check for in water
1300 SV_CheckWaterTransition (ent);
1304 ===============================================================================
1308 ===============================================================================
1315 Monsters freefall when they don't have a ground entity, otherwise
1316 all movement is done with discrete steps.
1318 This is also used for objects that have become still on the ground, but
1319 will fall if the floor is pulled out from under them.
1322 void SV_Physics_Step (edict_t *ent)
1324 // don't stick to ground if onground and moving upward
1325 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1326 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1328 // freefall if not onground/fly/swim
1329 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1331 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1334 SV_CheckVelocity(ent);
1335 SV_FlyMove(ent, sv.frametime, NULL);
1336 SV_LinkEdict(ent, true);
1339 if (hitsound && (int)ent->v->flags & FL_ONGROUND && gamemode != GAME_NEXUIZ)
1340 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1346 SV_CheckWaterTransition(ent);
1349 //============================================================================
1357 void SV_Physics (void)
1359 int i, newnum_edicts;
1361 qbyte runmove[MAX_EDICTS];
1363 // let the progs know that a new frame has started
1364 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1365 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1366 pr_global_struct->time = sv.time;
1367 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1370 for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1371 if ((runmove[i] = !ent->e->free))
1372 newnum_edicts = i + 1;
1373 sv.num_edicts = max(svs.maxclients + 1, newnum_edicts);
1376 // treat each object in turn
1379 for (i = 0, ent = sv.edicts;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))
1384 if (pr_global_struct->force_retouch)
1385 SV_LinkEdict (ent, true); // force retouch even for stationary
1387 if (i >= 1 && i <= svs.maxclients)
1389 // don't do physics on disconnected clients, FrikBot relies on this
1390 if (!svs.clients[i-1].spawned)
1393 // call standard client pre-think
1394 SV_CheckVelocity (ent);
1395 pr_global_struct->time = sv.time;
1396 pr_global_struct->self = EDICT_TO_PROG(ent);
1397 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1398 SV_CheckVelocity (ent);
1400 else if (sv_freezenonclients.integer)
1403 // LordHavoc: merged client and normal entity physics
1404 switch ((int) ent->v->movetype)
1407 case MOVETYPE_FAKEPUSH:
1408 SV_Physics_Pusher (ent);
1411 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1412 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1415 case MOVETYPE_FOLLOW:
1416 SV_Physics_Follow (ent);
1418 case MOVETYPE_NOCLIP:
1419 if (SV_RunThink(ent))
1422 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1423 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1425 // relink normal entities here, players always get relinked so don't relink twice
1426 if (!(i > 0 && i <= svs.maxclients))
1427 SV_LinkEdict(ent, false);
1430 SV_Physics_Step (ent);
1433 if (SV_RunThink (ent))
1435 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1436 SV_AddGravity (ent);
1437 SV_CheckStuck (ent);
1439 // relink normal entities here, players always get relinked so don't relink twice
1440 if (!(i > 0 && i <= svs.maxclients))
1441 SV_LinkEdict (ent, true);
1445 case MOVETYPE_BOUNCE:
1446 case MOVETYPE_BOUNCEMISSILE:
1447 case MOVETYPE_FLYMISSILE:
1449 if (SV_RunThink (ent) && runmove[i])
1450 SV_Physics_Toss (ent);
1453 if (SV_RunThink (ent) && runmove[i])
1455 if (i > 0 && i <= svs.maxclients)
1457 SV_CheckWater (ent);
1461 SV_Physics_Toss (ent);
1465 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1469 if (i >= 1 && i <= svs.maxclients)
1471 SV_CheckVelocity (ent);
1473 // call standard player post-think
1474 SV_LinkEdict (ent, true);
1476 SV_CheckVelocity (ent);
1478 pr_global_struct->time = sv.time;
1479 pr_global_struct->self = EDICT_TO_PROG(ent);
1480 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1484 if (pr_global_struct->force_retouch > 0)
1485 pr_global_struct->force_retouch = max(0, pr_global_struct->force_retouch - 1);
1487 // LordHavoc: endframe support
1490 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1491 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1492 pr_global_struct->time = sv.time;
1493 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1496 if (!sv_freezenonclients.integer)
1497 sv.time += sv.frametime;
1501 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1504 float gravity, savesolid;
1506 edict_t tempent, *tent;
1511 // copy the vars over
1512 memcpy(&vars, tossent->v, sizeof(entvars_t));
1513 // set up the temp entity to point to the copied vars
1517 savesolid = tossent->v->solid;
1518 tossent->v->solid = SOLID_NOT;
1520 // this has to fetch the field from the original edict, since our copy is truncated
1521 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1522 if (val != NULL && val->_float != 0)
1523 gravity = val->_float;
1526 gravity *= sv_gravity.value * 0.05;
1528 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1530 SV_CheckVelocity (tent);
1531 tent->v->velocity[2] -= gravity;
1532 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1533 VectorScale (tent->v->velocity, 0.05, move);
1534 VectorAdd (tent->v->origin, move, end);
1535 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1536 VectorCopy (trace.endpos, tent->v->origin);
1538 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1541 tossent->v->solid = savesolid;
1542 trace.fraction = 0; // not relevant