Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

g_phys.c (21370B)


      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 */
     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 */
     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 */
     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 */
    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 
    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
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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 */
    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 
    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 
    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 */
    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 }