
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Predator_Recon.cpp
// Project:	AvP3
// Author : Callum Hope
// Date   : 21-Nov-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "Actor/Vertebrates/Predator/AVP_Predator_Recon.h"

// Asura header-files...
#include "AI/Asura_AI_Navigation.h"
#include "Blueprint/Asura_Blueprint_System.h"
#include "Core/Asura_UserInput.h"
#include "Dynamics/Asura_Collision_Object.h"
#include "Entity/PhysicalObject/Moves/Asura_Movement_System.h"
#include "GUIMenu/Asura_GUIMenu_Element_Text.h"
#include "Input/Asura_ControlMap.h"
#include "Physics/Asura_Physics.h"
#include "Physics/Asura_Physics_Object.h"
#include "Rendering/Asura_Font_System.h"
#include "Rendering/Asura_Render.h"
#include "SpecialFX/PFX/Asura_PFX_Entity_Effect.h"
#include "SpecialFX/PFX/Asura_PFX_System.h"

// Game header-files...
#include "Actor/AVP_Actor_PhysicsObjectHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_Description.h"
#include "Actor/Vertebrates/Predator/AVP_Predator_Focus.h"
#include "Actor/Vertebrates/Predator/AVP_Predator_InputHandler.h"
#include "AVP_Predator_HUDHandler.h"
#include "Core/AVP_Navigation.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AVP_Vertebrate_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ClientActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ClientActor_Predator.h"
#include "GUIMenu/AVP_GUIMenu_System.h"
#include "Moves/AVP_Moves.h"

//#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"

////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////

// standard 3D space reference vectors. 
static const Asura_Vector_3 xFORWARD(0.0f, 0.0f, 1.0f);
static const Asura_Vector_3 xDOWN(0.0f, 1.0f, 0.0f);
static const Asura_Vector_3 xINVALID(0.0f, 0.0f, 0.0f);
static const Asura_Vector_3 xSCREEN_CENTRE(0.5f, 0.5f, 0.0f);

// all hash id names of blueprint variables. 
const Asura_Hash_ID uPREDATOR_RECON_MAX_DISP =		0xD43D7FFC;		//Asura_GetHashID("Recon.MaxDisplacement");
const Asura_Hash_ID uPREDATOR_RECON_MAX_DIST =		0xFDE7F85A;		//Asura_GetHashID("Recon.MaxDistance");
const Asura_Hash_ID uPREDATOR_RECON_MIN_DIST =		0x605AA724;		//Asura_GetHashID("MeleeStandardAttackRange");
//const Asura_Hash_ID uPREDATOR_RECON_PATH_BOLD_PFX =	0x25FEB0F0;		//Asura_GetHashID("Recon.PathHighlight");
//const Asura_Hash_ID uPREDATOR_RECON_PATH_PFX =		0x72D956DF;		//Asura_GetHashID("Recon.PathSelected");
const Asura_Hash_ID uPREDATOR_RECON_POTPREY_PFX =	0x9AF9423F;		//Asura_GetHashID("Recon.PotentialPreyHighlight");
const Asura_Hash_ID uPREDATOR_RECON_PREY_PFX =		0x2844B5FF;		//Asura_GetHashID("Recon.PreyHighlight");
const Asura_Hash_ID uPREDATOR_RECON_TRARGET_PFX =	0xD67E50C4;		//Asura_GetHashID("Recon.TargetHighlight");	
const Asura_Hash_ID uPREDATOR_RECON_INVALID_PFX =	0xF06A7A07;		//Asura_GetHashID("Recon.TargetInvalid");	
const Asura_Hash_ID uPREDATOR_RECON_SELECTED_PFX =	0x3EBC6C8B;		//Asura_GetHashID("Recon.TargetSelected");	

// Hash ID of the Predator HUD GUIMenu Page
const Asura_Hash_ID s_uPREDATOR_HUD =				0x0fc6f3af;		// Asura_GetHashID( "Predator_HUD" )

// Hash ID of the HUD elements we need to acces via code. 
const Asura_Hash_ID s_uTXT_ID_HIGH =				0x2AFBB1BA;		// Asura_GetHashID( "HUD_RECON_HIGH" )
const Asura_Hash_ID s_uTXT_ID_LOW =					0x74FFEC3C;		// Asura_GetHashID( "HUD_RECON_LOW" )
const Asura_Hash_ID s_uTXT_ID_MARINE =				0x3981443D;		// Asura_GetHashID( "HUD_RECON_SPECIES_MARINE" )
const Asura_Hash_ID s_uTXT_ID_CIVILIAN =			0x7D79D73E;		// Asura_GetHashID( "HUD_RECON_SPECIES_CIVILIAN" )
const Asura_Hash_ID s_uTXT_ID_ANDROID =				0x914A4F54;		// Asura_GetHashID( "HUD_RECON_SPECIES_ANDROID" )

////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////

// Declare the singleton instance of the class and hence call the constructor via this process. 
AVP_Predator_Recon AVP_Predator_Recon::s_xRecon;

////////////////////////////////////////////////////////////////////////////////
// Helper functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Class functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::AVP_Predator_Recon
// Scope		: Protected 
// Author       : Callum Hope
// Date         : 21-Nov-2008
//
// Desc			: Constructor the class, protected so only one instance can ever be created at a time. 
//				  All necessary variable initialisations
////////////////////////////////////////////////////////////////////////////////

AVP_Predator_Recon::AVP_Predator_Recon()
:	m_pxOwner				( NULL )
,	m_xPotPreyPos			( Asura_Maths::ZeroVector3 )
,	m_xPreyPos				( Asura_Maths::ZeroVector3 )
,	m_xTargetPos			( Asura_Maths::ZeroVector3 )
,	m_uPreyGuid				( ASURA_GUID_UNREGISTERED )
,	m_uPathMarkPFXID		( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uPathBoldMarkPFXID	( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uPotentialPreyPosPFXID( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uPreyPosPFXID			( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uTargetPosPFXID		( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uTargetInvPFXID		( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uTargetSelPFXID		( ASURA_PFX_INVALID_EFFECT_ID )
,	m_uSelectedPreyPosPFXID	( ASURA_PFX_INVALID_EFFECT_ID )
,	m_pxActivateSound		( NULL )
,	m_pxDeActivateSound		( NULL )
,	m_iDistSoundEventHandle	( ASURA_INVALID_HANDLE )
,	m_iPrevSoundEventHandle	( ASURA_INVALID_HANDLE )
{
	// set defaults. 
	m_bTargetJustSelected = m_bReconIsActive = m_bPotentialPrey = m_bPreyTargeted = m_bTargetPosValid = false;
	m_fMaxEngageDistance = m_fMaxDisplacement = 50.0f;
	m_fMinEngageDistance = 6.0f;
	m_fArrivalDistance = 3.0f;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::~AVP_Predator_Recon
// Scope		: Protected 
// Author       : Callum Hope
// Date         : 21-Nov-2008
//
// Desc			: Destructor the class, protected so only one instance can ever be created at a time. 
////////////////////////////////////////////////////////////////////////////////

AVP_Predator_Recon::~AVP_Predator_Recon()
{
	if( m_uPathBoldMarkPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uPathBoldMarkPFXID );
	}

	if( m_uPathMarkPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uPathMarkPFXID );
	}
	
	if( m_uPotentialPreyPosPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uPotentialPreyPosPFXID );
	}
	
	if( m_uPreyPosPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uPreyPosPFXID );
	}
	
	if( m_uTargetPosPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uTargetPosPFXID );
	}

	if( m_uTargetInvPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uTargetInvPFXID );
	}
	
	if( m_uTargetSelPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uTargetSelPFXID );
	}

	if( m_uSelectedPreyPosPFXID != ASURA_PFX_INVALID_EFFECT_ID )
	{
		Asura_PFX_System::DestroyEffect( m_uPotentialPreyPosPFXID );
	}

	// tidy up incase we have an old sound handle to event that has now finished, free the handle. 
	if( m_iDistSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( Asura_Sound_Event_System::IsPlaying( m_iDistSoundEventHandle ) )
		{
			Asura_Sound_Event_System::Stop( m_iDistSoundEventHandle );
		}
		Asura_Sound_Event_System::FinishedWithHandle( m_iDistSoundEventHandle );
		m_iDistSoundEventHandle = ASURA_INVALID_HANDLE;
	}

	// tidy up incase we have an old sound handle to event that has now finished, free the handle. 
	if( m_iPrevSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( Asura_Sound_Event_System::IsPlaying( m_iPrevSoundEventHandle ) )
		{
			Asura_Sound_Event_System::Stop( m_iPrevSoundEventHandle );
		}
		Asura_Sound_Event_System::FinishedWithHandle( m_iPrevSoundEventHandle );
		m_iPrevSoundEventHandle = ASURA_INVALID_HANDLE;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::PostPlayerCreateInitialise
// Scope		: Public 
// Author       : Callum Hope
// Date         : 21-Nov-2008
//
// Desc			: Called from the clientactor Predator (object not actor) after the player is definatly created.
//				  Loads in all data needed from the blueprints as part of the Predator initialisation process.
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::PostPlayerCreateInitialise()
{
	if( GetOwnerSet() )
	{
		const Asura_Hash_ID	uBlueprintHash	= m_pxOwner->GetBlueprintHashID();
		Asura_Hash_ID		uTypeHash		= uAVP_BLUEPRINT_TYPE_ACTORS;
		Asura_Blueprint*	pxBlueprint		= Asura_Blueprint_System::GetBlueprintByHashID( uTypeHash, uBlueprintHash );

		// first get the min engage distance, taken from the melee attacking range in the actor initialisation blueprint 
		// Melee attack Dist used because recon used the melee button and Melee takes priority, so its a way to avoid lots of Recon conditions all over the Melee system, 
		if( pxBlueprint )
		{
			Asura_Value xValue;
		
			if (pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_MIN_DIST, xValue ) )
			{
				m_fMinEngageDistance = xValue.GetFloatValue() + 1.0f;
			}
		}
			
		uTypeHash		= uAVP_BLUEPRINT_TYPE_PLAYERS;
		pxBlueprint		= Asura_Blueprint_System::GetBlueprintByHashID( uTypeHash, uBlueprintHash );

		// now get the rest of the data from the Player, Predator, FirstPerson, SinglePlayer blueprint. 
		if( pxBlueprint )
		{
			Asura_Value xValue;
			const u_short usPFXFlags = ASURA_PFX_EFFECT_CAMERA_FLAGS | ASURA_PFX_EFFECT_PRESERVE_WHILE_INACTIVE | ASURA_PFX_EFFECT_START_INACTIVE | ASURA_PFX_EFFECT_HUD_EFFECT | ASURA_PFX_EFFECT_ALWAYS_ON_TOP;
			
			if (pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_MAX_DISP, xValue ) )
			{
				m_fMaxDisplacement = xValue.GetFloatValue();
			}
			if (pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_MAX_DIST, xValue ) )
			{
				m_fMaxEngageDistance = xValue.GetFloatValue();
			}
			
			//CAH path functionality held off until other elements are in place
			//if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_PATH_PFX, xValue ) )
			//{
			//	m_uPathMarkPFXID = Asura_PFX_Entity_Effect::Create( XXXXXXX, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			//}
			//if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_PATH_BOLD_PFX, xValue ) )
			//{
			//	m_uPathBoldMarkPFXID = Asura_PFX_Entity_Effect::Create( XXXXXXX, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			//}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_POTPREY_PFX, xValue ) )
			{
				m_uPotentialPreyPosPFXID = Asura_PFX_Entity_Effect::Create( m_xPreyPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_PREY_PFX, xValue ) )
			{
				m_uPreyPosPFXID = Asura_PFX_Entity_Effect::Create( m_xPreyPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_TRARGET_PFX, xValue ) )
			{
				m_uTargetPosPFXID = Asura_PFX_Entity_Effect::Create( m_xTargetPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_INVALID_PFX, xValue ) )
			{
				m_uTargetInvPFXID = Asura_PFX_Entity_Effect::Create( m_xTargetPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_SELECTED_PFX, xValue ) )
			{
				m_uTargetSelPFXID = Asura_PFX_Entity_Effect::Create( m_xTargetPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
			if ( pxBlueprint->GetParameterValueByHashID( uPREDATOR_RECON_POTPREY_PFX, xValue ) ) // Uses the same PFX as m_uPotentialPreyPosPFXID
			{
				m_uSelectedPreyPosPFXID = Asura_PFX_Entity_Effect::Create( m_xPreyPos, xFORWARD, xValue.GetHashIDValue(), NULL, usPFXFlags );
			}
		}
	}
	else
	{
		Asura_Assert( AVP_Settings::IsMultiPlayer(), "AVP_Predator_Recon::PostPlayerCreateInitialise\n Blueprint data for player can not be read as the player pointer has not been set. " );
	}

	// saftey check for recon activation distances. 
	if( m_fMinEngageDistance >= m_fMaxEngageDistance )
	{
		Asura_Assert( false, "AVP_Predator_Recon::PostPlayerCreateInitialise\n Blueprint Lookup Value Issue\nMin engage distance is less than the Max, reverting to defaults" );
		m_fMaxEngageDistance = 50.0f;
		m_fMinEngageDistance = 6.0f;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdatePredRecon
// Scope		: Public 
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Per tick update function. called fron the AVP_ClientActor_Predator Class update. 
//				  Used as an update backbone to organise all the update sub-routeins. 
////////////////////////////////////////////////////////////////////////////////
void AVP_Predator_Recon::SetOwner( AVP_ClientActor_Predator* pxOwner )
{ 
	// set the owner as that passed to this function, it can be NULL on the player deinitialisaton
	m_pxOwner = pxOwner; 

	if( m_pxOwner )
	{
		m_pxActivateSound = pxOwner->GetSoundEventFromBlueprints( 0x126BD862 );		//ReconActivate
		m_pxDeActivateSound = pxOwner->GetSoundEventFromBlueprints( 0x3628B423 );	//ReconDeActivate
	}
	else
	{
		// if the owner is NULL then get rid of the sound event as well. 
		m_pxActivateSound = NULL;
		m_pxDeActivateSound = NULL;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdatePredRecon
// Scope		: Public 
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Per tick update function. called fron the AVP_ClientActor_Predator Class update. 
//				  Used as an update backbone to organise all the update sub-routeins. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::UpdatePredRecon()
{
	if( ! IsUpdateAllowed() )
	{
		// if recon is not being used or cant be updated then deAvcitave it and exit. 
		DeActivateRecon();
		return;
	}

	AVP_Predator_HUDHandler::SetReconTargetAvailable( false );
	
	const AVP_Vertebrate_InputHandler* pxInput = static_cast<const AVP_Vertebrate_InputHandler*>( m_pxOwner->GetInputHandler() );

	if( m_bTargetJustSelected )
	{
		// lower selection flag so that Melee attacks start registering again. 
		m_bTargetJustSelected = false;
	}

	// PREY UPDATE----------------------------------------------------------------
	
	// always update potential prey, even if Reconmode is already active. 
	UpdatePotentialPrey();
	
	if( m_bReconIsActive || m_bPreyTargeted )
	{
		// recon mode is active or we have prey, so update its position
		m_xPreyPos = FindCenterGroundPointForPrey( m_uPreyGuid );
	}

	// TARGET UPDATE--------------------------------------------------------------
	if( m_bReconIsActive )
	{
		// if recon is active then update potential targets and the HUD information
	//	UpdateHudInfo();
		UpdatePotentialTargets();
	}

	if( m_bPreyTargeted && ! m_bReconIsActive )
	{
		// if recon mode is not active but we still have a selecgted target from the previous runn through check to see if it should still be shown. 
		UpdateSelectedTarget();
	}

	// MODE ACTIVATION UPDATE-----------------------------------------------------
	if( m_bPotentialPrey )
	{
		// if we have potential prey and it is a humanoid
		AVP_ClientEntity_Actor* pxEntity = AVP_ClientEntity_Actor::FindEntity( m_uPotPreyGuid );
		if( pxEntity && pxEntity->GetSpeciesByClassification() == AVP_Settings::AVP_SPECIES_HUMAN 
			&& pxEntity->GetClassification() != AVP_ENTITYCLASS_SENTRYGUN ) // We cannot fool a sentrygun, FS 08 May 2009
		{
			AVP_Predator_HUDHandler::SetReconTargetAvailable( true );
		
			// if we have potential prey check for button presses to make it active. 
			if( pxInput->GetControlMapValue( AVP_Vertebrate_InputHandler::RECON_TOGGLE, true, true ) > 0.0f )
			{
				// activate again even if we are already active, just to swap who the confirmed prey is. 
				ActivateRecon();
			}
		}
	}
	
	if( m_bReconIsActive )
	{
		// if recon is active check for the target selection button
		if( pxInput->GetControlMapValue( AVP_Vertebrate_InputHandler::RECON_TOGGLE, true, true ) > 0.0f )
		{
			ConfirmTargetLocation();
		}

		// if recon is active check for any deactivate button presses ( anything but movement and the recon button )
		if( CheckForDeactivateButtonPress() )
		{
			DeActivateRecon();
			PlayModeDeActivationSound();
		}
	}

	// tidy up incase we have an old sound handle to event that has now finished, free the handle. 
	if( m_iDistSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( ! Asura_Sound_Event_System::IsPlaying( m_iDistSoundEventHandle ) )
		{
			Asura_Sound_Event_System::FinishedWithHandle( m_iDistSoundEventHandle );
			m_iDistSoundEventHandle = ASURA_INVALID_HANDLE;
		}
	}

	// tidy up incase we have an old sound handle to event that has now finished, free the handle. 
	if( m_iPrevSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( ! Asura_Sound_Event_System::IsPlaying( m_iPrevSoundEventHandle ) )
		{
			Asura_Sound_Event_System::FinishedWithHandle( m_iPrevSoundEventHandle );
			m_iPrevSoundEventHandle = ASURA_INVALID_HANDLE;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdatePotentialPrey
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Update Routein if update is allowed and reconmode is not already active. 
//				  Search down LOS and find if there is a potential prey NCP
//				  If so then set flags and record data from it, so this can be picked up in render function
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::UpdatePotentialPrey()
{
	Asura_Vector_3		xCameraPosition;
	Asura_Matrix_3x3	xCameraOrientation;

	// Get the Hash ID of the camera attached to the player model's eye position, its what we will use for the LOS test. 
	Asura_Hash_ID uCameraHashID = AVP_Vertebrate_Description::GetMarkerPointHashID( AVP_Vertebrate_Description::MPID_EYES ); 

	if( m_pxOwner->GetWorldSpaceMarkerPoint( uCameraHashID, &xCameraPosition, &xCameraOrientation) ) 
	{
		// if we got the camera position etc then get the vector direction to be used for the LOS test. 
		const Asura_Vector_3 xCameraDirection( xCameraOrientation.e13, xCameraOrientation.e23, xCameraOrientation.e33 );
		const AVP_ClientEntity_Actor* pxEntity = NULL;

		// lower the potential prey flag and ID each frame. 
		m_bPotentialPrey = false;
		m_uPotPreyGuid = ASURA_GUID_UNREGISTERED;

		// set the best screen position found to as far away from the centre as possible. 
		Asura_Vector_2 xBestScreenPos(1.0f, 1.0f); 

		for( Asura_Hashed_List_ConstIt<AVP_ClientEntity_Actor> xIt( AVP_ClientEntity_Actor::GetList() ); !xIt.Done(); xIt.Next() )
		{
			pxEntity = xIt.GetCurrent();

			if(		( pxEntity )																		// if we have an entiry
				&&	( ! pxEntity->IsDead() )															// and it is not dead
				&&	( ! pxEntity->IsDestroyed() )														// and it has not been destroyed
				&&	( pxEntity->GetGuid() != m_pxOwner->GetGuid() )	)									// and it is not the local player
			{
				if( pxEntity->GetSpeciesByClassification() == AVP_Settings::AVP_SPECIES_HUMAN				// if the entity is humanoid
					||( m_pxOwner->GetFocus()->GetActive()													// OR
					&& ( ( pxEntity->GetSpeciesByClassification() == AVP_Settings::AVP_SPECIES_PREDATOR )	// if focus mode is active
					|| ( pxEntity->GetSpeciesByClassification() == AVP_Settings::AVP_SPECIES_ALIEN ) )		// AND they are a predator or alien
					&& ( m_pxOwner->GetFocus()->GetMeleeTarget() == ASURA_GUID_UNREGISTERED ) ) )			// AND we dont have a melee target
				{
					if( TestEntityAgainstLOS( *pxEntity, xCameraPosition, xCameraDirection, xBestScreenPos ) )
					{
						// if we have a LOS collision and have not already selected this entity as confirmed prey
						if( ! ( m_bReconIsActive && ( pxEntity->GetGuid() == m_uPreyGuid ) ) )
						{
							// record needed data for render and raise 'potential found' flag AS LONG AS we are NOT looking at an already active prey
							m_bPotentialPrey = true;
							m_uPotPreyGuid = pxEntity->GetGuid();
							m_xPotPreyPos = FindCenterGroundPointForPrey( m_uPotPreyGuid );
						}
					}
				}
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdatePotentialTargets
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Update Routein if recon mode if active and hasnt chosen a target yet. 
//				  Compares the location you are looking at with possible waypoints near by and sets a waypoint position is found. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::UpdatePotentialTargets()
{
	Asura_Vector_3 xLookAtPos;
	Asura_Vector_3 xCameraPosition;
	Asura_Matrix_3x3 xCameraOrientation;
	const u_short usIgnoreFlags = m_pxOwner->GetFlagsToIgnore() | AsuraPolygonFlag_NoCollisions;
	u_short usWyPtId;

	// reset the valid flag, target position is guilty until proven innocent. 
	m_bTargetPosValid = false;

	// Get the Hash ID of the camera attached to the player model's eye position, its what we will use for the LOS test. 
	Asura_Hash_ID uCameraHashID = AVP_Vertebrate_Description::GetMarkerPointHashID( AVP_Vertebrate_Description::MPID_EYES ); 

	if( m_pxOwner->GetWorldSpaceMarkerPoint( uCameraHashID, &xCameraPosition, &xCameraOrientation) ) 
	{
		// if we got the camera position etc then get the vector direction to be used for the LOS test. 
		const Asura_Vector_3 xCameraDirection( xCameraOrientation.e13, xCameraOrientation.e23, xCameraOrientation.e33 );

		//Asura_LOS_InputData xInput( xCameraPosition, xCameraDirection, m_pxOwner->GetGuid(), m_fMaxEngageDistance, false, usIgnoreFlags );
		Asura_LOS_InputData xInput( xCameraPosition, xCameraDirection, m_pxOwner->GetGuid(), ASURA_LOS_MAX_DISTANCE, false, usIgnoreFlags );

		// Get the LOD output data only for the environment, so we pass through dynamic players and objects. 
		const Asura_LOS_OutputData* pxOutput = Asura_LOS::TestAgainstEnvironment( &xInput );

		if( pxOutput->m_bHitEnvironment )
		{
			// if we did hit the environment within the max distance then find the position that the intersection was. 
			xLookAtPos = xCameraPosition + ( xCameraDirection * pxOutput->m_fDistanceToIntersection );

			AVP_ServerEntity_Actor* pxTargetActor = AVP_ServerEntity_Actor::FindEntity( GetPreyGuid() );

			if ( pxTargetActor )
			{
				AVP_Brain_Actor* pxBrain = pxTargetActor->GetActorBrain();

				if ( pxBrain )
				{
					const AVP_Navigation::NavData& xNavData = pxBrain->GetNavData();

					// now find the nearest Waypoint that is valid for a HUMANOID using standard AVP test params. 
					AVP_Navigation::TestParams xTestParams	= AVP_Navigation::s_xTPStandardParams;
					xTestParams.m_usZone					= xNavData.m_usCurrentZone;
					xTestParams.m_uPathfinderFlags			=  AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID;
					xTestParams.m_xNormal					= -pxTargetActor->GetCurrentGravityDirection();
					xTestParams.m_bRejectNonalignedWPs		= true;

					// using the Human paramters look for the nearest waypoint
					if ( AVP_Navigation::GetNearestWaypointID(xLookAtPos, usWyPtId, xTestParams ) )
					{
						// if we found one double check it
						m_bTargetPosValid = Asura_AI_Navigation_System::IsPositionInWaypoint( xLookAtPos, usWyPtId );

						if( m_bTargetPosValid )
						{
							// if the position is on a slope make sure it has clearance or raise it - so the PFX wont clip the ground. 
							CheckAndAdjustTargetPositionHeight( xLookAtPos );

							//Asura_AI_NavVertex* pxWayPoint =  Asura_AI_Navigation_System::GetWaypoint( usWyPtId );
							m_xTargetPos = xLookAtPos;

							// Also check if the Preys collision object can fit in the waypoint location (not the look at position)
							const AVP_ClientActor_Human* pxPreyClientActor = AVP_ClientActor_Human::FindEntity( m_uPreyGuid );
							if( pxPreyClientActor )
							{
								const Asura_Physics_Object* pxPhysObj = pxPreyClientActor->GetPhysicsObject();
								if ( pxPhysObj )
								{
									const Asura_Collision_Object* pxCollObj = pxPhysObj->GetCollisionObject();
									if ( pxCollObj )
									{
										m_bTargetPosValid &= Asura_Physics_System::CanPlaceSphereStackAt( pxCollObj->GetBoundingBox(), m_xTargetPos, usIgnoreFlags, 0.01f );
									}
								}
							}

// 							// make sure the target is not too far away from the player. 
 							Asura_Vector_3 xDiffVec = xCameraPosition - m_xTargetPos;
// 							if( xDiffVec.MagnitudeSquared() > ( m_fMaxEngageDistance * m_fMaxEngageDistance ) )
// 							{
// 								m_bTargetPosValid = false;
// 							}

							// finally make sure the target is not too far away from the prey, defined by blueprint variable Recon.MaxDisplacement
							xDiffVec = m_xPreyPos - m_xTargetPos;
							if( xDiffVec.MagnitudeSquared() > ( m_fMaxDisplacement * m_fMaxDisplacement ) )
							{
								m_bTargetPosValid = false;
							}
						}
					}

					if( ! m_bTargetPosValid )
					{	
						// if we do not have a valid waypoint position (but hit the environment) then set the target position to the cursor position, so the invalid PFX is displayed there. 
						m_xTargetPos = xLookAtPos - ( xCameraDirection * 1 );
					}
				}
			}
		}
		else
		{
			// if we didnt hit the environment then set the target pos to 0 so it wont be rendered. 
			m_xTargetPos = xINVALID;
		}
	}
	else
	{
		m_xTargetPos = xINVALID;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdateSelectedTarget
// Scope		: Private
// Author       : Callum Hope
// Date         : 1-Dec-2008
//
// Desc			: Routein to check if the selected target shoudl still be highlighted, 
//				  Done based on the position if the prey to the target and the state of the prey. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::UpdateSelectedTarget()
{
	bool bStopRender = false;
	Asura_Vector_3 xDifferenceVec = m_xPreyPos - m_xTargetPos;
	float fDistanceSqrd = xDifferenceVec.MagnitudeSquared();

	if( fDistanceSqrd < ( m_fArrivalDistance * m_fArrivalDistance ) )
	{
		// if the distance between the prey and the seleced target is smaller than the threshold then stop this state
		bStopRender = true;
	}

	// if the prey entity is dead or no longer exists thenstop this state
	AVP_ClientEntity_Actor* pxEntity = AVP_ClientEntity_Actor::FindEntity( m_uPreyGuid );
	if( pxEntity )
	{
		if( ( pxEntity->IsDead() ) || ( pxEntity->IsDestroyed() ) )	
		{
			bStopRender = true;
		}
	}
	else
	{
		bStopRender = true;
	}

	if( bStopRender )
	{
		// this is the only place where the m_bPreyTargeted bool and the m_uPreyGuid are reset. 
		m_bPreyTargeted = false;
		m_bTargetPosValid = false;
		m_xTargetPos = xINVALID;
		m_xPreyPos = xINVALID;
		m_uPreyGuid = ASURA_GUID_UNREGISTERED;
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::RenderPredRecon
// Scope		: Public
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: This goes through all of the PFXs used with Redcon mode and draws them according to all of thier own conditions. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::RenderPredRecon()
{
	// First deal with the PFX to Highlight the Potential Prey
	Asura_PFX_Entity_Effect* pxEffect = Asura_PFX_System::GetEntityEffect( m_uPotentialPreyPosPFXID );
	if( pxEffect )
	{
		if( m_bPotentialPrey )
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}
			pxEffect->SetPosition( m_xPotPreyPos );
		}
		else if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	//  deal with the PFX to Highlight the confirmed Prey
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uPreyPosPFXID );
	if( pxEffect )
	{
		if( m_bReconIsActive )
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}
			pxEffect->SetPosition( m_xPreyPos );
		}
		else if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// deal with the PFX to Highlight the Prey ater a target has been chosen while the distraction sound plays. 
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uSelectedPreyPosPFXID );
	if( pxEffect )
	{
		if( m_bPreyTargeted && GetDistractionSoundPlaying() )
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}
			pxEffect->SetPosition( m_xPreyPos );
		}
		else if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// now its the valid target PFX's turn 
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetPosPFXID );
	if( pxEffect )
	{
		// if recon mode is active, we have an environment position, it is a valid selection and we are not looking at a potential prey
		// if ( m_xTargetPos == xINVALID ) then it means the cursor has not intersected with the environment at all
		if( m_bReconIsActive && ( m_xTargetPos != xINVALID ) && m_bTargetPosValid && ! m_bPotentialPrey)
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}

			pxEffect->SetPosition( m_xTargetPos );
		}
		else if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// Target PFX INVALID
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetInvPFXID );
	if( pxEffect )
	{
		// if recon mode is active, we have an environment position but it is an invalid selection and we are not looking at a potential prey
		// if ( m_xTargetPos == xINVALID ) then it means the cursor has not intersected with the environment at all within the legal range.
		if( m_bReconIsActive && ( m_xTargetPos != xINVALID ) && ! m_bTargetPosValid && ! m_bPotentialPrey )
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}
			pxEffect->SetPosition( m_xTargetPos );
		}
		else if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// Selected Target PFX 
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetSelPFXID );
	if( pxEffect )
	{
		// if recon mode is NOT active, we have a valid target position and this has been selected draw the PFX marking the selected position while the distraction sound is playing. 
		if( ! m_bReconIsActive && ( m_xTargetPos != xINVALID ) && m_bTargetPosValid && m_bPreyTargeted && GetDistractionSoundPlaying() )
		{
			if( pxEffect->GetState() != ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Start();
			}

			pxEffect->SetPosition( m_xTargetPos );
		}
		else if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	/*if( m_bReconIsActive )
	{
		Asura_RGBA xColour1( 1.0f, 1.0f, 0.0f, 1.0f);
		Asura_RGBA xColour2( 0.0f, 1.0f, 1.0f, 1.0f);
	
		for( u_int uCount = 0; uCount < m_xReconSpline.GetNumberOfPoints(); uCount ++ )
		{
			m_xReconSpline.RemovePoint( 0 );
		}
		m_xReconSpline.AddPoint( 1, m_xPreyPos );
		m_xReconSpline.AddPoint( 1, m_xTargetPos );
		m_xReconSpline.RenderLines( xColour1, xColour2 );
	}*/
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::CheckAndAdjustTargetPositionHeight
// Scope		: Private
// Author       : Callum Hope
// Date         : 4-Feb-2009
//
// Desc			: Takes a position and creates 4 posiitons around it. The performes a LOS test straight down to see if the environment is hit. 
//				  If so the position is raised and the routein starts again. 
//
// Return		: As soon as the function finds 4 failed LOS tests it returns true, meaning the positions is clear of the ground enough to draw the PFX without intersecting it. 
//
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::CheckAndAdjustTargetPositionHeight( Asura_Vector_3 &xPosition )
{
	u_int uCount;
	const u_int uNumOfTestPoints = 4;
	float fLosLength = 10.0f;
	Asura_Vector_3 xSidePositions[uNumOfTestPoints];
	
	{
		float fSearchRadius = 1.5f;

		for( uCount = 0; uCount < uNumOfTestPoints; uCount ++ )
		{
			xSidePositions[uCount] = xPosition;

			// raise all of the side points by 10 (-ve Y is up)
			xSidePositions[uCount].SetY( xPosition.GetY() - fLosLength );
		}

		// apply the offsets to the points to position them around xPosition
		xSidePositions[0].SetX( xPosition.GetX() - fSearchRadius );
		xSidePositions[1].SetZ( xPosition.GetZ() + fSearchRadius );
		xSidePositions[2].SetX( xPosition.GetX() + fSearchRadius );
		xSidePositions[3].SetZ( xPosition.GetZ() - fSearchRadius );
	}

	// OK now we are set up declare what we need for the LOS test process. 
	int iSafteyCatch = 0;
	Asura_LOS_InputData xInput( xSidePositions[0], xDOWN, ASURA_GUID_UNREGISTERED, Asura_Maths::Abs( xSidePositions[0].GetY() ), false );
	const Asura_LOS_OutputData* pxOutput;

	uCount = 0;

	// enter while loop until the position is raised enough (iSafteyCatch is a saftey net to make sure we abort after a set number of iterations)
	while( iSafteyCatch < 500 )
	{
		for( uCount = 0; uCount < uNumOfTestPoints; uCount ++ )
		{
			xInput.Initialise( xSidePositions[uCount], xDOWN, ASURA_GUID_UNREGISTERED, Asura_Maths::Abs( xSidePositions[uCount].GetY() ), false );
			pxOutput = Asura_LOS::TestAgainstEverything( &xInput );

			if( pxOutput->m_bHitEnvironment )
			{
				// distance to raise is the length of the LOS tes - the distance to the intersetion ( + a little bit for good measure )
				float fDistToRaise = Asura_Maths::Abs( fLosLength - pxOutput->m_fDistanceToIntersection + 0.3f );

				for( u_int uCount2 = 0; uCount2 < uNumOfTestPoints; uCount2 ++ )
				{
					// if we hit the environment on this LOS test then raise all of the test points ( -ve y is up )
					xSidePositions[uCount2].SetY( xSidePositions[uCount2].GetY() - fDistToRaise );
				}

				iSafteyCatch ++;
				break;
			}
		}

		// if we got here without breaking then it means all four points did not intersect the environment. 
		// set the new position height (and take off height change from earlier) and return true
		xPosition.SetY( xSidePositions[0].GetY() + fLosLength );
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::TestEntityAgainstLOS
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Performes the Line Of Sight tests for this class. But incorporates a whole area of the screen, not just the cross hair
//				  Checks that the entity under question is infront of the camera and within the max Recon Range. 
//				  Returns true if we have hit the entity under question. 
//
// Arguments	: xEntity - the entity to see if we are intersecting
//				  xCameraPosition - world space of the camera looking for it. 
//				  xCameraDirection - direction the camera is facing in. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::TestEntityAgainstLOS(const AVP_ClientEntity_Actor& xEntity, const Asura_Vector_3& xCameraPosition, Asura_Vector_3 xCameraDirection, Asura_Vector_2& xBestScreenPos ) const
{
	// make the screen area for selecetion 10% (5 in both directions)
	float fScreenSpaceFromCentreLimit = 0.05f;

	// get the chest position of the entity, as a point generally in the center of the model 
	Asura_Vector_3 xChestWorldPos;
	xEntity.GetChestPosition( xChestWorldPos );

	// using this position in world space find the camera space for it. (used for the valid range test)
	Asura_Vector_3 xChestCameraSpacePos = xChestWorldPos;
	Asura_Camera::ProjectWorldCoordsToScreenSpace( xChestCameraSpacePos );
	
	if( xChestCameraSpacePos.z <= 0.0f ) 
	{ 
		// return if the entity is behind the camera. 
		return false; 
	} 
	else if( ( xChestCameraSpacePos.z > m_fMaxEngageDistance ) || ( xChestCameraSpacePos.z < m_fMinEngageDistance ) )
	{ 
		// return false if the entity is too far away or too close from the camera
		return false; 
	} 

	xChestCameraSpacePos -= xSCREEN_CENTRE;
	xChestCameraSpacePos.z = 0.0f;

	// make a new vector 2 and fill with the x and y from the camera space position so we can compare it agains any other potential preys on the screen. 
	Asura_Vector_2 xNewScreenSpace( xChestCameraSpacePos.GetX(), xChestCameraSpacePos.GetY() );

	if ( xNewScreenSpace.MagnitudeSquared() >= xBestScreenPos.MagnitudeSquared() )
	{
		// Already have a more central target so return false
		return false;
	}
	else
	{
		xBestScreenPos = xNewScreenSpace;
	}

	// find the distance from the camera to the entity in question (used to limit the LOS search to a max length.)
	Asura_Vector_3 xDirToEntity = xChestWorldPos - xCameraPosition;
	float fDistToPrey = xDirToEntity.Magnitude() + 1.0f;
	xDirToEntity.Normalise();

	if( ( xChestCameraSpacePos.x > -fScreenSpaceFromCentreLimit )	&&
		( xChestCameraSpacePos.x < fScreenSpaceFromCentreLimit )	&&
		( xChestCameraSpacePos.y > -fScreenSpaceFromCentreLimit )	&&
		( xChestCameraSpacePos.y < fScreenSpaceFromCentreLimit )	)
	{
		// set the input to the LOS test: from position, direction, ignor the player, check distance. 
		Asura_LOS_InputData xInput( xCameraPosition, xDirToEntity, m_pxOwner->GetGuid(), fDistToPrey );

		// carry out the Asura Internal LOS test.
		const Asura_LOS_OutputData* pxOutput = Asura_LOS::TestAgainstEverything( &xInput );

		if( pxOutput->m_bHitEnvironment || ( pxOutput->m_uHitEntity && pxOutput->m_uHitEntity != xEntity.GetGuid() ) )
		{
			// if there is environment or another entity betwen us and them (that is not them) then return false. 
			return false;
		}

		return true;
	}

	// set the input to the LOS test: from position, direction, ignor the player, check distance. 
	Asura_LOS_InputData xInput( xCameraPosition, xCameraDirection, m_pxOwner->GetGuid(), fDistToPrey );

	// carry out the Asura Internal LOS test.
	const Asura_LOS_OutputData* pxOutput = Asura_LOS::TestAgainstEverything( &xInput );

	return( pxOutput->m_uHitEntity == xEntity.GetGuid() );

}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::IsUpdateAllowed
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: De-clutter function for the Recon update routein
//				  Checkes if recon mode is allowed to be used, and hence if we should carry out an update. 
//				  Returns true to carry out a full update. Conditions where an updte is not allowed is detailed in comments in the function. 
//				  As a general rule: If you cant get into focus mode do not allow player to enter Recon Mode. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::IsUpdateAllowed()
{
	// if there is no owner set then no update
	if( ! GetOwnerSet() )
	{
		return false;
	}

	// if there is no input handler do not allow access to update functinality
	const AVP_Vertebrate_InputHandler* pxInput = static_cast<const AVP_Vertebrate_InputHandler*>( m_pxOwner->GetInputHandler() );
	if( ! pxInput )
	{
		return false;
	}

	// if the player is off the ground they cant be in recon mode. 
	//if( m_pxOwner->GetGroundType() == AVP_Actor_PhysicsObjectHandler::OFF_GROUND )
	//{
	//	return false;
	//}

	// if the player is currenly watching a cutscene. 
	if( Asura_Render::GetCutsceneHasCameraControl() )
	{
		return false;
	}

	// If the player is currenly in the middle of a complex move do not allow update 
	const Asura_Movement_System* pxMovementSystem = m_pxOwner->GetMovementSystem();
	const AVP_Move* pxCurrentMove = ( pxMovementSystem && pxMovementSystem->IsMoveInProgress() ) ? static_cast<const AVP_Move*>( pxMovementSystem->GetCurrentMove() ) : NULL;
	if( pxCurrentMove && pxCurrentMove->GetPreventsFocus() )
	{
		return false;
	}

	//// if the player is in focus mode recon can not be used. 
	//if( m_pxOwner->GetFocus()->GetActive() )
	//{
	//	return false;
	//}

	// if this is a multiplayer game recon mode is not used. 
	if( AVP_Settings::IsMultiPlayer() )
	{
		return false;
	}

	// if for some reason we dont have a range for the recon dont update it as it wont ever come to anything any way. 
	if( m_fMaxEngageDistance <= 0.0f )
	{
		return false;
	}

	// if we are already in recon mode but our prey has died dont update. 
	if( m_bReconIsActive )
	{
		bool bRetVal = true;

		AVP_ClientEntity_Actor* pxEntity = AVP_ClientEntity_Actor::FindEntity( m_uPreyGuid );
		if( pxEntity )
		{
			if(		( pxEntity->IsDead() )																// it is dead
				||	( pxEntity->IsDestroyed() )															// or it has been destroyed
				||	( pxEntity->GetSpeciesByClassification() != AVP_Settings::AVP_SPECIES_HUMAN ) )		// or it not a humanoid
			{
				// if the prey we were looking at has died since we selected them then we cant update. 
				bRetVal = false;
			}
		}
		else
		{
			// else we dont even have an entity! no update
			bRetVal = false;
		}

		// if the target has become too close or far away dont update (and hence exit recon mode.)
		Asura_Vector_3 xDistanceAway = m_xPreyPos - m_pxOwner->GetPhysicsObject()->GetPosition();

		if( ( xDistanceAway.MagnitudeSquared() > ( m_fMaxEngageDistance * m_fMaxEngageDistance ) ) || ( xDistanceAway.MagnitudeSquared() < ( m_fMinEngageDistance * m_fMinEngageDistance ) ) )
		{
			bRetVal = false;
		}

		if( ! bRetVal )
		{
			// for instances where we cant update recon mode but recon mode is already active we need to play the deactivation sound as well. 
			PlayModeDeActivationSound();
			return bRetVal;
		}
	}

	// if we get here then we survived the update gauntlet, return true to allow update. 
	return true;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::ActivateRecon
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Small Routein to hold all actions involved with turning recon mode on. 
//				  NB because this can be called even if the recon mode is already active all condition saftey checks should be done 
//				     on function call, not in funciton. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::ActivateRecon()
{
	// raise the internal active flag. 
	m_bReconIsActive = true;

	//lower the potential and post flags
	m_bPotentialPrey = false;
	m_bPreyTargeted = false;

	// record the prey guid, now it is confirmed
	m_uPreyGuid = m_uPotPreyGuid;
	m_uPotPreyGuid = ASURA_GUID_UNREGISTERED;

	// transfer the position data to the correct vector reference structure
	m_xPreyPos = m_xPotPreyPos;

	// sort out any HUD changes that occur on activation. 
	AVP_Predator_HUDHandler* pxHUDHandler = static_cast<AVP_Predator_HUDHandler*>( m_pxOwner->GetHUDHandler() );
	if(pxHUDHandler != NULL)
	{
		pxHUDHandler->OnBeginRecon();
	}

	// lastly play the activation sound
	PlayModeActivationSound();
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::DeActivateRecon
// Scope		: Private
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Small Routein to deactivate recon mode but not effect the post targeting state. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::DeActivateRecon()
{
	// lower flags from potential and active states. 
	m_bReconIsActive = false;
	m_bPotentialPrey = false;
	m_uPotPreyGuid = ASURA_GUID_UNREGISTERED;

	// stop all PFX excet those to do with the post targeted state. 
	StopAllPfxNow( false );

	AVP_Predator_HUDHandler* pxHUDHandler = static_cast<AVP_Predator_HUDHandler*>( m_pxOwner->GetHUDHandler() );
	if(pxHUDHandler != NULL)
	{
		pxHUDHandler->OnEndRecon();
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::CutAllReconActions
// Scope		: Public
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Small Routein to stop EVERYTHING to do with recon IMMEDIATLY
//				  The typical use for this function would be if the AI targeted spotted you and hence was no longer fooled by the noise effect. 
//				  Public so that it can be accessed anywhere AI may be used. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::CutAllReconActions()
{
	// lower all flags
	m_bReconIsActive = false;
	m_bPotentialPrey = false;
	m_bPreyTargeted = false;
	m_uPreyGuid = ASURA_GUID_UNREGISTERED;
	m_uPotPreyGuid = ASURA_GUID_UNREGISTERED;

	// stop all PFX, NO EXCEPTIONS
	StopAllPfxNow( true );

	AVP_Predator_HUDHandler* pxHUDHandler = static_cast<AVP_Predator_HUDHandler*>( m_pxOwner->GetHUDHandler() );
	if(pxHUDHandler != NULL)
	{
		pxHUDHandler->OnEndRecon();
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::ConfirmTargetLocation
// Scope		: Private
// Author       : Callum Hope
// Date         : 1-Dec-2008
//
// Desc			: On a 'Recon' Button press while Recon mode is active the potential target must be check and selected if possible, this is dont here
//				  technically once a target position is selected recon mode is no longer active but we set a bool to indicate
//				  the chosen target PFX must still be rendered int he update, (until the player has approached it)
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::ConfirmTargetLocation()
{
	// dont allow selection if the mode is not active, if we are not looking at valid target or if we are looking at another character. 
	if( m_bReconIsActive && m_bTargetPosValid && ! m_bPotentialPrey )
	{
		// update state flags
		m_bPreyTargeted = true;
		m_bReconIsActive = false;

		// update info flags and data
		m_bTargetJustSelected = true;
		m_uPotPreyGuid = ASURA_GUID_UNREGISTERED;

		AVP_Predator_HUDHandler* pxHUDHandler = static_cast<AVP_Predator_HUDHandler*>( m_pxOwner->GetHUDHandler() );
		if(pxHUDHandler != NULL)
		{
			pxHUDHandler->OnSelectReconTarget();
		}

		SendDistractionMessages();
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::SendDistractionMessages
// Scope		: Private 
// Author       : Gaz Thomas
// Date         : 17-Dec-2008
//
// Desc			: Sends the message to the actor who is being distracted. 
//				  Also send the play audio messages to all clients
////////////////////////////////////////////////////////////////////////////////
void AVP_Predator_Recon::SendDistractionMessages()
{
	//Send a message to the marine team letting them know a distraction has been activated (the distraction target guid is sent in this message.
	Asura_Message* pxAIMessage = Asura_Network::CreateMessage( AVP_MSGID_DISTRACT_AI, sizeof( AVP_Msg_DistractAI ) );
	if( pxAIMessage )
	{
		AVP_Msg_DistractAI* pxData = static_cast<AVP_Msg_DistractAI*>( pxAIMessage->GetData() );
		pxData->SetTargetGuid( GetPreyGuid() );

		// the only data we need is to know if this is a recon mode distraction. 
		pxData->SetReconBool( true );

		pxAIMessage->SetToGuid( GetPreyGuid() );
		pxAIMessage->SetFromGuid( GetOwnerGuid() );

		Asura_Network::Send( pxAIMessage );
	}

	// Send a message to all clients to play the distraction sound.
	Asura_Message* pxSoundMessage = Asura_Network::CreateMessage( AVP_MSGID_PLAY_DISTRACTION_SOUND, sizeof( AVP_Msg_CreateSound ) );
	if (pxSoundMessage)
	{
		AVP_Msg_CreateSound* pxData = static_cast<AVP_Msg_CreateSound*>( pxSoundMessage->GetData() );

		pxData->SetOriginatesFromPlayer( false );
		pxData->SetSoundHashId( 0x41F14CC2 ); // Asura_GetHash_ID("Distraction");

		pxSoundMessage->SetToGuid( ASURA_GUID_MY_CLIENT_ENTITIES );
		pxSoundMessage->SetFromGuid( GetOwnerGuid() );

		Asura_Network::Send( pxSoundMessage );
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::GetOwnerSet
// Scope		: Private 
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: Returns true or false depending on if the pointer m_pxOwner has been set.
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::GetOwnerSet()
{
	if( m_pxOwner != NULL )
	{
		return true;
	}
	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::GetOwnerGuid
// Scope		: Public 
// Author       : Callum Hope
// Date         : 24-Nov-2008
//
// Desc			: If it has been set return the Guid of the owner client actor. 
////////////////////////////////////////////////////////////////////////////////

Asura_Guid AVP_Predator_Recon::GetOwnerGuid()
{
	if( GetOwnerSet() )
	{
		return m_pxOwner->GetGuid();
	}
	return ASURA_GUID_UNREGISTERED;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::FindCenterGroundPointForPrey
// Scope		: Private 
// Author       : Callum Hope
// Date         : 25-Nov-2008
//
// Desc			: Finds the position on the floor at the center of an entity,
//				  Needed because we can get positions of both feet, but we need something between them both
//				  Essentially just averages the two feet positions. 
//				  Aguid is passed and not just the entity pointer becuase it cant be a const to call GetFootPosition
//				  you could take x and z of chest and y of feet but this is more accurate for now. 
////////////////////////////////////////////////////////////////////////////////

Asura_Vector_3 AVP_Predator_Recon::FindCenterGroundPointForPrey( Asura_Guid uGuid )
{
	AVP_ClientEntity_Actor* pxEntity = AVP_ClientEntity_Actor::FindEntity( uGuid );

	if( ! pxEntity )
	{
		Asura_Assert( false, "AVP_Predator_Recon::FindCenterGroundPointForPrey\n The entity passed is invalid, Recon PFX can not be placed." );
		return xFORWARD;
	}

	Asura_Vector_3 xPos0;
	Asura_Vector_3 xPos1;
	Asura_Vector_3 xPosFINAL( 0.0f, 0.0f, 0.0f );

	pxEntity->GetFootPosition( 0, xPos0 );
	pxEntity->GetFootPosition( 1, xPos1 );

	xPosFINAL.SetX( ( xPos0.GetX() + xPos1.GetX() ) * 0.5f );
	xPosFINAL.SetY( ( xPos0.GetY() + xPos1.GetY() ) * 0.5f );
	xPosFINAL.SetZ( ( xPos0.GetZ() + xPos1.GetZ() ) * 0.5f );

	return xPosFINAL;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::CheckForDeactivateButtonPress
// Scope		: Private
// Author       : Callum Hope
// Date         : 25-Nov-2008
//
// Desc			: Goes through all key presses looking for anything that would mean Recon mode should deactivate
//				  In essence anything but what movement and recon toggle are assigned to. 
//				  Returns true if recon should deactivate. 
//				  Only checks against Keys, not axis. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::CheckForDeactivateButtonPress()
{
	// no saftey checks to be done, this does not rely on any other conditions. 

	// if there have been any keys presses in the last frame continue
	if( Asura_UserInput::HasAnyKeyBeenPressed() )
	{
		AVP_Actor_InputHandler* pxInput = m_pxOwner->GetInputHandler();
		const Asura_ControlMapping* pxMapping = NULL;
		int iCount;
		bool bDeactivate;

		// for every Asura key that could be possibly pressed. 
		for( iCount = ASURA_KEYID_VOID; iCount < MAX_NUMBER_OF_ASURA_KEYIDS; iCount ++ )
		{
			// if this key is pressed continue
			if( Asura_UserInput::KeyPressed( iCount )  )
			{
				bDeactivate = true;

				// check if this is a key assigned to any of the recon toggle mappings. 
				pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::RECON_TOGGLE );
				while( pxMapping )
				{
					// if this is any of the recon toggle keys lower the deactivate flag and carry on 
					if( pxMapping->GetControlID() == iCount )
					{
						bDeactivate = false;
						break;
					}
					pxMapping = pxMapping->GetNextMapping();
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the forward/backward movement presses. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::FORWARDS_BACKWARDS );
					while( pxMapping )
					{
						// if this is any of the Forward/Back keys lower the deactivate flag and carry on 
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the left/right movement presses. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::STRAFE_LEFT_RIGHT );
					while( pxMapping )
					{
						// if this is any of the Left/Right keys lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the CLOAK mappings. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::CLOAK );
					while( pxMapping )
					{
						// if this is any of the CLOAK keys lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the ZOOM presses. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::ZOOM_IN );
					while( pxMapping )
					{
						// if this is a zoom key lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::ZOOM_OUT );
					while( pxMapping )
					{
						// if this is a zoom key lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::ZOOM_HOLD );
					while( pxMapping )
					{
						// if this is a zoom key lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the FOCUS mappings. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::FOCUS_HELD );
					while( pxMapping )
					{
						// if this is any of the FOCUS keys lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::FOCUS_TOGGLE );
					while( pxMapping )
					{
						// if this is any of the FOCUS keys lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					// check if this is a key assigned to any of the JUMP mappings. 
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::JUMP );
					while( pxMapping )
					{
						// if this is any of the JUMP keys lower the deactivate flag and carry on
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::VISION_SELECTOR_NEXT );
					while( pxMapping )
					{
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
					pxMapping = pxInput->GetMapFirstPerson().GetMapping( AVP_Vertebrate_InputHandler::VISION_SELECTOR_PREV );
					while( pxMapping )
					{
						if( pxMapping->GetControlID() == iCount )
						{
							bDeactivate = false;
							break;
						}
						pxMapping = pxMapping->GetNextMapping();
					}
				}

				if( bDeactivate )
				{
					return true;
				}
			}
		}
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::StopAllPfxNow
// Scope		: Private
// Author       : Callum Hope
// Date         : 28-Nov-2008 HAPPY BIRTHDAY ME!!!!!!!!!!!!!
//
// Desc			: Function to simply cut off PFX if they are still active, used mainly by the deactivate function as a sub routein. 
//				  NB the one exception is the post targeting location marker and this is stopped if passed a high argument. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::StopAllPfxNow( bool bStopPostTargeting )
{
	// First deal with the PFX to Highlight the Potential Prey
	Asura_PFX_Entity_Effect* pxEffect = Asura_PFX_System::GetEntityEffect( m_uPotentialPreyPosPFXID );
	if( pxEffect )
	{
		if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// deal with the PFX to Highlight the confirmed Prey
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uPreyPosPFXID );
	if( pxEffect )
	{
		if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// deal with the PFX to Highlight the Prey while the sound plays. 
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uSelectedPreyPosPFXID );
	if( pxEffect )
	{
		if ( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// now its the target PFX's turn VALID
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetPosPFXID );
	if( pxEffect )
	{
		if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	// Target PFX INVALID
	pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetInvPFXID );
	if( pxEffect )
	{
		if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
		{
			pxEffect->Stop( true );
		}
	}

	if( bStopPostTargeting )
	{
		// Target PFX INVALID
		pxEffect = Asura_PFX_System::GetEntityEffect( m_uTargetSelPFXID );
		if( pxEffect )
		{
			if( pxEffect->GetState() == ASURA_PFX_EFFECT_RUNNING )
			{
				pxEffect->Stop( true );
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::UpdateHudInfo
// Scope		: Private
// Author       : Callum Hope
// Date         : 28-Nov-2008 HAPPY BIRTHDAY ME!!!!!!!!!!!!!
//
// Desc			: Fills the text in the HUD elements each frame if the mode is active
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::UpdateHudInfo()
{
	u_int uTextStingIDClass;
	u_int uTextStingIDThreat;
	AVP_GUIMenu_System::STORED_WIDGETS uTitleEnumID;
	Asura_GUIMenu_Root* pxTitleRootItem = NULL;

	AVP_ClientEntity_Actor* pxEntity = AVP_ClientEntity_Actor::FindEntity( m_uPreyGuid );
	if( pxEntity )
	{
		Asura_UnicodeChar awcUnicodeString[8];
		Asura_PrintfToBfr( awcUnicodeString, L"%d", 16, true, static_cast<int>( pxEntity->GetHealth() ) );

		switch( pxEntity->GetClassification() )
		{
			case AVP_ENTITYCLASS_MARINE:
			{
				uTextStingIDClass = s_uTXT_ID_MARINE;
				uTextStingIDThreat = s_uTXT_ID_HIGH;
				break;
			}
			case AVP_ENTITYCLASS_ANDROID:
			{
				uTextStingIDClass = s_uTXT_ID_ANDROID;
				uTextStingIDThreat = s_uTXT_ID_HIGH;
				break;
			}
			case AVP_ENTITYCLASS_CIVILIAN:  
			case AVP_ENTITYCLASS_HUMAN:
			default:
			{
				uTextStingIDClass = s_uTXT_ID_CIVILIAN;
				uTextStingIDThreat = s_uTXT_ID_LOW;
				break;
			}
		}

		uTitleEnumID = AVP_GUIMenu_System::RECON_CLASS;
		pxTitleRootItem = AVP_GUIMenu_System::GetHUDElement( uTitleEnumID, s_uPREDATOR_HUD, false );
		if( pxTitleRootItem )
		{
			Asura_GUIMenu_Element_Text* pxTitleTextElement = static_cast<Asura_GUIMenu_Element_Text*>( pxTitleRootItem );
			if( pxTitleTextElement )
			{
				// if the string is not the one already set in the text element set it and re-render it. (the title is not rendered each frame normally)
				if( pxTitleTextElement->GetTextID() != uTextStingIDClass )
				{
					pxTitleTextElement->SetTextID( uTextStingIDClass );
				}
			}
		}

		uTitleEnumID = AVP_GUIMenu_System::RECON_THREAT;
		pxTitleRootItem = AVP_GUIMenu_System::GetHUDElement( uTitleEnumID, s_uPREDATOR_HUD, false );
		if( pxTitleRootItem )
		{
			Asura_GUIMenu_Element_Text* pxTitleTextElement = static_cast<Asura_GUIMenu_Element_Text*>( pxTitleRootItem );
			if( pxTitleTextElement )
			{
				// if the string is not the one already set in the text element set it and re-render it. (the title is not rendered each frame normally)
				if( pxTitleTextElement->GetTextID() != uTextStingIDThreat )
				{
					pxTitleTextElement->SetTextID( uTextStingIDThreat );
				}
			}
		}

		uTitleEnumID = AVP_GUIMenu_System::RECON_HEALTH;
		pxTitleRootItem = AVP_GUIMenu_System::GetHUDElement( uTitleEnumID, s_uPREDATOR_HUD, false );
		if( pxTitleRootItem )
		{
			Asura_GUIMenu_Element_Text* pxTitleTextElement = static_cast<Asura_GUIMenu_Element_Text*>( pxTitleRootItem );
			if( pxTitleTextElement )
			{
				pxTitleTextElement->SetText( awcUnicodeString );
			}
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::PlayModeActivationSound
// Scope		: Public 
// Author       : Callum Hope
// Date         : 21-Jan-2009
//
// Desc			: Plays a little sound when a prey entity is selected and the mode is activated. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::PlayModeActivationSound()
{
	if( m_pxActivateSound )
	{
		Asura_Sound_Event_System::PlayEvent( m_pxActivateSound, NULL);
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::PlayModeDeActivationSound
// Scope		: Public 
// Author       : Callum Hope
// Date         : 21-Jan-2009
//
// Desc			: Plays a little sound when the mode is Deactivated without selecting a target position
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::PlayModeDeActivationSound()
{
	if( m_pxDeActivateSound )
	{
		Asura_Sound_Event_System::PlayEvent( m_pxDeActivateSound, NULL);
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::SetSoundHandle
// Scope		: Public 
// Author       : Callum Hope
// Date         : 
//
// Desc			: 
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_Recon::SetSoundHandle( Asura_Handle iSoundEventHandle )
{
	if( iSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( m_iDistSoundEventHandle != ASURA_INVALID_HANDLE )
		{
			if( GetDistractionSoundPlaying() )
			{
				// if we already have a sound handle to a playing sound then stop it with a small fade out and assign to Prev handle holder
				Asura_Sound_Event_System::Stop( m_iDistSoundEventHandle, 1.0f );
				m_iPrevSoundEventHandle = m_iDistSoundEventHandle;
			}
		}

		// Now we are free to assign the new handle passed to our stored data. 
		m_iDistSoundEventHandle = iSoundEventHandle;
	}
	else
	{
		Asura_Assert( false, "AVP_Predator_Recon::SetSoundHandle\n Recon Mode sound being set but no sound handle has been found. " );
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_Recon::GetDistractionSoundPlaying
// Scope		: Public 
// Author       : Callum Hope
// Date         : 
//
// Desc			: 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_Recon::GetDistractionSoundPlaying()
{
	if( m_iDistSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( Asura_Sound_Event_System::IsPlaying( m_iDistSoundEventHandle ) )
		{
			return true;
		}
		else
		{
			// else the sound has finsihed so free the handle, default to NULL and return false below.
			Asura_Sound_Event_System::FinishedWithHandle( m_iDistSoundEventHandle );
			m_iDistSoundEventHandle = ASURA_INVALID_HANDLE;
		}
	}

	// tidy up here incase we have an old handle to event that has now finished, free the handle. 
	if( m_iPrevSoundEventHandle != ASURA_INVALID_HANDLE )
	{
		if( ! Asura_Sound_Event_System::IsPlaying( m_iPrevSoundEventHandle ) )
		{
			Asura_Sound_Event_System::FinishedWithHandle( m_iPrevSoundEventHandle );
			m_iPrevSoundEventHandle = ASURA_INVALID_HANDLE;
		}
	}

	// else the handle is already (or is now) NULL so its not palying. 
	return false;
}

////////////////////////////////////////////////////////////////////////////////
/// End of file. ///
////////////////////////////////////////////////////////////////////////////////
