
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Predator_MovesJump.cpp
// Author : Anthony Gregson
// Date   : 08/10/07
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Moves/Vertebrates/Predator/AVP_Predator_MovesJump.h"

// Asura independent header-files...

// Game independent header-files...
#include "Actor/AVP_Actor_InputHandler.h"
#include "Actor/AVP_Actor_PhysicsObjectHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_AnimationHandler.h"
#include "Actor/Vertebrates/Predator/AVP_Predator_JumpHandler.h"
#include "Animation/AVP_AnimFlags.h"
#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ClientActor_Predator.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_Messages_Predator.h"


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

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


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Move_Predator_PreJumpTarget
// Date         : 08/10/07
////////////////////////////////////////////////////////////////////////////////

AVP_Move_Predator_PreJumpTarget::AVP_Move_Predator_PreJumpTarget(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash())
{
	// Initialise the move flags...
	m_bDisableMovement	= true;
	m_eAimDirectionUsage = AVP_ClientEntity_Actor::AIM_DIRECTION_SET_DIRECTLY;
//	m_fAimDirectionLimitAngle = Asura_Maths::DegToRad( 60.0f );

	m_bPreventsFlinch = true;
	m_bClearQueuedMeleeRequests = true;
	m_bClearQueuedCounterRequest = true;
	m_bSupportEndAnimFlag = true;
	m_bPreventsFocus = true;

	AddNextMove(AVP_Move_Predator_JumpTarget::GetStaticHash());


}


bool AVP_Move_Predator_PreJumpTarget::Start(const Asura_Msg_Move* pxStartMsg)
{
	// Have we been told to start via a message?
	if(pxStartMsg == NULL)
	{
		Asura_Assert(false, "Predator jump-to-target move can only be triggered by message.");
		return(false);
	}
	else
	{

		AVP_Move_Predator_JumpTarget* pxNextMove = static_cast<AVP_Move_Predator_JumpTarget*>(GetParentSystem().GetMove(AVP_Move_Predator_JumpTarget::GetStaticHash()));
		pxNextMove->SetFromMessage(pxStartMsg);

		AVP_ClientActor_Predator& xPredatorOwner = static_cast<AVP_ClientActor_Predator&>(GetAVPParentSystem().GetActorOwner());

		const AVP_Message_Predator_Move_WalkAndJumpStart* pxMessage = static_cast<const AVP_Message_Predator_Move_WalkAndJumpStart*>(pxStartMsg);

		Asura_Vector_3 xTargetPosition(pxMessage->GetStartPosition());

		// Update the animation to use

		Asura_Vector_3 xFlatOffset = xTargetPosition - xPredatorOwner.GetCurrentPosition();
		xFlatOffset.y = 0.0f;
		const float fWalkDuration = xFlatOffset.Magnitude() / pxMessage->GetMoveSpeed() ;

		m_xPositionInterpolationData.SetDuration(fWalkDuration);
		m_xPositionInterpolationData.SetFinal(xTargetPosition);


		Asura_Vector_3 xCurrentHeading(xPredatorOwner.GetCurrentOrientation().e13, xPredatorOwner.GetCurrentOrientation().e23, xPredatorOwner.GetCurrentOrientation().e33);
		Asura_Vector_3 xDesiredHeading(pxMessage->GetDestinationPosition()-pxMessage->GetStartPosition());
		xDesiredHeading.y = 0.0f;
		xDesiredHeading.Normalise();

		Asura_Matrix_3x3 xOri;
		Asura_Quat xTurnQuat;
		xTurnQuat.RotationFromAToB(xCurrentHeading, xDesiredHeading);
		Asura_Vector_3 xTurnAxis;
		float fTurnAngle = xTurnQuat.ToRotation(xTurnAxis);
		float fTurnDuration = fTurnAngle / pxMessage->GetTurnSpeed();

		if (fTurnDuration >= fWalkDuration) // if turn take too much time - turn how much we can
		{
			fTurnAngle = fTurnAngle * fWalkDuration / fTurnDuration;
			xTurnQuat.FromRotation(fTurnAngle, xTurnAxis);
			xDesiredHeading = xTurnQuat.RotateVector(xCurrentHeading);
			fTurnDuration = fWalkDuration;
		}


		Asura_Maths::OrientationFromDirection(xOri, xDesiredHeading);
		m_xOrientationInterpolationData.SetFinal(xOri);
		m_xOrientationInterpolationData.SetDuration(fTurnDuration);

		InitialisePositionInterpolation(m_xPositionInterpolationData);
		InitialiseOrientationInterpolation(m_xOrientationInterpolationData);
		m_xAimDirection = xDesiredHeading;
		m_fAimDirectionAngVel = pxMessage->GetTurnSpeed();
		

		// Finally, call the base-function...
		return(PARENT::Start(pxStartMsg));
	}
}

/// End of function 'AVP_Move_Predator_JumpTarget::Start'. ///

Asura_Move* AVP_Move_Predator_PreJumpTarget::Update()
{
//	const u_int uAnimFlags = GetAnimFlagsForLastFrame();
//	SetAimDirectionUsage(((uAnimFlags & AVP_ANIMFLAG_RESET_LOOK) != 0) ? AVP_ClientEntity_Actor::AIM_DIRECTION_RESET : AVP_ClientEntity_Actor::AIM_DIRECTION_LIMIT);

	return PARENT::Update();
}


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Move_Predator_JumpTarget::AVP_Move_Predator_JumpTarget
// Author       : Anthony Gregson
// Date         : 08/10/07
////////////////////////////////////////////////////////////////////////////////
DEBUGVAR float dbg_fPlayerJumpTargetLimitAngle = 30.0f * Asura_Maths::DegToRadConstant;

AVP_Move_Predator_JumpTarget::AVP_Move_Predator_JumpTarget(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash())
{
	// Initialise the move flags...
	m_bDisableMovement	= true;
	m_eAimDirectionUsage = AVP_ClientEntity_Actor::AIM_DIRECTION_RESET;
	const AVP_Movement_System& xAVPSystem = static_cast<AVP_Movement_System&>(xParentSystem);
	if (xAVPSystem.GetActorOwner().IsPlayer())
	{
		m_fAimDirectionLimitAngle = dbg_fPlayerJumpTargetLimitAngle;
	}

	m_bPreventsFlinch = true;
	m_bClearQueuedMeleeRequests = true;
	m_bClearQueuedCounterRequest = true;
	m_bSupportEndAnimFlag = true;

	// TODO - setup third person anims and use blueprints.
	SetAnimHashes(0xD6197979, 0xD6197979); //Asura_GetHashID("predator_hud_running_jump_5m");

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

/// End of function 'AVP_Move_Predator_JumpTarget::AVP_Move_Predator_JumpTarget'. ///

///////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Move_Predator_JumpTarget::Start
// Author       : Anthony Gregson
// Date         : 08/10/07
////////////////////////////////////////////////////////////////////////////////

bool AVP_Move_Predator_JumpTarget::Start(const Asura_Msg_Move* pxStartMsg)
{
	// Have we been told to start via a message?
	if(pxStartMsg)
	{
		SetFromMessage(pxStartMsg);
	}

	InitialisePositionInterpolation(m_xPositionInterpolationData);
	InitialiseOrientationInterpolation(m_xOrientationInterpolationData);
	
	AVP_ClientActor_Predator& xPredatorOwner = static_cast<AVP_ClientActor_Predator&>(GetAVPParentSystem().GetActorOwner());
	xPredatorOwner.OnBeginTargetedJump();

	// Finally, call the base-function...
	return(PARENT::Start(pxStartMsg));
}

void AVP_Move_Predator_JumpTarget::SetFromMessage(const Asura_Msg_Move* pxStartMsg)
{
	const AVP_Message_Predator_Move_JumpStart* pxMessage = static_cast<const AVP_Message_Predator_Move_JumpStart*>(pxStartMsg);
	AVP_ClientActor_Predator& xPredatorOwner = static_cast<AVP_ClientActor_Predator&>(GetAVPParentSystem().GetActorOwner());
	Asura_Vector_3 xTargetPosition(pxMessage->GetDestinationPosition());

	// Update the animation to use
	Asura_Hash_ID uFirstPersonAnim = ASURA_HASH_ID_UNSET;
	Asura_Hash_ID uThirdPersonAnim = ASURA_HASH_ID_UNSET;
	xPredatorOwner.GetTargetedJumpAnimationsForVariation(pxMessage->GetJumpVariation(), uFirstPersonAnim, uThirdPersonAnim);
	xPredatorOwner.SetJumpLandType( pxMessage->GetJumpLandType() );
	SetAnimHashes(uFirstPersonAnim, uThirdPersonAnim);

	if (m_pxAVPAnimationData)
	{
		// We need to ensure the correct anim hash is set up, as it's about to get used.
		if (xPredatorOwner.IsUsingFirstPersonSkin())
		{
			m_pxAVPAnimationData->SetAnimHash(m_uFirstPersonAnimHash);
		}
		else
		{
			m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		}
	}

	const bool bHasAnimation = m_pxAVPAnimationData && m_pxAVPAnimationData->HasValidAnimation();
	const float fDuration = (bHasAnimation) ? m_pxAVPAnimationData->GetAnimationDuration() : 0.500f;

	// For the time being we'll just move and rotate to our desired position...
	if(bHasAnimation)
	{
		m_xPositionInterpolationData.SetMovementOffsetOperation(Asura_MoveData_PositionInterpolation::STRETCH_MOVEMENT_OFFSET);
		m_xOrientationInterpolationData.SetMovementOffsetOperation(Asura_MoveData_OrientationInterpolation::STRETCH_MOVEMENT_OFFSET);
	}

	m_xPositionInterpolationData.SetDuration(fDuration);
	m_xPositionInterpolationData.SetFinal(xTargetPosition);

	float fTurnDuration = pxMessage->GetTurnTime() < fDuration ? pxMessage->GetTurnTime() : fDuration;

	m_xOrientationInterpolationData.SetDuration(fTurnDuration);
	Asura_Vector_3 xFlatOffset = xTargetPosition - xPredatorOwner.GetCurrentPosition();
	xFlatOffset.y = 0.0f;
	if (xFlatOffset.MagnitudeSquared() > 0.01f)
	{
		xFlatOffset.Normalise();
		Asura_Matrix_3x3 xOri;
		Asura_Maths::OrientationFromDirection(xOri, xFlatOffset);
		m_xOrientationInterpolationData.SetFinal(xOri);
	}
	else
	{
		const Asura_Matrix_3x3& xOri = xPredatorOwner.GetCurrentOrientation();
		m_xOrientationInterpolationData.SetFinal(xOri);
		xFlatOffset.x = xOri.e13;
		xFlatOffset.y = xOri.e23;
		xFlatOffset.z = xOri.e33;
	}

	m_xAimDirection = xFlatOffset;
}

Asura_Move* AVP_Move_Predator_JumpTarget::Update()
{
	const u_int uAnimFlags = GetAnimFlagsForLastFrame();
	SetAimDirectionUsage(((uAnimFlags & AVP_ANIMFLAG_RESET_LOOK) != 0) ? AVP_ClientEntity_Actor::AIM_DIRECTION_RESET : AVP_ClientEntity_Actor::AIM_DIRECTION_LIMIT);

	return PARENT::Update();
}

void AVP_Move_Predator_JumpTarget::Abort(void)
{
	AVP_ClientActor_Predator& xPredatorOwner = static_cast<AVP_ClientActor_Predator&>(GetAVPParentSystem().GetActorOwner());

	xPredatorOwner.OnEndTargetedJump();
	PARENT::Abort();
}

void AVP_Move_Predator_JumpTarget::Finish(void)
{
	AVP_ClientActor_Predator& xPredatorOwner = static_cast<AVP_ClientActor_Predator&>(GetAVPParentSystem().GetActorOwner());

	xPredatorOwner.OnEndTargetedJump();
	PARENT::Finish();
}



/// End of file. ///
