
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_FaceHugger_MovesJump.cpp
// Author : Andy Tate
// Date   : 4-Sep-2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Moves/Vertebrates/FaceHugger/AVP_FaceHugger_MovesJump.h"

// Asura independent header-files...
#include "Animation/Asura_AnimationController_Animation.h"
#include "Blueprint/Asura_Blueprint.h"
#include "Blueprint/Asura_Blueprint_System.h"

// Game independent header-files...
#include "Actor/AVP_Actor_PhysicsObjectHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_AnimationHandler.h"
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/FaceHugger/AVP_ClientActor_FaceHugger.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/FaceHugger/AVP_Messages_FaceHugger.h"

static const Asura_Hash_ID dbg_uAIJumpBP		= 0x79e722bd; //"FaceHugger AI Jump"
static const Asura_Hash_ID dbg_uGenericJump		= 0x0031f42e; //"Jump"

////////////////////////////////////////////////////////////////////////////////
// AVP_Move_FaceHugger_JumpBase::AVP_Move_FaceHugger_JumpBase
////////////////////////////////////////////////////////////////////////////////

AVP_Move_FaceHugger_JumpBase::AVP_Move_FaceHugger_JumpBase( Asura_Movement_System& xParentSystem, const Asura_Hash_ID uMoveHash )
: PARENT(xParentSystem, uMoveHash)
{
	// Initialise the move flags...
	SetDisableMovement( true );
	SetAimDirectionUsage( AVP_ClientEntity_Actor::AIM_DIRECTION_RESET );
	SetPreventsFlinch( true );
	SetDisableSurfaceReorientation( true );
}

bool AVP_Move_FaceHugger_JumpBase::Start(const Asura_Msg_Move* pxStartMsg)
{
	// Have we been told to start via a message?
	if(pxStartMsg == NULL)
	{
		Asura_Assert(false, "FaceHugger surface-interaction move can only be triggered by message.");
		return(false);
	}
	else
	{
		const AVP_Message_FaceHugger_Move_JumpStart*	pxMessage = static_cast<const AVP_Message_FaceHugger_Move_JumpStart*>(pxStartMsg);

		if (m_pxAVPAnimationData)
		{
			m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		}

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

		Asura_Vector_3 xTargetPosition;
		Asura_Matrix_3x3 xTargetOrientation;

		// Calculate our target position AND orientation...
		pxMessage->GetDestinationPosition(xTargetPosition);
		pxMessage->GetDestinationOrientation(xTargetOrientation);
		
		// For the time being we'll just move and rotate to our desired position...
		if(bHasAnimation)
		{
			m_xOrientationInterpolationData.SetMovementOffsetOperation(Asura_MoveData_OrientationInterpolation::STRETCH_MOVEMENT_OFFSET);
			m_xPositionInterpolationData.SetMovementOffsetOperation(Asura_MoveData_PositionInterpolation::STRETCH_MOVEMENT_OFFSET);
		}


		float fReorientDuration = Asura_Maths::ClampToRange(fDuration - 0.5f, Asura_Maths::Min(fDuration, 0.5f), 2.5f);

		m_xOrientationInterpolationData.SetDuration(fReorientDuration);
		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));
	}
}

////////////////////////////////////////////////////////////////////////////////
// AVP_Move_FaceHugger_Jump
////////////////////////////////////////////////////////////////////////////////

AVP_Move_FaceHugger_Jump::AVP_Move_FaceHugger_Jump(Asura_Movement_System& xParentSystem)
: PARENT(xParentSystem, GetStaticHash())
{
	SetUseSingularityAxis( true );

	Asura_Hash_ID uTPAnim = ASURA_HASH_ID_UNSET;
	Asura_Value xValue;

	Asura_Blueprint* pxBP = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_ACTOR_STATE, dbg_uAIJumpBP );
	if ( pxBP )
	{
		if ( pxBP->GetParameterValueByHashID( dbg_uGenericJump, xValue ) )
		{
			uTPAnim = xValue.GetHashIDValue();
		}
	}

	SetAnimHashes( ASURA_HASH_ID_UNSET, uTPAnim );

}

////////////////////////////////////////////////////////////////////////////////
// AVP_Move_FaceHugger_Falling
////////////////////////////////////////////////////////////////////////////////

AVP_Move_FaceHugger_Falling::AVP_Move_FaceHugger_Falling( Asura_Movement_System& xParentSystem )
: PARENT(xParentSystem, GetStaticHash())
, m_xOrientationInterpolationData()
, m_fTimeSinceStart(0.0f)
, m_bInAir(false)
, m_bFinished(false)
, m_xAwayFromSurfaceStart(Asura_Maths::ZeroAVector3)
{
	SetPreventsFlinch( true );
	SetAimDirectionUsage( AVP_ClientEntity_Actor::AIM_DIRECTION_RESET );
	SetPositionUsage(Asura_Move::POSITION_SET_FROM_VELOCITY);
}

bool AVP_Move_FaceHugger_Falling::Start(const Asura_Msg_Move* pxStartMsg)
{
	// Have we been told to start via a message?
	if(pxStartMsg == NULL)
	{
		Asura_Assert(false, "FaceHugger surface-interaction move can only be triggered by message.");
		return(false);
	}
	else
	{
		const AVP_Message_FaceHugger_Move_JumpStart* pxMessage = static_cast<const AVP_Message_FaceHugger_Move_JumpStart*>(pxStartMsg);

		if (m_pxAVPAnimationData)
		{
			m_pxAVPAnimationData->SetAnimHash(m_uThirdPersonAnimHash);
		}

		// const bool bHasAnimation = m_pxAVPAnimationData && m_pxAVPAnimationData->HasValidAnimation();

		Asura_Matrix_3x3 xTargetOrientation;

		// Calculate our target position AND orientation...
		pxMessage->GetDestinationOrientation(xTargetOrientation);


//  		if(bHasAnimation)
//  		{
//  			m_xOrientationInterpolationData.SetMovementOffsetOperation(Asura_MoveData_OrientationInterpolation::IGNORE_MOVEMENT_OFFSET);
//  		}

		float fReorientDuration = 1.0f;

		m_xOrientationInterpolationData.SetDuration(fReorientDuration);
		m_xOrientationInterpolationData.SetFinal(xTargetOrientation);

		InitialiseOrientationInterpolation(m_xOrientationInterpolationData);

		// set the gravity down if we on the server machine
		AVP_PhysicsObjectHandler* pxPhyHandler = NULL;
		if (Asura_Network::IsServer())
		{
			AVP_ServerActor_Vertebrate* pxOwner = AVP_ServerActor_Vertebrate::FindEntity(GetAVPParentSystem().GetOwnerGuid());
			pxPhyHandler = pxOwner->GetPhysicsObjectHandler();			
		}
		else
		{
			AVP_ClientActor_Vertebrate* pxOwner = AVP_ClientActor_Vertebrate::FindEntity(GetAVPParentSystem().GetOwnerGuid());
			pxPhyHandler = pxOwner->GetPhysicsObjectHandler();			
		}

		pxPhyHandler->SetForcedTargetSurfaceNormal(Asura_Vector_3(0.0f, -1.0f, 0.0f));
		pxPhyHandler->GetCurrentSurfaceNormal(m_xAwayFromSurfaceStart);

		m_fTimeSinceStart = 0.0f;
		m_bInAir = false;
		m_bFinished = false;

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

void AVP_Move_FaceHugger_Falling::UpdateStates(const float fTimeStep)
{
	bool bInContactWithFloor = false;
	AVP_Actor_PhysicsObjectHandler* pxPhyHandler = NULL;

	m_fTimeSinceStart += fTimeStep;

	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();
		}
	}

	Asura_Assert(pxPhyHandler, "PhysicsObjectHandler not found");

	bInContactWithFloor = pxPhyHandler ?  pxPhyHandler->GetPhysicsObject()->IsInContactWithFloor() : true;

	if ( m_bInAir )
	{
		m_bFinished = bInContactWithFloor;
	}
	else if ( !bInContactWithFloor )
	{
		m_bInAir = true;
	}
	else if ( m_fTimeSinceStart > 1.0f )
	{
		m_bFinished = true;
	}


	// release the orientation
	if (m_bFinished && Asura_Network::IsServer())
	{
		AVP_ServerActor_Vertebrate* pxOwner = AVP_ServerActor_Vertebrate::FindEntity(GetAVPParentSystem().GetOwnerGuid());
		pxOwner->GetPhysicsObjectHandler()->UnsetForcedTargetSurfaceNormal();
	}


	PARENT::UpdateStates(fTimeStep);
}

bool AVP_Move_FaceHugger_Falling::HasFinished() const
{

	if (!m_bFinished)
	{
		return false;
	}
	else
	{
		return PARENT::HasFinished();
	}
}

DEBUGVAR float dbg_fAwayFromWallVelocity = 1.0f;

bool AVP_Move_FaceHugger_Falling::CalculateVelocity(const float fTimeStep, Asura_AVector3_OutParam xVelocity) const
{
	PARENT::CalculateVelocity(fTimeStep, xVelocity);
	if (m_fTimeSinceStart < 1.0)
	{
		xVelocity += m_xAwayFromSurfaceStart * dbg_fAwayFromWallVelocity;
	}
	return false;
}


//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////
