//////////////////////////////////////////////////////////////////////////////
//
// AVP_ServerActor_Vertebrate.h
//
// Copyright (c) 2007 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_SERVERACTOR_VERTEBRATE_H___
#define ___AVP_SERVERACTOR_VERTEBRATE_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 "Actor/AVP_Actor_DynamicStat.h"
#include "Blueprint/Asura_Blueprint.h"
#include "Entity/Damage/AVP_EntityDamage.h"
#include "Entity/PhysicalObject/Actor/AVP_ServerEntity_Actor.h"
#include "Rendering/Asura_Project_Skin_Elements.h"

// axon
#include "AnimTemplates/Axon_Gamescene_AnimSequenceData.h"

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

class Asura_Collision_Object;
class Axon_Project_Brain;

class AVP_Message_VertebratePlayerCommands;
class AVP_Vertebrate_StateHandler;
class AVP_Vertebrate_MeleeCounter_System;

// C L A S S E S /////////////////////////////////////////////////////////////

class AVP_ServerActor_Vertebrate : public AVP_ServerEntity_Actor
{
public:

	enum { CURRENT_CLIENTCREATE_VERSION = 1 };

	// Public functions...
	virtual	void 	Update(void);
	virtual	bool 	HandleMessage(const Asura_Message* pxMessage);
	virtual void 	PostLoadInitialise();
	virtual	void	TakeDamageExtended(const AVP_EntityDamage_RequestVictim& xDamage, const bool bForceFatal, const bool bSendMessageToClient = true );

	// Static list functions...
	static AVP_ServerActor_Vertebrate*							FindEntity(const Asura_Guid uGuid)	{ return(s_xList.FindEntity(uGuid)); }
	static const Asura_Hashed_List<AVP_ServerActor_Vertebrate>*	GetList(void)						{ return(&s_xList); }

	bool IsSkinElementAvailable(u_int uSkinElement) const;
	float GetSkinElementHealth(u_int uSkinElement) const { return m_axSkinElementData[uSkinElement].m_fCurrentHealth; }

	u_int GetDestroyedSkinElementFlags() const;

	AVP_Vertebrate_MeleeCounter_System* GetMeleeSystem() { return m_pxMeleeSystem; }
	const AVP_Vertebrate_MeleeCounter_System* GetMeleeSystem() const { return m_pxMeleeSystem; }
	Asura_Guid GetCurrentMeleeTarget() const;

	virtual void GetMeleeOrigin(Asura_Vector_3& xOrigin) const;

	virtual bool IsDowned() const { return false; }

	// TODO - this probably wants to be the arbitrating inventory (once such a thing exists), rather than the master one.
	AVP_Inventory_System* GetMasterInventory();

	// Wrapper
	virtual u_int	GetElementFromBoneID(int iBoneID) const { return NUM_AVP_SKIN_ELEMENT_TYPES; }
	virtual int		GetAnyBoneIDFromElement(u_int uElement) const { return -1; } // Since bones->elements is a many->one mapping, this function will return one of the bones associated with the given element, but not necessarily the only one.

	// Overridden chunk-handling functions...
	virtual	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	virtual	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;
	virtual void WriteToClientCreateStream(Asura_Chunk_Memory_Stream& xStream) const;

	void SetIsAllowedToFlinch( bool bCanFlinch ) { m_bCanFlinch = bCanFlinch; }

	virtual void MakePlayer(Asura_Guid uPlayerGuid);		
	virtual void MakeAI();

	void CreateAIDistraction( const Asura_Guid uDistractionTarget = ASURA_GUID_UNREGISTERED ) const;
	void CreateAIReconDistraction() const;

	bool IsFlinching() const;
	float GetTimeLeftInFlinching() const {	return Asura_Maths::Max(m_fFlinchAnimDuration - m_fTimeSinceLastFlinch, 0.0f); }

	void SetAllowDamageLimb(bool bAllow) { m_bAllowDamageLimb = bAllow; }
	bool GetAllowDamageLimb() const { return m_bAllowDamageLimb; }

	void DestroySkinElement(const u_int uElement); // Way for outside systems to flag elements as destroyed, externally to damage.

protected:
	// Protected functions...
	virtual void UpdateMovement();

	void	ProcessVertebratePlayerCommands( const AVP_Message_VertebratePlayerCommands* pxData, float fMessageSentTime );

    virtual void	InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint );
	virtual void	RegisterMovementSoundsForAI();

	virtual float CalculateAndUpdateLocationSpecificDamage(const AVP_EntityDamage_RequestVictim& xDamage, u_int& uDestroyedSkinElements, u_int& uGibbedSkinElements, bool bForceFatal);
	virtual bool GetDamageCreatesGib(const AVP_EntityDamage_RequestVictim& xDamage) const;

	AVP_ServerActor_Vertebrate(const u_short usFlagsToIgnore, const Asura_Guid uGUID);
	virtual ~AVP_ServerActor_Vertebrate(void);

	void UpdatePlayersGamePlayVolume(void);

	// Overridden event functions...
	virtual void	OnDeath(const AVP_EntityDamage_ApplyToEntity& xDamage);

	void AddFlinchEffect(const AVP_EntityDamage_RequestVictim& xDamage);
	void StartFlinch();
	virtual const Asura_Blueprint* GetCurrentFlinchBlueprint() const { return NULL; }
	bool GetCanFlinch(bool& bFlinchInProgress) const;

	virtual bool GetIsInLowStance() const { return false; }

	AVP_Vertebrate_MeleeCounter_System* m_pxMeleeSystem; // Protected as is abstract, must be created in children

private:
	
	// Private typedefs...
	typedef AVP_ServerEntity_Actor PARENT; 

	// Friend classes...
	friend class ToolsAVP_Entity_Actor;

	// Private variables...
	// This enum refers to the direction the flinch will move you, not the direction the damage came from.
	enum FlinchDirection
	{
		FORWARD_LEFT = 0, // The first four are the original style, where the victim retains his current orientation
		FORWARD_RIGHT,
		BACKWARD_LEFT,
		BACKWARD_RIGHT,
		FORWARD, // The next two are the new style where the victim turns towards/away from (respectively) the direction of damage.
		BACKWARD,

		NUM_DIRECTIONS,
	};

	enum FlinchStance
	{
		STANDING,
		CROUCHING,

		NUM_STANCES,
	};

	// Every limb has it's own health. So once it will drop to zero, limb will fall of. Leg, Hand, tail, etc... However, torso
	// itself, can't be destroyed in this way. When player hits any limb and damage it, the damage will be also applied to "global"
	// health of that person. However, we have to use DamageMultiplier for distinguish between head-shot or limb-shot. Head-shot will
	// take more damage as for example damage from left leg.
	struct AVP_VertebrateSkinElement_ServerData
	{
		Asura_Hash_ID m_uBlueprint;
		float m_fCurrentHealth;
		float m_fDamageMultiplier;
		union
		{
			u_int m_uFlags;
			struct
			{
				u_int	m_bEssential	: 1,
						m_bDestructible	: 1,
										: 0;
			};
		};
	};

	Asura_Vector_3 m_xStoredFlinchEffect;
	float m_fStoredFlinchImpulse;
	float m_fLastFlinchMinImpulse;
	float m_fTimeSinceLastFlinch;
	float m_fFlinchAnimDuration;
	bool m_bCanFlinch;
	bool m_bAllowDamageLimb;

	AVP_VertebrateSkinElement_ServerData m_axSkinElementData[NUM_AVP_SKIN_ELEMENT_TYPES];

	static const char* const s_aaszFlinchParameterNames[NUM_DIRECTIONS][NUM_STANCES];

	static Asura_Hashed_List<AVP_ServerActor_Vertebrate> s_xList;

	static const u_int uCURRENT_CHUNK_VERSION = 2;
};

// Data required to define flinches.
const u_int uAVP_VERTEBRATE_MAX_FLINCH_TYPES = 4;

struct AVP_Vertebrate_FlinchData
{
	Asura_Hash_ID m_uFirstPersonBlueprint;
	Asura_Hash_ID m_uThirdPersonBlueprint;
	float m_fMinAttackPower;
	float m_fProbability;
	float m_fMinDelay;
	float m_fMaxDelay;
	bool m_bUseFlinchMove;
	bool m_bDisableSurfaceReorientation;
	bool m_bResetAimDirection;
	bool m_bOrientateToImpactDirection;
};

///////////////////////////////////////////////////////////////////
// Parameter enumerators to handle the more complex flinch data. //
///////////////////////////////////////////////////////////////////

// Enumerator to fill the flinch types array.
class AVP_Blueprint_ParameterEnumerator_FlinchTypes : public Asura_Blueprint_ParameterEnumerator
{
public:
	// This class will ensure it doesn't write more than uAVP_VERTEBRATE_MAX_FLINCH_TYPES entries, so ensure the storage is at least that big.
	// The class will also set the number of entries to the correct value;
	AVP_Blueprint_ParameterEnumerator_FlinchTypes(AVP_Vertebrate_FlinchData* pxFlinchDataStorage, u_int& uNumFlinchEntries, const Asura_Hash_ID uMovesBlueprintType);

	virtual void BeginEnumeration(void);
	virtual bool Enumerate(const u_int uIndex, char const* const szName, const Asura_Value& xValue);
	virtual void EndEnumeration(const bool bSuccess);

protected:
	AVP_Vertebrate_FlinchData* m_pxFlinchDataStorage;
	u_int& m_uNumFlinchEntries;
	const Asura_Hash_ID m_uMovesBlueprintType;
};

// Enumerator to pick a flinch variation. Can either pick a random one or a specified one (if there are enough parameters for the specified one).
class AVP_Blueprint_ParameterEnumerator_FlinchSelector : public Asura_Blueprint_ParameterEnumerator
{
public:
	AVP_Blueprint_ParameterEnumerator_FlinchSelector(int iSpecifiedVariation = -1);

	virtual void BeginEnumeration(void);
	virtual bool Enumerate(const u_int uIndex, char const* const szName, const Asura_Value& xValue);
	virtual void EndEnumeration(const bool bSuccess);

	Asura_Hash_ID GetSelectedFlinch() const;
	int GetSelectedVariation() const; // So this can be stored for future enumerations, e.g. ensuring you get the matching first and third person flinches.

protected:
	enum { MAX_FLINCH_VARIATIONS = 8 };

	Asura_Hash_ID m_auFlinchAnims[MAX_FLINCH_VARIATIONS];
	int m_iNumFlinchVariations;
	int m_iSelectedVariation;
};

#endif // #ifndef ___AVP_SERVERACTOR_VERTEBRATE_H___
