//---------------------------------------------------------------------------
// File			: AVP_Behaviour_Marine_SquadMember.cpp
// Created		: 
// Created By	: Gareth Thomas
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//---------------------------------------------------------------------------

// INCLUDES ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"
// header
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_SquadMember.h"
// asura
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Rendering/Asura_Font_System.h"
#include "Debugging/Asura_DebugLineRender.h"
#endif
#include "Network/Asura_Message.h"

// AVP
#include "Entity/Controller/AVP_ServerEntity_Squad_Marine.h"
#include "Entity/Locations/Objective/Marine/AVP_ServerEntity_Objective_Marine.h"
#include "Entity/GamePlayVolume/AVP_ServerEntity_GamePlayVolume.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ServerActor_Predator.h"
#include "Entity/PlayerInfo/AVP_ServerEntity_PlayerInfo.h"
#include "Entity/AVP_Messages.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/AVP_InventoryItem_PredatorCloak.h"

// AVP axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Alert.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_HideFromCloakedPredator.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_Investigate.h"
#include "Core/AVP_Navigation.h"
#include "Core/AVP_Waypoint_Manager.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Tactical/AVP_Tactical_System.h"
#include "Knowledge/AVP_Knowledge_System_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_Vision_Actor.h"

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: Constructor
//---------------------------------------------------------------------------
AVP_Behaviour_Marine_SquadMember::AVP_Behaviour_Marine_SquadMember( AVP_Brain_Actor_Marine* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_MARINE_SQUADMEMBER )
, m_eUpdateState( CHOOSE )
, m_pxMarineBrain( pxBrain )
, m_fPosEvalUpdateTimer( Asura_Random::GetFloat( 4.2f, 4.7f ) )
, m_bThreatIsCloakedPred( false )
, m_uCloakedPredGuid( ASURA_GUID_UNREGISTERED )
, m_xCloakedPredLastKnownPosition( Asura_Maths::ZeroVector3 )
, m_bHaveArrivedAtObjective( false )
, m_bNewLookSet( false )
, m_fLookTimer( 0.0f )
, m_fLookTimeout( 0.0f )
, m_bDirection( false )
, m_uLastRouteSegment( 0 )
, m_fRouteupdateTimer( 0.0f )
, m_bPlayerWasSprintingLastFrame( false )
, m_bRouteIsToLeader( false )
, m_usLeadersRouteIndex( 0 )
, m_fOurRouteDistance( 0.0f )
, m_fLeadersRouteDistance( 0.0f )
, m_bLeaderIsFar( false )
, m_fDistToDestinationSq( 0.0f )
, m_fDistToLeaderSq( 0.0f )
, m_fRouteDiff( 0.0f )
, m_xLeaderDestination( Asura_Maths::ZeroVector3 )
, m_bHasObjective( false )
, m_bMovingForward( false )
, m_fLeadersLastRouteDist( 0.0f )
, m_fTemp( 0.0f )
, m_fOurDist( 0.0f )
{
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadLeader :: Destructor
//---------------------------------------------------------------------------
AVP_Behaviour_Marine_SquadMember::~AVP_Behaviour_Marine_SquadMember()
{

}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: Activate
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::Activate()
{
	const bool bParentOk = PARENT::Activate();
	// Put Code Below This Comment

	// Put Code Above This Comment
	return bParentOk;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: Deactivate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::Deactivate()
{
	if ( GetMarineBrain()->IsActive() )
	{
		GetTacticalSystem()->SetAimLerpModifier(1.0f);
		GetTacticalSystem()->SetWeightAdjustmentOverride( false );
		GetTacticalSystem()->SetSpeedAdjustmentOverride( false );
	}

	// Put Code Above This Comment
	DestroyAllChildren( false );
	PARENT::Deactivate();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: PerFrameUpdate
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::GetAlertStatus( void )
{
	const Axon_Knowledge& xKnowledge = GetKnowledgeSystem()->GetBestAlertKnowledge();

	if ( xKnowledge.GetGuid() != ASURA_GUID_UNREGISTERED )
	{
		if ( xKnowledge.m_uSourceClassification == GetOurActor()->GetClassification() )
		{
			if ( (xKnowledge.m_uTypeInformation != AXON_SOUND_TYPE_GUNFIRE) && 
				(xKnowledge.m_uTypeInformation != AXON_SOUND_TYPE_RICOCHET) &&
				(xKnowledge.m_uTypeInformation != AXON_SOUND_TYPE_EXPLOSION) )
			{
				return true;
			}
			else
			{
				return false;
			}
		}

		return true;
	}
	else
	{
		return false;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: PerFrameUpdate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::PerFrameUpdate( const float fTimeslice )
{
	if ( !AreWeStillInASquad() || AreWeTheSquadLeader() )
	{
		SetFinished();
		return;
	}

	bool							bHaveThreat		= DoesHaveThreat();
	bool							bHaveAlert		= DoesHaveAlert();
	AVP_ServerActor_Human*			pxSquadLeader	= GetSquadLeader();
	AVP_ServerEntity_Squad_Marine*	pxSquad			= GetSquad();

	Asura_Assert( pxSquadLeader, "AVP_Behaviour_Marine_SquadMember :: PerFrameUpdate - Squad Leader Is Invalid This Is a Code Issue Report To Mantis And Assign To Gaz Please." );
	Asura_Assert( pxSquad, "AVP_Behaviour_Marine_SquadMember :: PerFrameUpdate - Squad  Is Invalid This Is a Code Issue Report To Mantis And Assign To Gaz Pleae." );

	if ( !pxSquad || !pxSquadLeader )
	{
		return;
	}

	if ( pxSquad->IsPlayersSquad() && pxSquadLeader->IsDead() )
	{
		return;
	}

	CheckForObjective( bHaveThreat, bHaveAlert );

	if ( bHaveThreat && GetUpdateState() != ATTACK )
	{
		SwitchToState( ATTACK );
	}
	else if ( bHaveAlert && GetUpdateState() != ATTACK && GetUpdateState() != ALERT)
	{
		SwitchToState( ALERT );
	}

	UpdateMovementData();

	switch ( GetUpdateState() )
	{
		//---------------------------------------------------------------------------
		case CHOOSE:
		{

			if ( GetKnowledgeSystem()->GetAlertLevel() == AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS )
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( false );
			}
			else
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( true );
			}

			if ( m_bHasObjective && pxSquad->IsPlayersSquad() )
			{
				if ( m_fRouteDiff > -2.0f )
				{
					GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( false );
					SwitchToState( MOVE );
				}
				else
				{
					SwitchToState( WAIT );
				}
			}
			else
			{
				SwitchToState( WAIT );
			}

			GetTacticalSystem()->SetSpeedAdjustmentOverride( false );

			AVP_ServerActor_Human*			pxLeader = pxSquad->GetLeaderMarine();
			u_int							uMoveSpeed = AVP_Navigation::MM_MEDIUM;

			if ( pxLeader->IsMovingFast() || m_fRouteDiff > 15.0f )
			{
				uMoveSpeed = AVP_Navigation::MM_FAST;
			}

			GetTacticalSystem()->SetMovementSpeed( uMoveSpeed );

		}break;

		//---------------------------------------------------------------------------
		case WAIT:
		{
			if ( m_bHasObjective )
			{
				if ( m_fLeadersLastRouteDist != m_fLeadersRouteDistance)
				{
					if ( m_fRouteDiff > 0.0f )
					{
						SwitchToState( CHOOSE );
					}
				}

				if ( m_fRouteDiff < -15.0f && m_bMovingForward )
				{
					SwitchToState( CHOOSE );
				}
			}
			else
			{
				m_fRouteupdateTimer += fTimeslice;

				if ( m_fRouteupdateTimer > 2.0f )
				{
					SwitchToState( CHOOSE );
				}
			}

			GetTacticalSystem()->SetSpeedAdjustmentOverride( true );

			m_bMovingForward = false;

			AVP_ServerActor_Human*			pxLeader = pxSquad->GetLeaderMarine();
			u_int							uMoveSpeed = AVP_Navigation::MM_MEDIUM;

			if ( pxLeader->IsMovingFast() || m_fRouteDiff > 15.0f )
			{
				uMoveSpeed = AVP_Navigation::MM_FAST;
			}

			GetTacticalSystem()->SetMovementSpeed( uMoveSpeed );


			if ( GetMarineBrain()->GetLookAtGuid() == ASURA_GUID_UNREGISTERED )
			{
				GetMarineBrain()->LookForward();
				GetMarineBrain()->AimForward();
			}

		}break;

		//---------------------------------------------------------------------------
		case MOVE:
		{
			if ( m_bHasObjective )
			{
				if ( m_fRouteDiff < -2.0f )
				{
					SwitchToState( CHOOSE );
				}
			}
			else
			{
				if ( m_fRouteDiff < 0.0f )
				{
					SwitchToState( CHOOSE );
				}
			}

			GetTacticalSystem()->SetSpeedAdjustmentOverride( false );

			AVP_ServerActor_Human*			pxLeader = pxSquad->GetLeaderMarine();
			u_int							uMoveSpeed = AVP_Navigation::MM_MEDIUM;

			if ( pxLeader->IsMovingFast() || m_fRouteDiff > 15.0f )
			{
				uMoveSpeed = AVP_Navigation::MM_FAST;
			}

			GetTacticalSystem()->SetMovementSpeed( uMoveSpeed );

		}break;

		//---------------------------------------------------------------------------
		case POST_ALERT:
		{
			//LookAround(fTimeslice);

			if ( GetKnowledgeSystem()->GetAlertLevel() == AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS )
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( false );
				SwitchToState( CHOOSE );
			}
			else
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( true );
			}

		}break;
		//---------------------------------------------------------------------------
		case ALERT:
		{
			Axon_Behaviour* pxBehaviour = GetChildWithType( this, AVP_BEHAVIOUR_TYPE_MARINE_ALERT );

			if ( pxBehaviour && pxBehaviour->IsFinished() )
			{
				AVP_Behaviour_Marine_Alert* pxAlertBehaviour = ( AVP_Behaviour_Marine_Alert* )GetChildWithType( this, AVP_BEHAVIOUR_TYPE_MARINE_ALERT );

				if ( pxAlertBehaviour )
				{
					bool bScan = false;

					if ( pxAlertBehaviour->GetUpdateState() == AVP_Behaviour_Marine_Alert::SCAN_AREA )
					{
						bScan = true;
					}

					DestroyChildWithType(AVP_BEHAVIOUR_TYPE_MARINE_ALERT);

					if ( bScan )
					{
						SwitchToState( BE_ALERT );
					}
					else
					{
						SwitchToState( CHOOSE );
					}
				}
			}

		}break;
		//---------------------------------------------------------------------------
		case ATTACK:
		{
			if ( !bHaveThreat && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation != AVP_Sense_Vision::TYPE_INFO_CLOAKED_CANT_SEE )
			{
				if ( ( m_bThreatIsCloakedPred ) && ( m_uCloakedPredGuid != ASURA_GUID_UNREGISTERED ) )
				{
					AVP_ServerActor_Predator* pxPredator = AVP_ServerActor_Predator::FindEntity( m_uCloakedPredGuid );

					if ( pxPredator && !pxPredator->IsDead() && pxPredator->IsEntityActive() )
					{
						SwitchToState( HIDE_FROM_CLOAKED_PRED );
					}
					else
					{
						SwitchToState( CHOOSE );
					}
				}
				else
				{
					// we don't have a threat any more kill the attack behaviour
					SwitchToState( CHOOSE );
				}
			}
			else
			{
				if ( GetKnowledgeSystem()->GetBestThreatKnowledge().m_uSourceClassification == AVP_ENTITYCLASS_PREDATOR && GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CLOAKED_CANT_SEE)
				{
					AVP_ServerActor_Predator* pxPredator = AVP_ServerActor_Predator::FindEntity( GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() );

					if ( pxPredator )
					{
						AVP_InventoryItem_Cloak* pxCloak = static_cast< AVP_InventoryItem_Cloak* >( pxPredator->GetInventorySystem()->GetItem( uAVP_INVENTORY_ITEMHASH_CLOAK ) );

						if ( pxCloak && pxCloak->IsUsing( false ) )
						{
							Asura_Vector_3 xPredChest	= Asura_Maths::ZeroVector3;
							Asura_Vector_3 xOurEyes		= Asura_Maths::ZeroVector3;

							GetOurActor()->GetHeadPosition( xOurEyes );
							pxPredator->GetChestPosition( xPredChest );

							Asura_Vector_3 xDirection = xPredChest - xOurEyes;
							float fDistance = xDirection.Normalise();

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

							if (pxOutput->m_fDistanceToIntersection >= fDistance)
							{
								m_bThreatIsCloakedPred = true;
								m_uCloakedPredGuid = GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid();
								m_xCloakedPredLastKnownPosition = xPredChest;
								
								if ((fDistance * fDistance) >= GetKnowledgeSystem()->GetCloakedVisibleRangeSq())
								{
									SwitchToState( HIDE_FROM_CLOAKED_PRED );
								}
							}
							else
							{
								m_uCloakedPredGuid = ASURA_GUID_UNREGISTERED;
								m_bThreatIsCloakedPred = false;
								m_xCloakedPredLastKnownPosition = Asura_Maths::ZeroVector3;
							}
						}
					}
				}
				else
				{
					m_uCloakedPredGuid = ASURA_GUID_UNREGISTERED;
					m_bThreatIsCloakedPred = false;
					m_xCloakedPredLastKnownPosition = Asura_Maths::ZeroVector3;
				}
			}
		}break;
		//---------------------------------------------------------------------------
		//---------------------------------------------------------------------------
		case HIDE_FROM_CLOAKED_PRED:
		{
			if ( bHaveThreat && ( GetKnowledgeSystem()->GetBestThreatKnowledge().m_uSourceClassification != AVP_ENTITYCLASS_PREDATOR || GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_LASER ) )
			{
				SwitchToState( ATTACK );
			}
			else
			{
				Axon_Behaviour* pxHideBehaviour = GetChildWithType( this, AVP_BEHAVIOUR_TYPE_MARINE_HIDEFROMCLOAKEDPREDATOR );

				if ( pxHideBehaviour && pxHideBehaviour->IsFinished() )
				{
					SwitchToState( CHOOSE );
				}
			}

		}break;
		//---------------------------------------------------------------------------
		//---------------------------------------------------------------------------
		case BE_ALERT:
		{
			//LookAround( fTimeslice );

			if ( GetKnowledgeSystem()->GetAlertLevel() == AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS )
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( false );
				SwitchToState( CHOOSE );
			}
			else
			{
				GetMarineBrain()->GetTacticalSystem()->SetIsAllowedToReact( true );
			}
		}break;
		//---------------------------------------------------------------------------
		default:
		{
			Asura_Assert( false, "AVP_Behaviour_Marine_SquadMember :: PerFrameUpdate - Update State Is Invalid Please Report To Mantis And Assign To Gaz" );
		}break;
	}

//
	
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadLeader :: SwitchToState
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::SwitchToState( SMUpdateState eState )
{
	switch ( GetUpdateState() )
	{
		case MOVE:
		{
			m_fRouteupdateTimer = 0.0f;

		}break;

		case WAIT:
		{
			m_fRouteupdateTimer = 0.0f;

		}break;

		case CHOOSE:
		{
			m_fRouteupdateTimer = 0.0f;

		}break;

		case ATTACK:
		{
			if ( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SELECTOR ) )
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SELECTOR );
		}break;

		case ALERT:
		{
			if ( GetChildWithType( this, AVP_BEHAVIOUR_TYPE_MARINE_ALERT ) )
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_ALERT );
		}break;

		case POST_ALERT:
		{
			GetMarineBrain()->GetTacticalSystem()->SetAimLerpModifier(1.0f);

		}break;

		case HIDE_FROM_CLOAKED_PRED:
		{
			if ( GetChildWithType(this, AVP_BEHAVIOUR_TYPE_MARINE_HIDEFROMCLOAKEDPREDATOR ) )
				DestroyChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_HIDEFROMCLOAKEDPREDATOR );

		}break;

		case BE_ALERT:
		{
			GetMarineBrain()->GetTacticalSystem()->SetAimLerpModifier(1.0f);

		}break;

		default:
		{
		}break;
	}

	SetUpdateState( eState );

	switch ( eState )
	{
		//---------------------------------------------------------------------------
		case MOVE:
		{
			AVP_Tactical_System* pxTactical = GetTacticalSystem();

			pxTactical->SetWeightAdjustmentOverride( true );
			pxTactical->CancelStopMovingWithDelay();
			pxTactical->CancelStopMoving();
			pxTactical->SetDestination( m_xLeaderDestination );
			pxTactical->LetRouteSetLookAt( true );
			pxTactical->SetAtDestinationRange( ONE_METER );
			pxTactical->OverrideStartMovementDelay();
			pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );

		}break;
		//---------------------------------------------------------------------------
		case WAIT:
		{
// 			if ( GetMarineBrain()->GetMarineSquad()->GetSquadCombatState() != AVP_ServerEntity_Squad_Marine::SQUAD_COMBAT_STATE_STANDGROUND )
// 			{
// 				FormationPositionEvaluation(0.0f);
// 			}

			if ( GetMarineBrain()->GetLookAtGuid() != ASURA_GUID_UNREGISTERED )
			{
				GetMarineBrain()->LookAt_LookAtEntity();
			}
			else
			{
				LookInAGoodDirection();
			}

		}break;
		//---------------------------------------------------------------------------
		case CHOOSE:
		{
			m_fPosEvalUpdateTimer = Asura_Random::GetFloat( 3.8f, 4.5f );
			m_fRouteupdateTimer = 0.0f;
		}break;
		//---------------------------------------------------------------------------
		case ATTACK:
		{
			// need to create an attack behaviour here
			CreateChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_SELECTOR );

		}break;
		//---------------------------------------------------------------------------
		case ALERT:
		{
			// need to create an alert behaviour here
			CreateChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_ALERT );
		}break;
		//---------------------------------------------------------------------------
		case POST_ALERT:
		{
			m_bNewLookSet = false;
			m_fLookTimer = 0.0f;

		}break;
		//---------------------------------------------------------------------------
		case HIDE_FROM_CLOAKED_PRED:
		{
			AVP_Behaviour_Marine_HideFromCloakedPredator* pxBehaviour = (AVP_Behaviour_Marine_HideFromCloakedPredator*)CreateChildWithType( AVP_BEHAVIOUR_TYPE_MARINE_HIDEFROMCLOAKEDPREDATOR );

			if ( pxBehaviour )
			{
				pxBehaviour->SetLastSeenPosition( m_xCloakedPredLastKnownPosition );
			}

		}break;
		//---------------------------------------------------------------------------
		case BE_ALERT:
		{
			m_bNewLookSet = false;
			m_fLookTimer = 0.0f;
		}break;
		//---------------------------------------------------------------------------
		default:
		{
			Asura_Assert( false, "AVP_Behaviour_Marine_SquadMember :: SwitchToState - Switch To State Is Invalid Please Report To Mantis And Assign To Gaz" );
		}break;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: UpdateMovementData
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::UpdateMovementData( void )
{
	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad(); // verified by brain

	if ( pxSquad->GetCurrentObjective() )
	{
		m_bHasObjective = true;
	}
	else
	{
		m_bHasObjective = false;
	}

	if ( pxSquad->IsPlayersSquad() )//&& pxSquad->GetSquadCombatState() == AVP_ServerEntity_Squad_Marine::SQUAD_COMBAT_STATE_TRAVELLING )
	{
		AVP_ServerActor_Human*			pxLeader = pxSquad->GetLeaderMarine();
		AVP_ServerEntity_PlayerInfo*	pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( pxLeader->GetPlayerInfoGuid() );

		if ( pxLeader && pxPlayerInfo )
		{
			const AVP_Navigation::NavData&	xLeadersNavData		= pxPlayerInfo->GetAINavData();
			const AVP_Navigation::NavData&	xOurNavData			= GetMarineBrain()->GetNavData();
			
			Asura_Vector_3 xPositionOnRoute( Asura_Maths::ZeroAVector3 );
			
			m_usLeadersRouteIndex = 0;

			if ( xLeadersNavData.m_pusRoute )
			{
				AVP_Navigation::FindNearestPointOnOtherRoute(xLeadersNavData, GetOurActor()->GetPosition(), xPositionOnRoute, m_usLeadersRouteIndex );

				if ( xOurNavData.m_xDestinationPosition == xLeadersNavData.m_xDestinationPosition )
				{
					Asura_Vector_3 xPositionOnOurRoute( Asura_Maths::ZeroVector3 );
					u_short usRouteIndex = 0;
					AVP_Navigation::FindNearestPointOnRoute( xOurNavData, GetOurActor()->GetPosition(), 0.0f,  xPositionOnOurRoute, usRouteIndex );

					float fDistBetweenNearestPointsSq = ( xPositionOnRoute - xPositionOnOurRoute ).MagnitudeSquared();

					if ( fDistBetweenNearestPointsSq > 10.0f )
					{
						AVP_Navigation::FindNearestPointOnOtherRoute(xLeadersNavData, xPositionOnOurRoute, xPositionOnRoute, m_usLeadersRouteIndex );
						m_bMovingForward = false;
					}
					else
					{
						m_bMovingForward = true;
					}
				}
				
				m_fLeadersLastRouteDist = m_fLeadersRouteDistance;

				m_fOurRouteDistance				= AVP_Navigation::CalculateRouteDistance( xLeadersNavData, xPositionOnRoute, m_usLeadersRouteIndex );
				m_fLeadersRouteDistance			= pxPlayerInfo->GetCurrentAIRouteDistance();
				m_fDistToLeaderSq				= ( GetOurActor()->GetPosition() - pxLeader->GetPosition() ).MagnitudeSquared();
				m_fDistToDestinationSq			= ( GetOurActor()->GetPosition() - xLeadersNavData.m_xDestinationPosition ).MagnitudeSquared();
				m_fRouteDiff					= m_fOurRouteDistance - m_fLeadersRouteDistance;

				if ( m_fDistToLeaderSq > 100.0f )
				{
					m_bLeaderIsFar = true;
				}
				else
				{
					m_bLeaderIsFar = false;
				}

				m_xLeaderDestination = xLeadersNavData.m_xDestinationPosition;			

				return;
			}
		}
	}

	m_xLeaderDestination = Asura_Maths::ZeroVector3;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: MoveToLeader
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::MoveToLeader( const float fTimeslice )
{
// 	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad(); // verified by brain
// 
// 	if ( pxSquad->IsPlayersSquad() && pxSquad->GetSquadCombatState() == AVP_ServerEntity_Squad_Marine::SQUAD_COMBAT_STATE_TRAVELLING )
// 	{
// 		AVP_ServerActor_Human*			pxLeader = pxSquad->GetLeaderMarine();
// 		AVP_ServerEntity_PlayerInfo*	pxPlayerInfo = AVP_ServerEntity_PlayerInfo::FindEntity( pxLeader->GetPlayerInfoGuid() );
// 
// 		if ( pxLeader && pxPlayerInfo )
// 		{
// 			AVP_Tactical_System*			pxTactical			= GetTacticalSystem();
// 			const AVP_Navigation::NavData&	xLeadersNavData		= pxPlayerInfo->GetAINavData();
// 		
// 			Asura_Vector_3 xPositionOnRoute( Asura_Maths::ZeroAVector3 );
// 			
// 			m_usLeadersRouteIndex = 0;
// 
// 			AVP_Navigation::FindNearestPointOnOtherRoute(xLeadersNavData, GetOurActor()->GetPosition(), xPositionOnRoute, m_usLeadersRouteIndex );
// 
// #ifndef ASURA_NO_DEBUG_OUTPUT
// 			Asura_DebugLineRender::AddSphere( xPositionOnRoute, 0.5f, 0xffff0000, 4, 2 );
// #endif
// 
// 			float	fLeadersRouteDist		= pxPlayerInfo->GetCurrentAIRouteDistance();
// 			float	fOurRouteDist			= AVP_Navigation::CalculateRouteDistance( xLeadersNavData, xPositionOnRoute, m_usLeadersRouteIndex );
// 			float	fDistToLeaderSq			= ( GetOurActor()->GetPosition() - pxLeader->GetPosition() ).MagnitudeSquared();
// 			bool	bLeaderIsFar			= false;
// 			float	fDistToDestinationSq	= ( GetOurActor()->GetPosition() - xLeadersNavData.m_xDestinationPosition ).MagnitudeSquared();
// 
// 			if ( fDistToLeaderSq > 100.0f )
// 			{
// 				bLeaderIsFar = true;
// 			}
// 
// 			m_fOurDist = fOurRouteDist;
// 
// 			float fStopDistance = fLeadersRouteDist - 7.0f;
// 			float fStartDistance = fLeadersRouteDist - 5.5f;
// 			float fRouteDiff = fOurRouteDist - ( fLeadersRouteDist - 3.0f );
// 
// 			m_fTemp = fRouteDiff;
// 
// 			// If the leader is closer than us
// 			if ( ( ( fStopDistance > fOurRouteDist ) && bLeaderIsFar ) || fDistToDestinationSq < 64.0f )
// 			{
// 				pxTactical->StopMovingWithDelay();
// 				return false;
// 			}
// 			else if ( 
// 					( fStartDistance > fOurRouteDist && pxLeader->GetVelocity().MagnitudeSquared() > 0.0f ) || 
// 					( m_usLeadersRouteIndex == 0 && fOurRouteDist > fLeadersRouteDist ) || 
// 					( fRouteDiff > 10.0f && fOurRouteDist > fLeadersRouteDist ) 
// 					)
// 			{
// 				u_int uSpeed = AVP_Navigation::MM_MEDIUM;
// 
// 				if ( ( fRouteDiff > 20.0f && bLeaderIsFar && fOurRouteDist > fLeadersRouteDist ) || pxLeader->IsMovingFast() )
// 				{
// 					uSpeed = AVP_Navigation::MM_FAST;
// 				}
// 
// 				m_bMovingForward = true;
// 				
// 				if ( !GetOurActor()->IsMoving() )
// 				{
// 					pxTactical->SetWeightAdjustmentOverride( true );
// 					pxTactical->CancelStopMovingWithDelay();
// 					pxTactical->SetDestination( xLeadersNavData.m_xDestinationPosition );
// 					pxTactical->LetRouteSetLookAt( true );
// 					pxTactical->SetAtDestinationRange( ONE_METER );
// 					pxTactical->OverrideStartMovementDelay();
// 				}
// 
// 				pxTactical->SetMovementSpeed( uSpeed );
// 			}
// 			else
// 			{
// 				pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );
// 			}
// 		}
// 	}

	return true;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: GetAILeadersMoveSpeed
//---------------------------------------------------------------------------
u_int AVP_Behaviour_Marine_SquadMember::GetAILeadersMoveSpeed( void )
{
	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();
	
	if ( pxSquad )
	{
		AVP_ServerActor_Human*	pxSquadLeader	= pxSquad->GetLeaderMarine();

		if ( pxSquadLeader )
		{
			AVP_Brain_Actor_Marine* pxLeadersBrain = (AVP_Brain_Actor_Marine*)pxSquadLeader->GetActorBrain();

			if ( pxLeadersBrain )
			{
				return pxLeadersBrain->GetTacticalSystem()->GetMovementSpeed();
			}
		}
	}

	return AVP_Navigation::MM_MEDIUM;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: CheckForObjective
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::CheckForObjective( bool bHaveThreat, bool bHaveAlert )
{	
	if ( GetOurActor()->GetCurrentObjective() )
	{
		bool bShouldExitOnObjectiveState = false;

		// If we are NOT a players squad we should be moving towards objectives and playing actions.
		if ( GetOurActor()->GetCurrentObjectiveState() != AVP_ServerNode_Objective_Marine::COMPLETE )
		{
			bShouldExitOnObjectiveState = true;
		}

		bool bExitNoThreat = false;

		// We are not engaging threats we want to keep moving towards the objective
		if ( GetOurActor()->GetCurrentObjectiveThreatAction() == AVP_ServerNode_Objective_Marine::NO_ACTION )
		{
			bExitNoThreat = true;
		}
		else
		{
			// we do not have a threat or an alert so move to objective
			if	( GetMarineBrain()->GetKnowledgeSystem()->GetAlertLevel() == AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS )
			{
				if ( !bHaveAlert && !bHaveThreat )
				{
					bExitNoThreat = true;
				}
			}
		}

		if ( bShouldExitOnObjectiveState && bExitNoThreat )
		{
			SetFinished();
		}

		return;
	}

	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();

	if ( !pxSquad || !pxSquad->GetCurrentObjective() ) { return; }

	bool bShouldExitOnObjectiveState = false;

	// If we are a players squad we do not move to objectives in the normal way however we still want to perfrom actions.
	if ( pxSquad->IsPlayersSquad() && 
		(pxSquad->GetCurrentObjectiveState() == AVP_ServerNode_Objective_Marine::ARRIVED_AT_OBJECTIVE ||
		pxSquad->GetCurrentObjectiveState() == AVP_ServerNode_Objective_Marine::WAITING_FOR_COMPLETION) )
	{
		bShouldExitOnObjectiveState = true;
	}

	// If we are NOT a players squad we should be moving towards objectives and playing actions.
	if ( !pxSquad->IsPlayersSquad() &&
		pxSquad->GetCurrentObjectiveState() != AVP_ServerNode_Objective_Marine::COMPLETE )
	{
		bShouldExitOnObjectiveState = true;
	}

	bool bExitNoThreat = false;

	// We are not engaging threats we want to keep moving towards the objective
	if ( pxSquad->GetCurrentObjectiveThreatAction() == AVP_ServerNode_Objective_Marine::NO_ACTION )
	{
		bExitNoThreat = true;
	}
	else
	{
		// we do not have a threat or an alert so move to objective
		if	( GetMarineBrain()->GetKnowledgeSystem()->GetAlertLevel() == AVP_Knowledge_System_Actor::PASSIVE_ALERTNESS || pxSquad->ShouldIgnoreAlertState() )
		{
			if ( !bHaveAlert && !bHaveThreat )
			{
				bExitNoThreat = true;
			}
		}
	}

	if ( bShouldExitOnObjectiveState && bExitNoThreat && AVP_Behaviour_Marine_Investigate::GetInvestigatorGuid() != GetMarineBrain()->GetOwnerGuid() )
	{
		SetFinished();
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: LookAround
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::LookAround(const float fTimeslice)
{
	GetMarineBrain()->GetTacticalSystem()->SetAimLerpModifier(0.5f);

	AVP_ServerActor_Human* pxOurActor = GetOurActor();

	if ( !m_bNewLookSet )
	{
		// we don't know where the sound came from so scan the area.
		const Asura_Matrix_3x3&		xOurOri		= pxOurActor->GetOrientation();
		Asura_Vector_3				xFwd		= Asura_Vector_3( xOurOri.e13, xOurOri.e23, xOurOri.e33 );
		Asura_Vector_3				xUp			= Asura_Vector_3( xOurOri.e12, xOurOri.e22, xOurOri.e32 );
		Asura_Vector_3				xDirection	= Asura_Maths::ZeroVector3;
		Asura_Vector_3				xLookAt		= Asura_Maths::ZeroVector3;
		Asura_Vector_3				xChestPos	= Asura_Maths::ZeroVector3;
		Asura_Angle					fDeg45		= Asura_Maths::Deg90 / 2.0f;
		Asura_Angle					fAngle		= Asura_Random::GetFloat( Asura_Maths::Deg90, Asura_Maths::Deg90 + fDeg45 );
		Asura_Quat					xQuat;

		if (Asura_Random::GetIntU(0, 1))
			fAngle = -fAngle;

		pxOurActor->GetChestPosition( xChestPos );
		xQuat.FromMatrix( xOurOri );
		xQuat.FromRotation( fAngle, xUp );
		xDirection = xQuat.RotateVector( xFwd);
		xDirection.Normalise();
		xLookAt = xChestPos + xDirection;
		GetMarineBrain()->AimAtPosition( xLookAt );

		m_bNewLookSet = true;
		m_fLookTimer = 0.0f;
		m_fLookTimeout = Asura_Random::GetFloat( 1.9f, 2.5f );
	}
	else
	{
		m_fLookTimer += fTimeslice;

		if ( m_fLookTimer > m_fLookTimeout )
		{
			m_bNewLookSet = false;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: LookScan
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::LookScan(const float fTimeslice)
{
	GetMarineBrain()->GetTacticalSystem()->SetAimLerpModifier(0.5f);

	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	AVP_Navigation::NavData& xNavData = GetMarineBrain()->GetNavData();

	if (xNavData.m_usRouteSegmentIndex != m_uLastRouteSegment && xNavData.m_usRouteSegmentIndex != 0)
	{
		if ( ( xNavData.m_usRouteSegmentIndex + 1 ) < xNavData.m_usRouteLength )
		{
			Asura_AI_NavVertex* pxNextWp = Asura_AI_Navigation_System::GetWaypoint( xNavData.m_pusRoute[xNavData.m_usRouteSegmentIndex + 1] );
			Asura_AI_NavVertex* pxThisWp = Asura_AI_Navigation_System::GetWaypoint( xNavData.m_pusRoute[xNavData.m_usRouteSegmentIndex] );
			Asura_AI_NavVertex* pxLastWp = Asura_AI_Navigation_System::GetWaypoint( xNavData.m_pusRoute[xNavData.m_usRouteSegmentIndex - 1] );

			if ( pxNextWp && pxThisWp && pxNextWp )
			{
				Asura_Vector_3 xDirection1( pxThisWp->m_xPosition - pxLastWp->m_xPosition );
				Asura_Vector_3 xDirection2( pxLastWp->m_xPosition - pxThisWp->m_xPosition );

				float fDot = xDirection1 * xDirection2;

				if (fDot < 0.995)
				{
					m_bNewLookSet = false;

					if (m_bDirection)
						m_bDirection = false;
					else
						m_bDirection = true;
				}
			}
		}
	}

	m_uLastRouteSegment = xNavData.m_usRouteSegmentIndex;

	if ( !m_bNewLookSet )
	{
		// we don't know where the sound came from so scan the area.
		const Asura_Matrix_3x3&		xOurOri			= pxOurActor->GetOrientation();
		Asura_Vector_3				xFwd			= GetMarineBrain()->GetMovementDirection();;
		Asura_Vector_3				xUp				= Asura_Vector_3( xOurOri.e12, xOurOri.e22, xOurOri.e32 );
		Asura_Vector_3				xDirection		= Asura_Maths::ZeroVector3;
		Asura_Vector_3				xLookAt			= Asura_Maths::ZeroVector3;
		Asura_Vector_3				xChestPos		= Asura_Maths::ZeroVector3;
		Asura_Angle					fDeg45			= Asura_Maths::Deg90 / 2.0f;
		Asura_Quat					xQuat;

		if ( m_bDirection == true )
		{
			fDeg45 = -fDeg45;
			m_bDirection = false;
		}
		else
		{
			m_bDirection = true;
		}

		xQuat.FromRotation( fDeg45, xUp );
		xDirection = xQuat.RotateVector( xFwd);
		xDirection.Normalise();
		GetMarineBrain()->SetAimDirection( xDirection );
		GetMarineBrain()->SetLookAtPosition( pxOurActor->GetPosition() + xDirection * 10.0f );

		m_bNewLookSet = true;
		m_fLookTimer = 0.0f;
		m_fLookTimeout = Asura_Random::GetFloat( 1.0f, 2.0f );
	}
	else
	{
		m_fLookTimer += fTimeslice;

		if ( m_fLookTimer > m_fLookTimeout )
		{
			m_bNewLookSet = false;
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: LookInAGoodDirection
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::LookInAGoodDirection()
{
	AVP_Navigation::NavData& xNavData = GetMarineBrain()->GetNavData();

	Asura_Vector_3 xLookDirection(0.0f, 0.0f, 0.0f);

	AVP_Waypoint_Manager::GetMaxLOFDirection(xNavData.m_usCurrentWPID, xLookDirection);

	if (xLookDirection != Asura_Maths::ZeroVector3)
	{
		GetMarineBrain()->SetAimDirection(xLookDirection);
		GetMarineBrain()->SetLookAtPosition( GetMarineBrain()->GetActor()->GetPosition() + xLookDirection * 10.0f );
	}
	else
	{
		GetMarineBrain()->AimForward();
	}
}

//DEBUGVAR float dbg_fLongTimeOut = 3.0f;

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: ShouldUpdatePositionEvaluation
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::ShouldUpdatePositionEvaluation( void )
{
	if (m_bMovingForward)
	{
		m_bMovingForward = false;
		return true;
	}
	else
	{
// 		if ( m_fPosEvalUpdateTimer > dbg_fLongTimeOut )
// 		{
// 			return true;
// 		}

		return false;
	}
// 	const AVP_Navigation::NavData& xNavData = GetMarineBrain()->GetNavData();
// 	AVP_ServerActor_Human*	pxSquadLeader	= GetSquadLeader();
// 	AVP_ServerActor_Human*	pxOurActor		= GetOurActor();
// 
// 	if ( m_bRouteIsToLeader && m_fPosEvalUpdateTimer > dbg_fLongTimeOut )
// 	{
// 		if (xNavData.m_usRouteSegmentIndex < xNavData.m_usRouteLength - 1)
// 		{
// 			Asura_AI_NavVertex*		pxTestWP		= Asura_AI_Navigation_System::GetWaypoint( xNavData.m_pusRoute[xNavData.m_usRouteSegmentIndex + 1] );
// 			AVP_ServerActor_Human*	pxOurActor		= GetOurActor();
// 
// 			if ( pxTestWP && pxSquadLeader && pxSquadLeader != pxOurActor )
// 			{
// 				Asura_Vector_3 xDirToNextWP = pxTestWP->GetPosition() - pxOurActor->GetPosition();
// 				xDirToNextWP.Normalise();
// 
// 				Asura_Vector_3 xDirToLeader = pxSquadLeader->GetPosition() - pxOurActor->GetPosition();
// 				xDirToLeader.Normalise();
// 
// 				float fDot = xDirToNextWP * xDirToLeader;
// 
// 				if ( fDot > -0.707f )
// 				{
// 					return true;
// 				}
// 			}
// 		}
// 	}
// 
// 	if ( GetTacticalSystem()->HasArrivedAtDestination() && m_fPosEvalUpdateTimer > dbg_fLongTimeOut )
// 	{
// 		return true;
// 	}
// 
// 	if ( pxSquadLeader && pxSquadLeader != pxOurActor )
// 	{
// 		float fDistance = ( pxOurActor->GetPosition() - pxSquadLeader->GetPosition() ).MagnitudeSquared();
// 
// 		if ( fDistance > 10.0f && pxSquadLeader->GetVelocity().MagnitudeSquared() > 23.0f && m_fPosEvalUpdateTimer > dbg_fLongTimeOut )
// 		{
// 			return true;
// 		}
// 	}
// 
// 	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: PositionEvaluation
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::FormationPositionEvaluation( const float fTimeslice)
{
	// Just do it once!
	m_fPosEvalUpdateTimer += fTimeslice;

	//if ( ShouldUpdatePositionEvaluation() )
	if (1)
	{
		AVP_ServerActor_Human* pxSquadLeader = GetSquadLeader();

		if ( pxSquadLeader )
		{
			AVP_Navigation::NavData&			xNavData			= GetMarineBrain()->GetNavData();
			Asura_Guid							uCombatZoneGuid		= (GetMarineBrain()->GetIsRestrictedToCombatZone()) ? GetMarineBrain()->GetCombatZoneGuid() : ASURA_GUID_UNREGISTERED;

			u_short uLeaderWPID = ASURA_INVALID_WAYPOINT_ID;

			if (!AVP_Navigation::GetNearestWaypointID( pxSquadLeader->GetPosition(), uLeaderWPID ))
			{
				uLeaderWPID = xNavData.m_usCurrentWPID;
			}

			AVP_ServerEntity_GamePlayVolume* pxGPV = pxSquadLeader->GetCurrentGamePlayVolume();

			float fEvaluationRange = 25.0f;

			if ( pxGPV )
			{
				switch ( pxGPV->GetGamePlayAreaType() )
				{
					case AVP_ServerEntity_GamePlayVolume::TIGHT_CORRIDOR:	fEvaluationRange = 10.0f; break;
					case AVP_ServerEntity_GamePlayVolume::LARGE_CORRIDOR:	fEvaluationRange = 12.0f; break;
					case AVP_ServerEntity_GamePlayVolume::SMALL_ROOM:		fEvaluationRange = 10.0f; break;
					case AVP_ServerEntity_GamePlayVolume::LARGE_ROOM:		fEvaluationRange = 15.0f; break;
					case AVP_ServerEntity_GamePlayVolume::OPEN_SPACE:		fEvaluationRange = 25.0f; break;
					case AVP_ServerEntity_GamePlayVolume::IGNORE_GPV:		fEvaluationRange = 25.0f; break;
					default:												fEvaluationRange = 25.0f; break;
				}
			}

			// Can't use the destination if we have a player as a squad leader
			if (pxSquadLeader->IsPlayer())
			{
				AVP_Navigation::AVP_PosEvalParams	xPosEvalParams( GetMarineBrain()->GetOwnerGuid(), uLeaderWPID, fEvaluationRange, uCombatZoneGuid );
				AVP_Navigation::PosEvalFunctor		pxPosEval( uLeaderWPID, fEvaluationRange, xPosEvalParams, GetFormationScoreForWaypoint);
				AVP_Navigation::SearchWaypoints(AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, &pxPosEval);
				FindBestWaypoint(&pxPosEval);
			}
			else
			{
				const AVP_Navigation::NavData& xLeaderNavData = pxSquadLeader->GetActorBrain()->GetNavData();

				float fLeadersDistToDestiantion = ( pxSquadLeader->GetPosition() -  xLeaderNavData.m_xDestinationPosition ).MagnitudeSquared();
				float fOurDistanceToLeadersDestination = ( GetOurActor()->GetPosition() - xLeaderNavData.m_xDestinationPosition ).MagnitudeSquared();

				if (xLeaderNavData.m_xDestinationPosition == Asura_Maths::ZeroVector3)
				{
					fLeadersDistToDestiantion = 0.0f;
				}

				if ( ( fLeadersDistToDestiantion > 100.0f ) && ( fOurDistanceToLeadersDestination < 1600.0f ) )
				{
					AVP_Navigation::AVP_PosEvalParams	xPosEvalParams( GetMarineBrain()->GetOwnerGuid(), uLeaderWPID, fEvaluationRange, uCombatZoneGuid );
					AVP_Navigation::PosEvalFunctor		pxPosEval( uLeaderWPID, fEvaluationRange, xPosEvalParams, GetLeadersDestinationFormationScoreForWaypoint);
					AVP_Navigation::SearchWaypoints(AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, &pxPosEval);
					FindBestWaypoint(&pxPosEval);
				}
				else 
				{
					AVP_Navigation::AVP_PosEvalParams	xPosEvalParams( GetMarineBrain()->GetOwnerGuid(), uLeaderWPID, fEvaluationRange, uCombatZoneGuid );
					AVP_Navigation::PosEvalFunctor		pxPosEval( uLeaderWPID, fEvaluationRange, xPosEvalParams, GetFormationScoreForWaypoint);
					AVP_Navigation::SearchWaypoints(AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, &pxPosEval);
					FindBestWaypoint(&pxPosEval);
				}
			}
		}

		m_fPosEvalUpdateTimer = 0.0f;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: FindBestWaypoint
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_SquadMember::FindBestWaypoint( AVP_Navigation::PosEvalFunctor* pxPosEval )
{
	u_int uBestWaypointID = pxPosEval->GetBestWaypointID();

	if ( uBestWaypointID != ASURA_INVALID_WAYPOINT_ID )
	{
		Asura_AI_NavVertex*	pxWaypoint	= Asura_AI_Navigation_System::GetWaypoint( uBestWaypointID );
		AVP_Tactical_System* pxTactical	= GetMarineBrain()->GetTacticalSystem();
		const Asura_Vector_3&	xOurPos	= GetMarineBrain()->GetHumanActor()->GetPosition();

		if ( pxWaypoint )
		{
			float fDistanceSq = ( pxWaypoint->m_xPosition - xOurPos ).MagnitudeSquared();
			if ( fDistanceSq >= 9.0f )
			{
				pxTactical->CancelStopMovingWithDelay();
				pxTactical->OverrideStartMovementDelay();
				pxTactical->SetDestination( pxWaypoint->m_xPosition );
				pxTactical->SetAtDestinationRange( ONE_METER );
				pxTactical->LetRouteSetLookAt( true );
				pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );
			}
		}
	}

#if 0
				AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();

				if ( !pxSquad )
				{
					pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );
				}
				else
				{
					AVP_ServerActor_Human* pxLeader = AVP_ServerActor_Human::FindEntity( pxSquad->GetSquadLeaderGuid() );

					if (!pxLeader->IsPlayer())
					{
						pxTactical->SetMovementSpeed( GetAILeadersMoveSpeed() );
						return;
					}

					if ( !pxLeader )
					{
						pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );
					}
					else
					{
						float fDistanceSq = ( xOurPos - pxLeader->GetPosition() ).MagnitudeSquared();

						if ( m_bRouteIsToLeader )
						{
							AVP_Navigation::NavData& xNavData = GetMarineBrain()->GetNavData();
							float fRouteDistance = AVP_Navigation::CalculateRouteDistance( xNavData, GetOurActor()->GetPosition(), xNavData.m_usRouteSegmentIndex );
							
							if ( fRouteDistance != 0.0f )
							{
								fDistanceSq = fRouteDistance;
							}
						}

						if (fDistanceSq > 100.0f)
						{
							pxTactical->SetMovementSpeed( AVP_Navigation::MM_FAST );
						}
						else
						{
							float fVelocity = pxLeader->GetVelocity().MagnitudeSquared();

							if ( fVelocity < 16.0f )
							{
								pxTactical->SetMovementSpeed( AVP_Navigation::MM_SLOW );
							}
							else if ( fVelocity < 49.0f )
							{
								pxTactical->SetMovementSpeed( AVP_Navigation::MM_MEDIUM );
							}
							else
							{
								pxTactical->SetMovementSpeed( AVP_Navigation::MM_FAST );
							}
						}
					}
				}
			}
		}
	}
#endif
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: GetFormationScoreForWaypoint
//---------------------------------------------------------------------------
u_int AVP_Behaviour_Marine_SquadMember::GetFormationScoreForWaypoint( AVP_Navigation::AVP_PosEvalParams xPosEvalParams )
{
	AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( xPosEvalParams.m_uActorGuid );

	u_int uScore = 0;

	// this should always be valid as he has just requested a position evaluation
	if ( !pxHuman ) { return uScore; }

	// Waypoint Proximity
	uScore += AVP_PositionEvaluation::GetProximityScore( pxHuman, xPosEvalParams.m_uTestWPID, xPosEvalParams.m_fEvaluationRange );

	// Waypoint Occupied by ally
	uScore += AVP_PositionEvaluation::GetHumanoidPositionOccupiedByAllyScore( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	// Always want a position close to the squad leader
	uScore += AVP_PositionEvaluation::GetPositionCloseToSquadLeaderScore( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	// Stops marines moving araound to much.
	uScore += AVP_PositionEvaluation::GetPositionIsInFrontOfSquadScore( pxHuman, xPosEvalParams.m_uTestWPID, 40 );

	// We do not really want to stand by walls
	uScore += AVP_PositionEvaluation::GetPositionIsWaypointNextToWall( xPosEvalParams.m_uTestWPID, 20 );

	return uScore;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: GetFormationScoreForWaypoint
//---------------------------------------------------------------------------
u_int AVP_Behaviour_Marine_SquadMember::GetLeadersDestinationFormationScoreForWaypoint( AVP_Navigation::AVP_PosEvalParams xPosEvalParams )
{
	AVP_ServerActor_Human* pxHuman = AVP_ServerActor_Human::FindEntity( xPosEvalParams.m_uActorGuid );

	u_int uScore = 0;

	// this should always be valid as he has just requested a position evaluation
	if ( !pxHuman ) { return uScore; }

	// Waypoint Proximity
	//uScore += AVP_PositionEvaluation::GetProximityScore( pxHuman, xPosEvalParams.m_uTestWPID, xPosEvalParams.m_fEvaluationRange );
	
	// Waypoint Occupied by ally
	uScore += AVP_PositionEvaluation::GetHumanoidPositionOccupiedByAllyScore( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	// Always want a position close to the squad leader
	uScore += AVP_PositionEvaluation::GetPositionCloseToSquadLeaderScore( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	// Always want a position close to the squad leader
	uScore += AVP_PositionEvaluation::GetPositionCloseToSquadLeaderDestinationScore( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	// Stops marines moving araound to much.
	uScore += AVP_PositionEvaluation::GetPositionIsInFrontOfSquadScore(pxHuman, xPosEvalParams.m_uTestWPID, 40 );

	// We do not really want to stand by walls
	uScore += AVP_PositionEvaluation::GetPositionIsWaypointNextToWall( xPosEvalParams.m_uTestWPID, 20 );

	return uScore;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: AreWeStillInASquad
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::AreWeStillInASquad( void ) const
{
	// If we don't have a squad Guid then we are in a squad on our own.
	if ( GetOurActor()->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED ) { return false; }

	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();

	// If we have no squad its in the default squad
	if ( !pxSquad )
	{
		return false;
	}
	else
	{
		return true;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: AreWeTheSquadLeader
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_SquadMember::AreWeTheSquadLeader( void ) const
{
	// If we don't have a squad Guid then we are in a squad on our own.
	if ( GetOurActor()->GetInitialSquadGuid() == ASURA_GUID_UNREGISTERED ) { return true; }

	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();

	// If we have no squad its in the default squad
	if ( !pxSquad )	{ return true; }

	// Check the squad leaders guid is our guid
	if ( pxSquad->GetSquadLeaderGuid() == GetOurActor()->GetGuid() )
	{
		return true;
	}
	else
	{
		return false;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: GetSquadLeader
//---------------------------------------------------------------------------
AVP_ServerActor_Human* AVP_Behaviour_Marine_SquadMember::GetSquadLeader() const
{
	AVP_ServerEntity_Squad_Marine* pxSquad = GetSquad();

	if ( !pxSquad ) { return NULL; }

	Asura_Guid uLeaderGuid = pxSquad->GetSquadLeaderGuid();

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

	AVP_ServerActor_Human* pxSquadLeader = AVP_ServerActor_Human::FindEntity( uLeaderGuid );

	return pxSquadLeader;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_SquadMember :: RenderDebugInfo
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszMarineStateStrings[ AVP_Behaviour_Marine_SquadMember::MAX_STATES ] =
{
	"MARINE SQUAD - UNSET",
	"MARINE SQUAD - CHOOSE",
	"MARINE SQUAD - WAIT",
	"MARINE SQUAD - MOVE",
	"MARINE SQUAD - ATTACK",
	"MARINE SQUAD - ALERT",
	"MARINE SQUAD - POST_ALERT",
	"MARINE SQUAD - HIDE_FROM_CLOAKED_PRED",
	"MARINE SQUAD - BE_ALERT",
};

static const char* s_aszAndroidStateStrings[AVP_Behaviour_Marine_SquadMember::MAX_STATES] =
{
	"ANDROID SQUAD - UNSET",
	"ANDROID SQUAD - CHOOSE",
	"ANDROID SQUAD - WAIT",
	"ANDROID SQUAD - MOVE",
	"ANDROID SQUAD - ATTACK",
	"ANDROID SQUAD - ALERT",
	"ANDROID SQUAD - POST_ALERT",
	"ANDROID SQUAD - HIDE_FROM_CLOAKED_PRED",
	"ANDROID SQUAD - BE_ALERT",
};

void AVP_Behaviour_Marine_SquadMember::RenderDebugInfo()
{
	PARENT::RenderDebugInfo();

	if (GetOurActor()->GetClassification() == AVP_ENTITYCLASS_MARINE)
	{
		Asura_Font_System::Print
		(
			GetProjectBrain()->GetDebugOutputPos().x,
			GetProjectBrain()->GetDebugOutputPos().y,
			0.5f, 
			0xff00ff00,
			ASURA_TEXTFORMAT_CENTREJUSTIFIED, 
			s_aszMarineStateStrings[ GetUpdateState() ]
		);
	}
	else
	{
		Asura_Font_System::Print
		(
			GetProjectBrain()->GetDebugOutputPos().x,
			GetProjectBrain()->GetDebugOutputPos().y,
			0.5f, 
			0xffff0000,
			ASURA_TEXTFORMAT_CENTREJUSTIFIED, 
			s_aszAndroidStateStrings[ GetUpdateState() ]
		);
	}

	GetProjectBrain()->GetDebugOutputPos().y += 10.0f;
#if defined(_DEBUG)
	//AVP_Navigation::PosEvalFunctor::RenerWpInfo();
#endif
}
#endif
