git-svn-id: http://bladebattles.com/kurok/SVN@11 20cd92bb-ff49-0410-b73e-96a06e42c3b9
[kurok.git] / sv_phys.c
blobd6aaed14a494d2fca485a45d7661e552082eb226
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;
93 float wishspeed;
96 // bound velocity
98 for (i=0 ; i<3 ; i++)
100 if (IS_NAN(ent->v.velocity[i]))
102 Con_Printf ("Got a NaN velocity on %s\n", pr_strings + ent->v.classname);
103 ent->v.velocity[i] = 0;
105 if (IS_NAN(ent->v.origin[i]))
107 Con_Printf ("Got a NaN origin on %s\n", pr_strings + ent->v.classname);
108 ent->v.origin[i] = 0;
111 if (ent->v.velocity[i] > sv_maxvelocity.value)
112 ent->v.velocity[i] = sv_maxvelocity.value;
113 else if (ent->v.velocity[i] < -sv_maxvelocity.value)
114 ent->v.velocity[i] = -sv_maxvelocity.value;
118 wishspeed = Length(ent->v.velocity);
119 if (wishspeed > sv_maxvelocity.value)
121 VectorScale (ent->v.velocity, sv_maxvelocity.value/wishspeed, ent->v.velocity);
122 wishspeed = sv_maxvelocity.value;
127 =============
128 SV_RunThink
130 Runs thinking code if time. There is some play in the exact time the think
131 function will be called, because it is called before any movement is done
132 in a frame. Not used for pushmove objects, because they must be exact.
133 Returns false if the entity removed itself.
134 =============
136 qboolean SV_RunThink (edict_t *ent)
138 float thinktime;
140 thinktime = ent->v.nextthink;
141 if (thinktime <= 0 || thinktime > sv.time + host_frametime)
142 return true;
144 if (thinktime < sv.time)
145 thinktime = sv.time; // don't let things stay in the past.
146 // it is possible to start that way
147 // by a trigger with a local time.
148 ent->v.nextthink = 0;
149 pr_global_struct->time = thinktime;
150 pr_global_struct->self = EDICT_TO_PROG(ent);
151 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
152 PR_ExecuteProgram (ent->v.think);
153 return !ent->free;
157 ==================
158 SV_Impact
160 Two entities have touched, so run their touch functions
161 ==================
163 void SV_Impact (edict_t *e1, edict_t *e2)
165 int old_self, old_other;
167 old_self = pr_global_struct->self;
168 old_other = pr_global_struct->other;
170 pr_global_struct->time = sv.time;
171 if (e1->v.touch && e1->v.solid != SOLID_NOT)
173 pr_global_struct->self = EDICT_TO_PROG(e1);
174 pr_global_struct->other = EDICT_TO_PROG(e2);
175 PR_ExecuteProgram (e1->v.touch);
178 if (e2->v.touch && e2->v.solid != SOLID_NOT)
180 pr_global_struct->self = EDICT_TO_PROG(e2);
181 pr_global_struct->other = EDICT_TO_PROG(e1);
182 PR_ExecuteProgram (e2->v.touch);
185 pr_global_struct->self = old_self;
186 pr_global_struct->other = old_other;
191 ==================
192 ClipVelocity
194 Slide off of the impacting object
195 returns the blocked flags (1 = floor, 2 = step / wall)
196 ==================
198 #define STOP_EPSILON 0.1
200 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
202 float backoff;
203 float change;
204 int i, blocked;
206 blocked = 0;
207 if (normal[2] > 0)
208 blocked |= 1; // floor
209 if (!normal[2])
210 blocked |= 2; // step
212 backoff = DotProduct (in, normal) * overbounce;
214 for (i=0 ; i<3 ; i++)
216 change = normal[i]*backoff;
217 out[i] = in[i] - change;
218 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
219 out[i] = 0;
222 return blocked;
227 ============
228 SV_FlyMove
230 The basic solid body movement clip that slides along multiple planes
231 Returns the clipflags if the velocity was modified (hit something solid)
232 1 = floor
233 2 = wall / step
234 4 = dead stop
235 If steptrace is not NULL, the trace of any vertical wall hit will be stored
236 ============
238 #define MAX_CLIP_PLANES 5
239 int SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
241 int bumpcount, numbumps;
242 vec3_t dir;
243 float d;
244 int numplanes;
245 vec3_t planes[MAX_CLIP_PLANES];
246 vec3_t primal_velocity, original_velocity, new_velocity;
247 int i, j;
248 trace_t trace;
249 vec3_t end;
250 float time_left;
251 int blocked;
253 numbumps = 4;
255 blocked = 0;
256 VectorCopy (ent->v.velocity, original_velocity);
257 VectorCopy (ent->v.velocity, primal_velocity);
258 numplanes = 0;
260 time_left = time;
262 for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
264 if (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])
265 break;
267 for (i=0 ; i<3 ; i++)
268 end[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];
270 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);
272 if (trace.allsolid)
273 { // entity is trapped in another solid
274 VectorCopy (vec3_origin, ent->v.velocity);
275 return 3;
278 if (trace.fraction > 0)
279 { // actually covered some distance
280 VectorCopy (trace.endpos, ent->v.origin);
281 VectorCopy (ent->v.velocity, original_velocity);
282 numplanes = 0;
285 if (trace.fraction == 1)
286 break; // moved the entire distance
288 if (!trace.ent)
289 Sys_Error ("SV_FlyMove: !trace.ent");
291 if (trace.plane.normal[2] > 0.7)
293 blocked |= 1; // floor
294 if (trace.ent->v.solid == SOLID_BSP)
296 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
297 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
300 if (!trace.plane.normal[2])
302 blocked |= 2; // step
303 if (steptrace)
304 *steptrace = trace; // save for player extrafriction
308 // run the impact function
310 SV_Impact (ent, trace.ent);
311 if (ent->free)
312 break; // removed by the impact function
315 time_left -= time_left * trace.fraction;
317 // cliped to another plane
318 if (numplanes >= MAX_CLIP_PLANES)
319 { // this shouldn't really happen
320 VectorCopy (vec3_origin, ent->v.velocity);
321 return 3;
324 VectorCopy (trace.plane.normal, planes[numplanes]);
325 numplanes++;
328 // modify original_velocity so it parallels all of the clip planes
330 for (i=0 ; i<numplanes ; i++)
332 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
333 for (j=0 ; j<numplanes ; j++)
334 if (j != i)
336 if (DotProduct (new_velocity, planes[j]) < 0)
337 break; // not ok
339 if (j == numplanes)
340 break;
343 if (i != numplanes)
344 { // go along this plane
345 VectorCopy (new_velocity, ent->v.velocity);
347 else
348 { // go along the crease
349 if (numplanes != 2)
351 // Con_Printf ("clip velocity, numplanes == %i\n",numplanes);
352 VectorCopy (vec3_origin, ent->v.velocity);
353 return 7;
355 CrossProduct (planes[0], planes[1], dir);
356 d = DotProduct (dir, ent->v.velocity);
357 VectorScale (dir, d, ent->v.velocity);
361 // if original velocity is against the original velocity, stop dead
362 // to avoid tiny occilations in sloping corners
364 if (DotProduct (ent->v.velocity, primal_velocity) <= 0)
366 VectorCopy (vec3_origin, ent->v.velocity);
367 return blocked;
371 return blocked;
376 ============
377 SV_AddGravity
379 ============
381 void SV_AddGravity (edict_t *ent)
383 float ent_gravity;
385 #ifdef QUAKE2
386 if (ent->v.gravity)
387 ent_gravity = ent->v.gravity;
388 else
389 ent_gravity = 1.0;
390 #else
391 eval_t *val;
393 val = GetEdictFieldValue(ent, "gravity");
394 if (val && val->_float)
395 ent_gravity = val->_float;
396 else
397 ent_gravity = 1.0;
398 #endif
399 ent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;
404 ===============================================================================
406 PUSHMOVE
408 ===============================================================================
412 ============
413 SV_PushEntity
415 Does not change the entities velocity at all
416 ============
418 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
420 trace_t trace;
421 vec3_t end;
423 VectorAdd (ent->v.origin, push, end);
425 if (ent->v.movetype == MOVETYPE_FLYMISSILE)
426 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);
427 else if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)
428 // only clip against bmodels
429 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);
430 else
431 trace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);
433 VectorCopy (trace.endpos, ent->v.origin);
434 SV_LinkEdict (ent, true);
436 if (trace.ent)
437 SV_Impact (ent, trace.ent);
439 return trace;
444 ============
445 SV_PushMove
447 ============
449 void SV_PushMove (edict_t *pusher, float movetime)
451 int i, e;
452 edict_t *check, *block;
453 vec3_t mins, maxs, move;
454 vec3_t entorig, pushorig;
455 int num_moved;
456 edict_t *moved_edict[MAX_EDICTS];
457 vec3_t moved_from[MAX_EDICTS];
459 if (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])
461 pusher->v.ltime += movetime;
462 return;
465 for (i=0 ; i<3 ; i++)
467 move[i] = pusher->v.velocity[i] * movetime;
468 mins[i] = pusher->v.absmin[i] + move[i];
469 maxs[i] = pusher->v.absmax[i] + move[i];
472 VectorCopy (pusher->v.origin, pushorig);
474 // move the pusher to it's final position
476 VectorAdd (pusher->v.origin, move, pusher->v.origin);
477 pusher->v.ltime += movetime;
478 SV_LinkEdict (pusher, false);
481 // see if any solid entities are inside the final position
482 num_moved = 0;
483 check = NEXT_EDICT(sv.edicts);
484 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
486 if (check->free)
487 continue;
488 if (check->v.movetype == MOVETYPE_PUSH
489 || check->v.movetype == MOVETYPE_NONE
490 #ifdef QUAKE2
491 || check->v.movetype == MOVETYPE_FOLLOW
492 #endif
493 || check->v.movetype == MOVETYPE_NOCLIP)
494 continue;
496 // if the entity is standing on the pusher, it will definately be moved
497 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
498 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
500 if ( check->v.absmin[0] >= maxs[0]
501 || check->v.absmin[1] >= maxs[1]
502 || check->v.absmin[2] >= maxs[2]
503 || check->v.absmax[0] <= mins[0]
504 || check->v.absmax[1] <= mins[1]
505 || check->v.absmax[2] <= mins[2] )
506 continue;
508 // see if the ent's bbox is inside the pusher's final position
509 if (!SV_TestEntityPosition (check))
510 continue;
513 // remove the onground flag for non-players
514 if (check->v.movetype != MOVETYPE_WALK)
515 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
517 VectorCopy (check->v.origin, entorig);
518 VectorCopy (check->v.origin, moved_from[num_moved]);
519 moved_edict[num_moved] = check;
520 num_moved++;
522 // try moving the contacted entity
523 pusher->v.solid = SOLID_NOT;
524 SV_PushEntity (check, move);
525 pusher->v.solid = SOLID_BSP;
527 // if it is still inside the pusher, block
528 block = SV_TestEntityPosition (check);
529 if (block)
530 { // fail the move
531 if (check->v.mins[0] == check->v.maxs[0])
532 continue;
533 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
534 { // corpse
535 check->v.mins[0] = check->v.mins[1] = 0;
536 VectorCopy (check->v.mins, check->v.maxs);
537 continue;
540 VectorCopy (entorig, check->v.origin);
541 SV_LinkEdict (check, true);
543 VectorCopy (pushorig, pusher->v.origin);
544 SV_LinkEdict (pusher, false);
545 pusher->v.ltime -= movetime;
547 // if the pusher has a "blocked" function, call it
548 // otherwise, just stay in place until the obstacle is gone
549 if (pusher->v.blocked)
551 pr_global_struct->self = EDICT_TO_PROG(pusher);
552 pr_global_struct->other = EDICT_TO_PROG(check);
553 PR_ExecuteProgram (pusher->v.blocked);
556 // move back any entities we already moved
557 for (i=0 ; i<num_moved ; i++)
559 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
560 SV_LinkEdict (moved_edict[i], false);
562 return;
569 #ifdef QUAKE2
571 ============
572 SV_PushRotate
574 ============
576 void SV_PushRotate (edict_t *pusher, float movetime)
578 int i, e;
579 edict_t *check, *block;
580 vec3_t move, a, amove;
581 vec3_t entorig, pushorig;
582 int num_moved;
583 edict_t *moved_edict[MAX_EDICTS];
584 vec3_t moved_from[MAX_EDICTS];
585 vec3_t org, org2;
586 vec3_t forward, right, up;
588 if (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])
590 pusher->v.ltime += movetime;
591 return;
594 for (i=0 ; i<3 ; i++)
595 amove[i] = pusher->v.avelocity[i] * movetime;
597 VectorSubtract (vec3_origin, amove, a);
598 AngleVectors (a, forward, right, up);
600 VectorCopy (pusher->v.angles, pushorig);
602 // move the pusher to it's final position
604 VectorAdd (pusher->v.angles, amove, pusher->v.angles);
605 pusher->v.ltime += movetime;
606 SV_LinkEdict (pusher, false);
609 // see if any solid entities are inside the final position
610 num_moved = 0;
611 check = NEXT_EDICT(sv.edicts);
612 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
614 if (check->free)
615 continue;
616 if (check->v.movetype == MOVETYPE_PUSH
617 || check->v.movetype == MOVETYPE_NONE
618 || check->v.movetype == MOVETYPE_FOLLOW
619 || check->v.movetype == MOVETYPE_NOCLIP)
620 continue;
622 // if the entity is standing on the pusher, it will definately be moved
623 if ( ! ( ((int)check->v.flags & FL_ONGROUND)
624 && PROG_TO_EDICT(check->v.groundentity) == pusher) )
626 if ( check->v.absmin[0] >= pusher->v.absmax[0]
627 || check->v.absmin[1] >= pusher->v.absmax[1]
628 || check->v.absmin[2] >= pusher->v.absmax[2]
629 || check->v.absmax[0] <= pusher->v.absmin[0]
630 || check->v.absmax[1] <= pusher->v.absmin[1]
631 || check->v.absmax[2] <= pusher->v.absmin[2] )
632 continue;
634 // see if the ent's bbox is inside the pusher's final position
635 if (!SV_TestEntityPosition (check))
636 continue;
639 // remove the onground flag for non-players
640 if (check->v.movetype != MOVETYPE_WALK)
641 check->v.flags = (int)check->v.flags & ~FL_ONGROUND;
643 VectorCopy (check->v.origin, entorig);
644 VectorCopy (check->v.origin, moved_from[num_moved]);
645 moved_edict[num_moved] = check;
646 num_moved++;
648 // calculate destination position
649 VectorSubtract (check->v.origin, pusher->v.origin, org);
650 org2[0] = DotProduct (org, forward);
651 org2[1] = -DotProduct (org, right);
652 org2[2] = DotProduct (org, up);
653 VectorSubtract (org2, org, move);
655 // try moving the contacted entity
656 pusher->v.solid = SOLID_NOT;
657 SV_PushEntity (check, move);
658 pusher->v.solid = SOLID_BSP;
660 // if it is still inside the pusher, block
661 block = SV_TestEntityPosition (check);
662 if (block)
663 { // fail the move
664 if (check->v.mins[0] == check->v.maxs[0])
665 continue;
666 if (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)
667 { // corpse
668 check->v.mins[0] = check->v.mins[1] = 0;
669 VectorCopy (check->v.mins, check->v.maxs);
670 continue;
673 VectorCopy (entorig, check->v.origin);
674 SV_LinkEdict (check, true);
676 VectorCopy (pushorig, pusher->v.angles);
677 SV_LinkEdict (pusher, false);
678 pusher->v.ltime -= movetime;
680 // if the pusher has a "blocked" function, call it
681 // otherwise, just stay in place until the obstacle is gone
682 if (pusher->v.blocked)
684 pr_global_struct->self = EDICT_TO_PROG(pusher);
685 pr_global_struct->other = EDICT_TO_PROG(check);
686 PR_ExecuteProgram (pusher->v.blocked);
689 // move back any entities we already moved
690 for (i=0 ; i<num_moved ; i++)
692 VectorCopy (moved_from[i], moved_edict[i]->v.origin);
693 VectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);
694 SV_LinkEdict (moved_edict[i], false);
696 return;
698 else
700 VectorAdd (check->v.angles, amove, check->v.angles);
706 #endif
709 ================
710 SV_Physics_Pusher
712 ================
714 void SV_Physics_Pusher (edict_t *ent)
716 float thinktime;
717 float oldltime;
718 float movetime;
720 oldltime = ent->v.ltime;
722 thinktime = ent->v.nextthink;
723 if (thinktime < ent->v.ltime + host_frametime)
725 movetime = thinktime - ent->v.ltime;
726 if (movetime < 0)
727 movetime = 0;
729 else
730 movetime = host_frametime;
732 if (movetime)
734 #ifdef QUAKE2
735 if (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])
736 SV_PushRotate (ent, movetime);
737 else
738 #endif
739 SV_PushMove (ent, movetime); // advances ent->v.ltime if not blocked
742 if (thinktime > oldltime && thinktime <= ent->v.ltime)
744 ent->v.nextthink = 0;
745 pr_global_struct->time = sv.time;
746 pr_global_struct->self = EDICT_TO_PROG(ent);
747 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
748 PR_ExecuteProgram (ent->v.think);
749 if (ent->free)
750 return;
757 ===============================================================================
759 CLIENT MOVEMENT
761 ===============================================================================
765 =============
766 SV_CheckStuck
768 This is a big hack to try and fix the rare case of getting stuck in the world
769 clipping hull.
770 =============
772 void SV_CheckStuck (edict_t *ent)
774 int i, j;
775 int z;
776 vec3_t org;
778 if (!SV_TestEntityPosition(ent))
780 VectorCopy (ent->v.origin, ent->v.oldorigin);
781 return;
784 VectorCopy (ent->v.origin, org);
785 VectorCopy (ent->v.oldorigin, ent->v.origin);
786 if (!SV_TestEntityPosition(ent))
788 Con_DPrintf ("Unstuck.\n");
789 SV_LinkEdict (ent, true);
790 return;
793 for (z=0 ; z< 18 ; z++)
794 for (i=-1 ; i <= 1 ; i++)
795 for (j=-1 ; j <= 1 ; j++)
797 ent->v.origin[0] = org[0] + i;
798 ent->v.origin[1] = org[1] + j;
799 ent->v.origin[2] = org[2] + z;
800 if (!SV_TestEntityPosition(ent))
802 Con_DPrintf ("Unstuck.\n");
803 SV_LinkEdict (ent, true);
804 return;
808 VectorCopy (org, ent->v.origin);
809 Con_DPrintf ("player is stuck.\n");
814 =============
815 SV_CheckWater
816 =============
818 qboolean SV_CheckWater (edict_t *ent)
820 vec3_t point;
821 int cont;
822 #ifdef QUAKE2
823 int truecont;
824 #endif
826 point[0] = ent->v.origin[0];
827 point[1] = ent->v.origin[1];
828 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
830 ent->v.waterlevel = 0;
831 ent->v.watertype = CONTENTS_EMPTY;
832 cont = SV_PointContents (point);
833 if (cont <= CONTENTS_WATER)
835 #ifdef QUAKE2
836 truecont = SV_TruePointContents (point);
837 #endif
838 ent->v.watertype = cont;
839 ent->v.waterlevel = 1;
840 point[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;
841 cont = SV_PointContents (point);
842 if (cont <= CONTENTS_WATER)
844 ent->v.waterlevel = 2;
845 point[2] = ent->v.origin[2] + ent->v.view_ofs[2];
846 cont = SV_PointContents (point);
847 if (cont <= CONTENTS_WATER)
848 ent->v.waterlevel = 3;
850 #ifdef QUAKE2
851 if (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)
853 static vec3_t current_table[] =
855 {1, 0, 0},
856 {0, 1, 0},
857 {-1, 0, 0},
858 {0, -1, 0},
859 {0, 0, 1},
860 {0, 0, -1}
863 VectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);
865 #endif
868 return ent->v.waterlevel > 1;
872 ============
873 SV_WallFriction
875 ============
877 void SV_WallFriction (edict_t *ent, trace_t *trace)
879 vec3_t forward, right, up;
880 float d, i;
881 vec3_t into, side;
883 AngleVectors (ent->v.v_angle, forward, right, up);
884 d = DotProduct (trace->plane.normal, forward);
886 d += 0.5;
887 if (d >= 0)
888 return;
890 // cut the tangential velocity
891 i = DotProduct (trace->plane.normal, ent->v.velocity);
892 VectorScale (trace->plane.normal, i, into);
893 VectorSubtract (ent->v.velocity, into, side);
895 ent->v.velocity[0] = side[0] * (1 + d);
896 ent->v.velocity[1] = side[1] * (1 + d);
900 =====================
901 SV_TryUnstick
903 Player has come to a dead stop, possibly due to the problem with limited
904 float precision at some angle joins in the BSP hull.
906 Try fixing by pushing one pixel in each direction.
908 This is a hack, but in the interest of good gameplay...
909 ======================
911 int SV_TryUnstick (edict_t *ent, vec3_t oldvel)
913 int i;
914 vec3_t oldorg;
915 vec3_t dir;
916 int clip;
917 trace_t steptrace;
919 VectorCopy (ent->v.origin, oldorg);
920 VectorCopy (vec3_origin, dir);
922 for (i=0 ; i<8 ; i++)
924 // try pushing a little in an axial direction
925 switch (i)
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);
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, &steptrace);
945 if ( fabsf(oldorg[1] - ent->v.origin[1]) > 4
946 || fabsf(oldorg[0] - ent->v.origin[0]) > 4 )
948 //Con_DPrintf ("unstuck!\n");
949 return clip;
952 // go back to the original pos and try again
953 VectorCopy (oldorg, ent->v.origin);
956 VectorCopy (vec3_origin, ent->v.velocity);
957 return 7; // still not moving
961 =====================
962 SV_WalkMove
964 Only used by players
965 ======================
967 #define STEPSIZE 18
968 void SV_WalkMove (edict_t *ent)
970 vec3_t upmove, downmove;
971 vec3_t oldorg, oldvel;
972 vec3_t nosteporg, nostepvel;
973 int clip;
974 int oldonground;
975 trace_t steptrace, downtrace;
978 // do a regular slide move unless it looks like you ran into a step
980 oldonground = (int)ent->v.flags & FL_ONGROUND;
981 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
983 VectorCopy (ent->v.origin, oldorg);
984 VectorCopy (ent->v.velocity, oldvel);
986 clip = SV_FlyMove (ent, host_frametime, &steptrace);
988 if ( !(clip & 2) )
989 return; // move didn't block on a step
991 if (!oldonground && ent->v.waterlevel == 0)
992 return; // don't stair up while jumping
994 if (ent->v.movetype != MOVETYPE_WALK)
995 return; // gibbed by a trigger
997 if (sv_nostep.value)
998 return;
1000 if ( (int)sv_player->v.flags & FL_WATERJUMP )
1001 return;
1003 VectorCopy (ent->v.origin, nosteporg);
1004 VectorCopy (ent->v.velocity, nostepvel);
1007 // try moving up and forward to go up a step
1009 VectorCopy (oldorg, ent->v.origin); // back to start pos
1011 VectorCopy (vec3_origin, upmove);
1012 VectorCopy (vec3_origin, downmove);
1013 upmove[2] = STEPSIZE;
1014 downmove[2] = -STEPSIZE + oldvel[2]*host_frametime;
1016 // move up
1017 SV_PushEntity (ent, upmove); // FIXME: don't link?
1019 // move forward
1020 ent->v.velocity[0] = oldvel[0];
1021 ent->v. velocity[1] = oldvel[1];
1022 ent->v. velocity[2] = 0;
1023 clip = SV_FlyMove (ent, host_frametime, &steptrace);
1025 // check for stuckness, possibly due to the limited precision of floats
1026 // in the clipping hulls
1027 if (clip)
1029 if ( fabsf(oldorg[1] - ent->v.origin[1]) < 0.03125
1030 && fabsf(oldorg[0] - ent->v.origin[0]) < 0.03125 )
1031 { // stepping up didn't make any progress
1032 clip = SV_TryUnstick (ent, oldvel);
1036 // extra friction based on view angle
1037 if ( clip & 2 )
1038 SV_WallFriction (ent, &steptrace);
1040 // move down
1041 downtrace = SV_PushEntity (ent, downmove); // FIXME: don't link?
1043 if (downtrace.plane.normal[2] > 0.7)
1045 if (ent->v.solid == SOLID_BSP)
1047 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1048 ent->v.groundentity = EDICT_TO_PROG(downtrace.ent);
1051 else
1053 // if the push down didn't end up on good ground, use the move without
1054 // the step up. This happens near wall / slope combinations, and can
1055 // cause the player to hop up higher on a slope too steep to climb
1056 VectorCopy (nosteporg, ent->v.origin);
1057 VectorCopy (nostepvel, ent->v.velocity);
1063 ================
1064 SV_Physics_Client
1066 Player character actions
1067 ================
1069 void SV_Physics_Client (edict_t *ent, int num)
1071 if ( ! svs.clients[num-1].active )
1072 return; // unconnected slot
1075 // call standard client pre-think
1077 pr_global_struct->time = sv.time;
1078 pr_global_struct->self = EDICT_TO_PROG(ent);
1079 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1082 // do a move
1084 SV_CheckVelocity (ent);
1087 // decide which move function to call
1089 switch ((int)ent->v.movetype)
1091 case MOVETYPE_NONE:
1092 if (!SV_RunThink (ent))
1093 return;
1094 break;
1096 case MOVETYPE_WALK:
1097 if (!SV_RunThink (ent))
1098 return;
1099 if (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )
1100 SV_AddGravity (ent);
1101 SV_CheckStuck (ent);
1102 #ifdef QUAKE2
1103 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1104 #endif
1105 SV_WalkMove (ent);
1107 #ifdef QUAKE2
1108 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1109 #endif
1110 break;
1112 case MOVETYPE_TOSS:
1113 case MOVETYPE_BOUNCE:
1114 SV_Physics_Toss (ent);
1115 break;
1117 case MOVETYPE_FLY:
1118 if (!SV_RunThink (ent))
1119 return;
1120 SV_FlyMove (ent, host_frametime, NULL);
1121 break;
1123 case MOVETYPE_NOCLIP:
1124 if (!SV_RunThink (ent))
1125 return;
1126 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1127 break;
1129 default:
1130 Sys_Error ("SV_Physics_client: bad movetype %i", (int)ent->v.movetype);
1134 // call standard player post-think
1136 SV_LinkEdict (ent, true);
1138 pr_global_struct->time = sv.time;
1139 pr_global_struct->self = EDICT_TO_PROG(ent);
1140 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1143 //============================================================================
1146 =============
1147 SV_Physics_None
1149 Non moving objects can only think
1150 =============
1152 void SV_Physics_None (edict_t *ent)
1154 // regular thinking
1155 SV_RunThink (ent);
1158 #ifdef QUAKE2
1160 =============
1161 SV_Physics_Follow
1163 Entities that are "stuck" to another entity
1164 =============
1166 void SV_Physics_Follow (edict_t *ent)
1168 // regular thinking
1169 SV_RunThink (ent);
1170 VectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);
1171 SV_LinkEdict (ent, true);
1173 #endif
1176 =============
1177 SV_Physics_Noclip
1179 A moving object that doesn't obey physics
1180 =============
1182 void SV_Physics_Noclip (edict_t *ent)
1184 // regular thinking
1185 if (!SV_RunThink (ent))
1186 return;
1188 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1189 VectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);
1191 SV_LinkEdict (ent, false);
1195 ==============================================================================
1197 TOSS / BOUNCE
1199 ==============================================================================
1203 =============
1204 SV_CheckWaterTransition
1206 =============
1208 void SV_CheckWaterTransition (edict_t *ent)
1210 int cont;
1211 #ifdef QUAKE2
1212 vec3_t point;
1214 point[0] = ent->v.origin[0];
1215 point[1] = ent->v.origin[1];
1216 point[2] = ent->v.origin[2] + ent->v.mins[2] + 1;
1217 cont = SV_PointContents (point);
1218 #else
1219 cont = SV_PointContents (ent->v.origin);
1220 #endif
1221 if (!ent->v.watertype)
1222 { // just spawned here
1223 ent->v.watertype = cont;
1224 ent->v.waterlevel = 1;
1225 return;
1228 if (cont <= CONTENTS_WATER)
1230 if (ent->v.watertype == CONTENTS_EMPTY)
1231 { // just crossed into water
1232 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1234 ent->v.watertype = cont;
1235 ent->v.waterlevel = 1;
1237 else
1239 if (ent->v.watertype != CONTENTS_EMPTY)
1240 { // just crossed into water
1241 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
1243 ent->v.watertype = CONTENTS_EMPTY;
1244 ent->v.waterlevel = cont;
1249 =============
1250 SV_Physics_Toss
1252 Toss, bounce, and fly movement. When onground, do nothing.
1253 =============
1255 void SV_Physics_Toss (edict_t *ent)
1257 trace_t trace;
1258 vec3_t move;
1259 float backoff;
1260 #ifdef QUAKE2
1261 edict_t *groundentity;
1263 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1264 if ((int)groundentity->v.flags & FL_CONVEYOR)
1265 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1266 else
1267 VectorCopy(vec_origin, ent->v.basevelocity);
1268 SV_CheckWater (ent);
1269 #endif
1270 // regular thinking
1271 if (!SV_RunThink (ent))
1272 return;
1274 #ifdef QUAKE2
1275 if (ent->v.velocity[2] > 0)
1276 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1278 if ( ((int)ent->v.flags & FL_ONGROUND) )
1279 //@@
1280 if (VectorCompare(ent->v.basevelocity, vec_origin))
1281 return;
1283 SV_CheckVelocity (ent);
1285 // add gravity
1286 if (! ((int)ent->v.flags & FL_ONGROUND)
1287 && ent->v.movetype != MOVETYPE_FLY
1288 && ent->v.movetype != MOVETYPE_BOUNCEMISSILE
1289 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1290 SV_AddGravity (ent);
1292 #else
1293 // if onground, return without moving
1294 if ( ((int)ent->v.flags & FL_ONGROUND) )
1295 return;
1297 SV_CheckVelocity (ent);
1299 // add gravity
1300 if (ent->v.movetype != MOVETYPE_FLY
1301 && ent->v.movetype != MOVETYPE_FLYMISSILE)
1302 SV_AddGravity (ent);
1303 #endif
1305 // move angles
1306 VectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);
1308 // move origin
1309 #ifdef QUAKE2
1310 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1311 #endif
1312 VectorScale (ent->v.velocity, host_frametime, move);
1313 trace = SV_PushEntity (ent, move);
1314 #ifdef QUAKE2
1315 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1316 #endif
1317 if (trace.fraction == 1)
1318 return;
1319 if (ent->free)
1320 return;
1322 if (ent->v.movetype == MOVETYPE_BOUNCE)
1323 backoff = 1.5;
1324 #ifdef QUAKE2
1325 else if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)
1326 backoff = 2.0;
1327 #endif
1328 else
1329 backoff = 1;
1331 ClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);
1333 // stop if on ground
1334 if (trace.plane.normal[2] > 0.7)
1336 #ifdef QUAKE2
1337 if (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))
1338 #else
1339 if (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)
1340 #endif
1342 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1343 ent->v.groundentity = EDICT_TO_PROG(trace.ent);
1344 VectorCopy (vec3_origin, ent->v.velocity);
1345 VectorCopy (vec3_origin, ent->v.avelocity);
1349 // check for in water
1350 SV_CheckWaterTransition (ent);
1354 ===============================================================================
1356 STEPPING MOVEMENT
1358 ===============================================================================
1362 =============
1363 SV_Physics_Step
1365 Monsters freefall when they don't have a ground entity, otherwise
1366 all movement is done with discrete steps.
1368 This is also used for objects that have become still on the ground, but
1369 will fall if the floor is pulled out from under them.
1370 =============
1372 #ifdef QUAKE2
1373 void SV_Physics_Step (edict_t *ent)
1375 qboolean wasonground;
1376 qboolean inwater;
1377 qboolean hitsound = false;
1378 float *vel;
1379 float speed, newspeed, control;
1380 float friction;
1381 edict_t *groundentity;
1383 groundentity = PROG_TO_EDICT(ent->v.groundentity);
1384 if ((int)groundentity->v.flags & FL_CONVEYOR)
1385 VectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);
1386 else
1387 VectorCopy(vec_origin, ent->v.basevelocity);
1388 //@@
1389 pr_global_struct->time = sv.time;
1390 pr_global_struct->self = EDICT_TO_PROG(ent);
1391 PF_WaterMove();
1393 SV_CheckVelocity (ent);
1395 wasonground = (int)ent->v.flags & FL_ONGROUND;
1396 // ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1398 // add gravity except:
1399 // flying monsters
1400 // swimming monsters who are in the water
1401 inwater = SV_CheckWater(ent);
1402 if (! wasonground)
1403 if (!((int)ent->v.flags & FL_FLY))
1404 if (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))
1406 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1407 hitsound = true;
1408 if (!inwater)
1409 SV_AddGravity (ent);
1412 if (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))
1414 ent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;
1415 // apply friction
1416 // let dead monsters who aren't completely onground slide
1417 if (wasonground)
1418 if (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))
1420 vel = ent->v.velocity;
1421 speed = sqrtf(vel[0]*vel[0] +vel[1]*vel[1]);
1422 if (speed)
1424 friction = sv_friction.value;
1426 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;
1427 newspeed = speed - host_frametime*control*friction;
1429 if (newspeed < 0)
1430 newspeed = 0;
1431 newspeed /= speed;
1433 vel[0] = vel[0] * newspeed;
1434 vel[1] = vel[1] * newspeed;
1438 VectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1439 SV_FlyMove (ent, host_frametime, NULL);
1440 VectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);
1442 // determine if it's on solid ground at all
1444 vec3_t mins, maxs, point;
1445 int x, y;
1447 VectorAdd (ent->v.origin, ent->v.mins, mins);
1448 VectorAdd (ent->v.origin, ent->v.maxs, maxs);
1450 point[2] = mins[2] - 1;
1451 for (x=0 ; x<=1 ; x++)
1452 for (y=0 ; y<=1 ; y++)
1454 point[0] = x ? maxs[0] : mins[0];
1455 point[1] = y ? maxs[1] : mins[1];
1456 if (SV_PointContents (point) == CONTENTS_SOLID)
1458 ent->v.flags = (int)ent->v.flags | FL_ONGROUND;
1459 break;
1465 SV_LinkEdict (ent, true);
1467 if ((int)ent->v.flags & FL_ONGROUND)
1468 if (!wasonground)
1469 if (hitsound)
1470 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1473 // regular thinking
1474 SV_RunThink (ent);
1475 SV_CheckWaterTransition (ent);
1477 #else
1478 void SV_Physics_Step (edict_t *ent)
1480 qboolean hitsound;
1482 // freefall if not onground
1483 if ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )
1485 if (ent->v.velocity[2] < sv_gravity.value*-0.1)
1486 hitsound = true;
1487 else
1488 hitsound = false;
1490 SV_AddGravity (ent);
1491 SV_CheckVelocity (ent);
1492 SV_FlyMove (ent, host_frametime, NULL);
1493 SV_LinkEdict (ent, true);
1495 if ( (int)ent->v.flags & FL_ONGROUND ) // just hit ground
1497 if (hitsound)
1498 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
1502 // regular thinking
1503 SV_RunThink (ent);
1505 SV_CheckWaterTransition (ent);
1507 #endif
1509 //============================================================================
1512 ================
1513 SV_Physics
1515 ================
1517 void SV_Physics (void)
1519 int i;
1520 edict_t *ent;
1522 // let the progs know that a new frame has started
1523 pr_global_struct->self = EDICT_TO_PROG(sv.edicts);
1524 pr_global_struct->other = EDICT_TO_PROG(sv.edicts);
1525 pr_global_struct->time = sv.time;
1526 PR_ExecuteProgram (pr_global_struct->StartFrame);
1528 //SV_CheckAllEnts ();
1531 // treat each object in turn
1533 ent = sv.edicts;
1534 for (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))
1536 if (ent->free)
1537 continue;
1539 if (pr_global_struct->force_retouch)
1541 SV_LinkEdict (ent, true); // force retouch even for stationary
1544 if (i > 0 && i <= svs.maxclients)
1545 SV_Physics_Client (ent, i);
1546 else if (ent->v.movetype == MOVETYPE_PUSH)
1547 SV_Physics_Pusher (ent);
1548 else if (ent->v.movetype == MOVETYPE_NONE)
1549 SV_Physics_None (ent);
1550 #ifdef QUAKE2
1551 else if (ent->v.movetype == MOVETYPE_FOLLOW)
1552 SV_Physics_Follow (ent);
1553 #endif
1554 else if (ent->v.movetype == MOVETYPE_NOCLIP)
1555 SV_Physics_Noclip (ent);
1556 else if (ent->v.movetype == MOVETYPE_STEP)
1557 SV_Physics_Step (ent);
1558 else if (ent->v.movetype == MOVETYPE_TOSS
1559 || ent->v.movetype == MOVETYPE_BOUNCE
1560 #ifdef QUAKE2
1561 || ent->v.movetype == MOVETYPE_BOUNCEMISSILE
1562 #endif
1563 || ent->v.movetype == MOVETYPE_FLY
1564 || ent->v.movetype == MOVETYPE_FLYMISSILE)
1565 SV_Physics_Toss (ent);
1566 else
1567 Sys_Error ("SV_Physics: bad movetype %i", (int)ent->v.movetype);
1570 if (pr_global_struct->force_retouch)
1571 pr_global_struct->force_retouch--;
1573 sv.time += host_frametime;
1577 #ifdef QUAKE2
1578 trace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)
1580 edict_t tempent, *tent;
1581 trace_t trace;
1582 vec3_t move;
1583 vec3_t end;
1584 double save_frametime;
1585 // extern particle_t *active_particles, *free_particles;
1586 // particle_t *p;
1589 save_frametime = host_frametime;
1590 host_frametime = 0.05;
1592 memcpy(&tempent, ent, sizeof(edict_t));
1593 tent = &tempent;
1595 while (1)
1597 SV_CheckVelocity (tent);
1598 SV_AddGravity (tent);
1599 VectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);
1600 VectorScale (tent->v.velocity, host_frametime, move);
1601 VectorAdd (tent->v.origin, move, end);
1602 trace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);
1603 VectorCopy (trace.endpos, tent->v.origin);
1605 // p = free_particles;
1606 // if (p)
1607 // {
1608 // free_particles = p->next;
1609 // p->next = active_particles;
1610 // active_particles = p;
1612 // p->die = 256;
1613 // p->color = 15;
1614 // p->type = pt_static;
1615 // VectorCopy (vec3_origin, p->vel);
1616 // VectorCopy (tent->v.origin, p->org);
1617 // }
1619 if (trace.ent)
1620 if (trace.ent != ignore)
1621 break;
1623 // p->color = 224;
1624 host_frametime = save_frametime;
1625 return trace;
1627 #endif