//---------------------------------------------------------------------------
// File			: AVP_Behaviour_Marine_Attack_StandGround.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_Attack_StandGround.h"
// asura
#include "Entity/Locations/OrientedNode/CoverpointNode/Asura_ServerNode_Coverpoint.h"
#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Rendering/Asura_Font_System.h"
#endif

// axon
// AVP
#include "Entity/GamePlayVolume/AVP_ServerEntity_GamePlayVolume.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
// AVP axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/BrainTypes/AVP_Brain_Actor_Marine.h"
#include "Tactical/AVP_Tactical_System.h"
#include "Core/AVP_PositionEvaluation.h"
#include "Knowledge/AVP_Knowledge_System_Actor.h"

#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Behaviour/BehaviourTypes/Human/Marine/AVP_Behaviour_Marine_InCover.h"

DEBUGVAR float dbg_fLookTimeout = 0.5f;

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: Constructor
//---------------------------------------------------------------------------
AVP_Behaviour_Marine_Attack_StandGround::AVP_Behaviour_Marine_Attack_StandGround( AVP_Brain_Actor_Marine* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_MARINE_ATTACK_STANDGROUND )
, m_pxMarineBrain( pxBrain )
, m_eUpdateState( STAND_GROUND_CHOOSE )
, m_fTimer( 2.0f )
, m_fAimTimer( dbg_fLookTimeout )
{

}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: Deconstructor
//---------------------------------------------------------------------------
AVP_Behaviour_Marine_Attack_StandGround::~AVP_Behaviour_Marine_Attack_StandGround( void )
{

}

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

	// Put Code Above This Comment
	return bParentOk;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: Deactivate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Attack_StandGround::Deactivate( void )
{
	// Put Code Above This Comment
	DestroyAllChildren();
	PARENT::Deactivate();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: PerFrameUpdate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Attack_StandGround::PerFrameUpdate( const float fTimeslice )
{
	switch (GetUpdateState())
	{
		case STAND_GROUND_CHOOSE:
		{
			if ( m_fTimer <= 0.0f )
			{
				AVP_Navigation::NavData&	xNavData		= GetMarineBrain()->GetNavData();
				Asura_Guid					uCombatZoneGuid	= GetMarineBrain()->GetCombatZoneGuid();

				AVP_Navigation::TestParams			xTestParams( AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, xNavData.m_usCurrentZone );
				AVP_Navigation::AVP_PosEvalParams	xPosEvalParams( GetMarineBrain()->GetOwnerGuid(), xNavData.m_usCurrentWPID, 30.0f, 15.0f, 30.0, uCombatZoneGuid );
				AVP_Navigation::PosEvalFunctor		pxPosEval( xNavData.m_usCurrentWPID, 30.0f, xPosEvalParams, EvaluationFunction );
				AVP_Navigation::SearchWaypoints( AVP_Navigation::AVP_AI_PATHFINDER_FLAG_HUMANOID, &pxPosEval );

				if ( FindBestWaypoint( &pxPosEval ) )
				{
					SwitchToState( STAND_GROUND_MOVE );
				}
				else
				{
					m_fTimer = 2.0f;
				}
			}
// 			else
// 			{
// 				CheckForCover();
// 			}

			m_fTimer -= fTimeslice;

		}break;

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

		case STAND_GROUND_MOVE:
		{

		}break;

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

		case UNSET:
		default:
		{

		}
	}

	GetMarineBrain()->AimAtThreat();
	GetMarineBrain()->LookAtThreat();
}

DEBUGVAR float dbg_fOffsetXZ = 2.5f;
DEBUGVAR float dbg_fOffsetY = 0.3f;

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: CheckForCover
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Attack_StandGround::LookInThreatsArea(const float fTimeslice)
{
	if ( m_fAimTimer >= dbg_fLookTimeout )
	{
		if (GetTacticalSystem() && GetKnowledgeSystem())
		{
			Asura_Vector_3 xThreatPos( Asura_Maths::ZeroVector3 );

			GetMarineBrain()->GetThreatPos( xThreatPos );

			xThreatPos.x += Asura_Random::GetFloat( -dbg_fOffsetXZ, dbg_fOffsetXZ );
			xThreatPos.y += Asura_Random::GetFloat( -dbg_fOffsetY, dbg_fOffsetY );
			xThreatPos.z += Asura_Random::GetFloat( -dbg_fOffsetXZ, dbg_fOffsetXZ );

			GetMarineBrain()->AimAtPosition( xThreatPos );
		}
	}

	m_fAimTimer -= fTimeslice;

	if ( m_fAimTimer <= 0.0f )
	{
		m_fAimTimer = dbg_fLookTimeout;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: CheckForCover
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Attack_StandGround::CheckForCover()
{
// 	AVP_ServerActor_Human*				pxOurActor			= GetOurActor(); // Validated every frame by brain
// 	AVP_ServerEntity_GamePlayVolume*	pxOurVolume			= pxOurActor->GetCurrentGamePlayVolume();
// 	Asura_Vector_3						xThreatPos			= Asura_Maths::ZeroVector3; GetMarineBrain()->GetThreatPos( xThreatPos );
// 	float								fBestDistance		= Asura_Maths::LargeFloat;
// 	Asura_ServerNode_Coverpoint*		pxBestCoverPoint	= NULL;
// 	
// 	if ( !pxOurVolume ) { return; }
// 
// 	for ( u_int u = 0; u < pxOurVolume->GetNumCoverPointGuids(); ++u )
// 	{
// 		Asura_ServerNode_Coverpoint* pxCoverPoint = Asura_ServerNode_Coverpoint::FindEntity( pxOurVolume->GetCoverPointGuid( u ) );
// 		if ( !pxCoverPoint || pxCoverPoint->IsOccupied() || !pxCoverPoint->IsEntityActive() ) { continue; }
// 
// 		Asura_Vector_3 xOurDirectionToCoverPoint( pxCoverPoint->GetPosition() - pxOurActor->GetPosition() );
// 		float fDistanceFromUsSq = xOurDirectionToCoverPoint.MagnitudeSquared();
// 		if ( fDistanceFromUsSq < 64.0f ) { continue; } // 8 meters
// 
// 		Asura_Vector_3 xThreatDirectionToCoverPoint( pxCoverPoint->GetPosition() - xThreatPos );
// 		float fDistanceFromThreatSq = xThreatDirectionToCoverPoint.MagnitudeSquared();
// 		if ( fDistanceFromThreatSq < 25.0f ) { continue; } // 5 meters
// 
// 		if ( !pxCoverPoint->ProvidesCoverFrom( xThreatPos) ) { continue; }
// 
// 		float fDot = xOurDirectionToCoverPoint * xThreatDirectionToCoverPoint;
// 
// 		if (fDot > 0) { continue; }
// 
// 		if ( fDistanceFromUsSq < fBestDistance )
// 		{
// 			fBestDistance = fDistanceFromUsSq;
// 			pxBestCoverPoint = pxCoverPoint;
// 		}
// 	}
// 
// 
// 	if ( pxBestCoverPoint )
// 	{
// 		m_uBestCoverPoint = pxBestCoverPoint->GetGuid();
// 		GetTacticalSystem()->SetDestination( pxBestCoverPoint->GetPosition() );
// 		GetTacticalSystem()->SetAtDestinationRange( ONE_METER );
// 		GetTacticalSystem()->SetMovementSpeed( AVP_Navigation::MM_SLOW );
// 		SwitchToState( SUPPORT_MOVE_TO_COVER );
// 	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: FindBestWaypoint
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Attack_StandGround::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();

		if ( pxWaypoint )
		{
// 			if ( DoesWaypointContainCoverAndItsNotOccupied( uBestWaypointID ) )
// 			{
// 				if ( m_uBestCoverPoint != ASURA_GUID_UNREGISTERED )
// 				{
// 					Asura_ServerNode_Coverpoint* pxCoverPoint = Asura_ServerNode_Coverpoint::FindEntity( m_uBestCoverPoint );
// 					if ( pxCoverPoint )
// 					{
// 						pxTactical->SetDestination( pxCoverPoint->GetPosition() );
// 						pxTactical->SetAtDestinationRange( ONE_METER );
// 						pxTactical->SetMovementSpeed( AVP_Navigation::MM_SLOW );
// 						SwitchToState( SUPPORT_MOVE_TO_COVER );
// 						return false;
// 					}
// 				}
// 			}

			float fDistanceSq = ( GetOurActor()->GetPosition() - pxWaypoint->m_xPosition ).MagnitudeSquared();

			if ( fDistanceSq > 9.0f )
			{
				pxTactical->SetDestination( pxWaypoint->m_xPosition );
				pxTactical->SetAtDestinationRange( ONE_METER );
				pxTactical->SetMovementSpeed( AVP_Navigation::MM_SLOW );
				return true;
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: DoesWaypointContainCoverAndItsNotOccupied
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Attack_StandGround::DoesWaypointContainCoverAndItsNotOccupied( u_int uWaypointID )
{
// 	// Ensure we have a threat
// 	if ( !GetMarineBrain()->DoesHaveThreat() ) { return false; }
// 
// 	// Ensure Our Waypoint Is Valid
// 	Asura_AI_NavVertex*					pxWaypoint	= Asura_AI_Navigation_System::GetWaypoint( uWaypointID );
// 	if ( !pxWaypoint ) { return false; }
// 
// 	// Ensure Our Volume Is Valid
// 	AVP_ServerEntity_GamePlayVolume*	pxVolume	= AVP_ServerEntity_GamePlayVolume::GetVolumeThatContainsPosition( pxWaypoint->GetPosition() );
// 	if ( ( !pxVolume ) || ( pxVolume->GetNumCoverPointGuids() == 0 ) ) { return false; }
// 
// 	Asura_Vector_3 xThreatPos = Asura_Maths::ZeroVector3;
// 	GetMarineBrain()->GetThreatPos( xThreatPos );
// 
// 	// Reset the best cover point
// 	m_uBestCoverPoint = ASURA_GUID_UNREGISTERED;
// 
// 	// Iterate around all cover points in the waypoints gameplay volume
// 	for ( u_int u = 0; u < pxVolume->GetNumCoverPointGuids(); ++u )
// 	{
// 		Asura_ServerNode_Coverpoint* pxCoverPoint = Asura_ServerNode_Coverpoint::FindEntity( pxVolume->GetCoverPointGuid( u ) );
// 		if ( !pxCoverPoint || !pxCoverPoint->IsEntityActive() || pxCoverPoint->IsOccupied() ) { continue; }
// 
// 		// is the cover point in our waypoint
// 		if ( Asura_AI_Navigation_System::IsPositionInWaypoint( pxCoverPoint->GetPosition(), uWaypointID ) )
// 		{
// 			Asura_Vector_3 xDirToThreat = ( xThreatPos - pxCoverPoint->GetPosition() );
// 			float fDistanceSq = xDirToThreat.MagnitudeSquared();
// 
// 			if ( fDistanceSq < 64.0f )
// 			{
// 				continue;
// 			}
// 
// 			// Does it provide cover from our threat?
// 			if ( pxCoverPoint->ProvidesCoverFrom( xThreatPos ) )
// 			{
// 				// wow we have one!
// 				m_uBestCoverPoint = pxCoverPoint->GetGuid();
// 				break;
// 			}
// 		}
// 	}
// 
// 	if ( m_uBestCoverPoint != ASURA_GUID_UNREGISTERED )
// 	{
// 		return true;
// 	}
// 	else
// 	{
		return false;
//	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: GetAttackingScoreForWaypoint
//---------------------------------------------------------------------------
u_int AVP_Behaviour_Marine_Attack_StandGround::EvaluationFunction( 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 * 2.0f );

	AVP_Brain_Actor_Marine* pxBrain = (AVP_Brain_Actor_Marine*)pxHuman->GetActorBrain();

	if ( pxBrain )
	{
		if ( !pxBrain->GetKnowledgeSystem()->ShootAtScriptedTarget() || ( pxBrain->GetKnowledgeSystem()->ShootAtScriptedTarget() && !pxBrain->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) )
		{
			// Line Of Fire To The Primary Threat
			uScore += AVP_PositionEvaluation::GetWaypointLOFtoPrimaryThreatScore( pxHuman, xPosEvalParams.m_uTestWPID, 40 );
		}
		else
		{
			uScore += AVP_PositionEvaluation::GetWaypointLOFToScriptedTarget( pxHuman, xPosEvalParams.m_uTestWPID, 40 );
		}
	}

	// Preferred Fighting Range
	uScore += AVP_PositionEvaluation::GetPreferredFightingRangeScore( pxHuman, xPosEvalParams.m_uTestWPID, xPosEvalParams.m_fMinFightingRange, xPosEvalParams.m_fMaxFightingRange, 40 );

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

	// Waypoint Gives no LOF from Secondary Threats
	uScore += AVP_PositionEvaluation::GetHumanoidPositionGivesCoverFromSecondaryThreatsScore( pxHuman, xPosEvalParams.m_uTestWPID, 30 );

	// Waypoint Has a cover point that provides cover from primary threat
	//uScore += AVP_PositionEvaluation::GetPositionProvidesCoverFromPrimaryThreat( pxHuman, xPosEvalParams.m_uTestWPID, 60 );

	return uScore;

}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: SwitchToState
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Attack_StandGround::SwitchToState( UpdateState eState )
{
	switch (GetUpdateState())
	{
		case UNSET:
		default:
		{

		}
	}

	SetUpdateState( eState );

	switch (GetUpdateState())
	{
		case STAND_GROUND_CHOOSE:
		{
			m_fTimer = 0.0f;

		}break;
		case UNSET:
		default:
		{

		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Attack_StandGround :: RenderDebugInfo
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[ AVP_Behaviour_Marine_Attack_StandGround::MAX_STATES ] =
{
	"Attack_StandGround - UNSET",
};

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

	Asura_Font_System::Print
	(
		GetProjectBrain()->GetDebugOutputPos().x,
		GetProjectBrain()->GetDebugOutputPos().y,
		0.5f, 
		0XFFFFFFFF,
		ASURA_TEXTFORMAT_CENTREJUSTIFIED, 
		s_aszStateStrings[GetUpdateState()]
	);

	// Offset the debug output position for other behaviours to render there own text
	GetProjectBrain()->GetDebugOutputPos().y += 10.0f;
}
#endif

/// End Of File 'AVP_behaviour_Marine_Attack_StandGround.cpp'
