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