
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_InventoryWeapon_ScopedRifle.cpp
// Author : Chris Wallace
// Date   : 05-Dec-2008
//
// Copyright (C) 2008 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_ScopedRifle.h"

// Asura independent header-files...

// Game independent header-files...
#include "Animation/Asura_Animation.h"
#include "Animation/Asura_AnimationController_Animation.h"
#include "Inventory/AVP_Inventory_Group.h"
#include "Inventory/AVP_Inventory_HashIDs.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Items/Weapons/AVP_RangedWeapon_ClientEffectsHandler.h"

#include "Actor/AVP_Actor_AnimStateData.h"
#include "Actor/Vertebrates/AVP_Vertebrate_InputHandler.h"
#include "Actor/Vertebrates/Human/AVP_Human_HUDHandler.h"
#include "Entity/PhysicalObject/Actor/AVP_ClientEntity_Actor.h"

Asura_Hash_ID AVP_InventoryWeapon_ScopedRifle::s_uAimingFSFX = ASURA_HASH_ID_UNSET;

AVP_InventoryWeapon_ScopedRifle::AVP_InventoryWeapon_ScopedRifle( AVP_Inventory_Group& xParentGroup, const Asura_Hash_ID uHash, const Asura_Hash_ID uBlueprintHash )
: PARENT(xParentGroup, uHash, uBlueprintHash)
, m_bIsInSniperMode(false)
, m_bFullSniperMode(false)
{
	m_eItemType = AVP_INVENTORYITEMTYPE_SCOPEDRIFLE;
}


void AVP_InventoryWeapon_ScopedRifle::OnStateChange(const u_int uOldState,
													 const u_int uNewState)
{
	// Call the base-function...
	PARENT::OnStateChange(uOldState, uNewState);

	// Handle stuff for the new state...
	switch(uNewState)
	{
		case INACTIVE:
		{
			m_bIsInSniperMode = false;
			m_bFullSniperMode = false;
			if(GetParentSystem().IsClientSide())
			{
				if(!Asura_Entity_Renderable::GetRenderableList()->FindEntity(GetParentSystem().GetParentClient()->GetGuid()))
				{
					GetParentSystem().GetParentClient()->AddToRenderableList();
					m_bFullSniperMode = false;
				}
			}

			break;
		}
		
		default:
		{
			break;
		}
	}	
}


void AVP_InventoryWeapon_ScopedRifle::InitialiseFromBlueprint()
{
	PARENT::InitialiseFromBlueprint();

	const Asura_Blueprint* pxBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_INVENTORY_ITEMS, GetBlueprintHash() );
	if ( pxBlueprint )
	{
		Asura_Value xValue;

		if ( pxBlueprint->GetParameterValueByHashID( uAVP_BLUEPRINT_PARAM_WEAPON_TYPE, xValue ) )
		{
			if ( pxBlueprint->GetParameterValueByHashID( uAVP_BLUEPRINT_PARAM_AIMING_FSFX, xValue ) )
			{
				s_uAimingFSFX = xValue.GetHashIDValue();
			}
		}
	}
	else
	{
		Asura_Assertf( false, ( "AVP_InventoryWeapon_RangedWeapon::InitialiseFromBlueprint - cannot find blueprint %u to initialise from.", GetBlueprintHash() ) );
	}
}

int AVP_InventoryWeapon_ScopedRifle::GetSubTypeIndexFromUsageType(const u_int uUsageType) const
{
	switch(uUsageType)
	{
	case UT_SNIPER_TOGGLE:
		{
			return( NULL ); // This has no subtype, so don't return one!
		}

	default:
		{
			return(PARENT::GetSubTypeIndexFromUsageType(uUsageType));
		}
	}
}

void AVP_InventoryWeapon_ScopedRifle::StartUsing( const u_int uUsageType )
{
	switch( uUsageType )
	{
		case UT_SNIPER_TOGGLE:
		{
			if(m_bIsInSniperMode)
			{
				EndScope();
				m_bIsInSniperMode = false;
			}
			else
			{
				StartScope();
				m_bIsInSniperMode = true;
			}
		}
		break;

	default:
		{
			PARENT::StartUsing( uUsageType );
		}
		break;
	}
}

void AVP_InventoryWeapon_ScopedRifle::StartScope(void)
{
	if(GetParentSystem().IsClientSide() && GetParentSystem().IsMaster())
	{
		AVP_Actor_AnimationHandler* pxAnimHandler = GetParentSystem().GetParentClient()->GetAnimationHandler();
		if(pxAnimHandler)
		{
			const AVP_Actor_AnimStateData* pxAnimStateData = pxAnimHandler->GetCurrentAnimStateData();
			if(pxAnimStateData)
			{
				Asura_Hash_ID uHash = pxAnimHandler->GetCurrentAnimStateData()->GetScopeInActorAnimHash();
				if((pxAnimHandler->GetAnimation()) && pxAnimHandler->GetAnimation()->GetControllerAnimationFromHash(uHash)== NULL)
				{
					pxAnimHandler->PlayWeaponAnimation( uHash, 0.01f, false, AAC_FLAG_ACTIVE | AAC_FLAG_ENSURE_UNIQUE_HASH );
				}
			}
		}
	}
}

void AVP_InventoryWeapon_ScopedRifle::EndScope(void)
{
	if(GetParentSystem().IsClientSide() && GetParentSystem().IsMaster())
	{
		AVP_Actor_AnimationHandler* pxAnimHandler = GetParentSystem().GetParentClient()->GetAnimationHandler();
		if(pxAnimHandler)
		{
			const AVP_Actor_AnimStateData* pxAnimStateData = pxAnimHandler->GetCurrentAnimStateData();
			if(pxAnimStateData)
			{
				Asura_Hash_ID uInHash = pxAnimHandler->GetCurrentAnimStateData()->GetScopeInActorAnimHash();
				pxAnimHandler->StopWeaponAnimation(uInHash, true);

				Asura_Hash_ID uOutHash = pxAnimHandler->GetCurrentAnimStateData()->GetScopeOutActorAnimHash();
				pxAnimHandler->PlayWeaponAnimation( uOutHash, 0.01f, false );
			}
		}
	}
}

void AVP_InventoryWeapon_ScopedRifle::UpdateClientState( AVP_ClientEntity_Actor& xClient )
{
	const State	eCurrentState	= GetCurrentState();
	const u_int	uUsageType		= GetCurrentUsageType();

	if(GetParentSystem().IsClientSide() && GetParentSystem().IsMaster())
	{
		AVP_Actor_AnimationHandler* pxAnimHandler = GetParentSystem().GetParentClient()->GetAnimationHandler();
		if(pxAnimHandler)
		{
			const AVP_Actor_AnimStateData* pxAnimStateData = pxAnimHandler->GetCurrentAnimStateData();
			if(pxAnimStateData)
			{
				Asura_Hash_ID uInHash = GetParentSystem().GetParentClient()->GetAnimationHandler()->GetCurrentAnimStateData()->GetScopeInActorAnimHash();
				Asura_Hash_ID uOutHash = GetParentSystem().GetParentClient()->GetAnimationHandler()->GetCurrentAnimStateData()->GetScopeOutActorAnimHash();
				Asura_Animation* pxAnim = pxAnimHandler->GetAnimation();

				Asura_AnimationController_Animation* pxInAnimCA = (pxAnim)?pxAnimHandler->GetAnimation()->GetControllerAnimationFromHash( uInHash ):NULL;
				Asura_AnimationController_Animation* pxOutAnimCA = (pxAnim)?pxAnimHandler->GetAnimation()->GetControllerAnimationFromHash( uOutHash ):NULL;
				if(m_bIsInSniperMode && pxInAnimCA && pxInAnimCA->IsFinished())
				{
					GetParentSystem().GetParentClient()->RemoveFromRenderableList(false);
					m_bFullSniperMode = true;
				}
				else if(pxOutAnimCA && pxOutAnimCA->GetParametricTimer() == 0.0f)
				{
					if(!Asura_Entity_Renderable::GetRenderableList()->FindEntity(GetParentSystem().GetParentClient()->GetGuid()))
					{
						GetParentSystem().GetParentClient()->AddToRenderableList();
						m_bFullSniperMode = false;
					}
				}
			}
		}
	}

	switch ( eCurrentState )
	{
		case USING:
		{
			m_bFirstShot = false; // As this weapon spins up, we don't want a first shot as such, it causes issues.

			switch(uUsageType)
			{
				case UT_SNIPER_TOGGLE:
				{
					if(GetParentSystem().IsMaster() && GetTimeInState() > 0.0f)
					{
						RequestIdling(false); // Always idles
					}
					break;
				}
			
				default:
				{
					PARENT::UpdateClientState( xClient );
					break; // don't do anything, the derived class will probably handle it
				}
			}		
		}

		default:
		{
			PARENT::UpdateClientState( xClient );
			break;
		}
	}
}

void AVP_InventoryWeapon_ScopedRifle::ProcessPlayerInput( const AVP_ClientEntity_Actor& xActor )
{
	const AVP_Actor_InputHandler* pxInputHandler = xActor.GetInputHandler();
	const State eCurrentState = GetCurrentState();

	if ( pxInputHandler != NULL && ( GetTimeInState() > 0.0f ) && !xActor.IsMovingFast() )
	{
		if ( pxInputHandler->GetControlMapValue( AVP_Vertebrate_InputHandler::SECONDARY_ATTACK_TAP ) > 0.0f ) // start zoom on tap
		{
			if ( eCurrentState == IDLING && !m_bIsInSniperMode)
			{
				RequestUsing( UT_SNIPER_TOGGLE );
				return;
			}
		}
		else if ( pxInputHandler->GetControlMapValue( AVP_Vertebrate_InputHandler::SECONDARY_ATTACK_HELD) == 0.0f ) // stop zoom on release
		{
			if ( eCurrentState == IDLING && m_bIsInSniperMode && Asura_Timers::GetGameTimeScale() > 0.0f)  // don't fall out if time is paused...
			{
				RequestUsing( UT_SNIPER_TOGGLE );
				return;
			}
		}
	
		PARENT::ProcessPlayerInput(xActor);
	}
}

/// End of file. ///
