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