
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_Alien_InteractionHandler.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 "Actor/Vertebrates/Alien/AVP_Alien_InteractionHandler.h"

// Game independent header-files...
#include "Actor/AVP_Actor_InputHandler.h"
#include "Actor/Vertebrates/Alien/AVP_Alien_HUDHandler.h"
#include "Actor/Vertebrates/AVP_Vertebrate_Description.h"
#include "Entity/PhysicalObject/Actor/AVP_Actor_Messages.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Alien/AVP_ClientActor_Alien.h"
#include "Entity/PhysicalObject/Interact/AVP_ClientEntity_InteractObject.h"
#include "Entity/Triggers/AVP_ClientEntity_InteractionTrigger.h"
#include "Moves/Vertebrates/Alien/AVP_Alien_MovesInteraction.h"
#include "Rendering/Asura_Project_Skin_Elements.h"
////////////////////////////////////////////////////////////////////////////////
// Constant declarations...
////////////////////////////////////////////////////////////////////////////////


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

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

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Alien_InteractionHandler::AVP_Alien_InteractionHandler
// Author       : Andy Tate
// Date         : 4-Sep-2007
////////////////////////////////////////////////////////////////////////////////

AVP_Alien_InteractionHandler::AVP_Alien_InteractionHandler(AVP_ClientActor_Alien& xAlien)
: PARENT(xAlien)
, m_uHeadbiteTarget(ASURA_GUID_UNREGISTERED)
{
}

/// End of function 'AVP_Alien_InteractionHandler::AVP_Alien_InteractionHandler'. ///

DEBUGVAR float dbg_fHeadbiteMaxDistance = 1.0f;
DEBUGVAR float dbg_fHeadbiteMinCosAngle = 0.866f;

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

	AVP_Alien_HUDHandler::SetHeadbiteTargetInRange( false );

	// Update the headbite target.
	m_uHeadbiteTarget = ASURA_GUID_UNREGISTERED;
	const AVP_ClientActor_Alien& xAlienOwner = static_cast<const AVP_ClientActor_Alien&>(m_xOwner);
	if (xAlienOwner.IsStanding()) { return; }

	float fBestDistance = dbg_fHeadbiteMaxDistance;
	float fBestCosAngle = dbg_fHeadbiteMinCosAngle; // This has priority.

	Asura_Vector_3 xCameraPos;
	Asura_Matrix_3x3 xCameraOri;
	if (!xAlienOwner.GetMarkerLocationFromHash(AVP_Vertebrate_Description::GetMarkerPointHashID(AVP_Vertebrate_Description::MPID_EYES), &xCameraPos, &xCameraOri)) { return; }

	const Asura_Vector_3 xForwardVector(xCameraOri.e13, xCameraOri.e23, xCameraOri.e33);

	Asura_Hashed_List_ConstIt<AVP_ClientActor_Vertebrate> xRagdolledIt(AVP_ClientActor_Vertebrate::GetRagdolledList());
	while (!xRagdolledIt.Done())
	{
		const AVP_ClientActor_Vertebrate* pxCurrent = xRagdolledIt.GetCurrent();
		xRagdolledIt.Next();

		if (!pxCurrent) { continue; }
		if (pxCurrent->GetClassification() == AVP_ENTITYCLASS_ALIEN) { continue; }

		if (!pxCurrent->IsElementUndamaged(AVP_SET_HEAD)) { continue; }

		// We also need to check if the headbit head is visible, as we shouldn't allow a second bite.
		const Asura_Animation* pxAnim = pxCurrent->GetAnimation();
		if (pxAnim)
		{
			const u_int uElement = Asura_Project_Skin_Elements::GetDamagedElementIndex(AVP_SET_HEAD_AFTER_HEADBITE);

			if (pxAnim->GetSkinElementVisibility(uElement))
			{
				continue;
			}
		}

		Asura_Vector_3 xHeadPos;
		// Target 2 is the head target
		if (!pxCurrent->GetMarkerLocationFromHash(AVP_Vertebrate_Description::GetMarkerPointHashID(AVP_Vertebrate_Description::MPID_TARGET_2), &xHeadPos, NULL)) { continue; }

		// We need to make sure this is within interaction range.
		Asura_Vector_3 xToHead = xHeadPos - xCameraPos;
		if (xToHead.ApproximatelyEquals(Asura_Maths::ZeroVector3)) { continue; }
		float fDistance = xToHead.Normalise();
		float fCosAngle = xForwardVector * xToHead;

		if (((fCosAngle > fBestCosAngle) && (fDistance < dbg_fHeadbiteMaxDistance)) || ((fCosAngle == fBestCosAngle) && (fDistance < fBestDistance)))
		{
			m_uHeadbiteTarget = pxCurrent->GetGuid();
			fBestDistance = fDistance;
			fBestCosAngle = fCosAngle;

			AVP_Alien_HUDHandler::SetHeadbiteTargetInRange( true );
		}
	}
}

////////////////////////////////////////////////////////////////////////////////
// Function     : AVP_Alien_InteractionHandler::HandleInteraction
// Author       : Ali Jakamy
// Date         : 03-Dec-2008
////////////////////////////////////////////////////////////////////////////////

bool AVP_Alien_InteractionHandler::HandleInteraction(AVP_INTERACTION_TYPES eType, int iKeyType, float fKeyValue) const
{
	const Asura_Guid uGuidForInteraction = GetGuidForInteraction( eType );
	if ( uGuidForInteraction != ASURA_GUID_UNREGISTERED )
	{
		if(eType == AVP_INTERACTION_TYPE_DEFAULT)
		{
			AVP_ClientEntity_InteractObject* pxInteractObject = AVP_ClientEntity_InteractObject::FindEntity( uGuidForInteraction );
			if ( pxInteractObject )
			{
				// Is it a battery receptacle?
				if (pxInteractObject->GetInteractionObjectType() == AVP_ClientEntity_InteractObject::INTERACTION_TYPE_BATTERYRECEPTACLE)
				{
					if (iKeyType == AVP_Actor_InputHandler::INTERACT && !IsInteracting())
					{
						return SendInteractMessage(eType, AVP_Alien_Move_Interaction_DestroyBattery::GetStaticHash(), pxInteractObject, AVP_Message_Actor_RequestInteraction::INTERACTION_INTIATED);
					}
				}
				else
				{
					if(!IsInteracting())
					{
						// Fall back to old interaction handle to not break up things already there
						return PARENT::HandleInteraction(eType, iKeyType, fKeyValue);
					}
				}
			}
		}
		else
		{
			// This is a head bite on actor alien interaction
			return PARENT::HandleInteraction(eType, iKeyType, fKeyValue);
		}
	}
	return false;
}

////////////////////////////////////////////////////////////////////////////////
// Protected functions...
////////////////////////////////////////////////////////////////////////////////

Asura_Guid AVP_Alien_InteractionHandler::GetGuidForInteraction(AVP_INTERACTION_TYPES eType) const
{
	if (eType == AVP_INTERACTION_TYPE_HEADBITE)
	{
		return m_uHeadbiteTarget;
	}
	else
	{
		return PARENT::GetGuidForInteraction(eType);
	}
}

bool AVP_Alien_InteractionHandler::IsInteracting() const
{
	const Asura_Move* pxMove = m_xOwner.GetMovementSystem() ? m_xOwner.GetMovementSystem()->GetCurrentMove() : NULL; 
	if (pxMove)
	{
		return GetIsAlienInteractionMove(pxMove->GetHash());
	}
	return false;
}

bool AVP_Alien_InteractionHandler::GetIsAlienInteractionMove(const Asura_Hash_ID uMoveHash)
{
	if (uMoveHash == AVP_Alien_Move_Interaction_DestroyBattery::GetStaticHash())
	{
		return true;
	}
	else
	{
		return false;
	}
}

/// End of file. ///
