///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Behaviour_AlienQueen_Movement.cpp
// Author : David Wooldridge
// Date   : 13/11/2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Behaviour/BehaviourTypes/AlienQueen/AVP_Behaviour_AlienQueen_Movement.h"

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

#include "Entity/Locations/OrientedNode/GamesceneNode/Asura_ServerNode_GS2Node.h"
#include "Entity/PhysicalObject/Moves/Asura_Movement_System.h"

// axon
#include "Behaviour/BehaviourTypes/AVP_Behaviour_Types.h"
#include "Core/BrainTypes/AVP_Brain_Actor_AlienQueen.h"

#include "Actor/AVP_Actor_AnimStateData.h"
#include "Actor/Vertebrates/AlienQueen/AVP_AlienQueen_AIAnimStateData.h"
#include "Actor/Vertebrates/AlienQueen/AVP_AlienQueen_AIAnimStateMachine.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_ServerActor_AlienQueen.h"

//avp
#include "Actor/Vertebrates/AlienQueen/AVP_AlienQueen_MeleeCounter_System.h"
#include "Moves/Vertebrates/AlienQueen/AVP_AlienQueen_MovesMelee.h"
#include "Moves/Vertebrates/Human/AVP_Human_MovesGamescene.h"

AVP_Behaviour_AlienQueen_Movement::AVP_Behaviour_AlienQueen_Movement( AVP_Brain_Actor* pxBrain )
: PARENT( pxBrain, AVP_BEHAVIOUR_TYPE_ALIENQUEEN_MOVEMENT )
, m_eCurrentState( UNSET )
, m_fTimeInState( 0.0f )
, m_fArrivalRange( 3.5f )
, m_xPrevPositionOnRoute( Asura_Maths::ZeroVector3 )
, m_fSmoothedPORVelocity( 0.0f )
, m_xPositionOnRoute( Asura_Maths::ZeroVector3 )
, m_xFollowPoint( Asura_Maths::ZeroVector3 )
, m_uGS2NodeGuid( ASURA_GUID_UNREGISTERED )
{
}

void AVP_Behaviour_AlienQueen_Movement::SetDestinationGS2NodeGuid( Asura_Guid uGS2NodeGuid )
{
	m_uGS2NodeGuid = uGS2NodeGuid;
}

bool AVP_Behaviour_AlienQueen_Movement::GetToPosition(const Asura_Vector_3& xDestination, MovementMode m_eMovementMode /*= AVP_Navigation::MM_MEDIUM*/, bool bOverrideMovementMode /*= false*/)
{
	SetInError( false );
	SetFinished( false );

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

	if (bOverrideMovementMode)
	{
		xNavData.m_eMovementMode = m_eMovementMode;
	}

	xNavData.m_xStartPosition       = GetAlienQueenBrain()->GetActor()->GetPosition();
	xNavData.m_xDestinationPosition = xDestination;
	// Our current waypoint ID should already be up to date, as we keep it up to date when moving.
	// Update our destination waypoint ID.
	const AVP_Navigation::TestParams xTestParams( xNavData.m_uPathfinderFlags, xNavData.m_usCurrentZone );
	if ( !AVP_Navigation::GetNearestWaypointID( xDestination, xNavData.m_usDestinationWPID, xTestParams ) )
	{
		SetInError();
		SwitchToState( FINISHED );
		return false;
	}

	if ( ( xNavData.m_xStartPosition - xNavData.m_xDestinationPosition ).MagnitudeSquared() < m_fArrivalRange * m_fArrivalRange )
	{
		// If we're already near enough the destination then there's nothing to do.
		SwitchToState( FINISHED );
	}
	else
	{
		// Clear out the old route and find the new one.
		xNavData.ResetRoute();

		AVP_Navigation::AlienQueenAStarFunctor xMoveFunctor;
		if ( !AVP_Navigation::FindRoute( xNavData, &xMoveFunctor  ) )
		{
			SetInError();
			SwitchToState( FINISHED );
			return false;
		}

		m_xPrevPositionOnRoute = Asura_AI_Navigation_System::GetWaypoint( xNavData.m_pusRoute[ 0 ] )->m_xPosition;
		m_fSmoothedPORVelocity = 5.0f;

		SwitchToState( TRAVERSING_STANDARD_LINK );
	}

	return true;
}

bool AVP_Behaviour_AlienQueen_Movement::Activate()
{
#ifndef ASURA_NO_DEBUG_OUTPUT
	GetAlienQueenBrain()->SetRenderRoute( true );
#endif

	return PARENT::Activate();
}

void AVP_Behaviour_AlienQueen_Movement::Deactivate()
{
	// If the brain is not active this indicates we're shutting down. We don't access the actor/etc if this is the case
	// as the virtual table is unlikely to be valid any more.
//	if ( GetAlienQueenBrain()->IsActive() )
//	{
//		GetAlienQueenBrain()->GetActor()->GetAIAnimStateMachine()->RequestIdle();
//	}

#ifndef ASURA_NO_DEBUG_OUTPUT
	GetAlienQueenBrain()->SetRenderRoute( false );
#endif

	PARENT::Deactivate();
}

void AVP_Behaviour_AlienQueen_Movement::Update( const float fTimeslice )
{
	PARENT::Update( fTimeslice );

	switch ( m_eCurrentState )
	{
		////////////////////
		case TRAVERSING_STANDARD_LINK:
		case MOVING_TO_DESTINATION:
		case FINISHED:
		////////////////////
		{
			break;
		}

		////////////////////
		case UNSET:
		case NUM_STATES:
		default:
		////////////////////
		{
			Asura_Assert( false, "AVP_Behaviour_AlienQueen_Movement::PerFrameUpdate - bad state" );
			SetInError();
			SetFinished();
			break;
		}
	}
}

void AVP_Behaviour_AlienQueen_Movement::PerFrameUpdate( const float fTimeslice )
{
	PARENT::PerFrameUpdate( fTimeslice );

	m_fTimeInState += fTimeslice;

	if ( IsInError() || IsFinished() )
	{
		return;
	}

	UpdatePositionOnRoute();
	UpdateMovementSpeed();
	UpdateStuckDetection( fTimeslice );

	switch ( m_eCurrentState )
	{
		////////////////////
		case TRAVERSING_STANDARD_LINK:
		////////////////////
		{
			// If we're on the last link of our route and in our last waypoint then head towards our destination.
			AVP_Navigation::NavData& xNavData = GetAlienQueenBrain()->GetNavData();
			if (AVP_Navigation::IsRouteBlocked(xNavData) )
			{
				SetInError(true);
				SwitchToState(FINISHED);
				return;
			}

			if ( ( xNavData.m_usRouteLength == 1 || xNavData.m_usRouteSegmentIndex == xNavData.m_usRouteLength - 2 ) &&
				xNavData.m_usCurrentWPID == xNavData.m_usDestinationWPID )
			{
				// if we are near the end then change state. 
				SwitchToState( MOVING_TO_DESTINATION );
			}
			else
			{
				if ( ! UpdateFollowPoint() )
				{
					// if the follow point is in the waypoint we are going to change state. 
					SwitchToState( MOVING_TO_DESTINATION );
				}

				Asura_Vector_3 xToFollowPoint = m_xFollowPoint - GetAlienQueenBrain()->GetActor()->GetPosition();
				xToFollowPoint.Normalise();

				if ( m_uGS2NodeGuid != ASURA_GUID_UNREGISTERED )
				{
					// if we are in a GS2 procedure
					Asura_ServerNode_GS2Node* pxGS2Node = Asura_ServerNode_GS2Node::FindEntity( m_uGS2NodeGuid );
					AVP_ServerActor_AlienQueen* pxQueen = (AVP_ServerActor_AlienQueen*)GetAlienQueenBrain()->GetActor();

					if ( pxGS2Node && pxQueen )
					{
						float fDistanceSq = ( pxGS2Node->GetPosition() - pxQueen->GetPosition() ).MagnitudeSquared();

						if ( fDistanceSq < 2.0f )
						{
							SwitchToState( MOVING_TO_DESTINATION );
							return;
						}
						
						if( GetAlienQueenBrain()->GetLookAtGuid() != ASURA_GUID_UNREGISTERED )
						{
							// if we have an entity we have to look at look at it
							GetAlienQueenBrain()->LookAtEntityFromMsgData();
						}
						else
						{
							// else look at the destination we are moving towards. 
							if ( fDistanceSq < 16.0f )
							{
								Asura_Matrix_3x3 xOri; pxGS2Node->GetOrientation(xOri);
								GetAlienQueenBrain()->SetAimDirection( Asura_Vector_3( xOri.e13, xOri.e23, xOri.e33 ) );
							}
							else
							{
								GetAlienQueenBrain()->SetLookAtPosition(m_xFollowPoint);
								GetAlienQueenBrain()->SetAimDirection(xToFollowPoint);
							}
						}
					}
				}
				else
				{
					// if we are not headed towards a GS2 node then just update the aim data and continue. 

					// dont update the aim and look directions if we are still finishing a move, if we are finishing an animation for it then the head can look in the wrong place. 
					if( ! IsQueenPerformingMeleeMove () )
					{
						if( GetAlienQueenBrain()->GetLookAtGuid() != ASURA_GUID_UNREGISTERED )
						{
							// if we have an entity we have to look at look at it
							GetAlienQueenBrain()->LookAtEntityFromMsgData();
						}
						else
						{
							// else make sure we are looking at our primary target or the direction we are going. 
							if( IsTargetInFrontOfQueen() )
							{
								// if the target is in front of the queen then make her look at it, not the direction she is going in. 

								// find the direction from the queen to the target (Target Pos - Queen Pos) and normalise. 
								Asura_Vector_3 xAimDirection = GetAlienQueenBrain()->GetTargetKnowledge()->m_xPosition - GetAlienQueenBrain()->GetActor()->GetPosition();
								xAimDirection.Normalise();
						
								GetAlienQueenBrain()->SetLookAtPosition( GetAlienQueenBrain()->GetTargetKnowledge()->m_xPosition );
								GetAlienQueenBrain()->SetAimDirection( xAimDirection );
							}
							else
							{
								GetAlienQueenBrain()->SetLookAtPosition( m_xFollowPoint );
								GetAlienQueenBrain()->SetAimDirection( xToFollowPoint );
							}
						}
					}
				}

				GetAlienQueenBrain()->SetMovementDirection( xToFollowPoint );
			}
			break;
		}
		////////////////////
		case MOVING_TO_DESTINATION:
		////////////////////
		{
			AVP_Navigation::NavData& xNavData = GetAlienQueenBrain()->GetNavData();

			Asura_Vector_3 xToDestination = xNavData.m_xDestinationPosition - GetAlienQueenBrain()->GetActor()->GetPosition();
			xToDestination.Normalise();

			if ( m_uGS2NodeGuid != ASURA_GUID_UNREGISTERED )
			{
				// if we are headed towards a GS2 node then we need to worry more about our orientaiton. 
				Asura_ServerNode_GS2Node* pxGS2Node = Asura_ServerNode_GS2Node::FindEntity( m_uGS2NodeGuid );
				AVP_ServerActor_AlienQueen* pxQueen = ( AVP_ServerActor_AlienQueen* )GetAlienQueenBrain()->GetActor();

				if ( pxGS2Node && pxQueen )
				{
					float fDistanceSq = ( pxGS2Node->GetPosition() - pxQueen->GetPosition() ).MagnitudeSquared();

					if ( fDistanceSq < 2.0f )
					{
						// If we've arrived we're done.
						AVP_Navigation::APParams xAPParams;
						xAPParams.m_fMaxCoplanarOffset = m_fArrivalRange;
						if ( AVP_Navigation::AtPosition( GetAlienQueenBrain()->GetActor()->GetPosition(), xNavData.m_xDestinationPosition, xAPParams ) )
						{
							SwitchToState( FINISHED );
						}
					}
					//else if ( fDistanceSq < 16.0f )
					//{
					//	// if we are within a certain range of the node we are headed to then start turning towards the orientaiton of it early. 
					//	Asura_Matrix_3x3 xOri; pxGS2Node->GetOrientation(xOri);
					//	GetAlienQueenBrain()->SetAimDirection( Asura_Vector_3( xOri.e13, xOri.e23, xOri.e33 ) );
					//}
					else
					{
						if( GetAlienQueenBrain()->GetLookAtGuid() != ASURA_GUID_UNREGISTERED )
						{
							// if we have an entity we have to look at look at it
							GetAlienQueenBrain()->LookAtEntityFromMsgData();
						}
						else
						{
							GetAlienQueenBrain()->SetAimDirection( xToDestination );
						}
						
					}
				}
			}
			else
			{
				// dont update the aim and look directions if we are still finishing a move, if we are finishing an animation for it then the head can look in the wrong place. 
				if( ! IsQueenPerformingMeleeMove () )
				{
					if( GetAlienQueenBrain()->GetLookAtGuid() != ASURA_GUID_UNREGISTERED )
					{
						// if we have an entity we have to look at look at it
						GetAlienQueenBrain()->LookAtEntityFromMsgData();
					}
					else
					{
						if( IsTargetInFrontOfQueen() )
						{
							// if the target is in front of the queen then make her look at it, not the direction she is going in. 

							// find the direction from the queen to the target (Target Pos - Queen Pos) and normalise. 
							Asura_Vector_3 xAimDirection = GetAlienQueenBrain()->GetTargetKnowledge()->m_xPosition - GetAlienQueenBrain()->GetActor()->GetPosition();
							xAimDirection.Normalise();

							GetAlienQueenBrain()->SetLookAtPosition( GetAlienQueenBrain()->GetTargetKnowledge()->m_xPosition );
							GetAlienQueenBrain()->SetAimDirection( xAimDirection );
						}
						else
						{
							GetAlienQueenBrain()->SetLookAtPosition( xNavData.m_xDestinationPosition );
							GetAlienQueenBrain()->SetAimDirection( xToDestination );
						}
					}
				}
				
				// If we've arrived we're done.
				AVP_Navigation::APParams xAPParams;
				xAPParams.m_fMaxCoplanarOffset = m_fArrivalRange;
				if ( AVP_Navigation::AtPosition( GetAlienQueenBrain()->GetActor()->GetPosition(), xNavData.m_xDestinationPosition, xAPParams ) )
				{
					SwitchToState( FINISHED );
				}
			}

			GetAlienQueenBrain()->SetMovementDirection( xToDestination );

			break;
		}
		////////////////////
		case FINISHED:
		////////////////////
		{
			break;
		}
		////////////////////
		case UNSET:
		case NUM_STATES:
		default:
		////////////////////
		{
			Asura_Assert( false, "AVP_Behaviour_Human_Movement::PerFrameUpdate - bad state" );
			SetInError();
			SetFinished();
			break;
		}
	}
}

#ifndef ASURA_NO_DEBUG_OUTPUT
static const char* s_aszStateStrings[] =
{
	"MOVEMENT - UNSET",	
	"MOVEMENT - TRAVERSING STANDARD LINK",
	"MOVEMENT - MOVING TO DESTINATION",
	"MOVEMENT - FINISHED"
};

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

	Asura_Font_System::Print
		(
		GetProjectBrain()->GetDebugOutputPos().x,
		GetProjectBrain()->GetDebugOutputPos().y,
		0.5f,
		0xffffffff,
		ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING,
		"%s", s_aszStateStrings[ m_eCurrentState ]
	);

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

	Asura_Font_System::Print
		(
		GetProjectBrain()->GetDebugOutputPos().x,
		GetProjectBrain()->GetDebugOutputPos().y,
		0.5f,
		0xffffffff,
		ASURA_TEXTFORMAT_CENTREJUSTIFIED | ASURA_TEXTFORMAT_FORMATSTRING,
		"smoothed por vel: %f", m_fSmoothedPORVelocity
		);

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

	if (m_xFollowPoint != Asura_Maths::ZeroVector3)
	{
		Asura_Vector_3 xOutputPos( m_xFollowPoint );

		if (Asura_Camera::ProjectWorldCoordsToScreenSpace(xOutputPos, true) || xOutputPos.z > 0.0f)
		{
			Asura_DebugLineRender::AddSphere(m_xFollowPoint, 0.5f, 0xffffff00, 3, 2);
			Asura_Font_System::Print(xOutputPos.x, xOutputPos.y, 0.5f, 0xffffff00, ASURA_TEXTFORMAT_CENTREJUSTIFIED, "Follow Point");
		}
	}
}
#endif

AVP_Brain_Actor_AlienQueen* AVP_Behaviour_AlienQueen_Movement::GetAlienQueenBrain() const
{
	return static_cast< AVP_Brain_Actor_AlienQueen* >( GetProjectBrain() );
}

void AVP_Behaviour_AlienQueen_Movement::SwitchToState( const State eNextState )
{
	// Do any work we need to exit our current state.
	switch ( m_eCurrentState )
	{
		////////////////////
		case TRAVERSING_STANDARD_LINK:
		case MOVING_TO_DESTINATION:
		case UNSET:
		case FINISHED:
		case NUM_STATES:
		default:
		////////////////////
		{
			break;
		}
	}

	// Do any work we need to change into our next state.
	m_eCurrentState = eNextState;
	m_fTimeInState  = 0.0f;
	switch ( m_eCurrentState )
	{
		////////////////////
		case FINISHED:
		////////////////////
		{
			// CAH commented out to stop the glitches in the animations on arrival to destination. 
			// rely on the next behaviour requesting what it needs. 
			//GetAlienQueenBrain()->GetActor()->GetAIAnimStateMachine()->RequestIdle();

			SetFinished();
			break;
		}
		////////////////////
		case UNSET:
		case MOVING_TO_DESTINATION:
		case TRAVERSING_STANDARD_LINK:
		case NUM_STATES:
		default:
		////////////////////
		{
			break;
		}
	}
}

bool AVP_Behaviour_AlienQueen_Movement::HandleMessage( const Asura_Message* pxMessage )
{
	switch ( pxMessage->GetMsgID() )
	{
		////////////////////
		case ASURA_MSG_MOVECHAINCOMPLETE:
		////////////////////
		{
			const Asura_Msg_MoveChainComplete* pxData = static_cast< const Asura_Msg_MoveChainComplete* >( pxMessage->GetData() );

			if ( pxData && pxData->GetInitialMoveID() == AVP_Move_Human_MountGamescene::GetStaticHash() )
			{
				SwitchToState( FINISHED );
			}

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

bool AVP_Behaviour_AlienQueen_Movement::UpdateFollowPoint()
{
	const AVP_Navigation::NavData&	xNavData				= GetAlienQueenBrain()->GetNavData();
	const Asura_Vector_3&			xCurrentPosition		= GetAlienQueenBrain()->GetActor()->GetPosition();
	u_short							usNearestRouteIndex;

	AVP_Navigation::FindNearestPointOnRoute( GetAlienQueenBrain()->GetNavData(), xCurrentPosition, 2.5f, m_xFollowPoint, usNearestRouteIndex );

	if( usNearestRouteIndex == ( xNavData.m_usRouteLength - 2 ) )
	{
		if( Asura_AI_Navigation_System::IsPositionInWaypoint( m_xFollowPoint, xNavData.m_pusRoute[usNearestRouteIndex + 1] ) )
		{
			return false;
		}
	}

	return true;
}

void AVP_Behaviour_AlienQueen_Movement::UpdatePositionOnRoute()
{
	AVP_Navigation::NavData& xNavData = GetAlienQueenBrain()->GetNavData();

	m_xPrevPositionOnRoute = m_xPositionOnRoute;
	AVP_Navigation::FindNearestPointOnRoute( xNavData, GetAlienQueenBrain()->GetActor()->GetPosition(), 0.0f, m_xPositionOnRoute, xNavData.m_usRouteSegmentIndex );
	Asura_Assert( xNavData.m_usRouteSegmentIndex < xNavData.m_usRouteLength, "AVP_Behaviour_AlienQueen_Movement::PerFrameUpdate - bug in AVP_Navigation::FindNearestPointOnRoute" );
}

void AVP_Behaviour_AlienQueen_Movement::UpdateMovementSpeed()
{
	switch ( m_eCurrentState )
	{
		////////////////////
		case MOVING_TO_DESTINATION:
		case TRAVERSING_STANDARD_LINK:
		////////////////////
		{
			AVP_Vertebrate_AIAnimStateMachine* pxVertStateMachine = static_cast< AVP_Vertebrate_AIAnimStateMachine* >( GetAlienQueenBrain()->GetActor()->GetAIAnimStateMachine() );
			switch ( GetAlienQueenBrain()->GetNavData().m_eMovementMode )
			{
				////////////////////
				case AVP_Navigation::MM_SLOW:
				////////////////////
				{
					if (!pxVertStateMachine->IsMoveSlow())
					{
						pxVertStateMachine->RequestMoveSlow();
					}
					break;
				}
				////////////////////
				default:
				case AVP_Navigation::MM_MEDIUM:
				////////////////////
				{
					if (!pxVertStateMachine->IsMoveMedium())
					{
						pxVertStateMachine->RequestMoveMedium();
					}
					break;
				}
				////////////////////
				case AVP_Navigation::MM_FAST:
				////////////////////
				{
					if (!pxVertStateMachine->IsMoveFast())
					{
						pxVertStateMachine->RequestMoveFast();
					}
					break;
				}
			} // end switch MovementMode
			break;
		}
		////////////////////
		default:
		////////////////////
		{
			break;
		}
	}
}

void AVP_Behaviour_AlienQueen_Movement::UpdateStuckDetection( const float fTimeslice )
{
	if ( fTimeslice > 0.0f )
	{
		const float fPORVelocity = ( m_xPositionOnRoute - m_xPrevPositionOnRoute ).Magnitude() / fTimeslice;
		m_fSmoothedPORVelocity += ( fPORVelocity - m_fSmoothedPORVelocity ) * 0.5f * fTimeslice;
		
		// We're stuck, tun queen around and set to error / finished. 
		if ( m_fSmoothedPORVelocity < 0.8f )
		{
			// set look direction to the opposite (but same Y)			
			Asura_Vector_3 xTempVec = - ( GetAlienQueenBrain()->GetLookAtPosition() );
			xTempVec.SetY( GetAlienQueenBrain()->GetLookAtPosition().GetY() );

			// same for the aim direction
			xTempVec = - ( GetAlienQueenBrain()->GetAimDirection() );
			xTempVec.SetY( GetAlienQueenBrain()->GetAimDirection().GetY() );

			// set movement direction to opposate
			GetAlienQueenBrain()->SetMovementDirection( - ( GetAlienQueenBrain()->GetMovementDirection() ) );

			// now set the behaviour in error. 
			SetInError();
			SetFinished();
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Behaviour_AlienQueen_Movement::IsTargetInFrontOfQueen
// Scope		: Private
// Author       : Callum Hope
// Date         : 24/3/2009
//
// Desc			: small routein to find if the target is in front if the queen in terms of local space to her. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Behaviour_AlienQueen_Movement::IsTargetInFrontOfQueen()
{
	if ( GetAlienQueenBrain() && GetAlienQueenBrain()->HasCurrentTarget() )
	{
		Asura_Matrix_3x3 xQueenOrientation = GetAlienQueenBrain()->GetActor()->GetOrientation();
		Asura_Vector_3 xQueenDirection = Asura_Vector_3( xQueenOrientation.e13, xQueenOrientation.e23, xQueenOrientation.e33 );
		xQueenDirection.Normalise();

		// now get the direction from the queen to her target. 
		Asura_Vector_3 xAimDirection = GetAlienQueenBrain()->GetTargetKnowledge()->m_xPosition - GetAlienQueenBrain()->GetActor()->GetPosition();
		xAimDirection.Normalise();

		float fDotProduct = xQueenDirection * xAimDirection;

		if( fDotProduct > GetAlienQueenBrain()->GetMaxHeadTurnCosine() )
		{
			return true;
		}
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Behaviour_AlienQueen_Movement::IsQueenPerformingMeleeMove
// Scope		: Private
// Author       : Callum Hope
// Date         : 25/3/2009
//
// Desc			: as the name suggests. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_Behaviour_AlienQueen_Movement::IsQueenPerformingMeleeMove()
{
	if( GetAlienQueenBrain() )
	{
		AVP_ServerActor_AlienQueen *pxQueenServerActor = static_cast<AVP_ServerActor_AlienQueen*>( GetAlienQueenBrain()->GetActor() );
		if( pxQueenServerActor )
		{
			AVP_AlienQueen_MeleeCounter_System *pxQueenMeleeSys = static_cast<AVP_AlienQueen_MeleeCounter_System*>( pxQueenServerActor->GetMeleeSystem() );
			if( pxQueenMeleeSys )
			{
				if( GetAlienQueenBrain()->GetClientActor()->GetMovementSystem()->IsMoveInProgress() )
				{
					// if we have a brain, server actor, melee system and are currently doing a move find its hash value
					int iCount;
					Asura_Hash_ID uCurrentMoveID = GetAlienQueenBrain()->GetClientActor()->GetMovementSystem()->GetCurrentMove()->GetHash();

					for( iCount = NUM_AVP_MELEEATTACK_TYPES; iCount < NUM_AVP_ALIENQUEEN_MELEEATTACK_TYPES; iCount ++ )
					{
						// for every melee move compare its hash to the current move, if we get a match return true
						if( uCurrentMoveID == pxQueenMeleeSys->GetMeleeMoveHashID( iCount ) )
						{
							return true;
						}
					}

					// if we get here then we need to make sure it is not returning from a move as well. 
					if( ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::GetStaticHash() ) 
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_Charge_Collide_Injured::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_Charge_Collide::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_Charge_Into_Idle::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_Stationary_Roar::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Countered::GetStaticHash() )
						|| ( uCurrentMoveID == AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Miss::GetStaticHash() ) )
					{
						return true;
					}
				}
			}
		}
	}
	return false;
}





