1 // g_phys.c
2 
3 #include "g_local.h"
4 
5 /*
6 
7 
8 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.
9 
10 onground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects
11 
12 doors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH
13 bonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS
14 corpses are SOLID_NOT and MOVETYPE_TOSS
15 crates are SOLID_BBOX and MOVETYPE_TOSS
16 walking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP
17 flying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY
18 
19 solid_edge items only clip against bsp models.
20 
21 */
22 
23 
24 /*
25 ============
26 SV_TestEntityPosition
27 
28 ============
29 */
SV_TestEntityPosition(edict_t * ent)30 edict_t	*SV_TestEntityPosition (edict_t *ent)
31 {
32 	trace_t	trace;
33 	int		mask;
34 
35 	if (ent->clipmask)
36 		mask = ent->clipmask;
37 	else
38 		mask = MASK_SOLID;
39 	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
40 
41 	if (trace.startsolid)
42 		return g_edicts;
43 
44 	return NULL;
45 }
46 
47 
48 /*
49 ================
50 SV_CheckVelocity
51 ================
52 */
SV_CheckVelocity(edict_t * ent)53 void SV_CheckVelocity (edict_t *ent)
54 {
55 	int		i;
56 
57 //
58 // bound velocity
59 //
60 	for (i=0 ; i<3 ; i++)
61 	{
62 		if (ent->velocity[i] > sv_maxvelocity->value)
63 			ent->velocity[i] = sv_maxvelocity->value;
64 		else if (ent->velocity[i] < -sv_maxvelocity->value)
65 			ent->velocity[i] = -sv_maxvelocity->value;
66 	}
67 }
68 
69 /*
70 =============
71 SV_RunThink
72 
73 Runs thinking code for this frame if necessary
74 =============
75 */
SV_RunThink(edict_t * ent)76 qboolean SV_RunThink (edict_t *ent)
77 {
78 	float	thinktime;
79 
80 	thinktime = ent->nextthink;
81 	if (thinktime <= 0)
82 		return true;
83 	if (thinktime > level.time+0.001)
84 		return true;
85 
86 	ent->nextthink = 0;
87 	if (!ent->think)
88 		gi.error ("NULL ent->think");
89 	ent->think (ent);
90 
91 	return false;
92 }
93 
94 /*
95 ==================
96 SV_Impact
97 
98 Two entities have touched, so run their touch functions
99 ==================
100 */
SV_Impact(edict_t * e1,trace_t * trace)101 void SV_Impact (edict_t *e1, trace_t *trace)
102 {
103 	edict_t		*e2;
104 //	cplane_t	backplane;
105 
106 	e2 = trace->ent;
107 
108 	if (e1->touch && e1->solid != SOLID_NOT)
109 		e1->touch (e1, e2, &trace->plane, trace->surface);
110 
111 	if (e2->touch && e2->solid != SOLID_NOT)
112 		e2->touch (e2, e1, NULL, NULL);
113 }
114 
115 
116 /*
117 ==================
118 ClipVelocity
119 
120 Slide off of the impacting object
121 returns the blocked flags (1 = floor, 2 = step / wall)
122 ==================
123 */
124 #define	STOP_EPSILON	0.1
125 
ClipVelocity(vec3_t in,vec3_t normal,vec3_t out,float overbounce)126 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
127 {
128 	float	backoff;
129 	float	change;
130 	int		i, blocked;
131 
132 	blocked = 0;
133 	if (normal[2] > 0)
134 		blocked |= 1;		// floor
135 	if (!normal[2])
136 		blocked |= 2;		// step
137 
138 	backoff = DotProduct (in, normal) * overbounce;
139 
140 	for (i=0 ; i<3 ; i++)
141 	{
142 		change = normal[i]*backoff;
143 		out[i] = in[i] - change;
144 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
145 			out[i] = 0;
146 	}
147 
148 	return blocked;
149 }
150 
151 
152 /*
153 ============
154 SV_FlyMove
155 
156 The basic solid body movement clip that slides along multiple planes
157 Returns the clipflags if the velocity was modified (hit something solid)
158 1 = floor
159 2 = wall / step
160 4 = dead stop
161 ============
162 */
163 #define	MAX_CLIP_PLANES	5
SV_FlyMove(edict_t * ent,float time,int mask)164 int SV_FlyMove (edict_t *ent, float time, int mask)
165 {
166 	edict_t		*hit;
167 	int			bumpcount, numbumps;
168 	vec3_t		dir;
169 	float		d;
170 	int			numplanes;
171 	vec3_t		planes[MAX_CLIP_PLANES];
172 	vec3_t		primal_velocity, original_velocity, new_velocity;
173 	int			i, j;
174 	trace_t		trace;
175 	vec3_t		end;
176 	float		time_left;
177 	int			blocked;
178 
179 	numbumps = 4;
180 
181 	blocked = 0;
182 	VectorCopy (ent->velocity, original_velocity);
183 	VectorCopy (ent->velocity, primal_velocity);
184 	numplanes = 0;
185 
186 	time_left = time;
187 
188 	ent->groundentity = NULL;
189 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
190 	{
191 		for (i=0 ; i<3 ; i++)
192 			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
193 
194 		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
195 
196 		if (trace.allsolid)
197 		{	// entity is trapped in another solid
198 			VectorCopy (vec3_origin, ent->velocity);
199 			return 3;
200 		}
201 
202 		if (trace.fraction > 0)
203 		{	// actually covered some distance
204 			VectorCopy (trace.endpos, ent->s.origin);
205 			VectorCopy (ent->velocity, original_velocity);
206 			numplanes = 0;
207 		}
208 
209 		if (trace.fraction == 1)
210 			 break;		// moved the entire distance
211 
212 		hit = trace.ent;
213 
214 		if (trace.plane.normal[2] > 0.7)
215 		{
216 			blocked |= 1;		// floor
217 			if ( hit->solid == SOLID_BSP)
218 			{
219 				ent->groundentity = hit;
220 				ent->groundentity_linkcount = hit->linkcount;
221 			}
222 		}
223 		if (!trace.plane.normal[2])
224 		{
225 			blocked |= 2;		// step
226 		}
227 
228 //
229 // run the impact function
230 //
231 		SV_Impact (ent, &trace);
232 		if (!ent->inuse)
233 			break;		// removed by the impact function
234 
235 
236 		time_left -= time_left * trace.fraction;
237 
238 	// cliped to another plane
239 		if (numplanes >= MAX_CLIP_PLANES)
240 		{	// this shouldn't really happen
241 			VectorCopy (vec3_origin, ent->velocity);
242 			return 3;
243 		}
244 
245 		VectorCopy (trace.plane.normal, planes[numplanes]);
246 		numplanes++;
247 
248 //
249 // modify original_velocity so it parallels all of the clip planes
250 //
251 		for (i=0 ; i<numplanes ; i++)
252 		{
253 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
254 
255 			for (j=0 ; j<numplanes ; j++)
256 				if ((j != i) && !VectorCompare (planes[i], planes[j]))
257 				{
258 					if (DotProduct (new_velocity, planes[j]) < 0)
259 						break;	// not ok
260 				}
261 			if (j == numplanes)
262 				break;
263 		}
264 
265 		if (i != numplanes)
266 		{	// go along this plane
267 			VectorCopy (new_velocity, ent->velocity);
268 		}
269 		else
270 		{	// go along the crease
271 			if (numplanes != 2)
272 			{
273 //				gi.dprintf ("clip velocity, numplanes == %i\n",numplanes);
274 				VectorCopy (vec3_origin, ent->velocity);
275 				return 7;
276 			}
277 			CrossProduct (planes[0], planes[1], dir);
278 			d = DotProduct (dir, ent->velocity);
279 			VectorScale (dir, d, ent->velocity);
280 		}
281 
282 //
283 // if original velocity is against the original velocity, stop dead
284 // to avoid tiny occilations in sloping corners
285 //
286 		if (DotProduct (ent->velocity, primal_velocity) <= 0)
287 		{
288 			VectorCopy (vec3_origin, ent->velocity);
289 			return blocked;
290 		}
291 	}
292 
293 	return blocked;
294 }
295 
296 
297 /*
298 ============
299 SV_AddGravity
300 
301 ============
302 */
SV_AddGravity(edict_t * ent)303 void SV_AddGravity (edict_t *ent)
304 {
305 	ent->velocity[2] -= ent->gravity * sv_gravity->value * FRAMETIME;
306 }
307 
308 /*
309 ===============================================================================
310 
311 PUSHMOVE
312 
313 ===============================================================================
314 */
315 
316 /*
317 ============
318 SV_PushEntity
319 
320 Does not change the entities velocity at all
321 ============
322 */
SV_PushEntity(edict_t * ent,vec3_t push)323 trace_t SV_PushEntity (edict_t *ent, vec3_t push)
324 {
325 	trace_t	trace;
326 	vec3_t	start;
327 	vec3_t	end;
328 	int		mask;
329 
330 	VectorCopy (ent->s.origin, start);
331 	VectorAdd (start, push, end);
332 
333 retry:
334 	if (ent->clipmask)
335 		mask = ent->clipmask;
336 	else
337 		mask = MASK_SOLID;
338 
339 	trace = gi.trace (start, ent->mins, ent->maxs, end, ent, mask);
340 
341 	VectorCopy (trace.endpos, ent->s.origin);
342 	gi.linkentity (ent);
343 
344 	if (trace.fraction != 1.0)
345 	{
346 		SV_Impact (ent, &trace);
347 
348 		// if the pushed entity went away and the pusher is still there
349 		if (!trace.ent->inuse && ent->inuse)
350 		{
351 			// move the pusher back and try again
352 			VectorCopy (start, ent->s.origin);
353 			gi.linkentity (ent);
354 			goto retry;
355 		}
356 	}
357 
358 	if (ent->inuse)
359 		G_TouchTriggers (ent);
360 
361 	return trace;
362 }
363 
364 
365 typedef struct
366 {
367 	edict_t	*ent;
368 	vec3_t	origin;
369 	vec3_t	angles;
370 	float	deltayaw;
371 } pushed_t;
372 pushed_t	pushed[MAX_EDICTS], *pushed_p;
373 
374 edict_t	*obstacle;
375 
376 /*
377 ============
378 SV_Push
379 
380 Objects need to be moved back on a failed push,
381 otherwise riders would continue to slide.
382 ============
383 */
SV_Push(edict_t * pusher,vec3_t move,vec3_t amove)384 qboolean SV_Push (edict_t *pusher, vec3_t move, vec3_t amove)
385 {
386 	int			i, e;
387 	edict_t		*check, *block;
388 	vec3_t		mins, maxs;
389 	pushed_t	*p;
390 	vec3_t		org, org2, move2, forward, right, up;
391 
392 	// clamp the move to 1/8 units, so the position will
393 	// be accurate for client side prediction
394 	for (i=0 ; i<3 ; i++)
395 	{
396 		float	temp;
397 		temp = move[i]*8.0;
398 		if (temp > 0.0)
399 			temp += 0.5;
400 		else
401 			temp -= 0.5;
402 		move[i] = 0.125 * (int)temp;
403 	}
404 
405 	// find the bounding box
406 	for (i=0 ; i<3 ; i++)
407 	{
408 		mins[i] = pusher->absmin[i] + move[i];
409 		maxs[i] = pusher->absmax[i] + move[i];
410 	}
411 
412 // we need this for pushing things later
413 	VectorSubtract (vec3_origin, amove, org);
414 	AngleVectors (org, forward, right, up);
415 
416 // save the pusher's original position
417 	pushed_p->ent = pusher;
418 	VectorCopy (pusher->s.origin, pushed_p->origin);
419 	VectorCopy (pusher->s.angles, pushed_p->angles);
420 	if (pusher->client)
421 		pushed_p->deltayaw = pusher->client->ps.pmove.delta_angles[YAW];
422 	pushed_p++;
423 
424 // move the pusher to it's final position
425 	VectorAdd (pusher->s.origin, move, pusher->s.origin);
426 	VectorAdd (pusher->s.angles, amove, pusher->s.angles);
427 	gi.linkentity (pusher);
428 
429 // see if any solid entities are inside the final position
430 	check = g_edicts+1;
431 	for (e = 1; e < globals.num_edicts; e++, check++)
432 	{
433 		if (!check->inuse)
434 			continue;
435 		if (check->movetype == MOVETYPE_PUSH
436 		|| check->movetype == MOVETYPE_STOP
437 		|| check->movetype == MOVETYPE_NONE
438 		|| check->movetype == MOVETYPE_NOCLIP)
439 			continue;
440 
441 		if (!check->area.prev)
442 			continue;		// not linked in anywhere
443 
444 	// if the entity is standing on the pusher, it will definitely be moved
445 		if (check->groundentity != pusher)
446 		{
447 			// see if the ent needs to be tested
448 			if ( check->absmin[0] >= maxs[0]
449 			|| check->absmin[1] >= maxs[1]
450 			|| check->absmin[2] >= maxs[2]
451 			|| check->absmax[0] <= mins[0]
452 			|| check->absmax[1] <= mins[1]
453 			|| check->absmax[2] <= mins[2] )
454 				continue;
455 
456 			// see if the ent's bbox is inside the pusher's final position
457 			if (!SV_TestEntityPosition (check))
458 				continue;
459 		}
460 
461 		if ((pusher->movetype == MOVETYPE_PUSH) || (check->groundentity == pusher))
462 		{
463 			// move this entity
464 			pushed_p->ent = check;
465 			VectorCopy (check->s.origin, pushed_p->origin);
466 			VectorCopy (check->s.angles, pushed_p->angles);
467 			pushed_p++;
468 
469 			// try moving the contacted entity
470 			VectorAdd (check->s.origin, move, check->s.origin);
471 			if (check->client)
472 			{	// FIXME: doesn't rotate monsters?
473 				check->client->ps.pmove.delta_angles[YAW] += amove[YAW];
474 			}
475 
476 			// figure movement due to the pusher's amove
477 			VectorSubtract (check->s.origin, pusher->s.origin, org);
478 			org2[0] = DotProduct (org, forward);
479 			org2[1] = -DotProduct (org, right);
480 			org2[2] = DotProduct (org, up);
481 			VectorSubtract (org2, org, move2);
482 			VectorAdd (check->s.origin, move2, check->s.origin);
483 
484 			// may have pushed them off an edge
485 			if (check->groundentity != pusher)
486 				check->groundentity = NULL;
487 
488 			block = SV_TestEntityPosition (check);
489 			if (!block)
490 			{	// pushed ok
491 				gi.linkentity (check);
492 				// impact?
493 				continue;
494 			}
495 
496 			// if it is ok to leave in the old position, do it
497 			// this is only relevent for riding entities, not pushed
498 			// FIXME: this doesn't acount for rotation
499 			VectorSubtract (check->s.origin, move, check->s.origin);
500 			block = SV_TestEntityPosition (check);
501 			if (!block)
502 			{
503 				pushed_p--;
504 				continue;
505 			}
506 		}
507 
508 		// save off the obstacle so we can call the block function
509 		obstacle = check;
510 
511 		// move back any entities we already moved
512 		// go backwards, so if the same entity was pushed
513 		// twice, it goes back to the original position
514 		for (p=pushed_p-1 ; p>=pushed ; p--)
515 		{
516 			VectorCopy (p->origin, p->ent->s.origin);
517 			VectorCopy (p->angles, p->ent->s.angles);
518 			if (p->ent->client)
519 			{
520 				p->ent->client->ps.pmove.delta_angles[YAW] = p->deltayaw;
521 			}
522 			gi.linkentity (p->ent);
523 		}
524 		return false;
525 	}
526 
527 //FIXME: is there a better way to handle this?
528 	// see if anything we moved has touched a trigger
529 	for (p=pushed_p-1 ; p>=pushed ; p--)
530 		G_TouchTriggers (p->ent);
531 
532 	return true;
533 }
534 
535 /*
536 ================
537 SV_Physics_Pusher
538 
539 Bmodel objects don't interact with each other, but
540 push all box objects
541 ================
542 */
SV_Physics_Pusher(edict_t * ent)543 void SV_Physics_Pusher (edict_t *ent)
544 {
545 	vec3_t		move, amove;
546 	edict_t		*part, *mv;
547 
548 	// if not a team captain, so movement will be handled elsewhere
549 	if ( ent->flags & FL_TEAMSLAVE)
550 		return;
551 
552 	// make sure all team slaves can move before commiting
553 	// any moves or calling any think functions
554 	// if the move is blocked, all moved objects will be backed out
555 //retry:
556 	pushed_p = pushed;
557 	for (part = ent ; part ; part=part->teamchain)
558 	{
559 		if (part->velocity[0] || part->velocity[1] || part->velocity[2] ||
560 			part->avelocity[0] || part->avelocity[1] || part->avelocity[2]
561 			)
562 		{	// object is moving
563 			VectorScale (part->velocity, FRAMETIME, move);
564 			VectorScale (part->avelocity, FRAMETIME, amove);
565 
566 			if (!SV_Push (part, move, amove))
567 				break;	// move was blocked
568 		}
569 	}
570 	if (pushed_p > &pushed[MAX_EDICTS])
571 		gi.error (ERR_FATAL, "pushed_p > &pushed[MAX_EDICTS], memory corrupted");
572 
573 	if (part)
574 	{
575 		// the move failed, bump all nextthink times and back out moves
576 		for (mv = ent ; mv ; mv=mv->teamchain)
577 		{
578 			if (mv->nextthink > 0)
579 				mv->nextthink += FRAMETIME;
580 		}
581 
582 		// if the pusher has a "blocked" function, call it
583 		// otherwise, just stay in place until the obstacle is gone
584 		if (part->blocked)
585 			part->blocked (part, obstacle);
586 #if 0
587 		// if the pushed entity went away and the pusher is still there
588 		if (!obstacle->inuse && part->inuse)
589 			goto retry;
590 #endif
591 	}
592 	else
593 	{
594 		// the move succeeded, so call all think functions
595 		for (part = ent ; part ; part=part->teamchain)
596 		{
597 			SV_RunThink (part);
598 		}
599 	}
600 }
601 
602 //==================================================================
603 
604 /*
605 =============
606 SV_Physics_None
607 
608 Non moving objects can only think
609 =============
610 */
SV_Physics_None(edict_t * ent)611 void SV_Physics_None (edict_t *ent)
612 {
613 // regular thinking
614 	SV_RunThink (ent);
615 }
616 
617 /*
618 =============
619 SV_Physics_Noclip
620 
621 A moving object that doesn't obey physics
622 =============
623 */
SV_Physics_Noclip(edict_t * ent)624 void SV_Physics_Noclip (edict_t *ent)
625 {
626 // regular thinking
627 	if (!SV_RunThink (ent))
628 		return;
629 
630 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
631 	VectorMA (ent->s.origin, FRAMETIME, ent->velocity, ent->s.origin);
632 
633 	gi.linkentity (ent);
634 }
635 
636 /*
637 ==============================================================================
638 
639 TOSS / BOUNCE
640 
641 ==============================================================================
642 */
643 
644 /*
645 =============
646 SV_Physics_Toss
647 
648 Toss, bounce, and fly movement.  When onground, do nothing.
649 =============
650 */
SV_Physics_Toss(edict_t * ent)651 void SV_Physics_Toss (edict_t *ent)
652 {
653 	trace_t		trace;
654 	vec3_t		move;
655 	float		backoff;
656 	edict_t		*slave;
657 	qboolean	wasinwater;
658 	qboolean	isinwater;
659 	vec3_t		old_origin;
660 
661 // regular thinking
662 	SV_RunThink (ent);
663 
664 	// if not a team captain, so movement will be handled elsewhere
665 	if ( ent->flags & FL_TEAMSLAVE)
666 		return;
667 
668 	if (ent->velocity[2] > 0)
669 		ent->groundentity = NULL;
670 
671 // check for the groundentity going away
672 	if (ent->groundentity)
673 		if (!ent->groundentity->inuse)
674 			ent->groundentity = NULL;
675 
676 // if onground, return without moving
677 	if ( ent->groundentity )
678 		return;
679 
680 	VectorCopy (ent->s.origin, old_origin);
681 
682 	SV_CheckVelocity (ent);
683 
684 // add gravity
685 	if (ent->movetype != MOVETYPE_FLY
686 	&& ent->movetype != MOVETYPE_FLYMISSILE
687 	// RAFAEL
688 	// move type for rippergun projectile
689 	&& ent->movetype != MOVETYPE_WALLBOUNCE)
690 		SV_AddGravity (ent);
691 
692 // move angles
693 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
694 
695 // move origin
696 	VectorScale (ent->velocity, FRAMETIME, move);
697 	trace = SV_PushEntity (ent, move);
698 	if (!ent->inuse)
699 		return;
700 
701 	if (trace.fraction < 1)
702 	{
703 		// RAFAEL
704 		if (ent->movetype == MOVETYPE_WALLBOUNCE)
705 			backoff = 2.0;
706 		// RAFAEL ( else )
707 		else if (ent->movetype == MOVETYPE_BOUNCE)
708 			backoff = 1.5;
709 		else
710 			backoff = 1;
711 
712 		ClipVelocity (ent->velocity, trace.plane.normal, ent->velocity, backoff);
713 
714 		// RAFAEL
715 		if (ent->movetype == MOVETYPE_WALLBOUNCE)
716 			vectoangles (ent->velocity, ent->s.angles);
717 
718 	// stop if on ground
719 		// RAFAEL
720 		if (trace.plane.normal[2] > 0.7 && ent->movetype != MOVETYPE_WALLBOUNCE)
721 		{
722 			if (ent->velocity[2] < 60 || ent->movetype != MOVETYPE_BOUNCE )
723 			{
724 				ent->groundentity = trace.ent;
725 				ent->groundentity_linkcount = trace.ent->linkcount;
726 				VectorCopy (vec3_origin, ent->velocity);
727 				VectorCopy (vec3_origin, ent->avelocity);
728 			}
729 		}
730 
731 //		if (ent->touch)
732 //			ent->touch (ent, trace.ent, &trace.plane, trace.surface);
733 	}
734 
735 // check for water transition
736 	wasinwater = (ent->watertype & MASK_WATER);
737 	ent->watertype = gi.pointcontents (ent->s.origin);
738 	isinwater = ent->watertype & MASK_WATER;
739 
740 	if (isinwater)
741 		ent->waterlevel = 1;
742 	else
743 		ent->waterlevel = 0;
744 
745 	if (!wasinwater && isinwater)
746 		gi.positioned_sound (old_origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
747 	else if (wasinwater && !isinwater)
748 		gi.positioned_sound (ent->s.origin, g_edicts, CHAN_AUTO, gi.soundindex("misc/h2ohit1.wav"), 1, 1, 0);
749 
750 // move teamslaves
751 	for (slave = ent->teamchain; slave; slave = slave->teamchain)
752 	{
753 		VectorCopy (ent->s.origin, slave->s.origin);
754 		gi.linkentity (slave);
755 	}
756 }
757 
758 /*
759 ===============================================================================
760 
761 STEPPING MOVEMENT
762 
763 ===============================================================================
764 */
765 
766 /*
767 =============
768 SV_Physics_Step
769 
770 Monsters freefall when they don't have a ground entity, otherwise
771 all movement is done with discrete steps.
772 
773 This is also used for objects that have become still on the ground, but
774 will fall if the floor is pulled out from under them.
775 FIXME: is this true?
776 =============
777 */
778 
779 //FIXME: hacked in for E3 demo
780 #define	sv_stopspeed		100
781 #define sv_friction			6
782 #define sv_waterfriction	1
783 
SV_AddRotationalFriction(edict_t * ent)784 void SV_AddRotationalFriction (edict_t *ent)
785 {
786 	int		n;
787 	float	adjustment;
788 
789 	VectorMA (ent->s.angles, FRAMETIME, ent->avelocity, ent->s.angles);
790 	adjustment = FRAMETIME * sv_stopspeed * sv_friction;
791 	for (n = 0; n < 3; n++)
792 	{
793 		if (ent->avelocity[n] > 0)
794 		{
795 			ent->avelocity[n] -= adjustment;
796 			if (ent->avelocity[n] < 0)
797 				ent->avelocity[n] = 0;
798 		}
799 		else
800 		{
801 			ent->avelocity[n] += adjustment;
802 			if (ent->avelocity[n] > 0)
803 				ent->avelocity[n] = 0;
804 		}
805 	}
806 }
807 
SV_Physics_Step(edict_t * ent)808 void SV_Physics_Step (edict_t *ent)
809 {
810 	qboolean	wasonground;
811 	qboolean	hitsound = false;
812 	float		*vel;
813 	float		speed, newspeed, control;
814 	float		friction;
815 	edict_t		*groundentity;
816 	int			mask;
817 
818 	// airborn monsters should always check for ground
819 	if (!ent->groundentity)
820 		M_CheckGround (ent);
821 
822 	groundentity = ent->groundentity;
823 
824 	SV_CheckVelocity (ent);
825 
826 	if (groundentity)
827 		wasonground = true;
828 	else
829 		wasonground = false;
830 
831 	if (ent->avelocity[0] || ent->avelocity[1] || ent->avelocity[2])
832 		SV_AddRotationalFriction (ent);
833 
834 	// add gravity except:
835 	//   flying monsters
836 	//   swimming monsters who are in the water
837 	if (! wasonground)
838 		if (!(ent->flags & FL_FLY))
839 			if (!((ent->flags & FL_SWIM) && (ent->waterlevel > 2)))
840 			{
841 				if (ent->velocity[2] < sv_gravity->value*-0.1)
842 					hitsound = true;
843 				if (ent->waterlevel == 0)
844 					SV_AddGravity (ent);
845 			}
846 
847 	// friction for flying monsters that have been given vertical velocity
848 	if ((ent->flags & FL_FLY) && (ent->velocity[2] != 0))
849 	{
850 		speed = fabs(ent->velocity[2]);
851 		control = speed < sv_stopspeed ? sv_stopspeed : speed;
852 		friction = sv_friction/3;
853 		newspeed = speed - (FRAMETIME * control * friction);
854 		if (newspeed < 0)
855 			newspeed = 0;
856 		newspeed /= speed;
857 		ent->velocity[2] *= newspeed;
858 	}
859 
860 	// friction for flying monsters that have been given vertical velocity
861 	if ((ent->flags & FL_SWIM) && (ent->velocity[2] != 0))
862 	{
863 		speed = fabs(ent->velocity[2]);
864 		control = speed < sv_stopspeed ? sv_stopspeed : speed;
865 		newspeed = speed - (FRAMETIME * control * sv_waterfriction * ent->waterlevel);
866 		if (newspeed < 0)
867 			newspeed = 0;
868 		newspeed /= speed;
869 		ent->velocity[2] *= newspeed;
870 	}
871 
872 	if (ent->velocity[2] || ent->velocity[1] || ent->velocity[0])
873 	{
874 		// apply friction
875 		// let dead monsters who aren't completely onground slide
876 		if ((wasonground) || (ent->flags & (FL_SWIM|FL_FLY)))
877 			if (!(ent->health <= 0.0 && !M_CheckBottom(ent)))
878 			{
879 				vel = ent->velocity;
880 				speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);
881 				if (speed)
882 				{
883 					friction = sv_friction;
884 
885 					control = speed < sv_stopspeed ? sv_stopspeed : speed;
886 					newspeed = speed - FRAMETIME*control*friction;
887 
888 					if (newspeed < 0)
889 						newspeed = 0;
890 					newspeed /= speed;
891 
892 					vel[0] *= newspeed;
893 					vel[1] *= newspeed;
894 				}
895 			}
896 
897 		if (ent->svflags & SVF_MONSTER)
898 			mask = MASK_MONSTERSOLID;
899 		else
900 			mask = MASK_SOLID;
901 		SV_FlyMove (ent, FRAMETIME, mask);
902 
903 		gi.linkentity (ent);
904 		G_TouchTriggers (ent);
905 		if (!ent->inuse)
906 			return;
907 
908 		if (ent->groundentity)
909 			if (!wasonground)
910 				if (hitsound)
911 					gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
912 	}
913 
914 // regular thinking
915 	SV_RunThink (ent);
916 }
917 
918 //============================================================================
919 /*
920 ================
921 G_RunEntity
922 
923 ================
924 */
G_RunEntity(edict_t * ent)925 void G_RunEntity (edict_t *ent)
926 {
927 	if (ent->prethink)
928 		ent->prethink (ent);
929 
930 	switch ( (int)ent->movetype)
931 	{
932 #ifdef WITH_ACEBOT
933 // ACEBOT_ADD
934 	case MOVETYPE_WALK:
935 		SV_RunThink (ent);
936 		break;
937 // ACEBOT_END
938 #endif
939 	case MOVETYPE_PUSH:
940 	case MOVETYPE_STOP:
941 		SV_Physics_Pusher (ent);
942 		break;
943 	case MOVETYPE_NONE:
944 		SV_Physics_None (ent);
945 		break;
946 	case MOVETYPE_NOCLIP:
947 		SV_Physics_Noclip (ent);
948 		break;
949 	case MOVETYPE_STEP:
950 		SV_Physics_Step (ent);
951 		break;
952 	case MOVETYPE_TOSS:
953 	case MOVETYPE_BOUNCE:
954 	case MOVETYPE_FLY:
955 	case MOVETYPE_FLYMISSILE:
956 	// RAFAEL
957 	case MOVETYPE_WALLBOUNCE:
958 		SV_Physics_Toss (ent);
959 		break;
960 	default:
961 		gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);
962 	}
963 }
964