
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_AlienQueen_MovesMelee.cpp
// Author : Andy McCabe
// Date   : 19-Nov-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"


// This file's header...
#include "Moves/Vertebrates/AlienQueen/AVP_AlienQueen_MovesMelee.h"

// Asura independent header-files...
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_AnimationAttachment.h"
#include "Animation/Asura_AnimationController_Animation.h"
#include "Blueprint/Asura_Blueprint.h"
#include "Blueprint/Asura_Blueprint_System.h"
#include "Network/Asura_Message.h"
#include "Physics/Asura_Physics_MovementQuery.h"
#include "SpecialFX/PFX/Asura_PFX_Entity_Effect.h"

// Game independent header-files...
#include "Actor/AVP_Actor_AnimationHandler.h"
#include "Actor/AVP_Actor_PhysicsObjectHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_Description.h"
#include "Actor/Vertebrates/AlienQueen/AVP_AlienQueen_MeleeCounter_System.h"
#include "Animation/AVP_AnimFlags.h"
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Camera/AVP_CameraShake_System.h"
#include "Entity/AVP_Messages.h"
#include "Entity/Damage/AVP_EntityDamage_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AVP_Vertebrate_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AlienQueen/AVP_ClientActor_AlienQueen.h"
#include "Mesh/AVP_PolygonFlags.h"

////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////

static const float g_fTweenInDuration = 0.1f;
static const float g_fTweenOutDuration = 0.1f;
static const float g_fLongTweenInDuration = 0.2f;
static const float g_fLongTweenOutDuration = 0.2f;

static const int g_iHitsInCombo = 2;						// number of hits in sucession that warrent a combo
static const float g_fComboDuration = 6.0f;					// the time in which these hits must occur

static const Asura_Hash_ID g_uAIMovesBP = 0xd81414b8;		// Asura_GetHashID( "Moves3rdPerson" )
static const Asura_Hash_ID g_uStunnedStumble = 0xA2FC640F;	// Asura_GetHashID( "StunnedStumble" )

static const Asura_Hash_ID g_uRoarCamShake_Duration = 0xDF96E2CE;	// Asura_GetHashID( "RoarCamShake_Duration" )
static const Asura_Hash_ID g_uRoarCamShake_MaxRange = 0x6FA8E793;	// Asura_GetHashID( "RoarCamShake_MaxRange" )
static const Asura_Hash_ID g_uRoarCamShake_CurveType = 0xA20892AF;	// Asura_GetHashID( "RoarCamShake_CurveType" )
static const Asura_Hash_ID g_uRoarCamShake_Flags = 0x3E05F38D;		// Asura_GetHashID( "RoarCamShake_Flags" )
static const Asura_Hash_ID g_uRoarCamShake_Amplitude = 0xBFD1AE89;	// Asura_GetHashID( "RoarCamShake_Amplitude" )
static const Asura_Hash_ID g_uRoarCamShake_Frequency = 0x6FD39762;	// Asura_GetHashID( "RoarCamShake_Frequency" )

static const Asura_Hash_ID g_uSprintCamShake_Duration = 0x9B601562;	// Asura_GetHashID( "SprintCamShake_Duration" )
static const Asura_Hash_ID g_uSprintCamShake_MaxRange = 0x2B721A27;	// Asura_GetHashID( "SprintCamShake_MaxRange" )
static const Asura_Hash_ID g_uSprintCamShake_CurveType = 0x5F65B29B;// Asura_GetHashID( "SprintCamShake_CurveType" )
static const Asura_Hash_ID g_uSprintCamShake_Flags = 0x8A67E979;	// Asura_GetHashID( "SprintCamShake_Flags" )
static const Asura_Hash_ID g_uSprintCamShake_Amplitude = 0x7D2ECE75;// Asura_GetHashID( "SprintCamShake_Amplitude" )
static const Asura_Hash_ID g_uSprintCamShake_Frequency = 0x2D30B74E;// Asura_GetHashID( "SprintCamShake_Frequency" )


////////////////////////////////////////////////////////////////////////////////
// Static variable declarations...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Global Declaraitons...
////////////////////////////////////////////////////////////////////////////////

float g_afTimeOfLastHits[g_iHitsInCombo];

////////////////////////////////////////////////////////////////////////////////
// Local Helper Functions...
////////////////////////////////////////////////////////////////////////////////

void RegisterHitAgainstTimer()
{
	if( ! g_afTimeOfLastHits[0] )
	{
		for( int iCount = 0; iCount < g_iHitsInCombo; iCount ++ )
		{
			// initialise the values in the hit time aray if this is the first hit registered. 
			g_afTimeOfLastHits[iCount] = -1.0f;
		}
	}

	for( int iCount = ( g_iHitsInCombo - 1 ); iCount > 0; iCount -- )
	{
		// move all of the values in the array down one to clear up the first array element. 
		g_afTimeOfLastHits[iCount] = g_afTimeOfLastHits[iCount - 1];
	}

	g_afTimeOfLastHits[0] = Asura_Timers::GetGlobalGameTime();
}

bool ComboPerformed()
{
	if( g_afTimeOfLastHits[g_iHitsInCombo - 1] == -1.0f )
	{
		// if we still havent had three hits connect this is not a combo. 
		return false;
	}

	if( ( g_afTimeOfLastHits[0] - g_afTimeOfLastHits[g_iHitsInCombo - 1] ) <= g_fComboDuration )
	{
		// if the most recent hit time minus the last time in the array is less than the combo max time then we have a combo, reset times and return. 
		for( int iCount = 0; iCount < g_iHitsInCombo; iCount ++ )
		{
			g_afTimeOfLastHits[iCount] = -1.0f;
		}
		return true;
	}

	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_Charge_BuildUp
// Author       : Andy McCabe
// Date         : 19/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_Charge_BuildUp::AVP_AlienQueen_Move_Melee_Charge_BuildUp(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_Charge_Loop::GetStaticHash());

	m_bRestrictedMovement = true;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ChargeBuildUp");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fLongTweenInDuration, 0.0f, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

void AVP_AlienQueen_Move_Melee_Charge_BuildUp::Abort()
{
	EnsureAnimationFinishes();

	PARENT::Abort();
}


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_Charge_Loop
// Author       : Andy McCabe
// Date         : 19/11/08
////////////////////////////////////////////////////////////////////////////////

DEBUGVAR float dbg_fMeleeChargeTurnRate = 5.0f;

AVP_AlienQueen_Move_Melee_Charge_Loop::AVP_AlienQueen_Move_Melee_Charge_Loop(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
, m_fTimeSinceStart(0.0f)
, m_fChargeTurnRate(dbg_fMeleeChargeTurnRate)
, m_bFinished(false)
, m_bChargeCollide(false)
, m_bChargeCollideInjured(false)
, m_bChargeIntoIdle(false)
, m_bHitTarget(false)
{
	AddNextMove(AVP_AlienQueen_Move_Melee_Charge_Into_Idle::GetStaticHash());
	AddNextMove(AVP_AlienQueen_Move_Melee_Charge_Collide::GetStaticHash());
	AddNextMove(AVP_AlienQueen_Move_Melee_Charge_Collide_Injured::GetStaticHash());

	// TODO - we still need to change the name of this flag to something more sensible (or remove it and just use the animation flag).
	m_bLoopAtEnd = true;

	m_bRestrictedMovement = true;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ChargeLoop");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetAnimFlags(AACA_FLAG_LOOPED);
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}

	AVP_ClientActor_AlienQueen* pxAlienQueen = AVP_ClientActor_AlienQueen::FindEntity( GetParentSystem().GetOwnerGuid() );
	if ( pxAlienQueen )
	{
		const Asura_Blueprint* pxBlueprint = pxAlienQueen->GetBlueprint();
		if (pxBlueprint)
		{
			Asura_Value xValue;
			if (pxBlueprint->GetParameterValueByHashID(0xA6F75ADD, xValue))	// Asura_GetHashID( "AIMeleeChargeTurnRate" )
			{
				m_fChargeTurnRate = xValue.GetFloatValue();
			}
		}
	}

	SetUpCamShakeParams();
}

void AVP_AlienQueen_Move_Melee_Charge_Loop::SetUpCamShakeParams()
{
	// set the parameters for the camera shake to default incase blueprint init oes wrong anywhere. 
	m_xCameraShakeParams.m_fDuration = 1.00f;						// seconds
	m_xCameraShakeParams.m_fMaxDist = 40.0f;							// meters
	m_xCameraShakeParams.m_uCurve = AVP_CAMERASHAKE_CURVE_PULSE;	// AVP_CAMERASHAKE_CURVE
	m_xCameraShakeParams.m_uFlags = 0;								// AVP_CAMERASHAKE_FLAG
	m_xCameraShakeParams.m_xAmplitude = Asura_Vector_3( 0.05f, 0.05f, 0.05f );
	m_xCameraShakeParams.m_xFrequency = Asura_Vector_3( 150.0f, 150.0f, 150.0f );


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MOVESALIENQUEEN, g_uAIMovesBP );
	if ( pxBP )
	{
		Asura_Value xValue;
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_Duration, xValue ) )
		{
			m_xCameraShakeParams.m_fDuration = xValue.GetFloatValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_MaxRange, xValue ) )
		{
			m_xCameraShakeParams.m_fMaxDist = xValue.GetFloatValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_CurveType, xValue ) )
		{
			m_xCameraShakeParams.m_uCurve = xValue.GetIntValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_Flags, xValue ) )
		{
			m_xCameraShakeParams.m_uFlags = xValue.GetIntValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_Amplitude, xValue ) )
		{
			m_xCameraShakeParams.m_xAmplitude.SetX( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xAmplitude.SetY( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xAmplitude.SetZ( xValue.GetFloatValue() );
		}
		if ( pxBP->GetParameterValueByHashID( g_uSprintCamShake_Frequency, xValue ) )
		{
			m_xCameraShakeParams.m_xFrequency.SetX( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xFrequency.SetY( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xFrequency.SetZ( xValue.GetFloatValue() );
		}
	}
}

bool AVP_AlienQueen_Move_Melee_Charge_Loop::Start(const Asura_Msg_Move* pxStartMsg)
{
	m_fTimeSinceStart = 0.0f;
	
	m_bFinished	= false;
	m_bChargeCollide = false;
	m_bChargeCollideInjured = false;
	m_bChargeIntoIdle = false;
	m_bHitTarget = false;

	// stop any shakes that still may be playing from the last loop and start it again from beggining. 
	AVP_CameraShake_System::StopShake( GetAVPParentSystem().GetOwnerGuid() );
	AVP_CameraShake_System::StartShake( m_xCameraShakeParams, GetAVPParentSystem().GetOwnerGuid() );	

	return PARENT::Start(pxStartMsg);
}

void AVP_AlienQueen_Move_Melee_Charge_Loop::UpdateStates(const float fTimeStep)
{
	m_fTimeSinceStart += fTimeStep;

	UpdateOrientationToTarget( fTimeStep );
	
	const AVP_ClientEntity_Actor* pxVictim = AVP_ClientEntity_Actor::FindEntity( GetHitEntity() );

	if( pxVictim && pxVictim->IsPlayer() )
	{
		m_bFinished = true;
		m_bChargeCollide = true;
		m_bHitTarget = true;
		SendImpulseMessage();
	}
	else if( ChargeHitEnvironment() )
	{
		m_bFinished = true;
		if( m_fTimeSinceStart > 1.0f )
		{
			// Been charging for more than a half second and hit wall, then collide injured
			m_bChargeCollideInjured = true;
		}
		else
		{
			m_bChargeCollide = true;
		}
	}
	else if (ChargeMissedTarget() || ChargeWillFallOffLedge())
	{
		m_bFinished = true;
		m_bChargeIntoIdle = true;
	}

	PARENT::UpdateStates(fTimeStep);
}

void AVP_AlienQueen_Move_Melee_Charge_Loop::SendImpulseMessage()
{
	// get the target entity so we can find the best position for the damage message.
	AVP_ClientEntity_Actor* pxActorTarget = AVP_ClientEntity_Actor::FindEntity( GetTargetGuid() );

	// get the vector to the target by subtracting the queen postion from the target position. 
	Asura_Vector_3 xVecToTarget = pxActorTarget->GetCurrentPosition() - GetAVPParentSystem().GetActorOwner().GetCurrentPosition();

	// set the positiuon for damage to be the middle point between the queen and the target. 
	Asura_Vector_3 xPosForDamage = GetAVPParentSystem().GetActorOwner().GetCurrentPosition() + ( xVecToTarget * 0.5f );
	
	//const float fDot = xOurForward * xToTarget;

	Asura_Message* pxMessage = Asura_Network::CreateMessage( AVP_MSGID_ENTITYDAMAGE_REQUEST_VICTIM, sizeof( AVP_Message_EntityDamage_RequestVictim ) );
	if( pxMessage )
	{
		AVP_Message_EntityDamage_RequestVictim*	pxData = static_cast<AVP_Message_EntityDamage_RequestVictim*>( pxMessage->GetData() );
		const AVP_EntityDamage_RequestVictim xDamage(	uAVP_BLUEPRINT_NAME_DAMAGE_EXPLOSIVEIMPACTDAMAGE,
														GetParentSystem().GetOwnerGuid(),
														uMELEE_MARKER_POINT_HASH,
														GetTargetGuid(),
														0.0f,
														xPosForDamage,
														xVecToTarget,
														Asura_Maths::ZeroVector3,
														500.0f);

		pxData->SetDamage( xDamage );

		pxMessage->SetFromGuid( GetAVPParentSystem().GetOwnerGuid() );
		pxMessage->SetToGuid( GetTargetGuid() );
		Asura_Network::Send( pxMessage );
	}
}

bool AVP_AlienQueen_Move_Melee_Charge_Loop::HasFinished() const
{
	return m_bFinished;
}

void AVP_AlienQueen_Move_Melee_Charge_Loop::Abort()
{
	EnsureAnimationFinishes();

	PARENT::Abort();
}

DEBUGVAR float dbg_fChargeMissedCosine = 0.20f;

bool AVP_AlienQueen_Move_Melee_Charge_Loop::ChargeMissedTarget() const
{
	const AVP_ClientEntity_Actor& xOwner = GetAVPParentSystem().GetActorOwner();
	const Asura_Vector_3 xOurPosition = xOwner.GetCurrentPosition();
	const Asura_Matrix_3x3& xOurOrientation = xOwner.GetCurrentOrientation();
	
	Asura_Vector_3 xOurForward( xOurOrientation.e13, xOurOrientation.e23, xOurOrientation.e33 );
	xOurForward.Normalise();

	AVP_ClientEntity_Actor* pxActorTarget = AVP_ClientEntity_Actor::FindEntity( GetTargetGuid() );

	if (pxActorTarget)
	{
		Asura_Vector_3 xToTarget = pxActorTarget->GetCurrentPosition() - xOurPosition;
		xToTarget.Normalise();

		const float fDot = xOurForward * xToTarget;

		if (fDot < dbg_fChargeMissedCosine)
		{
			return true;
		}
	}

	return false;
}

DEBUGVAR float dbg_fDownAngleForEnvLOSTest = 0.35f;

bool AVP_AlienQueen_Move_Melee_Charge_Loop::ChargeWillFallOffLedge() const
{
	const AVP_ServerEntity_Actor* pxActorOwner = AVP_ServerEntity_Actor::FindEntity( GetAVPParentSystem().GetOwnerGuid() );
	if ( !pxActorOwner ) return false;

	const Asura_Matrix_3x3& xOurOrientation = pxActorOwner->GetOrientation();

	Asura_Vector_3 xOurForward(xOurOrientation.e13, xOurOrientation.e23, xOurOrientation.e33);

	Asura_Vector_3 xHeadPos;
	if (!pxActorOwner->GetWorldSpaceMarkerPoint(AVP_Vertebrate_Description::GetMarkerPointHashID(AVP_Vertebrate_Description::MPID_EYES), &xHeadPos, NULL))
	{
		xHeadPos = pxActorOwner->GetPosition();
		xHeadPos.y -= 3.8f;
	}

	xOurForward.y = dbg_fDownAngleForEnvLOSTest;

	Asura_LOS_InputData xInput(xHeadPos, xOurForward, pxActorOwner->GetGuid(), 12.0f, false);
	const Asura_LOS_OutputData* pxOutput = Asura_LOS::TestAgainstEnvironment(&xInput);

	if (pxOutput->m_bHitEnvironment)
	{
		return false;
	}
	
	return true;
}

DEBUGVAR float dbg_fDisplacement = 3.0f;

bool AVP_AlienQueen_Move_Melee_Charge_Loop::ChargeHitEnvironment() const
{
	AVP_Actor_PhysicsObjectHandler* pxPhyHandler = NULL;

	if (Asura_Network::IsServer())
	{
		AVP_ServerEntity_Actor* pxActorOwner = AVP_ServerEntity_Actor::FindEntity( GetAVPParentSystem().GetOwnerGuid() );
		if ( pxActorOwner )
		{
			pxPhyHandler = pxActorOwner->GetPhysicsObjectHandler();
		}
	}
	else
	{
		AVP_ClientEntity_Actor* pxActorOwner = AVP_ClientEntity_Actor::FindEntity( GetAVPParentSystem().GetOwnerGuid() );
		if ( pxActorOwner )
		{
			pxPhyHandler = pxActorOwner->GetPhysicsObjectHandler();
		}
	}

	if (!pxPhyHandler)
	{
		Asura_Assert(pxPhyHandler, "PhysicsObjectHandler not found");
		return false;
	}

	if (!pxPhyHandler->GetPhysicsObject()) return false;
	
	const Asura_Collision_Object* pxCollObj = pxPhyHandler->GetPhysicsObject()->GetCollisionObject();

	//if (!pxCollObj) return false;

	const Asura_AVector3 xStartPosition = Asura_AVector3( pxPhyHandler->GetPhysicsObject()->GetPosition() );
	const Asura_Matrix_3x3& xOurOrientation = pxPhyHandler->GetPhysicsObject()->GetOrientation();

	Asura_AVector3 xDisplacement(xOurOrientation.e13, xOurOrientation.e23, xOurOrientation.e33);
	xDisplacement *= dbg_fDisplacement;

	// Proceed with the movement query
	Asura_OBB xOurOBB(pxCollObj->GetBoundingBox());
	xOurOBB.SetOrientation( Asura_AMatrix3x3(xOurOrientation) );

	Asura_Physics_MovementQuery xChargeLoopMovementQuery( xStartPosition, xDisplacement, 
															xOurOBB, 
															Asura_Physics_MovementQuery::ASURA_PMQCP_OBB,
															AsuraPolygonFlag_NoCollisions | AVP_PolygonFlag_IgnoreForPhysicsObjectCollision,
															false); 
	
	const Asura_Physics_MovementQuery_Results xChargeLoopMovementQueryResults( xChargeLoopMovementQuery ); 

	Asura_AVector3 xStartToEndPosVec = xChargeLoopMovementQueryResults.GetEndPosition() - xStartPosition;

	const float fDesiredDist = xDisplacement.Magnitude();
	const float fActualDist = xStartToEndPosVec.Magnitude();

	if (xStartToEndPosVec.ApproximatelyEquals(Asura_Maths::ZeroAVector3))
	{
		return true;
	}

	xDisplacement.Normalise();
	xStartToEndPosVec.Normalise();

	// Get the dot product to see is our end pos in the same direction as our desired position, or are we sliding along a wall
	const float fDot = xDisplacement * xStartToEndPosVec;

	if (fDot < 0.86f)
	{
		return true;
	}

	// Distance check, how far have we actually moved in comparison to how far we wanted to move
	if (fActualDist < (fDesiredDist * 0.5f))
	{
		// less than half probably means we have hit environment
		return true;
	}

	// do a final check to see how close the environment is in front of the queen, because her head is outside her collisoin sphere

	// set the direction to be the current queen world space direction but always slightly upwards
	Asura_Vector_3 xDirection  = Asura_Vector_3( xOurOrientation.e13, -2.0f, xOurOrientation.e33 );
	xDirection.Normalise();

	Asura_LOS_InputData xInput( pxPhyHandler->GetPhysicsObject()->GetPosition(), xDirection, GetAVPParentSystem().GetOwnerGuid(), 5.5f, false );
	const Asura_LOS_OutputData* pxOutput = Asura_LOS::TestAgainstEnvironment( &xInput );

	if( pxOutput->m_bHitEnvironment )
	{
		return true;
	}

	return false;
}


void AVP_AlienQueen_Move_Melee_Charge_Loop::UpdateOrientationToTarget(const float fTimeStep)
{
	AVP_Actor_PhysicsObjectHandler* pxPhyHandler = NULL;

	if (Asura_Network::IsServer())
	{
		AVP_ServerEntity_Actor* pxActorOwner = AVP_ServerEntity_Actor::FindEntity( GetAVPParentSystem().GetOwnerGuid() );
		if ( pxActorOwner )
		{
			pxPhyHandler = pxActorOwner->GetPhysicsObjectHandler();
		}
	}
	else
	{
		AVP_ClientEntity_Actor* pxActorOwner = AVP_ClientEntity_Actor::FindEntity( GetAVPParentSystem().GetOwnerGuid() );
		if ( pxActorOwner )
		{
			pxPhyHandler = pxActorOwner->GetPhysicsObjectHandler();
		}
	}

	if (!pxPhyHandler)
	{
		Asura_Assert(pxPhyHandler, "PhysicsObjectHandler not found");
		return;
	}

	if (!pxPhyHandler->GetPhysicsObject()) return;

	AVP_ClientEntity_Actor* pxActorTarget = AVP_ClientEntity_Actor::FindEntity( GetTargetGuid() );

	if (!pxActorTarget) return;

	const Asura_Matrix_3x3& xOurOrientation = pxPhyHandler->GetPhysicsObject()->GetOrientation();
	const Asura_Vector_3& xOurPosition = pxPhyHandler->GetPhysicsObject()->GetPosition();

	Asura_Vector_3 xToTarget = pxActorTarget->GetCurrentPosition() - xOurPosition;
	xToTarget.Normalise();

	Asura_Matrix_3x3 xDesiredOrientation;
	Asura_Maths::OrientationFromDirection( xDesiredOrientation, xToTarget );

	// If our orientation to target is already correct, return
	if (xOurOrientation.ApproximatelyEquals( xDesiredOrientation )) return;

	Asura_Quat xOurQOrientation;
	xOurQOrientation.FromMatrix( xOurOrientation );

	Asura_Quat xDesiredQOrientation;
	xDesiredQOrientation.FromMatrix( xDesiredOrientation );

	const float fFraction = Asura_Maths::ClampToRange( fTimeStep * m_fChargeTurnRate, 0.0f, 1.0f );
	Asura_Quat xSlerpQOri;
	xSlerpQOri.Slerp( xOurQOrientation, xDesiredQOrientation, fFraction );
	
	Asura_Matrix_3x3 xSlerpOri;
	xSlerpQOri.ToMatrix( xSlerpOri );

	pxPhyHandler->GetPhysicsObject()->SetOrientation(xSlerpOri);
}


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_Charge_Collide
// Author       : Andy McCabe
// Date         : 19/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_Charge_Collide::AVP_AlienQueen_Move_Melee_Charge_Collide(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
, m_bRoarAfter(false)
{
	AddNextMove( AVP_AlienQueen_Move_Melee_Stationary_Roar::GetStaticHash() );

	m_bRestrictedMovement = true;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ChargeCollide");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Melee_Charge_Collide::ShouldStart() const
{
	// There's only one move we can have come from.
	const AVP_AlienQueen_Move_Melee_Charge_Loop* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_Charge_Loop*>(GetParentSystem().GetCurrentMove());
	if( ! pxCurrentMove ) { return false; }

	if( pxCurrentMove->ChargeCollide() )
	{
		return true;
	}

	return PARENT::ShouldStart();
}

bool AVP_AlienQueen_Move_Melee_Charge_Collide::Start( const Asura_Msg_Move* pxStartMsg )
{
	// There's only one move we can have come from.
	const AVP_AlienQueen_Move_Melee_Charge_Loop* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_Charge_Loop*>(GetParentSystem().GetCurrentMove());
	
	if( pxCurrentMove && pxCurrentMove->ChargeCollide() )
	{
		// on the start of this move while the old is still active get the data we need from it. 
		m_bRoarAfter = pxCurrentMove->HitTarget();
	}

	return ( PARENT::Start( pxStartMsg ) );
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_Charge_Collide_Injured
// Author       : Andy McCabe
// Date         : 19/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_Charge_Collide_Injured::AVP_AlienQueen_Move_Melee_Charge_Collide_Injured(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	m_bRestrictedMovement = true;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ChargeCollideInjured");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Melee_Charge_Collide_Injured::ShouldStart() const
{
	// There's only one move we can have come from.
	const AVP_AlienQueen_Move_Melee_Charge_Loop* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_Charge_Loop*>(GetParentSystem().GetCurrentMove());
	if (!pxCurrentMove) { return false; }

	if (pxCurrentMove->ChargeCollideInjured())
	{
		return true;
	}

	return PARENT::ShouldStart();
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_Charge_Into_Idle
// Author       : Andy McCabe
// Date         : 19/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_Charge_Into_Idle::AVP_AlienQueen_Move_Melee_Charge_Into_Idle(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	m_bRestrictedMovement = true;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ChargeIntoIdle");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Melee_Charge_Into_Idle::ShouldStart() const
{
	// There's only one move we can have come from.
	const AVP_AlienQueen_Move_Melee_Charge_Loop* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_Charge_Loop*>(GetParentSystem().GetCurrentMove());
	if (!pxCurrentMove) { return false; }

	if (pxCurrentMove->ChargeIntoIdle())
	{
		return true;
	}

	return PARENT::ShouldStart();
}


////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Start
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Start::AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::GetStaticHash());

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeLeftStart");
	}

	if (m_pxAVPAnimationData)
	{
		// no tween out time because return anim always starts from finish pint of this anim
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, 0.0f, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

void AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Start::Abort()
{
	EnsureAnimationFinishes();

	PARENT::Abort();
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Loop_Start
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Loop_Start::AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Loop_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::GetStaticHash());

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeLeftLoopStart");
	}

	if (m_pxAVPAnimationData)
	{
		// no tween out time because return anim always starts from finish pint of this anim
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, 0.0f, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove( AVP_AlienQueen_Move_Melee_Stationary_Roar::GetStaticHash() );

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeLeftReturn");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::Start( const Asura_Msg_Move* pxStartMsg )
{
	const AVP_Move_Melee* pxCurrentMove = static_cast<const AVP_Move_Melee*>( GetParentSystem().GetCurrentMove() );
	if( pxCurrentMove->HasDoneDamage() ) 
	{ 
		RegisterHitAgainstTimer();
	}

	return PARENT::Start( pxStartMsg );
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Start
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Start::AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::GetStaticHash());

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeRightStart");
	}

	if (m_pxAVPAnimationData)
	{
		// no tween out time because return anim always starts from finish pint of this anim
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, 0.0f, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

void AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Start::Abort()
{
	EnsureAnimationFinishes();

	PARENT::Abort();
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Loop_Start
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Loop_Start::AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Loop_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::GetStaticHash());

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeRightLoopStart");
	}

	if (m_pxAVPAnimationData)
	{
		// no tween out time because return anim always starts from finish pint of this anim
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, 0.0f, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return
// Author       : Andy McCabe
// Date         : 28/11/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	AddNextMove( AVP_AlienQueen_Move_Melee_Stationary_Roar::GetStaticHash() );

	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash);
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	if (pxFirstPersonBlueprint || pxThirdPersonBlueprint)
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "ClawSwipeRightReturn");
	}

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(g_fTweenInDuration, g_fTweenOutDuration, true);
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::Start( const Asura_Msg_Move* pxStartMsg )
{
	const AVP_Move_Melee* pxCurrentMove = static_cast<const AVP_Move_Melee*>( GetParentSystem().GetCurrentMove() );
	if( pxCurrentMove->HasDoneDamage() ) 
	{ 
		RegisterHitAgainstTimer();
	}

	return PARENT::Start( pxStartMsg );
}

////////////////////////////////////////////////////////////////////////////////
// Class		: AVP_AlienQueen_Move_Melee_ClawSwipeKill_Start
// Author       : Andy McCabe
// Date         : 02/12/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipeKill_Start::AVP_AlienQueen_Move_Melee_ClawSwipeKill_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "ClawSwipeKillStart",
		 AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit::GetStaticHash(), AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Countered::GetStaticHash(), AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Miss::GetStaticHash())
{
	AddNextMove(AVP_AlienQueen_Move_Melee_ClawSwipeKill_Grapple::GetStaticHash());

	m_bClearQueuedMeleeRequests = true;
}


////////////////////////////////////////////////////////////////////////////////
// Class	    : AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit
// Author       : Andy McCabe
// Date         : 02/12/08
////////////////////////////////////////////////////////////////////////////////

// Currently hit, countered and miss all use the same animation, set up with just one parameter.
static const char* g_szClawSwipeKillReturnParameterName = "ClawSwipeKillReturn";

AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit::AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, g_szClawSwipeKillReturnParameterName)
{
	m_bClearQueuedMeleeRequests = true;
}

bool AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Hit::ShouldStart() const
{
	// If the parent says we can start, check that the entity is of a type that we don't attach on to.
	if (!PARENT::ShouldStart()) { return false; }

	// There's only one move we can have come from.
	const AVP_AlienQueen_Move_Melee_ClawSwipeKill_Start* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_ClawSwipeKill_Start*>(GetParentSystem().GetCurrentMove());
	if (!pxCurrentMove) { return false; }

	const AVP_ClientEntity_Actor* pxVictim = AVP_ClientEntity_Actor::FindEntity(pxCurrentMove->GetHitEntity());
	// TODO - These next two checks take the safe option of using this move if our victim has gone missing or died, but we should possibly be going into miss in that case.
	if (!pxVictim) { return true; }
	if (pxVictim->IsDead()) { return true; }

	switch (pxVictim->GetClassification())
	{
	default:
		return true;

		// Humans are attached to, so don't start this move.
	case AVP_ENTITYCLASS_ANDROID:
	case AVP_ENTITYCLASS_CIVILIAN:
	case AVP_ENTITYCLASS_MARINE:
		// However, we can only grab them if they aren't invulnerable.
		return pxVictim->IsInvulnerable();
	}
}


////////////////////////////////////////////////////////////////////////////////
// Class		: AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Countered
// Author       : Andy McCabe
// Date         : 02/12/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Countered::AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, g_szClawSwipeKillReturnParameterName)
{
}


////////////////////////////////////////////////////////////////////////////////
// Class		: AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Miss
// Author       : Andy McCabe
// Date         : 02/12/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Miss::AVP_AlienQueen_Move_Melee_ClawSwipeKill_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, g_szClawSwipeKillReturnParameterName)
{
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Melee_ClawSwipeKill_Grapple
// Author       : Andy McCabe
// Date         : 02/12/08
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_ClawSwipeKill_Grapple::AVP_AlienQueen_Move_Melee_ClawSwipeKill_Grapple(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash(),
		 AVP_Settings::AVP_SPECIES_ALIEN, AVP_Settings::AVP_SPECIES_HUMAN, uAVP_BLUEPRINT_NAME_ALIENQUEEN_HUMANVICTIM)
{
	m_bAlwaysFatal = true;
}

bool AVP_AlienQueen_Move_Melee_ClawSwipeKill_Grapple::ShouldStart() const
{
	// There's only one move we can have come from.
	const AVP_Move_Melee* pxCurrentMove = static_cast<const AVP_Move_Melee*>(GetParentSystem().GetCurrentMove());
	if (!pxCurrentMove) { return false; }

	const AVP_ClientEntity_Actor* pxVictim = AVP_ClientEntity_Actor::FindEntity(pxCurrentMove->GetHitEntity());
	// TODO - These next two checks take the safe option of using this move if our victim has gone missing or died, but we should possibly be going into miss in that case.
	if (!pxVictim) { return false; }
	if (pxVictim->IsDead()) { return false; }

	// not a player should use different move
	if (!pxVictim->IsPlayer())
	{
		return false;
	}

	return PARENT::ShouldStart();
}

////////////////////////////////////////////////////////////////////////////////
// Class        : AVP_AlienQueen_Move_Spit_Acid
// Author       : Andy McCabe
// Date         : 08/01/09
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Spit_Acid::AVP_AlienQueen_Move_Spit_Acid(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash())
{
	SetAnimHashes(0xAE9AC28E, 0xAE9AC28E); //Asura_GetHashID("Hag_Queen_spit");

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.05f, 0.05f, true );
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}
}

bool AVP_AlienQueen_Move_Spit_Acid::Start(const Asura_Msg_Move* pxStartMsg)
{
	// This has to start by message, and we need to use our own special message.
	if (!pxStartMsg) { return false; }

	return PARENT::Start(pxStartMsg);
}

////////////////////////////////////////////////////////////////////////////////
// CLASS FUNCTIONS
// AVP_AlienQueen_Move_Melee_Stationary_Roar

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Melee_Stationary_Roar - constructor
// Author       : Callum Hope
// Date         : 26/3/09
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Melee_Stationary_Roar::AVP_AlienQueen_Move_Melee_Stationary_Roar(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	m_bRestrictedMovement = false;
	m_bAllowMeleeTargetUpdate = true;

	const Asura_Blueprint* pxFirstPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash );
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if( pxFirstPersonBlueprint || pxThirdPersonBlueprint )
	{
		SetupAnimHashesFromBlueprint(pxFirstPersonBlueprint, pxThirdPersonBlueprint, "StationaryRoar");
	}

	if( m_pxAVPAnimationData )
	{
		m_pxAVPAnimationData->SetTweenData( g_fLongTweenInDuration, g_fTweenOutDuration * 4.0f , true );
		m_pxAVPAnimationData->SetLeaveAnimAtEnd( true );
	}

	SetUpCamShakeParams();

	SetVariation( 0 );
}

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Melee_Stationary_Roar::SetUpCamShakeParams()
// Author       : Callum Hope
// Date         : 6/4/09
// Scope		: Private
////////////////////////////////////////////////////////////////////////////////

void AVP_AlienQueen_Move_Melee_Stationary_Roar::SetUpCamShakeParams()
{
	// set the parameters for the camera shake to default incase blueprint init oes wrong anywhere. 
	m_xCameraShakeParams.m_fDuration = 2.75f;						// seconds
	m_xCameraShakeParams.m_fMaxDist = 20.0f;						// meters
	m_xCameraShakeParams.m_uCurve = AVP_CAMERASHAKE_CURVE_CONST_INC;// AVP_CAMERASHAKE_CURVE
	m_xCameraShakeParams.m_uFlags = 0;								// AVP_CAMERASHAKE_FLAG
	m_xCameraShakeParams.m_xAmplitude = Asura_Vector_3( 0.015f, 0.015f, 0.015f );
	m_xCameraShakeParams.m_xFrequency = Asura_Vector_3( 250.0f, 250.0f, 250.0f );


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MOVESALIENQUEEN, g_uAIMovesBP );
	if ( pxBP )
	{
		Asura_Value xValue;
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_Duration, xValue ) )
		{
			m_xCameraShakeParams.m_fDuration = xValue.GetFloatValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_MaxRange, xValue ) )
		{
			m_xCameraShakeParams.m_fMaxDist = xValue.GetFloatValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_CurveType, xValue ) )
		{
			m_xCameraShakeParams.m_uCurve = xValue.GetIntValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_Flags, xValue ) )
		{
			m_xCameraShakeParams.m_uFlags = xValue.GetIntValue();
		}
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_Amplitude, xValue ) )
		{
			m_xCameraShakeParams.m_xAmplitude.SetX( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xAmplitude.SetY( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xAmplitude.SetZ( xValue.GetFloatValue() );
		}
		if ( pxBP->GetParameterValueByHashID( g_uRoarCamShake_Frequency, xValue ) )
		{
			m_xCameraShakeParams.m_xFrequency.SetX( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xFrequency.SetY( xValue.GetFloatValue() );
			m_xCameraShakeParams.m_xFrequency.SetZ( xValue.GetFloatValue() );
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Melee_Stationary_Roar::Start()
// Author       : Callum Hope
// Date         : 2/4/09
// Scope		: Protected Virtual
////////////////////////////////////////////////////////////////////////////////

bool AVP_AlienQueen_Move_Melee_Stationary_Roar::Start( const Asura_Msg_Move* pxStartMsg )
{
	AVP_CameraShake_System::StartShake( m_xCameraShakeParams, GetAVPParentSystem().GetOwnerGuid() );

	return PARENT::Start( pxStartMsg );
}

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Melee_Stationary_Roar::Abort()
// Author       : Callum Hope
// Date         : 26/3/09
// Scope		: Protected Virtual
////////////////////////////////////////////////////////////////////////////////

void AVP_AlienQueen_Move_Melee_Stationary_Roar::Abort()
{
	EnsureAnimationFinishes();

	PARENT::Abort();
}

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Melee_Stationary_Roar::ShouldStart()
// Author       : Callum Hope
// Date         : 26/3/09
// Scope		: Public Virtual
// 
// Desc			: Checks against all of the moves that this can follow on from looking for conditions. 
////////////////////////////////////////////////////////////////////////////////

bool AVP_AlienQueen_Move_Melee_Stationary_Roar::ShouldStart() const
{	
	Asura_Hash_ID uCurrentMoveId = GetParentSystem().GetCurrentMove()->GetHash();

	if( uCurrentMoveId == AVP_AlienQueen_Move_Melee_Charge_Collide::GetStaticHash( ) )
	{
		// fist check if we have collided with a target after a charge. 
		const AVP_AlienQueen_Move_Melee_Charge_Collide* pxCurrentMove = static_cast<const AVP_AlienQueen_Move_Melee_Charge_Collide*>( GetParentSystem().GetCurrentMove() );
		if( ! pxCurrentMove ) 
		{ 
			return false; 
		}

		if( pxCurrentMove->RoarAfter() )
		{
			return true;
		}
	}
	else if(	( uCurrentMoveId == AVP_AlienQueen_Move_Melee_ClawSwipe_Left_Return::GetStaticHash( ) )
			||	( uCurrentMoveId == AVP_AlienQueen_Move_Melee_ClawSwipe_Right_Return::GetStaticHash( ) ) )
	{
		// if we are returning from a claw swipe on either arm and have had more than the limit of sequential hits

		if( ComboPerformed() )
		{
			return true;
		}
	}

	return PARENT::ShouldStart();
}

////////////////////////////////////////////////////////////////////////////////
// CLASS FUNCTIONS
// AVP_AlienQueen_Move_Stunned_Stumble

////////////////////////////////////////////////////////////////////////////////
// Function		: AVP_AlienQueen_Move_Stunned_Stumble - constructor
// Author       : Callum Hope
// Date         : 26/3/09
////////////////////////////////////////////////////////////////////////////////

AVP_AlienQueen_Move_Stunned_Stumble::AVP_AlienQueen_Move_Stunned_Stumble( Asura_Movement_System& xParentSystem )
: PARENT( xParentSystem, GetStaticHash() )
{
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MOVESALIENQUEEN, g_uAIMovesBP );
	if ( pxBP )
	{
		Asura_Value xValue;
		if ( pxBP->GetParameterValueByHashID( g_uStunnedStumble, xValue ) )
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}
	SetAnimHashes( ASURA_HASH_ID_UNSET, uTPAnim );
	if ( m_pxAVPAnimationData )
	{
		m_pxAVPAnimationData->SetTweenData( g_fLongTweenInDuration, g_fLongTweenOutDuration, true );
	}

	SetPreventsFlinch( true );
}

/// End of file. ///
