//////////////////////////////////////////////////////////////////////////////
//
// AVP_ServerEntity_Squad_Alien.h
//
// Copyright (C) 2008 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __AVP_SERVERENTITY_SQUAD_ALIEN_H__
#define __AVP_SERVERENTITY_SQUAD_ALIEN_H__ 1

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// asura
#include "Core/Asura_List.h"
#include "Core/Asura_Maths.h"

// avp
#include "Entity/Controller/AVP_ServerEntity_Squad.h"

// axon
#include "Core/AxonAVP_Messages.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class AVP_ServerActor_Alien;

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

struct AVP_AlienSpawnToken
{
	Asura_Hash_ID		 m_uBPTypeHashID;
	Asura_Hash_ID		 m_uBPHashID;
	Asura_Guid			 m_uSpawnPointGuid;
	Asura_Guid			 m_uOldActorGuid;
	float				 m_fRespawnTimer;
	AVP_AlienSpawnToken* m_pxNext;

	AVP_AlienSpawnToken()
	: m_uBPTypeHashID( ASURA_HASH_ID_UNSET )
	, m_uBPHashID( ASURA_HASH_ID_UNSET )
	, m_uSpawnPointGuid( ASURA_GUID_UNREGISTERED )
	, m_uOldActorGuid( ASURA_GUID_UNREGISTERED )
	, m_fRespawnTimer( Asura_Maths::LargeFloat )
	, m_pxNext( NULL )
	{
	}
	void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;

private:
	static const u_int uCURRENT_CHUNK_VERSION = 0;
};

//////////////////////////////////////////////////////////////////////////////
//
// AVP_ServerEntity_Squad_Alien
//
//////////////////////////////////////////////////////////////////////////////

class AVP_ServerEntity_Squad_Alien : public AVP_ServerEntity_Squad
{
	typedef AVP_ServerEntity_Squad PARENT;
	friend class ToolsAVP_Entity_Squad_Alien;

public:
	AVP_ServerEntity_Squad_Alien( Asura_Guid uGuid );
	virtual ~AVP_ServerEntity_Squad_Alien();

	virtual void InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint );
	virtual void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	virtual void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual void Update();
	virtual void PreDestructionShutdown();

#ifdef ASURA_TOOLS
	virtual bool CanBeIncludedInTemplate() const { return ( this != s_pxDefaultSquad ); }
#endif

	bool CanAttack( const Asura_Guid uTargetGuid, const Asura_Vector_3& xFromPosition, float fTimeBetweenAttacks ) const;
	u_int GetNumAttackers() const { return m_uNumAttackers; }
	void AddAttacker( const Asura_Guid uAttackerGuid, const Asura_Guid uTargetGuid );
	void RemoveAttacker( const Asura_Guid uAttackerGuid, const Asura_Guid uTargetGuid );
	void AddTargeter( const Asura_Guid uTargeterGuid, const Asura_Guid uTargetGuid );
	void RemoveTargeter( const Asura_Guid uTargeterGuid, const Asura_Guid uTargetGuid );
	bool HasLOSToTarget( const Asura_Guid uTargeterGuid, const Asura_Guid uTargetGuid );

	bool CanCharge( const Asura_Guid uTargetGuid, u_int uMaxNumberOfChargers ) const;
	void AddCharger( const Asura_Guid uTargetGuid );
	void RemoveCharger( const Asura_Guid uTargetGuid );
	void UpdateHealthFraction( const Asura_Guid uAlienGuid, float fHealthFraction );


	bool CanLockAttackGrapple( const Asura_Guid uTargetGuid, const Asura_Vector_3& xFromPosition );
	void LockAttackGrapple( const Asura_Guid uTargetGuid );
	void UnlockAttackGrapple( const Asura_Guid uTargetGuid );
	bool CanLockAttackStand( const Asura_Guid uTargetGuid, const Asura_Vector_3& xFromPosition );
	void LockAttackStand( const Asura_Guid uTargetGuid );
	void UnlockAttackStand( const Asura_Guid uTargetGuid );
	bool CanLockAttackJump( const Asura_Guid uTargetGuid, const Asura_Vector_3& xFromPosition );
	void LockAttackJump( const Asura_Guid uTargetGuid );
	void UnlockAttackJump( const Asura_Guid uTargetGuid );

	bool CanLockAmbushHiss();
	void LockAmbushHiss();
	void ReleaseAmbushHiss();

	void UnspawnAlien( AVP_ServerActor_Alien& xServerAlien, const Asura_Guid uSpawnPointGuid, float fRespawnDelay = -1.0f );

	const AVP_AlienBehaviourData& GetBehaviourData() const { return m_xBehaviourData; }

	Asura_Guid GetSwarmLeaderGuid( const Asura_Guid uTargetGuid ) const;
	int		   GetBurstingCount( const Asura_Guid uTargetGuid ) const;
	bool	   CanBurst( const Asura_Guid uTargetGuid ) const;
	void       SetSwarmLeaderGuid( const Asura_Guid uLeaderGuid, const Asura_Guid uTargetGuid );
	void	   SetBursting( const Asura_Guid uAlienGuid, bool bIsBursting);
	void       ResetSwarmLeaderGuid( const Asura_Guid uLeaderGuid );
	void       ResetSwarmRouteAge( const Asura_Guid uLeaderGuid );
	float      GetSwarmRouteAge( const Asura_Guid uLeaderGuid ) const;

	void	   SetInjurePrecentageOfHealth(float fInjureOnHealthPercentage);
	void	   SetChanceToGetInjoredPercentage(float fChanceToGetInjoredPercentage);
	float      GetInjurePrecentageOfHealth() const;
	float      GetChanceToGetInjoredPercentage() const;

	float GetJumpVsStandFraction() const { return 0.5f; } // obsolete for old behaviors

	static AVP_ServerEntity_Squad_Alien* FindEntity( const Asura_Guid uGuid, const bool bIgnoreDestroyed ) { return s_xList.FindEntity( uGuid, bIgnoreDestroyed ); }
	static Asura_Hashed_List< AVP_ServerEntity_Squad_Alien >* GetList() { return &s_xList; }
	static AVP_ServerEntity_Squad_Alien* GetDefaultSquad() { return s_pxDefaultSquad; }
	static void InitialiseMempools();
	static void ShutdownMempools();


private:

	virtual void* AllocateMemberData( const Asura_Guid uMemberGuid );
	virtual void  ReturnMemberData( void* pData );

	void SpawnAlien( const AVP_AlienSpawnToken& xSpawnToken );
	void DropAcidTrail(bool bForce);
	void SendOnHealthPercentMessages();

private:
	AVP_AlienBehaviourData m_xBehaviourData;

	u_int m_uNumAttackers;

	Asura_List< AVP_AlienSpawnToken > m_xSpawnTokenList;

	struct MemberData
	{
		// Guid this member is targeting.
		Asura_Guid m_uTargetGuid;
		// Guid this member is attacking.
		Asura_Guid m_uAttackeeGuid;
		bool	   m_bHasLOSToTarget;
		bool       m_bIsSwarmLeader;
		bool	   m_bIsBursting;
		float      m_fSwarmRouteAge;
		float	   m_fHealthFraction;
		void Reset()
		{
			m_uTargetGuid = ASURA_GUID_UNREGISTERED;
			m_uAttackeeGuid = ASURA_GUID_UNREGISTERED;
			m_bHasLOSToTarget = false;
			m_bIsSwarmLeader = false;
			m_bIsBursting = false;
			m_fSwarmRouteAge = 0.0f;
			m_fHealthFraction = 1.0f;
		}
	};

	float m_fInjureOnHealthPercentage;
	float m_fChanceToGetInjoredPercentage;
	float m_fPreviousMinHealthFractionSoFar;
	float m_fMinHealthFractionSoFar;
	bool m_bNeedToSendHealthPrecentMessages;
	bool m_bAmbushHissLock;

	static Asura_Hashed_List< AVP_ServerEntity_Squad_Alien > s_xList;
	static Asura_Mempool* s_pxSpawnTokenMempool;
	static Asura_Mempool* s_pxMemberDataMempool;
	static AVP_ServerEntity_Squad_Alien* s_pxDefaultSquad;
	static u_int s_uLOSTestFrame;
	static u_int s_uLOSTestsThisFrame;

	static const u_int uCURRENT_CHUNK_VERSION = 10;
};

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

#endif //__AVP_SERVERENTITY_SQUAD_ALIEN_H__
