// Author : Chris Tolley
// Date   : 7/28/2004
// Bug.h contains the class declaration for a bug derived from Object to use
// in the Survival game

#pragma warning ( disable: 4786 )
#pragma warning ( disable: 4305 )

#include <windows.h>
#include <gl/gl.h>
#include <math.h>
#include <vector>
#include <math.h>

using namespace std;

#include "Bug.h"
#include "WaterPool.h"
#include "Plant.h"
#include "logger.h"
#include "SurvivalEngine.h"
#include "viewFrustum.h"
#include "quadTreeTerrain.h"
#include "QuadTree.h"
#include "LeafQuadNode.h"
#include "ParticleSystem.h"

// Declare the static Bug variables
QuadTree*		 Bug::m_qtTree    = NULL;
quadTreeTerrain* Bug::m_qtTerrain = NULL;
SurvivalEngine*	 Bug::m_pEngine	  = NULL;


// Constructor.  x and z are the starting position of this unit
Bug::Bug( float x, float z, const char* ms3dFile, string species ) 
: m_gGenotype( sizeof( PatrolPath ) + sizeof( ThresholdValues ) ), 
  m_fPercent( 0 ), m_bsState( PATROLING ), m_ucHunger( 0 ), 
  m_ucThirst( 0 ), m_ucEnergy( 128 ), m_fAge( 0 ), m_fFertility( 0 ),
  m_ucPatrolPathPos( rand() % PATROL_PATH_LENGTH ), m_uiList( 0 ),
  m_sSpecies( species )
{
	// Copy the memory over from the gene into the actual structs
	memcpy( &m_ppPath, m_gGenotype.at( 0 ), sizeof( m_ppPath ) );

	memcpy( &m_tvThresholds, 
			m_gGenotype.at( sizeof( m_ppPath ) ), 
			sizeof( m_tvThresholds ) );

	// Make sure that the unit is on it's correct position
	int size = m_qtTerrain->GetSize();
	if( x > size ) x = size;
	if( z > size ) z = size;
	if( x < 0 )	   x = 0;
	if( z < 0 )	   z = 0;

	// Move the unit to it's initial position
	m_mLocal.Translate( x, m_qtTerrain->GetHeightAt( x, z ), z );

	// Load the ms3f file
	ms3d myModel( ms3dFile );

	// Create a new display list
	m_uiList = glGenLists( 1 );

	// Make sure that the list is a valid list
	if( m_uiList == 0 )
	{
		logger::event( "Bug::Initialize", "Error in creating display list.", 0 );
		return;
	}// End if

	// Put the commands into the list to draw the model
	glNewList( m_uiList, GL_COMPILE );
		glMatrixMode( GL_TEXTURE );
		glPushMatrix();
		glRotatef( 180, 1, 0, 0 );
		myModel.DrawTexturedMesh();
		glPopMatrix();
		glMatrixMode( GL_MODELVIEW );
	glEndList();
}// End Bug::Constructor


// Bug Constructor to use when a bug is giving birth
Bug::Bug( const Bug& rhs ) : m_gGenotype( rhs.m_gGenotype.Polymerize() ),
  m_fPercent( 0 ), m_bsState( PATROLING ), m_ucHunger( 0 ),
  m_ucThirst( 0 ), m_ucEnergy( 128 ), m_fAge( 0 ), m_fFertility( 0 ),
  m_ucPatrolPathPos( rand() % PATROL_PATH_LENGTH ), m_uiList( rhs.m_uiList ),
  m_sSpecies( rhs.m_sSpecies )
{
	// Set this bug to the position of it's parent
	m_mLocal = rhs.m_mLocal;

	// Copy the memory over from the gene into the actual structs
	memcpy( &m_ppPath, m_gGenotype.at( 0 ), sizeof( m_ppPath ) );

	memcpy( &m_tvThresholds, 
			m_gGenotype.at( sizeof( m_ppPath ) ), 
			sizeof( m_tvThresholds ) );
}// End Bug::Copy Constructor


// A bug constructor for the bug cam to use
Bug::Bug( string species, Gene& genotype, matrix& local, unsigned int list )
: m_bsState( PATROLING ), m_fAge( 0 ), m_fFertility( 0 ), m_fPercent( 0 ),
  m_gGenotype( genotype ), m_sSpecies( species ), m_ucEnergy( 128 ),
  m_ucHunger( 0 ), m_ucPatrolPathPos( rand() % PATROL_PATH_LENGTH ),
  m_ucThirst( 0 ), m_uiList( list )
{
	// Copy the memory over from the gene into the actual structs
	memcpy( &m_ppPath, genotype.at( 0 ), sizeof( m_ppPath ) );

	memcpy( &m_tvThresholds, genotype.at( sizeof( m_ppPath ) ),
			sizeof( m_tvThresholds ) );

	// Set this bug's local coordinate system to local
	m_mLocal = local;
}// End Bug::Constructor


// Another Bug constructor
Bug::Bug( string species, Gene& genotype, const char* ms3dFile, 
		  float x, float z )
: m_bsState( PATROLING ), m_fAge( 0 ), m_fFertility( 0 ), m_fPercent( 0 ),
  m_gGenotype( genotype ), m_sSpecies( species ), m_ucEnergy( 128 ),
  m_ucHunger( 0 ), m_ucPatrolPathPos( rand() % PATROL_PATH_LENGTH ),
  m_ucThirst( 0 ), m_uiList( 0 )
{
	// Copy the memory over from the gene into the actual structs
	memcpy( &m_ppPath, genotype.at( 0 ), sizeof( m_ppPath ) );

	memcpy( &m_tvThresholds, genotype.at( sizeof( m_ppPath ) ),
			sizeof( m_tvThresholds ) );

	// Make sure that the unit is on it's correct position
	int size = m_qtTerrain->GetSize();
	if( x > size ) x = size;
	if( z > size ) z = size;
	if( x < 0 )	   x = 0;
	if( z < 0 )	   z = 0;

	// Move the unit to it's initial position
	m_mLocal.Translate( x, m_qtTerrain->GetHeightAt( x, z ), z );

	// Load the ms3f file
	ms3d myModel( ms3dFile );

	// Create a new display list
	m_uiList = glGenLists( 1 );

	// Make sure that the list is a valid list
	if( m_uiList == 0 )
	{
		logger::event( "Bug::Initialize", "Error in creating display list.", 0 );
		return;
	}// End if

	// Put the commands into the list to draw the model
	glNewList( m_uiList, GL_COMPILE );
		glMatrixMode( GL_TEXTURE );
		glPushMatrix();
		glRotatef( 180, 1, 0, 0 );
		myModel.DrawTexturedMesh();
		glPopMatrix();
		glMatrixMode( GL_MODELVIEW );
	glEndList();
}// End Bug::Constructor


// Destructor
Bug::~Bug()
{
}// End Bug::Destructor


// Updates the object.  Must be implemented at a derived level
void Bug::Update( float elapsedSec )
{
	// Add the amount of time that has elapsed since the last update
	// to the percent
	m_fPercent += elapsedSec;

	// Add to the age of this bug
	m_fAge += elapsedSec;

	// Add the seconds to the fertility value
	m_fFertility += elapsedSec;

	// Declare some variables here cause you can't do it in a switch
	float mx = 0;
	float my = 0;
	float mz = 0;
	char rotationDir = 0;
	float distance = 0;
	float angle = 0;
	int size = 0;

	// A case switch to control the states of the bug
	switch( m_bsState )
	{
	case RESTING:
		// If a second has passed
		if( m_fPercent >= 1 )
		{
			// Reduce the percentage
			m_fPercent -= 1;

			// Adjust this bug's stats
			AdjustStats();

			// Check for a state change
			CheckState();
		}// End if
		break;
	case EATING:
//		logger::event( "Bug::Update", "Eating", 0 );

		// If the target is no longer valid
		if( ! m_spTarget.isValid() )
		{
			// Check for a state change
			CheckState();
		}// End if
		else
		{
			// If we are at the target and a second has passed
			if( MoveTowardTarget( elapsedSec ) && m_fPercent >= 1 )
			{
				// Reset the percent
				m_fPercent = 0;
				
				// Adjust the stats of this bug
				AdjustStats();

				// Check the state
				CheckState();
			}// End if
		}// End else
		break;
	case DRINKING:
//		logger::event( "Bug::Update", "Drinking", 0 );
		// If the target is no longer valid or if it is empty
		if( ! m_spTarget.isValid() || 
			! reinterpret_cast< WaterPool* >( m_spTarget.Get() )
													->HasWater() )
		{
			// Check for a state change
			CheckState();
		}// End if
		else
		{
			// If we are at the target and a second has passed
			if( MoveTowardTarget( elapsedSec ) && m_fPercent >= 1 )
			{
				// Reset the percent
				m_fPercent = 0;

				// Adjust the stats of this bug
				AdjustStats();

				// Check the state
				CheckState();
			}// End if
		}// End else
		break;
	case FIGHTING:
//		logger::event( "Bug::Update", "Fighting", 0 );
		// If the target is no longer valid
		if( ! m_spTarget.isValid() )
		{
			// Preform a state check
			CheckState();
		}// End if
		else
		{
			// If we are facing the target
			if( MoveTowardTarget( elapsedSec ) )
			{
				// Calculate the number of particles to add to the system
				int numParts = 0;
				if( elapsedSec > 0 )
					numParts = 3;

				// Get the position of this bug
				float mx, my, mz;
				GetPos( mx, my, mz );

				// Get the position of the target
				float tx, ty, tz;
				reinterpret_cast< Bug* >( m_spTarget.Get() )
											->GetPos( tx, ty, tz );

				// Calculate the slope of the line towards the target
				float sx = tx - mx;
				float sy = ty - my;
				float sz = tz - mz;

				// Create and add numParts particles
				for( int n = 0; n < numParts; ++n )
				{
					Particle temp;
					temp.Color_[0] = 0;
					temp.Color_[1] = 1;
					temp.Color_[2] = 0;

					temp.Position_[0] =  ( float( rand() % 100 ) / 1000 ) - .05;
					temp.Position_[1] = .2;
					temp.Position_[2] =  -1;
					m_mLocal.Transform( temp.Position_ );

					temp.Direction_[0] = ( sx / ATTACK_RANGE ) + 
										float( rand() % 100 ) / 1000;
					temp.Direction_[1] = ( sy / ATTACK_RANGE ) +
										float( rand() % 100 ) / 1000;
					temp.Direction_[2] = ( sz / ATTACK_RANGE ) +
										float( rand() % 100 ) / 1000;

					temp.Age_ = 0;
					temp.MaxAge_ = MAX_PART_AGE;

					m_pEngine->AddParticle( temp );
				}// End for n

				// If a second has passed since we started the attack
				if( m_fPercent >= 1 )
				{
					// Reset percent
					m_fPercent = 0;

					// Adjust the stats of this bug
					AdjustStats();
				}// End if
			}// End if
			else
			{
				// This keeps the bugs from chasing a target all around the map
				if( m_fPercent >= 1 )
				{
					m_fPercent = 0;
					CheckState();
				}// End if
			}// End else
		}// End else
		break;
	case PATROLING:
//		logger::event( "Bug::Update", "Patroling", 0 );
		// Calculate the direction of rotation
		// -1 = to the left, 0 = no rotation, 1 = to the right
		rotationDir = ( ( m_ppPath.Path_[m_ucPatrolPathPos] * 3 ) / 255 ) - 1;

		// Calculate the distance of movement and rotation this bug has
		// covered since the last update
		distance = ( elapsedSec * MOVEMENT_UNIT ) / TIME_UNIT;
		angle = ( ( elapsedSec * ROTATION_UNIT ) / TIME_UNIT ) * rotationDir;

		// Rotate the unit by angle
		m_mLocal.Rotate( 0, angle, 0 );

		// Translate the unit
		m_mLocal.Translate( 0, 0, distance );

		// Make sure the unit is still on the map and move it up to the
		// proper height;
		size = m_qtTerrain->GetSize();

		// Make sure that this bug is still on the terrain
		if( m_mLocal[12] > size ) m_mLocal[12] = size;
		if( m_mLocal[14] > size ) m_mLocal[14] = size;
		if( m_mLocal[12] < 0 )	  m_mLocal[12] = 0;
		if( m_mLocal[14] < 0 )	  m_mLocal[14] = 0;

		// Set up the height value for this bug
		m_mLocal[13] = 
			m_qtTerrain->GetHeightAt( m_mLocal[12], m_mLocal[14] );

		// If m_fPercent is >= 1
		if( m_fPercent >= 1 )
		{
			// Reduce the percentage
			m_fPercent = 0;

			// Move to the next position on the patrol path
			m_ucPatrolPathPos += 1;

			// Make sure m_ucPatrolPathPos is still in range;
			if( m_ucPatrolPathPos >= PATROL_PATH_LENGTH )
				m_ucPatrolPathPos = 0;

			// Update thirst, hunger, and energy and make sure they are 
			// in range
			AdjustStats();

			// Call check state to see if we need to change states now
			CheckState();
		}// End if
		break;
	case REPRODUCING:
//		logger::event( "Bug::Update", "Producing", 0 );
		// Check to see if enough time has passed 
		if( m_fPercent >= GESTATION_TIME )
		{
			// Reset percent
			m_fPercent = 0;

			m_fFertility = 0;

			// Create a new bug
			m_pEngine->CreateBug( this );

			// Set a new state
			CheckState();
		}// End if
		break;
	default:
		break;
	};// End switch( m_bsState )
}// End Bug::Update


// Renders the object to the screen. Must be implemented at a derived level
void Bug::Render()
{
	// Get the position of this bug
	float mx, my, mz;
	GetPos( mx, my, mz );

	// If this bug is in the view frustum we should draw it.
	if( viewFrustum::sphereInFrustum( mx, my, mz, mx + BUG_RADIUS, my, mz ) )
	{
		// Set up the local matrix system
		glPushMatrix();
		glMultMatrixf( m_mLocal.get() );

		// Call the display list containing the commands to draw the bug model
		glCallList( m_uiList );

		// Disable lighting
		glDisable( GL_LIGHTING );

		// Draw a point above this bug to indicate the state
		glPointSize( 5 );
		glBegin( GL_POINTS );
		switch( m_bsState )
		{
		case RESTING:
			// Gray for resting
			glColor3f( .5, .5, .5 );
			break;
		case REPRODUCING:
			// Green for reproducing
			glColor3f( 0, 1, 0 );
			break;
		case EATING:
			// Red for eating
			glColor3f( 1, 0, 0 );
			break;
		case DRINKING:
			// Blue for drinking
			glColor3f( 0, 0, 1 );
			break;
		case PATROLING:
			// White for patroling
			glColor3f( 1, 1, 1 );
			break;
		case FIGHTING:
			// Yellow for fighting
			glColor3f( 1, 1, 0 );
			break;
		default:
			break;
		}// End 
		// Reset the color and point size, and end points
		// Draw a point
		glVertex3f( 0, 3, 0 );
		glColor3f( 1, 1, 1 );
		glEnd();
		glPointSize( 1 );

		// Renable lighting
		glEnable( GL_LIGHTING );
		
		// Reset the matrix stack
		glPopMatrix();
	}// End if
}// End Bug::Render


// Returns true if this Object is inside the sphere
bool Bug::InSphere( float x, float z, float radius )
{
	// Get the center point of this Bug
	float bx, by, bz;
	GetPos( bx, by, bz );

	// Calculate the distance between this bug and point x,z
	float distance = sqrt( ( ( x - bx ) * ( x - bx ) ) +
						   ( ( z - bz ) * ( z - bz ) ) );

	// If the distance between this bug and x,z is less than radius
	// plus this of this bug, then it is in the sphere
	return distance <= ( radius +  BUG_RADIUS );
}// End Bug::InSphere


// Overloaded from object. Returns true if it is time to remove this object
bool Bug::TimeToDie()
{
	return m_fAge >= BUG_LIFETIME;
}// End Bug::TimeToDie


// Checks to see if we need to change states and to what state
void Bug::CheckState()
{
	// Create a place to store all the objects in site 
	vector< SmartPointer > objects;

	// Get the position on this bug
	float mx, my, mz;
	GetPos( mx, my, mz );

	// Some variables to hold the closest Plants, WaterPools and their distance
	SmartPointer closestFood, closestWater, closestEnemy;
	float enemyDist = SITE_RADIUS + 1;
	float waterDist = SITE_RADIUS + 1;
	float foodDist  = SITE_RADIUS + 1;
	float distToCur = SITE_RADIUS + 1;
	float tx = 0; float ty = 0; float tz = 0;

	// Get all objects within site of this bug
	m_qtTree->GetObjects( objects, SITE_RADIUS, mx, mz );

	// Loop through each object and calculate some value based on that info
	vector< SmartPointer >::iterator obj = objects.begin();
	for( obj; obj != objects.end(); ++obj )
	{
		// If obj is a WaterPool
		if( (*obj)->GetType() == "waterpool" )
		{
			// If there is water in that water pool
			if( reinterpret_cast< WaterPool* >( obj->Get() )->HasWater() )
			{
				// Get the position of obj
				(*obj)->GetPos( tx, ty, tz );

				// Calculate the distance between this and obj
				distToCur = sqrt( ( mx - tx ) * ( mx - tx ) +
								  ( mz - tz ) * ( mz - tz ) );

				// If this WaterPool is closer than the current closest
				if( distToCur < waterDist )
				{
					// Set obj to the closest WaterPool
					waterDist = distToCur;
					closestWater = (*obj);
				}// End if
			}// End if
		}// End if

		// If obj is a plant
		if( (*obj)->GetType() == "plant" )
		{
			// Get the position of obj
			(*obj)->GetPos( tx, ty, tz );

			// Calculate the distance between this and obj
			distToCur = sqrt( ( mx - tx ) * ( mx - tx ) +
							  ( mz - tz ) * ( mz - tz ) );

			// If this Plant if closer than the current closest
			if( distToCur < foodDist )
			{
				// Set obj as the closest Plant
				foodDist = distToCur;
				closestFood = (*obj);
			}// End if
		}// End if

		// If obj is a bug
		if( (*obj)->GetType() == "bug" &&
		   reinterpret_cast< Bug* >( obj->Get() )->GetSpecies() != m_sSpecies )
		{
			// Get the position of obj
			(*obj)->GetPos( tx, ty, tz );

			// Calculate the distance between this and obj
			distToCur = sqrt( ( mx - tx ) * ( mx - tx ) +
							  ( mz - tz ) * ( mz - tz ) );

			// If this Plant if closer than the current closest
			if( distToCur < enemyDist )
			{
				// Set obj as the closest Plant
				enemyDist = distToCur;
				closestEnemy = (*obj);
			}// End if
		}// End if
	}// End for obj

	// If there is an enemy in site
	if( closestEnemy.isValid() )
	{
		// Calculate the threat value
		float Threat = ( ( m_ucEnergy * 255 ) / ENERGY_MAX ) * .3 +
					   ( (  enemyDist * 255 ) / SITE_RADIUS ) * .7;

		// If the threat value is greater than or equal to the threshold's
		// threat value
		if( Threat >= m_tvThresholds.Fight_ )
		{
			// Enter into the fighting state
			m_bsState = FIGHTING;
			m_spTarget = closestEnemy;
			return;
		}// End if
	}// End if

	// If there is a food source in site
	if( closestFood.isValid() && m_ucHunger > 0 )
	{
		// Calculate the food value
		int Food = ( ( SITE_RADIUS - foodDist ) * 255 ) / SITE_RADIUS;

		// If the calculated need for food is greater than or equal to the
		// threshold for eating
		if( ( m_ucHunger * .7 ) + ( Food * .3 ) >= m_tvThresholds.Eat_ )
		{
			// Enter into the eating state
			m_bsState = EATING;
			m_spTarget = closestFood;
			return;
		}// End if
	}// End if

	// If there is a water source in site
	if( closestWater.isValid() && m_ucThirst > 0 )
	{
		// Calculate the water value
		int Water = ( ( SITE_RADIUS - waterDist ) * 255 ) / SITE_RADIUS;

		// If the calculated need for water is greater than or equal to the
		// threshold value for Drinking
		if( ( m_ucThirst * .7 ) + ( Water * .3 ) )
		{
			// Enter into the drinking state
			m_bsState = DRINKING;
			m_spTarget = closestWater;
			return;
		}// End if
	}// End if

	// If this bug has enough energy to reproduce
	if( m_ucEnergy >= GESTATION_COST && 
		m_fFertility >= m_pEngine->GetFertilityRate() )
	{
		// If the calculated need to reproduce is greater than or equal to
		// the threshold value
		if( ( ( m_ucEnergy - GESTATION_COST ) * 255 ) / 
									( ENERGY_MAX - GESTATION_COST ) >=
				m_tvThresholds.Reproduce_ )
		{
			// Enter into the reproducing state
			m_bsState = REPRODUCING;
			// Subtract the gestation cost
			m_ucEnergy -= GESTATION_COST;
			return;
		}// End if
	}// End if

	// If the amount of energy this bug doesn't have is >= the threshold value
	// for resting and the bug is not fully rested
	if( ( ( ENERGY_MAX - m_ucEnergy ) >= m_tvThresholds.Rest_ ) && 
		( m_ucEnergy < ENERGY_MAX ) )
	{
		// Enter into the resting state
		m_bsState = RESTING;
		return;
	}// End if

	// Enter into the default state of patroling if we have gotten this far
	m_bsState = PATROLING;
}// End Bug::CheckState


// Causes this bug to move towarded m_spTarget
bool Bug::MoveTowardTarget( float elapsedSec )
{
	// Check to see if target is valid
	if( ! m_spTarget.isValid() )
	{
		return false;
	}// End if

	// Get the position of this bug
	float mx, my, mz;
	GetPos( mx, my, mz );

	// If this bug is already at the target
	if( m_spTarget->InSphere( mx, mz, BUG_RADIUS ) )
	{
		return true;
	}// End if

	// Get the position of the target
	float tx, ty, tz;
	m_spTarget->GetPos( tx, ty, tz );

	// Calculate the distance between this and target
	float dist = sqrt( ( ( mx - tx ) * ( mx - tx ) ) +
					   ( ( mz - tz ) * ( mz - tz ) ) );

	// Create a point directly in front of this bug dist away
	float nx = 0; float ny = 0; float nz = -dist;
	m_mLocal.Transform( nx, ny, nz );

	// Calculate the mid point on line t,n
	float midX = ( nx + tx ) / 2;
	float midZ = ( nz + tz ) / 2;

	// Using points t, n, and m as an isoceles triangle, create two right
	// triangles, using midx, midz, and calculate the the angle of mid, m, n
	// and multiple that times two to get the angle that this unit needs to
	// turn  to face it's target
	float angle = atan( 
				  sqrt( ( ( midX - nx ) * ( midX - nx ) ) + 
					    ( ( midZ - nz ) * ( midZ - nz ) ) ) /
				  sqrt( ( ( midX - mx ) * ( midX - mx ) ) +
					    ( ( midZ - mz ) * ( midZ - mz ) ) ) );

	// Convert angle from radians to degrees and multiple it by 2
	angle = angle * ( 180 / PI );
	angle *= 2;

	// A special case for fighting
	if( m_bsState == FIGHTING )
	{
		// If the angle between this bug and the target is 2 or less
		// and the other bug is within attack range
		if( angle <= 2 && dist <= ATTACK_RANGE )
		{
			// Return true cause we can attack now
			return true;
		}// End if
	}// End if

	// The direction of rotation
	int rotationDir = 1;

	// If this bug is not roughly facing it's target
	if( angle >= 2 )
	{
		// If angle is roughly 180, then the target is almost directly behind the
		// bug and we can turn in any direction
		if( angle <= 178 )
		{
			// Figure out which way is closer to turn toward the target
			// Positive x is right
			// Negative x is left

			// Create a point to the left of this bug dist away
			float lx = -dist; float ly = 0; float lz = 0;
			m_mLocal.Transform( lx, ly, lz );

			// Calculate the mid point of line l,t
			midX = ( lx + tx ) / 2;
			midZ = ( lz + tz ) / 2;

			// Calculate the angle between the left of the bug and the target
			float lAngle = atan( 
				  sqrt( ( ( midX - lx ) * ( midX - lx ) ) + 
					    ( ( midZ - lz ) * ( midZ - lz ) ) ) /
				  sqrt( ( ( midX - mx ) * ( midX - mx ) ) +
					    ( ( midZ - mz ) * ( midZ - mz ) ) ) );

			// Convert the angle from radians to degrees and multiple by two
			lAngle = lAngle * ( 180 / PI );
			lAngle *= 2;

			// Create a point to the right of this bug dist away
			float rx = dist; float ry = 0; float rz = 0;
			m_mLocal.Transform( rx, ry, rz );

			// Calculate the mid point of line l,t
			midX = ( rx + tx ) / 2;
			midZ = ( rz + tz ) / 2;

			// Calculate the angle between the left of the bug and the target
			float rAngle = atan( 
				  sqrt( ( ( midX - rx ) * ( midX - rx ) ) + 
					    ( ( midZ - rz ) * ( midZ - rz ) ) ) /
				  sqrt( ( ( midX - mx ) * ( midX - mx ) ) +
					    ( ( midZ - mz ) * ( midZ - mz ) ) ) );

			// Convert the angle from radians to degrees and multiple by two
			rAngle = rAngle * ( 180 / PI );
			rAngle *= 2;

			// If the angle to the right is greater than the angle to the left
			if( lAngle > rAngle )
			{
				// Set the rotational direction to the other direction
				rotationDir = -1;
			}// End if
		}// End if

		// Now we preform the rotation
		m_mLocal.Rotate( 0, 
			( ( elapsedSec * ROTATION_UNIT ) / TIME_UNIT ) * rotationDir, 0 );
	}// End if
	else
	{
		// Otherwise we can move toward the target
		m_mLocal.Translate( 0, 0, ( elapsedSec * MOVEMENT_UNIT ) / TIME_UNIT );

		// Get the size of the terrain 
		int size = m_qtTerrain->GetSize();

		// Make sure that this bug is still on the terrain
		if( m_mLocal[12] > size ) m_mLocal[12] = size;
		if( m_mLocal[14] > size ) m_mLocal[14] = size;
		if( m_mLocal[12] < 0 )	  m_mLocal[12] = 0;
		if( m_mLocal[14] < 0 )	  m_mLocal[14] = 0;

		// Set up the height value for this bug
		m_mLocal[13] = 
			m_qtTerrain->GetHeightAt( m_mLocal[12], m_mLocal[14] );
	}// End else

	// Return false
	return false;
}// End Bug::MoveTowardTarget


// Adjusts the energy, hunger, and thirst of the bug
void Bug::AdjustStats()
{
	// Declara some variable cause we can't do it inside a switch
	unsigned water = 0;
	unsigned food  = 0;

	// A case switch to control the states of the bug
	switch( m_bsState )
	{
	case RESTING:
//		logger::event( "Bug::AdjustStats", "Resting", 0 );
		// Add the amount of energy to this bug's energy level that
		// it can gain per second and make sure it doesn't go over the max
		if( m_ucEnergy >= ( ENERGY_MAX - ENERGY_UNIT ) )
			m_ucEnergy = ENERGY_MAX;
		else
			m_ucEnergy += ENERGY_UNIT;
		break;
	case EATING:
//		logger::event( "Bug::AdjustStats", "Eating", 0 );
		if( m_ucHunger != 0 )
		{
			food = reinterpret_cast< Plant* >( m_spTarget.Get() )
				   ->GetFoodUnits();

			// Deincrement hunger and make sure it is still in range
			if( m_ucHunger >= food )
				m_ucHunger -= food;
			else
				m_ucHunger = 0;
			
			// Take some energy away from this unit
			if( m_ucEnergy != 0 )
				m_ucEnergy -= 1;

			// Increase the fertility rate
			m_fFertility += 3;
		}// End if
		break;
	case DRINKING:
//		logger::event( "Bug::AdjustStats", "Drinking", 0 );
		if( m_ucThirst != 0 )
		{
			water = reinterpret_cast< WaterPool* >( m_spTarget.Get() )
					->GetWaterUnits();

			// Deincrement thrist and make sure it is still in range
			if( m_ucThirst >= water )
				m_ucThirst -= water;
			else
				m_ucThirst = 0;

			// Take some energy away from this unit
			if( m_ucEnergy != 0 )
				m_ucEnergy -= 1;

			// Increase the fertility of this bug
			m_fFertility += 3;
		}// End if
		break;
	case FIGHTING:
//		logger::event( "Bug::AdjustStats", "Fighting", 0 );
		// Take some energy away from this unit
		if( m_ucEnergy > 0 )
			m_ucEnergy -= 1;
		else
			m_fAge += 1;

		// Do some damage to the other bug
		reinterpret_cast< Bug* >( m_spTarget.Get() )->
									DoDamage( ATTACK_DAMAGE );

		// If we killed our target
		if( reinterpret_cast< Bug* >( m_spTarget.Get() )->TimeToDie() )
		{
			// Increase this bug's life as a reward
			if( m_fAge - KILL_REWARD >= 0 )
				m_fAge -= KILL_REWARD;
			else
				m_fAge -= KILL_REWARD;
		}// End if
		break;
	case PATROLING:
//		logger::event( "Bug::AdjustStats", "Patroling", 0 );
		// Update thirst, hunger, and energy and make sure they are 
		// in range
		if( m_ucThirst < MAX_RESOURCE )
			m_ucThirst += 1;
		else
			m_fAge += 1;
	
		if( m_ucHunger < MAX_RESOURCE )
			m_ucHunger += 1;
		else
			m_fAge += 1;

		if( m_ucEnergy > 0 )
			m_ucEnergy -= 1;
		else
			m_fAge += 1;

		break;
	case REPRODUCING:
//		logger::event( "Bug::AdjustStats", "Reproducing", 0 );
		break;
	default:
		break;
	};// End switch( m_bsState )
}// End Bug::AdjustStats


// Does damage to this bug
void Bug::DoDamage( const unsigned char damage )
{
	// Reduce the energy of this bug if possible
	if( m_ucEnergy - damage >= 0 )
		m_ucEnergy -= damage;
	else
	{
		// Otherwise, reduce the energy to zero and increase the age
		m_fAge += damage;//( m_ucEnergy - damage );
		m_ucEnergy = 0;
	}// End else
}// End Bug::DoDamage


// Initializes the display list
void Bug::InitializeList(  SurvivalEngine* engine, 
						  quadTreeTerrain* terrain, QuadTree* tree )
{
	// Set up the terrain, quad tree, and engine for all bugs
	m_qtTerrain = terrain;
	m_qtTree	= tree;
	m_pEngine	= engine;
}// End Bug::InitializeList
