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 model_t *pushermodel;
569 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])
571 pusher->v->ltime += movetime;
575 switch ((int) pusher->v->solid)
577 // LordHavoc: valid pusher types
581 case SOLID_CORPSE: // LordHavoc: this would be weird...
583 // LordHavoc: no collisions
586 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
587 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
588 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
589 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
590 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
591 pusher->v->ltime += movetime;
592 SV_LinkEdict (pusher, false);
595 Con_Printf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
598 index = (int) pusher->v->modelindex;
599 if (index < 1 || index >= MAX_MODELS)
601 Con_Printf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
604 pushermodel = sv.models[index];
606 movetime2 = movetime;
607 VectorScale(pusher->v->velocity, movetime2, move1);
608 VectorScale(pusher->v->avelocity, movetime2, moveangle);
609 if (moveangle[0] || moveangle[2])
611 for (i = 0;i < 3;i++)
615 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
616 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
620 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
621 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
625 else if (moveangle[1])
627 for (i = 0;i < 3;i++)
631 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
632 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
636 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
637 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
643 for (i = 0;i < 3;i++)
647 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
648 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
652 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
653 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
658 VectorNegate (moveangle, a);
659 AngleVectorsFLU (a, forward, left, up);
661 VectorCopy (pusher->v->origin, pushorig);
662 VectorCopy (pusher->v->angles, pushang);
663 pushltime = pusher->v->ltime;
665 // move the pusher to it's final position
667 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
668 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
669 pusher->v->ltime += movetime;
670 SV_LinkEdict (pusher, false);
672 savesolid = pusher->v->solid;
674 // see if any solid entities are inside the final position
676 check = NEXT_EDICT(sv.edicts);
677 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
681 if (check->v->movetype == MOVETYPE_PUSH
682 || check->v->movetype == MOVETYPE_NONE
683 || check->v->movetype == MOVETYPE_FOLLOW
684 || check->v->movetype == MOVETYPE_NOCLIP
685 || check->v->movetype == MOVETYPE_FAKEPUSH)
688 // if the entity is standing on the pusher, it will definitely be moved
689 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
691 if (check->v->absmin[0] >= maxs[0]
692 || check->v->absmax[0] <= mins[0]
693 || check->v->absmin[1] >= maxs[1]
694 || check->v->absmax[1] <= mins[1]
695 || check->v->absmin[2] >= maxs[2]
696 || check->v->absmax[2] <= mins[2])
699 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
703 if (forward[0] != 1) // quick way to check if any rotation is used
705 VectorSubtract (check->v->origin, pusher->v->origin, org);
706 org2[0] = DotProduct (org, forward);
707 org2[1] = DotProduct (org, left);
708 org2[2] = DotProduct (org, up);
709 VectorSubtract (org2, org, move);
710 VectorAdd (move, move1, move);
713 VectorCopy (move1, move);
715 // remove the onground flag for non-players
716 if (check->v->movetype != MOVETYPE_WALK)
717 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
719 VectorCopy (check->v->origin, check->e->moved_from);
720 VectorCopy (check->v->angles, check->e->moved_fromangles);
721 sv.moved_edicts[num_moved++] = check;
723 // try moving the contacted entity
724 pusher->v->solid = SOLID_NOT;
725 trace = SV_PushEntity (check, move);
726 // FIXME: turn players specially
727 check->v->angles[1] += trace.fraction * moveangle[1];
728 pusher->v->solid = savesolid; // was SOLID_BSP
730 // if it is still inside the pusher, block
731 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
733 // try moving the contacted entity a tiny bit further to account for precision errors
734 pusher->v->solid = SOLID_NOT;
735 VectorScale(move, 0.1, move);
736 SV_PushEntity (check, move);
737 pusher->v->solid = savesolid;
738 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
740 // still inside pusher, so it's really blocked
743 if (check->v->mins[0] == check->v->maxs[0])
745 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
748 check->v->mins[0] = check->v->mins[1] = 0;
749 VectorCopy (check->v->mins, check->v->maxs);
753 VectorCopy (pushorig, pusher->v->origin);
754 VectorCopy (pushang, pusher->v->angles);
755 pusher->v->ltime = pushltime;
756 SV_LinkEdict (pusher, false);
758 // move back any entities we already moved
759 for (i = 0;i < num_moved;i++)
761 ed = sv.moved_edicts[i];
762 VectorCopy (ed->e->moved_from, ed->v->origin);
763 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
764 SV_LinkEdict (ed, false);
767 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
768 if (pusher->v->blocked)
770 pr_global_struct->self = EDICT_TO_PROG(pusher);
771 pr_global_struct->other = EDICT_TO_PROG(check);
772 PR_ExecuteProgram (pusher->v->blocked, "QC function self.blocked is missing");
778 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
779 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
780 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
789 void SV_Physics_Pusher (edict_t *ent)
791 float thinktime, oldltime, movetime;
793 oldltime = ent->v->ltime;
795 thinktime = ent->v->nextthink;
796 if (thinktime < ent->v->ltime + sv.frametime)
798 movetime = thinktime - ent->v->ltime;
803 movetime = sv.frametime;
806 // advances ent->v->ltime if not blocked
807 SV_PushMove (ent, movetime);
809 if (thinktime > oldltime && thinktime <= ent->v->ltime)
811 ent->v->nextthink = 0;
812 pr_global_struct->time = sv.time;
813 pr_global_struct->self = EDICT_TO_PROG(ent);
814 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
815 PR_ExecuteProgram (ent->v->think, "QC function self.think is missing");
821 ===============================================================================
825 ===============================================================================
832 This is a big hack to try and fix the rare case of getting stuck in the world
836 void SV_CheckStuck (edict_t *ent)
841 if (!SV_TestEntityPosition(ent))
843 VectorCopy (ent->v->origin, ent->v->oldorigin);
847 VectorCopy (ent->v->origin, org);
848 VectorCopy (ent->v->oldorigin, ent->v->origin);
849 if (!SV_TestEntityPosition(ent))
851 Con_DPrint("Unstuck.\n");
852 SV_LinkEdict (ent, true);
856 for (z=0 ; z< 18 ; z++)
857 for (i=-1 ; i <= 1 ; i++)
858 for (j=-1 ; j <= 1 ; j++)
860 ent->v->origin[0] = org[0] + i;
861 ent->v->origin[1] = org[1] + j;
862 ent->v->origin[2] = org[2] + z;
863 if (!SV_TestEntityPosition(ent))
865 Con_DPrint("Unstuck.\n");
866 SV_LinkEdict (ent, true);
871 VectorCopy (org, ent->v->origin);
872 Con_DPrint("player is stuck.\n");
881 qboolean SV_CheckWater (edict_t *ent)
886 point[0] = ent->v->origin[0];
887 point[1] = ent->v->origin[1];
888 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
890 ent->v->waterlevel = 0;
891 ent->v->watertype = CONTENTS_EMPTY;
892 cont = SV_PointQ1Contents(point);
893 if (cont <= CONTENTS_WATER)
895 ent->v->watertype = cont;
896 ent->v->waterlevel = 1;
897 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
898 cont = SV_PointQ1Contents(point);
899 if (cont <= CONTENTS_WATER)
901 ent->v->waterlevel = 2;
902 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
903 cont = SV_PointQ1Contents(point);
904 if (cont <= CONTENTS_WATER)
905 ent->v->waterlevel = 3;
909 return ent->v->waterlevel > 1;
918 void SV_WallFriction (edict_t *ent, float *stepnormal)
921 vec3_t forward, into, side;
923 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
924 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
926 // cut the tangential velocity
927 i = DotProduct (stepnormal, ent->v->velocity);
928 VectorScale (stepnormal, i, into);
929 VectorSubtract (ent->v->velocity, into, side);
930 ent->v->velocity[0] = side[0] * (1 + d);
931 ent->v->velocity[1] = side[1] * (1 + d);
936 =====================
939 Player has come to a dead stop, possibly due to the problem with limited
940 float precision at some angle joins in the BSP hull.
942 Try fixing by pushing one pixel in each direction.
944 This is a hack, but in the interest of good gameplay...
945 ======================
947 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
952 VectorCopy (ent->v->origin, oldorg);
955 for (i=0 ; i<8 ; i++)
957 // try pushing a little in an axial direction
960 case 0: dir[0] = 2; dir[1] = 0; break;
961 case 1: dir[0] = 0; dir[1] = 2; break;
962 case 2: dir[0] = -2; dir[1] = 0; break;
963 case 3: dir[0] = 0; dir[1] = -2; break;
964 case 4: dir[0] = 2; dir[1] = 2; break;
965 case 5: dir[0] = -2; dir[1] = 2; break;
966 case 6: dir[0] = 2; dir[1] = -2; break;
967 case 7: dir[0] = -2; dir[1] = -2; break;
970 SV_PushEntity (ent, dir);
972 // retry the original move
973 ent->v->velocity[0] = oldvel[0];
974 ent->v->velocity[1] = oldvel[1];
975 ent->v->velocity[2] = 0;
976 clip = SV_FlyMove (ent, 0.1, NULL);
978 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
979 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
981 Con_DPrint("TryUnstick - success.\n");
985 // go back to the original pos and try again
986 VectorCopy (oldorg, ent->v->origin);
990 VectorClear (ent->v->velocity);
991 Con_DPrint("TryUnstick - failure.\n");
996 =====================
1000 ======================
1002 void SV_WalkMove (edict_t *ent)
1004 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
1005 vec3_t upmove, downmove, start_origin, start_velocity, stepnormal, originalmove_origin, originalmove_velocity;
1008 SV_CheckVelocity(ent);
1010 // do a regular slide move unless it looks like you ran into a step
1011 oldonground = (int)ent->v->flags & FL_ONGROUND;
1012 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1014 VectorCopy (ent->v->origin, start_origin);
1015 VectorCopy (ent->v->velocity, start_velocity);
1017 clip = SV_FlyMove (ent, sv.frametime, NULL);
1019 SV_SetOnGround (ent);
1020 SV_CheckVelocity(ent);
1022 VectorCopy(ent->v->origin, originalmove_origin);
1023 VectorCopy(ent->v->velocity, originalmove_velocity);
1024 originalmove_clip = clip;
1025 originalmove_flags = (int)ent->v->flags;
1026 originalmove_groundentity = ent->v->groundentity;
1028 if ((int)ent->v->flags & FL_WATERJUMP)
1031 if (sv_nostep.integer)
1034 // if move didn't block on a step, return
1037 // if move was not trying to move into the step, return
1038 if (fabs(start_velocity[0]) < 0.03125 && fabs(start_velocity[1]) < 0.03125)
1041 if (ent->v->movetype != MOVETYPE_FLY)
1043 // return if gibbed by a trigger
1044 if (ent->v->movetype != MOVETYPE_WALK)
1047 // only step up while jumping if that is enabled
1048 if (!(sv_jumpstep.integer && sv_gameplayfix_stepwhilejumping.integer))
1049 if (!oldonground && ent->v->waterlevel == 0)
1053 // try moving up and forward to go up a step
1054 // back to start pos
1055 VectorCopy (start_origin, ent->v->origin);
1056 VectorCopy (start_velocity, ent->v->velocity);
1059 VectorClear (upmove);
1060 upmove[2] = sv_stepheight.value;
1061 // FIXME: don't link?
1062 SV_PushEntity(ent, upmove);
1065 ent->v->velocity[2] = 0;
1066 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1067 ent->v->velocity[2] += start_velocity[2];
1069 SV_CheckVelocity(ent);
1071 // check for stuckness, possibly due to the limited precision of floats
1072 // in the clipping hulls
1074 && fabs(originalmove_origin[1] - ent->v->origin[1]) < 0.03125
1075 && fabs(originalmove_origin[0] - ent->v->origin[0]) < 0.03125)
1077 //Con_Printf("wall\n");
1078 // stepping up didn't make any progress, revert to original move
1079 VectorCopy(originalmove_origin, ent->v->origin);
1080 VectorCopy(originalmove_velocity, ent->v->velocity);
1081 //clip = originalmove_clip;
1082 ent->v->flags = originalmove_flags;
1083 ent->v->groundentity = originalmove_groundentity;
1084 // now try to unstick if needed
1085 //clip = SV_TryUnstick (ent, oldvel);
1089 //Con_Printf("step - ");
1091 // extra friction based on view angle
1092 if (clip & 2 && sv_wallfriction.integer)
1093 SV_WallFriction (ent, stepnormal);
1095 // skip out if stepdown is enabled, moving downward, not in water, and the move started onground and ended offground
1096 else if (!(sv_gameplayfix_stepdown.integer && ent->v->waterlevel < 2 && start_velocity[2] < (1.0 / 32.0) && oldonground && !((int)ent->v->flags & FL_ONGROUND)))
1100 VectorClear (downmove);
1101 downmove[2] = -sv_stepheight.value + start_velocity[2]*sv.frametime;
1102 // FIXME: don't link?
1103 downtrace = SV_PushEntity (ent, downmove);
1105 if (downtrace.fraction < 1 && downtrace.plane.normal[2] > 0.7)
1107 // LordHavoc: disabled this check so you can walk on monsters/players
1108 //if (ent->v->solid == SOLID_BSP)
1110 //Con_Printf("onground\n");
1111 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1112 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1117 //Con_Printf("slope\n");
1118 // if the push down didn't end up on good ground, use the move without
1119 // the step up. This happens near wall / slope combinations, and can
1120 // cause the player to hop up higher on a slope too steep to climb
1121 VectorCopy(originalmove_origin, ent->v->origin);
1122 VectorCopy(originalmove_velocity, ent->v->velocity);
1123 //clip = originalmove_clip;
1124 ent->v->flags = originalmove_flags;
1125 ent->v->groundentity = originalmove_groundentity;
1128 SV_SetOnGround (ent);
1129 SV_CheckVelocity(ent);
1132 //============================================================================
1138 Entities that are "stuck" to another entity
1141 void SV_Physics_Follow (edict_t *ent)
1143 vec3_t vf, vr, vu, angles, v;
1147 if (!SV_RunThink (ent))
1150 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1151 e = PROG_TO_EDICT(ent->v->aiment);
1152 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])
1154 // quick case for no rotation
1155 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1159 angles[0] = -ent->v->punchangle[0];
1160 angles[1] = ent->v->punchangle[1];
1161 angles[2] = ent->v->punchangle[2];
1162 AngleVectors (angles, vf, vr, vu);
1163 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1164 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1165 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1166 angles[0] = -e->v->angles[0];
1167 angles[1] = e->v->angles[1];
1168 angles[2] = e->v->angles[2];
1169 AngleVectors (angles, vf, vr, vu);
1170 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1171 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1172 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1174 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1175 SV_LinkEdict (ent, true);
1179 ==============================================================================
1183 ==============================================================================
1188 SV_CheckWaterTransition
1192 void SV_CheckWaterTransition (edict_t *ent)
1195 cont = SV_PointQ1Contents(ent->v->origin);
1196 if (!ent->v->watertype)
1198 // just spawned here
1199 ent->v->watertype = cont;
1200 ent->v->waterlevel = 1;
1204 // check if the entity crossed into or out of water
1205 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1206 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1208 if (cont <= CONTENTS_WATER)
1210 ent->v->watertype = cont;
1211 ent->v->waterlevel = 1;
1215 ent->v->watertype = CONTENTS_EMPTY;
1216 ent->v->waterlevel = 0;
1224 Toss, bounce, and fly movement. When onground, do nothing.
1227 void SV_Physics_Toss (edict_t *ent)
1231 edict_t *groundentity;
1234 if (!SV_RunThink (ent))
1237 // don't stick to ground if onground and moving upward
1238 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1239 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1241 // if onground, return without moving
1242 if ((int)ent->v->flags & FL_ONGROUND)
1244 if (!sv_gameplayfix_noairborncorpse.integer)
1246 if (ent->v->groundentity == 0)
1248 // if ent was supported by a brush model on previous frame,
1249 // and groundentity is now freed, set groundentity to 0 (floating)
1250 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1251 if (groundentity->v->solid == SOLID_BSP)
1253 ent->e->suspendedinairflag = true;
1256 else if (ent->e->suspendedinairflag && groundentity->e->free)
1258 // leave it suspended in the air
1259 ent->v->groundentity = 0;
1260 ent->e->suspendedinairflag = false;
1264 ent->e->suspendedinairflag = false;
1266 SV_CheckVelocity (ent);
1269 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1270 SV_AddGravity (ent);
1273 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1276 VectorScale (ent->v->velocity, sv.frametime, move);
1277 trace = SV_PushEntity (ent, move);
1281 if (trace.fraction < 1)
1283 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1285 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1286 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1288 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1291 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1292 // LordHavoc: fixed grenades not bouncing when fired down a slope
1293 if (sv_gameplayfix_grenadebouncedownslopes.integer)
1295 d = DotProduct(trace.plane.normal, ent->v->velocity);
1296 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1298 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1299 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1300 VectorClear (ent->v->velocity);
1301 VectorClear (ent->v->avelocity);
1304 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1308 if (trace.plane.normal[2] > 0.7 && ent->v->velocity[2] < 60)
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;
1321 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1322 if (trace.plane.normal[2] > 0.7)
1324 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1325 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1326 VectorClear (ent->v->velocity);
1327 VectorClear (ent->v->avelocity);
1330 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1334 // check for in water
1335 SV_CheckWaterTransition (ent);
1339 ===============================================================================
1343 ===============================================================================
1350 Monsters freefall when they don't have a ground entity, otherwise
1351 all movement is done with discrete steps.
1353 This is also used for objects that have become still on the ground, but
1354 will fall if the floor is pulled out from under them.
1357 void SV_Physics_Step (edict_t *ent)
1359 // don't stick to ground if onground and moving upward
1360 if (ent->v->velocity[2] >= (1.0 / 32.0) && ((int)ent->v->flags & FL_ONGROUND))
1361 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1363 // freefall if not onground/fly/swim
1364 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1366 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1369 SV_CheckVelocity(ent);
1370 SV_FlyMove(ent, sv.frametime, NULL);
1371 SV_LinkEdict(ent, true);
1374 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1375 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1381 SV_CheckWaterTransition(ent);
1384 //============================================================================
1392 void SV_Physics (void)
1397 // let the progs know that a new frame has started
1398 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1399 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1400 pr_global_struct->time = sv.time;
1401 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1404 // treat each object in turn
1407 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1412 if (pr_global_struct->force_retouch)
1413 SV_LinkEdict (ent, true); // force retouch even for stationary
1415 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1418 // call standard client pre-think
1419 SV_CheckVelocity (ent);
1420 pr_global_struct->time = sv.time;
1421 pr_global_struct->self = EDICT_TO_PROG(ent);
1422 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1423 SV_CheckVelocity (ent);
1425 else if (sv_freezenonclients.integer)
1428 // LordHavoc: merged client and normal entity physics
1429 switch ((int) ent->v->movetype)
1432 case MOVETYPE_FAKEPUSH:
1433 SV_Physics_Pusher (ent);
1436 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1437 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1440 case MOVETYPE_FOLLOW:
1441 SV_Physics_Follow (ent);
1443 case MOVETYPE_NOCLIP:
1444 if (SV_RunThink(ent))
1447 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1448 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1450 // relink normal entities here, players always get relinked so don't relink twice
1451 if (!(i > 0 && i <= svs.maxclients))
1452 SV_LinkEdict(ent, false);
1455 SV_Physics_Step (ent);
1458 if (SV_RunThink (ent))
1460 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1461 SV_AddGravity (ent);
1462 SV_CheckStuck (ent);
1464 // relink normal entities here, players always get relinked so don't relink twice
1465 if (!(i > 0 && i <= svs.maxclients))
1466 SV_LinkEdict (ent, true);
1470 case MOVETYPE_BOUNCE:
1471 case MOVETYPE_BOUNCEMISSILE:
1472 case MOVETYPE_FLYMISSILE:
1473 SV_Physics_Toss (ent);
1476 if (i > 0 && i <= svs.maxclients)
1478 if (SV_RunThink (ent))
1480 SV_CheckWater (ent);
1485 SV_Physics_Toss (ent);
1488 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1492 if (i >= 1 && i <= svs.maxclients && svs.clients[i-1].spawned)
1494 SV_CheckVelocity (ent);
1496 // call standard player post-think
1497 SV_LinkEdict (ent, true);
1499 SV_CheckVelocity (ent);
1501 pr_global_struct->time = sv.time;
1502 pr_global_struct->self = EDICT_TO_PROG(ent);
1503 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1507 if (pr_global_struct->force_retouch)
1508 pr_global_struct->force_retouch--;
1510 // LordHavoc: endframe support
1513 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1514 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1515 pr_global_struct->time = sv.time;
1516 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "QC function EndFrame is missing");
1519 if (!sv_freezenonclients.integer)
1520 sv.time += sv.frametime;
1524 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1527 float gravity, savesolid;
1529 edict_t tempent, *tent;
1534 // copy the vars over
1535 memcpy(&vars, tossent->v, sizeof(entvars_t));
1536 // set up the temp entity to point to the copied vars
1540 savesolid = tossent->v->solid;
1541 tossent->v->solid = SOLID_NOT;
1543 // this has to fetch the field from the original edict, since our copy is truncated
1544 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1545 if (val != NULL && val->_float != 0)
1546 gravity = val->_float;
1549 gravity *= sv_gravity.value * 0.05;
1551 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1553 SV_CheckVelocity (tent);
1554 tent->v->velocity[2] -= gravity;
1555 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1556 VectorScale (tent->v->velocity, 0.05, move);
1557 VectorAdd (tent->v->origin, move, end);
1558 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1559 VectorCopy (trace.endpos, tent->v->origin);
1561 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1564 tossent->v->solid = savesolid;
1565 trace.fraction = 0; // not relevant