//----------------------------------------------------------------------------
// File			: AVP_Brain_Actor_Marine.cpp
// Created		: 29 / 10 / 07
// Created By	: Gareth Thomas
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// INCLUDES
//----------------------------------------------------------------------------
// Core
#include "Core/Asura.h"
// This files Header
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
// Asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#include "Network/Asura_Message.h"
#include "Network/Asura_Network.h"
#include "Core/Asura_Scheduler.h"
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Camera/Asura_Camera.h"
#include "Rendering/Asura_Font_System.h"
#include "Interface/Asura_CommandConsole.h"
#include "Debugging/Asura_DebugLineRender.h"
#endif

// Axon

// AVP
#include "Actor/Vertebrates/Human/AVP_Human_AIAnimStateMachine.h"
#include "Actor/Vertebrates/Human/AVP_Human_MoraleHandler.h"
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Controller/AVP_Controller_Messages.h"
#include "Entity/Controller/AVP_ServerEntity_Squad_Marine.h"
#include "Entity/Controller/AVP_ServerEntity_Team_Marine.h"
#include "Entity/Locations/LookAt/AVP_ServerEntity_LookAt.h"
#include "Entity/Locations/ShootAt/AVP_ServerEntity_ShootAt.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ClientActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/Android/AVP_ServerActor_Android.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/AVP_InventoryItem_Messages.h"
#include "Inventory/Items/AVP_InventoryItem_Torch.h"
#include "Inventory/Items/AVP_InventoryItem_Weapon.h"
#include "Inventory/Items/Weapons/AVP_RangedWeapon_SubType.h"
#include "Moves/AVP_Moves.h"

// AVP Axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/Axon_Project_System.h"
#include "Knowledge/AVP_Knowledge_System_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_Vision_Actor.h"
#include "Tactical/AVP_Tactical_System.h"

// Behaviour Header files includes
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_GS2Node_Human_CoreNodeWithGunFire.h"
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_GS2Spline_Human_CoreSplineWithGunFire.h"
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_Human_Grapple.h"
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_Human_Lift.h"
#include "Behaviour/BehaviourTypes/Human/AVP_Behaviour_Human_Movement.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Alert.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_SquadMember.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_SquadLeader.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_InCover.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Investigate.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_MeleeCounter.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Patrol.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Travel.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Weapon.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_TestBehaviour.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Node_Marine_Combat.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Node_Marine_LookAt.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_GS2Spline_Marine_Combat.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_HideFromCloakedPredator.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_HandleObjective.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_AttackSelector.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_Advance.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_FallBack.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_SmartGun.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_StandGround.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_Support.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Attack_Travelling.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Injured.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_MeleePlayer.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_TequilaCarried.h"


//----------------------------------------------------------------------------
// Statics
//----------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
u_int	AVP_Brain_Actor_Marine::s_uHighLevelBehaviourDebugColour		= 0xffff8888;
u_int	AVP_Brain_Actor_Marine::s_uPermentantChildDebugColour			= 0xff338833;
u_int	AVP_Brain_Actor_Marine::s_uTemporaryChildDebugColour			= 0xff333388;
u_int	AVP_Brain_Actor_Marine::s_uTemporaryLeadersChildDebugColour		= 0xff883388;
#endif

// Asura_Mempool* AVP_Brain_Actor_Marine::s_pxPosEvalMempool  = NULL;
// Asura_List<AVP_WaypointInfo> AVP_Brain_Actor_Marine::s_pxWaypointsList;

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine - Function Implementations
//----------------------------------------------------------------------------

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: Constructor
//----------------------------------------------------------------------------
AVP_Brain_Actor_Marine::AVP_Brain_Actor_Marine(AVP_ServerActor_Human* pxHuman): PARENT(pxHuman)
, m_iKnowledgeUpdateHandle(ASURA_INVALID_HANDLE)
, m_uLookAtGuid( ASURA_GUID_UNREGISTERED )
, m_uLookAtType( LOOK_AT_TYPE_NONE )
, m_bInjured( false )
, m_bHadAlertLastFrame( false )
, m_bHadThreatLastFrame( false )
{

}

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

	m_pxKnowledgeSystem = new AVP_Knowledge_System_Actor(this);

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

	m_pxTacticalSystem = new AVP_Tactical_System(this);
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Travel :: EstablishNavData
//---------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::EstablishNavData(void)
{
	AVP_ServerActor_Human* pxOurServerActor = GetHumanActor();

	AVP_Navigation::NavData& xNavData = GetNavData();

	// Set the human path finding flags
	xNavData.m_uPathfinderFlags = AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID;
	xNavData.m_eMovementMode = AVP_Navigation::MM_MEDIUM;

	// Establish our current waypoint ID.
	AVP_Navigation::TestParams xTestParams;
	xTestParams.m_uPathfinderFlags		= xNavData.m_uPathfinderFlags;
	xTestParams.m_bRejectNonalignedWPs	= true;
	xTestParams.m_xNormal				= -pxOurServerActor->GetCurrentGravityDirection();

	const bool bGotWaypointID = AVP_Navigation::GetNearestWaypointID(pxOurServerActor->GetPosition(), xNavData.m_usCurrentWPID, xTestParams);
	if (bGotWaypointID)
	{
		// Establish our current zone.
		xNavData.m_usCurrentZone = Asura_AI_Navigation_System::GetWaypoint(xNavData.m_usCurrentWPID)->m_usZone;
	}

	xNavData.m_fCharacterHeight = 2.0f;
	xNavData.m_fCharacterWidth  = 1.0f;
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: Shutdown
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::Shutdown(void)
{
	delete m_pxTacticalSystem;
	m_pxTacticalSystem = NULL;

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

	delete m_pxKnowledgeSystem;
	m_pxKnowledgeSystem = NULL;

	PARENT::Shutdown();
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: Shutdown
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::PostLoadInitialise(void)
{
	PARENT::PostLoadInitialise();

	if ( GetHumanActor()->IsEntityActive() )
	{
		RequestRegisterWithTeam();
	}

	SetShouldChunkNavData( true );

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

		if ( xNavData.m_usCurrentWPID != ASURA_INVALID_WAYPOINT_ID )
		{
			Asura_Vector_3		xLookDirection( Asura_Maths::ZeroVector3 );
			Asura_Matrix_3x3	xOri( Asura_Maths::IdentityMatrix3x3 );

			AVP_Waypoint_Manager::GetMaxLOFDirection(xNavData.m_usCurrentWPID, xLookDirection);
			if ( !xLookDirection.ApproximatelyEquals( Asura_Maths::ZeroVector3 ) )
			{
				Asura_Maths::OrientationFromDirection(xOri, xLookDirection);
			}

			//GetHumanActor()->TeleportTo( GetHumanActor()->GetPosition(), xOri ,true );
		}
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: InitialiseFromBlueprint
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::InitialiseFromBlueprint(const Asura_Blueprint& xBlueprint)
{
	PARENT::InitialiseFromBlueprint(xBlueprint);

	if ( m_pxKnowledgeSystem )
	{
		m_pxKnowledgeSystem->InitialiseFromBlueprint( xBlueprint );
	}

	CleanUpBehaviours();
	if ( IsActive() )
	{
		if (!CreateDefaultBehaviour())
		{
			Asura_Assert(false, "AVP_Brain_Actor_Marine :: InitialiseFromBlueprint - Could not create / push default marine behaviour");
		}
		CreateGS2BehaviourIfNecessary();
	}

	EstablishNavData();
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: DestroyChildren
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::DestroyChildren(Axon_Behaviour* pxParentBehaviour)
{
	// Destroy any children.
	Axon_Behaviour* pxChildBehaviour = pxParentBehaviour->GetChild();

	while (pxChildBehaviour)
	{
		pxParentBehaviour->UnlinkChild(pxChildBehaviour);
		DestroyBehaviour(pxChildBehaviour);
		pxChildBehaviour = pxParentBehaviour->GetChild();
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CleanUpBehaviours
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::DoPerFrameUpdate(const float fTimeslice)
{
	if ( !m_bHadAlertLastFrame && DoesHaveAlert() )
	{
		m_bHadAlertLastFrame = true;
		GetHumanActor()->SendOnAlertMessage();
	}
	else if ( !DoesHaveAlert() )
	{
		m_bHadAlertLastFrame = false;
	}

	if ( !m_bHadThreatLastFrame && DoesHaveThreat() )
	{
		m_bHadThreatLastFrame = true;
		GetHumanActor()->SendOnThreatMessage();
	}
	else if ( !DoesHaveAlert() )
	{
		m_bHadThreatLastFrame = false;
	}

	if ( !m_bInjured )
	{
		AVP_ServerActor_Human* pxOurActor = GetHumanActor();

		m_bInjured = pxOurActor->GetHasDamagedLegs() && pxOurActor->GetHealth() > 0.0f;
	}

	SetMaxAimDirAngularVelocity( Asura_Maths::Pi * GetTacticalSystem()->GetAimLerpModifier() );
	PARENT::DoPerFrameUpdate(fTimeslice);

	
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CleanUpBehaviours
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::CleanUpBehaviours()
{
	DestroyAllBehaviours();
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CreateBeahviour
//----------------------------------------------------------------------------
Axon_Behaviour* AVP_Brain_Actor_Marine::CreateBehaviour(const u_int uBehaviourType, const Asura_Message* pxMessage)
{
	bool				bIsMarineBehaviour	= IsMarineBehaviour(uBehaviourType);
	Axon_Behaviour*		pxBehaviour			= NULL;

 	if (bIsMarineBehaviour)
	{
		pxBehaviour = CreateMarineBehaviour(uBehaviourType);

        if (pxBehaviour && pxMessage)
        {
            pxBehaviour->DoHandleMessage(pxMessage, true);
        }
	}
	else
	{
		pxBehaviour = PARENT::CreateBehaviour(uBehaviourType, pxMessage);
	}

	return pxBehaviour;
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: RegisterCallbacks
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::RegisterCallbacks()
{
	PARENT::RegisterCallbacks();

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

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: UnregisterCallbacks
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::UnregisterCallbacks()
{
	PARENT::UnregisterCallbacks();

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

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: HandleMessage
//----------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::HandleMessage(const Asura_Message* pxMessage)
{
	switch (pxMessage->GetMsgID())
	{
		case AVP_MSGID_FORCE_AIM:
		{
			GetTacticalSystem()->SetMessageForceAiming( true );

			return true;

		}break;

		case AVP_MSGID_STOP_FORCE_AIM:
		{
			GetTacticalSystem()->SetMessageForceAiming( false );

			return true;

		}break;

		case AVP_MSGID_CLEAR_PLAYERS_LOF:
		{
			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
					AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 ); 
				 
					if ( pxPlayerInfo )
					{
						m_uLookAtGuid = pxPlayerInfo->GetPuppetGuid();
						m_uLookAtType = LOOK_AT_TYPE_PLAYER;
					}
				}
				else
				{
					if (pxMsgData->m_uLookAtGuid == m_uOwnerGuid)
					{
						return true;
					}

					m_uLookAtGuid = pxMsgData->m_uLookAtGuid;

					AVP_ServerEntity_LookAt* pxLookAt = AVP_ServerEntity_LookAt::FindEntity( m_uLookAtGuid );

					if ( pxLookAt )
					{
						m_uLookAtType = LOOK_AT_TYPE_NODE;
					}
					else
					{
						AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( m_uLookAtGuid );
						
						if ( pxActor )
						{
							m_uLookAtType = LOOK_AT_TYPE_ACTOR;
						}
						else
						{
							// error
							Asura_Assert( false, "Handling Message 'Look At Entity' bbut somthing has gone wrong not going to be looking at the entity!" );
							m_uLookAtType = 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 = LOOK_AT_TYPE_NONE;

			return true;
		}

		case AVP_MSGID_ATTACK_SCRIPTED_TARGET:
		{
			const AVP_Message_AttackScriptedTarget* pxMsgData = static_cast< const AVP_Message_AttackScriptedTarget*>( pxMessage->GetData() );

			if ( pxMsgData )
			{
				AVP_ServerEntity_ShootAt* pxShootAt = AVP_ServerEntity_ShootAt::FindEntity( pxMsgData->m_uShootAtGuid );

				if ( pxShootAt )
				{
					if ( pxShootAt->GetShootAtPlayer() )
					{
						// Find the player
						// This Needs changing in future as its single player only
						AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 ); 
					 
						if ( pxPlayerInfo )
						{
							AVP_ServerEntity_Actor* pxPlayer = AVP_ServerEntity_Actor::FindEntity( pxPlayerInfo->GetPuppetGuid() );

							if ( pxPlayer )
							{
								// Shoot at entity!
								GetKnowledgeSystem()->SetScriptedTargetIsShootAtPoint( false );
								GetKnowledgeSystem()->SetScriptedTarget( pxPlayer->GetGuid() );
							}
						}
					}
					else if ( pxShootAt->GetShouldShootAtLinkedEntity() )
					{
						// Shoot at entity!
						GetKnowledgeSystem()->SetScriptedTargetIsShootAtPoint( false );
						GetKnowledgeSystem()->SetScriptedTarget( pxShootAt->GetShootAtEntityGuid() );
					}
					else
					{
						// Shoot at ShootAtPoint!
						GetKnowledgeSystem()->SetScriptedTargetIsShootAtPoint( true );
						GetKnowledgeSystem()->SetScriptedTarget( pxShootAt->GetGuid() );
					}
				}
			}

			return true;
		}
		
		case AVP_MSGID_STOP_ATTACKING_SCRIPTED_TARGET:
		{
			GetKnowledgeSystem()->StopAttackingScriptedTarget();
			return true;
		}

		case AVP_MSGID_REQUEST_TORCH_ON:
		{
			TorchOn();
			return(true);
		}

		case AVP_MSGID_REQUEST_TORCH_OFF:
		{
			TorchOff();
			return(true);
		}

		case AVP_MSGID_ITEM_BEGIN_IDLING:
		{
			const AVP_Message_InventoryItem_BeginIdling*	pxData	= static_cast<const AVP_Message_InventoryItem_BeginIdling*>(pxMessage->GetData());

			if( (pxData != NULL) &&
				(pxData->GetGroupHash() == uAVP_INVENTORY_GROUPHASH_WEAPON) &&
				(pxData->GetUsageType() == AVP_InventoryItem_Weapon::UT_RELOAD_ALL) )
			{
				GetTacticalSystem()->SetReloadingWeapon(false);
			}

			return true;
		}

		case AVP_MSGID_ITEM_BEGIN_USING:
		{
			const AVP_Message_InventoryItem_BeginUsing* pxData = static_cast<const AVP_Message_InventoryItem_BeginUsing*>(pxMessage->GetData());

			if ((pxData) && (pxData->GetGroupHash() == uAVP_INVENTORY_GROUPHASH_WEAPON) && (pxData->GetUsageType()== AVP_InventoryItem_Weapon::UT_RELOAD_ALL) && (!GetTacticalSystem()->IsReloadingWeapon()))
			{
				if (GetKnowledgeSystem())
				{
					if (GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED)
					{
						if (GetHumanActor()->GetMoraleHandler())
						{
							GetHumanActor()->GetMoraleHandler()->EffectMorale(AVP_Human_MoraleHandler::AVP_MORALE_EFFECTOR_RELOADING_WHILE_UNDER_THREAT);
						}
					}
				}

				GetTacticalSystem()->SetReloadingWeapon(true);
			}

			return true;
		}

		case AVP_MSGID_MOUNT_LIFT:
		case AVP_MSGID_DISMOUNT_LIFT:
		case AVP_MSGID_MELEE_PLAYER_BACK:
		case AVP_MSGID_LEADER_MOVING_TO_AI_OBJECTIVE:
		case AVP_MSGID_PERFORM_AI_OBJECTIVE_ACTION:
		case AVP_MSGID_PICK_TEQUILA_UP:
		case AVP_MSGID_PUT_TEQUILA_DOWN:
		{
			if (m_pxFirstBehaviour)
			{
				m_pxFirstBehaviour->DoHandleMessage(pxMessage);
			}

			return true;
		}

		case AVP_MSGID_STOP_AI_OBJECTIVE_ACTIONS:
		{
			if (m_pxFirstBehaviour)
			{
				if (m_pxFirstBehaviour->GetType() == AVP_BEHAVIOUR_TYPE_MARINE)
				{
					m_pxFirstBehaviour->DoHandleMessage( pxMessage );
				}
			}

			return true;
		}

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

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CreateMarineBeahviour
//----------------------------------------------------------------------------
#include "Core/Asura_MemoryManagement_DebugOff.h"
Axon_Behaviour* AVP_Brain_Actor_Marine::CreateMarineBehaviour(u_int uBehaviourType)
{
	void*				pxMemory			= s_pxBehaviourMempool->Allocate();
	Axon_Behaviour*		pxBehaviour			= NULL;

	if (!pxMemory)
	{
		Asura_Assert(false, "Axon_Project_Brain::CreateBehaviour - could not allocate behaviour memory");
		return NULL;
	}

	switch (uBehaviourType)
	{
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE:									pxBehaviour = new (pxMemory) AVP_Behaviour_Marine(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ALERT:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Alert(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_SQUADMEMBER:						pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_SquadMember(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_SQUADLEADER:						pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_SquadLeader(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_HUMAN_GRAPPLE:							pxBehaviour = new (pxMemory) AVP_Behaviour_Human_Grapple(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_INCOVER:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_InCover(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_INVESTIGATE:						pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Investigate(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_HUMAN_MOVEMENT:							pxBehaviour = new (pxMemory) AVP_Behaviour_Human_Movement(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_MELEE_COUNTER:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_MeleeCounter(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_PATROL:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Patrol(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_TRAVEL:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Travel(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_WEAPON:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Weapon(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_TESTBEHAVIOUR:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_TestBehaviour(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_COMBAT:					pxBehaviour = new (pxMemory) AVP_Behaviour_GS2Node_Marine_Combat(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_GS2_MARINE_NODE_LOOKAT:					pxBehaviour = new (pxMemory) AVP_Behaviour_GS2Node_Marine_LookAt(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_HIDEFROMCLOAKEDPREDATOR:			pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_HideFromCloakedPredator(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_HANDLEOBJECTIVE:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_HandleObjective(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SELECTOR:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_AttackSelector(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_ADVANCE:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_Advance(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_FALLBACK:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_FallBack(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SMARTGUN:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_SmartGun(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_STANDGROUND:				pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_StandGround(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SUPPORT:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_Support(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_TRAVELLING:				pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Attack_Travelling(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_MELEE_PLAYER:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_MeleePlayer(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_INJURED:							pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_Injured(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_MARINE_TEQUIILACARRIED:					pxBehaviour = new (pxMemory) AVP_Behaviour_Marine_TequilaCarried(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_GS2_MARINE_SPLINE_COMBAT:				pxBehaviour = new (pxMemory) AVP_Behaviour_GS2Spline_Marine_Combat(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AVP_BEHAVIOUR_TYPE_HUMAN_LIFT:								pxBehaviour = new (pxMemory) AVP_Behaviour_Human_Lift(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AXON_BEHAVIOUR_TYPE_HUMAN_GS2NODE_ACTOR_WITH_GUNFIRE:		pxBehaviour = new (pxMemory) AVP_Behaviour_GS2Node_Human_CoreNodeWithGunFire(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		case AXON_BEHAVIOUR_TYPE_HUMAN_GS2SPLINE_ACTOR_WITH_GUNFIRE:	pxBehaviour = new (pxMemory) AVP_Behaviour_GS2Spline_Human_CoreSplineWithGunFire(this); break;
		//-------------------------------------------------------------------------------------------------------------------------------
		default: Asura_Assert(false, "AVP_Brain_Actor_Marine :: CreateMarineBeahviour - Unknown Behaviour Type"); break;
		//-------------------------------------------------------------------------------------------------------------------------------
	}

	if (!pxBehaviour)
	{
		s_pxBehaviourMempool->Deallocate(pxMemory);
	}

	return pxBehaviour;
}
#include "Core/Asura_MemoryManagement_DebugOn.h"

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: RegisterWithTeam
//----------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::RegisterWithTeam()
{
	if ( !PARENT::RegisterWithTeam() )
	{
		return false;
	}

	// Register with the team.
	if ( !AVP_ServerEntity_Team_Marine::GetInstance() )
	{
		return false;
	}
	AVP_ServerEntity_Team_Marine::GetInstance()->Register( GetOwnerGuid() );

	if ( GetActor()->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED )
	{
		return true;
	}

	// Register with our squad.
	AVP_ServerEntity_Squad_Marine* pxMarineSquad = AVP_ServerEntity_Squad_Marine::FindEntity( GetActor()->GetInitialSquadGuid() );
	if ( pxMarineSquad )
	{
		pxMarineSquad->AddMember( GetOwnerGuid() );
		return true;
	}
	else
	{
		return false;
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: UnregisterWithTeam
//----------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::UnregisterWithTeam()
{
	if ( !PARENT::UnregisterWithTeam() )
	{
		return false;
	}

	// Unregister with the team.
	if ( !AVP_ServerEntity_Team_Marine::GetInstance() )
	{
		return false;
	}
	AVP_ServerEntity_Team_Marine::GetInstance()->Unregister( GetOwnerGuid() );

	if ( GetActor()->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED )
	{
		return true;
	}

	// Unregister with our squad.
	AVP_ServerEntity_Squad_Marine* pxMarineSquad = AVP_ServerEntity_Squad_Marine::FindEntity( GetActor()->GetInitialSquadGuid() );
	if ( pxMarineSquad )
	{
		pxMarineSquad->RemoveMember( GetOwnerGuid() );
		return true;
	}
	else
	{
		return false;
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetNearbyRange
//----------------------------------------------------------------------------

DEBUGVAR float dbg_fSlowRange = 4.0f;
DEBUGVAR float dbg_fMediumRange = 8.0f;
DEBUGVAR float dbg_fFastRange = 10.0f;

float AVP_Brain_Actor_Marine::GetNearbyRange() const
{
	switch (GetActor()->GetAIAnimStateMachine()->GetTargetState())
	{

	case AVP_Vertebrate_AIAnimStateMachine::ACTOR_STATE_IDLE:
		return 0.0f;
	case AVP_Vertebrate_AIAnimStateMachine::VERTEBRATE_STATE_MOVE_SLOW:
		return dbg_fSlowRange;
	default:
	case AVP_Vertebrate_AIAnimStateMachine::VERTEBRATE_STATE_MOVE_MEDIUM:
		return dbg_fMediumRange;
	case AVP_Vertebrate_AIAnimStateMachine::VERTEBRATE_STATE_MOVE_FAST:
		return dbg_fFastRange;
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: IsMarineBehaviour
//----------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::IsMarineBehaviour(const u_int uBehaviourType)
{
	if ( uBehaviourType == AVP_BEHAVIOUR_TYPE_HUMAN_MOVEMENT || uBehaviourType == AVP_BEHAVIOUR_TYPE_HUMAN_GRAPPLE || 
		uBehaviourType == AVP_BEHAVIOUR_TYPE_HUMAN_LIFT || uBehaviourType == AXON_BEHAVIOUR_TYPE_HUMAN_GS2NODE_ACTOR_WITH_GUNFIRE || 
		uBehaviourType == AXON_BEHAVIOUR_TYPE_HUMAN_GS2SPLINE_ACTOR_WITH_GUNFIRE )
	{
		return true;
	}
	else if ( uBehaviourType >= AVP_BEHAVIOUR_TYPE_MARINE && uBehaviourType < AVP_BEHAVIOUR_TYPE_MARINE_MAX_BEHAVIOURS )
	{
		return true;
	}
	else
	{
		return false;
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CreateDefaultBehaviour
//----------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::CreateDefaultBehaviour(void)
{
	return ( CreateActivateAndPushBehaviour( AVP_BEHAVIOUR_TYPE_MARINE ) != NULL );
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: ReadFromChunkStream
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::ReadFromChunkStream(Asura_Chunk_Stream& xStream)
{
    u_int uVersion;
    xStream >> uVersion;

    PARENT::ReadFromChunkStream( xStream );

    if ( uVersion == uCURRENT_CHUNK_VERSION )
	{
		m_pxKnowledgeSystem->ReadFromChunkStream( xStream );
	}
	else if ( uVersion == 0 )
    {
    }
    else
    {
        Asura_Assertf( false, ( "AVP_Brain_Actor_Marine::ReadFromChunkStream - unhandled chunk version (%u)", uVersion ) );
    }
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: WriteToChunkStream
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::WriteToChunkStream(Asura_Chunk_Stream& xStream) const
{
    xStream << uCURRENT_CHUNK_VERSION;

    PARENT::WriteToChunkStream( xStream );

	m_pxKnowledgeSystem->WriteToChunkStream( xStream );
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Brain_Actor_Marine::IsTorchOn
// Author       : Andy Tate
// Date         : 25-Mar-2008
////////////////////////////////////////////////////////////////////////////////

bool AVP_Brain_Actor_Marine::IsTorchOn(void) const
{
	const AVP_ServerActor_Human*	pxHuman		= GetHumanActor();
	const AVP_InventoryItem_Torch*	pxTorchItem	= pxHuman->GetTorchItem();

	if(pxTorchItem == NULL)
	{
		return(false);
	}
	else
	{
		return(pxTorchItem->IsUsing( false ));
	}
}

/// End of function 'AVP_Brain_Actor_Marine::IsTorchOn'. ///

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: TorchOn
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::TorchOn(void)
{
	AVP_ServerActor_Human*		pxHuman		= GetHumanActor();
	AVP_InventoryItem_Torch*	pxTorchItem	= pxHuman->GetTorchItem();

	if(pxTorchItem != NULL)
	{
		pxTorchItem->RequestBeginUsage(AVP_InventoryItem_Torch::UT_TORCH, AVP_InventoryItem_Torch::TT_AUTOMATIC);
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: TorchOff
//----------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::TorchOff(void)
{
	AVP_ServerActor_Human*		pxHuman		= GetHumanActor();
	AVP_InventoryItem_Torch*	pxTorchItem	= pxHuman->GetTorchItem();

	if(pxTorchItem != NULL)
	{
		pxTorchItem->RequestEndUsage(AVP_InventoryItem_Torch::TT_AUTOMATIC);
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: WriteToChunkStream
//----------------------------------------------------------------------------
AVP_ServerActor_Human* AVP_Brain_Actor_Marine::GetHumanActor() const
{
    return static_cast<AVP_ServerActor_Human* >(GetActor());
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetSquad
//------------------------------------------------------------------------
AVP_ServerEntity_Squad_Marine* AVP_Brain_Actor_Marine::GetMarineSquad(void) const
{
	Asura_Guid uSquadGuid = GetHumanActor()->GetInitialSquadGuid();

	if ( uSquadGuid == ASURA_GUID_UNREGISTERED ) { return NULL; }

	return ( AVP_ServerEntity_Squad_Marine::FindEntity( uSquadGuid ) );
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: UpdateKnowledge
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::UpdateKnowledge(const float fTimeslice)
{
	if ( m_pxKnowledgeSystem )
	{ 
		m_pxKnowledgeSystem->Update(fTimeslice); 
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: Crouch
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::Crouch(void)
{
	AVP_ServerActor_Human* pxOurActor = GetHumanActor();

	if (pxOurActor)
	{
		AVP_Human_AIAnimStateMachine* pxStateMachine = static_cast< AVP_Human_AIAnimStateMachine*  >( pxOurActor->GetAIAnimStateMachine() );

		if ( pxOurActor->IsMoving() )
		{
			pxStateMachine->RequestIdle();
			pxStateMachine->RequestCrouchIdle();
		}
		else
		{
			pxStateMachine->RequestCrouchIdle();
		}
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: StandUp
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::StandUp(void)
{
	AVP_ServerActor_Human* pxOurActor = GetHumanActor();

	if ( pxOurActor )
	{
		AVP_Vertebrate_AIAnimStateMachine* pxStateMachine = static_cast< AVP_Vertebrate_AIAnimStateMachine*  >( pxOurActor->GetAIAnimStateMachine() );
		
		pxStateMachine->RequestIdle();
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: AimAtThreat
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::AimAtThreat(void)
{
	if ( GetTacticalSystem() && GetKnowledgeSystem() && GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED )
	{
		if ( ( !GetKnowledgeSystem()->ShootAtScriptedTarget() && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE ) || 
			( GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE ) )
		{
			AVP_ServerEntity_Actor* pxThreat = AVP_ServerEntity_Actor::FindEntity( GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() );

			if ( pxThreat )
			{
				Asura_Vector_3 xThreatChest( Asura_Maths::ZeroVector3 );
				pxThreat->GetChestPosition( xThreatChest );

				if ( GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_FLAMETHROWER )
				{
					float fDistSq = ( xThreatChest - GetHumanActor()->GetPosition() ).MagnitudeSquared();

					if ( fDistSq > 64.0f )
						xThreatChest.y += 1.0f;
				}

				AimAtPosition( xThreatChest );
			}
		}
		else
		{
			AimAtPosition( GetKnowledgeSystem()->GetBestThreatKnowledge().m_xPosition );
		}
	}
}
 
//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: AimAtThreat
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::LookAtThreat(void)
{
	if ( GetTacticalSystem() && GetKnowledgeSystem() && GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED )
	{
		if ( ( !GetKnowledgeSystem()->ShootAtScriptedTarget() && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE ) || 
			( GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE ) )
		{
			AVP_ServerEntity_Actor* pxThreat = AVP_ServerEntity_Actor::FindEntity( GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() );

			if ( pxThreat )
			{
				Asura_Vector_3 xHeadChest( Asura_Maths::ZeroVector3 );
				pxThreat->GetHeadPosition( xHeadChest);
				SetLookAtPosition( xHeadChest );
			}
		}
		else
		{
			SetLookAtPosition( GetKnowledgeSystem()->GetBestThreatKnowledge().m_xPosition );
		}
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: LookForward
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::LookForward( void )
{
	AVP_ServerActor_Human*			pxOurActor = GetHumanActor();
	AVP_Tactical_System*			pxTactical = GetTacticalSystem();

	if ( pxOurActor && pxTactical )
	{
		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 );
		pxTactical->LetRouteSetLookAt( false );
		SetLookAtPosition( xLookAt );
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: AimForward
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::AimForward()
{
	AVP_ServerActor_Human*			pxOurActor = GetHumanActor();
	AVP_Tactical_System*			pxTactical = GetTacticalSystem();

	if (pxOurActor && pxTactical)
	{
		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 );
		pxTactical->LetRouteSetLookAt( false );
		AimAtPosition( xLookAt );
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: AimAtPosition
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::AimAtPosition(const Asura_Vector_3& xPosition)
{
	AVP_ServerActor_Human* pxOurActor = GetHumanActor();
	Asura_Vector_3 xChestPos( Asura_Maths::ZeroVector3 );
	pxOurActor->GetChestPosition( xChestPos );
	Asura_Vector_3 xDirection( xPosition - xChestPos );
	xDirection.Normalise();
	SetAimDirection(xDirection);
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: DoesHaveThreat
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::DoesHaveThreat(void)
{
	AVP_Knowledge_System_Actor* pxKnowledgeSystem = GetKnowledgeSystem();

	if ( ( !pxKnowledgeSystem ) || ( pxKnowledgeSystem->GetBestThreatKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return false;
	}

	return true;
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: DoesHaveAlert
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::DoesHaveAlert(void)
{
	AVP_Knowledge_System_Actor* pxKnowledgeSystem = GetKnowledgeSystem();

	if ( ( !pxKnowledgeSystem ) || ( pxKnowledgeSystem->GetBestAlertKnowledge().GetGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return false;
	}

	return true;
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetPrimaryThreatGuid
//----------------------------------------------------------------------------
Asura_Guid AVP_Brain_Actor_Marine::GetPrimaryThreatGuid()
{
	AVP_Knowledge_System_Actor*	pxKnowledgeSystem = GetKnowledgeSystem();

	if ( !pxKnowledgeSystem ) 
	{
		return ASURA_GUID_UNREGISTERED;
	}
	else
	{
		return  pxKnowledgeSystem->GetBestThreatKnowledge().GetGuid();
	}
}

//----------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetAlertGuid
//----------------------------------------------------------------------------
Asura_Guid AVP_Brain_Actor_Marine::GetAlertGuid( void )
{
	AVP_Knowledge_System_Actor*	pxKnowledgeSystem = GetKnowledgeSystem();

	if ( !pxKnowledgeSystem ) 
	{
		return ASURA_GUID_UNREGISTERED;
	}

	const Axon_Knowledge xAlertInfo = pxKnowledgeSystem->GetBestAlertKnowledge();

	if ( xAlertInfo.m_uSourceGuid != ASURA_GUID_UNREGISTERED )
	{
		AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( xAlertInfo.m_uSourceGuid );

		if ( pxActor )
		{
			return xAlertInfo.m_uSourceGuid;
		}
		else
		{
			pxActor = AVP_ServerEntity_Actor::FindEntity( xAlertInfo.m_uProjectData );

			if ( pxActor )
			{
				return xAlertInfo.m_uProjectData;
			}
		}
	}

	return ASURA_GUID_UNREGISTERED;
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetCombatZoneGuid
//------------------------------------------------------------------------
Asura_Guid AVP_Brain_Actor_Marine::GetCombatZoneGuid( void )
{
	AVP_ServerEntity_Squad_Marine* pxSquad = AVP_ServerEntity_Squad_Marine::FindEntity( GetHumanActor()->GetInitialSquadGuid() );

	if ( pxSquad )
	{
		return pxSquad->GetCombatZoneGPVGuid();
	}
	else
	{
		return ASURA_GUID_UNREGISTERED;
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetCombatZoneGuid
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::GetIsRestrictedToCombatZone( void )
{
	AVP_ServerEntity_Squad_Marine* pxSquad = AVP_ServerEntity_Squad_Marine::FindEntity( GetHumanActor()->GetInitialSquadGuid() );

	if ( pxSquad )
	{
		return (pxSquad->GetIsRestrictedToCombatZone() );
	}
	else
	{
		return ASURA_GUID_UNREGISTERED;
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: HasValidRoute
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::HasValidRoute( void )
{
	const AVP_Navigation::NavData& xNavData = GetNavData();

	if ( xNavData.m_pusRoute )
	{
		return true;
	}
	else
	{
		return false;
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetCurrentWeaponType
//------------------------------------------------------------------------
u_int AVP_Brain_Actor_Marine::GetCurrentWeaponType()
{
	// What weapon Do I have?
	AVP_ServerActor_Human*		pxOurActor			= GetHumanActor();
	AVP_Inventory_System*		pxInventorySystem	= pxOurActor->GetInventorySystem();
	AVP_Inventory_Item*			pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON ) : NULL;
	AVP_RangedWeapon_SubType*	pxSubType			= NULL;

	if(pxCurrentWeapon && pxCurrentWeapon->GetNumSubTypes() > 0)
	{
		pxSubType = static_cast<AVP_RangedWeapon_SubType*>(pxCurrentWeapon->GetSubType( 0 ));
	}
	
	return ( pxSubType ? pxSubType->GetAIWeaponBehaviourType() : static_cast< u_int >( AVP_WEAPON_BEHAVIOUR_TYPE_NONE ) );
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetThreatPos
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::GetThreatPos( Asura_Vector_3& xPosition )
{
	xPosition = GetKnowledgeSystem()->GetBestThreatKnowledge().m_xPosition;
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: LookAtPlayerHeadPosition
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::LookAtPlayerHeadPosition(void)
{
	AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 );

	if ( pxPlayerInfo )
	{
		AVP_ServerActor_Human* pxPlayer = AVP_ServerActor_Human::FindEntity( pxPlayerInfo->GetPuppetGuid() );

		if ( pxPlayer )
		{
			Asura_Vector_3 xHeadPos( Asura_Maths::ZeroVector3 );

			pxPlayer->GetHeadPosition( xHeadPos );
			SetLookAtPosition( xHeadPos );
		}
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: AimAtPlayerHeadPosition
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::AimAtPlayerHeadPosition(void)
{
	AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 );

	if ( pxPlayerInfo )
	{
		AVP_ServerActor_Human* pxPlayer = AVP_ServerActor_Human::FindEntity( pxPlayerInfo->GetPuppetGuid() );

		if ( pxPlayer )
		{
			Asura_Vector_3 xHeadPos( Asura_Maths::ZeroVector3 );

			pxPlayer->GetHeadPosition( xHeadPos );
			AimAtPosition( xHeadPos );
		}
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: CanFidget
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::CanFidget()
{
	AVP_ServerActor_Human*		pxOurActor		= GetHumanActor();

	if ( pxOurActor->GetAIAnimStateMachine() && pxOurActor->GetAIAnimStateMachine()->IsIdle() )
	{
		const Asura_Matrix_3x3&		xOri			= pxOurActor->GetOrientation();
		Asura_Vector_3				xFwd( xOri.e13, xOri.e23, xOri.e33 );
		Asura_Vector_3				xAim( GetAimDirection() );

		float fDot = xFwd * xAim;

		if ( fDot > 0.97f )
		{
			return true;
		}
	}

	return false;
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: LookAt_LookAtEntity
//------------------------------------------------------------------------
void AVP_Brain_Actor_Marine::LookAt_LookAtEntity( void )
{
	switch ( m_uLookAtType )
	{
		case LOOK_AT_TYPE_NODE:
		{
			AVP_ServerEntity_LookAt* pxLookAt = AVP_ServerEntity_LookAt::FindEntity( m_uLookAtGuid );

			if ( pxLookAt )
			{
				AimAtPosition( pxLookAt->GetPosition() );
				SetLookAtPosition( pxLookAt->GetPosition() );
				
				AVP_Human_AIAnimStateMachine* pxHumanStateMachine = static_cast<AVP_Human_AIAnimStateMachine*>( GetHumanActor()->GetAIAnimStateMachine() );

				if ( pxHumanStateMachine && pxHumanStateMachine->IsIdle() )
				{
					Asura_Vector_3 xDir( pxLookAt->GetPosition() - GetHumanActor()->GetPosition() );
					xDir.Normalise();
					SetMovementDirection( xDir );
				}
			}

		}break;

		case LOOK_AT_TYPE_ACTOR:
		case LOOK_AT_TYPE_PLAYER:
		{
			AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( m_uLookAtGuid );

			if ( pxActor )
			{
				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 LOOK_AT_TYPE_NONE:
		default:
		{
			LookForward();
			return;
		}
	}
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetLaregestBehaviourSize
//------------------------------------------------------------------------
bool AVP_Brain_Actor_Marine::HasChildWhichIsAlertBehaviour( void )
{
	if ( m_pxFirstBehaviour )
	{
		Axon_Behaviour* pxBehaviour = m_pxFirstBehaviour->GetChildWithType( m_pxFirstBehaviour, AVP_BEHAVIOUR_TYPE_MARINE_SQUADLEADER );

		if ( pxBehaviour )
		{
			Axon_Behaviour* pxAlertBehaviour = pxBehaviour->GetChildWithType( m_pxFirstBehaviour, AVP_BEHAVIOUR_TYPE_MARINE_ALERT, true );

			if ( pxAlertBehaviour )
			{
				return true;
			}
			else
			{
				return false;
			}

		}

		pxBehaviour = m_pxFirstBehaviour->GetChildWithType( m_pxFirstBehaviour, AVP_BEHAVIOUR_TYPE_MARINE_SQUADMEMBER );

		if ( pxBehaviour )
		{
			Axon_Behaviour* pxAlertBehaviour = pxBehaviour->GetChildWithType( m_pxFirstBehaviour, AVP_BEHAVIOUR_TYPE_MARINE_ALERT, true );

			if ( pxAlertBehaviour )
			{
				return true;
			}
			else
			{
				return false;
			}
		}
	}

	return false;
}

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: GetLaregestBehaviourSize
//------------------------------------------------------------------------
u_int AVP_Brain_Actor_Marine::GetLargestBehaviourSize()
{
    u_int uLargestBehaviourSize = 0;

	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Alert);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_SquadMember);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_SquadLeader);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Human_Grapple);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_InCover);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Investigate);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Human_Movement);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_MeleeCounter);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Patrol);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Travel);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Weapon);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_TestBehaviour);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_GS2Node_Marine_Combat);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_GS2Node_Marine_LookAt);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_HideFromCloakedPredator);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_HandleObjective);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_AttackSelector);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_Advance);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_FallBack);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_SmartGun);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_StandGround);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_Support);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Attack_Travelling);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_MeleePlayer);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_Injured);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Marine_TequilaCarried);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_GS2Spline_Marine_Combat);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_Human_Lift);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_GS2Node_Human_CoreNodeWithGunFire);
	AXON_CALC_MAX_BEHAVIOUR_SIZE(uLargestBehaviourSize, AVP_Behaviour_GS2Spline_Human_CoreSplineWithGunFire);

    return uLargestBehaviourSize;
}

#ifndef ASURA_NO_DEBUG_OUTPUT

static const char* s_aszMoraleStrings[AVP_Human_MoraleHandler::MAX_MORALE_TYPES] =
{
	"LOW MORALE",
	"NORMAL MORALE",
	"HIGH MORALE",
};

DEBUGVAR bool g_bRenderMoraleInfo = true;
DEBUGVAR bool g_bRenderHeadDirection = false;

void AVP_Brain_Actor_Marine::DoRenderDebugInfo()
{
	Asura_Vector_3 xOutputPos = GetHumanActor()->GetPosition();

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

	if ( GetHumanActor()->GetClassification() == AVP_ENTITYCLASS_MARINE )
	{
		SetRenderRoute( true );
	}
	else
	{
		SetRenderRoute( false );
	}

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

	PARENT::DoRenderDebugInfo();

	if ((AVP_Brain_Actor::GetRenderGuid() == ASURA_GUID_UNREGISTERED) || (AVP_Brain_Actor::GetRenderGuid() == GetOwnerGuid()))
	{
		if ( g_bRenderHeadDirection )
		{
			AVP_ClientEntity_Actor* pxClient = AVP_ClientEntity_Actor::FindEntity(GetOwnerGuid());

			// For cases of spawned actors make sure we have started to render them before trying to use them for knowledge.
			if (pxClient && pxClient->GetShapeInstance().GetAnimation() && pxClient->GetShapeInstance().GetAnimation()->GetTweenStore())
			{
				if (pxClient->GetShapeInstance().GetAnimation()->GetTweenStore()->IsPositionDataValid())
				{
					// render the heads orientation
					Asura_Vector_3 xHeadPos = Asura_Maths::ZeroVector3;
					Asura_Vector_3 xHeadFwd = Asura_Maths::ZeroVector3;
					GetHumanActor()->GetHeadPosition(xHeadPos);
					GetHumanActor()->GetHeadFowardVector(xHeadFwd);
					Asura_DebugLineRender::AddArrow(xHeadPos, xHeadPos + (xHeadFwd * 0.5f));
				}
			}
		}

		if (g_bRenderMoraleInfo)
		{
			if (GetHumanActor()->GetMoraleHandler())
			{
				Asura_Font_System::Print
				(
					GetDebugOutputPos().x,
					GetDebugOutputPos().y,
					0.5f,
					0xffffffff,
					ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, 
					"Morale : %.2f", GetHumanActor()->GetMoraleHandler()->GetCurrentValue()
				);

				GetDebugOutputPos().y += 10.0f;

				Asura_Font_System::Print
				(
					GetDebugOutputPos().x,
					GetDebugOutputPos().y,
					0.5f,
					0xffffffff,
					ASURA_TEXTFORMAT_CENTREJUSTIFIED, 
					s_aszMoraleStrings[GetHumanActor()->GetMoraleHandler()->GetMoraleValue()]
				);
				GetDebugOutputPos().y += 10.0f;
			}
		}
	}

	GetKnowledgeSystem()->RenderDebugInfo();
}
#endif

//------------------------------------------------------------------------
// AVP_Brain_Actor_Marine :: Verify
//------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
bool AVP_Brain_Actor_Marine::Verify()
{
	Asura_Assert( m_pxTacticalSystem, "AVP_Brain_Actor_Marine::Verify - no tactical system" );
	Asura_Assert( m_pxKnowledgeSystem, "AVP_Brain_Actor_Marine::Verify - no knowledge system" );
	Asura_Assert( GetHumanActor(), "AVP_Brain_Actor_Marine::Verify - no human actor" );

	bool bSquadReturn = true;

	if ( GetHumanActor()->GetInitialSquadGuid() != ASURA_GUID_UNREGISTERED )
	{
		AVP_ServerEntity_Squad_Marine* pxSquad = GetMarineSquad();

		Asura_Assert( pxSquad, "AVP_Brain_Actor_Marine::Verify - We are meant to have a squad and we dont" );

		if ( !pxSquad )
		{
			bSquadReturn = false;
		}
	}

	return ( PARENT::Verify() && m_pxTacticalSystem && m_pxTacticalSystem->Verify() && m_pxKnowledgeSystem && m_pxKnowledgeSystem->Verify() && GetHumanActor() && bSquadReturn );
}
#endif

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
