//////////////////////////////////////////////////////////////////////////////
//
// AVP_Knowledge_System_Actor.cpp
//
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Knowledge/AVP_Knowledge_System_Actor.h"

// asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Rendering/Asura_Font_System.h"
#include "Debugging/Asura_DebugLineRender.h"
#endif

// avp
#include "Actor/Vertebrates/Predator/AVP_Predator_Recon.h"
#include "Core/BrainTypes/AVP_Brain_Actor.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Locations/ShootAt/AVP_ServerEntity_ShootAt.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Alien/AVP_ServerActor_Alien.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/Marine/AVP_ServerActor_Marine.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"


// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Civilian.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Predator.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Sentrygun.h"
#include "Knowledge/Axon_Knowledge.h"
#include "Knowledge/SenseTypes/AVP_Sense_Hearing_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_Vision_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_MotionTracker.h"
#include "Tactical/AVP_Tactical_System.h"

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Knowledge_System_Actor
//
//////////////////////////////////////////////////////////////////////////////

float AVP_Knowledge_System_Actor::s_fAggressiveToActiveTime		= 10.0f;
float AVP_Knowledge_System_Actor::s_fActiveToPassiveTime		= 20.0f;
float AVP_Knowledge_System_Actor::s_fVisibleCloakedRngSq		= 8.0f;

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Constructor
//---------------------------------------------------------------------------
AVP_Knowledge_System_Actor::AVP_Knowledge_System_Actor( AVP_Brain_Actor* pxBrain )
: PARENT( pxBrain )
, m_xBestThreatKnowledge()
, m_pxReconKnowledge( NULL )
, m_pxCorpseKnowledge( NULL )
, m_pxSecondaryThreatKnowledge( NULL )
, m_uNumSecondaryThreats( 0 )
, m_xBestAlertKnowledge()
, m_eAlertLevel(PASSIVE_ALERTNESS )
, m_fAlertLevelTimer( 0.0f )
, m_bShootAtScriptedTarget( false )
, m_bScriptedTargetIsShootAtPoint( false )
, m_pxScriptedTargetKnowledge( NULL )
, m_bEverBeenAggressive( false )
, m_fReconResetTimer( 0.0f )
, m_fCorpseResetTimer( 0.0f )
, m_pxMotionTracker( NULL )

{
	ResetAlertTimer();
	m_xBestThreatKnowledge.Reset();
	m_xBestAlertKnowledge.Reset();
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Deconstructor
//---------------------------------------------------------------------------
AVP_Knowledge_System_Actor::~AVP_Knowledge_System_Actor()
{
	if ( m_pxScriptedTargetKnowledge )
	{
		DestroyKnowledge( m_pxScriptedTargetKnowledge );
		m_pxScriptedTargetKnowledge = NULL;
	}

	if (m_pxSecondaryThreatKnowledge)
	{
		delete [] m_pxSecondaryThreatKnowledge;
		m_pxSecondaryThreatKnowledge = NULL;
	}

	if ( m_pxReconKnowledge )
	{
		DestroyKnowledge( m_pxReconKnowledge );
		m_pxReconKnowledge = NULL;
	}

	if ( m_pxCorpseKnowledge )
	{
		DestroyKnowledge( m_pxCorpseKnowledge );
		m_pxCorpseKnowledge = NULL;
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Verify
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
bool AVP_Knowledge_System_Actor::Verify()
{
	Asura_Assert( m_pxVision, "AVP_Knowledge_System_Actor::Verify - no vision" );
	Asura_Assert( m_pxHearing, "AVP_Knowledge_System_Actor::Verify - no hearing" );
	return ( PARENT::Verify() && m_pxVision && m_pxHearing );
}
#endif

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Initialise
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::Initialise()
{
	PARENT::Initialise();

	AVP_ServerActor_Marine* pxMarine = static_cast<AVP_ServerActor_Marine*>( GetActorBrain()->GetActor() );

	if ( pxMarine )
	{
		if ( pxMarine->GetHasMotionTracker() )
		{
			m_pxMotionTracker = CreateMotionTrackerSense();
		}
	}

	m_xBestThreatKnowledge.Reset();
	m_xBestAlertKnowledge.Reset();
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Shutdown
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::Shutdown( void )
{
	PARENT::Shutdown();

	if ( m_pxMotionTracker )
	{
		DestroyMotionTrackerSense( m_pxMotionTracker );
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: InitialiseFromBlueprint
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint )
{
	PARENT::InitialiseFromBlueprint( xBlueprint );
	
	if (m_pxMotionTracker) { m_pxMotionTracker->InitialiseFromBlueprint( xBlueprint ); }
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: ReadFromChunkStream
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
    int iVersion;
    xStream >> iVersion;

    PARENT::ReadFromChunkStream( xStream );

    if ( iVersion == CURRENT_CHUNK_VERSION )
    {

    }
    else
    {
        Asura_Assertf( iVersion == CURRENT_CHUNK_VERSION, ( "AVP_Knowledge_System_Actor::ReadFromChunkStream - unhandled chunk version (%d)", iVersion ) );
    }
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: WriteToChunkStream
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
    xStream << CURRENT_CHUNK_VERSION;

    PARENT::WriteToChunkStream( xStream );
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: Update
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::Update(const float fTimeslice)
{
	PARENT::Update(fTimeslice);
	
	if ( m_pxMotionTracker ) 
	{
		m_pxMotionTracker->Update( fTimeslice );
	}

	if ( m_fReconResetTimer > 0.0f )
	{
		m_fReconResetTimer -= fTimeslice;
	}
	else
	{
		m_fReconResetTimer = 0.0f;
		ResetReconKnowledge();
	}

	if ( m_fCorpseResetTimer > 0.0f )
	{
		m_fCorpseResetTimer -= fTimeslice;
	}
	else
	{
		m_fCorpseResetTimer = 0.0f;
		ResetCorpseKnowledge();
	}

	UpdateAlertLevel(fTimeslice);

	if ( ShootAtScriptedTarget() )
	{
		UpdateScriptedTargetKnowledge();
		m_xBestThreatKnowledge = *m_pxScriptedTargetKnowledge;
	}
	else
	{
		UpdateBestKnowledge(fTimeslice);
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdateScriptedTargetKnowledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::UpdateScriptedTargetKnowledge( void )
{
	if ( !ScriptedTargetIsShootAtPoint() )
	{
		AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( m_pxScriptedTargetKnowledge->GetGuid() );

		if ( pxActor )
		{
			m_pxScriptedTargetKnowledge->m_xPosition = pxActor->GetPosition();
		}

		SetAlertLevel( AGGRESSIVE_ALERTNESS );
		ResetAlertTimer();
	}

	AVP_ServerEntity_Actor* pxActor = GetActorBrain()->GetActor();

	Asura_Vector_3 xHeadPos( Asura_Maths::ZeroVector3 );
	pxActor->GetHeadPosition( xHeadPos );
	Asura_Vector_3 xTestDirection = ( m_pxScriptedTargetKnowledge->m_xPosition - xHeadPos );
	float fDistance = xTestDirection.Normalise();

	const Asura_LOS_InputData	xInput = Asura_LOS_InputData( xHeadPos, xTestDirection, pxActor->GetGuid(), fDistance, false );
	const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEnvironment(&xInput);

	// Check to see if we have hit our threat
	if ( pxOutput->m_fDistanceToIntersection == fDistance )
	{
		m_pxScriptedTargetKnowledge->m_uTypeInformation = AVP_Sense_Vision::TYPE_INFO_CAN_SEE;
	}
	else
	{
		m_pxScriptedTargetKnowledge->m_uTypeInformation = AVP_Sense_Vision::TYPE_INFO_CANT_SEE;
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdateAlertLevel
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::UpdateAlertLevel(const float fTimeslice)
{
	m_fAlertLevelTimer += fTimeslice;

	switch (GetAlertLevel())
	{
		case ACTIVE_ALERTNESS:
		{
			if (m_fAlertLevelTimer > s_fActiveToPassiveTime)
			{
				if (GetBestThreatKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED && GetBestAlertKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED)
				{
					ResetAlertTimer();
					SetAlertLevel(PASSIVE_ALERTNESS);
					
					if ( !m_bEverBeenAggressive )
					{
						AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity(m_pxBrain->GetOwnerGuid());

						if (pxHuman)
						{
							if ((pxHuman->GetClassification() == AVP_ENTITYCLASS_MARINE) || (pxHuman->GetClassification() == AVP_ENTITYCLASS_ANDROID) || (pxHuman->GetClassification() == AVP_ENTITYCLASS_CIVILIAN))
							{
								pxHuman->PlayDialogue(AVP_ServerActor_Human::AVP_DLG_HUMAN_ALERT_TO_PASSIVE);
							}
						}
					}
				}
			}
		}break;

		case AGGRESSIVE_ALERTNESS:
		{
			m_bEverBeenAggressive = true;

			if (m_fAlertLevelTimer > s_fAggressiveToActiveTime)
			{
				if (GetBestThreatKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED && GetBestAlertKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED)
				{
					ResetAlertTimer();
					SetAlertLevel(ACTIVE_ALERTNESS);

					AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity(m_pxBrain->GetOwnerGuid());

					if (pxHuman)
					{
						if ((pxHuman->GetClassification() == AVP_ENTITYCLASS_MARINE) || (pxHuman->GetClassification() == AVP_ENTITYCLASS_ANDROID) || (pxHuman->GetClassification() == AVP_ENTITYCLASS_CIVILIAN))
						{
							pxHuman->PlayDialogue(AVP_ServerActor_Human::AVP_DLG_HUMAN_AGGRESSIVE_TO_ALERT);
						}
					}
				}
			}
		}break;

		default:
		{

		}
		break;
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdateBestKnwoledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::UpdateKnowledgeSettings( KnowledgeSettings* pxKnowledgeSettings )
{
	(static_cast<AVP_Sense_Vision*>(m_pxVision))->UpdateKnowlegdeSettings( pxKnowledgeSettings );
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdateBestKnwoledge
//---------------------------------------------------------------------------
bool AVP_Knowledge_System_Actor::HandleMessage( const Asura_Message* pxMessage )
{
	switch ( pxMessage->GetMsgID() )
	{
// 		case AVP_MSGID_HUMANOID_DIED:
// 		{
// // 			AVP_ServerActor_Human* pxDeadHuman = AVP_ServerActor_Human::FindEntity( pxMessage->GetFromGuid() );
// // 			AVP_ServerActor_Human* pxOurActor = static_cast<AVP_ServerActor_Human*>( GetActorBrain()->GetActor() );
// // 
// // 			if ( pxDeadHuman && pxOurActor)
// // 			{
// // 				Asura_Vector_3 xDeadHumanChest( Asura_Maths::ZeroVector3 );
// // 				Asura_Vector_3 xOurActorHead( Asura_Maths:: ZeroVector3 );
// // 
// // 				pxDeadHuman->GetChestPosition( xDeadHumanChest );
// // 				pxOurActor->GetHeadPosition( xOurActorHead );
// // 
// // 				Asura_Vector_3	xDirection = ( xDeadHumanChest - xOurActorHead );
// // 				float			fDistance = xDirection.Normalise();
// // 
// // 				const Asura_LOS_InputData	xInput = Asura_LOS_InputData( xOurActorHead, xDirection, pxOurActor->GetGuid(), fDistance, false );
// // 				const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEnvironment(&xInput);
// // 
// // 				if ( pxOutput->m_fDistanceToIntersection == fDistance )
// // 				{
// // 					// Add knowledge
// // 					Axon_Knowledge* pxKnowledge = CreateKnowledge();
// // 
// // 					if ( pxKnowledge )
// // 					{
// // 						Asura_Vector_3 xCorpseTargetPos( xDeadHumanChest );
// // 
// // 						ResetAlertTimer();
// // 
// // 						pxKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
// // 						pxKnowledge->m_uSourceGuid           = pxMessage->GetFromGuid();
// // 						pxKnowledge->m_uSourceClassification = pxDeadHuman->GetClassification();
// // 						pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_HEARING;
// // 						pxKnowledge->m_uTypeInformation		 = AVP_SOUND_TYPE_HUMAN_HURT;
// // 						pxKnowledge->m_fAge                  = 0.0f;
// // 						pxKnowledge->m_fThreatValue          = 0.0f;
// // 						pxKnowledge->m_xPosition             = xDeadHumanChest;
// // 						pxKnowledge->m_xDirection            = xDirection;
// // 						pxKnowledge->m_fDistance             = fDistance;
// // 
// // 						m_pxCorpseKnowledge = pxKnowledge;
// // 						m_fCorpseResetTimer = 2.0f;
// // 					}
// // 				}
// //			}
// 
// 			return true;
// 			
// 		}break;

		default:
		{
			return PARENT::HandleMessage( pxMessage );

		}break;
	}

}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdateBestKnwoledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::UpdateBestKnowledge(const float fTimeslice)
{
	AVP_ServerEntity_Actor* pxOurActor = GetActorBrain()->GetActor();

	if (!pxOurActor)
	{
		return;
	}

	m_xBestThreatKnowledge.Reset();
	m_xBestAlertKnowledge.Reset(); 

	Axon_Knowledge xBestCanSeeKnowledge;
	Axon_Knowledge xBestCantSeeKnowledge;

	xBestCanSeeKnowledge.Reset();
	xBestCantSeeKnowledge.Reset();

	float	fBestCanSeeDistanceSq	= Asura_Maths::LargeFloat;
	float	fBestCantSeeDistanceSq	= Asura_Maths::LargeFloat;
	int		iBestCanSeePriority		= AVP_AI_TargetPriorityData::IGNORE_P;
	int		iBestCantSeePriority	= AVP_AI_TargetPriorityData::IGNORE_P;

	u_int uNumEntries					= m_pxVision->GetList()->GetNumEntries();

	bool bSmartGun = false;

	if ( pxOurActor->GetClassification() == AVP_ENTITYCLASS_ANDROID || pxOurActor->GetClassification() == AVP_ENTITYCLASS_MARINE )
	{
		if ( ( static_cast<AVP_Brain_Actor_Marine*>( GetActorBrain() ) )->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SMARTGUN )
		{
			bSmartGun = true;
		}
	}

	// Vision!
	if ( !bSmartGun )
	{
		for ( Asura_Hashed_List_ConstIt< Axon_Knowledge > xVisionIt( m_pxVision->GetList() ); !xVisionIt.Done(); xVisionIt.Next() )
		{
			// Use the closest enemy entity as our threat for now
			const Axon_Knowledge* pxKnowledge = xVisionIt.GetCurrent();
			Asura_Assert( pxKnowledge, "AVP_Knowledge_System::UpdateBestKnowledge: invalid vision knowledge" );

			if ( pxKnowledge )
			{
				if ( pxKnowledge->m_fAge < 0.5f )
				{
					continue;
				}

				AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity( pxKnowledge->GetGuid() );

				if (!pxThreatActor)
				{
					continue;
				}

				const Asura_Vector_3&		xThreatPos			= pxThreatActor->GetPosition();
				Asura_Vector_3				xThreatDirection	= xThreatPos - pxOurActor->GetPosition();
				const float					fDistanceSq			= xThreatDirection.MagnitudeSquared();
				bool						bIgnorePriority		= false;

				// Check the targets priority
				int iTargetPriority = AVP_AI_TargetPriorityData::NORMAL;

				iTargetPriority = GetTargetPriority( pxKnowledge->GetGuid() );
			
				if ( iTargetPriority == AVP_AI_TargetPriorityData::IGNORE_P )
				{
					continue;
				}

				if ( pxThreatActor->IsPlayer() && uNumEntries > 3 && fDistanceSq > 100.0f )
				{
					continue;
				}

				if ( fDistanceSq < 100.0f )
				{
					bIgnorePriority = true;
				}

				if (bIgnorePriority)
				{
					if ( pxKnowledge->m_uTypeInformation != AVP_Sense_Vision::TYPE_INFO_CANT_SEE )
					{
						if (fDistanceSq < fBestCanSeeDistanceSq)
						{
							fBestCanSeeDistanceSq = fDistanceSq;
							xBestCanSeeKnowledge  = *pxKnowledge;
						}
					}
					else if ( pxKnowledge->m_uTypeInformation != AVP_Sense_Vision::TYPE_INFO_CAN_SEE )
					{
						if (fDistanceSq < fBestCantSeeDistanceSq)
						{
							fBestCantSeeDistanceSq = fDistanceSq;
							xBestCantSeeKnowledge  = *pxKnowledge;
						}
					}
				}
				else
				{
					if ( pxKnowledge->m_uTypeInformation != AVP_Sense_Vision::TYPE_INFO_CANT_SEE )
					{
						if ( iTargetPriority > iBestCanSeePriority )
						{
							xBestCanSeeKnowledge	= *pxKnowledge;
							iBestCanSeePriority		= iTargetPriority;
						}
						else if (iTargetPriority == iBestCanSeePriority)
						{
							if (fDistanceSq < fBestCanSeeDistanceSq)
							{
								fBestCanSeeDistanceSq	= fDistanceSq;
								xBestCanSeeKnowledge	= *pxKnowledge;
							}
						}
					
					}
					else if ( pxKnowledge->m_uTypeInformation != AVP_Sense_Vision::TYPE_INFO_CAN_SEE )
					{
						if ( iTargetPriority > iBestCantSeePriority )
						{
							xBestCantSeeKnowledge	= *pxKnowledge;
							iBestCantSeePriority	= iTargetPriority;
						}
						else if (iTargetPriority == iBestCantSeePriority)
						{
							if (fDistanceSq < fBestCantSeeDistanceSq)
							{
								fBestCantSeeDistanceSq	= fDistanceSq;
								xBestCantSeeKnowledge	= *pxKnowledge;
							}
						}
					}
				}
			}
		}
	}
	else
	{
		float	fBestCanSeeDistanceSq	= 0.0f;
		float	fBestCantSeeDistanceSq	= 0.0f;

		for ( Asura_Hashed_List_ConstIt< Axon_Knowledge > xVisionIt( m_pxVision->GetList() ); !xVisionIt.Done(); xVisionIt.Next() )
		{
			// Use the closest enemy entity as our threat for now
			const Axon_Knowledge* pxKnowledge = xVisionIt.GetCurrent();
			Asura_Assert( pxKnowledge, "AVP_Knowledge_System::UpdateBestKnowledge: invalid vision knowledge" );

			if ( pxKnowledge )
			{
				if ( pxKnowledge->m_fAge < 0.5f )
				{
					continue;
				}

				AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity( pxKnowledge->GetGuid() );

				if (!pxThreatActor)
				{
					continue;
				}

				const Asura_Vector_3&		xThreatPos			= pxThreatActor->GetPosition();
				Asura_Vector_3				xThreatDirection	= xThreatPos - pxOurActor->GetPosition();
				const float					fDistanceSq			= xThreatDirection.MagnitudeSquared();
				bool						bIgnorePriority		= false;

				// Check the targets priority
				int iTargetPriority = AVP_AI_TargetPriorityData::NORMAL;

				iTargetPriority = GetTargetPriority( pxKnowledge->GetGuid() );

				if ( iTargetPriority == AVP_AI_TargetPriorityData::IGNORE_P )
				{
					continue;
				}

				if ( pxThreatActor->IsPlayer() && uNumEntries > 3 && fDistanceSq > 100.0f )
				{
					continue;
				}

				if ( fDistanceSq < 100.0f )
				{
					bIgnorePriority = true;
				}

				if (bIgnorePriority)
				{
					if ( pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE || pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_LASER)
					{
						if (fDistanceSq > fBestCanSeeDistanceSq)
						{
							fBestCanSeeDistanceSq = fDistanceSq;
							xBestCanSeeKnowledge  = *pxKnowledge;
						}
					}
					else if ( pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CANT_SEE || pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_LASER)
					{
						if (fDistanceSq > fBestCantSeeDistanceSq)
						{
							fBestCantSeeDistanceSq = fDistanceSq;
							xBestCantSeeKnowledge  = *pxKnowledge;
						}
					}
				}
				else
				{
					if ( pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE || pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_LASER)
					{
						if ( iTargetPriority > iBestCanSeePriority )
						{
							xBestCanSeeKnowledge	= *pxKnowledge;
							iBestCanSeePriority		= iTargetPriority;
						}
						else if (iTargetPriority == iBestCanSeePriority)
						{
							if (fDistanceSq > fBestCanSeeDistanceSq)
							{
								fBestCanSeeDistanceSq	= fDistanceSq;
								xBestCanSeeKnowledge	= *pxKnowledge;
							}
						}

					}
					else if ( pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CANT_SEE || pxKnowledge->m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_LASER)
					{
						if ( iTargetPriority > iBestCantSeePriority )
						{
							xBestCantSeeKnowledge	= *pxKnowledge;
							iBestCantSeePriority	= iTargetPriority;
						}
						else if (iTargetPriority == iBestCantSeePriority)
						{
							if (fDistanceSq > fBestCantSeeDistanceSq)
							{
								fBestCantSeeDistanceSq	= fDistanceSq;
								xBestCantSeeKnowledge	= *pxKnowledge;
							}
						}
					}
				}
			}
		}
	}

	if ( xBestCanSeeKnowledge.GetGuid() != ASURA_GUID_UNREGISTERED )
	{
		m_xBestThreatKnowledge = xBestCanSeeKnowledge;

		SetAlertLevel( AGGRESSIVE_ALERTNESS );
		ResetAlertTimer();
	}
	else if ( xBestCantSeeKnowledge.GetGuid() != ASURA_GUID_UNREGISTERED )
	{
		m_xBestThreatKnowledge = xBestCantSeeKnowledge;

		SetAlertLevel( AGGRESSIVE_ALERTNESS );
		ResetAlertTimer();
	}

	// Build an array of secondary threats
	if ( ( m_xBestThreatKnowledge.GetGuid() != ASURA_GUID_UNREGISTERED ) && ( uNumEntries > 1 ) )
	{
		BuildSecondaryThreatArray(uNumEntries);
	}

	SetSquadTarget( m_xBestThreatKnowledge.GetGuid() );

	// Finds the closest sound to them for both threat sounds and alert sounds
	float fClosestAlertThreatDistSq	= Asura_Maths::LargeFloat;

	// Sound!
	for ( Asura_List_ConstIt< Axon_Knowledge > xHearingIt( m_pxHearing->GetList() ); !xHearingIt.Done(); xHearingIt.Next() )
	{
		const Axon_Knowledge* pxKnowledge = xHearingIt.GetCurrent();	
		
		if (pxKnowledge)
		{
			int iTargetPriority = AVP_AI_TargetPriorityData::NORMAL;

			iTargetPriority = GetTargetPriority( pxKnowledge->GetGuid() );
		
			if ( iTargetPriority == AVP_AI_TargetPriorityData::IGNORE_P )
			{
				continue;
			}

			const float fDistanceSq = ( pxKnowledge->m_xPosition - pxOurActor->GetPosition() ).MagnitudeSquared();

			// Pick the closest one
			if ( fDistanceSq < fClosestAlertThreatDistSq )
			{
				fClosestAlertThreatDistSq = fDistanceSq;
				m_xBestAlertKnowledge	  = *pxKnowledge;
			}
		}
	}

	if ( m_pxMotionTracker )
	{
		for ( Asura_Hashed_List_ConstIt< Axon_Knowledge > xMTIt( m_pxMotionTracker->GetList() ); !xMTIt.Done(); xMTIt.Next() )
		{
			const Axon_Knowledge* pxKnowledge = xMTIt.GetCurrent();	

			if (pxKnowledge)
			{
				const float fDistanceSq = ( pxKnowledge->m_xPosition - pxOurActor->GetPosition() ).MagnitudeSquared();

				// Pick the closest one
				if ( fDistanceSq < fClosestAlertThreatDistSq )
				{
					fClosestAlertThreatDistSq = fDistanceSq;
					m_xBestAlertKnowledge	  = *pxKnowledge;
				}
			}
		}
	}

	if ( m_pxReconKnowledge )
	{
		if ( m_xBestAlertKnowledge.GetGuid() == ASURA_GUID_UNREGISTERED && m_pxReconKnowledge->GetGuid() != ASURA_GUID_UNREGISTERED )
		{
			m_xBestAlertKnowledge = *m_pxReconKnowledge;
		}
	}

	if ( m_pxCorpseKnowledge )
	{
		if ( m_xBestAlertKnowledge.GetGuid() == ASURA_GUID_UNREGISTERED && m_pxCorpseKnowledge->GetGuid() != ASURA_GUID_UNREGISTERED )
		{
			m_xBestAlertKnowledge = *m_pxCorpseKnowledge;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: BuildSecondaryThreatarray
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::BuildSecondaryThreatArray(u_int uNumEntries)
{
	m_uNumSecondaryThreats = 0;
	if (m_pxSecondaryThreatKnowledge)
	{
		delete [] m_pxSecondaryThreatKnowledge;
		m_pxSecondaryThreatKnowledge = NULL;
	}

	if (uNumEntries <= 1)
	{
		Asura_Assert( false, "AVP_Knowledge_System_Actor :: BuildSecondaryThreatArray - there are no secondary threats, shoudln't have been able to get here" );
		return;
	}

	// Clear secondary threat data
	m_pxSecondaryThreatKnowledge = new Axon_Knowledge[uNumEntries - 1];

	// reset the elements of the secondary threat array
	for ( u_int u = 0; u < uNumEntries - 1; ++u )
	{
		m_pxSecondaryThreatKnowledge[u].Reset();
	}

	// do a second iteration now we have found the primary threat
	for ( Asura_Hashed_List_ConstIt< Axon_Knowledge > xVisionIt( m_pxVision->GetList() ); !xVisionIt.Done(); xVisionIt.Next() )
	{
		// Use the closest enemy entity as our threat for now
		const Axon_Knowledge* pxKnowledge = xVisionIt.GetCurrent();
		Asura_Assert( pxKnowledge, "AVP_Knowledge_System::UpdateBestKnowledge: invalid vision knowledge" );

		if ( ( pxKnowledge ) && ( pxKnowledge->GetGuid() != m_xBestThreatKnowledge.GetGuid() ) )
		{
			if ( pxKnowledge->m_fAge < 0.5f )
			{
				continue;
			}

			m_pxSecondaryThreatKnowledge[m_uNumSecondaryThreats] = *pxKnowledge;
			++m_uNumSecondaryThreats;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: GetTargetPriority
//---------------------------------------------------------------------------
int	AVP_Knowledge_System_Actor::GetTargetPriority( Asura_Guid uThreatGuid )
{
	if ( uThreatGuid == ASURA_GUID_UNREGISTERED ) { return AVP_AI_TargetPriorityData::IGNORE_P; }

	AVP_ServerEntity_Actor*		pxThreatActor	= AVP_ServerEntity_Actor::FindEntity( uThreatGuid );

	if ( !pxThreatActor ) 
	{
		return AVP_AI_TargetPriorityData::NORMAL;
	}

	AVP_ServerEntity_Actor*		pxOurActor		= GetActorBrain()->GetActor();
	int							iPriority		= AVP_AI_TargetPriorityData::NORMAL;
	bool						bInValidSquad	= false;
	bool						bUseSquads		= false;
	AVP_ServerEntity_Squad*		pxSquad			= AVP_ServerEntity_Squad::FindEntity( pxOurActor->GetInitialSquadGuid() );

	if ( pxSquad )
	{
		bInValidSquad = true;
	}

	// Actors priority always overrides squads.
	if ( !GetActorBrain()->CalcTargetingPriority( pxThreatActor->GetClassification(), pxThreatActor->GetGuid(), iPriority ) )
	{
		if ( bInValidSquad )
		{
			bUseSquads = true;
		}
	}
	else
	{
		return iPriority;
	}

	if ( bUseSquads )
	{
		int iSquadsPriority = AVP_AI_TargetPriorityData::NORMAL;

		if ( bInValidSquad )
		{
			if ( !pxSquad->CalcTargetingPriority( pxThreatActor->GetClassification(), pxThreatActor->GetGuid(), iSquadsPriority ) )
			{
				return AVP_AI_TargetPriorityData::NORMAL;
			}
			else
			{
				return iSquadsPriority;
			}
		}
	}

	return AVP_AI_TargetPriorityData::NORMAL;
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: SquadAlreadyHasThisTarget
//---------------------------------------------------------------------------
bool AVP_Knowledge_System_Actor::SquadAlreadyHasThisTarget( u_int uNumThreats, Asura_Guid uThreatGuid )
{
	// validated by the brain every frame
	AVP_ServerEntity_Actor* pxOurActor = GetActorBrain()->GetActor();

	if ( pxOurActor->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED || ( pxOurActor->GetClassification() != AVP_ENTITYCLASS_ANDROID && pxOurActor->GetClassification() != AVP_ENTITYCLASS_MARINE ) )
	{
		return false;
	}

	AVP_ServerEntity_Squad_Marine* pxSquad = AVP_ServerEntity_Squad_Marine::FindEntity( pxOurActor->GetInitialSquadGuid() );

	if ( !pxSquad )
	{
		return false;
	}

	int iNumRemainingThreats = ( int )( uNumThreats - pxSquad->GetNumSquadMembers() );

	if (iNumRemainingThreats >= 0)
	{
		for ( int i = 0; i < (int)pxSquad->GetNumSquadMembers(); ++i )
		{
			if ( pxSquad->GetMemberGuid( i ) == pxOurActor->GetGuid() )
			{
				Asura_Guid uOurCurrentThreatGuid = pxSquad->GetTarget( i );

				if ( uOurCurrentThreatGuid == uThreatGuid )
				{
					return false;
				}
			}
			else
			{
				Asura_Guid uSquadThreatGuid = pxSquad->GetTarget( i );

				if ( uSquadThreatGuid == uThreatGuid )
				{
					AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity( uThreatGuid );

					if ( pxThreatActor )
					{
						Asura_Vector_3 xOurChest(Asura_Maths::ZeroVector3);
						pxOurActor->GetChestPosition(xOurChest);
						Asura_Vector_3 xThreatChest(Asura_Maths::ZeroVector3);
						pxThreatActor->GetChestPosition(xThreatChest);
						Asura_Vector_3 xDirection = xThreatChest - xOurChest;
						float fDistance = xDirection.Normalise();

						const Asura_LOS_InputData	xInput(xOurChest, xDirection, pxOurActor->GetGuid(), fDistance, false );
						const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEnvironment(&xInput);

						if (pxOutput->m_fDistanceToIntersection >= fDistance)
						{
							return false;
						}
					}

					return true;
				}
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: SetSquadTarget
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::SetSquadTarget( Asura_Guid uThreatGuid )
{
	// validated by the brain every frame
	AVP_ServerEntity_Actor* pxOurActor = GetActorBrain()->GetActor();

	if ( pxOurActor->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED || ( pxOurActor->GetClassification() != AVP_ENTITYCLASS_ANDROID && pxOurActor->GetClassification() != AVP_ENTITYCLASS_MARINE ) )
	{
		return;
	}

	AVP_ServerEntity_Squad_Marine* pxSquad = AVP_ServerEntity_Squad_Marine::FindEntity( pxOurActor->GetInitialSquadGuid() );

	if ( !pxSquad )
	{
		return;
	}

	for ( int i = 0; i < (int)pxSquad->GetNumSquadMembers(); ++i )
	{
		if ( pxSquad->GetMemberGuid( i ) == pxOurActor->GetGuid() )
		{
			pxSquad->SetTarget(uThreatGuid, i );
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: RenderDebugInfo
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
void AVP_Knowledge_System_Actor::RenderDebugInfo()
{
}
#endif

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: UpdatePlayerAlienAlertStatus
//---------------------------------------------------------------------------
bool AVP_Knowledge_System_Actor::UpdatePlayerAlienAlertStatus()
{
	for (Asura_Hashed_List_It<AVP_ServerActor_Vertebrate> it(AVP_ServerActor_Vertebrate::GetList()); !it.Done(); it.Next())
	{
		AVP_ServerActor_Vertebrate* pxVertebrate = it.GetCurrent();

		if (pxVertebrate)
		{
			if (pxVertebrate->IsPlayer())
				continue;

			if (!pxVertebrate->GetActorBrain())
				continue;

			if (pxVertebrate->IsDead())
				continue;

			if ((pxVertebrate->GetClassification() != AVP_ENTITYCLASS_ALIEN) && 
				(pxVertebrate->GetClassification() != AVP_ENTITYCLASS_ALIENFACEHUGGER) &&
				(pxVertebrate->GetClassification() != AVP_ENTITYCLASS_PREDATOR) ) // predator has its own knowledge system
			{
				// Don't want to do this as most of the code is common, but can't think of another way around it.
				switch (pxVertebrate->GetClassification())
				{
					case AVP_ENTITYCLASS_MARINE:
					case AVP_ENTITYCLASS_ANDROID:
					{
						AVP_Brain_Actor_Marine* pxBrain = (AVP_Brain_Actor_Marine*)pxVertebrate->GetActorBrain();

						if (pxBrain)
						{
							if ((pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED) &&
								(pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().m_uSourceClassification == AVP_ENTITYCLASS_ALIEN))
							{
								AVP_ServerActor_Alien* pxPlayerAlien = AVP_ServerActor_Alien::FindEntity(pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().GetGuid());

								if (pxPlayerAlien)
								{
									if (pxPlayerAlien->IsPlayer())
									{
										return true;
									}
									else
									{
										pxPlayerAlien = NULL;
										continue;
									}
								}
							}
							else
							{
								continue;
							}
						}
					}break;

					case AVP_ENTITYCLASS_CIVILIAN:
					{
						AVP_Brain_Actor_Civilian* pxBrain = (AVP_Brain_Actor_Civilian*)pxVertebrate->GetActorBrain();

						if ((pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED) &&
							(pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().m_uSourceClassification == AVP_ENTITYCLASS_ALIEN))
						{
							AVP_ServerActor_Alien* pxPlayerAlien = AVP_ServerActor_Alien::FindEntity(pxBrain->GetKnowledgeSystem()->GetBestAlertKnowledge().GetGuid());

							if (pxPlayerAlien)
							{
								if (pxPlayerAlien->IsPlayer())
								{
									return true;
								}
								else
								{
									pxPlayerAlien = NULL;
									continue;
								}
							}
						}
						else
						{
							continue;
						}
					}break;
				}
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: StopAttackingScriptedTarget
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::StopAttackingScriptedTarget( void )
{
	if ( m_pxScriptedTargetKnowledge )
	{
		DestroyKnowledge( m_pxScriptedTargetKnowledge );
		m_pxScriptedTargetKnowledge = NULL;
	}

	SetShootAtScriptedTarget( false );
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: AddKnowledgeIfNeeded
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::SetScriptedTarget(Asura_Guid uGuid)
{
	AVP_ServerEntity_Actor* pxServerActor	= GetActorBrain()->GetActor();

	if ( m_pxScriptedTargetKnowledge )
	{
		DestroyKnowledge( m_pxScriptedTargetKnowledge );
		m_pxScriptedTargetKnowledge = NULL;
	}

	if ( ScriptedTargetIsShootAtPoint() )
	{
		AVP_ServerEntity_ShootAt* pxShootAt = AVP_ServerEntity_ShootAt::FindEntity( uGuid );

		if ( pxShootAt )
		{
			m_pxScriptedTargetKnowledge = CreateKnowledge();

			m_pxScriptedTargetKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
			m_pxScriptedTargetKnowledge->m_uSourceGuid           = pxShootAt->GetGuid();
			m_pxScriptedTargetKnowledge->m_uSourceClassification = pxShootAt->GetClassification();
			m_pxScriptedTargetKnowledge->m_iSenseID              = AXON_SENSE_TYPE_VISION;
			m_pxScriptedTargetKnowledge->m_uTypeInformation      = AVP_Sense_Vision::TYPE_INFO_NOT_SET;
			m_pxScriptedTargetKnowledge->m_fAge                  = 0.0f;
			m_pxScriptedTargetKnowledge->m_fThreatValue          = 0.0f;
			m_pxScriptedTargetKnowledge->m_xPosition             = pxShootAt->GetPosition();
			m_pxScriptedTargetKnowledge->m_xDirection            = pxShootAt->GetPosition() - pxServerActor->GetPosition();
			m_pxScriptedTargetKnowledge->m_fDistance             = m_pxScriptedTargetKnowledge->m_xDirection.Normalise();

			SetShootAtScriptedTarget(true);
		}
		else
		{
			SetShootAtScriptedTarget(false);
		}
	}
	else
	{
		AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( uGuid );

		if ( pxActor )
		{
			m_pxScriptedTargetKnowledge = CreateKnowledge();

			m_pxScriptedTargetKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
			m_pxScriptedTargetKnowledge->m_uSourceGuid           = pxActor->GetGuid();
			m_pxScriptedTargetKnowledge->m_uSourceClassification = pxActor->GetClassification();
			m_pxScriptedTargetKnowledge->m_iSenseID              = AXON_SENSE_TYPE_VISION;
			m_pxScriptedTargetKnowledge->m_uTypeInformation      = AVP_Sense_Vision::TYPE_INFO_NOT_SET;
			m_pxScriptedTargetKnowledge->m_fAge                  = 0.0f;
			m_pxScriptedTargetKnowledge->m_fThreatValue          = 0.0f;
			m_pxScriptedTargetKnowledge->m_xPosition             = pxActor->GetPosition();
			m_pxScriptedTargetKnowledge->m_xDirection            = pxActor->GetPosition() - pxServerActor->GetPosition();
			m_pxScriptedTargetKnowledge->m_fDistance             = m_pxScriptedTargetKnowledge->m_xDirection.Normalise();

			SetShootAtScriptedTarget(true);
		}
		else
		{
			SetShootAtScriptedTarget(false);
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: AddKnowledgeIfNeeded
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::AddKnowledgeIfNeeded(const Axon_Knowledge& xNewKnowledge)
{
	AVP_ServerEntity_Actor* pxServerActor	= GetActorBrain()->GetActor();
	AVP_ServerEntity_Actor*	pxActor			= AVP_ServerEntity_Actor::FindEntity(xNewKnowledge.GetGuid());
	bool bAdd = true;

	for (Asura_Hashed_List_It<Axon_Knowledge> xVisionIt(m_pxVision->GetList()); !xVisionIt.Done(); xVisionIt.Next())
	{
		// Use the closest enemy entity as our threat for now
		Axon_Knowledge* pxKnowledge = xVisionIt.GetCurrent();

		if (pxKnowledge)
		{
			if (pxKnowledge->GetGuid() == xNewKnowledge.GetGuid())
			{
				if ( pxKnowledge->m_fAge > xNewKnowledge.m_fAge )
				{
					pxKnowledge->m_xPosition = xNewKnowledge.m_xPosition;
					pxKnowledge->m_xDirection = ( pxKnowledge->m_xPosition - pxServerActor->GetPosition() );
					pxKnowledge->m_fAge = xNewKnowledge.m_fAge;
				}

				bAdd = false;
				break;
			}
		}
	}


	if (bAdd)
	{
		if (pxActor && pxServerActor && !pxServerActor->IsDead() && GetActorBrain()->IsActive())
		{
			Axon_Knowledge*	pxKnowledge	= CreateKnowledge();
			if ( pxKnowledge )
			{
				pxKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
				pxKnowledge->m_uSourceGuid           = pxActor->GetGuid();
				pxKnowledge->m_uSourceClassification = pxActor->GetClassification();
				pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_VISION;
				pxKnowledge->m_uTypeInformation      = AVP_Sense_Vision::TYPE_INFO_NOT_SET;
				pxKnowledge->m_fAge                  = xNewKnowledge.m_fAge;
				pxKnowledge->m_fThreatValue          = xNewKnowledge.m_fThreatValue;
				pxKnowledge->m_xPosition             = pxActor->GetPosition();
				pxKnowledge->m_xDirection            = pxActor->GetPosition() - pxServerActor->GetPosition();
				pxKnowledge->m_fDistance             = pxKnowledge->m_xDirection.Normalise();

				AVP_Sense_Vision* pxVisionSense = static_cast<AVP_Sense_Vision*>(m_pxVision);
				pxVisionSense->AddToVisionList(pxKnowledge);
			}

			m_eAlertLevel = AGGRESSIVE_ALERTNESS;
		}
	}
}

float AVP_Knowledge_System_Actor::GetVisionRange()
{
	AVP_Sense_Vision* pxVisionSense = static_cast<AVP_Sense_Vision*>(m_pxVision);

	if ( pxVisionSense )
	{
		switch (GetAlertLevel())
		{
			case (AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS):
			{
				if ( EverBeenAggressive() )
				{
					return pxVisionSense->GetActiveRange();
				}
				else
				{
					return pxVisionSense->GetPassiveRange();
				}
			}
			case (AVP_Knowledge_System_Actor::ACTIVE_ALERTNESS):
			{
				return pxVisionSense->GetActiveRange();
			}
			case (AVP_Knowledge_System_Actor::AGGRESSIVE_ALERTNESS):
			{
				return pxVisionSense->GetAggressiveRange();
			}
			default:
			{
				return pxVisionSense->GetRange();
			}
		}
	}

	return 0.0f;
}

float AVP_Knowledge_System_Actor::GetCloakedVisibleRangeSq(void)
{
	AVP_ServerEntity_Actor* pxServerActor	= GetActorBrain()->GetActor();

	if ( pxServerActor->GetClassification() == AVP_ENTITYCLASS_MARINE || pxServerActor->GetClassification() == AVP_ENTITYCLASS_ANDROID )
	{
		AVP_Brain_Actor_Marine* pxMarineBrain = static_cast<AVP_Brain_Actor_Marine*>( GetActorBrain() );

		if ( pxMarineBrain )
		{
			if ( pxMarineBrain->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SMARTGUN )
			{
				return 10000.0f;
			}
		}
	}
	
	return s_fVisibleCloakedRngSq;
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: AddKnowledgeIfNeeded
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::AddAlertKnowledgeIfNeeded(const Axon_Knowledge& xNewKnowledge)
{
	bool bAdd = true;

	for (Asura_List_ConstIt<Axon_Knowledge> xHearingIt(m_pxHearing->GetList()); !xHearingIt.Done(); xHearingIt.Next())
	{
		const Axon_Knowledge* pxKnowledge = xHearingIt.GetCurrent();

		if (pxKnowledge)
		{
			if (pxKnowledge->GetGuid() == xNewKnowledge.GetGuid())
			{
				bAdd = false;
				break;
			}
		}
	}

	if (bAdd)
	{
		AVP_ServerEntity_Actor* pxServerActor	= GetActorBrain()->GetActor();
		AVP_ServerEntity_Actor*	pxActor			= AVP_ServerEntity_Actor::FindEntity(xNewKnowledge.GetGuid());

		if (pxActor && pxServerActor && !pxServerActor->IsDead() && GetActorBrain()->IsActive())
		{
			Axon_Knowledge*	pxKnowledge	= CreateKnowledge();
			if ( pxKnowledge )
			{
				pxKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
				pxKnowledge->m_uSourceGuid           = pxActor->GetGuid();
				pxKnowledge->m_uSourceClassification = pxActor->GetClassification();
				pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_HEARING;
				pxKnowledge->m_uTypeInformation      = AVP_Sense_Vision::TYPE_INFO_NOT_SET;
				pxKnowledge->m_fAge                  = xNewKnowledge.m_fAge;
				pxKnowledge->m_fThreatValue          = xNewKnowledge.m_fThreatValue;
				pxKnowledge->m_xPosition             = pxActor->GetPosition();
				pxKnowledge->m_xDirection            = pxActor->GetPosition() - pxServerActor->GetPosition();
				pxKnowledge->m_fDistance             = pxKnowledge->m_xDirection.Normalise();

				AVP_Sense_Hearing* pxHearingSense = static_cast<AVP_Sense_Hearing*>(m_pxHearing);
				pxHearingSense->AddToHearingList(pxKnowledge);
			}

			m_eAlertLevel = AGGRESSIVE_ALERTNESS;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: DeleteCurrentAlertKnowledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::DeleteCurrentAlertKnowledge( const Asura_Guid uAlertGuid )
{
	for (Asura_List_ConstIt<Axon_Knowledge> xHearingIt(m_pxHearing->GetList()); !xHearingIt.Done(); xHearingIt.Next())
	{
		const Axon_Knowledge* pxKnowledge = xHearingIt.GetCurrent();

		if (pxKnowledge)
		{
			if (pxKnowledge->GetGuid() == uAlertGuid)
			{
				AVP_Sense_Hearing* pxHearingSense = static_cast<AVP_Sense_Hearing*>(m_pxHearing);
				if (pxHearingSense)
				{
					pxHearingSense->DeleteFromHearingList(pxKnowledge);
					m_xBestAlertKnowledge.Reset();
				}
				break;
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: AddReconModeKnowledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::AddReconModeKnowledge( void )
{
	AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 );

	if ( pxPlayerInfo )
	{
		AVP_ServerEntity_Actor* pxPlayerActor = AVP_ServerEntity_Actor::FindEntity( pxPlayerInfo->GetPuppetGuid() );
		Axon_Knowledge* pxKnowledge = CreateKnowledge();

		if ( pxKnowledge && pxPlayerActor )
		{
			Asura_Vector_3 xReconTargetPos( *( AVP_Predator_Recon::GetRecon().GetTargetPosition() ) );

			ResetAlertTimer();

			pxKnowledge->m_uKnowledgeID          = GetNewKnowledgeID();
			pxKnowledge->m_uSourceGuid           = pxPlayerInfo->GetPuppetGuid();
			pxKnowledge->m_uSourceClassification = pxPlayerActor->GetClassification();
			pxKnowledge->m_iSenseID              = AXON_SENSE_TYPE_HEARING;
			pxKnowledge->m_uTypeInformation		 = AVP_SOUND_TYPE_DISTRACTION;
			pxKnowledge->m_fAge                  = 0.0f;
			pxKnowledge->m_fThreatValue          = 0.0f;
			pxKnowledge->m_xPosition             = xReconTargetPos;
			pxKnowledge->m_xDirection            = xReconTargetPos;
			pxKnowledge->m_fDistance             = pxKnowledge->m_xDirection.Normalise();

			m_pxReconKnowledge = pxKnowledge;
			m_fReconResetTimer = 2.0f;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: ResetReconKnowledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::ResetReconKnowledge()
{
	if ( m_pxReconKnowledge )
	{
		DestroyKnowledge( m_pxReconKnowledge );
		m_pxReconKnowledge = NULL;
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: ResetReconKnowledge
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::ResetCorpseKnowledge()
{
	if ( m_pxCorpseKnowledge )
	{
		DestroyKnowledge( m_pxCorpseKnowledge );
		m_pxCorpseKnowledge = NULL;
	}
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: GetActorBrain
//---------------------------------------------------------------------------
AVP_Brain_Actor* AVP_Knowledge_System_Actor::GetActorBrain() const
{
	return static_cast< AVP_Brain_Actor* >( GetBrain() );
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: CreateVisionSense
//---------------------------------------------------------------------------
Axon_Sense_Vision* AVP_Knowledge_System_Actor::CreateVisionSense() 
{
	return new AVP_Sense_Vision(this);
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: CreateHearingSense
//---------------------------------------------------------------------------
Axon_Sense_Hearing* AVP_Knowledge_System_Actor::CreateHearingSense() 
{
	return new AVP_Sense_Hearing(this);
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: CreateHearingSense
//---------------------------------------------------------------------------
AVP_Sense_MotionTracker* AVP_Knowledge_System_Actor::CreateMotionTrackerSense()
{
	return new AVP_Sense_MotionTracker(this);
}

//---------------------------------------------------------------------------
// AVP_Knowledge_System_Actor :: DestroyMotionTrackerSense
//---------------------------------------------------------------------------
void AVP_Knowledge_System_Actor::DestroyMotionTrackerSense( AVP_Sense_MotionTracker* pxSense )
{
	delete pxSense;
	pxSense = NULL;
}