///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Brain_Actor_AlienQueen.cpp
// Author : David Wooldridge
// Date   : 11/11/2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

// header
#include "Core/BrainTypes/AVP_Brain_Actor_AlienQueen.h"

// Asura
#include "Blueprint/Asura_Blueprint.h"
#include "Core/Asura_LOS.h"
#include "Entity/PhysicalObject/Moves/Asura_Movement_System.h"
#include "Network/Asura_Message.h"
#include "Network/Asura_Network.h"
#include "Rendering/Asura_Font_System.h"
#include "Core/Asura_Scheduler.h"

// Axon
#include "Core/Axon_System.h"

// AVP
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/BrainTypes/AVP_Brain_Team_Alien.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_Alien.h"
#include "Entity/Controller/AVP_ServerEntity_Team_Alien.h"
#include "Entity/GamePlayVolume/AVP_ServerEntity_GamePlayVolume.h"
#include "Entity/Locations/LookAt/AVP_ServerEntity_LookAt.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_AlienQueen_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_ClientActor_AlienQueen.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_ServerActor_AlienQueen.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"
#include "Entity/Spawners/AVP_ServerEntity_SpawnPoint2.h"
#include "Moves/Vertebrates/Alien/AVP_Alien_MovesJump.h"

// AVP axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Knowledge/AVP_Knowledge_System_AlienQueen.h"

// Alien Queen behaviours
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Attack.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_ForcedRoar.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_GS2Move.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Movement.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Wander.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Stalk.h"
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Stunned.h"


AVP_Brain_Actor_AlienQueen::AVP_Brain_Actor_AlienQueen( AVP_ServerActor_AlienQueen* pxAlienQueen )
: PARENT( pxAlienQueen )
, m_uCurrentTargetGuid( ASURA_GUID_UNREGISTERED )
, m_iKnowledgeUpdateHandle(ASURA_INVALID_HANDLE)
, m_pxKnowledgeSystem( NULL )
, m_eAttackType( NUM_AVP_AQ_ATTACKS )
, m_uLOSToCurrentTargetTestFrame( 0 )
, m_bHaveLOSToCurrentTarget( false )
, m_bIsGS2( false )
, m_bCanSpitAcid( false )
, m_fSpitAcidMinRange( 20.0f )
, m_fSpitAcidMaxRange( 50.0f )
, m_fMeleeChargeMinDistance( 10.0f )
, m_fMeleeChargeMaxDistance( 15.0f )
, m_fMinSlashAttackDistance( 4.5f )
, m_fHealthLastFrame( 0.0f )
, m_uLookAtGuid( ASURA_GUID_UNREGISTERED )
, m_uLookAtType( AVP_AQ_LOOK_AT_TYPE_NONE )
, m_fMaxHeadTurn_Cosine( 0.87f )
, m_xBehaviourData()
{
	// set aim velocity to 90deg per one second. 
	//SetMaxAimDirAngularVelocity( Asura_Maths::Pi * 0.5f );

	// dont allow the queen to turn mroe than 90deg a second. 
	SetMaxMoveDirAngularVelocity( Asura_Maths::Pi * 0.5f );
}

AVP_Brain_Actor_AlienQueen::~AVP_Brain_Actor_AlienQueen()
{

}

void AVP_Brain_Actor_AlienQueen::Initialise()
{
	m_pxKnowledgeSystem = new AVP_Knowledge_System_AlienQueen( this );

	if( m_pxKnowledgeSystem )
	{
		m_pxKnowledgeSystem->Initialise();
	}

	if( GetActor() )
	{
		m_fHealthLastFrame = GetActor()->GetHealth();
	}
}

void AVP_Brain_Actor_AlienQueen::Shutdown( void )
{
	DestroyAllBehaviours();

	if( m_pxKnowledgeSystem )
	{
		m_pxKnowledgeSystem->Shutdown();
	}
	delete m_pxKnowledgeSystem;
	m_pxKnowledgeSystem = NULL;

	PARENT::Shutdown();
}

void AVP_Brain_Actor_AlienQueen::InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint )
{
	PARENT::InitialiseFromBlueprint( xBlueprint );

	Asura_Value xValue;

	DestroyAllBehaviours();
	if ( IsActive() )
	{
		// Create our start behaviour based on our blueprint, if it specifies one.
		bool bCreatedFromBP = false;
		if( xBlueprint.GetParameterValueByHashID( 0xae7a48c3, xValue ) ) // Asura_GetHashID( "AIStartBehaviour" )
		{
			if( xValue.GetIntValue() >= AXON_BEHAVIOUR_TYPE_FIRST_PROJECT_SPECIFIC )
			{
				CreateActivateAndPushBehaviour( xValue.GetIntValue() );
			}
		}

		if ( !bCreatedFromBP )
		{
			CreateActivateAndPushBehaviour( AVP_BEHAVIOUR_TYPE_ALIENQUEEN );
		}
		CreateGS2BehaviourIfNecessary();
	}

	if( xBlueprint.GetParameterValueByHashID( 0xE9CD27AD, xValue ) ) // Asura_GetHashID( "AICanSpitAcid" )
	{
		m_bCanSpitAcid = xValue.GetBoolValue();
	}

	if( xBlueprint.GetParameterValueByHashID( 0x37E1CA58, xValue ) ) // Asura_GetHashID( "AISpitAcidMinRange" )
	{
		m_fSpitAcidMinRange = xValue.GetFloatValue();
	}

	if( xBlueprint.GetParameterValueByHashID( 0xA1C06686, xValue ) ) // Asura_GetHashID( "AISpitAcidMaxRange" )
	{
		m_fSpitAcidMaxRange = xValue.GetFloatValue();
	}

	if( xBlueprint.GetParameterValueByHashID( 0x68062C47, xValue ) ) // Asura_GetHashID( "AIMeleeChargeMinDistance" )
	{
		m_fMeleeChargeMinDistance = xValue.GetFloatValue();
	}

	if( xBlueprint.GetParameterValueByHashID( 0x9066F959, xValue ) ) // Asura_GetHashID( "AIMeleeChargeMaxDistance" )
	{
		m_fMeleeChargeMaxDistance = xValue.GetFloatValue();
	}
}


void AVP_Brain_Actor_AlienQueen::PostLoadInitialise()
{
	RequestRegisterWithTeam();

	PARENT::PostLoadInitialise();

	EstablishNavData();
}


void AVP_Brain_Actor_AlienQueen::DoPerFrameUpdate( const float fTimeslice )
{
	if( IsPaused() || !IsActive() ) 
	{ 
		return; 
	}

	if( m_pxKnowledgeSystem )
	{
		m_pxKnowledgeSystem->PerFrameUpdate( fTimeslice );
	}

	if( GetTargetKnowledge() )
	{
		m_uCurrentTargetGuid = GetTargetKnowledge()->GetGuid();
	}

	PARENT::DoPerFrameUpdate( fTimeslice );
}


void AVP_Brain_Actor_AlienQueen::RegisterCallbacks()
{
	PARENT::RegisterCallbacks();

	if( m_iKnowledgeUpdateHandle == ASURA_INVALID_HANDLE )
	{
		Asura_Scheduler& xKnowledgeUpdateScheduler = Axon_System::GetKnowledgeUpdateScheduler();
		Asura_Callback_MemberFunction_1Arg<void, float, AVP_Brain_Actor_AlienQueen > xKnowledgeCallback( this, &AVP_Brain_Actor_AlienQueen::DoKnowledgeUpdate );
		m_iKnowledgeUpdateHandle = xKnowledgeUpdateScheduler.RegisterCallback( 0.1f, &xKnowledgeCallback );
	}
}

void AVP_Brain_Actor_AlienQueen::UnregisterCallbacks()
{
	if( m_iKnowledgeUpdateHandle != ASURA_INVALID_HANDLE )
	{
		Axon_System::GetKnowledgeUpdateScheduler().UnregisterCallback( m_iKnowledgeUpdateHandle );
		m_iKnowledgeUpdateHandle = ASURA_INVALID_HANDLE;
	}

	PARENT::UnregisterCallbacks();
}

void AVP_Brain_Actor_AlienQueen::DoKnowledgeUpdate( const float fTimeslice )
{
	if( m_pxKnowledgeSystem )
	{
		m_pxKnowledgeSystem->Update( fTimeslice );
	}
}

void AVP_Brain_Actor_AlienQueen::ReadFromChunkStream( Asura_Chunk_Stream& xStream )
{
	int iVersion;
	xStream >> iVersion;

	switch( iVersion )
	{
		////////////////////
		case 2:
		////////////////////
		{
			m_xBehaviourData.ReadFromChunkStream( xStream );
			break;
		}
		////////////////////
		case 1:
		default:
		////////////////////
		{
			break;
		}
	}

	PARENT::ReadFromChunkStream( xStream );
}

void AVP_Brain_Actor_AlienQueen::WriteToChunkStream( Asura_Chunk_Stream& xStream ) const
{
	xStream << CURRENT_CHUNK_VERSION;

	m_xBehaviourData.WriteToChunkStream( xStream );

	PARENT::WriteToChunkStream( xStream );
}

void AVP_Brain_Actor_AlienQueen::SetMovementMode( AVP_Navigation::MovementMode uMode )
{
	GetNavData().m_eMovementMode = uMode;
}

#include "Core/Asura_MemoryManagement_DebugOff.h"
Axon_Behaviour* AVP_Brain_Actor_AlienQueen::CreateBehaviour( const u_int uBehaviourType, const Asura_Message* pxMessage /*= NULL*/ )
{
	void* pxMemory = s_pxBehaviourMempool->Allocate();
	if( ! pxMemory )
	{
		Asura_Assert( false, "Axon_Project_Brain::CreateBehaviour - could not allocate behaviour memory" );
		return NULL;
	}

	Axon_Behaviour* pxBehaviour = NULL;
	switch( uBehaviourType )
	{
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN:
		////////////////////
		{
			pxBehaviour = new ( pxMemory ) AVP_Behaviour_AlienQueen( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_ATTACK:
		////////////////////
		{
			pxBehaviour = new ( pxMemory ) AVP_Behaviour_AlienQueen_Attack( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_MOVEMENT:
		////////////////////
		{
			pxBehaviour = new ( pxMemory ) AVP_Behaviour_AlienQueen_Movement( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_WANDER:
		////////////////////
		{
			pxBehaviour = new ( pxMemory )AVP_Behaviour_AlienQueen_Wander( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STALK:
		////////////////////
		{
			pxBehaviour = new ( pxMemory )AVP_Behaviour_AlienQueen_Stalk( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_GS2MOVE:
		////////////////////
		{
			pxBehaviour = new ( pxMemory )AVP_Behaviour_AlienQueen_GS2Move( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_STUNNED:
		////////////////////
		{
			pxBehaviour = new ( pxMemory )AVP_Behaviour_AlienQueen_Stunned( this );
			break;
		}
		////////////////////
		case AVP_BEHAVIOUR_TYPE_ALIENQUEEN_FORCEDROAR:
		////////////////////
		{
			pxBehaviour = new ( pxMemory )AVP_Behaviour_AlienQueen_ForcedRoar( this );
			break;
		}
		////////////////////
		default:
		////////////////////
		{
			break;
		}
	}

	if( ! pxBehaviour )
	{
		// Couldn't create the behaviour - try the parent.
		s_pxBehaviourMempool->Deallocate( pxMemory );
		pxBehaviour = PARENT::CreateBehaviour( uBehaviourType, pxMessage );
	}
	else if( pxMessage )
	{
		pxBehaviour->DoHandleMessage( pxMessage, true );
	}

	return pxBehaviour;
}


void AVP_Brain_Actor_AlienQueen::EstablishNavData()
{
	AVP_Navigation::NavData& xNavData = GetNavData();

	// Alienqueen will use human path finding date, she will not crawl on walls etc...
	xNavData.m_eMovementMode    = AVP_Navigation::MM_FAST;
	xNavData.m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID | ASURA_AI_PATHFINDER_FLAGS_IGNOREZONES;
	xNavData.m_usCurrentZone    = ASURA_NAVVERTEX_MAX_ZONE_ID;


	AVP_Navigation::TestParams xTestParams;
	xTestParams.m_uPathfinderFlags		= xNavData.m_uPathfinderFlags;
	xTestParams.m_bRejectNonalignedWPs	= true;
	xTestParams.m_xNormal				= -GetActor()->GetCurrentGravityDirection();

	AVP_Navigation::GetNearestWaypointID( GetActor()->GetPosition(), xNavData.m_usCurrentWPID, xTestParams );

	xNavData.m_fCharacterHeight = 6.0f;
	xNavData.m_fCharacterWidth  = 5.0f;
}

u_int AVP_Brain_Actor_AlienQueen::GetLargestBehaviourSize()
{
	u_int uLargestBehaviourSize = 0;

	AXON_CALC_MAX_BEHAVIOUR_SIZE( uLargestBehaviourSize, AVP_Behaviour_AlienQueen );
	AXON_CALC_MAX_BEHAVIOUR_SIZE( uLargestBehaviourSize, AVP_Behaviour_AlienQueen_Movement);
	AXON_CALC_MAX_BEHAVIOUR_SIZE( uLargestBehaviourSize, AVP_Behaviour_AlienQueen_Wander);
	AXON_CALC_MAX_BEHAVIOUR_SIZE( uLargestBehaviourSize, AVP_Behaviour_AlienQueen_Stalk);
	AXON_CALC_MAX_BEHAVIOUR_SIZE( uLargestBehaviourSize, AVP_Behaviour_AlienQueen_Attack);

	return uLargestBehaviourSize;
}

bool AVP_Brain_Actor_AlienQueen::HandleMessage( const Asura_Message *pxMessage )
{
	switch (pxMessage->GetMsgID())
	{
		////////////////////
		case AVP_MSGID_ALIENQUEEN_ADD_TO_TARGET_LIST:
		////////////////////
		{
			m_pxKnowledgeSystem->AddEntityToTargetList( pxMessage->GetFromGuid(), pxMessage->GetEntityClassification() );
			return true;
		}
		////////////////////
		case AVP_MSGID_ALIENQUEEN_REMOVE_FROM_TARGET_LIST:
		////////////////////
		{
			m_pxKnowledgeSystem->RemoveEntityFromTargetList( pxMessage->GetFromGuid() );
			return true;
		}
		////////////////////
		case AVP_MSGID_LOOK_AT_ENTITY:
		////////////////////
		{
			const AVP_Message_LookAtEntity *pxMsgData = static_cast< const AVP_Message_LookAtEntity*>( pxMessage->GetData() );

			if ( pxMsgData )
			{
				if ( pxMsgData->m_bLookAtPlayer )
				{
					// Find the player
					// This Needs changing in future as its single player only - OK for queen as she is only in SP
					AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 ); 

					if( pxPlayerInfo )
					{
						m_uLookAtGuid = pxPlayerInfo->GetPuppetGuid();
						m_uLookAtType = AVP_AQ_LOOK_AT_TYPE_PLAYER;
					}
				}
				else
				{
					if (pxMsgData->m_uLookAtGuid == m_uOwnerGuid)
					{
						// if they want us to look at ourselves just ignore thier stupidity. 
						return true;
					}

					m_uLookAtGuid = pxMsgData->m_uLookAtGuid;

					// see if we can find a node with the GUID passed. 
					AVP_ServerEntity_LookAt* pxLookAt = AVP_ServerEntity_LookAt::FindEntity( m_uLookAtGuid );

					if( pxLookAt )
					{
						m_uLookAtType = AVP_AQ_LOOK_AT_TYPE_NODE;
					}
					else
					{
						// see if we can find an actor with the GUID passed. 
						AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( m_uLookAtGuid );

						if ( pxActor )
						{
							m_uLookAtType = AVP_AQ_LOOK_AT_TYPE_ACTOR;
						}
						else
						{
							// error
							Asura_Assert( false, "AVP_Brain_Actor_AlienQueen::HandleMessage\n Handling Message 'Look At Entity'\n Entity cant be found, just ignoring message. " );
							m_uLookAtType = AVP_AQ_LOOK_AT_TYPE_NONE;
							m_uLookAtGuid = ASURA_GUID_UNREGISTERED;
						}
					}
				}
			}
			return true;
		}
		////////////////////
		case AVP_MSGID_STOP_LOOKING_AT_ENTITY:
		////////////////////
		{
			m_uLookAtGuid = ASURA_GUID_UNREGISTERED;
			m_uLookAtType = AVP_AQ_LOOK_AT_TYPE_NONE;

			return true;
		}
		////////////////////
		case AVP_MSGID_ALIENQUEEN_FORCE_ROAR:
		////////////////////
		{
			if ( m_pxFirstBehaviour )
			{
				m_pxFirstBehaviour->DoHandleMessage( pxMessage );
			}
			return true;
		}
		/////////////////////
		case AVP_MSGID_ALIENQUEEN_SET_BEHAVIOUR:
		/////////////////////
		{
			const AVP_Message_SetAlienQueenBehaviour* pxData = static_cast< const AVP_Message_SetAlienQueenBehaviour* >( pxMessage->GetData() );
			m_xBehaviourData.m_iBehaviour = pxData->m_iBehaviour;

			if ( m_pxFirstBehaviour )
			{
				m_pxFirstBehaviour->DoHandleMessage( pxMessage );
				m_pxKnowledgeSystem->ClearTargetList();
			}

			return true;
		}
		////////////////////
		default:
		////////////////////
		{
			return PARENT::HandleMessage( pxMessage );
		}
	}
}

bool AVP_Brain_Actor_AlienQueen::RegisterWithTeam()
{
	return true;
}

bool AVP_Brain_Actor_AlienQueen::UnregisterWithTeam()
{
	return true;
}

Asura_Guid AVP_Brain_Actor_AlienQueen::GetPrimaryThreatGuid()
{
	return m_uCurrentTargetGuid;
}

Asura_Guid AVP_Brain_Actor_AlienQueen::GetAlertGuid()
{
	return m_uCurrentTargetGuid;
}

bool AVP_Brain_Actor_AlienQueen::HaveLOSToCurrentTarget()
{
	if( !HasCurrentTarget() ) 
	{
		return false;
	}

	const u_int uFrame = Asura_Timers::GetFrameNumber();
	if( uFrame == m_uLOSToCurrentTargetTestFrame )
	{
		return m_bHaveLOSToCurrentTarget;
	}

	// Calculate it afresh.
	m_uLOSToCurrentTargetTestFrame = uFrame;

	Asura_Vector_3 xEyePosition = GetActor()->GetPosition();
	GetActor()->GetHeadPosition( xEyePosition );

	const AVP_ServerEntity_Actor* pxTargetActor = AVP_ServerEntity_Actor::FindEntity( GetCurrentTargetGuid() );
	if( ! pxTargetActor )
	{
		m_bHaveLOSToCurrentTarget = false;
		return m_bHaveLOSToCurrentTarget;
	}

	Asura_Vector_3 xTargetPosition = pxTargetActor->GetPosition();
	pxTargetActor->GetChestPosition( xTargetPosition );

	Asura_Vector_3 xDirection = xTargetPosition - xEyePosition;
	const float    fDistance  = xDirection.Normalise();

	const Asura_LOS_InputData   xInputData( xEyePosition, xDirection, GetOwnerGuid(), fDistance, true );
	const Asura_LOS_OutputData* pxOutputData = Asura_LOS::TestAgainstEverything( &xInputData );
	m_bHaveLOSToCurrentTarget = ( ! pxOutputData->m_bHitEnvironment && ( pxOutputData->m_uHitEntity == GetCurrentTargetGuid() ) );

	return m_bHaveLOSToCurrentTarget;
}

bool AVP_Brain_Actor_AlienQueen::CanPlanMove() const
{
	// at the moment the queen does not jump, melee, sharp turn or fall, so just retun true;
	return true;
}

void AVP_Brain_Actor_AlienQueen::SetInGameScene( bool bInGS2 )
{
	Asura_Assert( m_bIsGS2 != bInGS2 , "AVP_Brain_Actor_AlienQueen::SetInGameScene\n Setting GS2 to existing value - mismatch");
	m_bIsGS2 = bInGS2;
}

#ifndef ASURA_NO_DEBUG_OUTPUT
void AVP_Brain_Actor_AlienQueen::DoRenderDebugInfo()
{
	PARENT::DoRenderDebugInfo();

	if( GetActor()->IsDead() || !GetActor()->IsEntityActive() )
	{
		return;
	}

	Asura_Vector_3 xOutputPos = GetActor()->GetPosition();
	if( ! Asura_Camera::ProjectWorldCoordsToScreenSpace( xOutputPos, true ) || xOutputPos.z <= 0.0f)
	{
		return;
	}

}

bool AVP_Brain_Actor_AlienQueen::Verify()
{
	// Test team, brain and knowledge system
	
	return PARENT::Verify();
}

#endif

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Brain_Actor_AlienQueen::LookAtEntityFromMsgData
// Scope		: Public
// Author       : Callum Hope
// Date         : 3/4/2009
//
// Desc			: If a look at entity has been set from mesages this is where it is decided where to look in the behaviours. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Brain_Actor_AlienQueen::LookAtEntityFromMsgData( void )
{
	switch( m_uLookAtType )
	{
		////////////////////
		case AVP_AQ_LOOK_AT_TYPE_NODE:
		////////////////////
		{
			// get a pointer to the target node. 
			AVP_ServerEntity_LookAt* pxLookAt = AVP_ServerEntity_LookAt::FindEntity( m_uLookAtGuid );

			if( pxLookAt )
			{
				Asura_Vector_3 xLookDirection = pxLookAt->GetPosition() - GetActor()->GetPosition();
				xLookDirection.Normalise();

				Asura_Matrix_3x3 xQnOri = GetActor()->GetOrientation();
				Asura_Vector_3 xQueenDirection = Asura_Vector_3( xQnOri.e13, xQnOri.e23, xQnOri.e33 );
				xQueenDirection.Normalise();

				float fDotProduct = xQueenDirection * xLookDirection;

				if( fDotProduct > m_fMaxHeadTurn_Cosine )
				{
					// set the aim and look vectors to be at the node 
					AimAtPosition( pxLookAt->GetPosition() );
					SetLookAtPosition( pxLookAt->GetPosition() );
				}
			}
			break;
		}
		////////////////////
		case AVP_AQ_LOOK_AT_TYPE_ACTOR:
		case AVP_AQ_LOOK_AT_TYPE_PLAYER:
		////////////////////
		{
			// get a pointer to the target actor
			AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( m_uLookAtGuid );

			if( pxActor )
			{
				Asura_Vector_3 xLookDirection = pxActor->GetPosition() - GetActor()->GetPosition();
				xLookDirection.Normalise();

				Asura_Matrix_3x3 xQnOri = GetActor()->GetOrientation();
				Asura_Vector_3 xQueenDirection = Asura_Vector_3( xQnOri.e13, xQnOri.e23, xQnOri.e33 );
				xQueenDirection.Normalise();

				float fDotProduct = xQueenDirection * xLookDirection;

				if( fDotProduct > m_fMaxHeadTurn_Cosine )
				{
					// set the aim at the actor chest (bigger target) but the look at the actor head (better visual accuracy)
					Asura_Vector_3 xHeadPosition( Asura_Maths::ZeroVector3 );
					Asura_Vector_3 xChestPosition( Asura_Maths::ZeroVector3 );
	
					pxActor->GetHeadPosition( xHeadPosition );
					pxActor->GetChestPosition( xChestPosition );

					AimAtPosition( xChestPosition );
					SetLookAtPosition( xHeadPosition );
				}
			}
			break;
		}
		////////////////////
		case AVP_AQ_LOOK_AT_TYPE_NONE:
		default:
		////////////////////
		{
			LookAndAimForward();
			break;
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Brain_Actor_AlienQueen::AimAtPosition
// Scope		: Public
// Author       : Callum Hope
// Date         : 3/4/2009
//
// Desc			: Because we can only set the aim direction from the AVP_Brain_Actor and below 
//				  this function works out the direction to ask for if we only have a position at hand here or in behaviours. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Brain_Actor_AlienQueen::AimAtPosition( const Asura_Vector_3& xPosition )
{
	AVP_ServerActor_AlienQueen *pxOurActor = GetQueenActor();
	if( pxOurActor )
	{
		Asura_Vector_3 xChestPos( Asura_Maths::ZeroVector3 );
		pxOurActor->GetChestPosition( xChestPos );
		Asura_Vector_3 xDirection( xPosition - xChestPos );
		xDirection.Normalise();
		SetAimDirection( xDirection );
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Brain_Actor_AlienQueen::LookAndAimForward
// Scope		: Public
// Author       : Callum Hope
// Date         : 3/4/2009
//
// Desc			: Time Saving Routein to set the look at position to just be inline with the entity;s world space orientation. 
////////////////////////////////////////////////////////////////////////////////

void AVP_Brain_Actor_AlienQueen::LookAndAimForward()
{
	AVP_ServerActor_AlienQueen* pxOurActor = GetQueenActor();
	if ( pxOurActor )
	{
		const Asura_Matrix_3x3& xOri = pxOurActor->GetOrientation();
		Asura_Vector_3 xFwd( xOri.e13, xOri.e23, xOri.e33 );
		Asura_Vector_3 xChestPos;
		pxOurActor->GetChestPosition( xChestPos );
		Asura_Vector_3 xLookAt( xChestPos + ( xFwd * 5 ) );
		SetLookAtPosition( xLookAt );
		SetAimDirection( xFwd );
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Brain_Actor_AlienQueen::GetQueenActor
// Scope		: Public
// Author       : Callum Hope
// Date         : 3/4/2009
//
// Desc			: Time Saving Routein to return the correct cast to the actor a level down, which is all the brain can return on its own. 
////////////////////////////////////////////////////////////////////////////////

AVP_ServerActor_AlienQueen* AVP_Brain_Actor_AlienQueen::GetQueenActor() const
{
	return static_cast<AVP_ServerActor_AlienQueen*>( GetActor() );
}





