Fix for the problem that SDL applications exited
[AROS-Contrib.git] / Games / Quake / sv_phys.c
blobe13c0e443dccc8b3843f87b7ba6c472024d29c6d
1 /*
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.
20 // sv_phys.c
22 #include "quakedef.h"
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 = {"sv_friction","4",false,true};
43 cvar_t sv_stopspeed = {"sv_stopspeed","100"};
44 cvar_t sv_gravity = {"sv_gravity","800",false,true};
45 cvar_t sv_maxvelocity = {"sv_maxvelocity","2000"};
46 cvar_t sv_nostep = {"sv_nostep","0"};
48 #ifdef QUAKE2
49 static vec3_t vec_origin = {0.0, 0.0, 0.0};
50 #endif
52 #define MOVE_EPSILON 0.01
54 void SV_Physics_Toss (edict_t *ent);
57 ================
58 SV_CheckAllEnts
59 ================
61 void SV_CheckAllEnts (void)
63 int e;
64 edict_t *check;
66 // see if any solid entities are inside the final position
67 check = NEXT_EDICT(sv.edicts);
68 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
70 if (check->free)
71 continue;
72 if (check->v.movetype == MOVETYPE_PUSH
73 || check->v.movetype == MOVETYPE_NONE
74 #ifdef QUAKE2
75 || check->v.movetype == MOVETYPE_FOLLOW
76 #endif
77 || check->v.movetype == MOVETYPE_NOCLIP)
78 continue;
80 if (SV_TestEntityPosition (check))
81 Con_Printf ("entity in invalid position\n");
86 ================
87 SV_CheckVelocity
88 ================
90 void SV_CheckVelocity (edict_t *ent)
92 int i;
95 // bound velocity
97 for (i=0 ; i<3 ; i++)
99 if (IS_NAN(ent->v.velocity[i]))
101 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
102 ent->v.velocity[i] = 0;
104 if (IS_NAN(ent->v.origin[i]))
106 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
107 ent->v.origin[i] = 0;
109 if (ent->v.velocity[i] > sv_maxvelocity.value)
110 ent->v.velocity[i] = sv_maxvelocity.value;
111 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
112 ent->v.velocity[i] = -sv_maxvelocity.value;
117 =============
118 SV_RunThink
120 Runs thinking code if time. There is some play in the exact time the think
121 function will be called, because it is called before any movement is done
122 in a frame. Not used for pushmove objects, because they must be exact.
123 Returns false if the entity removed itself.
124 =============
126 qboolean SV_RunThink (edict_t *ent)
128 float thinktime;
130 thinktime = ent->v.nextthink;
131 if (thinktime <= 0 || thinktime > sv.time + host_frametime)
132 return true;
134 if (thinktime < sv.time)
135 thinktime = sv.time; // don't let things stay in the past.
136 // it is possible to start that way
137 // by a trigger with a local time.
138 ent->v.nextthink = 0;
139 pr_global_struct->time = thinktime;
140 pr_global_struct->self = EDICT_TO_PROG(ent);
141 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
142 PR_ExecuteProgram (ent->v.think);
143 return !ent->free;
147 ==================
148 SV_Impact
150 Two entities have touched, so run their touch functions
151 ==================
153 void SV_Impact (edict_t *e1, edict_t *e2)
155 int old_self, old_other;
157 old_self = pr_global_struct->self;
158 old_other = pr_global_struct->other;
160 pr_global_struct->time = sv.time;
161 if (e1->v.touch && e1->v.solid != SOLID_NOT)
163 pr_global_struct->self = EDICT_TO_PROG(e1);
164 pr_global_struct->other = EDICT_TO_PROG(e2);
165 PR_ExecuteProgram (e1->v.touch);
168 if (e2->v.touch && e2->v.solid != SOLID_NOT)
170 pr_global_struct->self = EDICT_TO_PROG(e2);
171 pr_global_struct->other = EDICT_TO_PROG(e1);
172 PR_ExecuteProgram (e2->v.touch);
175 pr_global_struct->self = old_self;
176 pr_global_struct->other = old_other;
181 ==================
182 ClipVelocity
184 Slide off of the impacting object
185 returns the blocked flags (1 = floor, 2 = step / wall)
186 ==================
188 #define STOP_EPSILON 0.1
190 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
192 float backoff;
193 float change;
194 int i, blocked;
196 blocked = 0;
197 if (normal[2] > 0)
198 blocked |= 1; // floor
199 if (!normal[2])
200 blocked |= 2; // step
202 backoff = DotProduct (in, normal) * overbounce;
204 for (i=0 ; i<3 ; i++)
206 change = normal[i]*backoff;
207 out[i] = in[i] - change;
208 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
209 out[i] = 0;
212 return blocked;
217 ============
218 SV_FlyMove
220 The basic solid body movement clip that slides along multiple planes
221 Returns the clipflags if the velocity was modified (hit something solid)
222 1 = floor
223 2 = wall / step
224 4 = dead stop
225 If steptrace is not NULL, the trace of any vertical wall hit will be stored
226 ============
228 #define MAX_CLIP_PLANES 5
229 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
231 int bumpcount, numbumps;
232 vec3_t dir;
233 float d;
234 int numplanes;
235 vec3_t planes[MAX_CLIP_PLANES];
236 vec3_t primal_velocity, original_velocity, new_velocity;
237 int i, j;
238 trace_t trace;
239 vec3_t end;
240 float time_left;
241 int blocked;
243 numbumps = 4;
245 blocked = 0;
246 VectorCopy (ent->v.velocity, original_velocity);
247 VectorCopy (ent->v.velocity, primal_velocity);
248 numplanes = 0;
250 time_left = time;
252 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
254 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
255 break;
257 for (i=0 ; i<3 ; i++)
258 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
260 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
262 if (trace.allsolid)
263 { // entity is trapped in another solid
264 VectorCopy (vec3_origin, ent->v.velocity);
265 return 3;
268 if (trace.fraction > 0)
269 { // actually covered some distance
270 VectorCopy (trace.endpos, ent->v.origin);
271 VectorCopy (ent->v.velocity, original_velocity);
272 numplanes = 0;
275 if (trace.fraction == 1)
276 break; // moved the entire distance
278 if (!trace.ent)
279 Sys_Error ("SV_FlyMove: !trace.ent");
281 if (trace.plane.normal[2] > 0.7)
283 blocked |= 1; // floor
284 if (trace.ent->v.solid == SOLID_BSP)
286 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
287 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
290 if (!trace.plane.normal[2])
292 blocked |= 2; // step
293 if (steptrace)
294 *steptrace = trace; // save for player extrafriction
298 // run the impact function
300 SV_Impact (ent, trace.ent);
301 if (ent->free)
302 break; // removed by the impact function
305 time_left -= time_left * trace.fraction;
307 // cliped to another plane
308 if (numplanes >= MAX_CLIP_PLANES)
309 { // this shouldn't really happen
310 VectorCopy (vec3_origin, ent->v.velocity);
311 return 3;
314 VectorCopy (trace.plane.normal, planes[numplanes]);
315 numplanes++;
318 // modify original_velocity so it parallels all of the clip planes
320 for (i=0 ; i<numplanes ; i++)
322 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
323 for (j=0 ; j<numplanes ; j++)
324 if (j != i)
326 if (DotProduct (new_velocity, planes[j]) < 0)
327 break; // not ok
329 if (j == numplanes)
330 break;
333 if (i != numplanes)
334 { // go along this plane
335 VectorCopy (new_velocity, ent->v.velocity);
337 else
338 { // go along the crease
339 if (numplanes != 2)
341 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
342 VectorCopy (vec3_origin, ent->v.velocity);
343 return 7;
345 CrossProduct (planes[0], planes[1], dir);
346 d = DotProduct (dir, ent->v.velocity);
347 VectorScale (dir, d, ent->v.velocity);
351 // if original velocity is against the original velocity, stop dead
352 // to avoid tiny occilations in sloping corners
354 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
356 VectorCopy (vec3_origin, ent->v.velocity);
357 return blocked;
361 return blocked;
366 ============
367 SV_AddGravity
369 ============
371 void SV_AddGravity (edict_t *ent)
373 float ent_gravity;
375 #ifdef QUAKE2
376 if (ent->v.gravity)
377 ent_gravity = ent->v.gravity;
378 else
379 ent_gravity = 1.0;
380 #else
381 eval_t *val;
383 val = GetEdictFieldValue(ent, "gravity");
384 if (val && val->_float)
385 ent_gravity = val->_float;
386 else
387 ent_gravity = 1.0;
388 #endif
389 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
394 ===============================================================================
396 PUSHMOVE
398 ===============================================================================
402 ============
403 SV_PushEntity
405 Does not change the entities velocity at all
406 ============
408 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
410 trace_t trace;
411 vec3_t end;
413 VectorAdd (ent->v.origin, push, end);
415 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
416 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
417 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
418 // only clip against bmodels
419 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
420 else
421 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
423 VectorCopy (trace.endpos, ent->v.origin);
424 SV_LinkEdict (ent, true);
426 if (trace.ent)
427 SV_Impact (ent, trace.ent);
429 return trace;
434 ============
435 SV_PushMove
437 ============
439 void SV_PushMove (edict_t *pusher, float movetime)
441 int i, e;
442 edict_t *check, *block;
443 vec3_t mins, maxs, move;
444 vec3_t entorig, pushorig;
445 int num_moved;
446 edict_t *moved_edict[MAX_EDICTS];
447 vec3_t moved_from[MAX_EDICTS];
449 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
451 pusher->v.ltime += movetime;
452 return;
455 for (i=0 ; i<3 ; i++)
457 move[i] = pusher->v.velocity[i] * movetime;
458 mins[i] = pusher->v.absmin[i] + move[i];
459 maxs[i] = pusher->v.absmax[i] + move[i];
462 VectorCopy (pusher->v.origin, pushorig);
464 // move the pusher to it's final position
466 VectorAdd (pusher->v.origin, move, pusher->v.origin);
467 pusher->v.ltime += movetime;
468 SV_LinkEdict (pusher, false);
471 // see if any solid entities are inside the final position
472 num_moved = 0;
473 check = NEXT_EDICT(sv.edicts);
474 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
476 if (check->free)
477 continue;
478 if (check->v.movetype == MOVETYPE_PUSH
479 || check->v.movetype == MOVETYPE_NONE
480 #ifdef QUAKE2
481 || check->v.movetype == MOVETYPE_FOLLOW
482 #endif
483 || check->v.movetype == MOVETYPE_NOCLIP)
484 continue;
486 // if the entity is standing on the pusher, it will definately be moved
487 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
488 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
490 if ( check->v.absmin[0] >= maxs[0]
491 || check->v.absmin[1] >= maxs[1]
492 || check->v.absmin[2] >= maxs[2]
493 || check->v.absmax[0] <= mins[0]
494 || check->v.absmax[1] <= mins[1]
495 || check->v.absmax[2] <= mins[2] )
496 continue;
498 // see if the ent's bbox is inside the pusher's final position
499 if (!SV_TestEntityPosition (check))
500 continue;
503 // remove the onground flag for non-players
504 if (check->v.movetype != MOVETYPE_WALK)
505 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
507 VectorCopy (check->v.origin, entorig);
508 VectorCopy (check->v.origin, moved_from[num_moved]);
509 moved_edict[num_moved] = check;
510 num_moved++;
512 // try moving the contacted entity
513 pusher->v.solid = SOLID_NOT;
514 SV_PushEntity (check, move);
515 pusher->v.solid = SOLID_BSP;
517 // if it is still inside the pusher, block
518 block = SV_TestEntityPosition (check);
519 if (block)
520 { // fail the move
521 if (check->v.mins[0] == check->v.maxs[0])
522 continue;
523 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
524 { // corpse
525 check->v.mins[0] = check->v.mins[1] = 0;
526 VectorCopy (check->v.mins, check->v.maxs);
527 continue;
530 VectorCopy (entorig, check->v.origin);
531 SV_LinkEdict (check, true);
533 VectorCopy (pushorig, pusher->v.origin);
534 SV_LinkEdict (pusher, false);
535 pusher->v.ltime -= movetime;
537 // if the pusher has a "blocked" function, call it
538 // otherwise, just stay in place until the obstacle is gone
539 if (pusher->v.blocked)
541 pr_global_struct->self = EDICT_TO_PROG(pusher);
542 pr_global_struct->other = EDICT_TO_PROG(check);
543 PR_ExecuteProgram (pusher->v.blocked);
546 // move back any entities we already moved
547 for (i=0 ; i<num_moved ; i++)
549 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
550 SV_LinkEdict (moved_edict[i], false);
552 return;
559 #ifdef QUAKE2
561 ============
562 SV_PushRotate
564 ============
566 void SV_PushRotate (edict_t *pusher, float movetime)
568 int i, e;
569 edict_t *check, *block;
570 vec3_t move, a, amove;
571 vec3_t entorig, pushorig;
572 int num_moved;
573 edict_t *moved_edict[MAX_EDICTS];
574 vec3_t moved_from[MAX_EDICTS];
575 vec3_t org, org2;
576 vec3_t forward, right, up;
578 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
580 pusher->v.ltime += movetime;
581 return;
584 for (i=0 ; i<3 ; i++)
585 amove[i] = pusher->v.avelocity[i] * movetime;
587 VectorSubtract (vec3_origin, amove, a);
588 AngleVectors (a, forward, right, up);
590 VectorCopy (pusher->v.angles, pushorig);
592 // move the pusher to it's final position
594 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
595 pusher->v.ltime += movetime;
596 SV_LinkEdict (pusher, false);
599 // see if any solid entities are inside the final position
600 num_moved = 0;
601 check = NEXT_EDICT(sv.edicts);
602 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
604 if (check->free)
605 continue;
606 if (check->v.movetype == MOVETYPE_PUSH
607 || check->v.movetype == MOVETYPE_NONE
608 || check->v.movetype == MOVETYPE_FOLLOW
609 || check->v.movetype == MOVETYPE_NOCLIP)
610 continue;
612 // if the entity is standing on the pusher, it will definately be moved
613 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
614 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
616 if ( check->v.absmin[0] >= pusher->v.absmax[0]
617 || check->v.absmin[1] >= pusher->v.absmax[1]
618 || check->v.absmin[2] >= pusher->v.absmax[2]
619 || check->v.absmax[0] <= pusher->v.absmin[0]
620 || check->v.absmax[1] <= pusher->v.absmin[1]
621 || check->v.absmax[2] <= pusher->v.absmin[2] )
622 continue;
624 // see if the ent's bbox is inside the pusher's final position
625 if (!SV_TestEntityPosition (check))
626 continue;
629 // remove the onground flag for non-players
630 if (check->v.movetype != MOVETYPE_WALK)
631 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
633 VectorCopy (check->v.origin, entorig);
634 VectorCopy (check->v.origin, moved_from[num_moved]);
635 moved_edict[num_moved] = check;
636 num_moved++;
638 // calculate destination position
639 VectorSubtract (check->v.origin, pusher->v.origin, org);
640 org2[0] = DotProduct (org, forward);
641 org2[1] = -DotProduct (org, right);
642 org2[2] = DotProduct (org, up);
643 VectorSubtract (org2, org, move);
645 // try moving the contacted entity
646 pusher->v.solid = SOLID_NOT;
647 SV_PushEntity (check, move);
648 pusher->v.solid = SOLID_BSP;
650 // if it is still inside the pusher, block
651 block = SV_TestEntityPosition (check);
652 if (block)
653 { // fail the move
654 if (check->v.mins[0] == check->v.maxs[0])
655 continue;
656 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
657 { // corpse
658 check->v.mins[0] = check->v.mins[1] = 0;
659 VectorCopy (check->v.mins, check->v.maxs);
660 continue;
663 VectorCopy (entorig, check->v.origin);
664 SV_LinkEdict (check, true);
666 VectorCopy (pushorig, pusher->v.angles);
667 SV_LinkEdict (pusher, false);
668 pusher->v.ltime -= movetime;
670 // if the pusher has a "blocked" function, call it
671 // otherwise, just stay in place until the obstacle is gone
672 if (pusher->v.blocked)
674 pr_global_struct->self = EDICT_TO_PROG(pusher);
675 pr_global_struct->other = EDICT_TO_PROG(check);
676 PR_ExecuteProgram (pusher->v.blocked);
679 // move back any entities we already moved
680 for (i=0 ; i<num_moved ; i++)
682 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
683 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
684 SV_LinkEdict (moved_edict[i], false);
686 return;
688 else
690 VectorAdd (check->v.angles, amove, check->v.angles);
696 #endif
699 ================
700 SV_Physics_Pusher
702 ================
704 void SV_Physics_Pusher (edict_t *ent)
706 float thinktime;
707 float oldltime;
708 float movetime;
710 oldltime = ent->v.ltime;
712 thinktime = ent->v.nextthink;
713 if (thinktime < ent->v.ltime + host_frametime)
715 movetime = thinktime - ent->v.ltime;
716 if (movetime < 0)
717 movetime = 0;
719 else
720 movetime = host_frametime;
722 if (movetime)
724 #ifdef QUAKE2
725 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
726 SV_PushRotate (ent, movetime);
727 else
728 #endif
729 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
732 if (thinktime > oldltime && thinktime <= ent->v.ltime)
734 ent->v.nextthink = 0;
735 pr_global_struct->time = sv.time;
736 pr_global_struct->self = EDICT_TO_PROG(ent);
737 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
738 PR_ExecuteProgram (ent->v.think);
739 if (ent->free)
740 return;
747 ===============================================================================
749 CLIENT MOVEMENT
751 ===============================================================================
755 =============
756 SV_CheckStuck
758 This is a big hack to try and fix the rare case of getting stuck in the world
759 clipping hull.
760 =============
762 void SV_CheckStuck (edict_t *ent)
764 int i, j;
765 int z;
766 vec3_t org;
768 if (!SV_TestEntityPosition(ent))
770 VectorCopy (ent->v.origin, ent->v.oldorigin);
771 return;
774 VectorCopy (ent->v.origin, org);
775 VectorCopy (ent->v.oldorigin, ent->v.origin);
776 if (!SV_TestEntityPosition(ent))
778 Con_DPrintf ("Unstuck.\n");
779 SV_LinkEdict (ent, true);
780 return;
783 for (z=0 ; z< 18 ; z++)
784 for (i=-1 ; i <= 1 ; i++)
785 for (j=-1 ; j <= 1 ; j++)
787 ent->v.origin[0] = org[0] + i;
788 ent->v.origin[1] = org[1] + j;
789 ent->v.origin[2] = org[2] + z;
790 if (!SV_TestEntityPosition(ent))
792 Con_DPrintf ("Unstuck.\n");
793 SV_LinkEdict (ent, true);
794 return;
798 VectorCopy (org, ent->v.origin);
799 Con_DPrintf ("player is stuck.\n");
804 =============
805 SV_CheckWater
806 =============
808 qboolean SV_CheckWater (edict_t *ent)
810 vec3_t point;
811 int cont;
812 #ifdef QUAKE2
813 int truecont;
814 #endif
816 point[0] = ent->v.origin[0];
817 point[1] = ent->v.origin[1];
818 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
820 ent->v.waterlevel = 0;
821 ent->v.watertype = CONTENTS_EMPTY;
822 cont = SV_PointContents (point);
823 if (cont <= CONTENTS_WATER)
825 #ifdef QUAKE2
826 truecont = SV_TruePointContents (point);
827 #endif
828 ent->v.watertype = cont;
829 ent->v.waterlevel = 1;
830 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
831 cont = SV_PointContents (point);
832 if (cont <= CONTENTS_WATER)
834 ent->v.waterlevel = 2;
835 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
836 cont = SV_PointContents (point);
837 if (cont <= CONTENTS_WATER)
838 ent->v.waterlevel = 3;
840 #ifdef QUAKE2
841 if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
843 static vec3_t current_table[] =
845 {1, 0, 0},
846 {0, 1, 0},
847 {-1, 0, 0},
848 {0, -1, 0},
849 {0, 0, 1},
850 {0, 0, -1}
853 VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);
855 #endif
858 return ent->v.waterlevel > 1;
862 ============
863 SV_WallFriction
865 ============
867 void SV_WallFriction (edict_t *ent, trace_t *trace)
869 vec3_t forward, right, up;
870 float d, i;
871 vec3_t into, side;
873 AngleVectors (ent->v.v_angle, forward, right, up);
874 d = DotProduct (trace->plane.normal, forward);
876 d += 0.5;
877 if (d >= 0)
878 return;
880 // cut the tangential velocity
881 i = DotProduct (trace->plane.normal, ent->v.velocity);
882 VectorScale (trace->plane.normal, i, into);
883 VectorSubtract (ent->v.velocity, into, side);
885 ent->v.velocity[0] = side[0] * (1 + d);
886 ent->v.velocity[1] = side[1] * (1 + d);
890 =====================
891 SV_TryUnstick
893 Player has come to a dead stop, possibly due to the problem with limited
894 float precision at some angle joins in the BSP hull.
896 Try fixing by pushing one pixel in each direction.
898 This is a hack, but in the interest of good gameplay...
899 ======================
901 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
903 int i;
904 vec3_t oldorg;
905 vec3_t dir;
906 int clip;
907 trace_t steptrace;
909 VectorCopy (ent->v.origin, oldorg);
910 VectorCopy (vec3_origin, dir);
912 for (i=0 ; i<8 ; i++)
914 // try pushing a little in an axial direction
915 switch (i)
917 case 0: dir[0] = 2; dir[1] = 0; break;
918 case 1: dir[0] = 0; dir[1] = 2; break;
919 case 2: dir[0] = -2; dir[1] = 0; break;
920 case 3: dir[0] = 0; dir[1] = -2; break;
921 case 4: dir[0] = 2; dir[1] = 2; break;
922 case 5: dir[0] = -2; dir[1] = 2; break;
923 case 6: dir[0] = 2; dir[1] = -2; break;
924 case 7: dir[0] = -2; dir[1] = -2; break;
927 SV_PushEntity (ent, dir);
929 // retry the original move
930 ent->v.velocity[0] = oldvel[0];
931 ent->v. velocity[1] = oldvel[1];
932 ent->v. velocity[2] = 0;
933 clip = SV_FlyMove (ent, 0.1, &steptrace);
935 if ( fabs(oldorg[1] - ent->v.origin[1]) > 4
936 || fabs(oldorg[0] - ent->v.origin[0]) > 4 )
938 //Con_DPrintf ("unstuck!\n");
939 return clip;
942 // go back to the original pos and try again
943 VectorCopy (oldorg, ent->v.origin);
946 VectorCopy (vec3_origin, ent->v.velocity);
947 return 7; // still not moving
951 =====================
952 SV_WalkMove
954 Only used by players
955 ======================
957 #define STEPSIZE 18
958 void SV_WalkMove (edict_t *ent)
960 vec3_t upmove, downmove;
961 vec3_t oldorg, oldvel;
962 vec3_t nosteporg, nostepvel;
963 int clip;
964 int oldonground;
965 trace_t steptrace, downtrace;
968 // do a regular slide move unless it looks like you ran into a step
970 oldonground = (int)ent->v.flags & FL_ONGROUND;
971 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
973 VectorCopy (ent->v.origin, oldorg);
974 VectorCopy (ent->v.velocity, oldvel);
976 clip = SV_FlyMove (ent, host_frametime, &steptrace);
978 if ( !(clip & 2) )
979 return; // move didn't block on a step
981 if (!oldonground && ent->v.waterlevel == 0)
982 return; // don't stair up while jumping
984 if (ent->v.movetype != MOVETYPE_WALK)
985 return; // gibbed by a trigger
987 if (sv_nostep.value)
988 return;
990 if ( (int)sv_player->v.flags & FL_WATERJUMP )
991 return;
993 VectorCopy (ent->v.origin, nosteporg);
994 VectorCopy (ent->v.velocity, nostepvel);
997 // try moving up and forward to go up a step
999 VectorCopy (oldorg, ent->v.origin); // back to start pos
1001 VectorCopy (vec3_origin, upmove);
1002 VectorCopy (vec3_origin, downmove);
1003 upmove[2] = STEPSIZE;
1004 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1006 // move up
1007 SV_PushEntity (ent, upmove); // FIXME: don't link?
1009 // move forward
1010 ent->v.velocity[0] = oldvel[0];
1011 ent->v. velocity[1] = oldvel[1];
1012 ent->v. velocity[2] = 0;
1013 clip = SV_FlyMove (ent, host_frametime, &steptrace);
1015 // check for stuckness, possibly due to the limited precision of floats
1016 // in the clipping hulls
1017 if (clip)
1019 if ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125
1020 && fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1021 { // stepping up didn't make any progress
1022 clip = SV_TryUnstick (ent, oldvel);
1026 // extra friction based on view angle
1027 if ( clip & 2 )
1028 SV_WallFriction (ent, &steptrace);
1030 // move down
1031 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1033 if (downtrace.plane.normal[2] > 0.7)
1035 if (ent->v.solid == SOLID_BSP)
1037 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1038 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1041 else
1043 // if the push down didn't end up on good ground, use the move without
1044 // the step up. This happens near wall / slope combinations, and can
1045 // cause the player to hop up higher on a slope too steep to climb
1046 VectorCopy (nosteporg, ent->v.origin);
1047 VectorCopy (nostepvel, ent->v.velocity);
1053 ================
1054 SV_Physics_Client
1056 Player character actions
1057 ================
1059 void SV_Physics_Client (edict_t *ent, int num)
1061 if ( ! svs.clients[num-1].active )
1062 return; // unconnected slot
1065 // call standard client pre-think
1067 pr_global_struct->time = sv.time;
1068 pr_global_struct->self = EDICT_TO_PROG(ent);
1069 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1072 // do a move
1074 SV_CheckVelocity (ent);
1077 // decide which move function to call
1079 switch ((int)ent->v.movetype)
1081 case MOVETYPE_NONE:
1082 if (!SV_RunThink (ent))
1083 return;
1084 break;
1086 case MOVETYPE_WALK:
1087 if (!SV_RunThink (ent))
1088 return;
1089 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1090 SV_AddGravity (ent);
1091 SV_CheckStuck (ent);
1092 #ifdef QUAKE2
1093 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1094 #endif
1095 SV_WalkMove (ent);
1097 #ifdef QUAKE2
1098 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1099 #endif
1100 break;
1102 case MOVETYPE_TOSS:
1103 case MOVETYPE_BOUNCE:
1104 SV_Physics_Toss (ent);
1105 break;
1107 case MOVETYPE_FLY:
1108 if (!SV_RunThink (ent))
1109 return;
1110 SV_FlyMove (ent, host_frametime, NULL);
1111 break;
1113 case MOVETYPE_NOCLIP:
1114 if (!SV_RunThink (ent))
1115 return;
1116 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1117 break;
1119 default:
1120 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1124 // call standard player post-think
1126 SV_LinkEdict (ent, true);
1128 pr_global_struct->time = sv.time;
1129 pr_global_struct->self = EDICT_TO_PROG(ent);
1130 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1133 //============================================================================
1136 =============
1137 SV_Physics_None
1139 Non moving objects can only think
1140 =============
1142 void SV_Physics_None (edict_t *ent)
1144 // regular thinking
1145 SV_RunThink (ent);
1148 #ifdef QUAKE2
1150 =============
1151 SV_Physics_Follow
1153 Entities that are "stuck" to another entity
1154 =============
1156 void SV_Physics_Follow (edict_t *ent)
1158 // regular thinking
1159 SV_RunThink (ent);
1160 VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1161 SV_LinkEdict (ent, true);
1163 #endif
1166 =============
1167 SV_Physics_Noclip
1169 A moving object that doesn't obey physics
1170 =============
1172 void SV_Physics_Noclip (edict_t *ent)
1174 // regular thinking
1175 if (!SV_RunThink (ent))
1176 return;
1178 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1179 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1181 SV_LinkEdict (ent, false);
1185 ==============================================================================
1187 TOSS / BOUNCE
1189 ==============================================================================
1193 =============
1194 SV_CheckWaterTransition
1196 =============
1198 void SV_CheckWaterTransition (edict_t *ent)
1200 int cont;
1201 #ifdef QUAKE2
1202 vec3_t point;
1204 point[0] = ent->v.origin[0];
1205 point[1] = ent->v.origin[1];
1206 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
1207 cont = SV_PointContents (point);
1208 #else
1209 cont = SV_PointContents (ent->v.origin);
1210 #endif
1211 if (!ent->v.watertype)
1212 { // just spawned here
1213 ent->v.watertype = cont;
1214 ent->v.waterlevel = 1;
1215 return;
1218 if (cont <= CONTENTS_WATER)
1220 if (ent->v.watertype == CONTENTS_EMPTY)
1221 { // just crossed into water
1222 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1224 ent->v.watertype = cont;
1225 ent->v.waterlevel = 1;
1227 else
1229 if (ent->v.watertype != CONTENTS_EMPTY)
1230 { // just crossed into water
1231 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1233 ent->v.watertype = CONTENTS_EMPTY;
1234 ent->v.waterlevel = cont;
1239 =============
1240 SV_Physics_Toss
1242 Toss, bounce, and fly movement. When onground, do nothing.
1243 =============
1245 void SV_Physics_Toss (edict_t *ent)
1247 trace_t trace;
1248 vec3_t move;
1249 float backoff;
1250 #ifdef QUAKE2
1251 edict_t *groundentity;
1253 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1254 if ((int)groundentity->v.flags & FL_CONVEYOR)
1255 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1256 else
1257 VectorCopy(vec_origin, ent->v.basevelocity);
1258 SV_CheckWater (ent);
1259 #endif
1260 // regular thinking
1261 if (!SV_RunThink (ent))
1262 return;
1264 #ifdef QUAKE2
1265 if (ent->v.velocity[2] > 0)
1266 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1268 if ( ((int)ent->v.flags & FL_ONGROUND) )
1269 //@@
1270 if (VectorCompare(ent->v.basevelocity, vec_origin))
1271 return;
1273 SV_CheckVelocity (ent);
1275 // add gravity
1276 if (! ((int)ent->v.flags & FL_ONGROUND)
1277 && ent->v.movetype != MOVETYPE_FLY
1278 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE
1279 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1280 SV_AddGravity (ent);
1282 #else
1283 // if onground, return without moving
1284 if ( ((int)ent->v.flags & FL_ONGROUND) )
1285 return;
1287 SV_CheckVelocity (ent);
1289 // add gravity
1290 if (ent->v.movetype != MOVETYPE_FLY
1291 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1292 SV_AddGravity (ent);
1293 #endif
1295 // move angles
1296 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1298 // move origin
1299 #ifdef QUAKE2
1300 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1301 #endif
1302 VectorScale (ent->v.velocity, host_frametime, move);
1303 trace = SV_PushEntity (ent, move);
1304 #ifdef QUAKE2
1305 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1306 #endif
1307 if (trace.fraction == 1)
1308 return;
1309 if (ent->free)
1310 return;
1312 if (ent->v.movetype == MOVETYPE_BOUNCE)
1313 backoff = 1.5;
1314 #ifdef QUAKE2
1315 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1316 backoff = 2.0;
1317 #endif
1318 else
1319 backoff = 1;
1321 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1323 // stop if on ground
1324 if (trace.plane.normal[2] > 0.7)
1326 #ifdef QUAKE2
1327 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1328 #else
1329 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)
1330 #endif
1332 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1333 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1334 VectorCopy (vec3_origin, ent->v.velocity);
1335 VectorCopy (vec3_origin, ent->v.avelocity);
1339 // check for in water
1340 SV_CheckWaterTransition (ent);
1344 ===============================================================================
1346 STEPPING MOVEMENT
1348 ===============================================================================
1352 =============
1353 SV_Physics_Step
1355 Monsters freefall when they don't have a ground entity, otherwise
1356 all movement is done with discrete steps.
1358 This is also used for objects that have become still on the ground, but
1359 will fall if the floor is pulled out from under them.
1360 =============
1362 #ifdef QUAKE2
1363 void SV_Physics_Step (edict_t *ent)
1365 qboolean wasonground;
1366 qboolean inwater;
1367 qboolean hitsound = false;
1368 float *vel;
1369 float speed, newspeed, control;
1370 float friction;
1371 edict_t *groundentity;
1373 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1374 if ((int)groundentity->v.flags & FL_CONVEYOR)
1375 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1376 else
1377 VectorCopy(vec_origin, ent->v.basevelocity);
1378 //@@
1379 pr_global_struct->time = sv.time;
1380 pr_global_struct->self = EDICT_TO_PROG(ent);
1381 PF_WaterMove();
1383 SV_CheckVelocity (ent);
1385 wasonground = (int)ent->v.flags & FL_ONGROUND;
1386 // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1388 // add gravity except:
1389 // flying monsters
1390 // swimming monsters who are in the water
1391 inwater = SV_CheckWater(ent);
1392 if (! wasonground)
1393 if (!((int)ent->v.flags & FL_FLY))
1394 if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))
1396 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1397 hitsound = true;
1398 if (!inwater)
1399 SV_AddGravity (ent);
1402 if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))
1404 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1405 // apply friction
1406 // let dead monsters who aren't completely onground slide
1407 if (wasonground)
1408 if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))
1410 vel = ent->v.velocity;
1411 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
1412 if (speed)
1414 friction = sv_friction.value;
1416 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
1417 newspeed = speed - host_frametime*control*friction;
1419 if (newspeed < 0)
1420 newspeed = 0;
1421 newspeed /= speed;
1423 vel[0] = vel[0] * newspeed;
1424 vel[1] = vel[1] * newspeed;
1428 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1429 SV_FlyMove (ent, host_frametime, NULL);
1430 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1432 // determine if it's on solid ground at all
1434 vec3_t mins, maxs, point;
1435 int x, y;
1437 VectorAdd (ent->v.origin, ent->v.mins, mins);
1438 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
1440 point[2] = mins[2] - 1;
1441 for (x=0 ; x<=1 ; x++)
1442 for (y=0 ; y<=1 ; y++)
1444 point[0] = x ? maxs[0] : mins[0];
1445 point[1] = y ? maxs[1] : mins[1];
1446 if (SV_PointContents (point) == CONTENTS_SOLID)
1448 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1449 break;
1455 SV_LinkEdict (ent, true);
1457 if ((int)ent->v.flags & FL_ONGROUND)
1458 if (!wasonground)
1459 if (hitsound)
1460 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1463 // regular thinking
1464 SV_RunThink (ent);
1465 SV_CheckWaterTransition (ent);
1467 #else
1468 void SV_Physics_Step (edict_t *ent)
1470 qboolean hitsound;
1472 // freefall if not onground
1473 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1475 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1476 hitsound = true;
1477 else
1478 hitsound = false;
1480 SV_AddGravity (ent);
1481 SV_CheckVelocity (ent);
1482 SV_FlyMove (ent, host_frametime, NULL);
1483 SV_LinkEdict (ent, true);
1485 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1487 if (hitsound)
1488 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1492 // regular thinking
1493 SV_RunThink (ent);
1495 SV_CheckWaterTransition (ent);
1497 #endif
1499 //============================================================================
1502 ================
1503 SV_Physics
1505 ================
1507 void SV_Physics (void)
1509 int i;
1510 edict_t *ent;
1512 // let the progs know that a new frame has started
1513 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1514 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1515 pr_global_struct->time = sv.time;
1516 PR_ExecuteProgram (pr_global_struct->StartFrame);
1518 //SV_CheckAllEnts ();
1521 // treat each object in turn
1523 ent = sv.edicts;
1524 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1526 if (ent->free)
1527 continue;
1529 if (pr_global_struct->force_retouch)
1531 SV_LinkEdict (ent, true); // force retouch even for stationary
1534 if (i > 0 && i <= svs.maxclients)
1535 SV_Physics_Client (ent, i);
1536 else if (ent->v.movetype == MOVETYPE_PUSH)
1537 SV_Physics_Pusher (ent);
1538 else if (ent->v.movetype == MOVETYPE_NONE)
1539 SV_Physics_None (ent);
1540 #ifdef QUAKE2
1541 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1542 SV_Physics_Follow (ent);
1543 #endif
1544 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1545 SV_Physics_Noclip (ent);
1546 else if (ent->v.movetype == MOVETYPE_STEP)
1547 SV_Physics_Step (ent);
1548 else if (ent->v.movetype == MOVETYPE_TOSS
1549 || ent->v.movetype == MOVETYPE_BOUNCE
1550 #ifdef QUAKE2
1551 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1552 #endif
1553 || ent->v.movetype == MOVETYPE_FLY
1554 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1555 SV_Physics_Toss (ent);
1556 else
1557 Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1560 if (pr_global_struct->force_retouch)
1561 pr_global_struct->force_retouch--;
1563 sv.time += host_frametime;
1567 #ifdef QUAKE2
1568 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1570 edict_t tempent, *tent;
1571 trace_t trace;
1572 vec3_t move;
1573 vec3_t end;
1574 double save_frametime;
1575 // extern particle_t *active_particles, *free_particles;
1576 // particle_t *p;
1579 save_frametime = host_frametime;
1580 host_frametime = 0.05;
1582 memcpy(&tempent, ent, sizeof(edict_t));
1583 tent = &tempent;
1585 while (1)
1587 SV_CheckVelocity (tent);
1588 SV_AddGravity (tent);
1589 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1590 VectorScale (tent->v.velocity, host_frametime, move);
1591 VectorAdd (tent->v.origin, move, end);
1592 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1593 VectorCopy (trace.endpos, tent->v.origin);
1595 // p = free_particles;
1596 // if (p)
1597 // {
1598 // free_particles = p->next;
1599 // p->next = active_particles;
1600 // active_particles = p;
1602 // p->die = 256;
1603 // p->color = 15;
1604 // p->type = pt_static;
1605 // VectorCopy (vec3_origin, p->vel);
1606 // VectorCopy (tent->v.origin, p->org);
1607 // }
1609 if (trace.ent)
1610 if (trace.ent != ignore)
1611 break;
1613 // p->color = 224;
1614 host_frametime = save_frametime;
1615 return trace;
1617 #endif