
//============================================================================
//----------------------------------------------------------------------------
//									Enemy.c
//----------------------------------------------------------------------------
//============================================================================

// This file contains all enemy related functions (enemy "AI").  It handlesÉ
// the enemy decision making proccess, moves the enemies, etc.

#include "Externs.h"


#define kEnemyImpulse			8

#define kOwlMaxHVel				96
#define kOwlMaxVVel				320
#define kOwlHeightSmell			96
#define kOwlFlapImpulse			32

#define kWolfMaxHVel			128
#define kWolfMaxVVel			400
#define kWolfHeightSmell		160
#define kWolfFlapImpulse		48

#define kJackalMaxHVel			192
#define kJackalMaxVVel			512
#define kJackalHeightSmell		240
#define kJackalFlapImpulse		72


Boolean SetEnemyInitialLocation (Rect *);
void SetEnemyAttributes (short);
short AssignNewAltitude (void);
void InitEnemy (short, Boolean);
void CheckEnemyPlatformHit (short);
void CheckEnemyRoofCollision (short);
void HandleIdleEnemies (short);
void HandleFlyingEnemies (short);
void HandleWalkingEnemy (short);
void HandleSpawningEnemy (short);
void HandleFallingEnemy (short);
void HandleEggEnemy (short);
void ResolveEnemyPlayerHit (short);


handInfo	theHand;
eyeInfo		theEye;
Rect		grabZone;
short		deadEnemies, spawnedEnemies, numEnemiesThisLevel, numOwls;

extern	playerType	thePlayer;
extern	enemyType	theEnemies[kMaxEnemies];
extern	Rect		platformRects[6], enemyInitRects[5];
extern	long		theScore;
extern	short		numLedges, lightningCount, numEnemies, countDownTimer;
extern	short		levelOn, lightH, lightV;
extern	Boolean		evenFrame, doEnemyFlapSound, doEnemyScrapeSound;


//==============================================================  Functions
//--------------------------------------------------------------  SetEnemyInitialLocation

// When a new enemy is about to be "born", this function is called to determineÉ
// the enemies starting location.  The only thing important here is that the enemyÉ
// appears on a valid platform for the particular level we're on.  As well, whichÉ
// platform he (it) appears on should be random.

Boolean SetEnemyInitialLocation (Rect *theRect)
{
	short		where, possibilities;
	Boolean		facing;
	
	possibilities = numLedges - 1;		// Determine number of valid platforms.
	where = RandomInt(possibilities);	// Choose one at random.
	*theRect = enemyInitRects[where];	// Initially place enemy at default location.
	
	switch (where)						// Determine if enemy facing left or right.
	{									// It depends upon which platform they're on.
		case 0:							// These are the left-most platforms.
		case 2:
		facing = TRUE;					// Enemy will face right.
		break;
		
		case 3:							// Special case for the center platform.
		if (RandomInt(2) == 0)			// Enemy randomly faces either left or right.
			facing = TRUE;
		else
			facing = FALSE;
		break;
		
		default:						// Catch remaining (right-most) platforms.
		facing = FALSE;					// Enemy will face left.
		break;
	}
	
	if ((levelOn % 5) == 4)				// Handle special case for Egg Wave
	{									// Re-define enemy bounds.
		theRect->left += 12 + RandomInt(48) - 24;
		theRect->right = theRect->left + 24;
		theRect->top = theRect->bottom - 24;
	}
	
	return (facing);
}

//--------------------------------------------------------------  SetEnemyAttributes

// Depending upon the type of enemy this function is passed (there are threeÉ
// types of sphinx enemies), this function sets up that enemies variousÉ
// attributes - such as maximum vertical velocity, etc.

void SetEnemyAttributes (short i)
{
	short		h;
											// Point enemy toward center of screen.
	h = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
	if (h < 320)							// If enemy in left half of screenÉ
		theEnemies[i].facingRight = TRUE;	// the enemy will face to the right.
	else									// Otherwise, if in right half of screenÉ
		theEnemies[i].facingRight = FALSE;	// face to the left.
	
	switch (theEnemies[i].kind)				// Okay, depending upon what "kind" of enemyÉ
	{										// we're dealing with....
		case kOwl:							// The owl is the simplest (wimpiest) enemy.
		if (theEnemies[i].facingRight)		// Choose which graphic to use.
			theEnemies[i].srcNum = 0;
		else
			theEnemies[i].srcNum = 2;
											// Set owl's velocity limitations.
		theEnemies[i].maxHVel = kOwlMaxHVel;
		theEnemies[i].maxVVel = kOwlMaxVVel;
											// This is the distance within which he willÉ
											// pursue the player (it's strictly Y distance).
		theEnemies[i].heightSmell = kOwlHeightSmell;
											// This is how powerful the owl's "flap" is.
		theEnemies[i].flapImpulse = kOwlFlapImpulse;
		break;
		
		case kWolf:							// The wolf sphinx is of medium difficulty.
		if (theEnemies[i].facingRight)		// Choose which graphic to use.
			theEnemies[i].srcNum = 4;
		else
			theEnemies[i].srcNum = 6;
											// Set wolf's velocity limitations.
		theEnemies[i].maxHVel = kWolfMaxHVel;
		theEnemies[i].maxVVel = kWolfMaxVVel;
											// This is the distance within which he willÉ
											// pursue the player (it's strictly Y distance).
		theEnemies[i].heightSmell = kWolfHeightSmell;
											// This is how powerful the wolf's "flap" is.
		theEnemies[i].flapImpulse = kWolfFlapImpulse;
		break;
		
		case kJackal:						// The jackal is the swiftest, toughest enemy.
		if (theEnemies[i].facingRight)		// Choose which graphic to use.
			theEnemies[i].srcNum = 8;
		else
			theEnemies[i].srcNum = 10;
											// Set jackal's velocity limitations.
		theEnemies[i].maxHVel = kJackalMaxHVel;
		theEnemies[i].maxVVel = kJackalMaxVVel;
											// This is the distance within which he willÉ
											// pursue the player (it's strictly Y distance).
		theEnemies[i].heightSmell = kJackalHeightSmell;
											// This is how powerful the jackal's "flap" is.
		theEnemies[i].flapImpulse = kJackalFlapImpulse;
		break;
	}
}

//--------------------------------------------------------------  AssignNewAltitude

// The sphinxes "patrol" specific altitudes in the arena.  After wrapping aroundÉ
// the screen a few times, they randomly select a new altitude to patrol (thisÉ
// keeps the player from finding a "safe" place to stand.  This function choosesÉ
// a new altitude for the enemy to patrol.

short AssignNewAltitude (void)
{
	short		which, altitude;
	
	which = RandomInt(4);		// There are only 4 "patrol altitudes".
	switch (which)				// Depending on which random number came upÉ
	{
		case 0:					// This is just below the ceiling.
		altitude = 65 << 4;
		break;
		
		case 1:					// This is below the top platforms but above theÉ
		altitude = 150 << 4;	// center platform.
		break;
		
		case 2:					// This is just below the center platform.
		altitude = 245 << 4;
		break;
		
		case 3:					// This is striahgt across the lava pit.
		altitude = 384 << 4;
		break;
	}
	
	return (altitude);
}

//--------------------------------------------------------------  InitEnemy

// This resets an enemies info.  It is called when a new enemy is to be born.
// It is called if an egg is about to hatch, if a new level has begun, or ifÉ
// if it is simply time to add a new enemy.

void InitEnemy (short i, Boolean reincarnated)
{
	Boolean		facing;
	
	if (spawnedEnemies < numEnemiesThisLevel)	// New enemy to appear (in other wordsÉ
	{											// this enemy is not hatched).
												// Call function to set new location.
		facing = SetEnemyInitialLocation(&theEnemies[i].dest);
		theEnemies[i].wasDest = theEnemies[i].dest;
		theEnemies[i].h = theEnemies[i].dest.left << 4;
		theEnemies[i].v = theEnemies[i].dest.top << 4;
		theEnemies[i].wasH = theEnemies[i].h;	// Reset "old locations" variables.
		theEnemies[i].wasV = theEnemies[i].v;
												// Assign the "patrol altitude".
		theEnemies[i].targetAlt = theEnemies[i].v - (40 << 4);
		theEnemies[i].hVel = 0;					// Zero velocity vraiables.
		theEnemies[i].vVel = 0;
		theEnemies[i].pass = 0;					// Zero number of times wrapped around.
		if ((levelOn % 5) == 4)					// If this is an Egg WaveÉ
			theEnemies[i].mode = kEggTimer;		// set enemy in "wait to hatch" mode.
		else									// Otherwise, just sut enemy inÉ
			theEnemies[i].mode = kIdle;			// idle mode.
		if (i < numOwls)						// Determine what kind of enemy.
			theEnemies[i].kind = kOwl;
		else if (i > (numOwls + 6))	
			theEnemies[i].kind = kJackal;
		else
			theEnemies[i].kind = kWolf;
		theEnemies[i].facingRight = facing;
		SetEnemyAttributes(i);					// Initialize enemy attributes.
		
		if (reincarnated)						// If this is an egg that will hatchÉ
			theEnemies[i].frame = RandomInt(48) + 8 + (numOwls * 32);
		else
			theEnemies[i].frame = RandomInt(48) + 32 + (64 * i) + (numOwls * 32);
		
		if ((levelOn % 5) == 4)					// If this is an Egg Wave
			theEnemies[i].kind--;				// Decrement "kind" (since it's incrementedÉ
												// when they hatch).
		spawnedEnemies++;						// Keep track of number of enemies active.
	}
}

//--------------------------------------------------------------  GenerateEnemies

// This function is called only for a new level.  It goes through andÉ
// intializes a whole host of enemies in one go.

void GenerateEnemies (void)
{
	short		i;
	
	if ((levelOn % 5) == 4)			// If this is an Egg WaveÉ
	{
		numEnemies = kMaxEnemies;	// we insist upon the maximum number of enemies.
		numEnemiesThisLevel = numEnemies;
	}
	else							// If not an egg wave, use a formula to determineÉ
	{								// the max number of enemies that are to be active.
		numEnemies = ((levelOn / 5) + 2) * 2;
		if (numEnemies > kMaxEnemies)
			numEnemies = kMaxEnemies;
		numEnemiesThisLevel = numEnemies * 2;
	}
	
	deadEnemies = 0;				// No dead enemies yet.
	
									// Use formula to determine the number of owlsÉ
									// to appear.  This number goes down as the levelsÉ
									// increase.  It is used not merely to determineÉ
									// how many owls are to appear, but also how manyÉ
									// of the more advanced enemies.  For example, whenÉ
									// numOwls goes down to zero, all the enemies willÉ
									// be of the more advanced breed (wolves and jackals).
	numOwls = 4 - ((levelOn + 2) / 5);
	if (numOwls < 0)
		numOwls = 0;
	
	spawnedEnemies = 0;				// No enemies have been "born" yet.
									// Go through and set up all the enemies.
	for (i = 0; i < numEnemies; i++)
		InitEnemy(i, FALSE);
}

//--------------------------------------------------------------  CheckEnemyPlatformHit

// This is the enemy counterpart to a similarly named function that tests forÉ
// player collsions with the platforms.

void CheckEnemyPlatformHit (short h)
{
	Rect		hRect, vRect, whoCares;
	short		i, offset;
	
	for (i = 0; i < numLedges; i++)					// Test all platforms.
	{												// Do a simple bounds test.
		if (SectRect(&theEnemies[h].dest, &platformRects[i], &whoCares))
		{											// If the enemy has hit the platformÉ
			hRect.left = theEnemies[h].dest.left;	// Determine if enemy hit platform sides.
			hRect.right = theEnemies[h].dest.right;
			hRect.top = theEnemies[h].wasDest.top;
			hRect.bottom = theEnemies[h].wasDest.bottom;
													// Test this new special rect to see ifÉ
													// the enemy hit on of the platform sides.
			if (SectRect(&hRect, &platformRects[i], &whoCares))
			{										// If enemy hit from side, see which side.
													// We handle left and right seperatrelyÉ
													// so that there's no ambiguity as toÉ
													// what the new velocity and locationÉ
													// of the enemy is.  If we did not do itÉ
													// this way, there is the chance that anÉ
													// enemy get's "stuck" on the edge ofÉ
													// a platform (due to round-off errors).
				if (theEnemies[h].h > theEnemies[h].wasH)
				{									// Enemy was moving right (hit left side).
					offset = theEnemies[h].dest.right - platformRects[i].left;
													// Slide enemy "off" platform.
					theEnemies[h].dest.left -= offset;
					theEnemies[h].dest.right -= offset;
					theEnemies[h].h = theEnemies[h].dest.left << 4;
					theEnemies[h].wasH = theEnemies[h].h;
													// Bounce enemy (negate velocity).
					if (theEnemies[h].hVel > 0)
						theEnemies[h].hVel = -(theEnemies[h].hVel >> 1);
					else
						theEnemies[h].hVel = theEnemies[h].hVel >> 1;
				}
				if (theEnemies[h].h < theEnemies[h].wasH)
				{									// Enemy was moving left (hit right side).
					offset = platformRects[i].right - theEnemies[h].dest.left;
													// Slide enemy "off" platform.
					theEnemies[h].dest.left += offset;
					theEnemies[h].dest.right += offset;
					theEnemies[h].h = theEnemies[h].dest.left << 4;
					theEnemies[h].wasH = theEnemies[h].h;
													// Bounce enemy (negate velocity).
					if (theEnemies[h].hVel < 0)
						theEnemies[h].hVel = -(theEnemies[h].hVel >> 1);
					else
						theEnemies[h].hVel = theEnemies[h].hVel >> 1;
				}
				doEnemyScrapeSound = TRUE;			// Play a collision sound.
													// Flip enemy to face opposite direction.
				theEnemies[h].facingRight = !theEnemies[h].facingRight;
			}
			else									// Enemy didn't hit from side.
			{										// See if enemy hit top/bottom.
				vRect.left = theEnemies[h].wasDest.left;
				vRect.right = theEnemies[h].wasDest.right;
				vRect.top = theEnemies[h].dest.top;
				vRect.bottom = theEnemies[h].dest.bottom;
													// Special "test rect" for top/bottom hit.
				if (SectRect(&vRect, &platformRects[i], &whoCares))
				{									// If hit the top/bottom of platformÉ
					if (theEnemies[h].mode == kFalling)
					{								// Was the enemy a falling egg?
													// Bounce egg (with some inelasticity).
						theEnemies[i].hVel -= (theEnemies[i].hVel >> 3);
													// When the eggs velocity is betweenÉ
													// +/- 8, consider the egg at rest.
						if ((theEnemies[i].hVel < 8) && (theEnemies[i].hVel > -8))
						{
							if (theEnemies[i].hVel > 0)
								theEnemies[i].hVel--;
							else if (theEnemies[i].hVel < 0)
								theEnemies[i].hVel++;
						}
					}
													// Specifically, did enemy hit the top?
					if (theEnemies[h].v > theEnemies[h].wasV)
					{								// Enemy heading down (hit platform top).
						offset = theEnemies[h].dest.bottom - platformRects[i].top;
													// Move enemy up off platform.
						theEnemies[h].dest.top -= offset;
						theEnemies[h].dest.bottom -= offset;
						theEnemies[h].v = theEnemies[h].dest.top << 4;
						theEnemies[h].wasV = theEnemies[h].v;
						if (theEnemies[h].vVel > kDontFlapVel)
							doEnemyScrapeSound = TRUE;
													// "Bounce" enemy.
						if (theEnemies[h].vVel > 0)
							theEnemies[h].vVel = -(theEnemies[h].vVel >> 1);
						else
							theEnemies[h].vVel = theEnemies[h].vVel >> 1;
						if ((theEnemies[h].vVel < 8) && (theEnemies[h].vVel > -8) && 
								(theEnemies[h].hVel == 0) && (theEnemies[h].mode == kFalling))
						{						// Here we handle an egg come to rest.
							if (((theEnemies[h].dest.right - 8) > platformRects[i].right) && 
									(theEnemies[h].hVel == 0))
							{					// Special case where egg right on edge.
								theEnemies[h].hVel = 32;
							}
							else if (((theEnemies[h].dest.left + 8) < platformRects[i].left) && 
									(theEnemies[h].hVel == 0))
							{					// Special case where egg right on edge.
								theEnemies[h].hVel = -32;
							}
							else				// If egg not on the edge of platformÉ
							{					// switch to "timer" mode.
								theEnemies[h].mode = kEggTimer;
								theEnemies[h].frame = (numOwls * 96) + 128;
								theEnemies[h].vVel = 0;
							}
						}
					}
					if (theEnemies[h].v < theEnemies[h].wasV)
					{							// Enemy was rising - hit bottom of platform.
						offset = theEnemies[h].dest.top - platformRects[i].bottom;
												// Slide enemy off platform.
						theEnemies[h].dest.top -= offset;
						theEnemies[h].dest.bottom -= offset;
						theEnemies[h].v = theEnemies[h].dest.top << 4;
						theEnemies[h].wasV = theEnemies[h].v;
												// Play collision sound.
						doEnemyScrapeSound = TRUE;
												// "Bounce" enemy downward from platform.
						if (theEnemies[h].vVel < 0)
							theEnemies[h].vVel = -(theEnemies[h].vVel >> 2);
						else
							theEnemies[h].vVel = theEnemies[h].vVel >> 2;
						if ((theEnemies[h].vVel < 8) && (theEnemies[h].vVel > -8) && 
								(theEnemies[h].hVel == 0) && (theEnemies[h].mode == kFalling))
						{
							theEnemies[h].mode = kEggTimer;
							theEnemies[h].frame = (numOwls * 96) + 128;
							theEnemies[h].vVel = 0;
						}
					}
				}
			}
		}
	}
}

//--------------------------------------------------------------  CheckEnemyRoofCollision

// Like the player counterpart, this function checks to see if an enemy has hitÉ
// the ceiling or the lava.  It handles the consequences of both cases.

void CheckEnemyRoofCollision (short i)
{
	short		offset;
	
	if (theEnemies[i].dest.top < (kRoofHeight - 2))
	{					// If enemy has hit the ceilingÉ
		offset = kRoofHeight - theEnemies[i].dest.top;
						// Move enemy down to a "legal" altitude.
		theEnemies[i].dest.top += offset;
		theEnemies[i].dest.bottom += offset;
		theEnemies[i].v = theEnemies[i].dest.top << 4;
						// Play a collision sound.
		doEnemyScrapeSound = TRUE;
						// Bounce enemy downward.
		theEnemies[i].vVel = -(theEnemies[i].vVel >> 2);
	}
	else if (theEnemies[i].dest.top > kLavaHeight)
	{					// If enemy has fallen into lavaÉ
						// kill that enemy.
		theEnemies[i].mode = kDeadAndGone;
		deadEnemies++;
						// Play a splash sound.
		PlayExternalSound(kSplashSound, kSplashPriority);
						// Call up another from the ranks.
		InitEnemy(i, TRUE);
	}
}

//--------------------------------------------------------------  HandleIdleEnemies

// The following functions handle the various enemy modes.  Enemies areÉ
// considered to be in a specific mode and each mode is handled differently.
// Idle enemies are ones who are "invisible" - not yet born.  While idle, aÉ
// timer is ticking down - when it reaches zero, the enemy appears.

void HandleIdleEnemies (short i)
{
	theEnemies[i].frame--;					// Decrement timer.
	if (theEnemies[i].frame <= 0)			// If timer is zero or lessÉ
	{
		theEnemies[i].mode = kSpawning;		// enemy is "born".
		theEnemies[i].wasH = theEnemies[i].h;
		theEnemies[i].wasV = theEnemies[i].v;
		theEnemies[i].hVel = 0;
		theEnemies[i].vVel = 0;
		theEnemies[i].frame = 0;
		SetEnemyAttributes(i);				// Initialize enemy attributes.
		PlayExternalSound(kSpawnSound, kSpawnPriority);
	}
}

//--------------------------------------------------------------  HandleFlyingEnemies

// Once an enemy takes off from a platform, they will always be in flying modeÉ
// unless they should be killed.  This function handles the flying mode.

void HandleFlyingEnemies (short i)
{
	short		dist;
	Boolean		shouldFlap;
								// Take into account gravity pulling enemy down.
	theEnemies[i].vVel += kGravity;
								// Get absolute difference in enemy/player altitude.
	dist = thePlayer.dest.top - theEnemies[i].dest.top;
	if (dist < 0)
		dist = -dist;
								// See if the player is within the enemy's "seek" range.
	if ((dist < theEnemies[i].heightSmell) && 
			((thePlayer.mode == kFlying) || (thePlayer.mode == kWalking)))
	{							// Enemy will actively seek the player.
		if (thePlayer.dest.left < theEnemies[i].dest.left)
		{						// Determine if quicker to go left or right to get player.
			dist = theEnemies[i].dest.left - thePlayer.dest.left;
			if (dist < 320)		// Closest route is to the left.
				theEnemies[i].facingRight = FALSE;
			else				// Closest route is to the right.
				theEnemies[i].facingRight = TRUE;
		}
		else if (thePlayer.dest.left > theEnemies[i].dest.left)
		{						// Determine if quicker to go left or right to get player.
			dist = thePlayer.dest.left - theEnemies[i].dest.left;
			if (dist < 320)		// Closest route is to the right.
				theEnemies[i].facingRight = TRUE;
			else				// Closest route is to the left.
				theEnemies[i].facingRight = FALSE;
		}
								// Seek an altitude 16 pixels above player.
		if (((theEnemies[i].v + 16) > thePlayer.v) && (evenFrame))
			shouldFlap = TRUE;
		else
			shouldFlap = FALSE;
	}
	else						// Else, player not within enemy's "seek" altitude.
	{							// Flap if necessary to maintain "patrol altitude".
		if ((theEnemies[i].v > theEnemies[i].targetAlt) && (evenFrame))
			shouldFlap = TRUE;
		else
			shouldFlap = FALSE;
	}
	
	if (shouldFlap)				// If the enemy has determined that it needs to flapÉ
	{							// Give the enemy lift & play the flap sound.
		theEnemies[i].vVel -= theEnemies[i].flapImpulse;
		doEnemyFlapSound = TRUE;
	}
								// Enemy never hovers - must move right or left.
	if (theEnemies[i].facingRight)
	{							// If enemy facing right - move enemy to the right.
		theEnemies[i].hVel += kEnemyImpulse;
		if (theEnemies[i].hVel > theEnemies[i].maxHVel)
			theEnemies[i].hVel = theEnemies[i].maxHVel;
								// Determine correct graphic for enemy.
		switch (theEnemies[i].kind)
		{
			case kOwl:
			if (shouldFlap)
				theEnemies[i].srcNum = 12;
			else
				theEnemies[i].srcNum = 13;
			break;
			
			case kWolf:
			if (shouldFlap)
				theEnemies[i].srcNum = 16;
			else
				theEnemies[i].srcNum = 17;
			break;
			
			case kJackal:
			if (shouldFlap)
				theEnemies[i].srcNum = 20;
			else
				theEnemies[i].srcNum = 21;
			break;
		}
		
	}
	else						// If enemy not facing right (left) move to the left.
	{
		theEnemies[i].hVel -= kEnemyImpulse;
		if (theEnemies[i].hVel < -theEnemies[i].maxHVel)
			theEnemies[i].hVel = -theEnemies[i].maxHVel;
								// Determine correct graphic for enemy.
		switch (theEnemies[i].kind)
		{
			case kOwl:
			if (shouldFlap)
				theEnemies[i].srcNum = 14;
			else
				theEnemies[i].srcNum = 15;
			break;
			
			case kWolf:
			if (shouldFlap)
				theEnemies[i].srcNum = 18;
			else
				theEnemies[i].srcNum = 19;
			break;
			
			case kJackal:
			if (shouldFlap)
				theEnemies[i].srcNum = 22;
			else
				theEnemies[i].srcNum = 23;
			break;
		}
	}
										// Move enemy horizontally based on hori velocity.
	theEnemies[i].h += theEnemies[i].hVel;
	theEnemies[i].dest.left = theEnemies[i].h >> 4;
	theEnemies[i].dest.right = theEnemies[i].dest.left + 64;
										// Move enemy vertically based on vertical velocity.
	theEnemies[i].v += theEnemies[i].vVel;
	theEnemies[i].dest.top = theEnemies[i].v >> 4;
	theEnemies[i].dest.bottom = theEnemies[i].dest.top + 40;
										// Check for wrap-around.
	if (theEnemies[i].dest.left > 640)
	{									// If off right edge, wrap around to left side.
		OffsetRect(&theEnemies[i].dest, -640, 0);
		theEnemies[i].h = theEnemies[i].dest.left << 4;
		OffsetRect(&theEnemies[i].wasDest, -640, 0);
		theEnemies[i].pass++;			// Increment number of "wrap-arounds" for this enemy.
		if (theEnemies[i].pass > 2)		// After two screen passes (wrap arounds)É
		{								// enemy patrols a new altitude.
			theEnemies[i].targetAlt = AssignNewAltitude();
			theEnemies[i].pass = 0;
		}
	}
	else if (theEnemies[i].dest.right < 0)
	{									// If off left edge, wrap around to right side.
		OffsetRect(&theEnemies[i].dest, 640, 0);
		theEnemies[i].h = theEnemies[i].dest.left << 4;
		OffsetRect(&theEnemies[i].wasDest, 640, 0);
		theEnemies[i].pass++;
		if (theEnemies[i].pass > 2)
		{
			theEnemies[i].targetAlt = AssignNewAltitude();
			theEnemies[i].pass = 0;
		}
	}
										// Throw a touch of friction into the mix.
	theEnemies[i].vVel -= theEnemies[i].vVel >> 4;
										// Keep enemies from moving excessively fast.
	if (theEnemies[i].vVel > theEnemies[i].maxVVel)
		theEnemies[i].vVel = theEnemies[i].maxVVel;
	else if (theEnemies[i].vVel < -theEnemies[i].maxVVel)
		theEnemies[i].vVel = -theEnemies[i].maxVVel;
	
	CheckEnemyRoofCollision(i);			// Check for lava/celing collisions.
	CheckEnemyPlatformHit(i);			// Check for platform collisions.
}

//--------------------------------------------------------------  HandleWalkingEnemy

// This is a brief mode for an enemy.  When an enemy has hatched from an egg, itÉ
// walks only for 8 game frames at which point it takes off and flies for the restÉ
// of its life.

void HandleWalkingEnemy (short i)
{
	if (theEnemies[i].facingRight)		// If enemy facing right, walk to the right.
	{
		theEnemies[i].dest.left += 6;	// Move enemy to right.
		theEnemies[i].dest.right += 6;
		switch (theEnemies[i].kind)		// Determine correct graphic for walking enemy.
		{
			case kOwl:
			theEnemies[i].srcNum = 1 - theEnemies[i].srcNum;
			break;
			
			case kWolf:
			theEnemies[i].srcNum = 9 - theEnemies[i].srcNum;
			break;
			
			case kJackal:
			theEnemies[i].srcNum = 17 - theEnemies[i].srcNum;
			break;
		}
		theEnemies[i].hVel = 6 << 4;
	}
	else								// If enemy not facing right (left), walk to the left.
	{
		theEnemies[i].dest.left -= 6;	// Move enemy to left.
		theEnemies[i].dest.right -= 6;
		switch (theEnemies[i].kind)		// Determine correct graphic for walking enemy.
		{
			case kOwl:
			theEnemies[i].srcNum = 5 - theEnemies[i].srcNum;
			break;
			
			case kWolf:
			theEnemies[i].srcNum = 13 - theEnemies[i].srcNum;
			break;
			
			case kJackal:
			theEnemies[i].srcNum = 21 - theEnemies[i].srcNum;
			break;
		}
		theEnemies[i].hVel = -6 << 4;
	}
	
	theEnemies[i].frame++;				// Increment number of frames it has walked for.
	if (theEnemies[i].frame >= 8)		// If over 8, enemy takes off an flies.
	{
		theEnemies[i].mode = kFlying;	// Switch to flying mode.
		theEnemies[i].frame = 0;		// Reset "frame" variable.
		switch (theEnemies[i].kind)		// Determine correct graphic for flying enemy.
		{
			case kOwl:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 12;
			else
				theEnemies[i].srcNum = 14;
			break;
			
			case kWolf:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 16;
			else
				theEnemies[i].srcNum = 18;
			break;
			
			case kJackal:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 20;
			else
				theEnemies[i].srcNum = 22;
			break;
		}
										// Re-size enemy bounds to a "flying" size.
		theEnemies[i].dest.left -= 8;
		theEnemies[i].dest.right += 8;
		theEnemies[i].dest.bottom = theEnemies[i].dest.top + 40;
		theEnemies[i].h = theEnemies[i].dest.left * 16;
		theEnemies[i].v = theEnemies[i].dest.top * 16;
	}
}

//--------------------------------------------------------------  HandleSpawningEnemy

// This is an enemy "rising out of a platform".  Either an egg has just hatchedÉ
// or a brand new enemy has been introduced.  Irregardless, the sphinx is born.
// When the enemy is at its full height, it will begin to walk.

void HandleSpawningEnemy (short i)
{
	theEnemies[i].frame++;				// Advance timer.
	if (theEnemies[i].frame >= 48)		// If timer >= 48, enemy begins to walk.
	{
		theEnemies[i].mode = kWalking;
		theEnemies[i].frame = 0;
		
		switch (theEnemies[i].kind)		// Determine appropriate graphic.
		{
			case kOwl:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 0;
			else
				theEnemies[i].srcNum = 2;
			break;
			
			case kWolf:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 4;
			else
				theEnemies[i].srcNum = 6;
			break;
			
			case kJackal:
			if (theEnemies[i].facingRight)
				theEnemies[i].srcNum = 8;
			else
				theEnemies[i].srcNum = 10;
			break;
		}
	}
	else							// If not full height, use "timer" to determine height.
		theEnemies[i].dest.top = theEnemies[i].dest.bottom - theEnemies[i].frame;
}

//--------------------------------------------------------------  HandleFallingEnemy

// A "falling" enemy is an air borne egg.  The enemy was killed, turned into an egg, É
// and the egg is in freefall.  If the egg comes to rest, it will begin a countdownÉ
// until it is hatched.

void HandleFallingEnemy (short i)
{									// Take into account gravity - accelerate egg down.
	theEnemies[i].vVel += kGravity;
									// Don't allow velocities to skyrocket.
	if (theEnemies[i].vVel > theEnemies[i].maxVVel)
		theEnemies[i].vVel = theEnemies[i].maxVVel;
	else if (theEnemies[i].vVel < -theEnemies[i].maxVVel)
		theEnemies[i].vVel = -theEnemies[i].maxVVel;
	
	if (evenFrame)					// Apply friction on even frames (who knows).
	{								// "Friction" is 1/32nd of the velocity.
		theEnemies[i].hVel -= (theEnemies[i].hVel >> 5);
		if ((theEnemies[i].hVel < 32) && (theEnemies[i].hVel > -32))
		{
			if (theEnemies[i].hVel > 0)
				theEnemies[i].hVel--;
			else if (theEnemies[i].hVel < 0)
				theEnemies[i].hVel++;
		}
	}
									// Move egg horizontally.
	theEnemies[i].h += theEnemies[i].hVel;
	theEnemies[i].dest.left = theEnemies[i].h >> 4;
	theEnemies[i].dest.right = theEnemies[i].dest.left + 24;
									// Move egg vertically.
	theEnemies[i].v += theEnemies[i].vVel;
	theEnemies[i].dest.top = theEnemies[i].v >> 4;
	theEnemies[i].dest.bottom = theEnemies[i].dest.top + 24;
									// Check for wrap around.
	if (theEnemies[i].dest.left > 640)
	{
		OffsetRect(&theEnemies[i].dest, -640, 0);
		theEnemies[i].h = theEnemies[i].dest.left << 4;
		OffsetRect(&theEnemies[i].wasDest, -640, 0);
	}
	else if (theEnemies[i].dest.right < 0)
	{
		OffsetRect(&theEnemies[i].dest, 640, 0);
		theEnemies[i].h = theEnemies[i].dest.left << 4;
		OffsetRect(&theEnemies[i].wasDest, 640, 0);
	}
	
	CheckEnemyRoofCollision(i);	// See if egg hit ceiling or lava.
	CheckEnemyPlatformHit(i);	// Handle platform hit (it is here it determines ifÉ
								// egg has come to rest and should begin countdown).
}

//--------------------------------------------------------------  HandleEggEnemy

// This is the "idle" egg mode.  This is a static egg, sitting peacefully onÉ
// a platform.  Waiting patiently so it might hatch into a death-sphinx andÉ
// slaughter the player.

void HandleEggEnemy (short i)
{
	short		center;
	
	theEnemies[i].frame--;				// Decrement the egg timer!
	if (theEnemies[i].frame < 24)		// When it falls below 24, egg starts shrinking.
	{									// Use "frame" to determine height of egg.
		theEnemies[i].dest.top = theEnemies[i].dest.bottom - theEnemies[i].frame;
		if (theEnemies[i].frame <= 0)	// When the egg is completely flat (gone)É
		{								// then BOOM! a sphinx is spawned!
			theEnemies[i].frame = 0;
			PlayExternalSound(kSpawnSound, kSpawnPriority);
			center = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
										// Resize enemy bounds to new "walking enemy" size.
			theEnemies[i].dest.left = center - 24;
			theEnemies[i].dest.right = center + 24;
			theEnemies[i].wasDest = theEnemies[i].dest;
			theEnemies[i].h = theEnemies[i].dest.left << 4;
			theEnemies[i].v = theEnemies[i].dest.top << 4;
										// Set up all other enemy variables.
			theEnemies[i].wasH = theEnemies[i].h;
			theEnemies[i].wasV = theEnemies[i].v;
			theEnemies[i].hVel = 0;
			theEnemies[i].vVel = 0;
			theEnemies[i].mode = kSpawning;
			theEnemies[i].kind++;
			if (theEnemies[i].kind > kJackal)
				theEnemies[i].kind = kJackal;
			SetEnemyAttributes(i);
		}
	}
}

//--------------------------------------------------------------  MoveEnemies

// This is the "master" enemy function.  It goes through all the enemiesÉ
// and calls the above functions depending upon an enemy's mode.

void MoveEnemies (void)
{
	short		i;
	
	doEnemyFlapSound = FALSE;		// Intially, assume no flap or scrape sounds.
	doEnemyScrapeSound = FALSE;
									// Go through each enemy.
	for (i = 0; i < numEnemies; i++)
	{
		switch (theEnemies[i].mode)
		{							// Handle enemy according to mode it is in.
			case kIdle:				// Enemy not born yet.
			HandleIdleEnemies(i);
			break;
			
			case kFlying:			// Enemy air borne.
			HandleFlyingEnemies(i);
			break;
			
			case kWalking:			// Enemy just born, walking off platform.
			HandleWalkingEnemy(i);
			break;
			
			case kSpawning:			// Enemy growing from a platform.
			HandleSpawningEnemy(i);
			break;
			
			case kFalling:			// Enemy is an egg in flight.
			HandleFallingEnemy(i);
			break;
			
			case kEggTimer:			// Enemy is a patient, idle, silent egg.
			HandleEggEnemy(i);
			break;
			
			case kDeadAndGone:		// Enemy no more - gone for good this level.
			break;
		}
	}
									// If any sounds were flagged, play them.
	if (doEnemyFlapSound)
		PlayExternalSound(kFlap2Sound, kFlap2Priority);
	if (doEnemyScrapeSound)
		PlayExternalSound(kScrape2Sound, kScrape2Priority);
									// See if enough enemies were killed to advance toÉ
									// next level (wave).
	if ((deadEnemies >= numEnemiesThisLevel) && (countDownTimer == 0))
		countDownTimer = 30;
}

//--------------------------------------------------------------  InitHandLocation

// This simply sets up the hand.  Puts it deep in the lava (off bottom of screen).

void InitHandLocation (void)
{
	SetRect(&theHand.dest, 0, 0, 56, 57);
	OffsetRect(&theHand.dest, 48, 460);
}

//--------------------------------------------------------------  HandleHand

// This is the hand "AI".  The hand, like the sphinx enemies, has modes.

void HandleHand (void)
{
	Rect		whoCares;
	short		hDiff, vDiff, pull, speed;
	
	switch (theHand.mode)
	{
		case kLurking:				// Hand is down, waiting for player to stray near.
		if ((thePlayer.mode == kFlying) && (SectRect(&thePlayer.dest, &grabZone, &whoCares)))
		{							// If player flies near, hand begins to reach out.
			theHand.mode = kOutGrabeth;
			InitHandLocation();
		}
		break;
		
		case kOutGrabeth:			// Hand is either coming after or has a hold of player.
		case kClutching:
		if (SectRect(&thePlayer.dest, &grabZone, &whoCares))
		{							// See if player in the "grab/clutch zone".
			hDiff = theHand.dest.left - thePlayer.dest.left;
			vDiff = theHand.dest.top - thePlayer.dest.top;
									// Ah!  Player caught.  Move player to correctÉ
									// location relative to the hand (so the playerÉ
									// appears to, in fact, be held).
			if (thePlayer.facingRight)
				hDiff -= 3;
			else
				hDiff -= 21;
			vDiff -= 29;
									// How hard/fast the hand moves depends on level.
			speed = (levelOn >> 3) + 1;
			if (hDiff < 0)
			{
				theHand.dest.left += speed;
				theHand.dest.right += speed;
			}
			else if (hDiff > 0)
			{
				theHand.dest.left -= speed;
				theHand.dest.right -= speed;
			}
			if (vDiff < 0)
			{
				theHand.dest.top += speed;
				theHand.dest.bottom += speed;
			}
			else if (vDiff > 0)
			{
				theHand.dest.top -= speed;
				theHand.dest.bottom -= speed;
			}
									// Determine absolute distance player is from hand.
			if (hDiff < 0)
				hDiff = -hDiff;
			if (vDiff < 0)
				vDiff = -vDiff;
			
			if ((hDiff < 8) && (vDiff < 8))
			{						// If player in the "hot zone", player is nabbed!
				theHand.mode = kClutching;
				thePlayer.clutched = TRUE;
									// Player's movement is severely dampened.
				thePlayer.hVel = thePlayer.hVel >> 3;
				thePlayer.vVel = thePlayer.vVel >> 3;
									// Hand pulls player down (strength is greater onÉ
									// higher levels).
				pull = levelOn << 2;
				if (pull > 48)		// Set an absolute limit on hand strength.
					pull = 48;
									// Pull player donw!
				thePlayer.vVel += pull;
				theHand.dest.top = thePlayer.dest.top + 29;
				theHand.dest.bottom = theHand.dest.top + 57;
				if (thePlayer.facingRight)
					theHand.dest.left = thePlayer.dest.left + 3;
				else
					theHand.dest.left = thePlayer.dest.left + 21;
				theHand.dest.right = theHand.dest.left + 58;
			}
			else					// If player not in "sweet spot", hand is seeking.
			{
				thePlayer.clutched = FALSE;
				theHand.mode = kOutGrabeth;
			}
		}
		else						// Player not even close to handÉ
		{							// Hand sinks back down into lava.
			theHand.dest.top++;
			theHand.dest.bottom++;
									// When hand is off screen, hand resumes lurking.
			if (theHand.dest.top > 460)
				theHand.mode = kLurking;
			else
				theHand.mode = kOutGrabeth;
			thePlayer.clutched = FALSE;
		}
		break;
	}
}

//--------------------------------------------------------------  InitEye

// This initializes all the eye's variables.

void InitEye (void)
{
	SetRect(&theEye.dest, 0, 0, 48, 31);
	OffsetRect(&theEye.dest, 296, 97);
	theEye.mode = kWaiting;
	theEye.frame = (numOwls + 2) * 720;
	theEye.srcNum = 0;
	theEye.opening = 1;
	theEye.killed = FALSE;
	theEye.entering = FALSE;
}

//--------------------------------------------------------------  KillOffEye

// This function handles a "slain" eye!

void KillOffEye (void)
{
	if (theEye.mode == kStalking)
	{
		theEye.killed = TRUE;
		theEye.opening = 1;
		theEye.entering = FALSE;
		if (theEye.srcNum == 0)
			theEye.srcNum = 1;
	}
	else
		InitEye();
}

//--------------------------------------------------------------  HandleEye

// But of course, the eye has modes as well.  This function handles the eyeÉ
// depending upon the mode it is in.

void HandleEye (void)
{
	short		diffH, diffV, speed;
	
	if (theEye.mode == kStalking)		// Eye is alive!
	{
		speed = (levelOn >> 4) + 1;		// How fast it moves depends on level.
		if (speed > 3)
			speed = 3;
										// When eye appears or dies, it is stationary.
		if ((theEye.killed) || (theEye.entering))
		{
			speed = 0;
		}
		else if ((thePlayer.mode != kFlying) && (thePlayer.mode != kWalking))
		{
			diffH = theEye.dest.left - 296;
			diffV = theEye.dest.bottom - 128;
		}
		else
		{
			diffH = theEye.dest.left - thePlayer.dest.left;
			diffV = theEye.dest.bottom - thePlayer.dest.bottom;
		}
										// Find direction to player (no wrap-around for eye).
		if (diffH > 0)
		{
			if (diffH < speed)
				theEye.dest.left -= diffH;
			else
				theEye.dest.left -= speed;
			theEye.dest.right = theEye.dest.left + 48;
		}
		else if (diffH < 0)
		{
			if (-diffH < speed)
				theEye.dest.left -= diffH;
			else
				theEye.dest.left += speed;
			theEye.dest.right = theEye.dest.left + 48;
		}
		if (diffV > 0)
		{
			if (diffV < speed)
				theEye.dest.bottom -= diffV;
			else
				theEye.dest.bottom -= speed;
			theEye.dest.top = theEye.dest.bottom - 31;
		}
		else if (diffV < 0)
		{
			if (-diffV < speed)
				theEye.dest.bottom -= diffV;
			else
				theEye.dest.bottom += speed;
			theEye.dest.top = theEye.dest.bottom - 31;
		}
		
		theEye.frame++;					// Increment eye frame (timer).
										// Determine correct graphic for eye.
		if (theEye.srcNum != 0)
		{
			if (theEye.frame > 3)		// "Eye-closing frame" holds for 3 frames.
			{
				theEye.frame = 0;
				theEye.srcNum += theEye.opening;
				if (theEye.srcNum > 3)
				{
					theEye.srcNum = 3;
					theEye.opening = -1;
					if (theEye.killed)
						InitEye();
				}
				else if (theEye.srcNum <= 0)
				{
					theEye.srcNum = 0;
					theEye.opening = 1;
					theEye.frame = 0;
					theEye.entering = FALSE;
				}
			}
		}
		else if (theEye.frame > 256)
		{
			theEye.srcNum = 1;
			theEye.opening = 1;
			theEye.frame = 0;
		}
										// Get absolute distance from eye to player.
		diffH = theEye.dest.left - thePlayer.dest.left;
		diffV = theEye.dest.bottom - thePlayer.dest.bottom;
		if (diffH < 0)
			diffH = -diffH;
		if (diffV < 0)
			diffV = -diffV;
										// See if player close enough to be killed!
		if ((diffH < 16) && (diffV < 16) && (!theEye.entering) && 
				(!theEye.killed))		// Close enough to call it a kill.
		{
			if (theEye.srcNum == 0)		// If eye was open, player is killed.
			{							// Strike lightning (hit the player).
				if (lightningCount == 0)
				{
					lightH = thePlayer.dest.left + 24;
					lightV = thePlayer.dest.bottom - 24;
					lightningCount = 6;	// Strike 6 times!
				}
										// Player is smokin' bones!
				thePlayer.mode = kFalling;
				if (thePlayer.facingRight)
					thePlayer.srcNum = 8;
				else
					thePlayer.srcNum = 9;
				thePlayer.dest.bottom = thePlayer.dest.top + 37;
				PlayExternalSound(kBoom2Sound, kBoom2Priority);
			}
			else						// If the eye was "blinking", IT was killed!
			{							// Player killed the eye!
				if (lightningCount == 0)
				{						// Strike the eye with lightning!
					lightH = theEye.dest.left + 24;
					lightV = theEye.dest.top + 16;
										// Hit 'er with 15 bolts!
					lightningCount = 15;
				}
				theScore += 2000L;		// A big 2000 points for killing the eye!
				UpdateScoreNumbers();	// Refresh score display.
				PlayExternalSound(kBonusSound, kBonusPriority);
				
				KillOffEye();			// Slay eye!
			}							// Hey, anyone remember that giant eye fromÉ
		}								// Johnny Socko and his Flying Robot?
	}									// As a kid, I thought that was cool!
	else if (theEye.frame > 0)			// Eye has not yet appeared, but waits, lurking!
	{
		theEye.frame--;					// Decrement eye timer.
		if (theEye.frame <= 0)			// When timer hits zero, eye appears!
		{
			theEye.mode = kStalking;	// The eye is after the player!
			if (lightningCount == 0)	// Strike lightning at eye!
			{
				lightH = theEye.dest.left + 24;
				lightV = theEye.dest.top + 16;
				lightningCount = 6;
			}
			theEye.srcNum = 3;
			theEye.opening = 1;
			theEye.entering = TRUE;
		}
	}	
}

//--------------------------------------------------------------  ResolveEnemyPlayerHit

// Okay, a bounds test determined that the player and an enemy have collided.
// This function looks at the two and determines who wins or if it's a draw.

void ResolveEnemyPlayerHit (short i)
{
	short		wasVel, diff, h, v;
	
	if ((theEnemies[i].mode == kFalling) || (theEnemies[i].mode == kEggTimer))
	{						// Okay, if the enemy is an eggÉ
		deadEnemies++;		// simple - the enemy dies.
		
		theEnemies[i].mode = kDeadAndGone;
		theScore += 500L;	// Add that to our score!
		UpdateScoreNumbers();
		PlayExternalSound(kBonusSound, kBonusPriority);
		InitEnemy(i, TRUE);	// Reset the enemy (I guess you could say they're reincarnated.
	}
	else					// Now, here's a real, live sphinx enemy.
	{						// Get their difference in altitude.
		diff = (theEnemies[i].dest.top + 25) - (thePlayer.dest.top + 19);
		
		if (diff < -2)		// Player is bested.  :(
		{					// Strike player with lightning.
			if (lightningCount == 0)
			{
				lightH = thePlayer.dest.left + 24;
				lightV = thePlayer.dest.bottom - 24;
				lightningCount = 6;
			}
							// Player is bones.
			thePlayer.mode = kFalling;
			if (thePlayer.facingRight)
				thePlayer.srcNum = 8;
			else
				thePlayer.srcNum = 9;
			thePlayer.dest.bottom = thePlayer.dest.top + 37;
			PlayExternalSound(kBoom2Sound, kBoom2Priority);
		}
		else if (diff > 2)	// Yes!  Enemy is killed!
		{					// Well ... we can't kill an enemy who is spawning.
			if ((theEnemies[i].mode == kSpawning) && (theEnemies[i].frame < 16))
				return;
							// Resize enemy bounds (use an egg bounds).
			h = (theEnemies[i].dest.left + theEnemies[i].dest.right) >> 1;
			if (theEnemies[i].mode == kSpawning)
				v = theEnemies[i].dest.bottom - 2;
			else
				v = (theEnemies[i].dest.top + theEnemies[i].dest.bottom) >> 1;
			theEnemies[i].dest.left = h - 12;
			theEnemies[i].dest.right = h + 12;
			if (theEnemies[i].mode == kSpawning)
				theEnemies[i].dest.top = v - 24;
			else
				theEnemies[i].dest.top = v - 12;
			theEnemies[i].dest.bottom = theEnemies[i].dest.top + 24;
			theEnemies[i].h = theEnemies[i].dest.left << 4;
			theEnemies[i].v = theEnemies[i].dest.top << 4;
							// Enemy is a falling egg!
			theEnemies[i].mode = kFalling;
			theEnemies[i].wasDest = theEnemies[i].dest;
			theEnemies[i].wasH = theEnemies[i].h;
			theEnemies[i].wasV = theEnemies[i].v;
							// Give player points based on enemy kind.
			switch (theEnemies[i].kind)
			{
				case kOwl:
				theScore += 500L;
				break;
				
				case kWolf:
				theScore += 1000L;
				break;
				
				case kJackal:
				theScore += 1500L;
				break;
			}
			UpdateScoreNumbers();
			PlayExternalSound(kBoom2Sound, kBoom2Priority);
		}
		else		// Rare case - neither the player nor the enemy get killed.
		{			// They'll bounce off one another.
			if (theEnemies[i].hVel > 0)
				theEnemies[i].facingRight = TRUE;
			else
				theEnemies[i].facingRight = FALSE;
			PlayExternalSound(kScreechSound, kScreechPriority);
		}
		
		wasVel = thePlayer.hVel;
		thePlayer.hVel = theEnemies[i].hVel;
		theEnemies[i].hVel = wasVel;
		wasVel = thePlayer.vVel;
		thePlayer.vVel = theEnemies[i].vVel;
		theEnemies[i].vVel = wasVel;
	}
}

//--------------------------------------------------------------  CheckPlayerEnemyCollision

// This is a simple "bounds test" for determining player/enemy collisions.

void CheckPlayerEnemyCollision (void)
{
	Rect		whoCares, playTest, wrapTest;
	short		i;
	
	playTest = thePlayer.dest;		// Make a copy of player's bounds.
	InsetRect(&playTest, 8, 8);		// Shrink it by 8 pixels all 'round.
	if (thePlayer.wrapping)			// Need to test 2 players if "wraparounding".
		wrapTest = thePlayer.wrap;
	InsetRect(&wrapTest, 8, 8);
									// Test all enemies.
	for (i = 0; i < numEnemies; i++)
	{								// Ignore non-existant enemies.
		if ((theEnemies[i].mode != kIdle) && (theEnemies[i].mode != kDeadAndGone))
		{							// Simple bounds test.
			if (SectRect(&playTest, &theEnemies[i].dest, &whoCares))
			{						// Call function to determine who wins (or tie).
				ResolveEnemyPlayerHit(i);
			}						// If "wrap-arounding", test other rect.
			else if (thePlayer.wrapping)
			{
				if (SectRect(&wrapTest, &theEnemies[i].dest, &whoCares))
					ResolveEnemyPlayerHit(i);
			}
		}
	}
}

