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 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
580 index = (int) pusher->v->modelindex;
581 if (index < 1 || index >= MAX_MODELS)
582 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
583 pushermodel = sv.models[index];
585 movetime2 = movetime;
586 VectorScale(pusher->v->velocity, movetime2, move1);
587 VectorScale(pusher->v->avelocity, movetime2, moveangle);
588 if (moveangle[0] || moveangle[2])
590 for (i = 0;i < 3;i++)
594 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
595 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
599 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
600 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
604 else if (moveangle[1])
606 for (i = 0;i < 3;i++)
610 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
611 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
615 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
616 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
622 for (i = 0;i < 3;i++)
626 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
627 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
631 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
632 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
637 VectorNegate (moveangle, a);
638 AngleVectorsFLU (a, forward, left, up);
640 VectorCopy (pusher->v->origin, pushorig);
641 VectorCopy (pusher->v->angles, pushang);
642 pushltime = pusher->v->ltime;
644 // move the pusher to it's final position
646 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
647 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
648 pusher->v->ltime += movetime;
649 SV_LinkEdict (pusher, false);
651 savesolid = pusher->v->solid;
653 // see if any solid entities are inside the final position
655 check = NEXT_EDICT(sv.edicts);
656 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
660 if (check->v->movetype == MOVETYPE_PUSH
661 || check->v->movetype == MOVETYPE_NONE
662 || check->v->movetype == MOVETYPE_FOLLOW
663 || check->v->movetype == MOVETYPE_NOCLIP
664 || check->v->movetype == MOVETYPE_FAKEPUSH)
667 // if the entity is standing on the pusher, it will definitely be moved
668 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
670 if (check->v->absmin[0] >= maxs[0]
671 || check->v->absmax[0] <= mins[0]
672 || check->v->absmin[1] >= maxs[1]
673 || check->v->absmax[1] <= mins[1]
674 || check->v->absmin[2] >= maxs[2]
675 || check->v->absmax[2] <= mins[2])
678 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
682 if (forward[0] != 1) // quick way to check if any rotation is used
684 VectorSubtract (check->v->origin, pusher->v->origin, org);
685 org2[0] = DotProduct (org, forward);
686 org2[1] = DotProduct (org, left);
687 org2[2] = DotProduct (org, up);
688 VectorSubtract (org2, org, move);
689 VectorAdd (move, move1, move);
692 VectorCopy (move1, move);
694 // remove the onground flag for non-players
695 if (check->v->movetype != MOVETYPE_WALK)
696 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
698 VectorCopy (check->v->origin, check->e->moved_from);
699 VectorCopy (check->v->angles, check->e->moved_fromangles);
700 sv.moved_edicts[num_moved++] = check;
702 // try moving the contacted entity
703 pusher->v->solid = SOLID_NOT;
704 SV_PushEntity (check, move, moveangle);
705 pusher->v->solid = savesolid; // was SOLID_BSP
707 // if it is still inside the pusher, block
708 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
710 // try moving the contacted entity a tiny bit further to account for precision errors
711 pusher->v->solid = SOLID_NOT;
712 VectorScale(move, 0.1, move);
713 SV_PushEntity (check, move, vec3_origin);
714 pusher->v->solid = savesolid;
715 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
717 // still inside pusher, so it's really blocked
720 if (check->v->mins[0] == check->v->maxs[0])
722 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
725 check->v->mins[0] = check->v->mins[1] = 0;
726 VectorCopy (check->v->mins, check->v->maxs);
730 VectorCopy (pushorig, pusher->v->origin);
731 VectorCopy (pushang, pusher->v->angles);
732 pusher->v->ltime = pushltime;
733 SV_LinkEdict (pusher, false);
735 // move back any entities we already moved
736 for (i = 0;i < num_moved;i++)
738 ed = sv.moved_edicts[i];
739 VectorCopy (ed->e->moved_from, ed->v->origin);
740 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
741 SV_LinkEdict (ed, false);
744 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
745 if (pusher->v->blocked)
747 pr_global_struct->self = EDICT_TO_PROG(pusher);
748 pr_global_struct->other = EDICT_TO_PROG(check);
749 PR_ExecuteProgram (pusher->v->blocked, "");
755 pusher->v->angles[0] -= 360.0 * floor(pusher->v->angles[0] * (1.0 / 360.0));
756 pusher->v->angles[1] -= 360.0 * floor(pusher->v->angles[1] * (1.0 / 360.0));
757 pusher->v->angles[2] -= 360.0 * floor(pusher->v->angles[2] * (1.0 / 360.0));
766 void SV_Physics_Pusher (edict_t *ent)
768 float thinktime, oldltime, movetime;
770 oldltime = ent->v->ltime;
772 thinktime = ent->v->nextthink;
773 if (thinktime < ent->v->ltime + sv.frametime)
775 movetime = thinktime - ent->v->ltime;
780 movetime = sv.frametime;
783 // advances ent->v->ltime if not blocked
784 SV_PushMove (ent, movetime);
786 if (thinktime > oldltime && thinktime <= ent->v->ltime)
788 ent->v->nextthink = 0;
789 pr_global_struct->time = sv.time;
790 pr_global_struct->self = EDICT_TO_PROG(ent);
791 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
792 PR_ExecuteProgram (ent->v->think, "NULL think function");
798 ===============================================================================
802 ===============================================================================
809 This is a big hack to try and fix the rare case of getting stuck in the world
813 void SV_CheckStuck (edict_t *ent)
818 if (!SV_TestEntityPosition(ent))
820 VectorCopy (ent->v->origin, ent->v->oldorigin);
824 VectorCopy (ent->v->origin, org);
825 VectorCopy (ent->v->oldorigin, ent->v->origin);
826 if (!SV_TestEntityPosition(ent))
828 Con_DPrint("Unstuck.\n");
829 SV_LinkEdict (ent, true);
833 for (z=0 ; z< 18 ; z++)
834 for (i=-1 ; i <= 1 ; i++)
835 for (j=-1 ; j <= 1 ; j++)
837 ent->v->origin[0] = org[0] + i;
838 ent->v->origin[1] = org[1] + j;
839 ent->v->origin[2] = org[2] + z;
840 if (!SV_TestEntityPosition(ent))
842 Con_DPrint("Unstuck.\n");
843 SV_LinkEdict (ent, true);
848 VectorCopy (org, ent->v->origin);
849 Con_DPrint("player is stuck.\n");
858 qboolean SV_CheckWater (edict_t *ent)
863 point[0] = ent->v->origin[0];
864 point[1] = ent->v->origin[1];
865 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
867 ent->v->waterlevel = 0;
868 ent->v->watertype = CONTENTS_EMPTY;
869 cont = SV_PointQ1Contents(point);
870 if (cont <= CONTENTS_WATER)
872 ent->v->watertype = cont;
873 ent->v->waterlevel = 1;
874 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
875 cont = SV_PointQ1Contents(point);
876 if (cont <= CONTENTS_WATER)
878 ent->v->waterlevel = 2;
879 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
880 cont = SV_PointQ1Contents(point);
881 if (cont <= CONTENTS_WATER)
882 ent->v->waterlevel = 3;
886 return ent->v->waterlevel > 1;
895 void SV_WallFriction (edict_t *ent, float *stepnormal)
898 vec3_t forward, into, side;
900 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
901 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
903 // cut the tangential velocity
904 i = DotProduct (stepnormal, ent->v->velocity);
905 VectorScale (stepnormal, i, into);
906 VectorSubtract (ent->v->velocity, into, side);
907 ent->v->velocity[0] = side[0] * (1 + d);
908 ent->v->velocity[1] = side[1] * (1 + d);
913 =====================
916 Player has come to a dead stop, possibly due to the problem with limited
917 float precision at some angle joins in the BSP hull.
919 Try fixing by pushing one pixel in each direction.
921 This is a hack, but in the interest of good gameplay...
922 ======================
924 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
929 VectorCopy (ent->v->origin, oldorg);
932 for (i=0 ; i<8 ; i++)
934 // try pushing a little in an axial direction
937 case 0: dir[0] = 2; dir[1] = 0; break;
938 case 1: dir[0] = 0; dir[1] = 2; break;
939 case 2: dir[0] = -2; dir[1] = 0; break;
940 case 3: dir[0] = 0; dir[1] = -2; break;
941 case 4: dir[0] = 2; dir[1] = 2; break;
942 case 5: dir[0] = -2; dir[1] = 2; break;
943 case 6: dir[0] = 2; dir[1] = -2; break;
944 case 7: dir[0] = -2; dir[1] = -2; break;
947 SV_PushEntity (ent, dir, vec3_origin);
949 // retry the original move
950 ent->v->velocity[0] = oldvel[0];
951 ent->v->velocity[1] = oldvel[1];
952 ent->v->velocity[2] = 0;
953 clip = SV_FlyMove (ent, 0.1, NULL);
955 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
956 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
958 Con_DPrint("TryUnstick - success.\n");
962 // go back to the original pos and try again
963 VectorCopy (oldorg, ent->v->origin);
967 VectorClear (ent->v->velocity);
968 Con_DPrint("TryUnstick - failure.\n");
973 =====================
977 ======================
979 void SV_WalkMove (edict_t *ent)
981 int clip, oldonground, originalmove_clip, originalmove_flags, originalmove_groundentity;
982 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal, originalmove_origin, originalmove_velocity;
985 SV_CheckVelocity(ent);
987 // do a regular slide move unless it looks like you ran into a step
988 oldonground = (int)ent->v->flags & FL_ONGROUND;
989 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
991 VectorCopy (ent->v->origin, oldorg);
992 VectorCopy (ent->v->velocity, oldvel);
994 clip = SV_FlyMove (ent, sv.frametime, NULL);
995 VectorCopy(ent->v->origin, originalmove_origin);
996 VectorCopy(ent->v->velocity, originalmove_velocity);
997 originalmove_clip = clip;
998 originalmove_flags = (int)ent->v->flags;
999 originalmove_groundentity = ent->v->groundentity;
1001 SV_CheckVelocity(ent);
1003 // if move didn't block on a step, return
1007 // if move was not trying to move into the step, return
1008 if (fabs(oldvel[0]) < 0.03125 && fabs(oldvel[1]) < 0.03125)
1011 if (ent->v->movetype != MOVETYPE_FLY)
1013 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
1014 // don't stair up while jumping
1017 if (ent->v->movetype != MOVETYPE_WALK)
1018 // gibbed by a trigger
1022 SV_CheckVelocity(ent);
1024 if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP )
1027 VectorCopy (ent->v->origin, nosteporg);
1028 VectorCopy (ent->v->velocity, nostepvel);
1030 // try moving up and forward to go up a step
1031 // back to start pos
1032 VectorCopy (oldorg, ent->v->origin);
1034 VectorClear (upmove);
1035 VectorClear (downmove);
1036 upmove[2] = sv_stepheight.value;
1037 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
1040 // FIXME: don't link?
1041 SV_PushEntity(ent, upmove, vec3_origin);
1044 ent->v->velocity[0] = oldvel[0];
1045 ent->v->velocity[1] = oldvel[1];
1046 ent->v->velocity[2] = 0;
1047 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1048 ent->v->velocity[2] += oldvel[2];
1050 // check for stuckness, possibly due to the limited precision of floats
1051 // in the clipping hulls
1053 && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
1054 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
1056 // stepping up didn't make any progress, revert to original move
1057 VectorCopy(originalmove_origin, ent->v->origin);
1058 VectorCopy(originalmove_velocity, ent->v->velocity);
1059 clip = originalmove_clip;
1060 ent->v->flags = originalmove_flags;
1061 ent->v->groundentity = originalmove_groundentity;
1062 // now try to unstick if needed
1063 //clip = SV_TryUnstick (ent, oldvel);
1067 // extra friction based on view angle
1068 if (clip & 2 && sv_wallfriction.integer)
1069 SV_WallFriction (ent, stepnormal);
1072 // FIXME: don't link?
1073 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
1075 if (downtrace.plane.normal[2] > 0.7)
1077 // LordHavoc: disabled this so you can walk on monsters/players
1078 //if (ent->v->solid == SOLID_BSP)
1080 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1081 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1086 // if the push down didn't end up on good ground, use the move without
1087 // the step up. This happens near wall / slope combinations, and can
1088 // cause the player to hop up higher on a slope too steep to climb
1089 VectorCopy (nosteporg, ent->v->origin);
1090 VectorCopy (nostepvel, ent->v->velocity);
1093 SV_CheckVelocity(ent);
1096 //============================================================================
1102 Entities that are "stuck" to another entity
1105 void SV_Physics_Follow (edict_t *ent)
1107 vec3_t vf, vr, vu, angles, v;
1111 if (!SV_RunThink (ent))
1114 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1115 e = PROG_TO_EDICT(ent->v->aiment);
1116 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])
1118 // quick case for no rotation
1119 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1123 angles[0] = -ent->v->punchangle[0];
1124 angles[1] = ent->v->punchangle[1];
1125 angles[2] = ent->v->punchangle[2];
1126 AngleVectors (angles, vf, vr, vu);
1127 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1128 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1129 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1130 angles[0] = -e->v->angles[0];
1131 angles[1] = e->v->angles[1];
1132 angles[2] = e->v->angles[2];
1133 AngleVectors (angles, vf, vr, vu);
1134 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1135 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1136 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1138 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1139 SV_LinkEdict (ent, true);
1143 ==============================================================================
1147 ==============================================================================
1152 SV_CheckWaterTransition
1156 void SV_CheckWaterTransition (edict_t *ent)
1159 cont = SV_PointQ1Contents(ent->v->origin);
1160 if (!ent->v->watertype)
1162 // just spawned here
1163 ent->v->watertype = cont;
1164 ent->v->waterlevel = 1;
1168 // check if the entity crossed into or out of water
1169 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1170 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1172 if (cont <= CONTENTS_WATER)
1174 ent->v->watertype = cont;
1175 ent->v->waterlevel = 1;
1179 ent->v->watertype = CONTENTS_EMPTY;
1180 ent->v->waterlevel = 0;
1188 Toss, bounce, and fly movement. When onground, do nothing.
1191 void SV_Physics_Toss (edict_t *ent)
1195 edict_t *groundentity;
1198 if (!SV_RunThink (ent))
1201 // if onground, return without moving
1202 if ((int)ent->v->flags & FL_ONGROUND)
1204 if (ent->v->groundentity == 0)
1206 // if ent was supported by a brush model on previous frame,
1207 // and groundentity is now freed, set groundentity to 0 (floating)
1208 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1209 if (groundentity->v->solid == SOLID_BSP)
1211 ent->e->suspendedinairflag = true;
1214 else if (ent->e->suspendedinairflag && groundentity->e->free)
1216 // leave it suspended in the air
1217 ent->v->groundentity = 0;
1218 ent->e->suspendedinairflag = false;
1222 ent->e->suspendedinairflag = false;
1224 SV_CheckVelocity (ent);
1227 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1228 SV_AddGravity (ent);
1231 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1234 VectorScale (ent->v->velocity, sv.frametime, move);
1235 trace = SV_PushEntity (ent, move, vec3_origin);
1239 if (trace.fraction < 1)
1241 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1243 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1244 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1246 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1249 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1250 // LordHavoc: fixed grenades not bouncing when fired down a slope
1251 d = DotProduct(trace.plane.normal, ent->v->velocity);
1252 if (trace.plane.normal[2] > 0.7 && fabs(d) < 60)
1254 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1255 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1256 VectorClear (ent->v->velocity);
1257 VectorClear (ent->v->avelocity);
1260 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1264 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1265 if (trace.plane.normal[2] > 0.7)
1267 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1268 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1269 VectorClear (ent->v->velocity);
1270 VectorClear (ent->v->avelocity);
1273 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1277 // check for in water
1278 SV_CheckWaterTransition (ent);
1282 ===============================================================================
1286 ===============================================================================
1293 Monsters freefall when they don't have a ground entity, otherwise
1294 all movement is done with discrete steps.
1296 This is also used for objects that have become still on the ground, but
1297 will fall if the floor is pulled out from under them.
1300 void SV_Physics_Step (edict_t *ent)
1302 // freefall if not onground/fly/swim
1303 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1305 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1308 SV_CheckVelocity(ent);
1309 SV_FlyMove(ent, sv.frametime, NULL);
1310 SV_LinkEdict(ent, true);
1313 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1314 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1320 SV_CheckWaterTransition(ent);
1323 //============================================================================
1331 void SV_Physics (void)
1336 // let the progs know that a new frame has started
1337 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1338 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1339 pr_global_struct->time = sv.time;
1340 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1343 // treat each object in turn
1346 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1351 if (pr_global_struct->force_retouch)
1352 SV_LinkEdict (ent, true); // force retouch even for stationary
1354 if (i <= svs.maxclients)
1358 if (!svs.clients[i-1].spawned)
1361 // call standard client pre-think
1362 SV_CheckVelocity (ent);
1363 pr_global_struct->time = sv.time;
1364 pr_global_struct->self = EDICT_TO_PROG(ent);
1365 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1366 SV_CheckVelocity (ent);
1369 else if (sv_freezenonclients.integer)
1372 // LordHavoc: merged client and normal entity physics
1373 switch ((int) ent->v->movetype)
1376 case MOVETYPE_FAKEPUSH:
1377 SV_Physics_Pusher (ent);
1380 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1381 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1384 case MOVETYPE_FOLLOW:
1385 SV_Physics_Follow (ent);
1387 case MOVETYPE_NOCLIP:
1388 if (SV_RunThink(ent))
1391 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1392 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1394 // relink normal entities here, players always get relinked so don't relink twice
1395 if (!(i > 0 && i <= svs.maxclients))
1396 SV_LinkEdict(ent, false);
1399 SV_Physics_Step (ent);
1402 if (SV_RunThink (ent))
1404 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1405 SV_AddGravity (ent);
1406 SV_CheckStuck (ent);
1408 // relink normal entities here, players always get relinked so don't relink twice
1409 if (!(i > 0 && i <= svs.maxclients))
1410 SV_LinkEdict (ent, true);
1414 case MOVETYPE_BOUNCE:
1415 case MOVETYPE_BOUNCEMISSILE:
1416 case MOVETYPE_FLYMISSILE:
1417 SV_Physics_Toss (ent);
1420 if (i > 0 && i <= svs.maxclients)
1422 if (SV_RunThink (ent))
1424 SV_CheckWater (ent);
1429 SV_Physics_Toss (ent);
1432 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1436 if (i <= svs.maxclients && i > 0 && !ent->e->free)
1438 SV_CheckVelocity (ent);
1440 // call standard player post-think
1441 SV_LinkEdict (ent, true);
1443 SV_CheckVelocity (ent);
1445 pr_global_struct->time = sv.time;
1446 pr_global_struct->self = EDICT_TO_PROG(ent);
1447 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1451 if (pr_global_struct->force_retouch)
1452 pr_global_struct->force_retouch--;
1454 // LordHavoc: endframe support
1457 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1458 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1459 pr_global_struct->time = sv.time;
1460 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1463 if (!sv_freezenonclients.integer)
1464 sv.time += sv.frametime;
1468 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1471 float gravity, savesolid;
1473 edict_t tempent, *tent;
1478 // copy the vars over
1479 memcpy(&vars, tossent->v, sizeof(entvars_t));
1480 // set up the temp entity to point to the copied vars
1484 savesolid = tossent->v->solid;
1485 tossent->v->solid = SOLID_NOT;
1487 // this has to fetch the field from the original edict, since our copy is truncated
1488 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1489 if (val != NULL && val->_float != 0)
1490 gravity = val->_float;
1493 gravity *= sv_gravity.value * 0.05;
1495 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1497 SV_CheckVelocity (tent);
1498 tent->v->velocity[2] -= gravity;
1499 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1500 VectorScale (tent->v->velocity, 0.05, move);
1501 VectorAdd (tent->v->origin, move, end);
1502 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1503 VectorCopy (trace.endpos, tent->v->origin);
1505 if (trace.fraction < 1 && trace.ent && trace.ent != ignore)
1508 tossent->v->solid = savesolid;
1509 trace.fraction = 0; // not relevant