//---------------------------------------------------------------------------
// File			: AVP_Behaviour_Marine_Weapon.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_Weapon.h"
// asura
#include "Entity/PhysicalObject/Moves/Asura_Movement_System.h"
#include "Network/Asura_Message.h"

#ifndef ASURA_NO_DEBUG_OUTPUT
#include "Debugging/Asura_DebugLineRender.h"
#include "Rendering/Asura_Font_System.h"
#endif

// axon
// AVP
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ClientActor_Human.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ServerActor_Predator.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/Items/Weapons/AVP_RangedWeapon_SubType.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_RangedWeapon.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 "Knowledge/AVP_Knowledge_System_Actor.h"
#include "Knowledge/SenseTypes/AVP_Sense_Vision_Actor.h"
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_SmartGun.h"

//---------------------------------------------------------------------------------
// STATICS
//---------------------------------------------------------------------------------
float AVP_Behaviour_Marine_Weapon::s_fGrenadeRefireTime = 5.0f;
float AVP_Behaviour_Marine_Weapon::s_fGrenadeMinRange = 22.0f;
float AVP_Behaviour_Marine_Weapon::s_fGrenadeMaxRange = 24.0f;

//---------------------------------------------------------------------------------
//*********************************************************************************
//---------------------------------------------------------------------------------
// Class		: AVP_Behaviour_Marine_Weapon
// Description	: 
//---------------------------------------------------------------------------------
//*********************************************************************************
//---------------------------------------------------------------------------------

DEBUGVAR float dbg_fMinFireTime = 0.3f;
DEBUGVAR float dbg_fMaxFireTime = 0.5f;

float dbg_fMinScopedRifleStoppedFireTime = 2.9f;
float dbg_fMaxScopedRifleStoppedFireTime = 3.1f;


float dbg_fMinScopedRifleFireTime = 0.17f;
float dbg_fMaxScopedRifleFireTime = 0.25f;

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Constructor
//---------------------------------------------------------------------------
AVP_Behaviour_Marine_Weapon::AVP_Behaviour_Marine_Weapon(AVP_Brain_Actor_Marine* pxBrain)
: PARENT(pxBrain, AVP_BEHAVIOUR_TYPE_MARINE_WEAPON)
, m_eUpdateState( SUPPORT_IDLE )
, m_pxMarineBrain(pxBrain)
, m_fTimeSinceLastShot(5.0f)
, m_bReloading(false)
, m_bFiring(false)
, m_uEnemyGuid(ASURA_GUID_UNREGISTERED)
, m_fFiringToIdleTimer(0.0f)
, m_fFiringToIdleTimeOut(0.0f)
, m_fLastCheckDistance(0.0f)
, m_fTimeSinceGrenade(5.0f)
, m_fFiringTimer(0.0f)
, m_fStoppedFiringTimer(0.0f)
, m_fDialogueTimer(0.0f)
, m_bReloadStated(false)
, m_fTestDot(0.0f)
, m_fFlameTimeout( 0.0f )
{
	m_fFiringToIdleTimeOut = Asura_Random::GetFloat(3.0f, 6.0f);
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Activate
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::Activate(void)
{
	const bool bParentOk = PARENT::Activate();

	if ( GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SCOPED_RIFLE )
	{
		float fRoF = GetWeaponRateOfFire();
		dbg_fMinScopedRifleStoppedFireTime = fRoF - 0.1f;
		dbg_fMaxScopedRifleStoppedFireTime = fRoF + 0.1f;
	}

	return bParentOk;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Deactivate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::Deactivate(void)
{
	if (m_bFiring)
	{
		StopShooting();
	}

	PARENT::Deactivate();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Pause
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::Pause(void)
{
	PARENT::Pause();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Unpause
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::Unpause(void)
{
	PARENT::Unpause();
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Update
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::Update(const float fTimeslice)
{
	if ((!GetMarineBrain()) || (!GetMarineBrain()->GetHumanActor()))
	{
		return;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: PerFrameUpdate
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::PerFrameUpdate(const float fTimeslice)
{
	AVP_Tactical_System* pxTactical = GetMarineBrain()->GetTacticalSystem();

	if ( pxTactical->IsUsingExternalShooting() )
	{
		return;
	}

	if (pxTactical->IsInGrapple() || pxTactical->IsOnGameScene() || !GetMarineBrain()->GetHumanActor()->IsAiming() || pxTactical->GetStopShooting())
	{
		StopShooting();
		return;
	}

	m_fDialogueTimer += fTimeslice;

	switch (GetUpdateState())
	{
		//---------------------------------------------------------------------------
		case IDLE:
		{
			StopShooting();

			// Check to see if we can shoot
			if ((CheckForFire()) && (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED))
			{
				m_fStoppedFiringTimer = 0.0f;
				SetUpdateState(FIRING);
			}

			if (GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == true)
			{
				SetUpdateState(RELOADING);
			}

			ClearGuidBeingattackedIfWeaponIdle();
		}break;
		//---------------------------------------------------------------------------
		case RELOADING:
		{
			if (!m_bReloadStated)
			{
				m_bReloadStated = true;
				GetMarineBrain()->GetHumanActor()->PlayDialogue(AVP_ServerActor_Human::AVP_DLG_HUMAN_RELOADING);
			}

			if (CheckForReloadFinsihed())
			{
				m_bReloadStated = false;
				m_fStoppedFiringTimer = 0.0f;
				SetUpdateState(SUPPORT_IDLE);
			}

		}break;
		//---------------------------------------------------------------------------
		case FIRING:
		{
			DoFiring( fTimeslice );
			
		}break;
		//---------------------------------------------------------------------------
		case SUPPORT_IDLE:
		{
			if ( CheckForSupportFire() && (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED) )
			{
				m_fStoppedFiringTimer = 0.0f;
				SetUpdateState( SUPPORT_FIRE );
			}

			if (GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == true)
			{
				SetUpdateState(RELOADING);
			}

			ClearGuidBeingattackedIfWeaponIdle();

			float fAmmoPercentage = GetWeaponAmmo() / GetWeaponClipSize();
			float fRand1 = Asura_Random::GetFloat( 0.0f, 1.0f );
			float fRand2 = Asura_Random::GetFloat( 0.0f, 1.0f );

			if ( fAmmoPercentage < 0.1f || ( fRand1 > 0.9f && fRand2 > 0.9f && fAmmoPercentage < 0.8f ) )
			{
				if ( GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == false )
				{
					ReloadWeapon();
				}
			}

		}break;
		//---------------------------------------------------------------------------
		case SUPPORT_FIRE:
		{
			DoSupportFire( fTimeslice );

		}break;
		//---------------------------------------------------------------------------
		case UNSET:
		default:
		{

		}break;
	}

	if ( GetWeaponAmmo() < 1.0f )
	{
		if ( GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == false )
		{
			ReloadWeapon();
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: DoSupportFire
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::DoSupportFire( const float fTimeslice )
{
	// If we don't have a threat no point actually shooting

	if (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED)
	{
		m_bFiring = true;

		if ( !GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() || ( GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetMarineBrain()->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) )
		{
			AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity(GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid());

			if (pxThreatActor)
			{
				if (pxThreatActor->IsDead())
				{
					m_bFiring = false;
				}
			}
		}
	}

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

	bool bOverride = false;
	m_bFiring = false;
	AVP_Inventory_System*		pxInventorySystem	= pxOurActor->GetInventorySystem();
	AVP_InventoryItem_Weapon*	pxCurrentWeapon		= static_cast<AVP_InventoryItem_Weapon*>(pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

	if (pxCurrentWeapon != NULL)
	{
		if ( pxCurrentWeapon->IsIdling( true ) && m_fStoppedFiringTimer > 0.0f )
		{
			bOverride = true;
			m_fStoppedFiringTimer -= fTimeslice;

			if ( m_fFiringTimer < 0.1f && GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SMARTGUN )
			{
				m_fStoppedFiringTimer = 0.0f;
			}
		}
		else if ( pxCurrentWeapon->IsIdling( true ) )
		{
			if ( CheckForSupportFire() && m_fStoppedFiringTimer <= 0.0f )
			{
				m_bFiring = true;
			}

			bOverride = true;
		}
		else
		{
			m_fFiringTimer += fTimeslice;

			if ( GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_FLAMETHROWER )
			{
				if ( !CheckForSupportFire() || m_fFiringTimer > m_fFlameTimeout )
				{
					m_bFiring = false;
				}
				else
				{
					m_bFiring = false;
					bOverride = true;
				}
			}
			else
			{
				if ( !CheckForSupportFire() )
				{
					m_bFiring = false;
				}
				else
				{
					m_bFiring = false;
					bOverride = true;
				}
			}
		}
	}

	if ( GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SMARTGUN )
	{
		AVP_Human_AIAnimStateMachine* pxStateMachine = static_cast<AVP_Human_AIAnimStateMachine*>(GetMarineBrain()->GetHumanActor()->GetAIAnimStateMachine());

		if ( !pxStateMachine->IsIdle() && !pxStateMachine->IsAlertIdle())
		{
			bOverride = false;
			m_bFiring = false;
		}

		if ( !m_bFiring && bOverride == false )
		{
			StopShooting();
			SetUpdateState(SUPPORT_IDLE);
		}
		else if ( m_bFiring )
		{
			PlayAttackingDialogue(fTimeslice);
			SupportShoot();
		}
	}
	else
	{
		if ( !m_bFiring && bOverride == false )
		{
			StopShooting();
			SetUpdateState(SUPPORT_IDLE);
		}
		else if ( m_bFiring )
		{
			PlayAttackingDialogue(fTimeslice);
			SupportShoot();
		}
	}

	

	if (GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == true)
	{
		SetUpdateState(RELOADING);
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: DoFiring
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::DoFiring( const float fTimeslice )
{
	// If we don't have a threat no point actually shooting
	if (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED)
	{
		m_bFiring = true;

		if ( !GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() || ( GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetMarineBrain()->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) )
		{
			AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity(GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid());

			if (pxThreatActor)
			{
				if (pxThreatActor->IsDead())
				{
					m_bFiring = false;
				}
			}
		}
	}
	else
	{
		m_fFiringTimer			= 0.0f;
		m_fStoppedFiringTimer	= 0.0f;
		m_bFiring = false;
	}

	if (m_bFiring)
	{
		if ((m_fFiringTimer <= 0.0f) && (m_fStoppedFiringTimer <= 0.0f))
		{
			// Check to see if we can actually shoot
			if (!CheckForFire())
			{
				m_fFiringTimer			= 0.0f;
				m_fStoppedFiringTimer	= 0.0f;
				m_bFiring = false;
			}
		}
	}

	if ((m_fFiringTimer <= 0.0f) && (m_fStoppedFiringTimer > 0.0f))
	{
		m_bFiring = false;
	}

	AVP_ServerEntity_Actor*			pxOurActor			= GetMarineBrain()->GetHumanActor();
	const AVP_ClientEntity_Actor*	pxClient			= AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());
	const Asura_Movement_System*	pxMovementSystem	= (pxClient == NULL) ? NULL : pxClient->GetMovementSystem();
	const Asura_Move*				pxCurrentMove		= (pxMovementSystem == NULL) ? NULL : pxMovementSystem->GetCurrentMove();

	if (pxCurrentMove)
	{
		m_bFiring = false;
	}


	if (!m_bFiring)
	{
		StopShooting();
		SetUpdateState(IDLE);
	}
	else
	{
		PlayAttackingDialogue(fTimeslice);

		Shoot();
	}

	if (GetMarineBrain()->GetTacticalSystem()->IsReloadingWeapon() == true)
	{
		SetUpdateState(RELOADING);
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CanFireGreande
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::ClearGuidBeingattackedIfWeaponIdle(void)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_ClientEntity_Actor* pxOurClientActor = AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());

		if (pxOurClientActor)
		{
			AVP_Inventory_System*	pxInventorySystem	= pxOurActor->GetInventorySystem();
			AVP_Inventory_Item*		pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

			if((pxCurrentWeapon != NULL) && pxCurrentWeapon->IsIdling(true))
			{
				AVP_ClientEntity_Actor* pxClientActor = AVP_ClientEntity_Actor::FindEntity(GetMarineBrain()->GetOwnerGuid());
				pxClientActor->SetGuidOfActorBeingAttackedByUs(ASURA_GUID_UNREGISTERED);
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CanFireGreande
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::CanFireGrenade(void)
{
	if (GetTimeSinceLastGrenade() > s_fGrenadeRefireTime)
	{
		if (m_uEnemyGuid != ASURA_GUID_UNREGISTERED)
		{
			AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity(m_uEnemyGuid);

			if (pxActor)
			{
				if ((pxActor->GetClassification() == AVP_ENTITYCLASS_PREDATOR) && pxActor->IsCloaked(true))
				{
					return false;
				}

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

				if (pxOurActor)
				{
					if ((m_fLastCheckDistance <= s_fGrenadeMaxRange) && (m_fLastCheckDistance >= s_fGrenadeMinRange))
					{
						// Don't shoot grenades all the time add some randomness to it.
						if (Asura_Random::GetFloat(0.0f, 1.0f) >= 0.7f)
						{
							ResetTimeSinceLastGrenade();
							return true;
						}
					}
				}
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: ReloadWeapon
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::ReloadWeapon(void)
{
	AVP_Brain_Actor_Marine*	pxBrain				= GetMarineBrain();
	AVP_Tactical_System*	pxTacticalSystem	= pxBrain->GetTacticalSystem();

	if (!pxTacticalSystem->IsReloadingWeapon())
	{
		AVP_ServerActor_Human*	pxHuman				= pxBrain->GetHumanActor();
		AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		AVP_Inventory_Item*		pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

		if(pxCurrentWeapon != NULL)
		{
			pxCurrentWeapon->RequestBeginUsage(AVP_InventoryItem_Weapon::UT_RELOAD_ALL);
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CheckForReloadFinsihed
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::CheckForReloadFinsihed(void)
{
	AVP_Tactical_System* pxTactical = GetMarineBrain()->GetTacticalSystem();

	if (pxTactical->IsReloadingWeapon())
	{
		return false;
	}
	else
	{
		return true;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CheckForFire
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::CheckForFire(void)
{
// 	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();
// 
// 	if (pxOurActor)
// 	{
// 		float fWeaponAmmo = GetWeaponAmmo();
// 
// 		if (fWeaponAmmo > 0.0f)
// 		{
// 			Asura_Vector_3		xHeadPos = Asura_Maths::ZeroVector3;
// 
// 			// Get our actors marker point for the Head
// 			pxOurActor->GetHeadPosition(xHeadPos);
// 
// 			// Ensure we have a threat
// 			if (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED)
// 			{
// 				if ( !GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() || ( GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetMarineBrain()->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) )
// 				{
// 					AVP_ServerEntity_Actor* pxThreatActor = AVP_ServerEntity_Actor::FindEntity(GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid());
// 
// 					if (pxThreatActor && !pxThreatActor->IsDead())
// 					{
// 						Asura_Vector_3		xThreatChestPos = Asura_Maths::ZeroVector3;
// 
// 						pxThreatActor->GetChestPosition(xThreatChestPos);
// 
// 						Asura_Vector_3		xGunPos = Asura_Maths::ZeroVector3;
// 						Asura_Matrix_3x3	xGunOri;
// 
// 						// Get the Pulse rifles muzzle marker point
// 						if (GetWeaponMuzzlePositionAndOrientation(&xGunPos, &xGunOri))
// 						{
// 							float			fWeaponMaxRange		= GetWeaponsMaxRange();
// 							Asura_Vector_3	xTestDirection		= xThreatChestPos - xGunPos;
// 							float			fDistanceToThreat	= xTestDirection.Normalise();
// 							Asura_Vector_3	xGunFwd				= Asura_Vector_3(xGunOri.e13, xGunOri.e23, xGunOri.e33);
// 
// 							xGunPos = xGunPos - xGunFwd;
// 
// 							if (fDistanceToThreat > fWeaponMaxRange)
// 							{
// 								m_bFiring = false;
// 								m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
// 								return false;
// 							}
// 
// 							// Do a LOS test
// 							const Asura_LOS_InputData	xInput = Asura_LOS_InputData(xGunPos, xTestDirection, pxOurActor->GetGuid(), fWeaponMaxRange, false);
// 							const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEverything(&xInput);
// 
// 							// Check to see if we have hit our threat
// 							if (pxOutput->m_uHitEntity == pxThreatActor->GetGuid())
// 							{
// 								// Need to check if the gun is inside a friendly collision box.
// 								if ( IsWeaponPositionInsideFriendlyBoundingBox(xGunPos) || AllyToCloseToFire(xGunPos, xThreatChestPos ) )
// 								{
// 									m_bFiring = false;
// 									m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
// 									return false;
// 								}
// 
// 								float fDot = xTestDirection * xGunFwd;
// 
// 								if ((fDot > 0.9f) || ((fDistanceToThreat < 1.5f) && (fDot > 0.0f)))
// 								{
// 									m_bFiring = true;
// 									m_fLastCheckDistance = pxOutput->m_fDistanceToIntersection;
// 									m_uEnemyGuid = pxOutput->m_uHitEntity;
// 									return true;
// 								}
// 							}
// 						}
// 					}
// 				}
// 				else
// 				{
// 					Asura_Vector_3		xThreatPos = GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().m_xPosition;
// 					Asura_Vector_3		xGunPos = Asura_Maths::ZeroVector3;
// 					Asura_Matrix_3x3	xGunOri;
// 
// 					// Get the Pulse rifles muzzle marker point
// 					if (GetWeaponMuzzlePositionAndOrientation(&xGunPos, &xGunOri))
// 					{
// 						float			fWeaponMaxRange		= GetWeaponsMaxRange();
// 						Asura_Vector_3	xTestDirection		= xThreatPos - xGunPos;
// 
// 						float			fDistanceToThreat	= xTestDirection.Normalise();
// 						Asura_Vector_3	xGunFwd				= Asura_Vector_3(xGunOri.e13, xGunOri.e23, xGunOri.e33);
// 
// 						xGunPos = xGunPos - xGunFwd;
// 
// 						if (fDistanceToThreat > fWeaponMaxRange)
// 						{
// 							m_bFiring = false;
// 							m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
// 							return false;
// 						}
// 
// 						// Do a LOS test
// 						const Asura_LOS_InputData	xInput = Asura_LOS_InputData(xGunPos, xTestDirection, pxOurActor->GetGuid(), fWeaponMaxRange, false);
// 						const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEverything(&xInput);
// 
// 						// Check to see if we have hit our threat
// 						if (pxOutput->m_fDistanceToIntersection >= fDistanceToThreat)
// 						{
// 							// Need to check if the gun is inside a friendly collision box.
// 							if ( IsWeaponPositionInsideFriendlyBoundingBox(xGunPos) || AllyToCloseToFire(xGunPos, xThreatPos ) )
// 							{
// 								m_bFiring = false;
// 								m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
// 								return false;
// 							}
// 
// 							float fDot = xTestDirection * xGunFwd;
// 
// 							if ((fDot > 0.9f) || ((fDistanceToThreat < 1.5f) && (fDot > 0.0f)))
// 							{
// 								m_bFiring = true;
// 								m_fLastCheckDistance = pxOutput->m_fDistanceToIntersection;
// 								m_uEnemyGuid = pxOutput->m_uHitEntity;
// 								return true;
// 							}
// 						}
// 					}
// 				}
// 			}
// 		}
// 	}
// 
	m_bFiring = false;
	m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CheckForSupportFire
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::CheckForSupportFire()
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		float fWeaponAmmo = GetWeaponAmmo();

		if (fWeaponAmmo > 0.0f)
		{
			Asura_Vector_3		xHeadPos = Asura_Maths::ZeroVector3;

			// Get our actors marker point for the Head
			pxOurActor->GetHeadPosition(xHeadPos);

			// Ensure we have a threat
			if (GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED)
			{
				Asura_Vector_3 xThreatPos = Asura_Maths::ZeroVector3;
				GetMarineBrain()->GetThreatPos( xThreatPos );

				if ( ( GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetMarineBrain()->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) || ( !GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() ) )
				{
					AVP_ServerEntity_Actor* pxActor = AVP_ServerEntity_Actor::FindEntity( GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() );

					if ( pxActor )
					{
						pxActor->GetChestPosition( xThreatPos );
					}
				}

				Asura_Vector_3		xGunPos = Asura_Maths::ZeroVector3;
				Asura_Matrix_3x3	xGunOri;

				// Get the Pulse rifles muzzle marker point
				if (GetWeaponMuzzlePositionAndOrientation(&xGunPos, &xGunOri))
				{
					float			fWeaponMaxRange		= GetWeaponsMaxRange();
					Asura_Vector_3	xGunFwd(xGunOri.e13, xGunOri.e23, xGunOri.e33);
					xGunPos = xGunPos - xGunFwd;
					Asura_Vector_3	xTestDirection( xThreatPos - xGunPos );
					
					float fDistanceToThreat = xTestDirection.Normalise();

					// Do a LOS test
					const Asura_LOS_InputData	xInput = Asura_LOS_InputData(xGunPos, xGunFwd, pxOurActor->GetGuid(), fDistanceToThreat, false);
					const Asura_LOS_OutputData*	pxOutput = Asura_LOS::TestAgainstEverything(&xInput);

					AVP_ServerEntity_Actor* pxHitActor = AVP_ServerEntity_Actor::FindEntity( pxOutput->m_uHitEntity );

					if ( pxHitActor )
					{
						if ( AVP_Tactical_System::GetAllegiance( *pxOurActor, *pxHitActor ) != AVP_ALLEGIANCE_ENEMY )
						{
							m_bFiring = false;
							m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
							return false;
						}
					}
					else
					{
						Asura_Vector_3 xTestPos(xGunPos + ( xGunFwd * fWeaponMaxRange ) );

						// Need to check if the gun is inside a friendly collision box.
						if ( IsWeaponPositionInsideFriendlyBoundingBox(xGunPos) || AllyToCloseToFire(xGunPos, xTestPos ) )
						{
							m_bFiring = false;
							m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
							return false;
						}

						if ( fWeaponMaxRange < fDistanceToThreat )
						{
							m_bFiring = false;
							m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
							return false;
						}
					}

					float fPercentage = ( pxOutput->m_fDistanceToIntersection / fDistanceToThreat );

					bool bCanSeeThreat = false;

					if ( GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().GetGuid() != ASURA_GUID_UNREGISTERED )
					{
						if ( GetMarineBrain()->GetKnowledgeSystem()->GetBestThreatKnowledge().m_uTypeInformation == AVP_Sense_Vision::TYPE_INFO_CAN_SEE )
						{
							bCanSeeThreat = true;
						}
					}

					if ( fPercentage > 0.98f || bCanSeeThreat )
					{
						float fDot = xTestDirection * xGunFwd;

						m_fTestDot = fDot;

						if ( GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_SMARTGUN )
						{
							m_bFiring = true;
							m_fLastCheckDistance = pxOutput->m_fDistanceToIntersection;
							m_uEnemyGuid = pxOutput->m_uHitEntity;
							return true;
						}
						else
						{
							if ( fDot > 0.95f )
							{
								m_bFiring = true;
								m_fLastCheckDistance = pxOutput->m_fDistanceToIntersection;
								m_uEnemyGuid = pxOutput->m_uHitEntity;
								return true;
							}
						}
					}
				}
			}
		}
	}

	m_bFiring = false;
	m_uEnemyGuid = ASURA_GUID_UNREGISTERED;
	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: AllyToCloseToFire
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::AllyToCloseToFire( const Asura_Vector_3 &xStart, const Asura_Vector_3& xEnd )
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

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

		if ( pxHuman && !pxHuman->IsDead() && pxHuman->IsEntityActive() && ( pxHuman != pxOurActor ) )
		{
			if ( AVP_Tactical_System::GetAllegiance(*pxOurActor, *pxHuman) == AVP_ALLEGIANCE_FRIEND )
			{
				Asura_Vector_3			xNearestPoint = Asura_Maths::ZeroVector3;
				const Asura_Vector_3&	xHumanPos = pxHuman->GetPosition();

				Asura_Maths::GetNearestPointOnLineSegment( xStart, xEnd, pxHuman->GetPosition(), xNearestPoint );

				float fDistanceSq = ( xHumanPos - xNearestPoint ).MagnitudeSquared();
				float fDistFromStartsq = ( xHumanPos - xStart ).MagnitudeSquared();

				if ( fDistanceSq < 2.5f && fDistFromStartsq > 4.0f )
				{
					return true;
				}
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: DoWeHitFriendlyBeforeEnemy
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::IsWeaponPositionInsideFriendlyBoundingBox(const Asura_Vector_3& xTestPos)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	// Iterate through all humans
	for (Asura_Hashed_List_It<AVP_ServerActor_Human> xNodeIter(AVP_ServerActor_Human::GetList()); !xNodeIter.Done(); xNodeIter.Next())
	{
		AVP_ServerActor_Human* pxHuman = xNodeIter.GetCurrent();

		if ( pxHuman && ( pxHuman != pxOurActor ) )
		{
			if (!pxHuman->IsDead() && pxHuman->IsEntityActive())
			{
				if (pxHuman->GetPhysicsObject())
				{
					if (pxHuman->GetPhysicsObject()->GetBoundingBox().Contains(xTestPos))
					{
						return true;
					}
				}
			}
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: DoWeHitFriendlyBeforeEnemy
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::DoWeHitThreat(const Asura_Vector_3& xOrigin, const Asura_Vector_3& xDirection, const AVP_ServerEntity_Actor* pxThreat)
{
	if (!pxThreat || pxThreat->IsDead())
	{
		// Threat is invalid just return true
		return false;
	}

	// Need a best distance variable initialise to LargeFloat
	float fBestDistance = Asura_Maths::LargeFloat;

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

		//  Validate pointer // Don't include our actor
		if ((!pxHuman) || (pxHuman == GetMarineBrain()->GetHumanActor()) || (!pxHuman->IsEntityActive()) || (pxHuman->IsDead()))
		{
			continue;
		}

		Asura_Bounding_Box		xBoundingBox;
		float					fDistance		= 0.0f;

		// If the actor is the player we do not have a server side physics object, -
		// so get the client side one, as we can guarantee if this is the server we will have a client.
		if (pxHuman->IsPlayer())
		{
			AVP_ClientActor_Human* pxClientHuman = AVP_ClientActor_Human::FindEntity(pxHuman->GetGuid());

			Asura_Assert(pxClientHuman->GetPhysicsObject(), "AVP_Behaviour_Marine_Weapon::DoWeHitFriendlyBeforeEnemy - Can't find physics object for Player's Marine!");

			xBoundingBox = pxClientHuman->GetPhysicsObject()->GetBoundingBox();
		}
		else
		{
			Asura_Assert(pxHuman->GetPhysicsObject(), "AVP_Behaviour_Marine_Weapon::DoWeHitFriendlyBeforeEnemy - Can't find physics object for Server Actor Marine!");

			xBoundingBox = pxHuman->GetPhysicsObject()->GetBoundingBox();
		}

		// Make the humans bounding box bigger
		xBoundingBox.Grow(0.15f);

		// Test to see if we hit the humans larger bounding box
		if (Asura_Maths::RayIntersectsBoundingBox(xOrigin, xDirection, xBoundingBox, &fDistance))
		{
			// We have hit note the distance and compare
			if (fDistance < fBestDistance)
			{
				fBestDistance = fDistance;
			}
		}
	}

	// Now do the threat
	Asura_Bounding_Box	xBoundingBox;
	float				fDistance		= 0.0f;

	// If the threat actor is the player we do not have a server side physics object, -
	// so get the client side one, as we can guarantee if this is the server we will have a client.
	if (pxThreat->IsPlayer())
	{
		AVP_ClientEntity_Actor* pxClientThreat = AVP_ClientEntity_Actor::FindEntity(pxThreat->GetGuid());

		Asura_Assert(pxClientThreat->GetPhysicsObject(), "AVP_Behaviour_Marine_Weapon::DoWeHitFriendlyBeforeEnemy - Can't find physics object for Player's Threat Actor!");

		xBoundingBox = pxClientThreat->GetPhysicsObject()->GetBoundingBox();
	}
	else
	{
		Asura_Assert(pxThreat->GetPhysicsObject(), "AVP_Behaviour_Marine_Weapon::DoWeHitFriendlyBeforeEnemy - Can't find physics object for Server Threat Actor!");

		xBoundingBox = pxThreat->GetPhysicsObject()->GetBoundingBox();
	}

	// Test to see if we hit the threats bounding box, but don't make this one bigger.
	if (Asura_Maths::RayIntersectsBoundingBox(xOrigin, xDirection, xBoundingBox, &fDistance))
	{
		// Compare the distance to hit the threat, if its closer than the closest hit on a human then return false
		if (fDistance < fBestDistance)
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: testShoot
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::TestShoot(void)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_Inventory_System*		pxInventorySystem	= pxOurActor->GetInventorySystem();
		AVP_InventoryItem_Weapon*	pxCurrentWeapon		= static_cast<AVP_InventoryItem_Weapon*>(pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

		if (pxCurrentWeapon != NULL)
		{
			Asura_Vector_3		xTargetPos = Asura_Maths::ZeroVector3;
			Asura_Matrix_3x3	xTargetOri;

			GetWeaponMuzzlePositionAndOrientation(&xTargetPos, &xTargetOri);

			const Asura_Vector_3& xFwd = Asura_Vector_3(xTargetOri.e13, xTargetOri.e23, xTargetOri.e33);

			xTargetPos += xFwd;
//			pxCurrentWeapon->SetTargetPosition(xTargetPos);

			if (pxCurrentWeapon->IsIdling(true))
			{
				pxCurrentWeapon->RequestBeginUsage(AVP_InventoryWeapon_RangedWeapon::UT_FULL_AUTO_PRIMARY);
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: SupportShoot
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::SupportShoot( void )
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_ClientEntity_Actor* pxOurClientActor = AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());

		if (pxOurClientActor)
		{
			AVP_Inventory_System*		pxInventorySystem	= pxOurActor->GetInventorySystem();
			AVP_InventoryItem_Weapon*	pxCurrentWeapon		= static_cast< AVP_InventoryItem_Weapon* >( pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

			if (pxCurrentWeapon != NULL)
			{
				AVP_RangedWeapon_SubType* pxSubType = static_cast<AVP_RangedWeapon_SubType*>( pxCurrentWeapon->GetSubType( 0 ) );

				if ( pxSubType->GetCurrentQuantity() > 0 )
				{
					if ( pxCurrentWeapon->IsIdling( true ) )
					{
						if ( GetMarineBrain()->GetCurrentWeaponType() == AVP_WEAPON_BEHAVIOUR_TYPE_FLAMETHROWER )
						{
							pxCurrentWeapon->RequestBeginUsage( AVP_InventoryWeapon_RangedWeapon::UT_FULL_AUTO_PRIMARY );

							m_fStoppedFiringTimer = Asura_Random::GetFloat( pxSubType->GetBurstFireAIMinGap(), pxSubType->GetBurstFireAIMaxGap() );
							m_fFiringTimer = 0.0f;
							m_fFlameTimeout = Asura_Random::GetFloat( pxSubType->GetMinAIFireTime(), pxSubType->GetMaxAIFireTime() );
						}
						else
						{
							pxCurrentWeapon->RequestBeginUsage( AVP_InventoryWeapon_RangedWeapon::UT_N_BULLET_BURST_PRIMARY );

							m_fStoppedFiringTimer = Asura_Random::GetFloat( pxSubType->GetBurstFireAIMinGap(), pxSubType->GetBurstFireAIMaxGap() );
							m_fFiringTimer = 0.0f;
						}
					}
				}
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: Shoot
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::Shoot(void)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_ClientEntity_Actor* pxOurClientActor = AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());

		if (pxOurClientActor)
		{
			AVP_Inventory_System*		pxInventorySystem	= pxOurActor->GetInventorySystem();
			AVP_InventoryItem_Weapon*	pxCurrentWeapon		= static_cast<AVP_InventoryItem_Weapon*>(pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

			if (pxCurrentWeapon != NULL)
			{
				if ( !GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() || ( GetMarineBrain()->GetKnowledgeSystem()->ShootAtScriptedTarget() && !GetMarineBrain()->GetKnowledgeSystem()->ScriptedTargetIsShootAtPoint() ) )
				{
					AVP_ServerEntity_Actor* pxTargetActor = AVP_ServerEntity_Actor::FindEntity(m_uEnemyGuid);

					// Emergency fix (AN 18/02/08)
					if( !pxTargetActor )
					{
						return;
					}
				}

				if (pxCurrentWeapon->GetSubType(0)->GetCurrentQuantity() > 0)
				{
					if (pxCurrentWeapon->IsIdling(true))
					{
						pxCurrentWeapon->RequestBeginUsage(AVP_InventoryWeapon_RangedWeapon::UT_FULL_AUTO_PRIMARY);
						m_fFiringTimer = Asura_Random::GetFloat(dbg_fMinFireTime, dbg_fMaxFireTime);
					}
				}
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: StopShooting
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::StopShooting(void)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_ClientEntity_Actor* pxOurClientActor = AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());

		if (pxOurClientActor)
		{
			AVP_Inventory_System*	pxInventorySystem	= pxOurActor->GetInventorySystem();
			AVP_Inventory_Item*		pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

			if ((pxCurrentWeapon != NULL) && pxCurrentWeapon->IsUsing(true) && ( pxCurrentWeapon->GetCurrentUsageType() == AVP_InventoryWeapon_RangedWeapon::UT_FULL_AUTO_PRIMARY || pxCurrentWeapon->GetCurrentUsageType() == AVP_InventoryWeapon_RangedWeapon::UT_N_BULLET_BURST_PRIMARY ) )
			{
				pxCurrentWeapon->RequestEndUsage();
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: FireGrenade
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::FireGrenade(void)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		AVP_ClientEntity_Actor* pxOurClientActor = AVP_ClientEntity_Actor::FindEntity(pxOurActor->GetGuid());

		if (pxOurClientActor)
		{
			AVP_Inventory_System*	pxInventorySystem	= pxOurActor->GetInventorySystem();
			AVP_Inventory_Item*		pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

			if((pxCurrentWeapon != NULL) && pxCurrentWeapon->IsIdling(true))
			{
				pxCurrentWeapon->RequestBeginUsage(AVP_InventoryWeapon_RangedWeapon::UT_FULL_AUTO_PRIMARY);
				
			}
		}
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: CheckForReload
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::CheckForReload(float fAmountToReloadOn)
{
	AVP_ServerActor_Human* pxOurActor = GetMarineBrain()->GetHumanActor();

	if (pxOurActor)
	{
		if ((GetWeaponAmmo() > 0.0f) && (GetWeaponAmmo() <= fAmountToReloadOn))
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: IsWeaponPulseRifle
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::IsWeaponPulseRifle(void)
{
	AVP_ServerActor_Human* pxHuman = GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		const AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		const Asura_Hash_ID			uCurrentWeaponHash	= pxInventorySystem ? pxInventorySystem->GetCurrentItemID(uAVP_INVENTORY_GROUPHASH_WEAPON) : ASURA_HASH_ID_UNSET;

		if(uCurrentWeaponHash == uAVP_INVENTORY_WEAPONHASH_WEAPON01)
		{
			return true;
		}
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: GetWeaponsMaxRange
//---------------------------------------------------------------------------
float AVP_Behaviour_Marine_Weapon::GetWeaponsMaxRange(void)
{
	AVP_ServerActor_Human* pxHuman = GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		const AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		const AVP_Inventory_Item*	pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

		if (pxCurrentWeapon != NULL)
		{
			const AVP_RangedWeapon_SubType*	pxSubType	= static_cast<const AVP_RangedWeapon_SubType*>(pxCurrentWeapon->GetSubType(0));

			if (pxSubType != NULL)
			{
				return(pxSubType->GetMaxRange());
			}
		}
	}

	return 1.0f;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: GetWeaponRateOfFire
//---------------------------------------------------------------------------
float AVP_Behaviour_Marine_Weapon::GetWeaponRateOfFire()
{
	AVP_ServerActor_Human* pxHuman = GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		const AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		const AVP_Inventory_Item*	pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

		if (pxCurrentWeapon != NULL)
		{
			const AVP_RangedWeapon_SubType*	pxSubType	= static_cast<const AVP_RangedWeapon_SubType*>(pxCurrentWeapon->GetSubType(0));

			if (pxSubType != NULL)
			{
				return(pxSubType->GetRateOfFire());
			}
		}
	}

	return 1.0f;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: GetWeaponAmmo
//---------------------------------------------------------------------------
float AVP_Behaviour_Marine_Weapon::GetWeaponAmmo(void)
{
	const AVP_ServerActor_Human*	pxHuman	= GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		const AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		const AVP_Inventory_Item*	pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

		if (pxCurrentWeapon != NULL)
		{
			const AVP_InventoryItem_SubType* pxSubType = pxCurrentWeapon->GetSubType(0);

			if (pxSubType != NULL)
			{
				return pxSubType->GetCurrentQuantity();
			}
		}
	}

	return 0.0f;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: GetWeaponAmmo
//---------------------------------------------------------------------------
float AVP_Behaviour_Marine_Weapon::GetWeaponClipSize(void)
{
	const AVP_ServerActor_Human*	pxHuman	= GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		const AVP_Inventory_System*	pxInventorySystem	= pxHuman->GetInventorySystem();
		const AVP_Inventory_Item*	pxCurrentWeapon		= pxInventorySystem ? pxInventorySystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL;

		if (pxCurrentWeapon != NULL)
		{
			const AVP_InventoryItem_SubType* pxSubType = pxCurrentWeapon->GetSubType(0);

			if (pxSubType != NULL)
			{
				return pxSubType->GetMaxQuantity();
			}
		}
	}

	return 0.0f;
}



//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: GetWeaponMuzzlePositionAndOrientation
//---------------------------------------------------------------------------
bool AVP_Behaviour_Marine_Weapon::GetWeaponMuzzlePositionAndOrientation(Asura_Vector_3* xPosition, Asura_Matrix_3x3* xOrientation)
{
	AVP_ServerActor_Human* pxHuman = GetMarineBrain()->GetHumanActor();

	if (pxHuman)
	{
		return pxHuman->GetWorldSpaceMarkerPoint(0x0001A7D2, xPosition, xOrientation); // Asura_GetHashID("muz")
	}

	return false;
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: PlayAttackingDialogue
//---------------------------------------------------------------------------
void AVP_Behaviour_Marine_Weapon::PlayAttackingDialogue(const float fTimeslice)
{
	if (m_fDialogueTimer > 10.0f)
	{
		AVP_ServerActor_Human* pxHuman = GetMarineBrain()->GetHumanActor();

		if (pxHuman->GetInitialSquadGuid() != ASURA_GUID_UNREGISTERED)
		{
			AVP_ServerEntity_Squad_Marine* pxSquad = AVP_ServerEntity_Squad_Marine::FindEntity(pxHuman->GetInitialSquadGuid());

			if (pxSquad)
			{
				if (pxSquad->GetNumSquadMembers() > 0)
				{
					if ((Asura_Random::GetFloat(0.0f, 1.0f) > 0.98f) && (Asura_Random::GetFloat(0.0f, 1.0f) > 0.75f))
					{
						GetMarineBrain()->GetHumanActor()->PlayDialogue(AVP_ServerActor_Human::AVP_DLG_HUMAN_ATTACKING);
					}

					m_fDialogueTimer = 0.0f;
					return;
				}
			}
		}

		if ((Asura_Random::GetFloat(0.0f, 1.0f) > 0.98f) && (Asura_Random::GetFloat(0.0f, 1.0f) > 0.75f))
		{
			GetMarineBrain()->GetHumanActor()->PlayDialogue(AVP_ServerActor_Human::AVP_DLG_HUMAN_ATTACKING);
		}

		m_fDialogueTimer = 0.0f;
	}
}

//---------------------------------------------------------------------------
// AVP_Behaviour_Marine_Weapon :: RenderDebugInfo
//---------------------------------------------------------------------------
#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[AVP_Behaviour_Marine_Weapon::MAX_STATES] =
{
	"WEAPON - UNSET",
	"WEAPON - IDLE",
	"WEAPON - RELOADING",
	"WEAPON - TRYING TO FIRE",
	"WEAPON - SUPPORT IDLE",
	"WEAPON - SUPPORT FIRE",
};

static bool g_bDrawGunDirection = false;
static bool g_bRenderGunInfo = false;

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

	if (GetMarineBrain()->GetTacticalSystem()->IsPerformingAction())
	{
		return;
	}

	if ( m_fStoppedFiringTimer >= 0.0f )
	{
		Asura_Font_System::Print
		(
			GetProjectBrain()->GetDebugOutputPos().x,
			GetProjectBrain()->GetDebugOutputPos().y,
			0.5f, 
			0xffffffff,
			ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, 
			"FT : %.2f", m_fStoppedFiringTimer
		);

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


#ifdef _DEBUG

	if (g_bRenderGunInfo)
	{
		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;

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

		if (pxOurActor)
		{
			const Asura_Guid				uActorGuid			= pxOurActor->GetGuid();
			const AVP_ClientActor_Human*	pxClient			= AVP_ClientActor_Human::FindEntity(uActorGuid);
			const AVP_Inventory_System*		pxClientSystem		= (pxClient == NULL) ? NULL : pxClient->GetInventorySystem();
			const AVP_InventoryItem_Weapon*	pxClientWeapon		= static_cast<const AVP_InventoryItem_Weapon*>(pxClientSystem ? pxClientSystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

			const AVP_Inventory_System*		pxServerSystem		= pxOurActor->GetInventorySystem();
			const AVP_InventoryItem_Weapon*	pxServerWeapon		= static_cast<const AVP_InventoryItem_Weapon*>(pxServerSystem ? pxServerSystem->GetCurrentItem(uAVP_INVENTORY_GROUPHASH_WEAPON) : NULL);

			if(pxClientWeapon != NULL)
			{
				Asura_Char	szClientTemp[256]	= "CLNT: ";

				pxClientWeapon->CreateDebugString(250, &szClientTemp[6]);

				Asura_Font_System::Print
				(
					GetProjectBrain()->GetDebugOutputPos().x,
					GetProjectBrain()->GetDebugOutputPos().y,
					0.5f, 
					AVP_Brain_Actor_Marine::s_uPermentantChildDebugColour,
					ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, 
					szClientTemp
				);

				GetProjectBrain()->GetDebugOutputPos().y += 10.0f;
			}

			if(pxServerWeapon != NULL)
			{
				Asura_Char	szServerTemp[256]	= "SRVR: ";

				pxServerWeapon->CreateDebugString(250, &szServerTemp[6]);

				Asura_Font_System::Print
				(
					GetProjectBrain()->GetDebugOutputPos().x,
					GetProjectBrain()->GetDebugOutputPos().y,
					0.5f, 
					AVP_Brain_Actor_Marine::s_uPermentantChildDebugColour,
					ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING, 
					szServerTemp
				);

				GetProjectBrain()->GetDebugOutputPos().y += 10.0f;

				if (g_bDrawGunDirection)
				{
					Asura_Vector_3		xGunPos = Asura_Maths::ZeroVector3;
					Asura_Matrix_3x3	xGunOri;

					// Get the Pulse rifles muzzle marker point
					if (GetWeaponMuzzlePositionAndOrientation(&xGunPos, &xGunOri))
					{
						Asura_Vector_3	xGunFwd	= Asura_Vector_3(xGunOri.e13, xGunOri.e23, xGunOri.e33);
						Asura_Vector_3	xEndPos = xGunPos + (xGunFwd * GetWeaponsMaxRange());

						Asura_DebugLineRender::AddLine(xGunPos, xEndPos, 0xffff00ff);
						Asura_DebugLineRender::AddSphere(xEndPos, 0.05f, 0xffff00ff, 4, 2);
					}
				}
			}
		}
	}
#endif // _DEBUG
}
#endif

/// End Of File 'AVP_behaviour_Marine_Weapon.cpp'
