
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Predalien_MovesMelee.cpp
// Author : Chris Wallace
// Date   : 23-Jan-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"


// This file's header...
#include "Moves/Vertebrates/Predalien/AVP_Predalien_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/Vertebrates/Predalien/AVP_Predalien_MeleeCounter_System.h"
#include "Animation/AVP_AnimFlags.h"
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Core/AVP_Settings.h"
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/AVP_Vertebrate_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predalien/AVP_ClientActor_Predalien.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Human/AVP_ServerActor_Human.h"
#include "Entity/PhysicalObject/Gib/AVP_ClientEntity_Gib.h"
#include "Moves/Vertebrates/Alien/AVP_Alien_MovesMelee.h"
#include "Rendering/Asura_Project_Skin_Elements.h"
#include "Mesh/AVP_PolygonFlags.h"


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

static const float g_fTweenInDuration = 0.1f;
static const float g_fTweenOutDuration = 0.1f;

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

////////////////////////////////////////////////////////////////////////////////
// Close range attacks
////////////////////////////////////////////////////////////////////////////////
AVP_Predalien_Move_Melee_ClawRight_Start::AVP_Predalien_Move_Melee_ClawRight_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
  		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawRightStart",
		 AVP_Predalien_Move_Melee_ClawRight_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_ClawRight_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_ClawRight_Return_Miss::GetStaticHash())
{

}

AVP_Predalien_Move_Melee_ClawRight_Return_Hit::AVP_Predalien_Move_Melee_ClawRight_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawRightHit")
{

}

AVP_Predalien_Move_Melee_ClawRight_Return_Countered::AVP_Predalien_Move_Melee_ClawRight_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawRightCountered")
{

}


AVP_Predalien_Move_Melee_ClawRight_Return_Miss::AVP_Predalien_Move_Melee_ClawRight_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawRightMiss")
{

}

// left
AVP_Predalien_Move_Melee_ClawLeft_Start::AVP_Predalien_Move_Melee_ClawLeft_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawLeftStart",
		 AVP_Predalien_Move_Melee_ClawLeft_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_ClawLeft_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_ClawLeft_Return_Miss::GetStaticHash())
{

}

AVP_Predalien_Move_Melee_ClawLeft_Return_Hit::AVP_Predalien_Move_Melee_ClawLeft_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawLeftHit")
{

}

AVP_Predalien_Move_Melee_ClawLeft_Return_Countered::AVP_Predalien_Move_Melee_ClawLeft_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawLeftCountered")
{

}


AVP_Predalien_Move_Melee_ClawLeft_Return_Miss::AVP_Predalien_Move_Melee_ClawLeft_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "SwipeClawLeftMiss")
{
}

////////////////////////////////////////////////////////////////////////////////
// Close range stand attacks - back
////////////////////////////////////////////////////////////////////////////////
AVP_Predalien_Move_Melee_TailRight::AVP_Predalien_Move_Melee_TailRight(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	SetupAnimHashesFromBlueprint(NULL, pxThirdPersonBlueprint, "SwipeTailRight");

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


// left
AVP_Predalien_Move_Melee_TailLeft::AVP_Predalien_Move_Melee_TailLeft(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	const Asura_Blueprint* pxThirdPersonBlueprint = Asura_Blueprint_System::GetBlueprintByHashID(uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash);
	SetupAnimHashesFromBlueprint(NULL, pxThirdPersonBlueprint, "SwipeTailLeft");

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

////////////////////////////////////////////////////////////////////////////////
// Close range walk attacks
////////////////////////////////////////////////////////////////////////////////

DEBUGVAR float dbg_fWalkSwipeAnimDistance = 5.0f;
DEBUGVAR float dbg_fOptimalDisatnceFromPlayer = 1.0f;
DEBUGVAR float dbg_fStandAttackMaxTurnSpeed = Asura_Maths::Pi / 8.0f;

AVP_Predalien_Move_Melee_WalkClawRight_Start::AVP_Predalien_Move_Melee_WalkClawRight_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawRightStart",
		 AVP_Predalien_Move_Melee_WalkClawRight_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_WalkClawRight_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_WalkClawRight_Return_Miss::GetStaticHash())
, m_fAnimTime(0.0f)
, m_xTargetStartPosition(Asura_Maths::ZeroVector3)
, m_uTarget(ASURA_GUID_UNREGISTERED)
, m_fVelocityMultiplier(1.0f)
{
	SetPositionUsage(POSITION_SET_FROM_VELOCITY);
	SetOrientationUsage(ORIENTATION_SET_DIRECTLY);
	SetAimDirectionUsage(AVP_ClientEntity_Actor::AIM_DIRECTION_RESET);
	SetLookAtPositionUsage(AVP_ClientEntity_Actor::LOOK_AT_POSITION_RESET);
	m_bDisableSurfaceReorientation = true;

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

}

bool AVP_Predalien_Move_Melee_WalkClawRight_Start::Start( const Asura_Msg_Move* pxStartMsg )
{
	if (!pxStartMsg) { return false; }

	bool bResult = PARENT::Start(pxStartMsg);

	const AVP_Msg_Melee_Move* pxMeleeStart = static_cast< const AVP_Msg_Melee_Move* >( pxStartMsg );

	AVP_ClientEntity_Actor& xOwner = GetAVPParentSystem().GetActorOwner();

	// Get an upright orientation to interpolate to.
	m_uTarget = pxMeleeStart->GetTargetGuid();
	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );
	if ( !pxTarget ) { return false; }

	Asura_Matrix_3x3 xOri;
	Asura_Vector_3 xTargetOffset = pxTarget->GetCurrentPosition() - xOwner.GetCurrentPosition();
	xTargetOffset.y = 0.0f;	
	if (m_pxAVPAnimationData && m_pxAVPAnimationData->HasValidAnimation())
	{
		m_fAnimTime = m_pxAVPAnimationData->GetAnimationDuration();
	}
	else
	{
		m_fAnimTime = 1.0f;
	}
	m_xTargetStartPosition =  pxTarget->GetCurrentPosition();
	if (xTargetOffset.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		Asura_Euler_3 xEuler;
		xEuler.FromMatrix(xOwner.GetCurrentOrientation());
		xEuler.x = xEuler.z = 0.0f;
		xEuler.ToMatrix(xOri);
		m_fVelocityMultiplier = 1.0f;
	}
	else
	{
		float fTargetOffset = xTargetOffset.Normalise();
		m_fVelocityMultiplier = (fTargetOffset - dbg_fOptimalDisatnceFromPlayer) / dbg_fWalkSwipeAnimDistance;
// 		if (m_fVelocityMultiplier < 1.0f)
// 		{
// 			m_fVelocityMultiplier = 1.0;
// 		}

		Asura_Maths::OrientationFromDirection(xOri, xTargetOffset);
	}
	SetOrientationUsage(ORIENTATION_SET_DIRECTLY);

	return bResult;
}

bool AVP_Predalien_Move_Melee_WalkClawRight_Start::CalculateVelocity(const float fTimeStep, Asura_AVector3_OutParam xVelocity) const
{
	Asura_AVector3 xRefVelocity;
	bool bResult = PARENT::CalculateVelocity(fTimeStep, xRefVelocity);
	float fRefVelocity = xRefVelocity.Magnitude();

	if (xRefVelocity.ApproximatelyEquals(Asura_Maths::ZeroAVector3))
	{
		xVelocity = xRefVelocity; 
		return bResult;
	}

	xRefVelocity /= fRefVelocity;
	xRefVelocity *= m_fVelocityMultiplier;

	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );

	if ( !pxTarget || m_fAnimTime <= 0.0f ) 
	{
		xVelocity = xRefVelocity * fRefVelocity;
		return bResult; 
	}

	Asura_Vector_3 xTargetVelocity = (pxTarget->GetCurrentPosition() - m_xTargetStartPosition) / fTimeStep;
	m_xTargetStartPosition =  pxTarget->GetCurrentPosition();
	float fTargetVelocity = xTargetVelocity.Normalise();

	if ((Asura_Vector_3(xRefVelocity) * xTargetVelocity) <= 0.0f) // target moving towards us - return the animation velocity
	{
		xVelocity = xRefVelocity * fRefVelocity;
		return bResult; 
	}

	xVelocity = xRefVelocity * (fRefVelocity + fTargetVelocity * (Asura_Vector_3(xRefVelocity) * xTargetVelocity));

	return bResult;
}

bool AVP_Predalien_Move_Melee_WalkClawRight_Start::CalculateOrientation(const float fTimeStep, Asura_Quat& xOrientation) const
{
	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );
	const AVP_ClientEntity_Actor& xOwner = GetAVPParentSystem().GetActorOwner();
	const Asura_Matrix_3x3& xOwnerOri = xOwner.GetCurrentOrientation();

	if ( !pxTarget ) 
	{
		xOrientation.FromMatrix(xOwnerOri); // keep current orientation
		return false; 
	}

	Asura_Vector_3 xTargetOffset = pxTarget->GetCurrentPosition() - xOwner.GetCurrentPosition();
	xTargetOffset.y = 0.0f;	
	if (xTargetOffset.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		xOrientation.FromMatrix(xOwnerOri); // keep current orientation
	}
	else
	{
		const Asura_Vector_3 xForward(xOwnerOri.e13, xOwnerOri.e23, xOwnerOri.e33);
		xTargetOffset.Normalise();
		if (xForward * xTargetOffset > fTimeStep * dbg_fStandAttackMaxTurnSpeed) // small enough turn - just set new orientation
		{
			Asura_Matrix_3x3 xNewOrientation;
			Asura_Maths::OrientationFromDirection(xNewOrientation, xTargetOffset);
			xOrientation.FromMatrix(xNewOrientation);
		}
		else // turn is too much - turn as much as possible
		{
			const Asura_Vector_3 xRight(xOwnerOri.e12, xOwnerOri.e22, xOwnerOri.e32);
			const Asura_Vector_3 xUp(0.0f, -1.0f, 0.0f);
			float fTurnDirection = xRight * xTargetOffset > 0.0f ? 1.0f : -1.0f;
			Asura_Quat xTurn;

			xTurn.FromRotation(fTurnDirection* fTimeStep * dbg_fStandAttackMaxTurnSpeed, xUp);
			Asura_Vector_3 xNewDirection = xTurn.RotateVector(xForward);
			Asura_Matrix_3x3 xNewOrientation;
			Asura_Maths::OrientationFromDirection(xNewOrientation, xNewDirection);
			xOrientation.FromMatrix(xNewOrientation);
		}
	}
	// don't wait for this to finish
	return false;
}

void AVP_Predalien_Move_Melee_WalkClawRight_Start::UpdateStates(const float fTimeStep)
{
	Asura_Quat xOrientation;
	CalculateOrientation(false, xOrientation);
	m_xParentSystem.SetCurrentMoveOrientation(xOrientation);
	PARENT::UpdateStates(fTimeStep);

}

AVP_Predalien_Move_Melee_WalkClawRight_Return_Hit::AVP_Predalien_Move_Melee_WalkClawRight_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawRightHit")
{

}

AVP_Predalien_Move_Melee_WalkClawRight_Return_Countered::AVP_Predalien_Move_Melee_WalkClawRight_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawRightCountered")
{
}

AVP_Predalien_Move_Melee_WalkClawRight_Return_Miss::AVP_Predalien_Move_Melee_WalkClawRight_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawRightMiss")
{
}

// left 

AVP_Predalien_Move_Melee_WalkClawLeft_Start::AVP_Predalien_Move_Melee_WalkClawLeft_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawLeftStart",
		 AVP_Predalien_Move_Melee_WalkClawLeft_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_WalkClawLeft_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_WalkClawLeft_Return_Miss::GetStaticHash())
		 , m_fAnimTime(0.0f)
		 , m_xTargetStartPosition(Asura_Maths::ZeroVector3)
		 , m_uTarget(ASURA_GUID_UNREGISTERED)
		 , m_fVelocityMultiplier(1.0f)
{
	SetPositionUsage(POSITION_SET_FROM_VELOCITY);
	SetOrientationUsage(ORIENTATION_SET_DIRECTLY);
	SetAimDirectionUsage(AVP_ClientEntity_Actor::AIM_DIRECTION_RESET);
	SetLookAtPositionUsage(AVP_ClientEntity_Actor::LOOK_AT_POSITION_RESET);
	m_bDisableSurfaceReorientation = true;

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

}

bool AVP_Predalien_Move_Melee_WalkClawLeft_Start::Start( const Asura_Msg_Move* pxStartMsg )
{
	if (!pxStartMsg) { return false; }

	bool bResult = PARENT::Start(pxStartMsg);

	const AVP_Msg_Melee_Move* pxMeleeStart = static_cast< const AVP_Msg_Melee_Move* >( pxStartMsg );

	AVP_ClientEntity_Actor& xOwner = GetAVPParentSystem().GetActorOwner();

	// Get an upright orientation to interpolate to.
	m_uTarget = pxMeleeStart->GetTargetGuid();
	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );
	if ( !pxTarget ) { return false; }

	Asura_Matrix_3x3 xOri;
	Asura_Vector_3 xTargetOffset = pxTarget->GetCurrentPosition() - xOwner.GetCurrentPosition();
	xTargetOffset.y = 0.0f;	
	if (m_pxAVPAnimationData && m_pxAVPAnimationData->HasValidAnimation())
	{
		m_fAnimTime = m_pxAVPAnimationData->GetAnimationDuration();
	}
	else
	{
		m_fAnimTime = 1.0f;
	}
	m_xTargetStartPosition =  pxTarget->GetCurrentPosition();
	if (xTargetOffset.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		Asura_Euler_3 xEuler;
		xEuler.FromMatrix(xOwner.GetCurrentOrientation());
		xEuler.x = xEuler.z = 0.0f;
		xEuler.ToMatrix(xOri);
		m_fVelocityMultiplier = 1.0f;
	}
	else
	{
		float fTargetOffset = xTargetOffset.Normalise();
		m_fVelocityMultiplier = (fTargetOffset - dbg_fOptimalDisatnceFromPlayer) / dbg_fWalkSwipeAnimDistance;

		Asura_Maths::OrientationFromDirection(xOri, xTargetOffset);
	}
	SetOrientationUsage(ORIENTATION_SET_DIRECTLY);

	return bResult;
}

bool AVP_Predalien_Move_Melee_WalkClawLeft_Start::CalculateVelocity(const float fTimeStep, Asura_AVector3_OutParam xVelocity) const
{
	Asura_AVector3 xRefVelocity;
	bool bResult = PARENT::CalculateVelocity(fTimeStep, xRefVelocity);
	float fRefVelocity = xRefVelocity.Magnitude();

	if (xRefVelocity.ApproximatelyEquals(Asura_Maths::ZeroAVector3))
	{
		xVelocity = xRefVelocity; 
		return bResult;
	}


	xRefVelocity /= fRefVelocity;
	xRefVelocity *= m_fVelocityMultiplier;

	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );

	if ( !pxTarget || m_fAnimTime <= 0.0f ) 
	{
		xVelocity = xRefVelocity * fRefVelocity;
		return bResult; 
	}

	Asura_Vector_3 xTargetVelocity = (pxTarget->GetCurrentPosition() - m_xTargetStartPosition) / fTimeStep;
	m_xTargetStartPosition =  pxTarget->GetCurrentPosition();
	float fTargetVelocity = xTargetVelocity.Normalise();

	if ((Asura_Vector_3(xRefVelocity) * xTargetVelocity) <= 0.0f) // target moving towards us - return the animation velocity
	{
		xVelocity = xRefVelocity * fRefVelocity;
		return bResult; 
	}

	xVelocity = xRefVelocity * (fRefVelocity + fTargetVelocity * (Asura_Vector_3(xRefVelocity) * xTargetVelocity));

	return bResult;
}

bool AVP_Predalien_Move_Melee_WalkClawLeft_Start::CalculateOrientation(const float fTimeStep, Asura_Quat& xOrientation) const
{
	const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity( m_uTarget );
	const AVP_ClientEntity_Actor& xOwner = GetAVPParentSystem().GetActorOwner();
	const Asura_Matrix_3x3& xOwnerOri = xOwner.GetCurrentOrientation();

	if ( !pxTarget ) 
	{
		xOrientation.FromMatrix(xOwnerOri); // keep current orientation
		return false; 
	}

	Asura_Vector_3 xTargetOffset = pxTarget->GetCurrentPosition() - xOwner.GetCurrentPosition();
	xTargetOffset.y = 0.0f;	
	if (xTargetOffset.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		xOrientation.FromMatrix(xOwnerOri); // keep current orientation
	}
	else
	{
		const Asura_Vector_3 xForward(xOwnerOri.e13, xOwnerOri.e23, xOwnerOri.e33);
		xTargetOffset.Normalise();
		if (xForward * xTargetOffset > fTimeStep * dbg_fStandAttackMaxTurnSpeed) // small enough turn - just set new orientation
		{
			Asura_Matrix_3x3 xNewOrientation;
			Asura_Maths::OrientationFromDirection(xNewOrientation, xTargetOffset);
			xOrientation.FromMatrix(xNewOrientation);
		}
		else // turn is too much - turn as much as possible
		{
			const Asura_Vector_3 xRight(xOwnerOri.e12, xOwnerOri.e22, xOwnerOri.e32);
			const Asura_Vector_3 xUp(0.0f, -1.0f, 0.0f);
			float fTurnDirection = xRight * xTargetOffset > 0.0f ? 1.0f : -1.0f;
			Asura_Quat xTurn;

			xTurn.FromRotation(fTurnDirection* fTimeStep * dbg_fStandAttackMaxTurnSpeed, xUp);
			Asura_Vector_3 xNewDirection = xTurn.RotateVector(xForward);
			Asura_Matrix_3x3 xNewOrientation;
			Asura_Maths::OrientationFromDirection(xNewOrientation, xNewDirection);
			xOrientation.FromMatrix(xNewOrientation);
		}
	}
	// don't wait for this to finish
	return false;
}

void AVP_Predalien_Move_Melee_WalkClawLeft_Start::UpdateStates(const float fTimeStep)
{
	Asura_Quat xOrientation;
	CalculateOrientation(false, xOrientation);
	m_xParentSystem.SetCurrentMoveOrientation(xOrientation);
	PARENT::UpdateStates(fTimeStep);

}

AVP_Predalien_Move_Melee_WalkClawLeft_Return_Hit::AVP_Predalien_Move_Melee_WalkClawLeft_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawLeftHit")
{

}

AVP_Predalien_Move_Melee_WalkClawLeft_Return_Countered::AVP_Predalien_Move_Melee_WalkClawLeft_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawLeftCountered")
{
}

AVP_Predalien_Move_Melee_WalkClawLeft_Return_Miss::AVP_Predalien_Move_Melee_WalkClawLeft_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "WalkSwipeClawLeftMiss")
{
}

////////////////////////////////////////////////////////////////////////////////
// Stand -> Leap Attack
////////////////////////////////////////////////////////////////////////////////

DEBUGVAR float dbg_fStartGrappleOptimalDistance = 0.85f;
DEBUGVAR float dbg_fMaxTargetOrthoVelocity = 6.0f;

AVP_Predalien_Move_Melee_LeapAttack_Telegraph::AVP_Predalien_Move_Melee_LeapAttack_Telegraph(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xd1467e34 , xValue ) ) /* "LeapAttackTelegraph" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.25f, 0.0f, true );
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}

	AddNextMove( AVP_Predalien_Move_Melee_LeapAttack_Start::GetStaticHash() );

}

bool AVP_Predalien_Move_Melee_LeapAttack_Telegraph::Start(const Asura_Msg_Move* pxStartMsg)
{
	if(pxStartMsg == NULL)
	{
		Asura_Assert(false, "Predalien Leap attack can only be triggered by message.");
		return(false);
	}
	else
	{

		AVP_Predalien_Move_Melee_LeapAttack_Start* pxNextMove = static_cast<AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetMove(AVP_Predalien_Move_Melee_LeapAttack_Start::GetStaticHash()));
		if (!pxNextMove->SetFromMessage(pxStartMsg))
		{
			return false;
		}
		
	}

	const AVP_Msg_MeleeWithTargetPosition_Move* pxMeleeStart = static_cast<const AVP_Msg_MeleeWithTargetPosition_Move*>(pxStartMsg);

	Asura_Vector_3 xToTarget = pxMeleeStart->GetTargetPosition() - GetAVPParentSystem().GetActorOwner().GetCurrentPosition();
	xToTarget.Normalise();
	Asura_Matrix_3x3 xOri;

	Asura_Maths::OrientationFromDirection(xOri, xToTarget);
	m_xOrientationInterpolationData.SetInitial(GetAVPParentSystem().GetActorOwner().GetCurrentOrientation());
	m_xOrientationInterpolationData.SetFinal(xOri);
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		m_xOrientationInterpolationData.SetDuration(m_pxAVPAnimationData->GetAnimationDuration());
	}
	else
	{
		m_xOrientationInterpolationData.SetDuration(0.5f);
	}

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

AVP_Predalien_Move_Melee_LeapAttack_HitWall::AVP_Predalien_Move_Melee_LeapAttack_HitWall(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xbfdebe2d , xValue ) ) /* "LeapAttackHitWall" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
// 	if (m_pxAVPAnimationData)
// 	{
// 		m_pxAVPAnimationData->SetTweenData( 0.25f, 0.0f, true );
// 	}
}

bool AVP_Predalien_Move_Melee_LeapAttack_HitWall::ShouldStart() const
{
	const AVP_Predalien_Move_Melee_LeapAttack_Start* pxCurrentMove = static_cast<const AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetCurrentMove());
	if (pxCurrentMove)
	{
		if (pxCurrentMove->ShouldHitWall())
		{
			return true;
		}
	}

	return false;
}

AVP_Predalien_Move_Melee_LeapAttack_Start::AVP_Predalien_Move_Melee_LeapAttack_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "LeapAttackStart",
		 AVP_Predalien_Move_Melee_LeapAttack_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_LeapAttack_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_LeapAttack_Return_Miss::GetStaticHash())
, m_xTargetPosition(Asura_Maths::ZeroVector3)
, m_xToTargetDirection(Asura_Maths::ZeroVector3)
, m_fToTargetDistance(0.0f)
, m_uTargetGuid(ASURA_GUID_UNREGISTERED)
, m_xOrientationInterpolationDummy()
, m_bHitWall(false)
, m_bShouldGrapple(false)
{

	m_bClearQueuedMeleeRequests = true;
	SetGravityIgnored(true);
	SetPositionUsage(POSITION_SET_FROM_VELOCITY);
	// Remove the default generic start aiming behaviour
	SetAimDirectionUsage(AVP_ClientEntity_Actor::AIM_DIRECTION_RESET);

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData(0.0f, 0.0f, false);
	}

	AddNextMove(AVP_Predalient_Move_Melee_PredatorGrapple_Start::GetStaticHash());
	AddNextMove(AVP_Predalien_Move_Melee_LeapAttack_HitWall::GetStaticHash());

}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::SetFromMessage(const Asura_Msg_Move* pxStartMsg)
{
	// The message has to be a AVP_Msg_MeleeWithTargetPosition_Move.
	const AVP_Msg_MeleeWithTargetPosition_Move* pxMeleeStart = static_cast<const AVP_Msg_MeleeWithTargetPosition_Move*>(pxStartMsg);

	SetVariation(pxMeleeStart->GetVariation());
	m_xTargetPosition = pxMeleeStart->GetTargetPosition();
	m_uTargetGuid = pxMeleeStart->GetTargetGuid();

	return true;
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::ShouldGrapple() const
{
	return m_bShouldGrapple;
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::ShouldHitWall() const
{
	return m_bHitWall;
}


bool AVP_Predalien_Move_Melee_LeapAttack_Start::Start(const Asura_Msg_Move* pxStartMsg)
{

	m_bHitWall = false;
	m_bShouldGrapple = false;

	// This has to be started by from previous move.
	if (pxStartMsg) {
		Asura_Assert(false, "Predalien Leap attack can only follow telegraph move");
		return false; 
	}

	if (!m_pxAVPAnimationData) 
	{ 
		return false;
	}

	// We need to ensure the correct anim hash is set up, as it's about to get used.
	m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
	
	m_fAnimationTime = m_pxAVPAnimationData->GetAnimationDuration();

 	InitialiseOrientationInterpolation(m_xOrientationInterpolationDummy);

	SetOrientationUsage(ORIENTATION_SET_DIRECTLY);

	if(!PARENT::Start(pxStartMsg))
	{
		return false;
	}

	return true;
}

void AVP_Predalien_Move_Melee_LeapAttack_Start::CheckStatesToStart()
{
//	bool bHasController = m_pxAVPAnimationData->GetAnimationController() != NULL;
	
	PARENT::CheckStatesToStart();

// 	Asura_AnimationController_Animation* pxAnimationController	= m_pxAVPAnimationData->GetAnimationController();
// 	if (!bHasController && pxAnimationController)
// 	{
// 		const AVP_ClientEntity_Actor* pxTarget = AVP_ClientEntity_Actor::FindEntity(m_uTargetGuid);
// 		if (!pxTarget)
// 		{
// 			return;
// 		}
// 
// 		float fActualDistance = (pxTarget->GetCurrentPosition() - GetAVPParentSystem().GetActorOwner().GetCurrentPosition()).Magnitude() - dbg_fStartGrappleOptimalDistance;
// 
// 		Asura_AVector3 xAnimationOffset;
// 		Asura_Quat xDummy;
// 		m_pxAVPAnimationData->CalculateMovementOffset(1.0f, &xAnimationOffset, &xDummy );
// 
// 		float fAnimationOffset = xAnimationOffset.Magnitude();
// 
		// m_fAnimationTime *= fActualDistance / fAnimationOffset;
//	}
}


void AVP_Predalien_Move_Melee_LeapAttack_Start::UpdateStates(const float fTimeStep)
{
	UpdateShouldHitWall();
	UpdateTargetPosition(fTimeStep);
	PARENT::UpdateStates(fTimeStep);
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::CalculateVelocity(const float fTimeStep, Asura_AVector3_OutParam xVelocity) const
{
 
	float fToTarget = Asura_Maths::Max(m_fToTargetDistance - dbg_fStartGrappleOptimalDistance, 0.0f);

	if ( m_fAnimationTime < 0.08f)
	{
		xVelocity = Asura_Maths::ZeroVector3;
	}
	else
	{
		xVelocity = m_xToTargetDirection * fToTarget / m_fAnimationTime;			
	}

	m_fAnimationTime = Asura_Maths::Max ( m_fAnimationTime - fTimeStep, 0.0f); 

	return false;
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::CalculateOrientation(const float fTimeStep, Asura_Quat& xOrientation) const
{
	Asura_Matrix_3x3 xOriM;
	Asura_Vector_3 xFlatToTargetDirection = m_xToTargetDirection;
	xFlatToTargetDirection.y = 0.0f;
	if (xFlatToTargetDirection.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		return false;
	}
	xFlatToTargetDirection.Normalise();
	Asura_Maths::OrientationFromDirection(xOriM, xFlatToTargetDirection);
	xOrientation.FromMatrix(xOriM);
	return false;
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::HasFinished() const
{
	if (m_bHitWall)
	{
		return true;
	}
	else
	{
		return PARENT::HasFinished();
	}
}

bool AVP_Predalien_Move_Melee_LeapAttack_Start::HandleMessage( const Asura_Message* pxMessage )
{
	if (pxMessage->GetMsgID() == AVP_MSGID_MELEE_ATTACK_HIT)
	{
		const AVP_Msg_Melee_Attack_Hit* pxData = static_cast<const AVP_Msg_Melee_Attack_Hit*>(pxMessage->GetData());
		// We can't afford to skip a valid hit entity, so only set the flag if we have data.
		if (pxData)
		{
			m_bShouldGrapple =  pxData->GetPendingAttackType() == AVP_PREDPREDALIEN_MELEEATTACK_TYPE_LEAP_ATTACK_DO_GRAPPLE;
		}
		return PARENT::HandleMessage(pxMessage);		
	}

	return PARENT::HandleMessage(pxMessage);

}


void AVP_Predalien_Move_Melee_LeapAttack_Start::UpdateTargetPosition(float fTimeStep) 
{

	if(!Asura_Network::IsServer()) // really only matter for the client on the server side
	{
		return;
	}

	const AVP_ServerEntity_Actor* pxTarget = AVP_ServerEntity_Actor::FindEntity(m_uTargetGuid);
	if (!pxTarget)
	{
		return;
	}

	Asura_Vector_3 xOldToNewTargetPosition = pxTarget->GetPosition() - m_xTargetPosition;
	Asura_Vector_3 xOwnerToOldTargetPosDirection = m_xTargetPosition - GetAVPParentSystem().GetActorOwner().GetCurrentPosition();
	xOwnerToOldTargetPosDirection.Normalise();
    // split the movement to the owner-target direction and orthogonal to that direction
	Asura_Vector_3 xPerpendicular = xOwnerToOldTargetPosDirection * (xOldToNewTargetPosition * xOwnerToOldTargetPosDirection);
	Asura_Vector_3 xOrthogonal = xOldToNewTargetPosition - xPerpendicular;
	float fOrthogonal = xOrthogonal.Normalise();
	if (fOrthogonal < dbg_fMaxTargetOrthoVelocity * fTimeStep)
	{
		m_xTargetPosition = pxTarget->GetPosition();
	}
	else
	{
		m_xTargetPosition += xPerpendicular + xOrthogonal * dbg_fMaxTargetOrthoVelocity * fTimeStep;
	}

	m_xToTargetDirection = m_xTargetPosition - GetAVPParentSystem().GetActorOwner().GetCurrentPosition();;
	m_xToTargetDirection.y = 0.0f; // ignore hight 
	if (m_xToTargetDirection.ApproximatelyEquals(Asura_Maths::ZeroVector3))
	{
		m_fToTargetDistance = 0.0f;
	}
	else
	{
		m_fToTargetDistance = m_xToTargetDirection.Normalise();
	}
}

DEBUGVAR float dbg_fDisplacement = 3.0f;
DEBUGVAR float dbg_fDisplacementAngleCosine = Asura_Maths::Cosine(Asura_Maths::DegToRad(30.0f));
DEBUGVAR float dbg_fDisplacementFraction = 0.33f;

void AVP_Predalien_Move_Melee_LeapAttack_Start::UpdateShouldHitWall()
{
	m_bHitWall = false;
	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();
		}
	}

	const Asura_Physics_Object* pxPhyObj = pxPhyHandler ?  pxPhyHandler->GetPhysicsObject() : NULL;
	const Asura_Collision_Object* pxCollObj = pxPhyObj ?  pxPhyObj->GetCollisionObject() : NULL;
	if (!pxCollObj) 
	{
		return;
	}

	const Asura_AVector3 xStartPosition = Asura_AVector3( pxPhyObj->GetPosition() );
	const Asura_Matrix_3x3& xOurOrientation = pxPhyObj->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_SPHERESTACK,
		AsuraPolygonFlag_NoCollisions | AVP_PolygonFlag_IgnoreForPhysicsObjectCollision,
		false,
		true); 

	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))
	{
		m_bHitWall = true;
		return;
	}

	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 < dbg_fDisplacementAngleCosine)
	{
		m_bHitWall = true;
		return;
	}

	// Distance check, how far have we actually moved in comparison to how far we wanted to move
	if (fActualDist < (fDesiredDist * dbg_fDisplacementFraction))
	{
		m_bHitWall = true;
		return;
	}	
}


AVP_Predalien_Move_Melee_LeapAttack_Return_Hit::AVP_Predalien_Move_Melee_LeapAttack_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "LeapAttackHit")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.05f, false);
	}
}

bool AVP_Predalien_Move_Melee_LeapAttack_Return_Hit::ShouldStart() const
{
	const AVP_Predalien_Move_Melee_LeapAttack_Start* pxCurrentMove = static_cast<const AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetCurrentMove());
	if (pxCurrentMove)
	{
		if (pxCurrentMove->ShouldHitWall())
		{
			return false;
		}
		if (pxCurrentMove->ShouldGrapple())
		{
			return false;
		}
	}

	return PARENT::ShouldStart();
}

AVP_Predalien_Move_Melee_LeapAttack_Return_Countered::AVP_Predalien_Move_Melee_LeapAttack_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "LeapAttackCountered")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.05f, false);
	}
}

bool AVP_Predalien_Move_Melee_LeapAttack_Return_Countered::ShouldStart() const
{
	const AVP_Predalien_Move_Melee_LeapAttack_Start* pxCurrentMove = static_cast<const AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetCurrentMove());
	if (pxCurrentMove)
	{
		if (pxCurrentMove->ShouldHitWall())
		{
			return false;
		}
		if (pxCurrentMove->ShouldGrapple())
		{
			return false;
		}
	}

	return PARENT::ShouldStart();
}


AVP_Predalien_Move_Melee_LeapAttack_Return_Miss::AVP_Predalien_Move_Melee_LeapAttack_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "LeapAttackMiss")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.05f, false);
	}
}

bool AVP_Predalien_Move_Melee_LeapAttack_Return_Miss::ShouldStart() const
{
	const AVP_Predalien_Move_Melee_LeapAttack_Start* pxCurrentMove = static_cast<const AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetCurrentMove());
	if (pxCurrentMove)
	{
		if (pxCurrentMove->ShouldHitWall())
		{
			return false;
		}
		if (pxCurrentMove->ShouldGrapple())
		{
			return false;
		}
	}

	return PARENT::ShouldStart();
}


AVP_Predalient_Move_Melee_PredatorGrapple_Start::AVP_Predalient_Move_Melee_PredatorGrapple_Start(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash(),
		 AVP_Settings::AVP_SPECIES_ALIEN, AVP_Settings::AVP_SPECIES_PREDATOR, uAVP_BLUEPRINT_NAME_PREDALIENGRAPPLE_PREDATORVICTIM,
		 AVP_Predalien_Move_Melee_PredatorGrapple_Kill::GetStaticHash(), AVP_Predalien_Move_Melee_PredatorGrapple_Countered::GetStaticHash())
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.05f, false);
	}
}

bool AVP_Predalient_Move_Melee_PredatorGrapple_Start::ShouldStart() const
{
	if (!PARENT::ShouldStart())
	{
		return false;
	}

	const AVP_Predalien_Move_Melee_LeapAttack_Start* pxCurrentMove = static_cast<const AVP_Predalien_Move_Melee_LeapAttack_Start*>(GetParentSystem().GetCurrentMove());
	if (pxCurrentMove)
	{
		if (pxCurrentMove->ShouldHitWall())
		{
			return false;
		}

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

	return false;
}

AVP_Predalien_Move_Melee_PredatorGrapple_Kill::AVP_Predalien_Move_Melee_PredatorGrapple_Kill(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash(),
		 AVP_Settings::AVP_SPECIES_ALIEN, AVP_Settings::AVP_SPECIES_PREDATOR, uAVP_BLUEPRINT_NAME_PREDALIENGRAPPLE_PREDATORVICTIM)
{
	m_bAlwaysFatal = true;
}

AVP_Predalien_Move_Melee_PredatorGrapple_Countered::AVP_Predalien_Move_Melee_PredatorGrapple_Countered(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash(),
		 AVP_Settings::AVP_SPECIES_ALIEN, AVP_Settings::AVP_SPECIES_PREDATOR, uAVP_BLUEPRINT_NAME_PREDALIENGRAPPLE_PREDATORVICTIM)
{
}

////////////////////////////////////////////////////////////////////////////////
// Jump Down Attack
////////////////////////////////////////////////////////////////////////////////

AVP_Predalien_Move_Melee_JumpDownAttack_Start::AVP_Predalien_Move_Melee_JumpDownAttack_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0x16e7ef4a , xValue ) ) /* "JumpDownAttackStart" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.25f, 0.0f, true );
		m_pxAVPAnimationData->SetLeaveAnimAtEnd(true);
	}

	AddNextMove( AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown::GetStaticHash() );

}

bool AVP_Predalien_Move_Melee_JumpDownAttack_Start::Start(const Asura_Msg_Move* pxStartMsg)
{
	if(pxStartMsg == NULL)
	{
		Asura_Assert(false, "Predalien JumpDown attack can only be triggered by message.");
		return(false);
	}
	else
	{

		AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown* pxNextMove = static_cast<AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown*>(GetParentSystem().GetMove(AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown::GetStaticHash()));
		if (!pxNextMove->SetFromMessage(pxStartMsg))
		{
			return false;
		}
	}

	const AVP_Msg_MeleeWithTargetPosition_Move* pxMeleeStart = static_cast<const AVP_Msg_MeleeWithTargetPosition_Move*>(pxStartMsg);

	Asura_Vector_3 xToTarget = pxMeleeStart->GetTargetPosition() - GetAVPParentSystem().GetActorOwner().GetCurrentPosition();
	xToTarget.y = 0.0f; // only horizontal move
	float fToTarget = xToTarget.Normalise();

	if (fToTarget > 1.0f) // stop before the exact position - 
	{
		fToTarget -= 0.5;
	}

	m_xPositionInterpolationData.SetFinal(GetAVPParentSystem().GetActorOwner().GetCurrentPosition() + xToTarget * fToTarget);
	m_xPositionInterpolationData.SetMovementOffsetOperation(Asura_MoveData_PositionInterpolation::STRETCH_MOVEMENT_OFFSET);


	Asura_Matrix_3x3 xOri;
	Asura_Maths::OrientationFromDirection(xOri, xToTarget);
	m_xOrientationInterpolationData.SetInitial(GetAVPParentSystem().GetActorOwner().GetCurrentOrientation());
	m_xOrientationInterpolationData.SetFinal(xOri);
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		m_xOrientationInterpolationData.SetDuration(m_pxAVPAnimationData->GetAnimationDuration());
		m_xPositionInterpolationData.SetDuration(m_pxAVPAnimationData->GetAnimationDuration());
	}
	else
	{
		m_xOrientationInterpolationData.SetDuration(0.5f);
		m_xPositionInterpolationData.SetDuration(0.5f);
	}

	InitialisePositionInterpolation(m_xPositionInterpolationData);
	InitialiseOrientationInterpolation(m_xOrientationInterpolationData);
	return PARENT::Start(pxStartMsg);
}


AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown::AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "JumpDownAttackMoveDown",
		 AVP_Predalien_Move_Melee_JumpDownAttack_Return_Hit::GetStaticHash(), AVP_Predalien_Move_Melee_JumpDownAttack_Return_Countered::GetStaticHash(), AVP_Predalien_Move_Melee_JumpDownAttack_Return_Miss::GetStaticHash()) 
, m_xTargetPosition(Asura_Maths::ZeroVector3)
{
}

bool AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown::SetFromMessage(const Asura_Msg_Move* pxStartMsg)
{
	const AVP_Msg_MeleeWithTargetPosition_Move* pxMeleeStart = static_cast<const AVP_Msg_MeleeWithTargetPosition_Move*>(pxStartMsg);

	m_xTargetPosition  = pxMeleeStart->GetTargetPosition();

	return true;
}

bool AVP_Predalien_Move_Melee_JumpDownAttack_MoveDown::Start(const Asura_Msg_Move* pxStartMsg)
{
	
	m_xPositionInterpolationData.SetFinal(m_xTargetPosition);
	m_xPositionInterpolationData.SetMovementOffsetOperation(Asura_MoveData_PositionInterpolation::STRETCH_MOVEMENT_OFFSET);

	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		m_xPositionInterpolationData.SetDuration(m_pxAVPAnimationData->GetAnimationDuration());
	}
	else
	{
		m_xPositionInterpolationData.SetDuration(0.5f);
	}

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

AVP_Predalien_Move_Melee_JumpDownAttack_Return_Hit::AVP_Predalien_Move_Melee_JumpDownAttack_Return_Hit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "JumpDownHit")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.0f, false);
	}
}

AVP_Predalien_Move_Melee_JumpDownAttack_Return_Countered::AVP_Predalien_Move_Melee_JumpDownAttack_Return_Countered(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "JumpDownCountered")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.0f, false);
	}
}

AVP_Predalien_Move_Melee_JumpDownAttack_Return_Miss::AVP_Predalien_Move_Melee_JumpDownAttack_Return_Miss(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash(),
		 uAVP_BLUEPRINT_TYPE_MELEE, uFirstPersonBlueprintHash, uThirdPersonBlueprintHash, "JumpDownMiss")
{
	if (m_pxAVPAnimationData)
	{		
		m_pxAVPAnimationData->SetTweenData(0.1f, 0.0f, false);
	}
}

AVP_Predalien_Move_Melee_JumpDownAttack_SuperHit::AVP_Predalien_Move_Melee_JumpDownAttack_SuperHit(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xe647ba50 , xValue ) ) /* "JumpDownAttackSuperHit" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.25f, 0.0f, true );
	}
}

////////////////////////////////////////////////////////////////////////////////
// Being knocked down
////////////////////////////////////////////////////////////////////////////////
AVP_Predalien_Move_KnockedDown_Start::AVP_Predalien_Move_KnockedDown_Start(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xe5c448c9 , xValue ) ) /* "KnockedDown.Start" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.25f, 0.0f, true );
	}

	AddNextMove( AVP_Predalien_Move_KnockedDown_Middle::GetStaticHash() );

}

AVP_Predalien_Move_KnockedDown_Middle::AVP_Predalien_Move_KnockedDown_Middle(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xc7ede20e , xValue ) ) /* "KnockedDown.Middle" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.0f, 0.0f, true );
	}

	AddNextMove( AVP_Predalien_Move_KnockedDown_Finish::GetStaticHash() );

}

AVP_Predalien_Move_KnockedDown_Finish::AVP_Predalien_Move_KnockedDown_Finish(Asura_Movement_System& xParentSystem, Asura_Hash_ID uFirstPersonBlueprintHash, Asura_Hash_ID uThirdPersonBlueprintHash)
: PARENT(xParentSystem, GetStaticHash())
{
	Asura_Hash_ID uFPAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;


	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_MELEE, uThirdPersonBlueprintHash );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( 0xbc00950c , xValue ) ) /* "KnockedDown.Finish" */
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( uFPAnim, uTPAnim );

	// Only tween in to our anim.
	if (m_pxAVPAnimationData)
	{
		m_pxAVPAnimationData->SetTweenData( 0.0f, 0.0f, true );
	}
}

