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"};
52 #define MOVE_EPSILON 0.01
54 void SV_Physics_Toss (edict_t *ent);
56 void SV_Phys_Init (void)
58 Cvar_RegisterVariable(&sv_stepheight);
59 Cvar_RegisterVariable(&sv_jumpstep);
60 Cvar_RegisterVariable(&sv_wallfriction);
61 Cvar_RegisterVariable(&sv_newflymove);
69 void SV_CheckAllEnts (void)
74 // see if any solid entities are inside the final position
75 check = NEXT_EDICT(sv.edicts);
76 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
80 if (check->v->movetype == MOVETYPE_PUSH
81 || check->v->movetype == MOVETYPE_NONE
82 || check->v->movetype == MOVETYPE_FOLLOW
83 || check->v->movetype == MOVETYPE_NOCLIP)
86 if (SV_TestEntityPosition (check))
87 Con_Printf ("entity in invalid position\n");
96 void SV_CheckVelocity (edict_t *ent)
104 for (i=0 ; i<3 ; i++)
106 if (IS_NAN(ent->v->velocity[i]))
108 Con_Printf ("Got a NaN velocity on %s\n", PR_GetString(ent->v->classname));
109 ent->v->velocity[i] = 0;
111 if (IS_NAN(ent->v->origin[i]))
113 Con_Printf ("Got a NaN origin on %s\n", PR_GetString(ent->v->classname));
114 ent->v->origin[i] = 0;
118 // LordHavoc: max velocity fix, inspired by Maddes's source fixes, but this is faster
119 wishspeed = DotProduct(ent->v->velocity, ent->v->velocity);
120 if (wishspeed > sv_maxvelocity.value * sv_maxvelocity.value)
122 wishspeed = sv_maxvelocity.value / sqrt(wishspeed);
123 ent->v->velocity[0] *= wishspeed;
124 ent->v->velocity[1] *= wishspeed;
125 ent->v->velocity[2] *= wishspeed;
133 Runs thinking code if time. There is some play in the exact time the think
134 function will be called, because it is called before any movement is done
135 in a frame. Not used for pushmove objects, because they must be exact.
136 Returns false if the entity removed itself.
139 qboolean SV_RunThink (edict_t *ent)
143 thinktime = ent->v->nextthink;
144 if (thinktime <= 0 || thinktime > sv.time + sv.frametime)
147 // don't let things stay in the past.
148 // it is possible to start that way by a trigger with a local time.
149 if (thinktime < sv.time)
152 ent->v->nextthink = 0;
153 pr_global_struct->time = thinktime;
154 pr_global_struct->self = EDICT_TO_PROG(ent);
155 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
156 PR_ExecuteProgram (ent->v->think, "NULL think function");
157 return !ent->e->free;
164 Two entities have touched, so run their touch functions
167 void SV_Impact (edict_t *e1, edict_t *e2)
169 int old_self, old_other;
171 old_self = pr_global_struct->self;
172 old_other = pr_global_struct->other;
174 pr_global_struct->time = sv.time;
175 if (e1->v->touch && e1->v->solid != SOLID_NOT)
177 pr_global_struct->self = EDICT_TO_PROG(e1);
178 pr_global_struct->other = EDICT_TO_PROG(e2);
179 PR_ExecuteProgram (e1->v->touch, "");
182 if (e2->v->touch && e2->v->solid != SOLID_NOT)
184 pr_global_struct->self = EDICT_TO_PROG(e2);
185 pr_global_struct->other = EDICT_TO_PROG(e1);
186 PR_ExecuteProgram (e2->v->touch, "");
189 pr_global_struct->self = old_self;
190 pr_global_struct->other = old_other;
198 Slide off of the impacting object
199 returns the blocked flags (1 = floor, 2 = step / wall)
202 #define STOP_EPSILON 0.1
203 void ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
208 backoff = -DotProduct (in, normal) * overbounce;
209 VectorMA(in, backoff, normal, out);
211 for (i = 0;i < 3;i++)
212 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
221 The basic solid body movement clip that slides along multiple planes
222 Returns the clipflags if the velocity was modified (hit something solid)
226 If stepnormal is not NULL, the plane normal of any vertical wall hit will be stored
229 // LordHavoc: increased from 5 to 20
230 #define MAX_CLIP_PLANES 20
231 int SV_FlyMove (edict_t *ent, float time, float *stepnormal)
233 if (sv_newflymove.integer)
235 int blocked, impact, bumpcount;
236 vec3_t end, primal_velocity;
240 VectorCopy (ent->v->velocity, primal_velocity);
242 for (bumpcount = 0;bumpcount < 4;bumpcount++)
244 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
247 VectorMA(ent->v->origin, time, ent->v->velocity, end);
248 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
249 //Con_Printf("trace %f %f %f : %f : %f %f %f\n", trace.endpos[0], trace.endpos[1], trace.endpos[2], trace.fraction, trace.plane.normal[0], trace.plane.normal[1], trace.plane.normal[2]);
252 if (trace.startsolid)
254 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
255 // entity is trapped in another solid
256 VectorClear(ent->v->velocity);
261 if (trace.fraction >= 0.001)
263 // actually covered some distance
264 VectorCopy (trace.endpos, ent->v->origin);
267 // break if it moved the entire distance
268 if (trace.fraction == 1)
272 Host_Error ("SV_FlyMove: !trace.ent");
274 if ((int) ent->v->flags & FL_ONGROUND)
276 if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
280 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
287 if (trace.plane.normal[2] > 0.7)
291 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
292 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
294 if (!trace.plane.normal[2])
298 // save the trace for player extrafriction
300 VectorCopy(trace.plane.normal, stepnormal);
303 // run the impact function
306 SV_Impact (ent, trace.ent);
308 // break if removed by the impact function
313 time *= 1 - trace.fraction;
315 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1);
322 int i, j, blocked, impact, numplanes, bumpcount, numbumps;
324 vec3_t dir, end, planes[MAX_CLIP_PLANES], primal_velocity, original_velocity, new_velocity;
330 VectorCopy (ent->v->velocity, original_velocity);
331 VectorCopy (ent->v->velocity, primal_velocity);
336 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
338 if (!ent->v->velocity[0] && !ent->v->velocity[1] && !ent->v->velocity[2])
341 for (i=0 ; i<3 ; i++)
342 end[i] = ent->v->origin[i] + time_left * ent->v->velocity[i];
344 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
347 if (trace.startsolid)
349 // LordHavoc: note: this code is what makes entities stick in place if embedded in another object (which can be the world)
350 // entity is trapped in another solid
351 VectorClear(ent->v->velocity);
356 if (trace.fraction > 0)
358 // actually covered some distance
359 VectorCopy (trace.endpos, ent->v->origin);
360 VectorCopy (ent->v->velocity, original_velocity);
364 // break if it moved the entire distance
365 if (trace.fraction == 1)
369 Host_Error ("SV_FlyMove: !trace.ent");
371 if ((int) ent->v->flags & FL_ONGROUND)
373 if (ent->v->groundentity == EDICT_TO_PROG(trace.ent))
377 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
384 if (trace.plane.normal[2] > 0.7)
388 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
389 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
391 if (!trace.plane.normal[2])
395 // save the trace for player extrafriction
397 VectorCopy(trace.plane.normal, stepnormal);
400 // run the impact function
403 SV_Impact (ent, trace.ent);
405 // break if removed by the impact function
411 time_left -= time_left * trace.fraction;
413 // clipped to another plane
414 if (numplanes >= MAX_CLIP_PLANES)
416 // this shouldn't really happen
417 VectorClear(ent->v->velocity);
421 VectorCopy (trace.plane.normal, planes[numplanes]);
424 // modify original_velocity so it parallels all of the clip planes
425 for (i=0 ; i<numplanes ; i++)
427 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
428 for (j=0 ; j<numplanes ; j++)
432 if (DotProduct (new_velocity, planes[j]) < 0)
441 // go along this plane
442 VectorCopy (new_velocity, ent->v->velocity);
446 // go along the crease
449 VectorClear(ent->v->velocity);
452 CrossProduct (planes[0], planes[1], dir);
453 // LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
454 VectorNormalize(dir);
455 d = DotProduct (dir, ent->v->velocity);
456 VectorScale (dir, d, ent->v->velocity);
459 // if original velocity is against the original velocity,
460 // stop dead to avoid tiny occilations in sloping corners
461 if (DotProduct (ent->v->velocity, primal_velocity) <= 0)
463 VectorClear(ent->v->velocity);
479 void SV_AddGravity (edict_t *ent)
484 val = GETEDICTFIELDVALUE(ent, eval_gravity);
485 if (val!=0 && val->_float)
486 ent_gravity = val->_float;
489 ent->v->velocity[2] -= ent_gravity * sv_gravity.value * sv.frametime;
494 ===============================================================================
498 ===============================================================================
505 Does not change the entities velocity at all
508 trace_t SV_PushEntity (edict_t *ent, vec3_t push, vec3_t pushangles)
513 VectorAdd (ent->v->origin, push, end);
515 if (ent->v->movetype == MOVETYPE_FLYMISSILE)
516 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_MISSILE, ent);
517 else if (ent->v->solid == SOLID_TRIGGER || ent->v->solid == SOLID_NOT)
518 // only clip against bmodels
519 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NOMONSTERS, ent);
521 trace = SV_Move (ent->v->origin, ent->v->mins, ent->v->maxs, end, MOVE_NORMAL, ent);
523 VectorCopy (trace.endpos, ent->v->origin);
524 // FIXME: turn players specially
525 ent->v->angles[1] += trace.fraction * pushangles[1];
526 SV_LinkEdict (ent, true);
528 if (trace.ent && (!((int)ent->v->flags & FL_ONGROUND) || ent->v->groundentity != EDICT_TO_PROG(trace.ent)))
529 SV_Impact (ent, trace.ent);
540 trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end);
541 void SV_PushMove (edict_t *pusher, float movetime)
545 float savesolid, movetime2, pushltime;
546 vec3_t mins, maxs, move, move1, moveangle, pushorig, pushang, a, forward, left, up, org, org2;
548 model_t *pushermodel;
550 switch ((int) pusher->v->solid)
552 // LordHavoc: valid pusher types
556 case SOLID_CORPSE: // LordHavoc: this would be weird...
558 // LordHavoc: no collisions
561 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
562 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
563 pusher->v->ltime += movetime;
564 SV_LinkEdict (pusher, false);
567 Host_Error("SV_PushMove: unrecognized solid type %f\n", pusher->v->solid);
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;
574 index = (int) pusher->v->modelindex;
575 if (index < 1 || index >= MAX_MODELS)
576 Host_Error("SV_PushMove: invalid modelindex %f\n", pusher->v->modelindex);
577 pushermodel = sv.models[index];
579 movetime2 = movetime;
580 VectorScale(pusher->v->velocity, movetime2, move1);
581 VectorScale(pusher->v->avelocity, movetime2, moveangle);
582 if (moveangle[0] || moveangle[2])
584 for (i = 0;i < 3;i++)
588 mins[i] = pushermodel->rotatedmins[i] + pusher->v->origin[i] - 1;
589 maxs[i] = pushermodel->rotatedmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
593 mins[i] = pushermodel->rotatedmins[i] + move1[i] + pusher->v->origin[i] - 1;
594 maxs[i] = pushermodel->rotatedmaxs[i] + pusher->v->origin[i] + 1;
598 else if (moveangle[1])
600 for (i = 0;i < 3;i++)
604 mins[i] = pushermodel->yawmins[i] + pusher->v->origin[i] - 1;
605 maxs[i] = pushermodel->yawmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
609 mins[i] = pushermodel->yawmins[i] + move1[i] + pusher->v->origin[i] - 1;
610 maxs[i] = pushermodel->yawmaxs[i] + pusher->v->origin[i] + 1;
616 for (i = 0;i < 3;i++)
620 mins[i] = pushermodel->normalmins[i] + pusher->v->origin[i] - 1;
621 maxs[i] = pushermodel->normalmaxs[i] + move1[i] + pusher->v->origin[i] + 1;
625 mins[i] = pushermodel->normalmins[i] + move1[i] + pusher->v->origin[i] - 1;
626 maxs[i] = pushermodel->normalmaxs[i] + pusher->v->origin[i] + 1;
631 VectorNegate (moveangle, a);
632 AngleVectorsFLU (a, forward, left, up);
634 VectorCopy (pusher->v->origin, pushorig);
635 VectorCopy (pusher->v->angles, pushang);
636 pushltime = pusher->v->ltime;
638 // move the pusher to it's final position
640 VectorMA (pusher->v->origin, movetime, pusher->v->velocity, pusher->v->origin);
641 VectorMA (pusher->v->angles, movetime, pusher->v->avelocity, pusher->v->angles);
642 pusher->v->ltime += movetime;
643 SV_LinkEdict (pusher, false);
645 savesolid = pusher->v->solid;
647 // see if any solid entities are inside the final position
649 check = NEXT_EDICT(sv.edicts);
650 for (e = 1;e < sv.num_edicts;e++, check = NEXT_EDICT(check))
654 if (check->v->movetype == MOVETYPE_PUSH
655 || check->v->movetype == MOVETYPE_NONE
656 || check->v->movetype == MOVETYPE_FOLLOW
657 || check->v->movetype == MOVETYPE_NOCLIP)
660 // if the entity is standing on the pusher, it will definitely be moved
661 if (!(((int)check->v->flags & FL_ONGROUND) && PROG_TO_EDICT(check->v->groundentity) == pusher))
663 if (check->v->absmin[0] >= maxs[0]
664 || check->v->absmax[0] <= mins[0]
665 || check->v->absmin[1] >= maxs[1]
666 || check->v->absmax[1] <= mins[1]
667 || check->v->absmin[2] >= maxs[2]
668 || check->v->absmax[2] <= mins[2])
671 if (!SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
675 if (forward[0] != 1) // quick way to check if any rotation is used
677 VectorSubtract (check->v->origin, pusher->v->origin, org);
678 org2[0] = DotProduct (org, forward);
679 org2[1] = DotProduct (org, left);
680 org2[2] = DotProduct (org, up);
681 VectorSubtract (org2, org, move);
682 VectorAdd (move, move1, move);
685 VectorCopy (move1, move);
687 // remove the onground flag for non-players
688 if (check->v->movetype != MOVETYPE_WALK)
689 check->v->flags = (int)check->v->flags & ~FL_ONGROUND;
691 VectorCopy (check->v->origin, check->e->moved_from);
692 VectorCopy (check->v->angles, check->e->moved_fromangles);
693 sv.moved_edicts[num_moved++] = check;
695 // try moving the contacted entity
696 pusher->v->solid = SOLID_NOT;
697 SV_PushEntity (check, move, moveangle);
698 pusher->v->solid = savesolid; // was SOLID_BSP
700 // if it is still inside the pusher, block
701 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
703 // try moving the contacted entity a tiny bit further to account for precision errors
704 pusher->v->solid = SOLID_NOT;
705 VectorScale(move, 0.1, move);
706 SV_PushEntity (check, move, vec3_origin);
707 pusher->v->solid = savesolid;
708 if (SV_ClipMoveToEntity(pusher, check->v->origin, check->v->mins, check->v->maxs, check->v->origin).startsolid)
710 // still inside pusher, so it's really blocked
713 if (check->v->mins[0] == check->v->maxs[0])
715 if (check->v->solid == SOLID_NOT || check->v->solid == SOLID_TRIGGER)
718 check->v->mins[0] = check->v->mins[1] = 0;
719 VectorCopy (check->v->mins, check->v->maxs);
723 VectorCopy (pushorig, pusher->v->origin);
724 VectorCopy (pushang, pusher->v->angles);
725 pusher->v->ltime = pushltime;
726 SV_LinkEdict (pusher, false);
728 // move back any entities we already moved
729 for (i = 0;i < num_moved;i++)
731 ed = sv.moved_edicts[i];
732 VectorCopy (ed->e->moved_from, ed->v->origin);
733 VectorCopy (ed->e->moved_fromangles, ed->v->angles);
734 SV_LinkEdict (ed, false);
737 // if the pusher has a "blocked" function, call it, otherwise just stay in place until the obstacle is gone
738 if (pusher->v->blocked)
740 pr_global_struct->self = EDICT_TO_PROG(pusher);
741 pr_global_struct->other = EDICT_TO_PROG(check);
742 PR_ExecuteProgram (pusher->v->blocked, "");
756 void SV_Physics_Pusher (edict_t *ent)
758 float thinktime, oldltime, movetime;
760 oldltime = ent->v->ltime;
762 thinktime = ent->v->nextthink;
763 if (thinktime < ent->v->ltime + sv.frametime)
765 movetime = thinktime - ent->v->ltime;
770 movetime = sv.frametime;
773 // advances ent->v->ltime if not blocked
774 SV_PushMove (ent, movetime);
776 if (thinktime > oldltime && thinktime <= ent->v->ltime)
778 ent->v->nextthink = 0;
779 pr_global_struct->time = sv.time;
780 pr_global_struct->self = EDICT_TO_PROG(ent);
781 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
782 PR_ExecuteProgram (ent->v->think, "NULL think function");
788 ===============================================================================
792 ===============================================================================
799 This is a big hack to try and fix the rare case of getting stuck in the world
803 void SV_CheckStuck (edict_t *ent)
808 if (!SV_TestEntityPosition(ent))
810 VectorCopy (ent->v->origin, ent->v->oldorigin);
814 VectorCopy (ent->v->origin, org);
815 VectorCopy (ent->v->oldorigin, ent->v->origin);
816 if (!SV_TestEntityPosition(ent))
818 Con_DPrintf ("Unstuck.\n");
819 SV_LinkEdict (ent, true);
823 for (z=0 ; z< 18 ; z++)
824 for (i=-1 ; i <= 1 ; i++)
825 for (j=-1 ; j <= 1 ; j++)
827 ent->v->origin[0] = org[0] + i;
828 ent->v->origin[1] = org[1] + j;
829 ent->v->origin[2] = org[2] + z;
830 if (!SV_TestEntityPosition(ent))
832 Con_DPrintf ("Unstuck.\n");
833 SV_LinkEdict (ent, true);
838 VectorCopy (org, ent->v->origin);
839 Con_DPrintf ("player is stuck.\n");
848 qboolean SV_CheckWater (edict_t *ent)
853 point[0] = ent->v->origin[0];
854 point[1] = ent->v->origin[1];
855 point[2] = ent->v->origin[2] + ent->v->mins[2] + 1;
857 ent->v->waterlevel = 0;
858 ent->v->watertype = CONTENTS_EMPTY;
859 cont = SV_PointQ1Contents(point);
860 if (cont <= CONTENTS_WATER)
862 ent->v->watertype = cont;
863 ent->v->waterlevel = 1;
864 point[2] = ent->v->origin[2] + (ent->v->mins[2] + ent->v->maxs[2])*0.5;
865 cont = SV_PointQ1Contents(point);
866 if (cont <= CONTENTS_WATER)
868 ent->v->waterlevel = 2;
869 point[2] = ent->v->origin[2] + ent->v->view_ofs[2];
870 cont = SV_PointQ1Contents(point);
871 if (cont <= CONTENTS_WATER)
872 ent->v->waterlevel = 3;
876 return ent->v->waterlevel > 1;
885 void SV_WallFriction (edict_t *ent, float *stepnormal)
888 vec3_t forward, into, side;
890 AngleVectors (ent->v->v_angle, forward, NULL, NULL);
891 if ((d = DotProduct (stepnormal, forward) + 0.5) < 0)
893 // cut the tangential velocity
894 i = DotProduct (stepnormal, ent->v->velocity);
895 VectorScale (stepnormal, i, into);
896 VectorSubtract (ent->v->velocity, into, side);
897 ent->v->velocity[0] = side[0] * (1 + d);
898 ent->v->velocity[1] = side[1] * (1 + d);
903 =====================
906 Player has come to a dead stop, possibly due to the problem with limited
907 float precision at some angle joins in the BSP hull.
909 Try fixing by pushing one pixel in each direction.
911 This is a hack, but in the interest of good gameplay...
912 ======================
914 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
919 VectorCopy (ent->v->origin, oldorg);
922 for (i=0 ; i<8 ; i++)
924 // try pushing a little in an axial direction
927 case 0: dir[0] = 2; dir[1] = 0; break;
928 case 1: dir[0] = 0; dir[1] = 2; break;
929 case 2: dir[0] = -2; dir[1] = 0; break;
930 case 3: dir[0] = 0; dir[1] = -2; break;
931 case 4: dir[0] = 2; dir[1] = 2; break;
932 case 5: dir[0] = -2; dir[1] = 2; break;
933 case 6: dir[0] = 2; dir[1] = -2; break;
934 case 7: dir[0] = -2; dir[1] = -2; break;
937 SV_PushEntity (ent, dir, vec3_origin);
939 // retry the original move
940 ent->v->velocity[0] = oldvel[0];
941 ent->v->velocity[1] = oldvel[1];
942 ent->v->velocity[2] = 0;
943 clip = SV_FlyMove (ent, 0.1, NULL);
945 if (fabs(oldorg[1] - ent->v->origin[1]) > 4
946 || fabs(oldorg[0] - ent->v->origin[0]) > 4)
948 Con_DPrintf("TryUnstick - success.\n");
952 // go back to the original pos and try again
953 VectorCopy (oldorg, ent->v->origin);
957 VectorClear (ent->v->velocity);
958 Con_DPrintf("TryUnstick - failure.\n");
963 =====================
967 ======================
969 void SV_WalkMove (edict_t *ent)
971 int clip, oldonground;
972 vec3_t upmove, downmove, oldorg, oldvel, nosteporg, nostepvel, stepnormal;
975 SV_CheckVelocity(ent);
977 // do a regular slide move unless it looks like you ran into a step
978 oldonground = (int)ent->v->flags & FL_ONGROUND;
979 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
981 VectorCopy (ent->v->origin, oldorg);
982 VectorCopy (ent->v->velocity, oldvel);
984 clip = SV_FlyMove (ent, sv.frametime, NULL);
986 SV_CheckVelocity(ent);
988 // if move didn't block on a step, return
992 if (ent->v->movetype != MOVETYPE_FLY)
994 if (!oldonground && ent->v->waterlevel == 0 && !sv_jumpstep.integer)
995 // don't stair up while jumping
998 if (ent->v->movetype != MOVETYPE_WALK)
999 // gibbed by a trigger
1003 SV_CheckVelocity(ent);
1005 if (sv_nostep.integer || (int)ent->v->flags & FL_WATERJUMP )
1008 VectorCopy (ent->v->origin, nosteporg);
1009 VectorCopy (ent->v->velocity, nostepvel);
1011 // try moving up and forward to go up a step
1012 // back to start pos
1013 VectorCopy (oldorg, ent->v->origin);
1015 VectorClear (upmove);
1016 VectorClear (downmove);
1017 upmove[2] = sv_stepheight.value;
1018 downmove[2] = -sv_stepheight.value + oldvel[2]*sv.frametime;
1021 // FIXME: don't link?
1022 SV_PushEntity (ent, upmove, vec3_origin);
1025 ent->v->velocity[0] = oldvel[0];
1026 ent->v->velocity[1] = oldvel[1];
1027 ent->v->velocity[2] = 0;
1028 clip = SV_FlyMove (ent, sv.frametime, stepnormal);
1029 ent->v->velocity[2] += oldvel[2];
1031 // check for stuckness, possibly due to the limited precision of floats
1032 // in the clipping hulls
1034 && fabs(oldorg[1] - ent->v->origin[1]) < 0.03125
1035 && fabs(oldorg[0] - ent->v->origin[0]) < 0.03125)
1036 // stepping up didn't make any progress
1037 clip = SV_TryUnstick (ent, oldvel);
1039 // extra friction based on view angle
1040 if (clip & 2 && sv_wallfriction.integer)
1041 SV_WallFriction (ent, stepnormal);
1044 // FIXME: don't link?
1045 downtrace = SV_PushEntity (ent, downmove, vec3_origin);
1047 if (downtrace.plane.normal[2] > 0.7)
1049 // LordHavoc: disabled this so you can walk on monsters/players
1050 //if (ent->v->solid == SOLID_BSP)
1052 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1053 ent->v->groundentity = EDICT_TO_PROG(downtrace.ent);
1058 // if the push down didn't end up on good ground, use the move without
1059 // the step up. This happens near wall / slope combinations, and can
1060 // cause the player to hop up higher on a slope too steep to climb
1061 VectorCopy (nosteporg, ent->v->origin);
1062 VectorCopy (nostepvel, ent->v->velocity);
1065 SV_CheckVelocity(ent);
1068 //============================================================================
1074 Entities that are "stuck" to another entity
1077 void SV_Physics_Follow (edict_t *ent)
1079 vec3_t vf, vr, vu, angles, v;
1083 if (!SV_RunThink (ent))
1086 // LordHavoc: implemented rotation on MOVETYPE_FOLLOW objects
1087 e = PROG_TO_EDICT(ent->v->aiment);
1088 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])
1090 // quick case for no rotation
1091 VectorAdd(e->v->origin, ent->v->view_ofs, ent->v->origin);
1095 angles[0] = -ent->v->punchangle[0];
1096 angles[1] = ent->v->punchangle[1];
1097 angles[2] = ent->v->punchangle[2];
1098 AngleVectors (angles, vf, vr, vu);
1099 v[0] = ent->v->view_ofs[0] * vf[0] + ent->v->view_ofs[1] * vr[0] + ent->v->view_ofs[2] * vu[0];
1100 v[1] = ent->v->view_ofs[0] * vf[1] + ent->v->view_ofs[1] * vr[1] + ent->v->view_ofs[2] * vu[1];
1101 v[2] = ent->v->view_ofs[0] * vf[2] + ent->v->view_ofs[1] * vr[2] + ent->v->view_ofs[2] * vu[2];
1102 angles[0] = -e->v->angles[0];
1103 angles[1] = e->v->angles[1];
1104 angles[2] = e->v->angles[2];
1105 AngleVectors (angles, vf, vr, vu);
1106 ent->v->origin[0] = v[0] * vf[0] + v[1] * vf[1] + v[2] * vf[2] + e->v->origin[0];
1107 ent->v->origin[1] = v[0] * vr[0] + v[1] * vr[1] + v[2] * vr[2] + e->v->origin[1];
1108 ent->v->origin[2] = v[0] * vu[0] + v[1] * vu[1] + v[2] * vu[2] + e->v->origin[2];
1110 VectorAdd (e->v->angles, ent->v->v_angle, ent->v->angles);
1111 SV_LinkEdict (ent, true);
1115 ==============================================================================
1119 ==============================================================================
1124 SV_CheckWaterTransition
1128 void SV_CheckWaterTransition (edict_t *ent)
1131 cont = SV_PointQ1Contents(ent->v->origin);
1132 if (!ent->v->watertype)
1134 // just spawned here
1135 ent->v->watertype = cont;
1136 ent->v->waterlevel = 1;
1140 // check if the entity crossed into or out of water
1141 if ((ent->v->watertype == CONTENTS_WATER || ent->v->watertype == CONTENTS_SLIME) != (cont == CONTENTS_WATER || cont == CONTENTS_SLIME))
1142 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1144 if (cont <= CONTENTS_WATER)
1146 ent->v->watertype = cont;
1147 ent->v->waterlevel = 1;
1151 ent->v->watertype = CONTENTS_EMPTY;
1152 ent->v->waterlevel = 0;
1160 Toss, bounce, and fly movement. When onground, do nothing.
1163 void SV_Physics_Toss (edict_t *ent)
1167 edict_t *groundentity;
1170 if (!SV_RunThink (ent))
1173 // if onground, return without moving
1174 if ((int)ent->v->flags & FL_ONGROUND)
1176 if (ent->v->groundentity == 0)
1178 // if ent was supported by a brush model on previous frame,
1179 // and groundentity is now freed, set groundentity to 0 (floating)
1180 groundentity = PROG_TO_EDICT(ent->v->groundentity);
1181 if (groundentity->v->solid == SOLID_BSP)
1183 ent->e->suspendedinairflag = true;
1186 else if (ent->e->suspendedinairflag && groundentity->e->free)
1188 // leave it suspended in the air
1189 ent->v->groundentity = 0;
1190 ent->e->suspendedinairflag = false;
1194 ent->e->suspendedinairflag = false;
1196 SV_CheckVelocity (ent);
1199 if (ent->v->movetype == MOVETYPE_TOSS || ent->v->movetype == MOVETYPE_BOUNCE)
1200 SV_AddGravity (ent);
1203 VectorMA (ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1206 VectorScale (ent->v->velocity, sv.frametime, move);
1207 trace = SV_PushEntity (ent, move, vec3_origin);
1211 if (trace.fraction < 1)
1213 if (ent->v->movetype == MOVETYPE_BOUNCEMISSILE)
1215 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 2.0);
1216 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1218 else if (ent->v->movetype == MOVETYPE_BOUNCE)
1220 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.5);
1221 // LordHavoc: fixed grenades not bouncing when fired down a slope
1222 if (trace.plane.normal[2] > 0.7 && DotProduct(trace.plane.normal, ent->v->velocity) < 60)
1224 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1225 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1226 VectorClear (ent->v->velocity);
1227 VectorClear (ent->v->avelocity);
1230 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1234 ClipVelocity (ent->v->velocity, trace.plane.normal, ent->v->velocity, 1.0);
1235 if (trace.plane.normal[2] > 0.7)
1237 ent->v->flags = (int)ent->v->flags | FL_ONGROUND;
1238 ent->v->groundentity = EDICT_TO_PROG(trace.ent);
1239 VectorClear (ent->v->velocity);
1240 VectorClear (ent->v->avelocity);
1243 ent->v->flags = (int)ent->v->flags & ~FL_ONGROUND;
1247 // check for in water
1248 SV_CheckWaterTransition (ent);
1252 ===============================================================================
1256 ===============================================================================
1263 Monsters freefall when they don't have a ground entity, otherwise
1264 all movement is done with discrete steps.
1266 This is also used for objects that have become still on the ground, but
1267 will fall if the floor is pulled out from under them.
1270 void SV_Physics_Step (edict_t *ent)
1272 // freefall if not onground/fly/swim
1273 if (!((int)ent->v->flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))
1275 int hitsound = ent->v->velocity[2] < sv_gravity.value * -0.1;
1278 SV_CheckVelocity(ent);
1279 SV_FlyMove(ent, sv.frametime, NULL);
1280 SV_LinkEdict(ent, true);
1283 if (hitsound && (int)ent->v->flags & FL_ONGROUND)
1284 SV_StartSound(ent, 0, "demon/dland2.wav", 255, 1);
1290 SV_CheckWaterTransition(ent);
1293 //============================================================================
1301 void SV_Physics (void)
1306 // let the progs know that a new frame has started
1307 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1308 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1309 pr_global_struct->time = sv.time;
1310 PR_ExecuteProgram (pr_global_struct->StartFrame, "QC function StartFrame is missing");
1313 // treat each object in turn
1316 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1321 if (pr_global_struct->force_retouch)
1322 SV_LinkEdict (ent, true); // force retouch even for stationary
1324 if (i > 0 && i <= svs.maxclients)
1326 if (!svs.clients[i-1].spawned)
1329 // call standard client pre-think
1330 SV_CheckVelocity (ent);
1331 pr_global_struct->time = sv.time;
1332 pr_global_struct->self = EDICT_TO_PROG(ent);
1333 PR_ExecuteProgram (pr_global_struct->PlayerPreThink, "QC function PlayerPreThink is missing");
1334 SV_CheckVelocity (ent);
1337 // LordHavoc: merged client and normal entity physics
1338 switch ((int) ent->v->movetype)
1341 SV_Physics_Pusher (ent);
1344 // LordHavoc: manually inlined the thinktime check here because MOVETYPE_NONE is used on so many objects
1345 if (ent->v->nextthink > 0 && ent->v->nextthink <= sv.time + sv.frametime)
1348 case MOVETYPE_FOLLOW:
1349 SV_Physics_Follow (ent);
1351 case MOVETYPE_NOCLIP:
1352 if (SV_RunThink(ent))
1355 VectorMA(ent->v->origin, sv.frametime, ent->v->velocity, ent->v->origin);
1356 VectorMA(ent->v->angles, sv.frametime, ent->v->avelocity, ent->v->angles);
1358 // relink normal entities here, players always get relinked so don't relink twice
1359 if (!(i > 0 && i <= svs.maxclients))
1360 SV_LinkEdict(ent, false);
1363 SV_Physics_Step (ent);
1366 if (SV_RunThink (ent))
1368 if (!SV_CheckWater (ent) && ! ((int)ent->v->flags & FL_WATERJUMP) )
1369 SV_AddGravity (ent);
1370 SV_CheckStuck (ent);
1372 // relink normal entities here, players always get relinked so don't relink twice
1373 if (!(i > 0 && i <= svs.maxclients))
1374 SV_LinkEdict (ent, true);
1378 case MOVETYPE_BOUNCE:
1379 case MOVETYPE_BOUNCEMISSILE:
1380 case MOVETYPE_FLYMISSILE:
1381 SV_Physics_Toss (ent);
1384 if (i > 0 && i <= svs.maxclients)
1386 if (SV_RunThink (ent))
1388 SV_CheckWater (ent);
1393 SV_Physics_Toss (ent);
1396 Host_Error ("SV_Physics: bad movetype %i", (int)ent->v->movetype);
1400 if (i > 0 && i <= svs.maxclients && !ent->e->free)
1402 SV_CheckVelocity (ent);
1404 // call standard player post-think
1405 SV_LinkEdict (ent, true);
1407 SV_CheckVelocity (ent);
1409 pr_global_struct->time = sv.time;
1410 pr_global_struct->self = EDICT_TO_PROG(ent);
1411 PR_ExecuteProgram (pr_global_struct->PlayerPostThink, "QC function PlayerPostThink is missing");
1415 if (pr_global_struct->force_retouch)
1416 pr_global_struct->force_retouch--;
1418 // LordHavoc: endframe support
1421 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1422 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1423 pr_global_struct->time = sv.time;
1424 PR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions), "");
1427 sv.time += sv.frametime;
1431 trace_t SV_Trace_Toss (edict_t *tossent, edict_t *ignore)
1434 float gravity, savesolid;
1436 edict_t tempent, *tent;
1441 // copy the vars over
1442 memcpy(&vars, tossent->v, sizeof(entvars_t));
1443 // set up the temp entity to point to the copied vars
1447 savesolid = tossent->v->solid;
1448 tossent->v->solid = SOLID_NOT;
1450 // this has to fetch the field from the original edict, since our copy is truncated
1451 val = GETEDICTFIELDVALUE(tossent, eval_gravity);
1452 if (val != NULL && val->_float != 0)
1453 gravity = val->_float;
1456 gravity *= sv_gravity.value * 0.05;
1458 for (i = 0;i < 200;i++) // LordHavoc: sanity check; never trace more than 10 seconds
1460 SV_CheckVelocity (tent);
1461 tent->v->velocity[2] -= gravity;
1462 VectorMA (tent->v->angles, 0.05, tent->v->avelocity, tent->v->angles);
1463 VectorScale (tent->v->velocity, 0.05, move);
1464 VectorAdd (tent->v->origin, move, end);
1465 trace = SV_Move (tent->v->origin, tent->v->mins, tent->v->maxs, end, MOVE_NORMAL, tent);
1466 VectorCopy (trace.endpos, tent->v->origin);
1468 if (trace.fraction < 1 && trace.ent)
1469 if (trace.ent != ignore)
1472 tossent->v->solid = savesolid;
1473 trace.fraction = 0; // not relevant