
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_ClientProjectile_Mine.cpp
// Author : Chris Wallace
// Date   : 25-Feb-2009
//
// Copyright (C) 2009 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

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

#include "Core/Asura.h"

// This file's header...
#include "Entity/PhysicalObject/Projectile/AVP_ClientProjectile_Mine.h"

// Asura independent header-files...
#include "Light/Asura_Photon.h"
#include "Network/Asura_Message.h"
#include "Sound/Asura_Sound_Event_Storage.h"
#include "Sound/Asura_Sound_Event_System.h"

// Game independent header-files...
#include "Entity/AVP_Entity_Classification.h"
#include "Entity/PhysicalObject/Actor/Vertebrates/Predator/AVP_ClientActor_Predator.h"
#include "Entity/PhysicalObject/Projectile/AVP_Projectile_Messages.h"
#include "Inventory/AVP_Inventory_System.h"
#include "Inventory/Groups/AVP_InventoryGroup_Weapons.h"
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_Mine.h"
#include "Actor/Vertebrates/AVP_Vertebrate_HUDHandler.h"

Asura_Hashed_List<AVP_ClientProjectile_Mine>	AVP_ClientProjectile_Mine::s_xList;

AVP_ClientProjectile_Mine::AVP_ClientProjectile_Mine ( const AVP_Message_ProjectileClientUpdate* pxData )
: PARENT( pxData )
, m_uMineState(MINE_IN_FLIGHT)
, m_fStateTimer(0.0f)
, m_fDetonationOffset(0.0f)
, m_uArmingSound(ASURA_HASH_ID_UNSET)
, m_uTriggeredSound(ASURA_HASH_ID_UNSET)
, m_iTriggerSoundHandle(ASURA_INVALID_HANDLE)
, m_pxLightPhoton(NULL)
{
	Classification = AVP_ENTITYCLASS_MINE;

	s_xList.AddToList(this);


	m_xInputStateFlying.SetNumInputs(1);
	m_xInputStateFlying.SetStateHash(0, 0xB438D28F );	// Asura_GetHashID("Flying")

	m_xInputStateArming.SetNumInputs(1);
	m_xInputStateArming.SetStateHash(0, 0x7A20AF4E );	// Asura_GetHashID("Arming on ground")

	m_xInputStateArmed.SetNumInputs(1);
	m_xInputStateArmed.SetStateHash(0, 0xA1FA7035 );	// Asura_GetHashID("Armed and ready")

	m_xInputStateArming_OnFocus.SetNumInputs(1);
	m_xInputStateArming_OnFocus.SetStateHash(0, 0xFC5B3787 );// Asura_GetHashID("Arming on ground OnFocus")

	m_xInputStateArmed_OnFocus.SetNumInputs(1);
	m_xInputStateArmed_OnFocus.SetStateHash(0, 0x5835216E );// Asura_GetHashID("Armed and ready OnFocus")

	UpdateMineContainerAttachmentState();
}

void AVP_ClientProjectile_Mine::UpdateMineContainerAttachmentState()
{
	if (m_pxContainerAttachment)
	{
		bool bInFocusMode = AVP_Vertebrate_HUDHandler::GetFocusMode()>=0.5f ? true : false;

		switch( m_uMineState )
		{
		case MINE_IN_FLIGHT:	m_pxContainerAttachment->ChangeState( m_xInputStateFlying );	return;
		case MINE_ARMING:		m_pxContainerAttachment->ChangeState( bInFocusMode ? m_xInputStateArmed_OnFocus : m_xInputStateArmed );	return;
		case MINE_ARMED:		m_pxContainerAttachment->ChangeState( bInFocusMode ? m_xInputStateArming_OnFocus: m_xInputStateArming );	return;
		}
	}
}

AVP_ClientProjectile_Mine::~AVP_ClientProjectile_Mine ()
{
	Asura_Photon_System::DestroyPhoton(m_pxLightPhoton);
	if(Asura_Sound_Event_System::IsPlaying(m_iTriggerSoundHandle))
	{
		Asura_Sound_Event_System::Stop(m_iTriggerSoundHandle);
	}
	m_pxLightPhoton = NULL;

	s_xList.RemoveFromList(this);
}

void AVP_ClientProjectile_Mine::Create(const Asura_Message *pxMessage)
{
	AVP_ClientProjectile_Mine*	pxClient = new AVP_ClientProjectile_Mine( static_cast< const AVP_Message_ProjectileClientUpdate* >( pxMessage->GetData() ) );

	pxClient->HandleMessage(pxMessage);
}

void AVP_ClientProjectile_Mine::PostCreateInitialise()
{
	Asura_Blueprint* pxBlueprint =  GetBlueprint();
	if(pxBlueprint)
	{
		m_uArmingSound	  = pxBlueprint->GetParameterAsHash( 0x2C589FA2, ASURA_HASH_ID_UNSET);	// Asura_GetHashID("Sound.Mine.Arming")
		m_uTriggeredSound = pxBlueprint->GetParameterAsHash( 0xC6E86F3B, ASURA_HASH_ID_UNSET);	// Asura_GetHashID("Sound.Mine.Triggered")
	}
}

bool AVP_ClientProjectile_Mine::HandleMessage(const Asura_Message* pxMessage)
{
	switch( pxMessage->GetMsgID() )
	{
		case ASURA_MSG_CLIENTUPDATE:
		{
			const AVP_Message_MineClientUpdate* pxData =  static_cast<const AVP_Message_MineClientUpdate*>(pxMessage->GetData());
			if(pxData)
			{
				u_int uState = pxData->GetMineState();
				if(uState != m_uMineState)
				{
					m_fDetonationOffset = pxData->GetDetonationOffset();
					OnStateChange(uState);
					m_uMineState = uState;
					m_fStateTimer = 0.0f;
				}
			}
			break;
		}
	}

	return(PARENT::HandleMessage(pxMessage));
}

DEBUGVAR float dbg_fFalloffPower = 30.0f;
DEBUGVAR float dbg_fFalloffScale = 1.0f;

void AVP_ClientProjectile_Mine::OnStateChange(u_int uNewState)
{
	switch(uNewState)
	{
		case MINE_ARMING:
		{
			const Asura_Sound_Event* pxSoundEvent = Asura_Sound_Event_Storage::FindEvent(m_uArmingSound); 
			if (pxSoundEvent)
			{
				if (m_iTriggerSoundHandle != ASURA_INVALID_HANDLE && !Asura_Sound_Event_System::IsPlaying(m_iTriggerSoundHandle))
				{
					Asura_Sound_Event_System::Stop( m_iTriggerSoundHandle );
				}
				if (m_iTriggerSoundHandle == ASURA_INVALID_HANDLE)
				{
					Asura_Sound_Event_System::PlayEvent(pxSoundEvent, &m_iTriggerSoundHandle, &GetCurrentPosition(), 1.0f, GetGuid());
				}
			}
			break;
		}

		case MINE_ARMED:
		{
			break;
		}
		case MINE_TRIGGERED:
		{
			if(m_iTriggerSoundHandle != ASURA_INVALID_HANDLE)
			{
				Asura_Sound_Event_System::Stop(m_iTriggerSoundHandle);
			}
			break;
		}
	}
}

void AVP_ClientProjectile_Mine::Update(void)
{
#if defined (ASURA_TARGET_SM3)
	Asura_Vector_3 xDir(GetCurrentOrientation().e13, GetCurrentOrientation().e23, GetCurrentOrientation().e33);
	
	if( m_pxLightPhoton == NULL )
	{
		m_pxLightPhoton = Asura_Photon_System::CreatePhoton();
		
		m_pxLightPhoton->SetRange( 0.5f );
		m_pxLightPhoton->SetFalloffPower( dbg_fFalloffPower );
		m_pxLightPhoton->SetFalloffScale( dbg_fFalloffScale );
		m_pxLightPhoton->SetCorona( false );
		const Asura_ShadowParameters xShadowParameters( ( false ? ( ASURA_SHADOWFLAG_CASTS_OWN_SHADOWS | ASURA_SHADOWFLAG_CASTS_ENVIRONMENT_SHADOWS ) : 0 ) | ( false ? ASURA_SHADOWFLAG_USE_NOISE : 0 ) );
		m_pxLightPhoton->SetShadowParameters( xShadowParameters );
		m_pxLightPhoton->SetColours( 0.0f, 0.0f, 0.0f );
		m_pxLightPhoton->SetPosition( GetCurrentPosition() + (xDir*0.01f) );
		m_pxLightPhoton->SetIsDirectional(true);
		
		Asura_Matrix_3x3 xOri;
		Asura_Maths::OrientationFromDirection(xOri, -xDir);
		m_pxLightPhoton->SetLightOrientation( xOri );
	}
	else
	{
		m_pxLightPhoton->SetPosition(GetCurrentPosition() + (xDir*0.01f) );
		Asura_Matrix_3x3 xOri;
		Asura_Maths::OrientationFromDirection(xOri, -xDir);
		m_pxLightPhoton->SetLightOrientation( xOri );
	}
#endif

	switch(m_uMineState)
	{
 		case MINE_IN_FLIGHT:
 		{
			// Do nothing
 		}
 		break;

		case MINE_ARMING:
		{
			// Use a timer
 			m_fStateTimer += Asura_Timers::GetGameTimeSlice();
			
			if(m_pxLightPhoton)
			{
				if(Asura_Maths::Sine(m_fStateTimer*5.0f) > 0.0f)
				{
					m_pxLightPhoton->SetColours(0.0f,20.0f,0.0f);
				}
				else
				{
					m_pxLightPhoton->SetColours(0.0f,0.0f,0.0f);
				}
			}
		}
		break;

		case MINE_ARMED:
		{
			if(m_pxLightPhoton)
			{
				m_pxLightPhoton->SetColours(0.0f,0.0f,0.0f); // dont give away position when just armed.
			}
		}
		break;

		case MINE_TRIGGERED:
		{
			// Just flash at us, we wait for server to make us explode
			m_fStateTimer += Asura_Timers::GetGameTimeSlice();

			if(m_fStateTimer >= m_fDetonationOffset)
			{
				if(m_iTriggerSoundHandle == ASURA_INVALID_HANDLE)
				{
					const Asura_Sound_Event* pxSoundEvent = Asura_Sound_Event_Storage::FindEvent(m_uTriggeredSound); 
					if (pxSoundEvent)
					{
						Asura_Sound_Event_System::PlayEvent(pxSoundEvent, &m_iTriggerSoundHandle, &GetCurrentPosition(), 1.0f, GetGuid());
					}
				}
			}
						
			if(m_pxLightPhoton)
			{
				if(Asura_Maths::Sine(m_fStateTimer*5.0f) > 0.0f)
				{
					m_pxLightPhoton->SetColours(20.0f,0.0f,0.0f);
				}
				else
				{
					m_pxLightPhoton->SetColours(0.0f,0.0f,0.0f);
				}
			}
		}
	}

	UpdateMineContainerAttachmentState();

	PARENT::Update();
}

/// End of file. ///
