//----------------------------------------------------------------------
// File			: AVP_ServerEntity_Squad_Marine.cpp
// Created		: 01 / 11 / 07
// Created By	: Gareth Thomas
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//----------------------------------------------------------------------

//----------------------------------------------------------------------
// INCLUDES
//----------------------------------------------------------------------
// Core
#include "Core/Asura.h"

// Header
#include "Entity/Controller/AVP_ServerEntity_Squad_Marine.h"

#include <stdlib.h>

// Asura
#include "ChunkSystem/Asura_Chunk_Stream.h"
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Camera/Asura_Camera.h"
#include "Debugging/Asura_DebugLineRender.h"
#include "Rendering/Asura_Font_System.h"
#endif
#include "Entity/Locations/OrientedNode/CoverpointNode/AVP_ServerNode_CoverpointNode.h"
#include "Interface/Asura_CommandConsole.h"
#include "Network/Asura_Message.h"
#ifdef ASURA_TOOLS
#include "EntityTemplate/Tools_EntityTemplate_System.h"
#endif

// AvP
#include "Actor/Vertebrates/Human/AVP_Human_MoraleHandler.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/AVP_Entity_EventIDs.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Controller/AVP_Controller_Messages.h"
#include "Entity/GamePlayVolume/AVP_ServerEntity_GamePlayVolume.h"
#include "Entity/Locations/FormationPoint/AVP_ServerNode_FormationPoint.h"
#include "Entity/Locations/Objective/Marine/AVP_ServerEntity_Objective_Marine.h"
#include "Entity/Locations/OrientedNode/GamesceneNode/AVP_ServerNode_GS2Node.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_AlienQueen_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"

// Axon
#include "Core/BrainTypes/AVP_Brain_Actor.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Core/BrainTypes/AVP_Brain_Squad_Marine.h"
#include "Knowledge/AVP_Knowledge_System_Actor.h"
#include "Knowledge/Axon_Knowledge.h"
#include "Tactical/AVP_Tactical_System.h"

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine
//----------------------------------------------------------------------

AVP_ServerEntity_Squad_Marine* AVP_ServerEntity_Squad_Marine::s_pxDefaultSquad = NULL;
Asura_Hashed_List< AVP_ServerEntity_Squad_Marine > AVP_ServerEntity_Squad_Marine::s_xList;

const char* AVP_ServerEntity_Squad_Marine::s_aszSquadCombatStateNames[ AVP_ServerEntity_Squad_Marine::MAX_SQUAD_COMBAT_STATES ] =
{
	"Normal Mode",
	"Stand Ground Mode",
};

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: Constructor
//----------------------------------------------------------------------
AVP_ServerEntity_Squad_Marine::AVP_ServerEntity_Squad_Marine( Asura_Guid uGuid )
: AVP_ServerEntity_Squad( uGuid )
, m_uFlags(0)
, m_pxSquadBrain( NULL )
, m_pxCurrentObjective( NULL )
, m_uSquadLeaderGuid( ASURA_GUID_UNREGISTERED )
, m_fTimeSinceLastThreat( 0.0f )
, m_pxAssignedRequiredActions( NULL )
, m_pxAssignedOptionalActions( NULL )
, m_uNumAssignedRequiredAction( 0 )
, m_uNumAssignedOptionalAction( 0 )
, m_uNumMembersCompletedActions( 0 )
, m_uNumMembersMovingToObjective( 0 )
, m_uNumMembersRequestedactions( 0 )
, m_bHasObjective( false )
, m_uCombatZoneGPVGuid( ASURA_GUID_UNREGISTERED )
, m_uSquadCombatState( SQUAD_COMBAT_STATE_NORMAL )
, m_uLeadGuid( ASURA_GUID_UNREGISTERED )
, m_uRearGuardGuid( ASURA_GUID_UNREGISTERED )
, m_bSquadTransferred( false )
, m_bSquadSetup( false )
, m_uCurrentObjectiveType( AVP_ServerNode_Objective_Marine::MOVE_SLOW_STOP_TO_ENGAGE )
, m_uCurrentObjectiveThreatAction( AVP_ServerNode_Objective_Marine::STOP_TO_ENGAGE )
, m_uCurrentObjectiveMovementMode( AVP_Navigation::MM_SLOW )
{
	Classification = AVP_ENTITYCLASS_MARINESQUAD;

	SetNeverUpdateClient();

	// Create the objective list
	m_pxObjectiveList = new Asura_List< Objective >;
	m_pxObjectiveList->ClearList();

	// Create the squads brain
	m_pxSquadBrain = new AVP_Brain_Squad_Marine( this );
	m_pxSquadBrain->Initialise();

	for ( int i = 0; i < MAX_SQUAD_MEMBERS; ++i )
	{
		m_auTargets[i] = ASURA_GUID_UNREGISTERED;
	}

	s_xList.AddToList( this );
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: Deconstructor
//----------------------------------------------------------------------
AVP_ServerEntity_Squad_Marine::~AVP_ServerEntity_Squad_Marine( void )
{
	// deleted the objective list
	if ( m_pxObjectiveList )
	{
		Asura_List_It < Objective > xObjectiveListIter ( m_pxObjectiveList );

		while ( !xObjectiveListIter.Done() )
		{
			Objective* pxObjective = xObjectiveListIter.GetCurrent();
			xObjectiveListIter.DeleteCurrent();
			delete ( pxObjective );
		}

		m_pxObjectiveList->ClearList();
		delete ( m_pxObjectiveList );
		m_pxObjectiveList = NULL;
	}

	// delete our current objective
	if ( m_pxCurrentObjective )
	{
		delete m_pxCurrentObjective;
		m_pxCurrentObjective = NULL;
	}

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

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

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

	s_xList.RemoveFromList( this );
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: GetPlayersSquad
//----------------------------------------------------------------------
AVP_ServerEntity_Squad_Marine* AVP_ServerEntity_Squad_Marine::GetPlayersSquad()
{
	for ( Asura_Hashed_List_It<AVP_ServerEntity_Squad_Marine> it( /*AVP_ServerEntity_Squad_Marine::*/GetList() ); !it.Done(); it.Next() )
	{
		AVP_ServerEntity_Squad_Marine* pxEntity = it.GetCurrent();

		if ( pxEntity && ( pxEntity->IsPlayersSquad() || pxEntity->IsAILedPlayersSquad() ) && pxEntity->GetNumSquadMembers() > 0 )
		{
			return pxEntity;
		}
	}

	return NULL;
}

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


	if ( iVersion == 0 )
	{
		Asura_Entity_Server::ReadFromChunkStream( xStream );
	}
	else
	{
		PARENT::ReadFromChunkStream( xStream );
	}

	if (iVersion == CURRENT_CHUNK_VERSION)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			Objective* pxCurrentObjective = new Objective;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> pxCurrentObjective->uObjectiveState;

			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;

			xStream >> pxObjective->uObjectiveGuid;
			xStream >> pxObjective->uObjectiveState;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		xStream >> m_uCombatZoneGPVGuid;

		xStream >> m_uSquadCombatState;

		if ( m_uSquadCombatState == 2 )
		{
			m_uSquadCombatState = SQUAD_COMBAT_STATE_NORMAL;
		}

		xStream >> m_uCurrentObjectiveType;
		xStream >> m_uCurrentObjectiveThreatAction;
		xStream >> m_uCurrentObjectiveMovementMode;

		m_pxSquadBrain->ReadFromChunkStream( xStream );

	}
	else if (iVersion == 10 || iVersion == 9)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			u_int uDummy;

			Objective* pxCurrentObjective = new Objective;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxCurrentObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;

			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		xStream >> m_uCombatZoneGPVGuid;

		xStream >> m_uSquadCombatState;

		if ( m_uSquadCombatState == 2 )
		{
			m_uSquadCombatState = SQUAD_COMBAT_STATE_NORMAL;
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );

	}
	else if (iVersion == 8)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			Objective* pxCurrentObjective = new Objective;
			u_int uDummy;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxCurrentObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;
			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		xStream >> m_uCombatZoneGPVGuid;

		xStream >> m_uSquadCombatState;

		if ( m_uSquadCombatState == 2 )
		{
			m_uSquadCombatState = SQUAD_COMBAT_STATE_NORMAL;
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );

		m_bHasInvestigator = false;

	}
	else if (iVersion == 7)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			Objective* pxCurrentObjective = new Objective;
			u_int uDummy;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxCurrentObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;
			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		xStream >> m_uCombatZoneGPVGuid;

		m_pxSquadBrain->ReadFromChunkStream( xStream );

	}
	else if (iVersion == 6)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			Objective* pxCurrentObjective = new Objective;
			u_int uDummy;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxCurrentObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;
			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> pxObjective->uObjectiveState;
			xStream >> uDummy;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else if (iVersion == 5)
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			Objective* pxCurrentObjective = new Objective;
			u_int uDummy;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			xStream >> uDummy;
			xStream >> pxCurrentObjective->uObjectiveState;
			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;

			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else if ( iVersion == 1 || iVersion == 0 )
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );
		xStream >> xBitfield;

		u_int uTempDummyValue = 0;

		// not used any more
		xStream >> uTempDummyValue;

		// Need to store these so we can fix it up in tools
		for ( int i = 0; i < MAX_SQUAD_MEMBERS; ++i )
		{
			xStream >> m_auSquadMembers[ i ];
		}

		// Not used any more
		xStream >> uTempDummyValue;

		// set so we can fix up in tools.
		m_bSquadTransferred = false;

		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else if ( iVersion == 2 )
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;
		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else if ( iVersion == 3 )
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		m_bOldAndUnusedNow1 = false;
		m_bMemberHasThreat = false;
		m_bMemberHasAlertKnowledge = false;
		m_bOldAndUnusedNow2 = false;
		m_bHasThreatMessageSent = false;
		m_bHasAlertMessageSent = false;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{

			u_int uDummy;
			Objective* pxCurrentObjective = new Objective;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;
			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else if ( iVersion == 4 )
	{
		Asura_ReadFromStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

		xStream >> xBitfield;

		u_char bHasObjective = 0;
		xStream >> bHasObjective;

		if ( bHasObjective == 1 )
		{
			u_int uDummy;
			Objective* pxCurrentObjective = new Objective;
			xStream >> pxCurrentObjective->uObjectiveGuid;
			xStream >> uDummy;
			m_bHasObjective = false;
			m_pxObjectiveList->PushHead( pxCurrentObjective );
		}

		u_int uNumObjectives = 0;
		xStream >> uNumObjectives;

		for ( u_int u = 0; u < uNumObjectives; ++u )
		{
			Objective* pxObjective = new Objective;
			u_int uDummy;
			xStream >> pxObjective->uObjectiveGuid;
			xStream >> uDummy;

			m_pxObjectiveList->PushTail( pxObjective );
		}

		m_pxSquadBrain->ReadFromChunkStream( xStream );
	}
	else
	{
		Asura_Assertf( false, ( "AVP_ServerEntity_Squad_Marine::ReadFromChunkStream - bad chunk version (%d)", iVersion ) );
	}
	#ifdef ASURA_TOOLS
	if(iVersion < 10)
	{
		//Fix old data so that the unused bits are zeroed. RAR 28/11/2008
		m_uFlags &= 0x7ff;
	}
	#endif
}

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

	PARENT::WriteToChunkStream( xStream );

	Asura_WriteToStream_Bitfield_Wrapper< u_int > xBitfield( m_uFlags );

	xBitfield.Add( m_bIsPlayersSquad			, 1 );
	xBitfield.Add( m_bOldAndUnusedNow1			, 1 );
	xBitfield.Add( m_bMemberHasThreat			, 1 );
	xBitfield.Add( m_bMemberHasAlertKnowledge	, 1 );
	xBitfield.Add( m_bOldAndUnusedNow2			, 1 );
	xBitfield.Add( m_bHasThreatMessageSent		, 1 );
	xBitfield.Add( m_bHasAlertMessageSent		, 1 );
	xBitfield.Add( m_bIsAILedPlayersSquad		, 1 );
	xBitfield.Add( m_bIsLimitedToCombatZone		, 1 );
	xBitfield.Add( m_bIgnoreAlertState			, 1 );
	xBitfield.Add( m_bHasInvestigator			, 1 );

	xStream << xBitfield;

	u_char bHasObjective = 0;

	if ( m_pxCurrentObjective )
	{
		bHasObjective = 1;
		xStream << bHasObjective;
		xStream << m_pxCurrentObjective->uObjectiveGuid;
		xStream << m_pxCurrentObjective->uObjectiveState;
	}
	else
	{
		xStream << bHasObjective;
	}

	u_int uNumObjectives = m_pxObjectiveList->GetNumEntries();

	xStream << uNumObjectives;

	for ( u_int u = 0; u < uNumObjectives; ++u )
	{
		Objective* pxObjective = m_pxObjectiveList->GetEntryByIndex( u );

		xStream << pxObjective->uObjectiveGuid;
		xStream << pxObjective->uObjectiveState;
	}

	xStream << m_uCombatZoneGPVGuid;

	xStream << m_uSquadCombatState;

	xStream << m_uCurrentObjectiveType;
	xStream << m_uCurrentObjectiveThreatAction;
	xStream << m_uCurrentObjectiveMovementMode;

	m_pxSquadBrain->WriteToChunkStream( xStream );
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: HandleMessage
//----------------------------------------------------------------------
bool AVP_ServerEntity_Squad_Marine::HandleMessage( const Asura_Message* pxMessage )
{
	switch (pxMessage->GetMsgID() )
	{
		case AVP_MSGID_ALIENQUEEN_ADD_TO_TARGET_LIST:
		{
			const AVP_Msg_Add_Entity_To_Queen_Target_List *pxData = static_cast<const AVP_Msg_Add_Entity_To_Queen_Target_List*>( pxMessage->GetData() );

			if( pxData->GetQueenGuid() != ASURA_GUID_UNREGISTERED )
			{
				Asura_Network::Forward( pxMessage, pxData->GetQueenGuid(), GetGuid()  );
			}

			return true;
		}

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

			if( pxData->GetQueenGuid() != ASURA_GUID_UNREGISTERED )
			{
				Asura_Network::Forward( pxMessage, pxData->GetQueenGuid(), GetGuid()  );
			}

			return true;
		}

		case AVP_MSGID_MOUNT_LIFT:
		case AVP_MSGID_DISMOUNT_LIFT:
		case AVP_MSGID_LOOK_AT_ENTITY:
		case AVP_MSGID_STOP_LOOKING_AT_ENTITY:
		case AVP_MSGID_ATTACK_SCRIPTED_TARGET:
		case AVP_MSGID_STOP_ATTACKING_SCRIPTED_TARGET:
		{
			for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
			{
				Asura_Guid uMemberGuid = GetMemberGuid( u );
				
				AVP_ServerActor_Human* pxMember = AVP_ServerActor_Human::FindEntity( uMemberGuid );

				if ( pxMember && !pxMember->IsDead() && pxMember->IsEntityActive() && !pxMember->IsPlayer() )
				{
					pxMember->HandleMessage( pxMessage );
				}
			}

			return true;

		}

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

			if ( pxMsgData )
			{
				m_bIsPlayersSquad			= ( pxMsgData->m_bIsPlayersSquad == 1 ) ? true : false;
				m_bIsAILedPlayersSquad		= ( pxMsgData->m_bIsAiLedPlayersSquad == 1 ) ? true : false;
				m_bIsLimitedToCombatZone	= ( pxMsgData->m_bIsRestrictedToCombatZone == 1) ? true : false;

				if (!m_bIsLimitedToCombatZone)
				{
					m_uCombatZoneGPVGuid	= ASURA_GUID_UNREGISTERED;
				}
				else
				{
					m_uCombatZoneGPVGuid	= pxMsgData->m_uCombatZoneGPVGuid;
				}

				m_uSquadCombatState = (u_int)pxMsgData->m_iSquadCombatType;
				
				UpdateLeaderIfNeeded();
			}

			return true;
		}
		//----------------------------------------------------------------------

		case AVP_MSGID_SET_SQUAD_ALERT_STATUS_TO_PASSIVE:
		{
			for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
			{
				AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

				if ( pxHuman && pxHuman->IsEntityActive() && !pxHuman->IsDead() && !pxHuman->IsPlayer() )
				{
					AVP_Brain_Actor_Marine* pxMarineBrain = ( AVP_Brain_Actor_Marine* )pxHuman->GetActorBrain();

					if ( pxMarineBrain )
					{
						pxMarineBrain->GetKnowledgeSystem()->SetAlertLevel( AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS );
						pxMarineBrain->GetKnowledgeSystem()->ResetAlertTimer();
					}
				}
			}

			return true;

		}

		case AVP_MSGID_SET_SQUAD_ALERT_STATUS_TO_ACTIVE:
		{
			for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
			{
				AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

				if ( pxHuman && pxHuman->IsEntityActive() && !pxHuman->IsDead() && !pxHuman->IsPlayer() )
				{
					AVP_Brain_Actor_Marine* pxMarineBrain = ( AVP_Brain_Actor_Marine* )pxHuman->GetActorBrain();

					if ( pxMarineBrain )
					{
						pxMarineBrain->GetKnowledgeSystem()->SetAlertLevel( AVP_Knowledge_System_Actor::ACTIVE_ALERTNESS );
						pxMarineBrain->GetKnowledgeSystem()->ResetAlertTimer();
					}
				}
			}

			return true;

		}

		case AVP_MSGID_SET_SQUAD_ALERT_STATUS_TO_AGGRESSIVE:
		{
			for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
			{
				AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

				if ( pxHuman && pxHuman->IsEntityActive() && !pxHuman->IsDead() && !pxHuman->IsPlayer() )
				{
					AVP_Brain_Actor_Marine* pxMarineBrain = ( AVP_Brain_Actor_Marine* )pxHuman->GetActorBrain();

					if ( pxMarineBrain )
					{
						pxMarineBrain->GetKnowledgeSystem()->SetAlertLevel( AVP_Knowledge_System_Actor::AGGRESSIVE_ALERTNESS );
						pxMarineBrain->GetKnowledgeSystem()->ResetAlertTimer();
					}
				}
			}

			return true;

		}

		//----------------------------------------------------------------------

		case ASURA_MSG_AXON_GS2_EXIT_GAMESCENE:
		{
			for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
			{
				AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

				if ( pxHuman )
				{
					Asura_Message* pxMessage = Asura_Network::CreateMessage( ASURA_MSG_AXON_GS2_EXIT_GAMESCENE );
					if ( pxMessage )
					{
						pxMessage->SetFromGuid( GetGuid() );
						pxMessage->SetToGuid( pxHuman->GetGuid() );
						pxHuman->HandleMessage( pxMessage );
						Asura_Network::DestroyMessage( pxMessage );
					}

					pxMessage = Asura_Network::CreateMessage( AVP_MSGID_STOP_AI_OBJECTIVE_ACTIONS );
					if ( pxMessage )
					{
						pxMessage->SetFromGuid( GetGuid() );
						pxMessage->SetToGuid( pxHuman->GetGuid() );
						pxHuman->HandleMessage( pxMessage );
						Asura_Network::DestroyMessage( pxMessage );
					}
				}
			}
		}

		//----------------------------------------------------------------------

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

			if ( pxMsgData )
			{
				// check it doesn't already exist
				for ( int i = 0; i < m_pxObjectiveList->GetNumEntries(); ++i )
				{
					Objective* pxObjective = m_pxObjectiveList->GetEntryByIndex( i );

					if ( pxObjective )
					{
						if ( pxObjective->uObjectiveGuid == pxMsgData->GetObjectiveGuid() )
						{
							Asura_Assertf( false, ( "This Squad Already Had this Goal. GUID %d", pxMsgData->GetObjectiveGuid() ) );
							return true;
						}
					}
				}

				AVP_ServerNode_Objective_Marine* pxFindObjective = AVP_ServerNode_Objective_Marine::FindEntity( pxMsgData->GetObjectiveGuid() );

				if ( !pxFindObjective )
				{
					Asura_Assertf( false, ( "Trying to add an Goal that doesn't exist. GUID  : %d", pxMsgData->GetObjectiveGuid() ) );
					return true;
				}

				// add the objective to the list
				Objective* pxNewObjective = new Objective;

				pxNewObjective->uObjectiveGuid = pxMsgData->GetObjectiveGuid(); 
				pxNewObjective->uObjectiveState = AVP_ServerNode_Objective_Marine::NOT_STARTED;

				m_pxObjectiveList->PushTail( pxNewObjective );
				m_bHasObjective = false;
			}
			return true;

		}

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

			if ( pxMsgData )
			{
				m_uCurrentObjectiveType = pxMsgData->m_iMovementMode;

				switch ( pxMsgData->m_iMovementMode )
				{
					case AVP_ServerNode_Objective_Marine::ADVANCE_SLOW:
					case AVP_ServerNode_Objective_Marine::RETREAT_SLOW:
					case AVP_ServerNode_Objective_Marine::MOVE_SLOW_DONT_STOP_TO_ENGAGE:
					{
						m_uCurrentObjectiveThreatAction = AVP_ServerNode_Objective_Marine::NO_ACTION;
						m_uCurrentObjectiveMovementMode = AVP_Navigation::MM_SLOW;

					}break;
					
					case AVP_ServerNode_Objective_Marine::MOVE_MEDIUM_STOP_TO_ENGAGE:
					{
						m_uCurrentObjectiveThreatAction = AVP_ServerNode_Objective_Marine::STOP_TO_ENGAGE;
						m_uCurrentObjectiveMovementMode = AVP_Navigation::MM_MEDIUM;

					}break;

					case AVP_ServerNode_Objective_Marine::ADVANCE_MEDIUM:
					case AVP_ServerNode_Objective_Marine::RETREAT_MEDIUM:
					case AVP_ServerNode_Objective_Marine::MOVE_MEDIUM_DONT_STOP_TO_ENGAGE:
					{
						m_uCurrentObjectiveThreatAction = AVP_ServerNode_Objective_Marine::NO_ACTION;
						m_uCurrentObjectiveMovementMode = AVP_Navigation::MM_MEDIUM;

					}break;
				
					case AVP_ServerNode_Objective_Marine::MOVE_SLOW_STOP_TO_ENGAGE:
					default:
					{
						m_uCurrentObjectiveThreatAction = AVP_ServerNode_Objective_Marine::STOP_TO_ENGAGE;
						m_uCurrentObjectiveMovementMode = AVP_Navigation::MM_SLOW;

					}break;
				}
			}

			return true;
		}


		//----------------------------------------------------------------------

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

			if ( pxMsgData )
			{
				if ( GetNumSquadMembers() < MAX_SQUAD_MEMBERS )
				{
					bool bExists = false;

					for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
					{
						if ( GetMemberGuid(u) == pxMsgData->GetGuidToAdd() )
						{
							bExists = true;
						}
					}

					if ( !bExists )
					{
						AddMember( pxMsgData->GetGuidToAdd() );

						AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( pxMsgData->GetGuidToAdd() );

						if ( pxHuman )
						{
							pxHuman->SetInitialSquadGuid( GetGuid() );
						}
					}
				}
			}

			return true;

		}

		//----------------------------------------------------------------------

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

			if ( pxMsgData )
			{
				for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
				{
					if ( GetMemberGuid( u ) == pxMsgData->GetGuidToRemove() )
					{
						RemoveMember( pxMsgData->GetGuidToRemove() );

						AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( pxMsgData->GetGuidToRemove() );

						if ( pxHuman )
						{
							pxHuman->SetInitialSquadGuid( ASURA_GUID_UNREGISTERED );
						}
					}
				}
			}

			return true;

		}

		//----------------------------------------------------------------------

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

			if ( pxMsgData )
			{
				AVP_ServerEntity_Squad_Marine* pxDestinationSquad = AVP_ServerEntity_Squad_Marine::FindEntity( pxMsgData->m_uSquadToAddTo );

				if ( pxDestinationSquad )
				{
					for ( u_int u = 0; u < MAX_SQUAD_MEMBERS; ++u )
					{
						if (pxMsgData->m_auSplitMembers[ u ] != ASURA_GUID_UNREGISTERED)
						{
							RemoveMember( pxMsgData->m_auSplitMembers[ u ] );
						}
					}

					for ( u_int u = 0; u < MAX_SQUAD_MEMBERS; ++u )
					{
						if ( pxMsgData->m_auSplitMembers[ u ] != ASURA_GUID_UNREGISTERED )
						{
							pxDestinationSquad->AddMember( pxMsgData->m_auSplitMembers[ u ] );

							AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( pxMsgData->m_auSplitMembers[ u ] );

							if ( pxHuman )
							{
								pxHuman->SetInitialSquadGuid( pxDestinationSquad->GetGuid() );
							}
						}
					}
				}
			}

			return true;

		}

		//----------------------------------------------------------------------

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

			if ( pxMsgData )
			{
				AVP_ServerEntity_Squad_Marine* pxDestinationSquad = AVP_ServerEntity_Squad_Marine::FindEntity( pxMsgData->m_uSquadToMergeInto );

				if ( pxDestinationSquad )
				{
					Asura_Guid uMemberGuids[ MAX_SQUAD_MEMBERS ];

					for ( u_int u = 0; u < MAX_SQUAD_MEMBERS; ++u )
					{
						uMemberGuids[ u ] = ASURA_GUID_UNREGISTERED;
					}

					for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
					{
						uMemberGuids[ u ] = GetMemberGuid( u );
					}

					for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
					{
						pxDestinationSquad->AddMember( GetMemberGuid( u ) );
						
						AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

						if ( pxHuman )
						{
							pxHuman->SetInitialSquadGuid( pxDestinationSquad->GetGuid() );
						}
					}

					for ( u_int u = 0; u < MAX_SQUAD_MEMBERS; ++u )
					{
						RemoveMember( uMemberGuids[ u ] );
					}
				}
			}

			return true;

		}

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

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: Create
//----------------------------------------------------------------------
AVP_ServerEntity_Squad_Marine* AVP_ServerEntity_Squad_Marine::Create( const Asura_Guid uGuid )
{
	return new AVP_ServerEntity_Squad_Marine( uGuid );
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: UpdateLeaderIfNeeded
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::UpdateLeaderIfNeeded( void )
{
	if ( IsPlayersSquad() )
	{
		// This Needs changing in future as its single player only
		AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 ); 
	 
		if ( pxPlayerInfo )
		{
			AVP_ServerActor_Human* pxPlayerMarine = AVP_ServerActor_Human::FindEntity( pxPlayerInfo->GetPuppetGuid() );
 
			if ( pxPlayerMarine )
			{
				SetSquadLeader( pxPlayerMarine->GetGuid() );
			}
		}

		return;
	}

	bool bFoundLeader = false;

	for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
	{
		Asura_Guid uMemberGuid = GetMemberGuid( u );

		if ( ( uMemberGuid != ASURA_GUID_UNREGISTERED ) && ( GetSquadLeaderGuid() == uMemberGuid ) )
		{
			AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( uMemberGuid );

			if ( pxHuman && !pxHuman->IsDead() && pxHuman->IsEntityActive() )
			{
				bFoundLeader = true;
			}
		}
	}

	if ( !bFoundLeader )
	{
		for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
		{
			Asura_Guid uMemberGuid = GetMemberGuid( u );

			AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( uMemberGuid );

			if ( pxHuman && !pxHuman->IsDead() && pxHuman->IsEntityActive() )
			{
				if ( uMemberGuid != ASURA_GUID_UNREGISTERED )
				{
					SetSquadLeader( uMemberGuid );
					break;
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: Update
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::Update( void )
{
	PARENT::Update();

	if ( !IsSquadSetup() )
	{
		// Can't go in post load as we cannot guarantee that all members have registered with the squad yet.
		SetupSquad();
	}

	// Keep the squad leader up to date
	UpdateLeaderIfNeeded();

	// Update objectives
	ProcessObjective();
	ProcessCurrentObjective();

	// See if anyone in the squad has a threat
	UpdateSquadThreatStatus();

	if ( !IsPlayersSquad() && AllMembersHaveValidRoute() )
	{
		UpdatePositions();
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: UpdateLeadPositionMarine
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::UpdatePositions()
{
	float fBestRearRouteDistance = 0.0f;
	float fBestLeadRouteDistance = Asura_Maths::LargeFloat;

	m_uLeadGuid = ASURA_GUID_UNREGISTERED;
	m_uRearGuardGuid = ASURA_GUID_UNREGISTERED;

	for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
	{
		AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( GetMemberGuid( u ) );

		if ( pxActor && !pxActor->IsDead() && pxActor->IsEntityActive() && pxActor->GetActorBrain() )
		{
			const AVP_Navigation::NavData& xNavData = pxActor->GetActorBrain()->GetNavData();

			u_short			uRouteSegmentIndex = 0;
			Asura_Vector_3	xNearestPos( Asura_Maths::ZeroVector3 );

			if ( xNavData.m_pusRoute && xNavData.m_usRouteLength > 0 )
			{
				AVP_Navigation::FindNearestPointOnRoute( xNavData, pxActor->GetPosition(), 0.0f, xNearestPos, uRouteSegmentIndex );
				float fRouteDistance = AVP_Navigation::CalculateRouteDistance( xNavData, xNearestPos, uRouteSegmentIndex );

				if ( fRouteDistance < fBestLeadRouteDistance )
				{
					m_uLeadGuid = pxActor->GetGuid();
					fBestLeadRouteDistance = fRouteDistance;
				}

				if ( fRouteDistance > fBestRearRouteDistance )
				{
					m_uRearGuardGuid = pxActor->GetGuid();
					fBestRearRouteDistance = fRouteDistance;
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: SendMemberDeadMessage
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::SendMemberDeadEventMessage( void )
{
	PARENT::SendMemberDeadEventMessage();

	AVP_ServerActor_Human* pxLeader = GetLeaderMarine();

	if ( pxLeader && pxLeader->IsEntityActive() && !pxLeader->IsDead() )
	{
		pxLeader->PlayDialogue( AVP_ServerActor_Human::AVP_DLG_HUMAN_TEAMMATE_KILLED );
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: SendEventMessages
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::SendEventMessages( void )
{
	if ( IsSquadSetup() )
	{
		if ( GetHasHadMoreThanOneMember() && GetNumSquadMembers() == 0 && !GetElimintedEventSent() && !IsPlayersSquad() && IsEntityActive() )
		{
			SetElimintedEventSent( true );
			SendMessagesForEvent( AVP_ENTITY_EVENT_SQUAD_ELIMINATED );
		}

		// Alert event
		if ( DoesMemberHaveAlertKnowledge() && !m_bHasAlertMessageSent )
		{
			m_bHasAlertMessageSent = true;
			SendMessagesForEvent( AVP_ENTITY_EVENT_SQUAD_ALERTED );
		}
		else if ( !DoesMemberHaveAlertKnowledge() && m_bHasAlertMessageSent )
		{
			m_bHasAlertMessageSent = false;
		}
		
		// Entering combat event
		if ( DoesMemberHaveThreat() && !m_bHasThreatMessageSent )
		{
			m_bHasThreatMessageSent = true;
			SendMessagesForEvent( AVP_ENTITY_EVENT_SQUAD_ENTERING_COMBAT );
		}
		else if ( !DoesMemberHaveThreat() && m_bHasThreatMessageSent )
		{
			m_bHasThreatMessageSent = false;
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: UpdateSquadThreatStatus
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::UpdateSquadThreatStatus( void )
{
	m_bMemberHasThreat = false;
	m_bMemberHasAlertKnowledge = false;

	if ( m_fTimeSinceLastThreat > 0.0f )
	{
		m_fTimeSinceLastThreat -= Asura_Timers::GetFrameTime();
	}

	if ( m_fTimeSinceLastThreat < 0.0f )
	{
		m_fTimeSinceLastThreat = 0.0f;
	}

	// Iterate through the squad to see if any of them have a threat.
	for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
	{
		AVP_ServerActor_Human* pxSquadMember = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

		if ( pxSquadMember && pxSquadMember->IsEntityActive() )
		{
			AVP_Brain_Actor_Marine* pxMarineBrain = ( AVP_Brain_Actor_Marine* )pxSquadMember->GetActorBrain();

			if ( pxMarineBrain && pxMarineBrain->GetKnowledgeSystem() )
			{
				AVP_Knowledge_System_Actor* pxKnowledgeSystem = pxMarineBrain->GetKnowledgeSystem();

				if ( pxKnowledgeSystem->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED )
				{
					m_bMemberHasThreat = true;
					m_fTimeSinceLastThreat = 15.0f;
				}

				if ( pxKnowledgeSystem->GetBestAlertKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED )
				{
					m_bMemberHasAlertKnowledge = true;
				}
				else
				{
					if ( pxMarineBrain->HasChildWhichIsAlertBehaviour() )
					{
						m_bMemberHasAlertKnowledge = true;
					}
				}

				if ( m_bMemberHasAlertKnowledge && m_bMemberHasThreat )
				{
					return;
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: SetupSquad
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::SetupSquad( void )
{
	if ( IsPlayersSquad() )
	{
		// This Needs changing in future as its single player only
		AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 ); 
	 
		if ( pxPlayerInfo )
		{
			AVP_ServerActor_Human* pxPlayerMarine = AVP_ServerActor_Human::FindEntity( pxPlayerInfo->GetPuppetGuid() );
 
			if ( !pxPlayerMarine )
			{
				SetIsPlayersSquad( false );
			}
			else
			{
				SetSquadLeader( pxPlayerMarine->GetGuid() );
			}
		}
	}

	if ( !IsPlayersSquad() )
	{
		for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
		{
			Asura_Guid uGuid = GetMemberGuid(u);

			AVP_ServerActor_Human* pxSquadMember = AVP_ServerActor_Human::FindEntity(uGuid);

			if ( ( !pxSquadMember ) || ( pxSquadMember->IsDead() ) || ( !pxSquadMember->IsEntityActive() ) )
			{
				continue;
			}

			if ( uGuid != ASURA_GUID_UNREGISTERED )
			{
				SetSquadLeader( uGuid );
				break;
			}
		}
	}

	m_bSquadSetup = true;
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: GetLeaderMarine
//----------------------------------------------------------------------
AVP_ServerActor_Human* AVP_ServerEntity_Squad_Marine::GetLeaderMarine( void )
{
	if ( IsPlayersSquad() )
	{
		AVP_ServerEntity_PlayerInfo* pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( 1000 );

		if ( pxPlayerInfo )
		{
			return ( AVP_ServerActor_Human::FindEntity( pxPlayerInfo->GetPuppetGuid() ) );
		}
	}
	else
	{
		return ( AVP_ServerActor_Human::FindEntity( m_uSquadLeaderGuid ) );
	}

	return NULL;
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ProcessCurrentObjective
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ProcessCurrentObjective( void )
{
	// Make sure our current Objective is actually valid
	if ( !GetCurrentObjective() )
	{
		return;
	}

	// Get the objective entity
	AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( GetCurrentObjectiveGuid() );

	if ( !pxObjective )
	{
		return;
	}

	if ( pxObjective->GetObjectiveCompleteOnMessageOnly() && pxObjective->GetHasReceivedCompleteMessage() )
	{
		GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::COMPLETE );
	}

	// switch on the objective state
	switch ( GetCurrentObjectiveState() )
	{
		// If we haven't started check the members how many members have started moving to objective;
		case AVP_ServerNode_Objective_Marine::NOT_STARTED:
		{
			if ( IsPlayersSquad() )
			{
				GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::MOVING_TO_OBJECTIVE );
			}

		}break;

		// Check if the squad leader has arrived at the objective
		case AVP_ServerNode_Objective_Marine::MOVING_TO_OBJECTIVE:
		{
			AVP_ServerActor_Human* pxSquadLeader = AVP_ServerActor_Human::FindEntity( GetSquadLeaderGuid() );

			if ( pxSquadLeader && pxObjective->Contains( pxSquadLeader->GetPosition() ) )
			{
				GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::ARRIVED_AT_OBJECTIVE );
				pxObjective->SendObjectiveReachedMessage();
			}
		}break;

		// If we have arrived at the objective then members will need actions assigning.
		case AVP_ServerNode_Objective_Marine::ARRIVED_AT_OBJECTIVE:
		{
			u_int uNumRequired = 0, uNumOptional = 0;

			GetNumOptionalAndRequiredActionGuids( &uNumRequired, &uNumOptional, true );

			if ( uNumRequired == 0 && uNumOptional == 0 )
			{
				GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::COMPLETE );
			}
			
		}break;

		// waiting for members actions to complete
		case AVP_ServerNode_Objective_Marine::WAITING_FOR_COMPLETION:
		{
			u_int uNumRequired = 0, uNumOptional = 0;

			GetNumOptionalAndRequiredActionGuids( &uNumRequired, &uNumOptional, true );
			
			if ( uNumRequired == 0 && uNumOptional == 0 )
			{
				GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::COMPLETE );
			}

		}break;

		case AVP_ServerNode_Objective_Marine::COMPLETE:
		{
			m_bHasObjective = false;
		}break;
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ProcessObjective
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ProcessObjective(void)
{
	if ( !m_bHasObjective )
	{
		if ( m_pxCurrentObjective )
		{
			AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( GetCurrentObjectiveGuid() );
			if ( pxObjective ) { pxObjective->Reset(); }

			ResetCurrentObjective();
		}

		// Assign a new objective if we have one
		if (m_pxObjectiveList->GetNumEntries() > 0)
		{
			m_bHasObjective					= true;
			m_pxCurrentObjective			= m_pxObjectiveList->PopHeadObject();
			m_uNumMembersMovingToObjective	= 0;
			m_uNumMembersRequestedactions	= 0;

			BuildAssignedActionArrays();
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ResetCurrentObjective
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ResetCurrentObjective()
{
	delete m_pxCurrentObjective;
	m_pxCurrentObjective = NULL;

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

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

	m_uNumAssignedRequiredAction = 0;
	m_uNumAssignedOptionalAction = 0;
	m_uNumMembersCompletedActions = 0;
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: MemberIsMovingToObjective
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::MemberIsMovingToObjective( void )
{
	++m_uNumMembersMovingToObjective;

	if ( m_uNumMembersMovingToObjective >= GetNumSquadMembers() )
	{
		if ( GetCurrentObjective() )
		{
			GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::MOVING_TO_OBJECTIVE );
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: MemberHasRequestedAction
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::MemberHasRequestedAction(void)
{
	++m_uNumMembersRequestedactions;

	if ( m_uNumMembersRequestedactions >= GetNumSquadMembers() )
	{
		if ( GetCurrentObjective() )
		{
			GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::WAITING_FOR_COMPLETION );
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: MemberHasCompletedAction
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::MemberHasCompletedAction(void)
{
	++m_uNumMembersCompletedActions;

	if ( m_uNumMembersCompletedActions >= GetNumSquadMembers() )
	{
		if ( GetCurrentObjective() )
		{
			AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( GetCurrentObjectiveGuid() );

			if ( pxObjective )
			{
				pxObjective->SendCompleteEvent();
				m_uNumMembersCompletedActions = 0;
				GetCurrentObjective()->SetObjectiveState( AVP_ServerNode_Objective_Marine::COMPLETE );
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: BuildAssignedActionArrays
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::BuildAssignedActionArrays(void)
{
	u_int uNumRequired = 0;
	u_int uNumOptional = 0;

	GetNumOptionalAndRequiredActionGuids(&uNumRequired, &uNumOptional, false);

	if (uNumRequired > 0)
	{
		if (m_pxAssignedRequiredActions)
		{
			delete [] m_pxAssignedRequiredActions;
			m_pxAssignedRequiredActions = NULL;
		}

		m_pxAssignedRequiredActions = new Asura_Guid[ uNumRequired ];

		for (u_int u = 0; u < uNumRequired; ++u)
		{
			m_pxAssignedRequiredActions[u] = ASURA_GUID_UNREGISTERED;
		}

		m_uNumAssignedRequiredAction = 0;
	}

	if (uNumOptional > 0)
	{
		if (m_pxAssignedOptionalActions)
		{
			delete [] m_pxAssignedOptionalActions;
			m_pxAssignedOptionalActions = NULL;
		}

		m_pxAssignedOptionalActions = new Asura_Guid[ uNumOptional ];

		for (u_int u = 0; u < uNumOptional; ++u)
		{
			m_pxAssignedOptionalActions[u] = ASURA_GUID_UNREGISTERED;
		}

		m_uNumAssignedOptionalAction = 0;
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: RequestAction
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::GetNumOptionalAndRequiredActionGuids( u_int* uNumRequired, u_int* uNumOptional, bool bConsiderActiveState /*= true*/)
{
	if ( ( !m_pxCurrentObjective ) || ( m_pxCurrentObjective->GetObjectiveGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return;
	}

	AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( m_pxCurrentObjective->GetObjectiveGuid() );

	if ( !pxObjective )
	{
		return;
	}

	// What method are we doing to find out actions?
	if ( pxObjective->GetShouldUseSpecificGPV() == 1 )
	{
		// We are using a very specific Game Scene
		AVP_ServerEntity_GamePlayVolume* pxVolume = AVP_ServerEntity_GamePlayVolume::FindEntity(pxObjective->GetGamePlayVolumeGuid());

		if (pxVolume)
		{
			for (Asura_Hashed_List_It<AVP_ServerNode_GS2Node> it(AVP_ServerNode_GS2Node::GetList()); !it.Done(); it.Next())
			{
				AVP_ServerNode_GS2Node* pxGS2Node = it.GetCurrent();


				if ( ( pxGS2Node && pxGS2Node->IsEntityActive() && bConsiderActiveState ) || ( pxGS2Node && !bConsiderActiveState ) )
				{
					if (pxVolume->Contains(pxGS2Node->GetPosition()))
					{
						if (pxGS2Node->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION)
						{
							++(*uNumRequired);
						}
						else if (pxGS2Node->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION)
						{
							++(*uNumOptional);
						}
					}
				}
			}
		}
	}
	else if ( pxObjective->GetShouldUseSpecificGameScenes() == 1 )
	{
		for ( u_int u = 0; u < pxObjective->GetNumRequiredActions(); ++u )
		{
			AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity( pxObjective->GetRequiredActionGuid( u ) );

			if ( ( pxGS2Node && pxGS2Node->IsEntityActive() && bConsiderActiveState ) || ( pxGS2Node && !bConsiderActiveState ) )
			{
				++(*uNumRequired);
			}
		}

		for ( u_int u = 0; u < pxObjective->GetNumOptionalActions(); ++u )
		{
			AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity( pxObjective->GetOptionalActionGuid( u ) );

			if ( ( pxGS2Node && pxGS2Node->IsEntityActive() && bConsiderActiveState ) || ( pxGS2Node && !bConsiderActiveState ) )
			{
				++(*uNumOptional);
			}
		}
	}
	else
	{
		// We are just using the GPV that the objective is inside
		AVP_ServerEntity_GamePlayVolume* pxVolume = AVP_ServerEntity_GamePlayVolume::GetVolumeThatContainsPosition(pxObjective->GetPosition());

		if (pxVolume)
		{
			for (Asura_Hashed_List_It<AVP_ServerNode_GS2Node> it(AVP_ServerNode_GS2Node::GetList()); !it.Done(); it.Next())
			{
				AVP_ServerNode_GS2Node* pxGS2Node = it.GetCurrent();

				if ( ( pxGS2Node && pxGS2Node->IsEntityActive() && bConsiderActiveState ) || ( pxGS2Node && !bConsiderActiveState ) )
				{
					if (pxVolume->Contains(pxGS2Node->GetPosition()))
					{
						if (pxGS2Node->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION)
						{
							++(*uNumRequired);
						}
						else if (pxGS2Node->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION)
						{
							++(*uNumOptional);
						}
					}
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: GetOptionalAndRequiredGuids
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::GetOptionalAndRequiredGuids( Asura_Guid* pxRequired, Asura_Guid* pxOptional )
{
	if ( ( !m_pxCurrentObjective ) || ( m_pxCurrentObjective->GetObjectiveGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return;
	}

	AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( m_pxCurrentObjective->GetObjectiveGuid() );

	if ( !pxObjective )
	{
		return;
	}

	// What method are we using to find out actions?
	if ( pxObjective->GetShouldUseSpecificGameScenes() == 0 )
	{
		// We are using a very specific Game Scene
		AVP_ServerEntity_GamePlayVolume* pxVolume = NULL;

		if (pxObjective->GetShouldUseSpecificGPV() == 1)
		{
			pxVolume = AVP_ServerEntity_GamePlayVolume::FindEntity(pxObjective->GetGamePlayVolumeGuid());
		}
		else
		{
			pxVolume = AVP_ServerEntity_GamePlayVolume::GetVolumeThatContainsPosition(pxObjective->GetPosition());
		}

		if ( pxVolume )
		{
			u_int uNumReqProcessed = 0;
			u_int uNumOptProcessed = 0;

			for (Asura_Hashed_List_It<AVP_ServerNode_GS2Node> it(AVP_ServerNode_GS2Node::GetList()); !it.Done(); it.Next())
			{
				AVP_ServerNode_GS2Node* pxGS2Node = it.GetCurrent();

				if (pxGS2Node && pxGS2Node->IsEntityActive())
				{
					if (pxVolume->Contains(pxGS2Node->GetPosition()))
					{
						if (pxGS2Node->GetStructureType() == AVP_GS_ST_REQUIRED_MARINE_ACTION)
						{
							pxRequired[uNumReqProcessed] = pxGS2Node->GetGuid();
							++uNumReqProcessed;
						}
						else if (pxGS2Node->GetStructureType() == AVP_GS_ST_OPTIONAL_MARINE_ACTION)
						{
							pxOptional[uNumOptProcessed] = pxGS2Node->GetGuid();
							++uNumOptProcessed;
						}
					}
				}
			}
		}
	}
	else if ( pxObjective->GetShouldUseSpecificGameScenes() == 1 )
	{
		u_int uNumReqProcessed = 0;
		u_int uNumOptProcessed = 0;

		for (u_int u = 0; u < pxObjective->GetNumRequiredActions(); ++u)
		{
			AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(pxObjective->GetRequiredActionGuid( u ) );

			if (pxGS2Node && pxGS2Node->IsEntityActive())
			{
				pxRequired[uNumReqProcessed] = pxObjective->GetRequiredActionGuid(u);
				++uNumReqProcessed;
			}
		}

		for (u_int u = 0; u < pxObjective->GetNumOptionalActions(); ++u)
		{
			AVP_ServerNode_GS2Node* pxGS2Node = AVP_ServerNode_GS2Node::FindEntity(pxObjective->GetOptionalActionGuid( u ) );

			if (pxGS2Node && pxGS2Node->IsEntityActive())
			{
				pxOptional[uNumOptProcessed] = pxObjective->GetOptionalActionGuid(u);
				++uNumOptProcessed;
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: GetRequiredGuidToAssign
//----------------------------------------------------------------------
Asura_Guid AVP_ServerEntity_Squad_Marine::GetActionGuidToAssign(Asura_Guid* pxActions, u_int uNumActions, Asura_Guid uIgnoreActionGuid, bool bIsRequiredAction )
{
	Asura_Guid uGuidToAssign = ASURA_GUID_UNREGISTERED;

	for ( u_int u = 0; u < uNumActions; ++u )
	{
		Asura_Guid uGuidToCheck = pxActions[ u ];
		bool bInUse = false;

		if ( uGuidToCheck == ASURA_GUID_UNREGISTERED )
		{
			continue;
		}

		for ( u_int v = 0; v < uNumActions; ++v )
		{
			if ( bIsRequiredAction )
			{
				if ( m_pxAssignedRequiredActions[v] == uGuidToCheck )
				{
					bInUse = true;
					break;
				}
			}
			else
			{
				if ( m_pxAssignedOptionalActions[v] == uGuidToCheck )
				{
					bInUse = true;
					break;
				}
			}
		}

		if ( uIgnoreActionGuid == uGuidToCheck )
		{
			bInUse = true;
		}

		if ( !bInUse )
		{
			uGuidToAssign = uGuidToCheck;
			break;
		}
	}

	return uGuidToAssign;
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: BuildRandomisedOptionalArray
//----------------------------------------------------------------------
bool AVP_ServerEntity_Squad_Marine::BuildRandomisedOptionalArray( u_int uNumOptional, Asura_Guid* pxOptionalActions, Asura_Guid* pxRandomOptionals )
{
	for ( u_int u = 0; u < uNumOptional; ++u )
	{
		pxRandomOptionals[ u ] = ASURA_GUID_UNREGISTERED;
	}

	u_int uRandomOptionalsProcessed = 0;

	// first things first build a random array of objective optional actions
	bool bFailed = false;
	bool bDone = false;

	if ( uNumOptional > 1 )
	{
		u_int uCount = 0;

		while ( !bDone && !bFailed )
		{
			u_int uActionGuid = pxOptionalActions[ ( Asura_Random::GetIntU( 0, uNumOptional - 1) ) ];

			bool bExists = false;

			for (u_int u = 0; u < uNumOptional; ++u)
			{
				if (pxRandomOptionals[u] == uActionGuid)
				{
					bExists = true;
					break;
				}
			}

			if (!bExists)
			{
				pxRandomOptionals[uRandomOptionalsProcessed] = uActionGuid;
				++uRandomOptionalsProcessed;

				if (uRandomOptionalsProcessed >= uNumOptional)
				{
					bDone = true;
				}
			}
			else
			{
				++uCount;

				if (uCount > (uNumOptional * 4))
				{
					return true;
				}
			}
		}

		return false;
	}
	else
	{
		pxRandomOptionals[0] = pxOptionalActions[0];
		return false;
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: AssignAction
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::AssignAction( Asura_Guid uMemberGuid, Asura_Guid uGuidToAssign, bool bIsRequiredAction, u_int uNumActions )
{
	if ( ( !m_pxCurrentObjective ) || ( m_pxCurrentObjective->GetObjectiveGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return;
	}

	AVP_ServerNode_Objective_Marine* pxObjective = AVP_ServerNode_Objective_Marine::FindEntity( m_pxCurrentObjective->GetObjectiveGuid() );

	if ( !pxObjective )
	{
		return;
	}

	AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( uMemberGuid );

	if ( pxHuman )
	{
		SendPerformActionMessage( pxHuman, uGuidToAssign );
		
		if ( bIsRequiredAction )
		{
			Asura_Assert( ( m_uNumAssignedRequiredAction <= uNumActions ), "Attempting to Write Past the End of Assigned Action Array" );
		
			m_pxAssignedRequiredActions[ m_uNumAssignedRequiredAction ] = uGuidToAssign;
			++m_uNumAssignedRequiredAction;
		}
		else
		{
			Asura_Assert( ( m_uNumAssignedOptionalAction <= uNumActions ), "Attempting to Write Past the End of Assigned Action Array" );
			m_pxAssignedOptionalActions[ m_uNumAssignedOptionalAction ] = uGuidToAssign;
			++m_uNumAssignedOptionalAction;
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: RequestAction
//----------------------------------------------------------------------
bool AVP_ServerEntity_Squad_Marine::RequestAction(Asura_Guid uMemberGuid, Asura_Guid uIgnoreActionGuid /*= ASURA_GUID_UNREGISTERED*/)
{
	if ( ( !m_pxCurrentObjective ) || ( m_pxCurrentObjective->GetObjectiveGuid() == ASURA_GUID_UNREGISTERED ) )
	{
		return false;
	}

	u_int uNumRequired = 0, uNumOptional = 0;

	// Need to know how many Optional and Required Guids we have, this can change per request also as some gamescenes will be made inactive.
	GetNumOptionalAndRequiredActionGuids( &uNumRequired, &uNumOptional );

	Asura_Guid*	pxRequiredActions = new Asura_Guid[ uNumRequired ];
	Asura_Guid*	pxOptionalActions = new Asura_Guid[ uNumOptional ];

	for ( u_int u = 0; u < uNumRequired; ++u )
	{
		pxRequiredActions[ u ] = ASURA_GUID_UNREGISTERED;
	}
	
	for ( u_int u = 0; u < uNumOptional; ++u )
	{
		pxOptionalActions[ u ] = ASURA_GUID_UNREGISTERED;
	}

	// Fill the arrays with the guids
	GetOptionalAndRequiredGuids( pxRequiredActions, pxOptionalActions );

	// Get a required action Guid
	Asura_Guid uGuidToAssign = GetActionGuidToAssign( pxRequiredActions, uNumRequired, uIgnoreActionGuid, true );

	// Assign a required guid if we can
	if ( uGuidToAssign != ASURA_GUID_UNREGISTERED )
	{
		AssignAction(uMemberGuid, uGuidToAssign, true, uNumRequired);
	}
	else // If we found no required action to assign then try an optional
	{
		uGuidToAssign = ASURA_GUID_UNREGISTERED;

		// Only try to assign an optional if we have more than zero
		if (uNumOptional > 0)
		{
			Asura_Guid* pxRandomOptionals = new Asura_Guid[uNumOptional];

			// Randomise our optional guids
			bool bFailed = BuildRandomisedOptionalArray( uNumOptional, pxOptionalActions, pxRandomOptionals );

			if (bFailed)
			{
				delete [] pxRandomOptionals;
				delete [] pxRequiredActions;
				delete [] pxOptionalActions;
				return false;
			}

			uGuidToAssign = GetActionGuidToAssign( pxRandomOptionals, uNumOptional, uIgnoreActionGuid, false );

			if (uGuidToAssign != ASURA_GUID_UNREGISTERED)
			{
				AssignAction( uMemberGuid, uGuidToAssign, false, uNumOptional );
			}

			delete [] pxRandomOptionals;
		}
	}

	delete [] pxRequiredActions;
	delete [] pxOptionalActions;

	if (uGuidToAssign == ASURA_GUID_UNREGISTERED)
	{
		return false;
	}
	else
	{
		return true;
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: RekeaseActionGuid
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ReleaseActionGuid(Asura_Guid uGuidToRelease)
{
	bool bRemoved = false;

	for (u_int u = 0; u < m_uNumAssignedRequiredAction; ++u)
	{
		if (u < (m_uNumAssignedRequiredAction - 1))
		{
			if ((m_pxAssignedRequiredActions[u] == uGuidToRelease) || (bRemoved))
			{
				m_pxAssignedRequiredActions[u] =  m_pxAssignedRequiredActions[u + 1];
				bRemoved = true;
			}
		}
		else
		{
			if ((m_pxAssignedRequiredActions[u] == uGuidToRelease) || (bRemoved))
			{
				if (m_pxAssignedRequiredActions[u] == uGuidToRelease)
				{
					bRemoved = true;
				}

				m_pxAssignedRequiredActions[u] = ASURA_GUID_UNREGISTERED;
			}
		}
	}

	if (bRemoved)
	{
		if (m_uNumAssignedRequiredAction > 0)
		{
			--m_uNumAssignedRequiredAction;
		}
	}

	bRemoved = false;

	for (u_int u = 0; u < m_uNumAssignedOptionalAction; ++u)
	{
		if (u < (m_uNumAssignedOptionalAction - 1))
		{
			if ((m_pxAssignedOptionalActions[u] == uGuidToRelease) || (bRemoved))
			{
				m_pxAssignedOptionalActions[u] =  m_pxAssignedOptionalActions[u + 1];
				bRemoved = true;
			}
		}
		else
		{
			if ((m_pxAssignedOptionalActions[u] == uGuidToRelease) || (bRemoved))
			{
				if (m_pxAssignedOptionalActions[u] == uGuidToRelease)
				{
					bRemoved = true;
				}

				m_pxAssignedOptionalActions[u] = ASURA_GUID_UNREGISTERED;
			}
		}
	}

	if (bRemoved)
	{
		if (m_uNumAssignedOptionalAction > 0)
		{
			--m_uNumAssignedOptionalAction;
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: SendPerformActionMessage
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::SendPerformActionMessage(AVP_ServerActor_Human* pxSquadMember, Asura_Guid uActionGuid)
{
	AVP_ServerNode_GS2Node* pxNode = AVP_ServerNode_GS2Node::FindEntity(uActionGuid);

	if (pxNode)
	{
		// pxNodeIsValid!
		Asura_Message* pxMessage = Asura_Network::CreateMessage(AVP_MSGID_PERFORM_AI_OBJECTIVE_ACTION, sizeof(AVP_Message_PerformObjectiveAction));

		if (pxMessage)
		{
			AVP_Message_PerformObjectiveAction* pxMsgData = static_cast<AVP_Message_PerformObjectiveAction*>(pxMessage->GetData());

			pxMessage->SetToGuid(pxSquadMember->GetGuid());
			pxMessage->SetFromGuid(GetGuid());
			pxMsgData->SetActionGuid(pxNode->GetGuid());
			Asura_Network::Send(pxMessage);
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: TargetAquired
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::TargetAquired(Asura_Guid uThreatSpotterGuid, const Axon_Knowledge& xThreat)
{
	AVP_ServerActor_Human* pxSpotterHuman = AVP_ServerActor_Human::FindEntity(uThreatSpotterGuid);

	if (pxSpotterHuman && !pxSpotterHuman->IsDead() && pxSpotterHuman->IsEntityActive())
	{
		for (u_int u = 0; u < GetNumSquadMembers(); ++u)
		{
			Asura_Guid uMemberGuid = GetMemberGuid(u);

			if ((uMemberGuid != ASURA_GUID_UNREGISTERED) && (uMemberGuid != pxSpotterHuman->GetGuid()))
			{
				AVP_ServerActor_Human* pxSquadMember = AVP_ServerActor_Human::FindEntity(uMemberGuid);
				
				if (pxSquadMember && !pxSquadMember->IsDead() && pxSquadMember->IsEntityActive())
				{
					float fDistanceSq = (pxSquadMember->GetPosition() - pxSpotterHuman->GetPosition()).MagnitudeSquared();

					if (fDistanceSq < 225.0f)
					{
						AVP_Brain_Actor_Marine* pxMarineBrain = static_cast<AVP_Brain_Actor_Marine*>(pxSquadMember->GetActorBrain());
				
						if (pxMarineBrain)
						{
							pxMarineBrain->GetKnowledgeSystem()->AddKnowledgeIfNeeded(xThreat);
						}
					}
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: AlertAquired
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::AlertAquired(Asura_Guid uAlertSpotterGuid, const Axon_Knowledge& xAlert)
{
	AVP_ServerActor_Human* pxSpotterHuman = AVP_ServerActor_Human::FindEntity(uAlertSpotterGuid);

	if (pxSpotterHuman && !pxSpotterHuman->IsDead() && pxSpotterHuman->IsEntityActive())
	{
		for (u_int u = 0; u < GetNumSquadMembers(); ++u)
		{
			Asura_Guid uMemberGuid = GetMemberGuid(u);

			if ((uMemberGuid != ASURA_GUID_UNREGISTERED) && (uMemberGuid != pxSpotterHuman->GetGuid()))
			{
				AVP_ServerActor_Human* pxSquadMember = AVP_ServerActor_Human::FindEntity(uMemberGuid);

				if (pxSquadMember && !pxSquadMember->IsDead() && pxSquadMember->IsEntityActive())
				{
					float fDistanceSq = (pxSquadMember->GetPosition() - pxSpotterHuman->GetPosition()).MagnitudeSquared();

					if (fDistanceSq < 225.0f)
					{
						AVP_Brain_Actor_Marine* pxMarineBrain = static_cast<AVP_Brain_Actor_Marine*>(pxSquadMember->GetActorBrain());

						if (pxMarineBrain)
						{
							pxMarineBrain->GetKnowledgeSystem()->AddAlertKnowledgeIfNeeded(xAlert);
						}
					}
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: EffectSquadMorale
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::EffectSquadMorale(u_int eMoraleEffector, Asura_Guid uIgnoreGuid /*= ASURA_GUID_UNREGISTERED*/)
{
	if (!IsPlayersSquad())
	{
		for (u_int u = 0; u < GetNumSquadMembers(); ++u)
		{
			if (GetMemberGuid(u) != ASURA_GUID_UNREGISTERED)
			{
				AVP_ServerActor_Human* pxSquadMember = AVP_ServerActor_Human::FindEntity(GetMemberGuid(u));

				if ((pxSquadMember) && (pxSquadMember->GetMoraleHandler()))
				{
					if (pxSquadMember->GetGuid() != uIgnoreGuid)
					{
						pxSquadMember->GetMoraleHandler()->EffectMorale(eMoraleEffector);
					}
				}
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: GetMarineSquadBrain
//----------------------------------------------------------------------
AVP_Brain_Squad_Marine* AVP_ServerEntity_Squad_Marine::GetMarineSquadBrain() const
{
	return m_pxSquadBrain;
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: InialiseFromBlueprint
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::InitialiseFromBlueprint(const Asura_Blueprint& xBlueprint)
{
	m_pxSquadBrain->InitialiseFromBlueprint(xBlueprint);
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ChooseNewSquadLeader
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ChooseNewSquadLeader( Asura_Guid uOldLeaderGuid )
{
	for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
	{
		AVP_ServerActor_Human* pxMember = AVP_ServerActor_Human::FindEntity( GetMemberGuid( (int)u ) );

		if (pxMember && pxMember->IsEntityActive() && !pxMember->IsDead())
		{
			if ( pxMember->GetGuid() != uOldLeaderGuid )
			{
				SetSquadLeader( pxMember->GetGuid() );
				break;
			}
		}
	}
}

//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ChooseNewSquadLeader
//----------------------------------------------------------------------
bool AVP_ServerEntity_Squad_Marine::AllMembersHaveValidRoute( void )
{
	for ( u_int u = 0; u < GetNumSquadMembers(); ++u )
	{
		AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( GetMemberGuid( u ) );

		if ( pxHuman && !pxHuman->IsDead() && pxHuman->IsEntityActive() && pxHuman->GetActorBrain() )
		{
			const AVP_Navigation::NavData& xNavData = pxHuman->GetActorBrain()->GetNavData();

			if ( !xNavData.m_pusRoute )
			{
				return false;
			}
		}
	}

	return true;
}

#ifdef ASURA_TOOLS
//----------------------------------------------------------------------
// AVP_ServerEntity_Squad_Marine :: ApplyChangesForTemplateInstance
//----------------------------------------------------------------------
void AVP_ServerEntity_Squad_Marine::ApplyChangesForTemplateInstance( Tools_EntityTemplateInstance* pxInstance )
{
	PARENT::ApplyChangesForTemplateInstance( pxInstance );

	m_uCombatZoneGPVGuid = pxInstance->ConvertGuid( m_uCombatZoneGPVGuid );
}
#endif