1 /*
2 sv_phys.c
3
4 @description@
5
6 Copyright (C) 1996-1997 Id Software, Inc.
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
17 See the GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to:
21
22 Free Software Foundation, Inc.
23 59 Temple Place - Suite 330
24 Boston, MA 02111-1307, USA
25
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include "QF/cvar.h"
32 #include "QF/sys.h"
33
34 #include "server.h"
35 #include "sv_progs.h"
36 #include "world.h"
37
38 /*
39 pushmove objects do not obey gravity, and do not interact with each
40 other or trigger fields, but block normal movement and push normal
41 objects when they move.
42
43 onground is set for toss objects when they come to a complete rest. it
44 is set for steping or walking objects
45
46 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
47 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
48 corpses are SOLID_NOT and MOVETYPE_TOSS
49 crates are SOLID_BBOX and MOVETYPE_TOSS
50 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
51 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
52
53 solid_edge items clip against only bsp models.
54 */
55
56 cvar_t *sv_friction;
57 cvar_t *sv_gravity;
58 cvar_t *sv_jump_any;
59 cvar_t *sv_maxvelocity;
60 cvar_t *sv_stopspeed;
61
62 #define MOVE_EPSILON 0.01
63 #if 0
64 static void
65 SV_CheckAllEnts (void)
66 {
67 edict_t *check;
68 int e;
69
70 // see if any solid entities are inside the final position
71 check = NEXT_EDICT (&sv_pr_state, sv.edicts);
72 for (e = 1; e < sv.num_edicts;
73 e++, check = NEXT_EDICT (&sv_pr_state, check)) {
74 if (check->free)
75 continue;
76 if (SVfloat (check, movetype) == MOVETYPE_PUSH
77 || SVfloat (check, movetype) == MOVETYPE_NONE
78 || SVfloat (check, movetype) == MOVETYPE_NOCLIP)
79 continue;
80
81 if (SV_TestEntityPosition (check))
82 Sys_Printf ("entity in invalid position\n");
83 }
84 }
85 #endif
86 void
SV_CheckVelocity(edict_t * ent)87 SV_CheckVelocity (edict_t *ent)
88 {
89 float wishspeed;
90 // int i;
91
92 // bound velocity
93 #if 0
94 for (i = 0; i < 3; i++) {
95 if (IS_NAN (SVvector (ent, velocity)[i])) {
96 Sys_Printf ("Got a NaN velocity on %s\n",
97 PR_GetString (&sv_pr_state, SVstring (ent,
98 classname)));
99 SVvector (ent, velocity)[i] = 0;
100 }
101 if (IS_NAN (SVvector (ent, origin)[i])) {
102 Sys_Printf ("Got a NaN origin on %s\n",
103 PR_GetString (&sv_pr_state, SVstring (ent,
104 classname)));
105 SVvector (ent, origin)[i] = 0;
106 }
107 }
108 #endif
109 wishspeed = VectorLength (SVvector (ent, velocity));
110 if (wishspeed > sv_maxvelocity->value) {
111 VectorScale (SVvector (ent, velocity), sv_maxvelocity->value /
112 wishspeed, SVvector (ent, velocity));
113 }
114 }
115
116 /*
117 SV_RunThink
118
119 Runs thinking code if time. There is some play in the exact time the think
120 function will be called, because it is called before any movement is done
121 in a frame. Not used for pushmove objects, because they must be exact.
122 Returns false if the entity removed itself.
123 */
124 qboolean
SV_RunThink(edict_t * ent)125 SV_RunThink (edict_t *ent)
126 {
127 float thinktime;
128
129 do {
130 thinktime = SVfloat (ent, nextthink);
131 if (thinktime <= 0 || thinktime > sv.time + sv_frametime)
132 return true;
133
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 SVfloat (ent, nextthink) = 0;
139 *sv_globals.time = thinktime;
140 sv_pr_think (ent);
141
142 if (ent->free)
143 return false;
144 } while (SVfloat (ent, nextthink) > thinktime);
145
146 return true;
147 }
148
149 /*
150 SV_Impact
151
152 Two entities have touched, so run their touch functions
153 */
154 static void
SV_Impact(edict_t * e1,edict_t * e2)155 SV_Impact (edict_t *e1, edict_t *e2)
156 {
157 int old_self, old_other;
158
159 old_self = *sv_globals.self;
160 old_other = *sv_globals.other;
161
162 *sv_globals.time = sv.time;
163 if (SVfunc (e1, touch) && SVfloat (e1, solid) != SOLID_NOT) {
164 sv_pr_touch (e1, e2);
165 }
166
167 if (SVfunc (e2, touch) && SVfloat (e2, solid) != SOLID_NOT) {
168 sv_pr_touch (e2, e1);
169 }
170
171 *sv_globals.self = old_self;
172 *sv_globals.other = old_other;
173 }
174
175 /*
176 ClipVelocity
177
178 Slide off of the impacting object
179 returns the blocked flags (1 = floor, 2 = step / wall)
180 */
181 static int
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)182 ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
183 {
184 float backoff, change;
185 int i, blocked;
186
187 blocked = 0;
188 if (normal[2] > 0)
189 blocked |= 1; // floor
190 if (!normal[2])
191 blocked |= 2; // step
192
193 backoff = DotProduct (in, normal) * overbounce;
194
195 for (i = 0; i < 3; i++) {
196 change = normal[i] * backoff;
197 out[i] = in[i] - change;
198 if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
199 out[i] = 0;
200 }
201
202 return blocked;
203 }
204
205 int
SV_EntCanSupportJump(edict_t * ent)206 SV_EntCanSupportJump (edict_t *ent)
207 {
208 int solid = SVfloat (ent, solid);
209 if (solid == SOLID_BSP)
210 return 1;
211 if (!sv_jump_any->int_val)
212 return 0;
213 if (solid == SOLID_NOT || solid == SOLID_SLIDEBOX)
214 return 0;
215 return 1;
216 }
217
218 #define MAX_CLIP_PLANES 5
219
220 /*
221 SV_FlyMove
222
223 The basic solid body movement clip that slides along multiple planes
224 Returns the clipflags if the velocity was modified (hit something solid)
225 1 = floor
226 2 = wall / step
227 4 = dead stop
228 If steptrace is not NULL, the trace of any vertical wall hit will be stored
229 */
230 int
SV_FlyMove(edict_t * ent,float time,trace_t * steptrace)231 SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)
232 {
233 float d, time_left;
234 int blocked, bumpcount, numbumps, numplanes, i, j;
235 trace_t trace;
236 vec3_t dir, end;
237 vec3_t planes[MAX_CLIP_PLANES];
238 vec3_t primal_velocity, original_velocity, new_velocity;
239
240 numbumps = 4;
241
242 blocked = 0;
243 VectorCopy (SVvector (ent, velocity), original_velocity);
244 VectorCopy (SVvector (ent, velocity), primal_velocity);
245 numplanes = 0;
246
247 time_left = time;
248
249 for (bumpcount = 0; bumpcount < numbumps; bumpcount++) {
250 if (VectorIsZero (SVvector (ent, velocity)))
251 break;
252
253 VectorMultAdd (SVvector (ent, origin), time_left,
254 SVvector (ent, velocity), end);
255 if (SVdata (ent)->add_grav) {
256 SVdata (ent)->add_grav = false;
257 SV_FinishGravity (ent, end);
258 }
259
260 trace = SV_Move (SVvector (ent, origin), SVvector (ent, mins),
261 SVvector (ent, maxs), end, false, ent);
262
263 if (trace.allsolid) { // entity is trapped in another solid
264 VectorZero (SVvector (ent, velocity));
265 return 3;
266 }
267
268 if (trace.fraction > 0) { // actually covered some distance
269 VectorCopy (trace.endpos, SVvector (ent, origin));
270 VectorCopy (SVvector (ent, velocity), original_velocity);
271 numplanes = 0;
272 }
273
274 if (trace.fraction == 1)
275 break; // moved the entire distance
276
277 if (!trace.ent)
278 Sys_Error ("SV_FlyMove: !trace.ent");
279
280 if (trace.plane.normal[2] > 0.7) {
281 blocked |= 1; // floor
282 if (SV_EntCanSupportJump (trace.ent)) {
283 SVfloat (ent, flags) = (int) SVfloat (ent, flags) |
284 FL_ONGROUND;
285 SVentity (ent, groundentity) = EDICT_TO_PROG (&sv_pr_state,
286 trace.ent);
287 }
288 }
289 if (!trace.plane.normal[2]) {
290 blocked |= 2; // step
291 if (steptrace)
292 *steptrace = trace; // save for player extrafriction
293 }
294
295 // run the impact function
296 SV_Impact (ent, trace.ent);
297 if (ent->free)
298 break; // removed by the impact function
299
300 time_left -= time_left * trace.fraction;
301
302 // cliped to another plane
303 if (numplanes >= MAX_CLIP_PLANES) { // this shouldn't really happen
304 VectorZero (SVvector (ent, velocity));
305 return 3;
306 }
307
308 VectorCopy (trace.plane.normal, planes[numplanes]);
309 numplanes++;
310
311 // modify original_velocity so it parallels all of the clip planes
312 for (i = 0; i < numplanes; i++) {
313 ClipVelocity (original_velocity, planes[i], new_velocity, 1);
314 for (j = 0; j < numplanes; j++)
315 if (j != i) {
316 if (DotProduct (new_velocity, planes[j]) < 0)
317 break; // not ok
318 }
319 if (j == numplanes)
320 break;
321 }
322
323 if (i != numplanes) { // go along this plane
324 VectorCopy (new_velocity, SVvector (ent, velocity));
325 } else { // go along the crease
326 if (numplanes != 2) {
327 VectorZero (SVvector (ent, velocity));
328 return 7;
329 }
330 CrossProduct (planes[0], planes[1], dir);
331 d = DotProduct (dir, SVvector (ent, velocity));
332 VectorScale (dir, d, SVvector (ent, velocity));
333 }
334
335 // if original velocity is against the original velocity, stop dead
336 // to avoid tiny occilations in sloping corners
337 if (DotProduct (SVvector (ent, velocity), primal_velocity) <= 0) {
338 VectorZero (SVvector (ent, velocity));
339 return blocked;
340 }
341 }
342
343 return blocked;
344 }
345
346 void
SV_AddGravity(edict_t * ent)347 SV_AddGravity (edict_t *ent)
348 {
349 float ent_grav;
350
351 if (sv_fields.gravity != -1 && SVfloat (ent, gravity))
352 ent_grav = SVfloat (ent, gravity);
353 else
354 ent_grav = 1.0;
355 SVvector (ent, velocity)[2] -= ent_grav * sv_gravity->value * sv_frametime;
356 SVdata (ent)->add_grav = true;
357 }
358
359 void
SV_FinishGravity(edict_t * ent,vec3_t move)360 SV_FinishGravity (edict_t *ent, vec3_t move)
361 {
362 float ent_grav;
363
364 if (sv_fields.gravity != -1 && SVfloat (ent, gravity))
365 ent_grav = SVfloat (ent, gravity);
366 else
367 ent_grav = 1.0;
368 ent_grav *= sv_gravity->value;
369 move[2] += ent_grav * sv_frametime * sv_frametime / 2;
370 }
371
372 /* PUSHMOVE */
373
374 /*
375 SV_PushEntity
376
377 Does not change the entities velocity at all
378 */
379 trace_t
SV_PushEntity(edict_t * ent,vec3_t push)380 SV_PushEntity (edict_t *ent, vec3_t push)
381 {
382 trace_t trace;
383 vec3_t end;
384 vec_t *e_origin, *e_mins, *e_maxs;
385 int e_movetype, e_solid;
386
387 e_origin = SVvector (ent, origin);
388 e_mins = SVvector (ent, mins);
389 e_maxs = SVvector (ent, maxs);
390 e_movetype = SVfloat (ent, movetype);
391 e_solid = SVfloat (ent, solid);
392
393 VectorAdd (e_origin, push, end);
394
395 if (e_movetype == MOVETYPE_FLYMISSILE)
396 trace = SV_Move (e_origin, e_mins, e_maxs, end, MOVE_MISSILE, ent);
397 else if (e_solid == SOLID_TRIGGER || e_solid == SOLID_NOT)
398 // clip against only bmodels
399 trace = SV_Move (e_origin, e_mins, e_maxs, end, MOVE_NOMONSTERS, ent);
400 else
401 trace = SV_Move (e_origin, e_mins, e_maxs, end, MOVE_NORMAL, ent);
402
403 VectorCopy (trace.endpos, e_origin);
404 SV_LinkEdict (ent, true);
405
406 if (trace.ent)
407 SV_Impact (ent, trace.ent);
408
409 return trace;
410 }
411
412 static qboolean
SV_Push(edict_t * pusher,const vec3_t tmove,const vec3_t amove)413 SV_Push (edict_t *pusher, const vec3_t tmove, const vec3_t amove)
414 {
415 float solid_save;
416 int num_moved, i, e;
417 edict_t *check, *block;
418 edict_t **moved_edict;
419 vec3_t move, org, org2;
420 vec3_t mins, maxs, pushtorig, pushaorig;
421 vec3_t *moved_from;
422 vec3_t forward = {1, 0, 0};
423 vec3_t left = {0, 1, 0};
424 vec3_t up = {0, 0, 1};
425 int mark;
426 int c_flags, c_movetype, c_groundentity, c_solid;
427 vec_t *c_absmin, *c_absmax, *c_origin, *c_angles, *c_mins, *c_maxs;
428 vec_t *p_origin, *p_angles;
429
430 VectorAdd (SVvector (pusher, absmin), tmove, mins);
431 VectorAdd (SVvector (pusher, absmax), tmove, maxs);
432
433 if (!VectorIsZero (amove)) {
434 vec3_t a;
435 VectorSubtract (vec3_origin, amove, a);
436 AngleVectors (a, forward, left, up);
437 VectorNegate (left, left); // AngleVectors is right-handed
438 }
439
440 p_origin = SVvector (pusher, origin);
441 p_angles = SVvector (pusher, angles);
442 VectorCopy (p_origin, pushtorig);
443 VectorCopy (p_angles, pushaorig);
444
445 // move the pusher to it's final position
446 VectorAdd (p_origin, tmove, p_origin);
447 VectorAdd (p_angles, amove, p_angles);
448 SV_LinkEdict (pusher, false);
449
450 mark = Hunk_LowMark ();
451 moved_edict = Hunk_Alloc (sv.num_edicts * sizeof (edict_t *));
452 moved_from = Hunk_Alloc (sv.num_edicts * sizeof (vec_t));
453
454 // see if any solid entities are inside the final position
455 num_moved = 0;
456 check = NEXT_EDICT (&sv_pr_state, sv.edicts);
457 for (e = 1; e < sv.num_edicts;
458 e++, check = NEXT_EDICT (&sv_pr_state, check)) {
459 if (check->free)
460 continue;
461 c_movetype = SVfloat (check, movetype);
462 if (c_movetype == MOVETYPE_PUSH || c_movetype == MOVETYPE_NONE
463 || c_movetype == MOVETYPE_NOCLIP)
464 continue;
465
466 // If the entity is in another solid, it's not free to move. Make the
467 // pusher non-solid to ensure it doesn't interfere with the check.
468 solid_save = SVfloat (pusher, solid);
469 SVfloat (pusher, solid) = SOLID_NOT;
470 block = SV_TestEntityPosition (check);
471 SVfloat (pusher, solid) = solid_save;
472 if (block)
473 continue;
474
475 // if the entity is standing on the pusher, it will definately be moved
476 c_flags = SVfloat (check, flags);
477 c_groundentity = SVentity (check, groundentity);
478 if (!(c_flags & FL_ONGROUND)
479 || PROG_TO_EDICT (&sv_pr_state, c_groundentity) != pusher) {
480 // The entity is NOT standing on pusher, so check whether the
481 // entity is inside the pusher's final position.
482 // FIXME what if the pusher is moving so fast it skips past the
483 // entity?
484 c_absmin = SVvector (check, absmin);
485 c_absmax = SVvector (check, absmax);
486 if (VectorCompCompare (c_absmin, >=, maxs)
487 || VectorCompCompare (c_absmax, <=, mins))
488 continue;
489
490 if (!SV_TestEntityPosition (check))
491 continue;
492 // The pusher and entity collide, so push the entity.
493 }
494 // remove the onground flag for non-players
495 if (c_movetype != MOVETYPE_WALK)
496 SVfloat (check, flags) = c_flags & ~FL_ONGROUND;
497
498 c_origin = SVvector (check, origin);
499 VectorCopy (c_origin, moved_from[num_moved]);
500 moved_edict[num_moved] = check;
501 num_moved++;
502
503 // calculate destination position
504 VectorSubtract (c_origin, p_origin, org);
505 org2[0] = DotProduct (org, forward);
506 org2[1] = DotProduct (org, left);
507 org2[2] = DotProduct (org, up);
508 VectorSubtract (org2, org, move);
509 VectorAdd (move, tmove, move);
510
511 // try moving the contacted entity
512 solid_save = SVfloat (pusher, solid);
513 SVfloat (pusher, solid) = SOLID_NOT;
514 SV_PushEntity (check, move);
515 SVfloat (pusher, solid) = solid_save;
516
517 block = SV_TestEntityPosition (check);
518 if (!block) {
519 c_angles = SVvector (check, angles);
520 VectorAdd (c_angles, amove, c_angles);
521 continue;
522 }
523 // if it is still inside the pusher, block
524 c_mins = SVvector (check, mins);
525 c_maxs = SVvector (check, maxs);
526 c_solid = SVfloat (check, solid);
527 if (c_mins[0] == c_maxs[0]
528 || c_solid == SOLID_NOT || c_solid == SOLID_TRIGGER) { // corpse
529 c_mins[0] = c_mins[1] = 0;
530 VectorCopy (c_mins, c_maxs);
531 SV_LinkEdict (check, false);
532 continue;
533 }
534
535 VectorCopy (pushtorig, p_origin);
536 VectorCopy (pushaorig, p_angles);
537 SV_LinkEdict (pusher, false);
538
539 // if the pusher has a "blocked" function, call it
540 // otherwise, just stay in place until the obstacle is gone
541 if (SVfunc (pusher, blocked))
542 sv_pr_blocked (pusher, check);
543
544 // move back any entities we already moved
545 for (i = 0; i < num_moved; i++) {
546 vec_t *m_origin = SVvector (moved_edict[i], origin);
547 vec_t *m_angles = SVvector (moved_edict[i], angles);
548 VectorCopy (moved_from[i], m_origin);
549 VectorSubtract (m_angles, amove, m_angles);
550 SV_LinkEdict (moved_edict[i], false);
551 }
552 Hunk_FreeToLowMark (mark);
553 return false;
554 }
555 Hunk_FreeToLowMark (mark);
556 return true;
557 }
558
559 static void
SV_PushMove(edict_t * pusher,float movetime)560 SV_PushMove (edict_t *pusher, float movetime)
561 {
562 vec3_t move;
563 vec3_t amove;
564
565 if (VectorIsZero (SVvector (pusher, velocity))
566 && VectorIsZero (SVvector (pusher, avelocity))) {
567 SVfloat (pusher, ltime) += movetime;
568 return;
569 }
570
571 VectorScale (SVvector (pusher, velocity), movetime, move);
572 //FIXME finish gravity
573 VectorScale (SVvector (pusher, avelocity), movetime, amove);
574
575 if (SV_Push (pusher, move, amove))
576 SVfloat (pusher, ltime) += movetime;
577 }
578
579 static void
SV_Physics_Pusher(edict_t * ent)580 SV_Physics_Pusher (edict_t *ent)
581 {
582 float movetime, oldltime, thinktime;
583 float l;
584 vec3_t oldorg, move;
585
586 oldltime = SVfloat (ent, ltime);
587
588 thinktime = SVfloat (ent, nextthink);
589 if (thinktime < SVfloat (ent, ltime) + sv_frametime) {
590 movetime = thinktime - SVfloat (ent, ltime);
591 if (movetime < 0)
592 movetime = 0;
593 } else
594 movetime = sv_frametime;
595
596 if (movetime) {
597 SV_PushMove (ent, movetime); // advances SVfloat (ent, ltime) if not
598 // blocked
599 }
600
601 if (thinktime > oldltime && thinktime <= SVfloat (ent, ltime)) {
602 VectorCopy (SVvector (ent, origin), oldorg);
603 SVfloat (ent, nextthink) = 0;
604 *sv_globals.time = sv.time;
605 sv_pr_think (ent);
606 if (ent->free)
607 return;
608 VectorSubtract (SVvector (ent, origin), oldorg, move);
609
610 l = VectorLength (move);
611 if (l > (1.0 / 64.0)) {
612 VectorCopy (oldorg, SVvector (ent, origin));
613 SV_Push (ent, move, vec3_origin); //FIXME angle
614 }
615 }
616 }
617
618 /*
619 SV_Physics_None
620
621 Non moving objects can only think
622 */
623 static void
SV_Physics_None(edict_t * ent)624 SV_Physics_None (edict_t *ent)
625 {
626 // regular thinking
627 if (SV_RunThink (ent))
628 SV_LinkEdict (ent, false);
629 }
630
631 /*
632 SV_Physics_Noclip
633
634 A moving object that doesn't obey physics
635 */
636 static void
SV_Physics_Noclip(edict_t * ent)637 SV_Physics_Noclip (edict_t *ent)
638 {
639 // regular thinking
640 if (!SV_RunThink (ent))
641 return;
642
643 VectorMultAdd (SVvector (ent, angles), sv_frametime,
644 SVvector (ent, avelocity), SVvector (ent, angles));
645 VectorMultAdd (SVvector (ent, origin), sv_frametime,
646 SVvector (ent, velocity), SVvector (ent, origin));
647
648 SV_LinkEdict (ent, false);
649 }
650
651 /* TOSS / BOUNCE */
652
653 static void
SV_CheckWaterTransition(edict_t * ent)654 SV_CheckWaterTransition (edict_t *ent)
655 {
656 int cont;
657
658 cont = SV_PointContents (SVvector (ent, origin));
659
660 if (!SVfloat (ent, watertype)) { // just spawned here
661 SVfloat (ent, watertype) = cont;
662 SVfloat (ent, waterlevel) = 1;
663 return;
664 }
665
666 if (cont <= CONTENTS_WATER) {
667 if (SVfloat (ent, watertype) == CONTENTS_EMPTY) {
668 // just crossed into water
669 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
670 }
671 SVfloat (ent, watertype) = cont;
672 SVfloat (ent, waterlevel) = 1;
673 } else {
674 if (SVfloat (ent, watertype) != CONTENTS_EMPTY) {
675 // just crossed into water
676 SV_StartSound (ent, 0, "misc/h2ohit1.wav", 255, 1);
677 }
678 SVfloat (ent, watertype) = CONTENTS_EMPTY;
679 SVfloat (ent, waterlevel) = cont;
680 }
681 }
682
683 /*
684 SV_Physics_Toss
685
686 Toss, bounce, and fly movement. When onground, do nothing.
687 */
688 void
SV_Physics_Toss(edict_t * ent)689 SV_Physics_Toss (edict_t *ent)
690 {
691 float backoff;
692 trace_t trace;
693 vec3_t move;
694
695 // regular thinking
696 if (!SV_RunThink (ent))
697 return;
698
699 if (SVvector (ent, velocity)[2] > 0)
700 SVfloat (ent, flags) = (int) SVfloat (ent, flags) & ~FL_ONGROUND;
701
702 // if onground, return without moving
703 if (((int) SVfloat (ent, flags) & FL_ONGROUND))
704 return;
705
706 SV_CheckVelocity (ent);
707
708 // add gravity
709 if (SVfloat (ent, movetype) != MOVETYPE_FLY
710 && SVfloat (ent, movetype) != MOVETYPE_FLYMISSILE)
711 SV_AddGravity (ent);
712
713 // move angles
714 VectorMultAdd (SVvector (ent, angles), sv_frametime,
715 SVvector (ent, avelocity), SVvector (ent, angles));
716
717 // move origin
718 VectorScale (SVvector (ent, velocity), sv_frametime, move);
719 if (SVdata (ent)->add_grav) {
720 SVdata (ent)->add_grav = false;
721 SV_FinishGravity (ent, move);
722 }
723 trace = SV_PushEntity (ent, move);
724 if (trace.fraction == 1)
725 return;
726 if (ent->free)
727 return;
728
729 if (SVfloat (ent, movetype) == MOVETYPE_BOUNCE)
730 backoff = 1.5;
731 else
732 backoff = 1;
733
734 ClipVelocity (SVvector (ent, velocity), trace.plane.normal,
735 SVvector (ent, velocity), backoff);
736
737 // stop if on ground
738 if (trace.plane.normal[2] > 0.7) {
739 if (SVvector (ent, velocity)[2] < 60
740 || SVfloat (ent, movetype) != MOVETYPE_BOUNCE) {
741 SVfloat (ent, flags) = (int) SVfloat (ent, flags) | FL_ONGROUND;
742 SVentity (ent, groundentity) = EDICT_TO_PROG (&sv_pr_state,
743 trace.ent);
744 VectorZero (SVvector (ent, velocity));
745 VectorZero (SVvector (ent, avelocity));
746 }
747 }
748 // check for in water
749 SV_CheckWaterTransition (ent);
750 }
751
752 /* STEPPING MOVEMENT */
753
754 /*
755 SV_Physics_Step
756
757 Monsters freefall when they don't have a ground entity, otherwise
758 all movement is done with discrete steps.
759
760 This is also used for objects that have become still on the ground, but
761 will fall if the floor is pulled out from under them.
762 FIXME: is this true?
763 */
764 static void
SV_Physics_Step(edict_t * ent)765 SV_Physics_Step (edict_t *ent)
766 {
767 qboolean hitsound;
768
769 // freefall if not on ground
770 if (!((int) SVfloat (ent, flags) & (FL_ONGROUND | FL_FLY | FL_SWIM))) {
771 if (SVvector (ent, velocity)[2] < sv_gravity->value * -0.1)
772 hitsound = true;
773 else
774 hitsound = false;
775
776 SV_AddGravity (ent);
777 SV_CheckVelocity (ent);
778 SV_FlyMove (ent, sv_frametime, NULL);
779 SV_LinkEdict (ent, true);
780
781 if ((int) SVfloat (ent, flags) & FL_ONGROUND) { // just hit ground
782 if (hitsound)
783 SV_StartSound (ent, 0, "demon/dland2.wav", 255, 1);
784 }
785 }
786 // regular thinking
787 SV_RunThink (ent);
788
789 SV_CheckWaterTransition (ent);
790 }
791
792 void
SV_ProgStartFrame(void)793 SV_ProgStartFrame (void)
794 {
795 // let the progs know that a new frame has started
796 *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv.edicts);
797 *sv_globals.other = EDICT_TO_PROG (&sv_pr_state, sv.edicts);
798 *sv_globals.time = sv.time;
799 PR_ExecuteProgram (&sv_pr_state, sv_funcs.StartFrame);
800 }
801
802 static void
SV_RunEntity(edict_t * ent)803 SV_RunEntity (edict_t *ent)
804 {
805 if (sv_fields.lastruntime != -1) {
806 if (SVfloat (ent, lastruntime) == (float) sv.time)
807 return;
808 SVfloat (ent, lastruntime) = (float) sv.time;
809 }
810 SVdata (ent)->add_grav = false;
811
812 switch ((int) SVfloat (ent, movetype)) {
813 case MOVETYPE_PUSH:
814 SV_Physics_Pusher (ent);
815 break;
816 case MOVETYPE_NONE:
817 SV_Physics_None (ent);
818 break;
819 case MOVETYPE_NOCLIP:
820 SV_Physics_Noclip (ent);
821 break;
822 case MOVETYPE_STEP:
823 SV_Physics_Step (ent);
824 break;
825 case MOVETYPE_TOSS:
826 case MOVETYPE_BOUNCE:
827 case MOVETYPE_FLY:
828 case MOVETYPE_FLYMISSILE:
829 SV_Physics_Toss (ent);
830 break;
831 default:
832 Sys_Error ("SV_Physics: bad movetype %i",
833 (int) SVfloat (ent, movetype));
834 }
835 }
836
837 void
SV_RunNewmis(void)838 SV_RunNewmis (void)
839 {
840 edict_t *ent;
841
842 if (sv_fields.lastruntime == -1 || !sv_globals.newmis
843 || !*sv_globals.newmis)
844 return;
845 ent = PROG_TO_EDICT (&sv_pr_state, *sv_globals.newmis);
846 sv_frametime = 0.05;
847 *sv_globals.newmis = 0;
848
849 SV_RunEntity (ent);
850 }
851
852 void
SV_Physics(void)853 SV_Physics (void)
854 {
855 edict_t *ent;
856 int i;
857
858 SV_ProgStartFrame ();
859
860 // treat each object in turn
861 // even the world gets a chance to think
862 ent = sv.edicts;
863 for (i = 0; i < sv.num_edicts; i++, ent = NEXT_EDICT (&sv_pr_state, ent)) {
864 if (ent->free)
865 continue;
866
867 if (*sv_globals.force_retouch) {
868 SV_LinkEdict (ent, true); // force retouch even for stationary
869 }
870
871 if (i > 0 && i <= svs.maxclients) {
872 if (svs.phys_client)
873 svs.phys_client (ent, i);
874 continue;
875 }
876
877 SV_RunEntity (ent);
878 SV_RunNewmis ();
879 }
880
881 if (*sv_globals.force_retouch)
882 (*sv_globals.force_retouch)--;
883
884 if (sv_funcs.EndFrame) {
885 // let the progs know that the frame has ended
886 *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv.edicts);
887 *sv_globals.other = EDICT_TO_PROG (&sv_pr_state, sv.edicts);
888 *sv_globals.time = sv.time;
889 PR_ExecuteProgram (&sv_pr_state, sv_funcs.EndFrame);
890 }
891 }
892