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, "NULL think function");
159 return !ent->e->free;
166 Two entities have touched, so run their touch functions
169 void SV_Impact (edict_t *e1, edict_t *e2)
171 int old_self, old_other;
173 old_self = pr_global_struct->self;
174 old_other = pr_global_struct->other;
176 pr_global_struct->time = sv.time;
177 if (e1->v->touch && e1->v->solid != SOLID_NOT)
179 pr_global_struct->self = EDICT_TO_PROG(e1);
180 pr_global_struct->other = EDICT_TO_PROG(e2);
181 PR_ExecuteProgram (e1->v->touch, "");
184 if (e2->v->touch && e2->v->solid != SOLID_NOT)
186 pr_global_struct->self = EDICT_TO_PROG(e2);
187 pr_global_struct->other = EDICT_TO_PROG(e1);
188 PR_ExecuteProgram (e2->v->touch, "");
191 pr_global_struct->self = old_self;
192 pr_global_struct->other = old_other;
200 Slide off of the impacting object
201 returns the blocked flags (1 = floor, 2 = step / wall)
204 #define STOP_EPSILON 0.1
205 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
210 backoff = -DotProduct (in, normal) * overbounce;
211 VectorMA(in, backoff, normal, out);
213 for (i = 0;i < 3;i++)
214 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
223 The basic solid body movement clip that slides along multiple planes
224 Returns the clipflags if the velocity was modified (hit something solid)
228 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
231 // LordHavoc: increased from 5 to 20
232 #define MAX_CLIP_PLANES 20
233 int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
235 int blocked, bumpcount;
236 edict_t *hackongroundentity;
237 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);
481 void SV_AddGravity (edict_t *ent)
486 val = GETEDICTFIELDVALUE(ent, eval_gravity);
487 if (val!=0 && val->_float)
488 ent_gravity = val->_float;
491 ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
496 ===============================================================================
500 ===============================================================================
507 Does not change the entities velocity at all
510 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
515 VectorAdd (ent->v->origin, push, end);
517 if (ent->v->movetype == MOVETYPE_FLYMISSILE)
518 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE, ent);
519 else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
520 // only clip against bmodels
521 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, ent);
523 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
525 VectorCopy (trace.endpos, ent->v->origin);
526 // FIXME: turn players specially
527 ent->v->angles[1] += trace.fraction * pushangles[1];
528 SV_LinkEdict (ent, true);
530 if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
531 SV_Impact (ent, trace.ent);
542 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
543 void SV_PushMove (edict_t *pusher, float movetime)
547 float savesolid, movetime2, pushltime;
548 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
550 model_t *pushermodel;
552 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])
554 pusher->v->ltime += movetime;
558 switch ((int) pusher->v->solid)
560 // LordHavoc: valid pusher types
564 case SOLID_CORPSE: // LordHavoc: this would be weird...
566 // LordHavoc: no collisions
569 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
570 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
571 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
572 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
573 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
574 pusher->v->ltime += movetime;
575 SV_LinkEdict (pusher, false);
578 Con_DPrintf("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
581 index = (int) pusher->v->modelindex;
582 if (index < 1 || index >= MAX_MODELS)
584 Con_DPrintf("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
587 pushermodel = sv.models[index];
589 movetime2 = movetime;
590 VectorScale(pusher->v->velocity, movetime2, move1);
591 VectorScale(pusher->v->avelocity, movetime2, moveangle);
592 if (moveangle[0] || moveangle[2])
594 for (i = 0;i < 3;i++)
598 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
599 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
603 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
604 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
608 else if (moveangle[1])
610 for (i = 0;i < 3;i++)
614 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
615 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
619 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
620 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
626 for (i = 0;i < 3;i++)
630 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
631 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
635 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
636 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
641 VectorNegate (moveangle, a);
642 AngleVectorsFLU (a, forward, left, up);
644 VectorCopy (pusher->v->origin, pushorig);
645 VectorCopy (pusher->v->angles, pushang);
646 pushltime = pusher->v->ltime;
648 // move the pusher to it's final position
650 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
651 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
652 pusher->v->ltime += movetime;
653 SV_LinkEdict (pusher, false);
655 savesolid = pusher->v->solid;
657 // see if any solid entities are inside the final position
659 check = NEXT_EDICT(sv.edicts);
660 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
664 if (check->v->movetype == MOVETYPE_PUSH
665 || check->v->movetype == MOVETYPE_NONE
666 || check->v->movetype == MOVETYPE_FOLLOW
667 || check->v->movetype == MOVETYPE_NOCLIP
668 || check->v->movetype == MOVETYPE_FAKEPUSH)
671 // if the entity is standing on the pusher, it will definitely be moved
672 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
674 if (check->v->absmin[0] >= maxs[0]
675 || check->v->absmax[0] <= mins[0]
676 || check->v->absmin[1] >= maxs[1]
677 || check->v->absmax[1] <= mins[1]
678 || check->v->absmin[2] >= maxs[2]
679 || check->v->absmax[2] <= mins[2])
682 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
686 if (forward[0] != 1) // quick way to check if any rotation is used
688 VectorSubtract (check->v->origin, pusher->v->origin, org);
689 org2[0] = DotProduct (org, forward);
690 org2[1] = DotProduct (org, left);
691 org2[2] = DotProduct (org, up);
692 VectorSubtract (org2, org, move);
693 VectorAdd (move, move1, move);
696 VectorCopy (move1, move);
698 // remove the onground flag for non-players
699 if (check->v->movetype != MOVETYPE_WALK)
700 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
702 VectorCopy (check->v->origin, check->e->moved_from);
703 VectorCopy (check->v->angles, check->e->moved_fromangles);
704 sv.moved_edicts[num_moved++] = check;
706 // try moving the contacted entity
707 pusher->v->solid = SOLID_NOT;
708 SV_PushEntity (check, move, moveangle);
709 pusher->v->solid = savesolid; // was SOLID_BSP
711 // if it is still inside the pusher, block
712 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
714 // try moving the contacted entity a tiny bit further to account for precision errors
715 pusher->v->solid = SOLID_NOT;
716 VectorScale(move, 0.1, move);
717 SV_PushEntity (check, move, vec3_origin);
718 pusher->v->solid = savesolid;
719 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
721 // still inside pusher, so it's really blocked
724 if (check->v->mins[0] == check->v->maxs[0])
726 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
729 check->v->mins[0] = check->v->mins[1] = 0;
730 VectorCopy (check->v->mins, check->v->maxs);
734 VectorCopy (pushorig, pusher->v->origin);
735 VectorCopy (pushang, pusher->v->angles);
736 pusher->v->ltime = pushltime;
737 SV_LinkEdict (pusher, false);
739 // move back any entities we already moved
740 for (i = 0;i < num_moved;i++)
742 ed = sv.moved_edicts[i];
743 VectorCopy (ed->e->moved_from, ed->v->origin);
744 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
745 SV_LinkEdict (ed, false);
748 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
749 if (pusher->v->blocked)
751 pr_global_struct->self = EDICT_TO_PROG(pusher);
752 pr_global_struct->other = EDICT_TO_PROG(check);
753 PR_ExecuteProgram (pusher->v->blocked, "");
759 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
760 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
761 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
770 void SV_Physics_Pusher (edict_t *ent)
772 float thinktime, oldltime, movetime;
774 oldltime = ent->v->ltime;
776 thinktime = ent->v->nextthink;
777 if (thinktime < ent->v->ltime + sv.frametime)
779 movetime = thinktime - ent->v->ltime;
784 movetime = sv.frametime;
787 // advances ent->v->ltime if not blocked
788 SV_PushMove (ent, movetime);
790 if (thinktime > oldltime && thinktime <= ent->v->ltime)
792 ent->v->nextthink = 0;
793 pr_global_struct->time = sv.time;
794 pr_global_struct->self = EDICT_TO_PROG(ent);
795 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
796 PR_ExecuteProgram (ent->v->think, "NULL think function");
802 ===============================================================================
806 ===============================================================================
813 This is a big hack to try and fix the rare case of getting stuck in the world
817 void SV_CheckStuck (edict_t *ent)
822 if (!SV_TestEntityPosition(ent))
824 VectorCopy (ent->v->origin, ent->v->oldorigin);
828 VectorCopy (ent->v->origin, org);
829 VectorCopy (ent->v->oldorigin, ent->v->origin);
830 if (!SV_TestEntityPosition(ent))
832 Con_DPrint("Unstuck.\n");
833 SV_LinkEdict (ent, true);
837 for (z=0 ; z< 18 ; z++)
838 for (i=-1 ; i <= 1 ; i++)
839 for (j=-1 ; j <= 1 ; j++)
841 ent->v->origin[0] = org[0] + i;
842 ent->v->origin[1] = org[1] + j;
843 ent->v->origin[2] = org[2] + z;
844 if (!SV_TestEntityPosition(ent))
846 Con_DPrint("Unstuck.\n");
847 SV_LinkEdict (ent, true);
852 VectorCopy (org, ent->v->origin);
853 Con_DPrint("player is stuck.\n");
862 qboolean SV_CheckWater (edict_t *ent)
867 point[0] = ent->v->origin[0];
868 point[1] = ent->v->origin[1];
869 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
871 ent->v->waterlevel = 0;
872 ent->v->watertype = CONTENTS_EMPTY;
873 cont = SV_PointQ1Contents(point);
874 if (cont <= CONTENTS_WATER)
876 ent->v->watertype = cont;
877 ent->v->waterlevel = 1;
878 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
879 cont = SV_PointQ1Contents(point);
880 if (cont <= CONTENTS_WATER)
882 ent->v->waterlevel = 2;
883 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
884 cont = SV_PointQ1Contents(point);
885 if (cont <= CONTENTS_WATER)
886 ent->v->waterlevel = 3;
890 return ent->v->waterlevel > 1;
899 void SV_WallFriction (edict_t *ent, float *stepnormal)
902 vec3_t forward, into, side;
904 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
905 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
907 // cut the tangential velocity
908 i = DotProduct (stepnormal, ent->v->velocity);
909 VectorScale (stepnormal, i, into);
910 VectorSubtract (ent->v->velocity, into, side);
911 ent->v->velocity[0] = side[0] * (1 + d);
912 ent->v->velocity[1] = side[1] * (1 + d);
917 =====================
920 Player has come to a dead stop, possibly due to the problem with limited
921 float precision at some angle joins in the BSP hull.
923 Try fixing by pushing one pixel in each direction.
925 This is a hack, but in the interest of good gameplay...
926 ======================
928 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
933 VectorCopy (ent->v->origin, oldorg);
936 for (i=0 ; i<8 ; i++)
938 // try pushing a little in an axial direction
941 case 0: dir[0] = 2; dir[1] = 0; break;
942 case 1: dir[0] = 0; dir[1] = 2; break;
943 case 2: dir[0] = -2; dir[1] = 0; break;
944 case 3: dir[0] = 0; dir[1] = -2; break;
945 case 4: dir[0] = 2; dir[1] = 2; break;
946 case 5: dir[0] = -2; dir[1] = 2; break;
947 case 6: dir[0] = 2; dir[1] = -2; break;
948 case 7: dir[0] = -2; dir[1] = -2; break;
951 SV_PushEntity (ent, dir, vec3_origin);
953 // retry the original move
954 ent->v->velocity[0] = oldvel[0];
955 ent->v->velocity[1] = oldvel[1];
956 ent->v->velocity[2] = 0;
957 clip = SV_FlyMove (ent, 0.1, NULL);
959 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
960 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
962 Con_DPrint("TryUnstick - success.\n");
966 // go back to the original pos and try again
967 VectorCopy (oldorg, ent->v->origin);
971 VectorClear (ent->v->velocity);
972 Con_DPrint("TryUnstick - failure.\n");
977 =====================
981 ======================
983 void SV_WalkMove (edict_t *ent)
985 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
986 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal, originalmove_origin, originalmove_velocity;
989 SV_CheckVelocity(ent);
991 // do a regular slide move unless it looks like you ran into a step
992 oldonground = (int)ent->v->flags & FL_ONGROUND;
993 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
995 VectorCopy (ent->v->origin, oldorg);
996 VectorCopy (ent->v->velocity, oldvel);
998 clip = SV_FlyMove (ent, sv.frametime, NULL);
999 VectorCopy(ent->v->origin, originalmove_origin);
1000 VectorCopy(ent->v->velocity, originalmove_velocity);
1001 originalmove_clip = clip;
1002 originalmove_flags = (int)ent->v->flags;
1003 originalmove_groundentity = ent->v->groundentity;
1005 SV_CheckVelocity(ent);
1007 // if move didn't block on a step, return
1011 // if move was not trying to move into the step, return
1012 if (fabs(oldvel[0]) < 0.03125 && fabs(oldvel[1]) < 0.03125)
1015 if (ent->v->movetype != MOVETYPE_FLY)
1017 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
1018 // don't stair up while jumping
1021 if (ent->v->movetype != MOVETYPE_WALK)
1022 // gibbed by a trigger
1026 SV_CheckVelocity(ent);
1028 if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP )
1031 VectorCopy (ent->v->origin, nosteporg);
1032 VectorCopy (ent->v->velocity, nostepvel);
1034 // try moving up and forward to go up a step
1035 // back to start pos
1036 VectorCopy (oldorg, ent->v->origin);
1038 VectorClear (upmove);
1039 VectorClear (downmove);
1040 upmove[2] = sv_stepheight.value;
1041 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
1044 // FIXME: don't link?
1045 SV_PushEntity(ent, upmove, vec3_origin);
1048 ent->v->velocity[0] = oldvel[0];
1049 ent->v->velocity[1] = oldvel[1];
1050 ent->v->velocity[2] = 0;
1051 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1052 ent->v->velocity[2] += oldvel[2];
1054 // check for stuckness, possibly due to the limited precision of floats
1055 // in the clipping hulls
1057 && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
1058 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
1060 // stepping up didn't make any progress, revert to original move
1061 VectorCopy(originalmove_origin, ent->v->origin);
1062 VectorCopy(originalmove_velocity, ent->v->velocity);
1063 clip = originalmove_clip;
1064 ent->v->flags = originalmove_flags;
1065 ent->v->groundentity = originalmove_groundentity;
1066 // now try to unstick if needed
1067 //clip = SV_TryUnstick (ent, oldvel);
1071 // extra friction based on view angle
1072 if (clip & 2 && sv_wallfriction.integer)
1073 SV_WallFriction (ent, stepnormal);
1076 // FIXME: don't link?
1077 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
1079 if (downtrace.plane.normal[2] > 0.7)
1081 // LordHavoc: disabled this so you can walk on monsters/players
1082 //if (ent->v->solid == SOLID_BSP)
1084 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1085 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1090 // if the push down didn't end up on good ground, use the move without
1091 // the step up. This happens near wall / slope combinations, and can
1092 // cause the player to hop up higher on a slope too steep to climb
1093 VectorCopy (nosteporg, ent->v->origin);
1094 VectorCopy (nostepvel, ent->v->velocity);
1097 SV_CheckVelocity(ent);
1100 //============================================================================
1106 Entities that are "stuck" to another entity
1109 void SV_Physics_Follow (edict_t *ent)
1111 vec3_t vf, vr, vu, angles, v;
1115 if (!SV_RunThink (ent))
1118 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1119 e = PROG_TO_EDICT(ent->v->aiment);
1120 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])
1122 // quick case for no rotation
1123 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1127 angles[0] = -ent->v->punchangle[0];
1128 angles[1] = ent->v->punchangle[1];
1129 angles[2] = ent->v->punchangle[2];
1130 AngleVectors (angles, vf, vr, vu);
1131 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1132 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1133 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1134 angles[0] = -e->v->angles[0];
1135 angles[1] = e->v->angles[1];
1136 angles[2] = e->v->angles[2];
1137 AngleVectors (angles, vf, vr, vu);
1138 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1139 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1140 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1142 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1143 SV_LinkEdict (ent, true);
1147 ==============================================================================
1151 ==============================================================================
1156 SV_CheckWaterTransition
1160 void SV_CheckWaterTransition (edict_t *ent)
1163 cont = SV_PointQ1Contents(ent->v->origin);
1164 if (!ent->v->watertype)
1166 // just spawned here
1167 ent->v->watertype = cont;
1168 ent->v->waterlevel = 1;
1172 // check if the entity crossed into or out of water
1173 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1174 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1176 if (cont <= CONTENTS_WATER)
1178 ent->v->watertype = cont;
1179 ent->v->waterlevel = 1;
1183 ent->v->watertype = CONTENTS_EMPTY;
1184 ent->v->waterlevel = 0;
1192 Toss, bounce, and fly movement. When onground, do nothing.
1195 void SV_Physics_Toss (edict_t *ent)
1199 edict_t *groundentity;
1202 if (!SV_RunThink (ent))
1205 // if onground, return without moving
1206 if ((int)ent->v->flags & FL_ONGROUND)
1208 if (ent->v->groundentity == 0)
1210 // if ent was supported by a brush model on previous frame,
1211 // and groundentity is now freed, set groundentity to 0 (floating)
1212 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1213 if (groundentity->v->solid == SOLID_BSP)
1215 ent->e->suspendedinairflag = true;
1218 else if (ent->e->suspendedinairflag && groundentity->e->free)
1220 // leave it suspended in the air
1221 ent->v->groundentity = 0;
1222 ent->e->suspendedinairflag = false;
1226 ent->e->suspendedinairflag = false;
1228 SV_CheckVelocity (ent);
1231 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1232 SV_AddGravity (ent);
1235 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1238 VectorScale (ent->v->velocity, sv.frametime, move);
1239 trace = SV_PushEntity (ent, move, vec3_origin);
1243 if (trace.fraction < 1)
1245 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1247 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1248 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1250 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1253 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1254 // LordHavoc: fixed grenades not bouncing when fired down a slope
1255 d = DotProduct(trace.plane.normal, ent->v->velocity);
1256 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1258 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1259 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1260 VectorClear (ent->v->velocity);
1261 VectorClear (ent->v->avelocity);
1264 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1268 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1269 if (trace.plane.normal[2] > 0.7)
1271 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1272 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1273 VectorClear (ent->v->velocity);
1274 VectorClear (ent->v->avelocity);
1277 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1281 // check for in water
1282 SV_CheckWaterTransition (ent);
1286 ===============================================================================
1290 ===============================================================================
1297 Monsters freefall when they don't have a ground entity, otherwise
1298 all movement is done with discrete steps.
1300 This is also used for objects that have become still on the ground, but
1301 will fall if the floor is pulled out from under them.
1304 void SV_Physics_Step (edict_t *ent)
1306 // freefall if not onground/fly/swim
1307 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1309 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1312 SV_CheckVelocity(ent);
1313 SV_FlyMove(ent, sv.frametime, NULL);
1314 SV_LinkEdict(ent, true);
1317 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1318 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1324 SV_CheckWaterTransition(ent);
1327 //============================================================================
1335 void SV_Physics (void)
1340 // let the progs know that a new frame has started
1341 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1342 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1343 pr_global_struct->time = sv.time;
1344 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1347 // treat each object in turn
1350 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1355 if (pr_global_struct->force_retouch)
1356 SV_LinkEdict (ent, true); // force retouch even for stationary
1358 if (i <= svs.maxclients)
1362 if (!svs.clients[i-1].spawned)
1365 // call standard client pre-think
1366 SV_CheckVelocity (ent);
1367 pr_global_struct->time = sv.time;
1368 pr_global_struct->self = EDICT_TO_PROG(ent);
1369 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1370 SV_CheckVelocity (ent);
1373 else if (sv_freezenonclients.integer)
1376 // LordHavoc: merged client and normal entity physics
1377 switch ((int) ent->v->movetype)
1380 case MOVETYPE_FAKEPUSH:
1381 SV_Physics_Pusher (ent);
1384 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1385 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1388 case MOVETYPE_FOLLOW:
1389 SV_Physics_Follow (ent);
1391 case MOVETYPE_NOCLIP:
1392 if (SV_RunThink(ent))
1395 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1396 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1398 // relink normal entities here, players always get relinked so don't relink twice
1399 if (!(i > 0 && i <= svs.maxclients))
1400 SV_LinkEdict(ent, false);
1403 SV_Physics_Step (ent);
1406 if (SV_RunThink (ent))
1408 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1409 SV_AddGravity (ent);
1410 SV_CheckStuck (ent);
1412 // relink normal entities here, players always get relinked so don't relink twice
1413 if (!(i > 0 && i <= svs.maxclients))
1414 SV_LinkEdict (ent, true);
1418 case MOVETYPE_BOUNCE:
1419 case MOVETYPE_BOUNCEMISSILE:
1420 case MOVETYPE_FLYMISSILE:
1421 SV_Physics_Toss (ent);
1424 if (i > 0 && i <= svs.maxclients)
1426 if (SV_RunThink (ent))
1428 SV_CheckWater (ent);
1433 SV_Physics_Toss (ent);
1436 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1440 if (i <= svs.maxclients && i > 0 && !ent->e->free)
1442 SV_CheckVelocity (ent);
1444 // call standard player post-think
1445 SV_LinkEdict (ent, true);
1447 SV_CheckVelocity (ent);
1449 pr_global_struct->time = sv.time;
1450 pr_global_struct->self = EDICT_TO_PROG(ent);
1451 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1455 if (pr_global_struct->force_retouch)
1456 pr_global_struct->force_retouch--;
1458 // LordHavoc: endframe support
1461 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1462 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1463 pr_global_struct->time = sv.time;
1464 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1467 if (!sv_freezenonclients.integer)
1468 sv.time += sv.frametime;
1472 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1475 float gravity, savesolid;
1477 edict_t tempent, *tent;
1482 // copy the vars over
1483 memcpy(&vars, tossent->v, sizeof(entvars_t));
1484 // set up the temp entity to point to the copied vars
1488 savesolid = tossent->v->solid;
1489 tossent->v->solid = SOLID_NOT;
1491 // this has to fetch the field from the original edict, since our copy is truncated
1492 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1493 if (val != NULL && val->_float != 0)
1494 gravity = val->_float;
1497 gravity *= sv_gravity.value * 0.05;
1499 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1501 SV_CheckVelocity (tent);
1502 tent->v->velocity[2] -= gravity;
1503 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1504 VectorScale (tent->v->velocity, 0.05, move);
1505 VectorAdd (tent->v->origin, move, end);
1506 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1507 VectorCopy (trace.endpos, tent->v->origin);
1509 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1512 tossent->v->solid = savesolid;
1513 trace.fraction = 0; // not relevant