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