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