
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_RangedWeapon_ClientEffectsHandler.h
// Author : Will Plano
// Date   : 11/12/2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif   // ifdef ASURA_USE_PRAGMA_ONCE

#ifndef __AVP_RANGEDWEAPON_CLIENTEFFECTSHANDLER_H__
#define __AVP_RANGEDWEAPON_CLIENTEFFECTSHANDLER_H__

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

// asura
#include "Core/Asura_HashTree.h"
#include "Rendering/Asura_Colour.h"
#include "SpecialFX/Asura_Beam_System.h"

// avp 
#include "Inventory/Items/Weapons/AVP_InventoryWeapon_RangedWeapon.h"

////////////////////////////////////////////////////////////////////////////////
// Forward class declarations...
////////////////////////////////////////////////////////////////////////////////

class Asura_Animation;
class Asura_AnimationAttachment_Projector;
class Asura_Blueprint;
class Asura_Sound_Event;
class AVP_Actor_AnimStateData;
class AVP_AnimationAttachment_Laser;
class Asura_AnimationAttachment_Animation;
class AVP_Laser;

////////////////////////////////////////////////////////////////////////////////
// Class declaration...
////////////////////////////////////////////////////////////////////////////////

#define AVP_MAX_MUZZLE_FLASH_EFFECT_PFX 3

// Class that will contain list of PFX and Sound. These variables will be used for creating MuzzleEffect. (Like Fire, Smoke, HotBarrel, etc...)
class AVP_MuzzleFlash_Data
{
public:
	AVP_MuzzleFlash_Data() : m_uNumPFX(0), m_uSoundHash( ASURA_HASH_ID_UNSET ) {}

	bool InitialiseFromBlueprint( const Asura_Hash_ID uBlueprintHash );
	u_int GetNumOfPFX()	const {return m_uNumPFX;}
	Asura_Hash_ID GetPFXHash( u_int uNumber ) const
	{
		if( uNumber>=AVP_MAX_MUZZLE_FLASH_EFFECT_PFX || uNumber>=GetNumOfPFX() )
		{
			Asura_Assertf( false, ("Failed to get Proper muzzle PFX for weapon. We are requesting PFX number: %d, but maximum number of PFX is: %d", uNumber, Asura_Maths::Min(GetNumOfPFX(), (u_int)AVP_MAX_MUZZLE_FLASH_EFFECT_PFX) ) );
			return ASURA_HASH_ID_UNSET;
		}
		return m_auPFXHash[uNumber];
	}
	Asura_Hash_ID GetSoundHash() const	{ return m_uSoundHash; }	// For the moment, it contain correct data, but it is not playing the sound yet.

private:
	u_int m_uNumPFX;
	Asura_Hash_ID m_auPFXHash[ AVP_MAX_MUZZLE_FLASH_EFFECT_PFX ];
	Asura_Hash_ID m_uSoundHash;										// For the moment, it contain correct data, but it is not playing the sound yet.
};


class AVP_RangedWeapon_ClientEffectsHandler
{
public:
	enum EffectType
	{
		EFFECT_ANY = -1,

		EFFECT_RELOAD = 0,
		EFFECT_FIRE_BEGIN,
		EFFECT_FIRE_LOOP,
		EFFECT_FIRE_END,
		EFFECT_CHARGING,
		NUM_EFFECT_TYPES
	};
	AVP_RangedWeapon_ClientEffectsHandler( const Asura_Hash_ID uHash, const Asura_Guid uOwnerGuid );
	virtual ~AVP_RangedWeapon_ClientEffectsHandler();

	void PlaySound( AVP_ClientEntity_Actor& xClient, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );
	void StopSound( const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );
	void UpdateSoundPosition( const Asura_Vector_3& xPosition, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );
	bool IsSoundPlaying( const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );

	void PlayActorAnim( AVP_ClientEntity_Actor& xClient, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY);
	void StopActorAnim( AVP_ClientEntity_Actor& xClient, const bool bDestroyIfNoEndAnim, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );
	void DestroyActorAnim( AVP_ClientEntity_Actor& xClient );
	bool IsActorAnimPlaying( const AVP_ClientEntity_Actor& xClient, const EffectType eEffect = EFFECT_ANY, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY ) const;
	u_int GetActorAnimFlagsForLastFrame( const AVP_ClientEntity_Actor& xClient ) const;

	void PlayPermenantWeaponAnim(void);
	void StopPermenantWeaponAnim(void);
	bool IsPermenantWeaponAnimPlaying(void) const;
	void SetWeaponPermenantAnimParametricTimer(float fParametricTimer);

	void SetWeaponAnimParametricTimer(float fParametricTimer, AVP_ClientEntity_Actor& xClient, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY);
	void PlayWeaponAnim( const AVP_ClientEntity_Actor& xClient, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY);
	void PlayWeaponAnim( const Asura_Hash_ID uHash );
	void StopWeaponAnim( const AVP_ClientEntity_Actor& xClient, const bool bDestroyIfNoEndAnim, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY );
	bool IsWeaponAnimPlaying( const AVP_ClientEntity_Actor& xClient, const EffectType eEffect = EFFECT_ANY, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY ) const;
	void DoChargePFX( const AVP_ClientEntity_Actor& xClient, Asura_Animation& xAnimation, const Asura_Vector_3& xFirePosition, const Asura_Matrix_3x3& xFireOrientation, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType );
	void StopChargePFX( const AVP_InventoryWeapon_RangedWeapon::SubType eSubType );
	bool IsChargePFXPlaying( const AVP_InventoryWeapon_RangedWeapon::SubType eSubType ) const;

	void DoRecoilCameraShake(const Asura_Guid uPlayerGuid, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType );
	void DoTracerBeam( const Asura_Vector_3& xFirePosition, const Asura_Matrix_3x3& xFireOrientation, const float fRange, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType, u_int uNumTracers );

	void UpdateAmmoCount(Asura_Animation* pxAnimation, float fAmmo);

	enum MuzzleFlashTypes
	{
		FLASH_FIRE = 0,
		FLASH_RELOAD,
		FLASH_HOT,
	};
	void DoMuzzleFlash( MuzzleFlashTypes eMuzzleFlashType, const AVP_ClientEntity_Actor& xClient, Asura_Animation& xAnimation, const Asura_Vector_3& xFirePosition, const Asura_Matrix_3x3& xFireOrientation, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType );
	float GetWeaponHotMuzzleFlash_NumBulletsToBegin( const AVP_InventoryWeapon_RangedWeapon::SubType eSubType );


	void ActivateLaser( Asura_Animation& xAnimation );
	void DeactivateLaser();

	void SetTracerCount( u_int uCount )	{ m_uTracerCount = uCount; }
	void SetLaserTarget( const Asura_Vector_3& xPosition ); 
	void SetLaserTarget( const Asura_Guid uTargetGuid, const Asura_Hash_ID uTargetMPHash ); 
	void ResetLaserTarget(void);
	void UpdateLaserLoopedSound( const Asura_Vector_3& xFirePosition);

	virtual Asura_Animation* CreateAnimation();
	void DestroyAnimation();
	Asura_Animation* GetAnimation() { return m_pxAnimation; }
	const Asura_Animation* GetAnimation() const { return m_pxAnimation; }

	bool HasLaser() const { return m_pxLaserAttachment != NULL; }

	static void ResetStorage() { s_xClientDataTree.Reset(); }

	Asura_Animation* AddPermenantAnimation( const Asura_Hash_ID uAnimHash, u_int uPriority );
	void RemovePermenantAnimation( const Asura_Hash_ID uAnimHash );

	void SetRestAnim( const Asura_Hash_ID uRestAnim );

protected:
	Asura_Guid								m_uOwnerGuid;
	Asura_Animation*						m_pxAnimation;

private:
	Asura_Hash_ID GetActorAnimForEffectType( const AVP_Actor_AnimStateData& xStateData, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY, float* pfTweenTime = NULL ) const;
	Asura_Hash_ID GetWeaponAnimForEffectType( const AVP_Actor_AnimStateData& xStateData, const EffectType eEffect, const AVP_InventoryWeapon_RangedWeapon::SubType eSubType = AVP_InventoryWeapon_RangedWeapon::ST_PRIMARY, float* pfTweenTime = NULL ) const;

	void DoMuzzleFlashEffect( const AVP_MuzzleFlash_Data* pxMuzzleFlashData, const AVP_ClientEntity_Actor& xClient, Asura_Animation& xAnimation, const Asura_Vector_3& xFirePosition, const Asura_Matrix_3x3& xFireOrientation, const Asura_Hash_ID uMarkerPoint );

	struct AVP_RangedWeapon_ClientData
	{
		AVP_RangedWeapon_ClientData();

		bool InitialiseFromBlueprint( const Asura_Hash_ID uBlueprintHash );
		void InitialiseLaserFromBlueprint( const Asura_Blueprint& xBlueprint );

		int								m_iLaserNumDots;
		float							m_fLaserBeamRadius;
		float							m_fLaserRadius;
		float							m_fLaserBeamSharpness;
		float							m_fLaserBeamSpread;
		float							m_fLaserMaxLength;
		float							m_fLaserFalloffLength;

		float							m_fLaserFallOffStartAngle;
		float							m_fLaserFallOffEndAngle;
		float							m_fLaserFallOffStartDistance;
		float							m_fLaserFallOffEndDistance;
		float							m_fLaserFallOffAngleEndIntensity;
		float							m_fLaserBeamVisibilityDistance;

		bool							m_bOriginPhotonEnabled;	
		float							m_fOriginPhotonRadius;
		float							m_fOriginPhotonFalloffScale;
		float							m_fOriginPhotonFalloffPower;
		bool 							m_bOriginPhotonEnableDistanceFade;
		float 							m_fOriginPhotonDistanceFadeStart;
		float 							m_fOriginPhotonDistanceFadeDist;

		bool							m_bContactPhotonEnabled;
		float 							m_fContactPhotonRadius;
		float 							m_fContactPhotonFalloffScale;
		float 							m_fContactPhotonFalloffPower;
		bool  							m_bContactPhotonEnableDistanceFade;
		float 							m_fContactPhotonDistanceFadeStart;
		float 							m_fContactPhotonDistanceFadeDist;
		float 							m_fContactPhotonBackOffDistance;

		Asura_RGBA						m_xOriginPhotonColour;
		Asura_RGBA						m_xContactPhotonColour;




		Asura_Hash_ID					m_uLaserMarkerPoint;
		Asura_Hash_ID					m_uLaserFalloffTextureHash;
		Asura_Hash_ID					m_uLaserProjectedTextureHash;

		Asura_Hash_ID					m_uLaserActivationSoundHash;
		Asura_Hash_ID					m_uLaserDeactivationSoundHash;
		Asura_Hash_ID					m_uLaserLoopingSoundHash;

		Asura_Hash_ID					m_uBulletBySoundHash;

		Asura_Hash_ID					m_uSkinHash;

		Asura_Hash_ID					m_uPermenantAnimHash;

		Asura_Hash_ID					m_uAmmoCounterMarker1Hash;
		Asura_Hash_ID					m_uAmmoCounterMarker2Hash;
		Asura_Hash_ID					m_uAmmoCounterAttachment;
		
		struct AVP_RangedWeapon_SubType_ClientData
		{
			AVP_RangedWeapon_SubType_ClientData();

			void InitialiseFromBlueprint( const Asura_Hash_ID uSubTypeBPHash );
			void InitialiseBeamTemplateFromBlueprint( const Asura_Hash_ID pxTracerBPHash );

			Asura_Hash_ID				m_auSoundEventHash[ NUM_EFFECT_TYPES ];

			Asura_Hash_ID				m_uMuzzleMarkerHashFirstPerson;
			Asura_Hash_ID				m_uMuzzleMarkerHashThirdPerson;

			Asura_Hash_ID				m_uChargingPFXHash;
			Asura_Hash_ID				m_uCameraShakeHash;

			Asura_Beam_Template 		m_xTracerTemplate;

			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Fire1P;
			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Fire3P;
			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Reload1P;
			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Reload3P;
			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Hot1P;
			AVP_MuzzleFlash_Data		m_xMuzzleFlash_Hot3P;
			float						m_fMuzzleFlash_Hot_NumBulletsToBegin;	// How many bullets needs to be shot, before the Reload effect will start to play.


			static void	SetBeamColourFromARGB( Asura_Beam_Colour& xColour, const u_int uARGB );

		}	m_axSubTypeData[ AVP_InventoryWeapon_RangedWeapon::NUM_SUB_TYPES ];

	}*	m_pxClientData;

	AVP_AnimationAttachment_Laser*			m_pxLaserAttachment;
	Asura_AnimationAttachment_Animation*	m_pxAmmoAttachments[2];

	u_int									m_uTracerCount;

	Asura_Handle	m_aaiSoundHandles[ NUM_EFFECT_TYPES ][ AVP_InventoryWeapon_RangedWeapon::NUM_SUB_TYPES ];
	Asura_Handle	m_iLaserSoundHandle;
	u_int			m_uCurrentChargePFXEffectID[ AVP_InventoryWeapon_RangedWeapon::NUM_SUB_TYPES ];
	Asura_Hash_ID	m_uActorAnimControllerHash;
	Asura_Hash_ID	m_uWeaponAnimControllerHash;

	Asura_Hash_ID	m_uCurrentActorAnimHash;
	Asura_Hash_ID	m_uCurrentWeaponAnimHash;

	Asura_Hash_ID	m_uRestAnimHash;
	Asura_Hash_ID	m_uRestAnimControllerHash;

	static Asura_TemplateHashTree< AVP_RangedWeapon_ClientData >	s_xClientDataTree;

	static void InitiliaseLaserFromClientData( AVP_Laser* pxLaser, const AVP_RangedWeapon_ClientData* const pxClientData, const Asura_Guid uOwnerGuid );

public:
		const AVP_RangedWeapon_ClientData* GetClientData(void) const { return m_pxClientData; }
};

#endif   // ifndef __AVP_RANGEDWEAPON_CLIENTEFFECTSHANDLER_H__

/// End of file. ///
