Quake-2

Quake 2 GPL Source Release
Log | Files | Refs

g_phys.c (21442B)


      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 	if (ent->clipmask)
     55 		mask = ent->clipmask;
     56 	else
     57 		mask = MASK_SOLID;
     58 	trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, ent->s.origin, ent, mask);
     59 	
     60 	if (trace.startsolid)
     61 		return g_edicts;
     62 		
     63 	return NULL;
     64 }
     65 
     66 
     67 /*
     68 ================
     69 SV_CheckVelocity
     70 ================
     71 */
     72 void SV_CheckVelocity (edict_t *ent)
     73 {
     74 	int		i;
     75 
     76 //
     77 // bound velocity
     78 //
     79 	for (i=0 ; i<3 ; i++)
     80 	{
     81 		if (ent->velocity[i] > sv_maxvelocity->value)
     82 			ent->velocity[i] = sv_maxvelocity->value;
     83 		else if (ent->velocity[i] < -sv_maxvelocity->value)
     84 			ent->velocity[i] = -sv_maxvelocity->value;
     85 	}
     86 }
     87 
     88 /*
     89 =============
     90 SV_RunThink
     91 
     92 Runs thinking code for this frame if necessary
     93 =============
     94 */
     95 qboolean SV_RunThink (edict_t *ent)
     96 {
     97 	float	thinktime;
     98 
     99 	thinktime = ent->nextthink;
    100 	if (thinktime <= 0)
    101 		return true;
    102 	if (thinktime > level.time+0.001)
    103 		return true;
    104 	
    105 	ent->nextthink = 0;
    106 	if (!ent->think)
    107 		gi.error ("NULL ent->think");
    108 	ent->think (ent);
    109 
    110 	return false;
    111 }
    112 
    113 /*
    114 ==================
    115 SV_Impact
    116 
    117 Two entities have touched, so run their touch functions
    118 ==================
    119 */
    120 void SV_Impact (edict_t *e1, trace_t *trace)
    121 {
    122 	edict_t		*e2;
    123 //	cplane_t	backplane;
    124 
    125 	e2 = trace->ent;
    126 
    127 	if (e1->touch && e1->solid != SOLID_NOT)
    128 		e1->touch (e1, e2, &trace->plane, trace->surface);
    129 	
    130 	if (e2->touch && e2->solid != SOLID_NOT)
    131 		e2->touch (e2, e1, NULL, NULL);
    132 }
    133 
    134 
    135 /*
    136 ==================
    137 ClipVelocity
    138 
    139 Slide off of the impacting object
    140 returns the blocked flags (1 = floor, 2 = step / wall)
    141 ==================
    142 */
    143 #define	STOP_EPSILON	0.1
    144 
    145 int ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)
    146 {
    147 	float	backoff;
    148 	float	change;
    149 	int		i, blocked;
    150 	
    151 	blocked = 0;
    152 	if (normal[2] > 0)
    153 		blocked |= 1;		// floor
    154 	if (!normal[2])
    155 		blocked |= 2;		// step
    156 	
    157 	backoff = DotProduct (in, normal) * overbounce;
    158 
    159 	for (i=0 ; i<3 ; i++)
    160 	{
    161 		change = normal[i]*backoff;
    162 		out[i] = in[i] - change;
    163 		if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
    164 			out[i] = 0;
    165 	}
    166 
    167 	return blocked;
    168 }
    169 
    170 
    171 /*
    172 ============
    173 SV_FlyMove
    174 
    175 The basic solid body movement clip that slides along multiple planes
    176 Returns the clipflags if the velocity was modified (hit something solid)
    177 1 = floor
    178 2 = wall / step
    179 4 = dead stop
    180 ============
    181 */
    182 #define	MAX_CLIP_PLANES	5
    183 int SV_FlyMove (edict_t *ent, float time, int mask)
    184 {
    185 	edict_t		*hit;
    186 	int			bumpcount, numbumps;
    187 	vec3_t		dir;
    188 	float		d;
    189 	int			numplanes;
    190 	vec3_t		planes[MAX_CLIP_PLANES];
    191 	vec3_t		primal_velocity, original_velocity, new_velocity;
    192 	int			i, j;
    193 	trace_t		trace;
    194 	vec3_t		end;
    195 	float		time_left;
    196 	int			blocked;
    197 	
    198 	numbumps = 4;
    199 	
    200 	blocked = 0;
    201 	VectorCopy (ent->velocity, original_velocity);
    202 	VectorCopy (ent->velocity, primal_velocity);
    203 	numplanes = 0;
    204 	
    205 	time_left = time;
    206 
    207 	ent->groundentity = NULL;
    208 	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
    209 	{
    210 		for (i=0 ; i<3 ; i++)
    211 			end[i] = ent->s.origin[i] + time_left * ent->velocity[i];
    212 
    213 		trace = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, mask);
    214 
    215 		if (trace.allsolid)
    216 		{	// entity is trapped in another solid
    217 			VectorCopy (vec3_origin, ent->velocity);
    218 			return 3;
    219 		}
    220 
    221 		if (trace.fraction > 0)
    222 		{	// actually covered some distance
    223 			VectorCopy (trace.endpos, ent->s.origin);
    224 			VectorCopy (ent->velocity, original_velocity);
    225 			numplanes = 0;
    226 		}
    227 
    228 		if (trace.fraction == 1)
    229 			 break;		// moved the entire distance
    230 
    231 		hit = trace.ent;
    232 
    233 		if (trace.plane.normal[2] > 0.7)
    234 		{
    235 			blocked |= 1;		// floor
    236 			if ( hit->solid == SOLID_BSP)
    237 			{
    238 				ent->groundentity = hit;
    239 				ent->groundentity_linkcount = hit->linkcount;
    240 			}
    241 		}
    242 		if (!trace.plane.normal[2])
    243 		{
    244 			blocked |= 2;		// step
    245 		}
    246 
    247 //
    248 // run the impact function
    249 //
    250 		SV_Impact (ent, &trace);
    251 		if (!ent->inuse)
    252 			break;		// removed by the impact function
    253 
    254 		
    255 		time_left -= time_left * trace.fraction;
    256 		
    257 	// cliped to another plane
    258 		if (numplanes >= MAX_CLIP_PLANES)
    259 		{	// this shouldn't really happen
    260 			VectorCopy (vec3_origin, ent->velocity);
    261 			return 3;
    262 		}
    263 
    264 		VectorCopy (trace.plane.normal, planes[numplanes]);
    265 		numplanes++;
    266 
    267 //
    268 // modify original_velocity so it parallels all of the clip planes
    269 //
    270 		for (i=0 ; i<numplanes ; i++)
    271 		{
    272 			ClipVelocity (original_velocity, planes[i], new_velocity, 1);
    273 
    274 			for (j=0 ; j<numplanes ; j++)
    275 				if ((j != i) && !VectorCompare (planes[i], planes[j]))
    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 		if (!ent->inuse)
    913 			return;
    914 
    915 		if (ent->groundentity)
    916 			if (!wasonground)
    917 				if (hitsound)
    918 					gi.sound (ent, 0, gi.soundindex("world/land.wav"), 1, 1, 0);
    919 	}
    920 
    921 // regular thinking
    922 	SV_RunThink (ent);
    923 }
    924 
    925 //============================================================================
    926 /*
    927 ================
    928 G_RunEntity
    929 
    930 ================
    931 */
    932 void G_RunEntity (edict_t *ent)
    933 {
    934 	if (ent->prethink)
    935 		ent->prethink (ent);
    936 
    937 	switch ( (int)ent->movetype)
    938 	{
    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 		SV_Physics_Toss (ent);
    957 		break;
    958 	default:
    959 		gi.error ("SV_Physics: bad movetype %i", (int)ent->movetype);			
    960 	}
    961 }