#ifndef C_BASEANIMATING_H
#define C_BASEANIMATING_H

#ifdef _WIN32
#pragma once
#endif

#include "c_baseentity.h"
#include "studio.h"
#include "utlvector.h"
#include "ragdoll.h"
#include "mouthinfo.h"
#include "ai_activity.h"
#include "animationlayer.h"
#include "sequence_Transitioner.h"
#include "bone_accessor.h"
#include "bone_merge_cache.h"
#include "ragdoll_shared.h"
#include "threadtools.h"
#include "idatacache.h"

#include "baseentity_shared.h" 

#define LIPSYNC_POSEPARAM_NAME "mouth"
#define NUM_HITBOX_FIRES	10

class IRagdoll;
class CIKContext;
class CIKState;
class ConVar;
class C_RopeKeyframe;
class CBoneBitList;
class CBoneList;
class KeyValues;
class CJiggleBones;
class IBoneSetup;
FORWARD_DECLARE_HANDLE(memhandle_t);
typedef unsigned short MDLHandle_t;

extern ConVar vcollide_wireframe;


struct ClientModelRenderInfo_t : public ModelRenderInfo_t
{
	matrix3x4_t lightingOffset;

	matrix3x4_t modelToWorld;
};

struct RagdollInfo_t
{
	bool		m_bActive;
	float		m_flSaveTime;
	int			m_nNumBones;
	Vector		m_rgBonePos[MAXSTUDIOBONES];
	Quaternion	m_rgBoneQuaternion[MAXSTUDIOBONES];
};


class CAttachmentData
{
public:
	matrix3x4_t	m_AttachmentToWorld;
	QAngle	m_angRotation;
	Vector	m_vOriginVelocity;
	int		m_nLastFramecount : 31;
	int		m_bAnglesComputed : 1;
};


typedef unsigned int			ClientSideAnimationListHandle_t;

#define		INVALID_CLIENTSIDEANIMATION_LIST_HANDLE	(ClientSideAnimationListHandle_t)~0


class C_BaseAnimating : public C_BaseEntity, private IModelLoadCallback
{
public:
	DECLARE_CLASS(C_BaseAnimating, C_BaseEntity);
	DECLARE_CLIENTCLASS();
	DECLARE_PREDICTABLE();
	DECLARE_INTERPOLATION();

	enum
	{
		NUM_POSEPAREMETERS = 24,
		NUM_BONECTRLS = 4
	};

	C_BaseAnimating();
	~C_BaseAnimating();

	virtual C_BaseAnimating* GetBaseAnimating() { return this; }

	bool UsesPowerOfTwoFrameBufferTexture(void);

	virtual bool	Interpolate(float currentTime);
	virtual void	Simulate();
	virtual void	Release();

	float	GetAnimTimeInterval(void) const;

	virtual unsigned char	GetClientSideFade(void);

	virtual void	GetBoneControllers(float controllers[MAXSTUDIOBONECTRLS]);
	virtual float	SetBoneController(int iController, float flValue);

	LocalFlexController_t GetNumFlexControllers(void);
	const char* GetFlexDescFacs(int iFlexDesc);
	const char* GetFlexControllerName(LocalFlexController_t iFlexController);
	const char* GetFlexControllerType(LocalFlexController_t iFlexController);

	virtual void	GetAimEntOrigin(IClientEntity* pAttachedTo, Vector* pAbsOrigin, QAngle* pAbsAngles);

	bool ComputeHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs);
	bool ComputeEntitySpaceHitboxSurroundingBox(Vector* pVecWorldMins, Vector* pVecWorldMaxs);

	bool HitboxToWorldTransforms(matrix3x4_t* pHitboxToWorld[MAXSTUDIOBONES]);

	float		  ClampCycle(float cycle, bool isLooping);
	virtual void GetPoseParameters(CStudioHdr* pStudioHdr, float poseParameter[MAXSTUDIOPOSEPARAM]);
	virtual void BuildTransformations(CStudioHdr* pStudioHdr, Vector* pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList& boneComputed);
	virtual void ApplyBoneMatrixTransform(matrix3x4_t& transform);
	virtual int	VPhysicsGetObjectList(IPhysicsObject** pList, int listMax);

	virtual bool SetupBones(matrix3x4_t* pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime);
	virtual void UpdateIKLocks(float currentTime);
	virtual void CalculateIKLocks(float currentTime);
	virtual bool ShouldDraw();
	virtual int DrawModel(int flags);
	virtual int	InternalDrawModel(int flags);
	virtual bool OnInternalDrawModel(ClientModelRenderInfo_t* pInfo);
	virtual bool OnPostInternalDrawModel(ClientModelRenderInfo_t* pInfo);
	void		DoInternalDrawModel(ClientModelRenderInfo_t* pInfo, DrawModelState_t* pState, matrix3x4_t* pBoneToWorldArray = NULL);

	virtual CMouthInfo* GetMouth();
	virtual void	ControlMouth(CStudioHdr* pStudioHdr);

	virtual void DoAnimationEvents(CStudioHdr* pStudio);
	virtual void FireEvent(const Vector& origin, const QAngle& angles, int event, const char* options);
	virtual void FireObsoleteEvent(const Vector& origin, const QAngle& angles, int event, const char* options);
	virtual const char* ModifyEventParticles(const char* token) { return token; }

	virtual bool DispatchMuzzleEffect(const char* options, bool isFirstPerson);

	virtual void ValidateModelIndex(void);
	virtual CStudioHdr* OnNewModel(void);
	CStudioHdr* GetModelPtr() const;
	void InvalidateMdlCache();

	virtual void SetPredictable(bool state);
	void UseClientSideAnimation();

	virtual	void StandardBlendingRules(CStudioHdr* pStudioHdr, Vector pos[], Quaternion q[], float currentTime, int boneMask);
	void UnragdollBlend(CStudioHdr* hdr, Vector pos[], Quaternion q[], float currentTime);

	void MaintainSequenceTransitions(IBoneSetup& boneSetup, float flCycle, Vector pos[], Quaternion q[]);
	virtual void AccumulateLayers(IBoneSetup& boneSetup, Vector pos[], Quaternion q[], float currentTime);

	virtual void ChildLayerBlend(Vector pos[], Quaternion q[], float currentTime, int boneMask);

	int		LookupAttachment(const char* pAttachmentName);
	int		LookupRandomAttachment(const char* pAttachmentNameSubstring);

	int		LookupPoseParameter(CStudioHdr* pStudioHdr, const char* szName);
	inline int LookupPoseParameter(const char* szName) { return LookupPoseParameter(GetModelPtr(), szName); }

	float	SetPoseParameter(CStudioHdr* pStudioHdr, const char* szName, float flValue);
	inline float SetPoseParameter(const char* szName, float flValue) { return SetPoseParameter(GetModelPtr(), szName, flValue); }
	float	SetPoseParameter(CStudioHdr* pStudioHdr, int iParameter, float flValue);
	inline float SetPoseParameter(int iParameter, float flValue) { return SetPoseParameter(GetModelPtr(), iParameter, flValue); }

	float	GetPoseParameter(int iPoseParameter);

	bool	GetPoseParameterRange(int iPoseParameter, float& minValue, float& maxValue);

	int		LookupBone(const char* szName);
	void	GetBonePosition(int iBone, Vector& origin, QAngle& angles);
	void	GetBoneTransform(int iBone, matrix3x4_t& pBoneToWorld);

	int		GetHitboxBone(int hitboxIndex);

	virtual void		AttachEntityToBone(C_BaseAnimating* attachTarget, int boneIndexAttached = -1, Vector bonePosition = Vector(0, 0, 0), QAngle boneAngles = QAngle(0, 0, 0));
	void				AddBoneAttachment(C_BaseAnimating* newBoneAttachment);
	void				RemoveBoneAttachment(C_BaseAnimating* boneAttachment);
	void				RemoveBoneAttachments();
	void				DestroyBoneAttachments();
	void				MoveBoneAttachments(C_BaseAnimating* attachTarget);
	int					GetNumBoneAttachments();
	C_BaseAnimating* GetBoneAttachment(int i);
	virtual void		NotifyBoneAttached(C_BaseAnimating* attachTarget);
	virtual void		UpdateBoneAttachments(void);

	virtual void					PreDataUpdate(DataUpdateType_t updateType);
	virtual void					PostDataUpdate(DataUpdateType_t updateType);
	virtual int						RestoreData(const char* context, int slot, int type);

	virtual void					NotifyShouldTransmit(ShouldTransmitState_t state);
	virtual void					OnPreDataChanged(DataUpdateType_t updateType);
	virtual void					OnDataChanged(DataUpdateType_t updateType);
	virtual void					AddEntity(void);

	void							ForceClientSideAnimationOn();

	void							AddToClientSideAnimationList();
	void							RemoveFromClientSideAnimationList();

	virtual bool					IsSelfAnimating();
	virtual void					ResetLatched();

	virtual void					GetRenderBounds(Vector& theMins, Vector& theMaxs);
	virtual const Vector& GetRenderOrigin(void);
	virtual const QAngle& GetRenderAngles(void);

	virtual bool					GetSoundSpatialization(SpatializationInfo_t& info);

	bool							GetAttachment(const char* szName, Vector& absOrigin);
	bool							GetAttachment(const char* szName, Vector& absOrigin, QAngle& absAngles);

	virtual bool					GetAttachment(int number, Vector& origin);
	virtual bool					GetAttachment(int number, Vector& origin, QAngle& angles);
	virtual bool					GetAttachment(int number, matrix3x4_t& matrix);
	virtual bool					GetAttachmentVelocity(int number, Vector& originVel, Quaternion& angleVel);

	bool							GetAttachmentLocal(int iAttachment, matrix3x4_t& attachmentToLocal);
	bool							GetAttachmentLocal(int iAttachment, Vector& origin, QAngle& angles);
	bool                            GetAttachmentLocal(int iAttachment, Vector& origin);

	bool							GetRootBone(matrix3x4_t& rootBone);

	virtual ShadowType_t			ShadowCastType();

	virtual CollideType_t			GetCollideType(void);

	virtual bool					TestCollision(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr);
	virtual bool					TestHitboxes(const Ray_t& ray, unsigned int fContentsMask, trace_t& tr);

	bool							IsRagdoll() const;
	bool							IsAboutToRagdoll() const;
	virtual C_BaseAnimating* BecomeRagdollOnClient();
	C_BaseAnimating* CreateRagdollCopy();
	bool							InitAsClientRagdoll(const matrix3x4_t* pDeltaBones0, const matrix3x4_t* pDeltaBones1, const matrix3x4_t* pCurrentBonePosition, float boneDt, bool bFixedConstraints = false);
	void							IgniteRagdoll(C_BaseAnimating* pSource);
	void							TransferDissolveFrom(C_BaseAnimating* pSource);
	virtual void					SaveRagdollInfo(int numbones, const matrix3x4_t& cameraTransform, CBoneAccessor& pBoneToWorld);
	virtual bool					RetrieveRagdollInfo(Vector* pos, Quaternion* q);
	virtual void					Clear(void);
	void							ClearRagdoll();
	void							CreateUnragdollInfo(C_BaseAnimating* pRagdoll);
	void							ForceSetupBonesAtTime(matrix3x4_t* pBonesOut, float flTime);
	virtual void					GetRagdollInitBoneArrays(matrix3x4_t* pDeltaBones0, matrix3x4_t* pDeltaBones1, matrix3x4_t* pCurrentBones, float boneDt);

	virtual int GetBody() { return m_nBody; }
	virtual int GetSkin() { return m_nSkin; }

	bool IsOnFire() { return ((GetFlags() & FL_ONFIRE) != 0); }

	inline float					GetPlaybackRate();
	inline void						SetPlaybackRate(float rate);

	void							SetModelScale(float scale, float change_duration = 0.0f);
	float							GetModelScale() const { return m_flModelScale; }
	inline bool						IsModelScaleFractional() const;                      
	inline bool						IsModelScaled() const;
	void							UpdateModelScale(void);
	virtual	void					RefreshCollisionBounds(void);

	int								GetSequence();
	virtual void					SetSequence(int nSequence);
	inline void						ResetSequence(int nSequence);
	float							GetSequenceGroundSpeed(CStudioHdr* pStudioHdr, int iSequence);
	inline float					GetSequenceGroundSpeed(int iSequence) { return GetSequenceGroundSpeed(GetModelPtr(), iSequence); }
	bool							IsSequenceLooping(CStudioHdr* pStudioHdr, int iSequence);
	inline bool						IsSequenceLooping(int iSequence) { return IsSequenceLooping(GetModelPtr(), iSequence); }
	float							GetSequenceMoveDist(CStudioHdr* pStudioHdr, int iSequence);
	void							GetSequenceLinearMotion(int iSequence, Vector* pVec);
	void							GetBlendedLinearVelocity(Vector* pVec);
	int								LookupSequence(const char* label);
	int								LookupActivity(const char* label);
	char const* GetSequenceName(int iSequence);
	char const* GetSequenceActivityName(int iSequence);
	Activity						GetSequenceActivity(int iSequence);
	KeyValues* GetSequenceKeyValues(int iSequence);
	virtual void					StudioFrameAdvance();          

	virtual float					FrameAdvance(float flInterval = 0.0f);
	virtual float					GetSequenceCycleRate(CStudioHdr* pStudioHdr, int iSequence);
	virtual void					UpdateClientSideAnimation();
	void							ClientSideAnimationChanged();
	virtual unsigned int			ComputeClientSideAnimationFlags();

	virtual void ResetClientsideFrame(void) { SetCycle(0); }

	void SetCycle(float flCycle);
	float GetCycle() const;

	void SetBodygroup(int iGroup, int iValue);
	int GetBodygroup(int iGroup);

	const char* GetBodygroupName(int iGroup);
	int FindBodygroupByName(const char* name);
	int GetBodygroupCount(int iGroup);
	int GetNumBodyGroups(void);

	class CBoneCache* GetBoneCache(CStudioHdr* pStudioHdr);
	void							SetHitboxSet(int setnum);
	void							SetHitboxSetByName(const char* setname);
	int								GetHitboxSet(void);
	char const* GetHitboxSetName(void);
	int								GetHitboxSetCount(void);
	void							DrawClientHitboxes(float duration = 0.0f, bool monocolor = false);

	C_BaseAnimating* FindFollowedEntity();

	virtual bool					IsActivityFinished(void) { return m_bSequenceFinished; }
	inline bool						IsSequenceFinished(void);
	inline bool						SequenceLoops(void) { return m_bSequenceLoops; }

	virtual void					UncorrectViewModelAttachment(Vector& vOrigin) {}

	void							InvalidateBoneCache();
	bool							IsBoneCacheValid() const;	            
	void							GetCachedBoneMatrix(int boneIndex, matrix3x4_t& out);

	const matrix3x4_t& GetBone(int iBone) const;
	matrix3x4_t& GetBoneForWrite(int iBone);

	struct AutoAllowBoneAccess
	{
		AutoAllowBoneAccess(bool bAllowForNormalModels, bool bAllowForViewModels);
		~AutoAllowBoneAccess(void);
	};
	static void						PushAllowBoneAccess(bool bAllowForNormalModels, bool bAllowForViewModels, char const* tagPush);
	static void						PopBoneAccess(char const* tagPop);
	static void						ThreadedBoneSetup();
	static void						InitBoneSetupThreadPool();
	static void						ShutdownBoneSetupThreadPool();

	static void						InvalidateBoneCaches();

	virtual void					VPhysicsUpdate(IPhysicsObject* pPhysics);

	void DisableMuzzleFlash();		             
	virtual void DoMuzzleFlash();	            
	bool ShouldMuzzleFlash() const;	      

	virtual void ProcessMuzzleFlashEvent();

	static void UpdateClientSideAnimations();

	void InitModelEffects(void);

	virtual void SetServerIntendedCycle(float intended) { (void)intended; }
	virtual float GetServerIntendedCycle(void) { return -1.0f; }

	int								SelectWeightedSequence(int activity);
	void							ResetSequenceInfo(void);
	float							SequenceDuration(void);
	float							SequenceDuration(CStudioHdr* pStudioHdr, int iSequence);
	inline float					SequenceDuration(int iSequence) { return SequenceDuration(GetModelPtr(), iSequence); }
	int								FindTransitionSequence(int iCurrentSequence, int iGoalSequence, int* piDir);

	void							RagdollMoved(void);

	virtual void					GetToolRecordingState(KeyValues* msg);
	virtual void					CleanupToolRecordingState(KeyValues* msg);

	void							SetReceivedSequence(void);
	virtual bool					ShouldResetSequenceOnNewModel(void);

	virtual bool					IsViewModel() const;

protected:
	virtual void					FormatViewModelAttachment(int nAttachment, matrix3x4_t& attachmentToWorld) {}

	bool							IsBoneAccessAllowed() const;
	CMouthInfo& MouthInfo();

	virtual bool					IsMenuModel() const;

	virtual int						GetStudioBody(void) { return m_nBody; }

	virtual bool					CalcAttachments();

private:
	virtual float					LastBoneChangedTime() { return FLT_MAX; }

	CBoneList* RecordBones(CStudioHdr* hdr, matrix3x4_t* pBoneState);

	bool							PutAttachment(int number, const matrix3x4_t& attachmentToWorld);
	void							TermRopes();

	void							DelayedInitModelEffects(void);

	void							UpdateRelevantInterpolatedVars();
	void							AddBaseAnimatingInterpolatedVars();
	void							RemoveBaseAnimatingInterpolatedVars();

public:
	CRagdoll* m_pRagdoll;

	int								m_nSkin;

	int								m_nBody;

	int								m_nHitboxSet;

	CSequenceTransitioner			m_SequenceTransitioner;

protected:
	CIKContext* m_pIk;

	int								m_iEyeAttachment;

	float							m_flPlaybackRate;

	bool							m_bStoreRagdollInfo;
	RagdollInfo_t* m_pRagdollInfo;
	Vector							m_vecForce;
	int								m_nForceBone;

	unsigned long					m_iMostRecentModelBoneCounter;
	unsigned long					m_iMostRecentBoneSetupRequest;
	int								m_iPrevBoneMask;
	int								m_iAccumulatedBoneMask;

	CBoneAccessor					m_BoneAccessor;
	CThreadFastMutex				m_BoneSetupLock;

	ClientSideAnimationListHandle_t	m_ClientSideAnimationListHandle;

	bool							m_bClientSideFrameReset;

	CUtlVector<CHandle<C_BaseAnimating> > m_BoneAttachments;
	int								m_boneIndexAttached;
	Vector							m_bonePosition;
	QAngle							m_boneAngles;
	CHandle<C_BaseAnimating>		m_pAttachedTo;

protected:

	float							m_fadeMinDist;
	float							m_fadeMaxDist;
	float							m_flFadeScale;

private:

	float							m_flGroundSpeed;	       
	float							m_flLastEventCheck;	        
	bool							m_bSequenceFinished;         
	bool							m_bSequenceLoops;	     

	CMouthInfo						m_mouth;

	CNetworkVar(float, m_flModelScale);

	float							m_flPoseParameter[MAXSTUDIOPOSEPARAM];
	CInterpolatedVarArray< float, MAXSTUDIOPOSEPARAM >		m_iv_flPoseParameter;
	float							m_flOldPoseParameters[MAXSTUDIOPOSEPARAM];

	int								m_nPrevSequence;
	int								m_nRestoreSequence;

	CUtlLinkedList<C_RopeKeyframe*, unsigned short> m_Ropes;

	float							m_flPrevEventCycle;
	int								m_nEventSequence;

	float							m_flEncodedController[MAXSTUDIOBONECTRLS];
	CInterpolatedVarArray< float, MAXSTUDIOBONECTRLS >		m_iv_flEncodedController;
	float							m_flOldEncodedController[MAXSTUDIOBONECTRLS];

	bool							m_bClientSideAnimation;
	bool							m_bLastClientSideFrameReset;

	int								m_nNewSequenceParity;
	int								m_nResetEventsParity;

	int								m_nPrevNewSequenceParity;
	int								m_nPrevResetEventsParity;

	bool							m_builtRagdoll;
	Vector							m_vecPreRagdollMins;
	Vector							m_vecPreRagdollMaxs;

	int								m_nSequence;
	bool							m_bReceivedSequence;

protected:
	float							m_flCycle;
	CInterpolatedVar< float >		m_iv_flCycle;
	float							m_flOldCycle;
	bool							m_bNoModelParticles;

private:
	float							m_flOldModelScale;
	int								m_nOldSequence;
	CBoneMergeCache* m_pBoneMergeCache;	          
	CUtlVector< matrix3x4_t >		m_CachedBoneData;       
	memhandle_t						m_hitboxBoneCacheHandle;
	float							m_flLastBoneSetupTime;
	CJiggleBones* m_pJiggleBones;

	CUtlVector<CAttachmentData>		m_Attachments;

	void							SetupBones_AttachmentHelper(CStudioHdr* pStudioHdr);

	EHANDLE							m_hLightingOrigin;
	EHANDLE							m_hLightingOriginRelative;

	CNetworkVar(unsigned char, m_nMuzzleFlashParity);
	unsigned char m_nOldMuzzleFlashParity;

	bool							m_bInitModelEffects;

	bool							m_bDynamicModelAllowed;
	bool							m_bDynamicModelPending;
	bool							m_bResetSequenceInfoOnLoad;
	CRefCountedModelIndex			m_AutoRefModelIndex;
public:
	void							EnableDynamicModels() { m_bDynamicModelAllowed = true; }
	bool							IsDynamicModelLoading() const { return m_bDynamicModelPending; }
private:
	virtual void					OnModelLoadComplete(const model_t* pModel);

private:
	void							LockStudioHdr();
	void							UnlockStudioHdr();
	mutable CStudioHdr* m_pStudioHdr;
	mutable MDLHandle_t				m_hStudioHdr;
	CThreadFastMutex				m_StudioHdrInitLock;
};

enum
{
	RAGDOLL_FRICTION_OFF = -2,
	RAGDOLL_FRICTION_NONE,
	RAGDOLL_FRICTION_IN,
	RAGDOLL_FRICTION_HOLD,
	RAGDOLL_FRICTION_OUT,
};

class C_ClientRagdoll : public C_BaseAnimating, public IPVSNotify
{

public:
	C_ClientRagdoll(bool bRestoring = true);
	DECLARE_CLASS(C_ClientRagdoll, C_BaseAnimating);
	DECLARE_DATADESC();

	virtual void OnPVSStatusChanged(bool bInPVS);

	virtual void Release(void);
	virtual void SetupWeights(const matrix3x4_t* pBoneToWorld, int nFlexWeightCount, float* pFlexWeights, float* pFlexDelayedWeights);
	virtual void ImpactTrace(trace_t* pTrace, int iDamageType, const char* pCustomImpactName);
	void ClientThink(void);
	void ReleaseRagdoll(void) { m_bReleaseRagdoll = true; }
	bool ShouldSavePhysics(void) { return true; }
	virtual void	OnSave();
	virtual void	OnRestore();
	virtual int ObjectCaps(void) { return BaseClass::ObjectCaps() | FCAP_SAVE_NON_NETWORKABLE; }
	virtual IPVSNotify* GetPVSNotifyInterface() { return this; }

	void	HandleAnimatedFriction(void);
	virtual void SUB_Remove(void);

	void	FadeOut(void);
	virtual float LastBoneChangedTime();

	bool m_bFadeOut;
	bool m_bImportant;
	float m_flEffectTime;

private:
	int m_iCurrentFriction;
	int m_iMinFriction;
	int m_iMaxFriction;
	float m_flFrictionModTime;
	float m_flFrictionTime;

	int  m_iFrictionAnimState;
	bool m_bReleaseRagdoll;

	bool m_bFadingOut;

	float m_flScaleEnd[NUM_HITBOX_FIRES];
	float m_flScaleTimeStart[NUM_HITBOX_FIRES];
	float m_flScaleTimeEnd[NUM_HITBOX_FIRES];
};

inline void C_BaseAnimating::ResetSequence(int nSequence)
{
	SetSequence(nSequence);
	ResetSequenceInfo();
}

inline float C_BaseAnimating::GetPlaybackRate()
{
	return m_flPlaybackRate;
}

inline void C_BaseAnimating::SetPlaybackRate(float rate)
{
	m_flPlaybackRate = rate;
}

inline const matrix3x4_t& C_BaseAnimating::GetBone(int iBone) const
{
	return m_BoneAccessor.GetBone(iBone);
}

inline matrix3x4_t& C_BaseAnimating::GetBoneForWrite(int iBone)
{
	return m_BoneAccessor.GetBoneForWrite(iBone);
}


inline bool C_BaseAnimating::ShouldMuzzleFlash() const
{
	return m_nOldMuzzleFlashParity != m_nMuzzleFlashParity;
}

inline float C_BaseAnimating::GetCycle() const
{
	return m_flCycle;
}

inline CStudioHdr* C_BaseAnimating::GetModelPtr() const
{
	if (IsDynamicModelLoading())
		return NULL;

#ifdef _DEBUG
#endif
	if (!m_pStudioHdr)
	{
		const_cast<C_BaseAnimating*>(this)->LockStudioHdr();
	}
	Assert(m_pStudioHdr ? m_pStudioHdr->GetRenderHdr() == mdlcache->GetStudioHdr(m_hStudioHdr) : m_hStudioHdr == MDLHANDLE_INVALID);
	return m_pStudioHdr;
}


inline void C_BaseAnimating::InvalidateMdlCache()
{
	if (m_pStudioHdr)
	{
		UnlockStudioHdr();
		delete m_pStudioHdr;
		m_pStudioHdr = NULL;
	}
}


inline bool C_BaseAnimating::IsModelScaleFractional() const               
{
	COMPILE_TIME_ASSERT(sizeof(m_flModelScale) == sizeof(int));
	return *((const int*)&m_flModelScale) < 0x3f800000;
}

inline bool C_BaseAnimating::IsModelScaled() const
{
	return (m_flModelScale > 1.0f + FLT_EPSILON || m_flModelScale < 1.0f - FLT_EPSILON);
}

inline int C_BaseAnimating::GetSequence()
{
	return m_nSequence;
}

inline bool C_BaseAnimating::IsSequenceFinished(void)
{
	return m_bSequenceFinished;
}

inline float C_BaseAnimating::SequenceDuration(void)
{
	return SequenceDuration(GetSequence());
}


inline CMouthInfo& C_BaseAnimating::MouthInfo()
{
	return m_mouth;
}


void GetColumn(matrix3x4_t& src, int column, Vector& dest);
void SetColumn(Vector& src, int column, matrix3x4_t& dest);

EXTERN_RECV_TABLE(DT_BaseAnimating);


extern void DevMsgRT(PRINTF_FORMAT_STRING char const* pMsg, ...);

#endif  