
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Move_Interaction.cpp
// Author : Will Plano
// Date   : 12/06/2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Moves/AVP_Move_Interaction.h"

#include "Actor/AVP_Actor_AnimStateData.h"
#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Interact/AVP_ClientEntity_InteractObject.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/AVP_InventoryItem_Weapon.h"
#include "Moves/Vertebrates/Human/AVP_Human_MovesInteraction.h"

AVP_Move_Interaction_BeginWeaponAway::AVP_Move_Interaction_BeginWeaponAway( Asura_Movement_System& xParentSystem )
: PARENT( xParentSystem, GetStaticHash() )
, m_uInteractionGuid( ASURA_GUID_UNREGISTERED )
, m_uNextMoveHash( ASURA_HASH_ID_UNSET )
, m_bOn( false )
{
	// Initialise the move flags...
	m_bClearQueuedCounterRequest	= true;
	m_bClearQueuedMeleeRequests		= true;
	m_bPreventsFlinch				= true;
	m_bDisableMovement				= true;
	m_eAimDirectionUsage			= AVP_ClientEntity_Actor::AIM_DIRECTION_RESET;

	AddNextMove( AVP_Move_Interaction::GetStaticHash() );
}

bool AVP_Move_Interaction_BeginWeaponAway::Start( const Asura_Msg_Move* pxStartMsg )
{
	// Have we been told to start via a message?
	if ( pxStartMsg == NULL )
	{
		Asura_Assert( false, "Interaction move can only be triggered by message." );
		return false;
	}
	else
	{
		const AVP_Message_InteractionMoveStart*	pxMessage = static_cast< const AVP_Message_InteractionMoveStart* >( pxStartMsg );
		// We need to ensure the correct anim hash is set up, as it's about to get used.
		m_uInteractionGuid = pxMessage->GetInteractionObject();
		m_bOn = pxMessage->GetOn();
		m_uNextMoveHash = pxMessage->GetNextMoveHash();
		AVP_ClientEntity_InteractObject* pxInteractObject = AVP_ClientEntity_InteractObject::FindEntity( m_uInteractionGuid );
		Asura_Assertf( pxInteractObject, ( "Unable to find client side interaction object %d to interact with", m_uInteractionGuid ) );
		if ( pxInteractObject == NULL )
		{
			return false;
		}
		else
		{
			AVP_ClientEntity_Actor* pxActor = AVP_ClientEntity_Actor::FindEntity( GetParentSystem().GetOwnerGuid() );
			Asura_Assert( pxActor, "Only actors should be interacting" );
			if ( !pxActor || !pxActor->GetAnimationHandler() )
			{
				return false;
			}
			else
			{
				// play the weapon anim
				AVP_Inventory_System* pxInvSys = pxActor->GetInventorySystem();
				AVP_InventoryItem_Weapon* pxWeapon = pxInvSys ? static_cast < AVP_InventoryItem_Weapon* >( pxInvSys->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON ) ) : NULL;
				if ( pxWeapon )
				{
					pxWeapon->PlayDeactivationWeaponAnim();
				}

				Asura_Hash_ID uWeaponOutAnim = ASURA_HASH_ID_UNSET;
				const AVP_Actor_AnimStateData* pxStateData = pxActor->GetCurrentAnimStateData();
				if ( pxStateData )
				{
					uWeaponOutAnim = pxStateData->GetWeaponOutActorAnimHash();
				}

				SetAnimHashes( uWeaponOutAnim, uWeaponOutAnim );
				if ( m_pxAVPAnimationData )
				{
					m_pxAVPAnimationData->SetTweenData( 0.1f, 0.0f, true );
					m_pxAVPAnimationData->SetLeaveAnimAtEnd( true );
					m_pxAVPAnimationData->SetAnimPriority( AVP_AAPC_WEAPON_ANIM );
					m_pxAVPAnimationData->SetControllerGroupHash( pxActor->GetAnimationHandler()->GetWeaponGroupHash() );
				}

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

AVP_Move_Interaction::AVP_Move_Interaction( Asura_Movement_System& xParentSystem )
: PARENT( xParentSystem, GetStaticHash() )
{
	// Initialise the move flags...
	m_bClearQueuedCounterRequest	= true;
	m_bClearQueuedMeleeRequests		= true;
	m_bPreventsFlinch				= true;
	m_bDisableMovement				= true;
	m_eAimDirectionUsage			= AVP_ClientEntity_Actor::AIM_DIRECTION_RESET;
	m_bHideReticle					= true;

	AddNextMove( AVP_Move_Interaction_EndWeaponBack::GetStaticHash() );
}

bool AVP_Move_Interaction::Start( const Asura_Msg_Move* pxStartMsg )
{
	// Have we been told to start via a message?
	if ( pxStartMsg != NULL )
	{
		Asura_Assert( false, "Interaction move can not be triggered by message." );
		return false;
	}
	else
	{
		const Asura_Move* pxMove = GetParentSystem().GetCurrentMove();
		if ( pxMove->GetHash() != AVP_Move_Interaction_BeginWeaponAway::GetStaticHash() )
		{
			Asura_Assert( false, "Can only be started from AVP_Move_Interaction_Begin" );
			return false;
		}
		const AVP_Move_Interaction_BeginWeaponAway* pxIntBeginMove = static_cast< const AVP_Move_Interaction_BeginWeaponAway* >( pxMove );

		Asura_Guid uInteractionGuid = pxIntBeginMove->GetInteractionObject();
		bool bOn = pxIntBeginMove->GetOn();

		AVP_ClientEntity_InteractObject* pxInteractObject = AVP_ClientEntity_InteractObject::FindEntity( uInteractionGuid );
		Asura_Assertf( pxInteractObject, ( "Unable to find client side interaction object %d to interact with", uInteractionGuid ) );
		if ( pxInteractObject == NULL )
		{
			return false;
		}
		else
		{
			AVP_ClientEntity_Actor* pxActor = AVP_ClientEntity_Actor::FindEntity( GetParentSystem().GetOwnerGuid() );
			Asura_Assert( pxActor, "Only actors should be interacting" );
			if ( !pxActor || !pxActor->GetAnimationHandler() )
			{
				return false;
			}
			else
			{
				pxActor->DeactivateCurrentWeapon();

				const AVP_ClientEntity_InteractObject::AnimData xAnimData = pxInteractObject->GetInteractionData( *pxActor, bOn );

				// play the object anim
				if ( xAnimData.m_uObjectAnim != ASURA_HASH_ID_UNSET )
				{
					pxInteractObject->PlayAnimation( xAnimData.m_uObjectAnim );
				}

				// play the weapon anim
				AVP_Inventory_System* pxInvSys = pxActor->GetInventorySystem();
				AVP_InventoryItem_Weapon* pxWeapon = pxInvSys ? static_cast < AVP_InventoryItem_Weapon* >( pxInvSys->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON ) ) : NULL;
				if ( pxWeapon && xAnimData.m_uWeaponAnim != ASURA_HASH_ID_UNSET )
				{
					pxWeapon->PlayWeaponAnim( xAnimData.m_uWeaponAnim );
				}

				SetAnimHashes( xAnimData.m_uActorAnim, xAnimData.m_uActorAnim );
				if ( m_pxAVPAnimationData )
				{
					m_pxAVPAnimationData->SetTweenData( 0.05f, 0.0f, true );
					m_pxAVPAnimationData->SetLeaveAnimAtEnd( true );
					m_pxAVPAnimationData->SetAnimPriority( AVP_AAPC_WEAPON_ANIM );
					m_pxAVPAnimationData->SetControllerGroupHash( pxActor->GetAnimationHandler()->GetWeaponGroupHash() );
				}

				const float	fDuration = 0.400f;
				Asura_Vector_3 xTargetPosition;
				Asura_Matrix_3x3 xTargetOrientation;

				if ( xAnimData.m_uActorAnim != ASURA_HASH_ID_UNSET )
				{
					if ( !pxInteractObject->GetMarkerLocationFromHash( xAnimData.m_uActorPositionMarkerPoint, &xTargetPosition, &xTargetOrientation ) )
					{
						xTargetPosition = pxActor->GetCurrentPosition();
						xTargetOrientation = pxActor->GetCurrentOrientation();
					}

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

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

					InitialiseOrientationInterpolation( m_xOrientationInterpolationData );
					InitialisePositionInterpolation( m_xPositionInterpolationData );
				}

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

bool AVP_Move_Interaction::ShouldStart() const
{
	const Asura_Move* pxMove = GetParentSystem().GetCurrentMove();
	if ( pxMove->GetHash() != AVP_Move_Interaction_BeginWeaponAway::GetStaticHash() )
	{
		Asura_Assert( false, "Can only be started from AVP_Move_Interaction_Begin" );
		return false;
	}
	const AVP_Move_Interaction_BeginWeaponAway* pxIntBeginMove = static_cast< const AVP_Move_Interaction_BeginWeaponAway* >( pxMove );
	return pxIntBeginMove->GetNextMoveHash() == GetStaticHash();
}

void AVP_Move_Interaction::Finish()
{
	AVP_ClientEntity_Actor* pxActor = AVP_ClientEntity_Actor::FindEntity( GetParentSystem().GetOwnerGuid() );
	if ( pxActor ) pxActor->ActivateCurrentWeapon();

	PARENT::Finish();
}

void AVP_Move_Interaction::Abort()
{
	AVP_ClientEntity_Actor* pxActor = AVP_ClientEntity_Actor::FindEntity( GetParentSystem().GetOwnerGuid() );
	if ( pxActor ) pxActor->ActivateCurrentWeapon();

	PARENT::Abort();
}

AVP_Move_Interaction_EndWeaponBack::AVP_Move_Interaction_EndWeaponBack( Asura_Movement_System& xParentSystem )
: PARENT( xParentSystem, GetStaticHash() )
{
	// Initialise the move flags...
	m_bClearQueuedCounterRequest	= true;
	m_bClearQueuedMeleeRequests		= true;
	m_bPreventsFlinch				= true;
	m_bDisableMovement				= true;
	m_eAimDirectionUsage			= AVP_ClientEntity_Actor::AIM_DIRECTION_RESET;
}

bool AVP_Move_Interaction_EndWeaponBack::Start( const Asura_Msg_Move* pxStartMsg )
{
	AVP_ClientEntity_Actor* pxActor = AVP_ClientEntity_Actor::FindEntity( GetParentSystem().GetOwnerGuid() );
	Asura_Assert( pxActor, "Only actors should be interacting" );
	if ( !pxActor || !pxActor->GetAnimationHandler() )
	{
		return false;
	}
	else
	{
		// play the weapon anim
		AVP_Inventory_System* pxInvSys = pxActor->GetInventorySystem();
		AVP_InventoryItem_Weapon* pxWeapon = pxInvSys ? static_cast < AVP_InventoryItem_Weapon* >( pxInvSys->GetCurrentItem( uAVP_INVENTORY_GROUPHASH_WEAPON ) ) : NULL;
		if ( pxWeapon )
		{
			pxWeapon->PlayActivationWeaponAnim();
		}

		Asura_Hash_ID uWeaponInAnim = ASURA_HASH_ID_UNSET;
		const AVP_Actor_AnimStateData* pxStateData = pxActor->GetCurrentAnimStateData();
		if ( pxStateData )
		{
			uWeaponInAnim = pxStateData->GetWeaponInActorAnimHash();
		}

		SetAnimHashes( uWeaponInAnim, uWeaponInAnim );
		if ( m_pxAVPAnimationData )
		{
			m_pxAVPAnimationData->SetTweenData( 0.05f, 0.1f, true );
			m_pxAVPAnimationData->SetAnimPriority( AVP_AAPC_WEAPON_ANIM );
			m_pxAVPAnimationData->SetControllerGroupHash( pxActor->GetAnimationHandler()->GetWeaponGroupHash() );
		}

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