//////////////////////////////////////////////////////////////////////////////
//
// FILE : Asura_ServerEntity_PhysicalObject.h
//
// Copyright (C) 2002 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
    #pragma once
#endif

#ifndef __ASURA_SERVER_ENTITY_PHYSICAL_OBJECT_H__
#define __ASURA_SERVER_ENTITY_PHYSICAL_OBJECT_H__

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

#include "Animation/Asura_Animation.h"
#include "Core/Asura_Hash.h"
#include "Debugging/Asura_Assert.h"
#include "Dynamics/Asura_Collision_Object.h"
#include "Entity/Asura_Entity.h"
#include "Entity/PhysicalObject/Asura_Dynamic_Extents.h"
#include "Physics/Asura_Physics_Object.h"

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

class ApplyForceMsg_ImpulseData;
class Asura_AI_NavConnection_Index;
template< typename T > class Asura_Hashed_List;
class Axon_Brain;

//////////////////////////////////////////////////////////////////////////////
//
// Asura_ServerEntity_PhysicalObject
//
//////////////////////////////////////////////////////////////////////////////

//Defines for m_uPhysicalObjectFlags
#define ASURA_PHYSICALOBJECT_FLAG_NOSHADOW               0x00000001 //Animation doesn't have a shadow
#define ASURA_PHYSICALOBJECT_FLAG_STATIC                 0x00000002 // (NRM - 12.07.2003) useful for reducing AABB position tests
#define ASURA_PHYSICALOBJECT_FLAG_NOCOLLISIONS           0x00000004 // Causes object to have no collisions (which may also occur because of the shape being flagged in this way)
#define ASURA_PHYSICALOBJECT_FLAG_SHOULDMERGEWITHENV     0x00000008 // If set then the object's mesh should be merged into the environment's mesh
#define ASURA_PHYSICALOBJECT_FLAG_ISMERGEDWITHENV	     0x00000010 // Indicates that the mesh for this object is part of the environment
#define ASURA_PHYSICALOBJECT_FLAG_IGNOREMODULELINKING    0x00000020 // Ignore module linking when rendering
#define ASURA_PHYSICALOBJECT_FLAG_INVISIBLE	             0x00000040 // Object isn't rendered or hit by LOS
#define ASURA_PHYSICALOBJECT_FLAG_SHOULDMERGEWITHSKY     0x00000080 // (RJF - 12.07.2005) If set then this object's mesh/anim should be rendered as part of the skybox
#define ASURA_PHYSICALOBJECT_FLAG_FULLBRIGHT             0x00000100 // Object is drawn at maximum normal brightness.
#define ASURA_PHYSICALOBJECT_FLAG_BLOCKWAYPOINTLINKS     0x00000200 // Object should block waypoint links. This is off by default except for doors. Can be toggled in tools.
#define ASURA_PHYSICALOBJECT_FLAG_ISSKIN                 0x00000400 // (RAR - 26/06/2006) Used as a means to differentiate between shapes and skins with no anims (mainly required for client update message)
#define ASURA_PHYSICALOBJECT_FLAG_USEANIMMOVEMENT        0x00000800 // (RAR - 27/06/2006) Compass movement stored in animation will be added to position/orient for rendering and client-side LOS purposes.
#define ASURA_PHYSICALOBJECT_FLAG_IGNOREFORLOS	         0x00001000 // (RAR - 13/09/2006) Disables LOS test for this entity
#define ASURA_PHYSICALOBJECT_FLAG_BLOCKNAVDATAGENERATION 0x00002000 // (TI  - 01/03/2007) Object should block waypoints and links. Off by default except for doors and statics. Can be toggled in tools.
#define ASURA_PHYSICALOBJECT_FLAG_ATTACHEDWITHPHYSICS    0x00004000 // (NY  - 06/03/2007) Object is attached to a parent, but with external control physics
#define ASURA_PHYSICALOBJECT_FLAG_1STPROJECTSPECIFIC     0x00010000 // (RDM - 14.07.2004) make sure this is the last entry!

#define ASURA_oldPHYSICALOBJECT_FLAG_1STPROJECTSPECIFIC 0x00000100 // RJF - 12.07.2005 - this old value previously gave us no room to breathe so it's being replaced
#define ASURA_oldPHYSICALOBJECT_MASK_PROJECTSPECIFIC	0xFFFFFF00 // AND this with a value to select only any old-style project specific flags
#define ASURA_oldPHYSICALOBJECT_SHIFT_PROJECTSPECIFIC	8		   // Number of places to shift old project specific flags to map to new values

#define ASURA_MSG_PLAY_PFX_MAX_CHARS					16

class Asura_ServerEntity_PhysicalObject : public virtual Asura_Entity_Server
{
	typedef Asura_Entity_Server PARENT;

    friend class Tools_Entity_PhysicalObject;// to set health
	friend class Asura_Entity_System;//To allow access to the dynamic BB so it can be rendered.

protected:
	Asura_ServerEntity_PhysicalObject(int iBBIndex = ASURA_DYNAMIC_BB_DEFAULT);
	virtual ~Asura_ServerEntity_PhysicalObject();

public:
	// Destructibility info...
	bool IsDead() const			{ return m_fHealth<=0.0f; }
	bool IsDestructible() const	{ return m_bIsDestructible; }
    void SetDestructible(bool bEnable)   { m_bIsDestructible = bEnable; }
	bool IsDamageable() const	{ return (IsDestructible() && !IsDead() && !IsDestroyed()); }

	float GetHealth() const { return m_fHealth; }
	void SetHealth(float fHealth);

	float GetMaxHealth() const { return m_fMaxHealth; }
	void SetMaxHealth(float fMax) { m_fMaxHealth = fMax; }

	bool HasShapeOrSkin() const { return (GetShapeFileID() != ASURA_HASH_ID_UNSET) || (GetSkinID() != ASURA_HASH_ID_UNSET); }

	Asura_Hash_ID GetShapeFileID() const { return ( m_uSkinID == ASURA_HASH_ID_UNSET ) ? m_uFileID : ASURA_HASH_ID_UNSET; }

	void SetShapeFileID(Asura_Hash_ID uFileID)
    { 
        m_uFileID = uFileID;
        m_uSkinID = ASURA_HASH_ID_UNSET;
        m_uAnimID = ASURA_HASH_ID_UNSET;
        m_uAnimFileID = ASURA_HASH_ID_UNSET;
		UpdateSkinPhysicalObjectFlag();
		ResetCollisionObject();
    }

    Asura_Hash_ID GetSkinID() const { return m_uSkinID; }
    Asura_Hash_ID GetAnimID() const { return m_uAnimID; }
    
    void SetSkinAndAnimID(Asura_Hash_ID uSkinID, Asura_Hash_ID uAnimID)
    {
        m_uSkinID = uSkinID;
        m_uAnimID = uAnimID;
		UpdateSkinPhysicalObjectFlag();
		ResetCollisionObject();
    }

    void SetSkinAndAnimFileID(Asura_Hash_ID uSkinFileID, Asura_Hash_ID uAnimFileID)
    {
        m_uFileID = uSkinFileID;
        m_uAnimFileID = uAnimFileID;
		ResetCollisionObject();
    }

    Asura_Hash_ID GetSkinFileID() const { return ( m_uSkinID == ASURA_HASH_ID_UNSET ) ? ASURA_HASH_ID_UNSET : m_uFileID; }
    Asura_Hash_ID GetAnimFileID() const { return ( m_uAnimID == ASURA_HASH_ID_UNSET ) ? ASURA_HASH_ID_UNSET : m_uAnimFileID; }
    int GetAnimFlags() const { return ( m_uAnimID == ASURA_HASH_ID_UNSET ) ? 0 : m_iAnimFlags; }
	void SetAnimFlags(int iAnimFlags) { m_iAnimFlags = iAnimFlags; };

	u_int GetPhysicalObjectFlags() const { return m_uPhysicalObjectFlags; }
	void  SetPhysicalObjectFlags(u_int uFlags); 

	bool ShouldBeMergedWithEnvironment() const {return (m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_SHOULDMERGEWITHENV) !=0;}
	bool IsMergedWithEnvironment() const {return (m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_ISMERGEDWITHENV) !=0;}

	bool IsMergedWithSkybox() const {return (m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_SHOULDMERGEWITHSKY) !=0;}
	bool IsIgnoreForLOS() const {return (m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_IGNOREFORLOS) !=0;}

	//Indicates whether the physical object 'no collisions' flag has been set. The object
	//may have no collisions for other reasons however.
	bool HasNoCollisionsFlag() const {return (m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_NOCOLLISIONS) !=0;}
	void SetNoCollisionsFlag(bool bSet);

	void SetBlockNavDataGenerationFlag( bool bBlock );
	bool HasBlockNavDataGenerationFlag() const { return ( m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_BLOCKNAVDATAGENERATION ) != 0; }

    bool HasBlockWaypointLinksFlag() const { return ( m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_BLOCKWAYPOINTLINKS ) != 0; }
    void SetBlockWaypointLinksFlag( bool bBlock );

	void SetAttachedWithPhysicsFlag( bool bAttachWithPhysics );
	bool HasAttachedWithPhysicsFlag() const { return ( m_uPhysicalObjectFlags & ASURA_PHYSICALOBJECT_FLAG_ATTACHEDWITHPHYSICS ) != 0; }

	Asura_Physics_Object::COLLISION_PROXY	GetCollisionProxy(void) const											{ return((m_pxDynamicObject == NULL) ? Asura_Physics_Object::COLLISION_PROXY_OBB : m_pxDynamicObject->GetCollisionProxy()); }
	void									SetCollisionProxy(const Asura_Physics_Object::COLLISION_PROXY eProxy)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetCollisionProxy(eProxy); }

	float	GetGravityScale(void) const			{ return((m_pxDynamicObject == NULL) ? 1.000f : m_pxDynamicObject->GetGravityScale()); }
	void	SetGravityScale(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetGravityScale(fValue); }

	float	GetElasticity(void) const			{ return((m_pxDynamicObject == NULL) ? 1.000f : m_pxDynamicObject->GetElasticity()); }
	void	SetElasticity(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetElasticity(fValue); }

	float	GetFriction(void) const			{ return((m_pxDynamicObject == NULL) ? 0.200f : m_pxDynamicObject->GetFriction()); }
	void	SetFriction(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetFriction(fValue); }

	float	GetDrag(void) const			{ return((m_pxDynamicObject == NULL) ? 0.001f : m_pxDynamicObject->GetDrag()); }
	void	SetDrag(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetDrag(fValue); }

	float	GetAngularDrag(void) const			{ return((m_pxDynamicObject == NULL) ? 0.01f : m_pxDynamicObject->GetAngularDrag()); }
	void	SetAngularDrag(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetAngularDrag(fValue); }

	float	GetInvMass( bool bReturnEffectiveValue = true ) const			{ return((m_pxDynamicObject == NULL) ? 1.000f : m_pxDynamicObject->GetInvMass(bReturnEffectiveValue)); }
	void	SetInvMass(const float fValue)	{ if(m_pxDynamicObject != NULL) m_pxDynamicObject->SetInvMass(fValue); }

	void SetOnlyCollideWithEnvironmentAndStaticObjects( bool bNewSetting ) { if ( m_pxDynamicObject ) m_pxDynamicObject->SetOnlyCollideWithEnvironmentAndStaticObjects( bNewSetting ); }
	bool IsOnlyCollideWithEnvironmentAndStaticObjects() const { return m_pxDynamicObject ? m_pxDynamicObject->IsOnlyCollideWithEnvironmentAndStaticObjects() : false; }

    bool HasBlockedLinks() const { return m_bBlockedLinks; }

	#ifdef ASURA_TOOLS
	//Used by skybox objects to ensure the client entity exists and is up to date while in tools
	void ForceClientUpdate();
	#endif

#ifdef ASURA_USE_STREAMING
    // This function starts an asynchronous pass on all of the physical objects to calculate any waypoint link blocks and activate them if necessary.
    // It is only used when streaming once a new zone has been loaded in, to allow the already resident objects to operate on the newly loaded waypoint graph.
    static void BeginLinkBlockPass();
    static void UpdateLinkBlockPass();
    static void ShutdownLinkBlockPass();
private:
    static bool         s_bLinkBlockPassPending;
    static unsigned int s_uLinkBlockPassFrameStart;
public:
#endif

    // Before calculating the waypoint link blocks the memory for the calculations must be initialised.
    // After all necessary objects have calculated their blocked links the memory should be let go.
    // These functions accomplish that.
    static bool WaypointLinkBlockCalculationsInitialised() { return ( s_pxLinksToBlock != NULL ); }
    static void InitialiseWaypointLinkBlockCalculations();
    static void ShutdownWaypointLinkBlockCalculations();
    // Determines which links this object should block. Returns whether the link block information changed or not.
    // Note that if we have already calculated them for this object they won't be re-calculated unless we force them to be (which we do by default).
    virtual bool CalculatePhysicsObjectWaypointLinkBlocks( Asura_Physics_Object* pxPhysicsObject, const bool bForceUpdate = true );
	virtual bool CalculateWaypointLinkBlocks( const bool bForceUpdate = true )
	{
		return CalculatePhysicsObjectWaypointLinkBlocks( m_pxDynamicObject, bForceUpdate );
	}

    virtual void UpdateWaypointLinkBlocks( const bool bForceRemoval = false );
    // Returns whether the link block information changed or not.
    bool DiscardWaypointLinkBlockInformation();
	u_int GetNumLinksToBlock() const { return m_uNumLinksToBlock; }

    // send a network message to clients to change animation to this one.
    // ensures that if you join a game halfway through you get the right anim
    // when you create the object

	// Note that the start and end times are ignored unless the appropriate flags are set (Asura_PhysicalObject_AnimationFlag_UseStartTime , Asura_PhysicalObject_AnimationFlag_UseEndTime) RAR 25/08/2006
    void ChangeAnim(Asura_Hash_ID uAnimID, Asura_Hash_ID uAnimFileID, 
                    int iAnimFlags = AsuraAnimationFlag_Tween, float fTweenDuration = 0.2f, float fStartTime = 0.0f,float fEndTime = 1.0f);

    inline bool HasSkinOrHierarchy() const { return (m_uSkinID != ASURA_HASH_ID_UNSET); }

	// Position, orientation...
	virtual const Asura_Vector_3& GetPosition() const  { return m_pxDynamicObject ? m_pxDynamicObject->GetPosition() : Asura_Maths::ZeroVector3; }
	virtual const Asura_Matrix_3x3& GetOrientation() const { return m_pxDynamicObject ? m_pxDynamicObject->GetOrientation() : Asura_Maths::IdentityMatrix3x3; }
	// Some velocity methods, taken from later derived classes and brought back up to this class since they're so useful.
	virtual const Asura_Vector_3& GetImpulse() const { return m_pxDynamicObject ? m_pxDynamicObject->GetLinImpulse() : Asura_Maths::ZeroVector3; }
	virtual void SetLinImpulse( const Asura_Vector_3& xImpulse ) { if (m_pxDynamicObject) { m_pxDynamicObject->SetLinImpulse(xImpulse); } }
	virtual const Asura_Vector_3& GetVelocity() const { return m_pxDynamicObject ? m_pxDynamicObject->GetLinVelocity() : Asura_Maths::ZeroVector3; }
	virtual void SetLinVelocity( const Asura_Vector_3& xVelocity ) { if (m_pxDynamicObject) { m_pxDynamicObject->SetLinVelocity(xVelocity); } }
	virtual void GetAngVelocity( Asura_Vector_3& xAng ) const
	{
		if(m_pxDynamicObject)
		{
			Asura_Vector_3 xLin; // Discarded
			m_pxDynamicObject->GetVelocities(xLin, xAng);
		}
		else
		{
			xAng = Asura_Maths::ZeroVector3;
		}
	}
	virtual void SetAngVelocity( const Asura_Vector_3& xAngVelocity ) { if (m_pxDynamicObject) { m_pxDynamicObject->SetAngVelocity(xAngVelocity); } }

	// KJFL - Tuesday, November 16, 2004 - not sure what to do about representations of collision meshes yet. PHYSICSTODO
	const Asura_Collision_Object* GetCollisionObject() const { return m_pxDynamicObject ? m_pxDynamicObject->GetCollisionObject() : NULL; }

	const Asura_Bounding_Box* GetBB() const
	{
		const Asura_Collision_Object* pxCollisionObj = GetCollisionObject();
		return pxCollisionObj ? &pxCollisionObj->GetBoundingBox() : NULL;
	}

	bool HasPhysicsObject() const { return (NULL != m_pxDynamicObject); }
	void SetPhysicsObjectIgnore(const bool bSet) { if (m_pxDynamicObject) { m_pxDynamicObject->SetIgnore(bSet); } }
	bool IsPhysicsObjectIgnored() const { return m_pxDynamicObject ? m_pxDynamicObject->IsIgnore() : true; }
	void SetPhysicsObjectHandleToIgnore(const Asura_Handle xHandle) { if (m_pxDynamicObject) { m_pxDynamicObject->SetHandleToIgnore(xHandle); } }
	Asura_Handle GetPhysicsObjectHandle() const { return m_pxDynamicObject ? m_pxDynamicObject->GetHandle() : ASURA_INVALID_HANDLE; }


	void SleepPhysicsObject() { m_pxDynamicObject->Sleep(); }
	
	ASURA_PHYSICS_OBJECT_TYPE GetPhysicsObjectType() const { return m_pxDynamicObject ? m_pxDynamicObject->GetType() : NUM_ASURA_PHYSICS_OBJECT_TYPES; }
	void ChangeType( ASURA_PHYSICS_OBJECT_TYPE eType ) { if (m_pxDynamicObject) { m_pxDynamicObject->ChangeType( eType ); } }

	virtual void SetPosition(const Asura_Vector_3& xPosition) { if (m_pxDynamicObject) { m_pxDynamicObject->SetPosition(xPosition); } }

    // This should be used when initialising position on load, etc.
    void InitialisePosition( const Asura_Vector_3& xInitialPosition );

	virtual void SetOrientation(const Asura_Matrix_3x3& xOrientation) { if (m_pxDynamicObject) { m_pxDynamicObject->SetOrientation(xOrientation); } }

	// Move and reorient the entity.
	virtual void TeleportTo(const Asura_Vector_3& xPosition, const Asura_Matrix_3x3& xOrientation, const bool bInformClients);

	// Functions to get/change BB index (eg if an actor crouches/uncrouches)
	inline int GetBBIndex() const {return m_iBBIndex;}
	
	void SetBBIndex(int iIndex);

	inline float GetAnimTimer() const {return m_fAnimTimer;}
	inline void SetAnimTimer( float fTimer ) { m_fAnimTimer = fTimer; }

	float GetAnimEndTime() const {return m_fAnimEndTime;}

	#ifdef ASURA_USE_AXON
	Axon_Brain* GetBrain() const { return m_pxBrain; }
	virtual void CreateAndInitialiseBrain();
	virtual void ShutdownAndDestroyBrain();
	#endif

	void TakeDamage(float fDamage); // Reduce health if destructible.

	virtual void Update();
	virtual bool HandleMessage(const Asura_Message* pxMessage);

	virtual bool CanBeSavedToChunk() const {return true;}

	virtual	int	 GetChunkBufferSize();
	virtual	void FillInChunkBuffer(char*& pcChunkBuffer);

	virtual	void ReadFromChunkStream(Asura_Chunk_Stream& xStream);
	virtual	void WriteToChunkStream(Asura_Chunk_Stream& xStream) const;

	// MakeDead: Called if health is reduced to zero by TakeDamage,
	// not called if it receives DESTRUCT message or is SetAsDestroyed.
	// NOTE: We can also call this if we want to make the object die immediately.
	// (all overriden versions of this function should set health to zero)
	virtual void MakeDead(); // Reduce health to zero and inform clients.

	// Change shape to use destroyed shape from the fragments.
	// Returns true if this change was done
	bool ChangeToDestroyedShape();

    virtual bool LOSTest( const class Asura_LOS_InputData*, class Asura_LOS_OutputData* ) const;

	#ifdef ASURA_TOOLS
	virtual void ApplyChangesForTemplateInstance(class Tools_EntityTemplateInstance* pxInstance);
	//This must be set back to true in project derived version if this is to be allowed in templates
	virtual bool CanBeIncludedInTemplate() const {return false;}
	//Gets a value based on position/orientation for detecting changes. RAR 11/05/04
	u_int GetPositionAndOrientChecksum();
	// Exclude skybox objects from export
	virtual bool ShouldIncludeInLevelExport() const;
	//For reporting shapes used to tools
	virtual void TraverseUsedShapes(void (*pfnCallback)(Asura_Hash_ID uShapeHash,void* pUserData),void* pUserData) const;
	#endif

	//access to texture animation settings
	unsigned char GetTextureAnimSequence() const {return m_ucTextureAnimationSequence;}
	short GetTextureAnimSpeed_Short() const {return m_sTextureAnimationSpeed;}

	virtual void ForceUpdateMessage() {}

	//Called by cutscene code to hide/unhide the entity
	void HideForCutscene(bool bHide);

	// Parent linkage functions...
	bool LinkToParent(const Asura_Guid uParentGuid, const Asura_Hash_ID uMarkerHash, const bool bWithPhysics = false);
	bool LinkToParent(const Asura_Guid uParentGuid, const Asura_Vector_3& xBoneRelativePos, const Asura_Quat& xBoneRelativeOri, const u_int uBoneID);
	bool LinkToParent(const Asura_Guid uParentGuid, const Asura_Hash_ID uMarkerHash, const u_int uBoneID, const Asura_Vector_3& xPosition);
	bool UnlinkFromParent();

	Asura_Guid	  GetParentGuid() const			{ return m_uParentGuid; }
	Asura_Hash_ID GetParentMarkerHashID() const	{ return m_uParentMarkerHashID; }
	ASURA_PHYSICS_OBJECT_TYPE GetPhysicsTypeBeforeAttach() const { return m_ePhysicsTypeBeforeAttach; }

    bool IsPhysicsObjectIgnoredByDeactivate() const { return m_bPhysicsObjectIgnoredByDeactivate; }
    void SetPhysicsObjectIgnoredByDeactivate( bool bIgnore ) { m_bPhysicsObjectIgnoredByDeactivate = bIgnore; }

	void ApplyLinearImpuseFromMsg( const Asura_Vector_3& xSourcePos, const Asura_Vector_3& xOffsetFromCentreOfMass, ApplyForceMsg_ImpulseData& xImpulseData );

	// Function used to work out how far a point is away from this entity...
	float	CalculateSquaredDistanceTo(const Asura_Vector_3& xPosition) const	{ const Asura_Vector_3 xDistance(GetPosition() - xPosition); return(xDistance.MagnitudeSquared()); }

protected:
	virtual void InitialiseFromChunkBuffer(const char*& pcChunkBuffer);

    void TestForPhysicsObjectBlockedLinks( Asura_Physics_Object* pxPhysicsObject );
	static bool AddWaypointToTest( u_short usWaypointIndex );
	static bool AddLinkToBlock( const u_int uWPID, const u_int uLinkIndex );

    void BlockLinks( const bool bBlock );

    void ResetCollisionObject();

	virtual void SendOnDestructionMessages();
	void SendOnDeathMessages();
	void SendOnHealthPercentMessages( const float fOldHealth, const float fNewHealth );

	virtual void PostLoadInitialise();
	virtual void PreDestructionShutdown();
	virtual void InitialiseFromBlueprint( const Asura_Blueprint& xBlueprint );

	// overrides of OnEntityActivate()/OnEntityDeactivate() - called when active status changes or is initialised. 
	// Derived classes should always call parent versions if they override them. 
	virtual	void OnEntityActivateMessage();
	virtual	void OnEntityDeactivateMessage();

	//Called internally for hiding/unhiding in response to a cutscene request
	virtual void HandleHideForCutscene(bool bHide) {}

#ifdef ASURA_USE_AXON
	virtual Axon_Brain* CreateBrain() { return NULL; }
	virtual void DestroyBrain( Axon_Brain* pxBrain );
	void SetBrainActive( const bool bActive );
#endif

	//Updates state of skin flag according to whether this is a skin or a shape
	void UpdateSkinPhysicalObjectFlag()
	{
		if(m_uSkinID)
		{
			m_uPhysicalObjectFlags |= ASURA_PHYSICALOBJECT_FLAG_ISSKIN;
		}
		else
		{
			m_uPhysicalObjectFlags &= ~ASURA_PHYSICALOBJECT_FLAG_ISSKIN;
		}
	}

#ifdef ASURA_USE_STREAMING
	virtual Asura_Hash_ID CheckForZoneChange();
#endif //#ifdef ASURA_USE_STREAMING

	void ProcessMessage_ApplyLinearImpuse( const Asura_Message* pxMessage );

protected:
	// KJFL - Monday, November 15, 2004 - makes me cringe but I'm going to reuse the data member name 
	// "m_pxDynamicObject". If we match up the methods between Asura_Dynamics/Asura_Physics classes,
	// we don't have to change hideous amounts of code.
	Asura_Physics_Object* m_pxDynamicObject;

	u_int m_uPhysicalObjectFlags;

private:
	Asura_Hash_ID m_uFileID; // Hash value for Shape or Skin filename.
    Asura_Hash_ID m_uSkinID; // Hash value for Skin name (normally filename without path/ext)
    Asura_Hash_ID m_uAnimID; // intial anim ID. If set then m_uFileID is a skin ID
    Asura_Hash_ID m_uAnimFileID;    // stored as well just in case the same anim name is used for different anims, e.g. for different cutscenes
    int m_iAnimFlags;
	float m_fAnimTimer;//Time in seconds since animation started. Used for getting the state correct for load/save
	float m_fAnimEndTime;//Target time for current animation. Only used if AsuraAnimationFlag_ToPosition is set
	float m_fHealth;
	float m_fMaxHealth; // the health the entity was created with
	int m_iBBIndex;

	Asura_Guid		m_uParentGuid;			// The GUID used for the parent entity.
	Asura_Hash_ID	m_uParentMarkerHashID;	// the marker point on the parent we're attached to.
	ASURA_PHYSICS_OBJECT_TYPE m_ePhysicsTypeBeforeAttach;

	short m_sTextureAnimationSpeed;//speed multiplier for texture animation , scaled by 100
	unsigned char m_ucTextureAnimationSequence;//current texture anim sequence

protected:
	// If we are set to block waypoint links these will (once the test has been done) contain the links.
	u_int                         m_uNumLinksToBlock;
	Asura_AI_NavConnection_Index* m_pxLinksToBlock;

private:
    union
    {
    	unsigned int m_uFlags;
    	struct 
    	{
    		// NOTE: These bits are written out, adding any new bits means
    		// ~~~~~ that you will need to add those bits to the bitfield
    		//       preparation code in "WriteToChunkStream".
    		unsigned int m_bIsDestructible 						:  1, // Destructibility flag
                         m_bBlockedLinks   					 	:  1, // Whether we have set any links that we collide with as blocked.
						 m_bPhysicsObjectIgnoredByDeactivate	:  1, // should we stop ignoring on activation?
					     m_bHasBrain							:  1, // Whether we have a brain created or not.
    					 A_SE_PO_Unused							: 28;
    	};
    };

	#ifdef ASURA_USE_AXON
	Axon_Brain* m_pxBrain;
	#endif

#ifdef ASURA_TOOLS
	//Store of quaternion and position that was last saved , used to stop gradual errors causes
	//by conversion between matrices and quats on each load/save.
	//Also with physics system the values returned by the Get() functions can be slightly
	//different from the values Set(). RAR 23/01/2006
	Asura_Quat m_xSavedQuat;
	Asura_Vector_3 m_xSavedPosition;

	// remember if the BlockLinks data need to be discarded.
	bool m_bDiscardWaypointInfo;
#endif

    // The static storage used when calculating each object's links to block.
    static u_short*                      s_pusWaypoints;
	static u_int                         s_uWaypointArrayCapacity;
	static u_int                         s_uNumWaypoints;
	static Asura_AI_NavConnection_Index* s_pxLinksToBlock;
	static u_int                         s_uLinkArrayCapacity;
    static u_int                         s_uNumLinksToBlock;

public:
	static Asura_ServerEntity_PhysicalObject* FindEntity(Asura_Guid uGuid)
	{
		return s_xList.FindEntity(uGuid);
	}
	static const Asura_Hashed_List<Asura_ServerEntity_PhysicalObject>* GetList()
	{
		return &s_xList;
	}

	// Loop over all the physical objects resetting their collision objects.
	static void ResetAllCollisionObjects();

private:
	// List of all asura server physical objects
	static Asura_Hashed_List<Asura_ServerEntity_PhysicalObject> s_xList;

	static const u_int uCURRENT_CHUNK_VERSION = 20;
};

//////////////
// MESSAGES //
//////////////

// NOTE: This isn't actually sent as a message, but is a base class
// for other messages to inherit from.
class Asura_Message_PhysicalObject_ClientUpdate
{
public:
	Asura_Quat     m_xOrientation;
	Asura_Vector_3 m_xPosition;
	float          m_fHealth;
	Asura_Hash_ID  m_uShapeFileID;
    Asura_Hash_ID  m_uAnimID;
    int            m_iAnimFlags;
	float          m_fAnimTimer;
	float          m_fAnimEndTime;
	u_int          m_uPhysicalObjectFlags;
	Asura_Guid     m_uParentGuid;
	Asura_Hash_ID  m_uParentMarkerHashID;
	short m_sTextureAnimSpeed;
	unsigned char m_ucTextureAnimSequence;

	void FillPhysical(const Asura_ServerEntity_PhysicalObject* pxObject)
	{
		m_xOrientation.FromMatrix(pxObject->GetOrientation());
		m_xPosition = pxObject->GetPosition();
		m_fHealth   = pxObject->GetHealth();
		m_uPhysicalObjectFlags = pxObject->GetPhysicalObjectFlags();
		if (pxObject->GetSkinID() == ASURA_HASH_ID_UNSET)
        {
            m_uShapeFileID = pxObject->GetShapeFileID();
        }
        else
        {
            m_uShapeFileID = pxObject->GetSkinID();
        }
        m_uAnimID = pxObject->GetAnimID();
        m_iAnimFlags = pxObject->GetAnimFlags();
		m_fAnimTimer = pxObject->GetAnimTimer();
		m_fAnimEndTime = pxObject->GetAnimEndTime();
		m_uParentGuid = pxObject->GetParentGuid();
		m_uParentMarkerHashID = pxObject->GetParentMarkerHashID();
		m_sTextureAnimSpeed = pxObject->GetTextureAnimSpeed_Short();
		m_ucTextureAnimSequence = pxObject->GetTextureAnimSequence();
	}

#ifdef ASURA_SUPPORT_NETMSG_SYSTEM

	static void RegisterFields(u_short usMsgID, u_short usEntityClassification);
	static void RegisterFields(class Asura_NetMsg* pxNetMsg);
	static u_char GetNumFields() { return 13; }

	static void SetHealthFieldAccuracy(u_int uBits, float fMin, float fMax, float fChangeThreshold );
	static u_int s_uHealthBits;
	static float s_fHealthMin;
	static float s_fHealthMax;
	static float s_fHealthChangeThreshold;

#endif//#ifdef ASURA_SUPPORT_NETMSG_SYSTEM
};


// (MH - 17.10.2002) warning: this message is saved out in tools message blocks, so
// you might get problems if you go changing this class. It might be necessary to use
// a new message ID if you need to do that, then the old messages could be converted.
// I am asserting that the message data size hasn't changed so you should find out.
class Asura_Message_PhysicalObject_ChangeAnimation
{
public:
    
    void Initialise()
    {
        m_uAnimID = ASURA_HASH_ID_UNSET;
        m_uAnimFileID = ASURA_HASH_ID_UNSET;
        m_iFlags = AsuraAnimationFlag_Tween;
        m_fTweenDuration = 0.2f;
		m_fStartTime = 0.0f;
		m_fEndTime = 1.0f;
    }

    Asura_Hash_ID m_uAnimID;
    Asura_Hash_ID m_uAnimFileID;
    int m_iFlags;
    float m_fTweenDuration;
	float m_fStartTime;
	float m_fEndTime;
};



////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Message_PhysicalObject_LinkToParent
// Author       : Andy Tate
// Date         : 1-Nov-2006
//
// Description  : Class to enable a physical object to be hooked to its parent.
////////////////////////////////////////////////////////////////////////////////

class Asura_Message_PhysicalObject_LinkToParent
{
public:
	// Public functions...
	void			SetParentGuid	(const Asura_Guid uGuid)	{ m_uParentGuid = uGuid; }
	Asura_Guid		GetParentGuid	(void) const				{ return (m_uParentGuid); }

	void			SetMarkerHash	(const Asura_Hash_ID uHash)	{ m_uMarkerHash = uHash; }
	Asura_Hash_ID	GetMarkerHash	(void) const				{ return (m_uMarkerHash); }

#ifdef ASURA_NETMSG_PACK_ALL_DATA
	void RegisterFields(Asura_NetMsg* pxNetMsg) const;
	static u_char GetNumFields() { return 2; }
#endif

private:
	// Private variables...
	Asura_Guid		m_uParentGuid;		// The GUID for the parent to link to.
	Asura_Hash_ID	m_uMarkerHash;		// The hash-ID of the marker-point to link to on this parent.

	Asura_Message_PhysicalObject_LinkToParent&	operator=	(const Asura_Message_PhysicalObject_LinkToParent& xOther);

};   // End of class 'Asura_Message_PhysicalObject_LinkToParent'.



////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Message_PhysicalObject_LinkToParentBoneRelative
// Author       : Andy Tate
// Date         : 6-Nov-2006
//
// Description  : Class to enable a physical object to be hooked to its parent.
////////////////////////////////////////////////////////////////////////////////

class Asura_Message_PhysicalObject_LinkToParentBoneRelative
{
public:
	// Public functions...
	void					SetParentGuid	(const Asura_Guid uGuid)	{ m_uParentGuid = uGuid; }
	Asura_Guid				GetParentGuid	(void) const				{ return (m_uParentGuid); }

	void					SetBoneID		(const u_int uBoneID)	{ m_uBoneID = uBoneID; }
	u_int					GetBoneID		(void) const			{ return(m_uBoneID); }

	void					SetPosition		(const Asura_Vector_3& xPostion)	{ m_xPosition = xPostion; }
	const Asura_Vector_3&	GetPosition		(void) const						{ return(m_xPosition); }

	void					SetOrientation	(const Asura_Quat& xOrientation)	{ m_xOrientation = xOrientation; }
	const Asura_Quat&		GetOrientation	(void) const						{ return(m_xOrientation); }


protected:
	// Protected variables...

	// Protected functions...


private:
	// Private variables...
	Asura_Guid		m_uParentGuid;		// The GUID for the parent to link to.
	u_int			m_uBoneID;			// The ID of the bone to attach to.
	Asura_Vector_3	m_xPosition;		// The bone-relative position to attach to.
	Asura_Quat		m_xOrientation;		// The bone-relative position to attach to.

	// Private functions...
	Asura_Message_PhysicalObject_LinkToParentBoneRelative&	operator=	(const Asura_Message_PhysicalObject_LinkToParentBoneRelative& xOther);

};   // End of class 'Asura_Message_PhysicalObject_LinkToParentBoneRelative'.



////////////////////////////////////////////////////////////////////////////////
// Class        : Asura_Message_PhysicalObject_LinkToParentSticky
// Author       : Andy Tate
// Date         : 6-Nov-2006
//
// Description  : Class to enable a physical object to be hooked to its parent.
////////////////////////////////////////////////////////////////////////////////

class Asura_Message_PhysicalObject_LinkToParentSticky
{
public:
	// Public functions...
	void		SetParentGuid	(const Asura_Guid uGuid)	{ m_uParentGuid = uGuid; }
	Asura_Guid	GetParentGuid	(void) const				{ return (m_uParentGuid); }

	void			SetMarkerHash	(const Asura_Hash_ID uHash)	{ m_uMarkerHash = uHash; }
	Asura_Hash_ID	GetMarkerHash	(void) const				{ return (m_uMarkerHash); }

	void	SetBoneID	(const u_int uBoneID)	{ m_uBoneID = uBoneID; }
	u_int	GetBoneID	(void) const			{ return(m_uBoneID); }

	void					SetPosition	(const Asura_Vector_3& xPositiion)	{ m_xPosition = xPositiion; }
	const Asura_Vector_3&	GetPosition	(void) const						{ return(m_xPosition); }


protected:
	// Protected variables...

	// Protected functions...


private:
	// Private variables...
	Asura_Guid		m_uParentGuid;		// The GUID for the parent to link to.
	Asura_Hash_ID	m_uMarkerHash;		// The hash-ID of the marker-point to link to on this parent.
	u_int			m_uBoneID;			// The ID of the bone to stick to.
	Asura_Vector_3	m_xPosition;		// The world-space position to stick to.

	// Private functions...
	Asura_Message_PhysicalObject_LinkToParentSticky&	operator=	(const Asura_Message_PhysicalObject_LinkToParentSticky& xOther);

};   // End of class 'Asura_Message_PhysicalObject_LinkToParentSticky'.


//Special animation flags that get shoved in the change animation messages. RAR 25/08/2006
#define Asura_PhysicalObject_AnimationFlag_UseStartTime	0x40000000
#define Asura_PhysicalObject_AnimationFlag_UseEndTime	0x80000000


///////////////////////////////
// Asura_Msg_PlayPFXOnEntity //
///////////////////////////////
// MGH 10/12/2007: Static message for ASURA_MSG_PLAY_PFX_ON_ENTITY.
// Don't change the data in this message as it is saved out in static message blocks.

// Note: m_uDummy is currently unused. I've added it for future expansion, as it is such
// a pain to change the size of static messages later. If an NPC has two guns attached,
// each with a "muzzle" marker then there is currently no way of specifying which one
// to play the PFX on; this variable could be used for disambiguation purposes.

const u_int uASURA_PLAYPFXONENTITY_FLAG_ATTACH = 0x00000001; // Move effect with the marker.

class Asura_Msg_PlayPFXOnEntity
{
public:
	void Reset()
	{
		m_uPFXEffectHash	= ASURA_HASH_ID_UNSET;
		m_uMarkerHash		= ASURA_HASH_ID_UNSET;
		m_uPlayPFXFlags		= uASURA_PLAYPFXONENTITY_FLAG_ATTACH;
		m_uDummy			= 0;

		m_xMarkerString[0]	= 0;
	}
	
	Asura_Hash_ID m_uPFXEffectHash;	// Hash of PFX effect to play.
	Asura_Hash_ID m_uMarkerHash;	// Hash of marker at which PFX is played.
	u_int m_uPlayPFXFlags;			// Flags
	u_int m_uDummy;					// Currently unused

	Asura_Char m_xMarkerString[ASURA_MSG_PLAY_PFX_MAX_CHARS];
};

#endif //__ASURA_SERVER_ENTITY_PHYSICAL_OBJECT_H__
