
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Predator_AnimationHandler.cpp
// Author : Andy Tate
// Date   : 18-Oct-2006
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Actor/Vertebrates/Predator/AVP_Predator_AnimationHandler.h"

// Asura independent header-files...
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_AnimationBlend.h"
#include "Animation/Asura_AnimationController_Animation.h"
#include "Network/Asura_Network.h"
#include "Entity/AVP_Entity_Classification.h"
#include "Physics/Asura_Physics_Ragdoll.h"
#include "ProjectSettings/Asura_PhysicsConfiguration.h"
#include "SpecialFX/PFX/Asura_PFX_Entity_Effect.h"

#ifndef ASURA_NO_DEBUG_OUTPUT
	#include "Debugging/Asura_DebugLineRender.h"
	#include "Interface/Asura_CommandConsole.h"
#endif

// Game independent header-files...
#include "Actor/AVP_Actor_CameraHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_Focus.h"
#include "Actor/Vertebrates/Predator/AVP_Predator_Description.h"
#include "Actor/Vertebrates/Predator/AVP_Predator_CameraHandler.h"
#include "Animation/AVP_AnimFlags.h"
#include "Core/AVP_Game_Core.h"
#include "Entity/AVP_Messages.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_Messages_Predator.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ClientActor_Predator.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ServerActor_Predator.h"
#include "Entity/PhysicalObject/Projectile/AVP_ClientProjectile_Disc.h"
#include "Inventory/AVP_Inventory_Group.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_Disc.h"


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

//DEBUGVAR Asura_Vector_3	dbg_xSpearToCrosshairOffset					(0.0f, 0.0f, 20.0f);
//DEBUGVAR float			dbg_fSpearThrowInitialSpeed					= 20.0f;
//DEBUGVAR float			dbg_fSpearThrowVerticalSpeedModified		= -2.500f;

//DEBUGVAR Asura_Vector_3	dbg_xPlasmaBoltToCrosshairOffset			(0.0f, 0.0f, 50.0f);

//DEBUGVAR Asura_Vector_3	dbg_xDiscToCrosshairOffset					(0.0f, 0.0f, 20.0f);
//DEBUGVAR float			dbg_fDiscThrowVerticalSpeedModified			= 0.0f;

//DEBUGVAR float			dbg_SpearRunOffset							= 0.3f;

static const Asura_AVector3 g_xDownVector( 0.0f, 1.0f, 0.0f );

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


////////////////////////////////////////////////////////////////////////////////
// Private functions...
////////////////////////////////////////////////////////////////////////////////


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_AnimationHandler::CalculateMarkerPointToCrosshairData
// Author       : Andy Tate
// Date         : 3-Jan-2007
////////////////////////////////////////////////////////////////////////////////

bool AVP_Predator_AnimationHandler::CalculateMarkerPointToCrosshairData(const Asura_Hash_ID uSourceMarkerPointHash,
																		 const float fInitialSpeed,
																		 const Asura_Vector_3& xCrosshairOffset,
																		 Asura_Vector_3& xPosition,
																		 Asura_Matrix_3x3& xOrientation,
																		 Asura_Vector_3& xVelocity) const
{
	AVP_ClientActor_Predator*		pxClientPredator	= AVP_ClientActor_Predator::FindEntity(m_uOwnerGuid);
	if(!pxClientPredator)
	{
		return false;
	}
	
	const Asura_Vector_3&			xClientPosition		= pxClientPredator->GetCurrentPosition();
	const Asura_Matrix_3x3&			xClientOrientation	= pxClientPredator->GetCurrentOrientation();

	// Find the marker-point orientation/position...
	if(pxClientPredator->GetObjectSpaceMarkerPoint(uSourceMarkerPointHash, &xPosition, &xOrientation))
	{
		const AVP_Actor_CameraHandler*	pxCameraHandler		= pxClientPredator->GetCameraHandler();
		const Asura_Matrix_3x3&			xCameraOrientation	= pxCameraHandler->GetOrientation();

		Asura_Vector_3					xForwards;
		Asura_Vector_3					xSide;
		Asura_Vector_3					xUp;
		Asura_Vector_3					xTargetPosition;

		// Transform the position/orientation into world-space...
		xPosition		= (xPosition * xClientOrientation) + xClientPosition;
		xOrientation	= xClientOrientation * xOrientation;

		// Calculate the direction from the marker-point to the target...
		xForwards = (xCrosshairOffset * xCameraOrientation);
		xForwards.Normalise();

		// Re-create the orientation matrix using this direction...
		xUp[0]	= xOrientation.e12;
		xUp[1]	= xOrientation.e22;
		xUp[2]	= xOrientation.e32;

		xSide	= xForwards ^ xUp;
		xUp		= xForwards ^ xSide;

		xOrientation.e11	= xSide[0];
		xOrientation.e21	= xSide[1];
		xOrientation.e31	= xSide[2];
		xOrientation.e12	= xUp[0];
		xOrientation.e22	= xUp[1];
		xOrientation.e32	= xUp[2];
		xOrientation.e13	= xForwards[0];
		xOrientation.e23	= xForwards[1];
		xOrientation.e33	= xForwards[2];

		// Calculate the velocity...
		xVelocity	= xForwards * fInitialSpeed;

		return(true);
	}
	else
	{
		return(false);
	}
}

/// End of function 'AVP_Predator_AnimationHandler::CalculateMarkerPointToCrosshairData'. ///


////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_AnimationHandler::UpdateSkin
// Author       : Andy Tate
// Date         : 27-Oct-2006
////////////////////////////////////////////////////////////////////////////////

void AVP_Predator_AnimationHandler::UpdateSkin(void)
{
	Asura_Hierarchy_Skin*	pxSkin;

	// Firstly, call the parent function...
	PARENT::UpdateSkin();

	// Update the marker-point indices...
	pxSkin	= Asura_Animation_System::GetSkinByHash(m_uSkinHash);

	if(pxSkin != NULL)
	{
		pxSkin->GetMarkerPointIndex(AVP_Predator_Description::GetMarkerPointHashID(AVP_Predator_Description::RIGHT_HAND_MARKER_POINT_HASH), m_iRightHandMarkerPointIndex);
	}
}

/// End of function 'AVP_Predator_AnimationHandler::UpdateSkin'. ///



////////////////////////////////////////////////////////////////////////////////
// Public functions...
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Predator_AnimationHandler::AVP_Predator_AnimationHandler
// Author       : Andy Tate
// Date         : 18-Oct-2006
////////////////////////////////////////////////////////////////////////////////

AVP_Predator_AnimationHandler::AVP_Predator_AnimationHandler(AVP_ClientActor_Predator& xOwner)
: PARENT(xOwner)
, m_xOwnerPredator(xOwner)
{
}

/// End of function 'AVP_Predator_AnimationHandler::AVP_Predator_AnimationHandler'. ///

AVP_Predator_AnimationHandler::~AVP_Predator_AnimationHandler()
{
}

void AVP_Predator_AnimationHandler::Initialise( void )
{
	PARENT::Initialise();

	if ( m_pxBodyRig )
	{
		if ( AVP_Game_Core::IsLocalPlayer( m_uOwnerGuid ) )
		{
			m_pxBodyRig->SetMaxAimRightLeft( Asura_Maths::Deg90 );
		}
		else
		{
			m_pxBodyRig->SetMaxAimRightLeft( Asura_Maths::Deg90 );
		}
	}

	InitialiseIKSolver();
}

//------------------------------------------------------------------------------
// Function     : AVP_Predator_AnimationHandler::HandleAnimationRequest
// Author       : Gareth Thomas
// Date         : 05 / 06 / 07
//------------------------------------------------------------------------------
void AVP_Predator_AnimationHandler::HandleAnimationRequest( const AVP_Message_Actor_RequestAnimation& xAnimRequestData )
{
	#if 0
	if ( m_xCurrentAnimSequenceData.IsValid() || m_xPendingAnimSequenceData.IsValid() )
	{
		Asura_Assert( false, "AVP_Predator_AnimationHandler::HandleAnimationRequest - shouldn't request an anim whilst playing a gamescene anim template" );
		return;
	}

	u_int uAnimFlags	= AAC_FLAG_ACTIVE | AAC_FLAG_DESTROY_WHEN_FINISHED | AAC_FLAG_ENSURE_UNIQUE_HASH | AACA_FLAG_CALCULATE_VELOCITY;
	u_int uHashId		= AVP_Predator_Description::GetAnimationHashID(static_cast<AVP_Predator_Description::AnimationType>(xAnimRequestData.m_uAnimation));

	if (xAnimRequestData.m_eLoopStatus == 1)
	{
		uAnimFlags |= AACA_FLAG_LOOPED;
	}

	CreateRequestedAnimation(uHashId, uAnimFlags);
	#endif
}

void AVP_Predator_AnimationHandler::Update()
{
	PARENT::Update();

	const u_int uAnimFlags = GetAnimation()->GetFlagsForAllAnimsLastFrame();

	m_xLeftLegIKChain.SetAnimVeto( ( uAnimFlags & AVP_ANIMFLAG_NOT_IK_FEET ) != 0 );
	m_xRightLegIKChain.SetAnimVeto( ( uAnimFlags & AVP_ANIMFLAG_NOT_IK_FEET ) != 0 );
}

void AVP_Predator_AnimationHandler::CreateRequestedAnimation( const Asura_Hash_ID uAnimHashID, const u_int uAnimFlags )
{
	Asura_AnimationBlend* pxAnimBlend = new Asura_AnimationBlend_AnimatedTween( 0.1f, 0.1f, false );
	m_uCurrentRequestedAnimControllerHash = PlayAnimation( uAnimFlags, 0x00008000, uAnimHashID, pxAnimBlend );
}

const Asura_Animation_IK_Chain_LOS* AVP_Predator_AnimationHandler::GetLimbIKChainLOS( u_int uLimbItr ) const
{
	switch ( uLimbItr )
	{
	case AVP_ClientEntity_Actor::FOOT_REAR_LEFT:
		{
			return &m_xLeftLegIKChain;
		}

	case AVP_ClientEntity_Actor::FOOT_REAR_RIGHT:
		{
			return &m_xRightLegIKChain;
		}

	default:
		{
			return NULL;
		}
	}
}

void AVP_Predator_AnimationHandler::InitialiseIKSolver()
{
	Asura_Assert( m_xIKSolver.GetFirstChain() == NULL, "IK Solver already initialised, clearing it..." );
	if ( m_xIKSolver.GetFirstChain() )
	{
		m_xIKSolver.Clear();
	}

	static const int NUM_EXCEPTIONS = 7;
	static const u_short s_ausClassificationExceptionArray[NUM_EXCEPTIONS] = { 
		AVP_ENTITYCLASS_DISC, 
		AVP_ENTITYCLASS_DROPSHIP_MISSILE, 
		AVP_ENTITYCLASS_GENERICPROJECTILE, 
		AVP_ENTITYCLASS_HUMANFLARE, 
		AVP_ENTITYCLASS_PROJECTILE_FLAMETHROWER,
		AVP_ENTITYCLASS_MINE,
		AVP_ENTITYCLASS_PROJECTILE_ACIDSPIT
	};

	if ( IsFirstPerson() )
	{
		m_xLeftLegIKChain.SetBonesArrays( AVP_Predator_Description::GetFirstPersonLeftLegChainBonesArray() );
		if ( m_pxAnimation->GetSkin() != NULL )
		{
			m_xLeftLegIKChain.SetAxesFromRestPose( m_pxAnimation->GetSkin()->BoneRestPose );
		}
		m_xLeftLegIKChain.SetIsRootBoneMover();
		m_xLeftLegIKChain.SetLocalLOSDirection( g_xDownVector );
		m_xLeftLegIKChain.SetExclusionLists( NUM_EXCEPTIONS, s_ausClassificationExceptionArray );
		m_xLeftLegIKChain.SetMoveLimit(0.75f);
		m_xLeftLegIKChain.SetTestAgainstEverything( m_uOwnerGuid );
		m_xLeftLegIKChain.SetExtendLimit( 0.01f );
		m_xIKSolver.AddChain( m_xLeftLegIKChain );

		m_xRightLegIKChain.SetBonesArrays( AVP_Predator_Description::GetFirstPersonRightLegChainBonesArray() );
		if ( m_pxAnimation->GetSkin() != NULL )
		{
			m_xRightLegIKChain.SetAxesFromRestPose( m_pxAnimation->GetSkin()->BoneRestPose );
		}
		m_xRightLegIKChain.SetIsRootBoneMover();
		m_xRightLegIKChain.SetLocalLOSDirection( g_xDownVector );
		m_xRightLegIKChain.SetExclusionLists( NUM_EXCEPTIONS, s_ausClassificationExceptionArray );
		m_xRightLegIKChain.SetMoveLimit(0.75f);
		m_xRightLegIKChain.SetTestAgainstEverything( m_uOwnerGuid );
		m_xRightLegIKChain.SetExtendLimit( 0.01f );
		m_xIKSolver.AddChain( m_xRightLegIKChain );
	}
	else
	{
		m_xLeftLegIKChain.SetBonesArrays( AVP_Predator_Description::GetThirdPersonLeftLegChainBonesArray() );
		if ( m_pxAnimation->GetSkin() != NULL )
		{
			m_xLeftLegIKChain.SetAxesFromRestPose( m_pxAnimation->GetSkin()->BoneRestPose );
		}
		m_xLeftLegIKChain.SetIsRootBoneMover();
		m_xLeftLegIKChain.SetLocalLOSDirection( g_xDownVector );
		m_xLeftLegIKChain.SetExclusionLists( NUM_EXCEPTIONS, s_ausClassificationExceptionArray );
		m_xLeftLegIKChain.SetMoveLimit(0.75f);
		m_xLeftLegIKChain.SetTestAgainstEverything( m_uOwnerGuid );
		m_xLeftLegIKChain.SetExtendLimit( 0.01f );
		m_xIKSolver.AddChain( m_xLeftLegIKChain );

		m_xRightLegIKChain.SetBonesArrays( AVP_Predator_Description::GetThirdPersonRightLegChainBonesArray() );
		if ( m_pxAnimation->GetSkin() != NULL )
		{
			m_xRightLegIKChain.SetAxesFromRestPose( m_pxAnimation->GetSkin()->BoneRestPose );
		}
		m_xRightLegIKChain.SetIsRootBoneMover();
		m_xRightLegIKChain.SetLocalLOSDirection( g_xDownVector );
		m_xRightLegIKChain.SetExclusionLists( NUM_EXCEPTIONS, s_ausClassificationExceptionArray );
		m_xRightLegIKChain.SetMoveLimit(0.75f);
		m_xRightLegIKChain.SetTestAgainstEverything( m_uOwnerGuid );
		m_xRightLegIKChain.SetExtendLimit( 0.01f );
		m_xIKSolver.AddChain( m_xRightLegIKChain );
	}

	EnableIKSolver();
}

/// End of file. ///
