//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: Shared util code between client and server.
//
//=============================================================================//

#ifndef UTIL_SHARED_H
#define UTIL_SHARED_H
#ifdef _WIN32
#pragma once
#endif

#include "mathlib/vector.h"
#include "cmodel.h"
#include "utlvector.h"
#include "networkvar.h"
#include "engine/IEngineTrace.h"
#include "engine/IStaticPropMgr.h"
#include "shared_classnames.h"

#ifdef CLIENT_DLL
#include "cdll_client_int.h"
#endif

#ifdef PORTAL
#include "portal_util_shared.h"
#endif

//-----------------------------------------------------------------------------
// Forward declarations
//-----------------------------------------------------------------------------
class CGameTrace;
class CBasePlayer;
typedef CGameTrace trace_t;

extern ConVar developer;	// developer mode


//-----------------------------------------------------------------------------
// Language IDs.
//-----------------------------------------------------------------------------
#define LANGUAGE_ENGLISH				0
#define LANGUAGE_GERMAN					1
#define LANGUAGE_FRENCH					2
#define LANGUAGE_BRITISH				3


//-----------------------------------------------------------------------------
// Pitch + yaw
//-----------------------------------------------------------------------------
float		UTIL_VecToYaw			(const Vector &vec);
float		UTIL_VecToPitch			(const Vector &vec);
float		UTIL_VecToYaw			(const matrix3x4_t& matrix, const Vector &vec);
float		UTIL_VecToPitch			(const matrix3x4_t& matrix, const Vector &vec);
Vector		UTIL_YawToVector		( float yaw );

//-----------------------------------------------------------------------------
// Shared random number generators for shared/predicted code:
// whenever generating random numbers in shared/predicted code, these functions
// have to be used. Each call should specify a unique "sharedname" string that
// seeds the random number generator. In loops make sure the "additionalSeed"
// is increased with the loop counter, otherwise it will always return the
// same random number
//-----------------------------------------------------------------------------
float	SharedRandomFloat( const char *sharedname, float flMinVal, float flMaxVal, int additionalSeed = 0 );
int		SharedRandomInt( const char *sharedname, int iMinVal, int iMaxVal, int additionalSeed = 0 );
Vector	SharedRandomVector( const char *sharedname, float minVal, float maxVal, int additionalSeed = 0 );
QAngle	SharedRandomAngle( const char *sharedname, float minVal, float maxVal, int additionalSeed = 0 );

//-----------------------------------------------------------------------------
// Standard collision filters...
//-----------------------------------------------------------------------------
bool PassServerEntityFilter( const IHandleEntity *pTouch, const IHandleEntity *pPass );
bool StandardFilterRules( IHandleEntity *pHandleEntity, int fContentsMask );


// "weapon_"
#define WEAPON_CLASSNAME_PREFIX_LENGTH 7
bool IsWeaponClassname( const char *pszClassName );

//-----------------------------------------------------------------------------
// Converts an IHandleEntity to an CBaseEntity
//-----------------------------------------------------------------------------
inline const CBaseEntity *EntityFromEntityHandle( const IHandleEntity *pConstHandleEntity )
{
	IHandleEntity *pHandleEntity = const_cast<IHandleEntity*>(pConstHandleEntity);

#ifdef CLIENT_DLL
	IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity;
	return pUnk->GetBaseEntity();
#else
	if ( staticpropmgr->IsStaticProp( pHandleEntity ) )
		return NULL;

	IServerUnknown *pUnk = (IServerUnknown*)pHandleEntity;
	return pUnk->GetBaseEntity();
#endif
}

inline CBaseEntity *EntityFromEntityHandle( IHandleEntity *pHandleEntity )
{
#ifdef CLIENT_DLL
	IClientUnknown *pUnk = (IClientUnknown*)pHandleEntity;
	return pUnk->GetBaseEntity();
#else
#ifndef _GAMECONSOLE
	if ( staticpropmgr->IsStaticProp( pHandleEntity ) )
		return NULL;
#else
	if ( !pHandleEntity || pHandleEntity->m_bIsStaticProp )
		return NULL;
#endif

	IServerUnknown *pUnk = (IServerUnknown*)pHandleEntity;
	Assert( !pUnk || pUnk->GetBaseEntity() );
	return pUnk->GetBaseEntity();
#endif
}


typedef bool (*ShouldHitFunc_t)( IHandleEntity *pHandleEntity, int contentsMask );

//-----------------------------------------------------------------------------
// traceline methods
//-----------------------------------------------------------------------------
class CTraceFilterSimple : public CTraceFilter
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS_NOBASE( CTraceFilterSimple );
	
	CTraceFilterSimple( const IHandleEntity *passentity, int collisionGroup, ShouldHitFunc_t pExtraShouldHitCheckFn = NULL );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
	virtual void SetPassEntity( const IHandleEntity *pPassEntity ) { m_pPassEnt = pPassEntity; }
	virtual void SetCollisionGroup( int iCollisionGroup ) { m_collisionGroup = iCollisionGroup; }

	const IHandleEntity *GetPassEntity( void ){ return m_pPassEnt;}
	int GetCollisionGroup( void ) const { return m_collisionGroup; }

private:
	const IHandleEntity *m_pPassEnt;
	int m_collisionGroup;
	ShouldHitFunc_t m_pExtraShouldHitCheckFunction;

};

class CTraceFilterSkipTwoEntities : public CTraceFilterSimple
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS( CTraceFilterSkipTwoEntities, CTraceFilterSimple );
	
	CTraceFilterSkipTwoEntities( const IHandleEntity *passentity = NULL, const IHandleEntity *passentity2 = NULL, int collisionGroup = COLLISION_GROUP_NONE );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
	virtual void SetPassEntity2( const IHandleEntity *pPassEntity2 ) { m_pPassEnt2 = pPassEntity2; }

private:
	const IHandleEntity *m_pPassEnt2;
};

class CTraceFilterSimpleList : public CTraceFilterSimple
{
public:
	CTraceFilterSimpleList( int collisionGroup );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

	void	AddEntityToIgnore( IHandleEntity *pEntity );
	void	AddEntitiesToIgnore( int nCount, IHandleEntity **ppEntities );

protected:
	CUtlVector<IHandleEntity*>	m_PassEntities;
};

class CTraceFilterOnlyHitThis : public CTraceFilterEntitiesOnly
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS_NOBASE( CTraceFilterOnlyHitThis );

	CTraceFilterOnlyHitThis( const IHandleEntity *hitentity );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

private:
	const IHandleEntity *m_pHitEnt;
};

class CTraceFilterOnlyNPCsAndPlayer : public CTraceFilterSimple
{
public:
	CTraceFilterOnlyNPCsAndPlayer( const IHandleEntity *passentity, int collisionGroup )
		: CTraceFilterSimple( passentity, collisionGroup )
	{
	}

	virtual TraceType_t	GetTraceType() const
	{
		return TRACE_ENTITIES_ONLY;
	}

	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
};

class CTraceFilterNoNPCsOrPlayer : public CTraceFilterSimple
{
public:
	CTraceFilterNoNPCsOrPlayer( const IHandleEntity *passentity = NULL, int collisionGroup = COLLISION_GROUP_NONE )
		: CTraceFilterSimple( passentity, collisionGroup )
	{
	}

	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
};

class CTraceFilterNoPlayers : public CTraceFilterSimple
{
public:
	CTraceFilterNoPlayers( const IHandleEntity *passentity = NULL, int collisionGroup = COLLISION_GROUP_NONE )
		: CTraceFilterSimple( passentity, collisionGroup )
	{
	}

	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
};

//-----------------------------------------------------------------------------
// Purpose: Custom trace filter used for NPC LOS traces
//-----------------------------------------------------------------------------
class CTraceFilterLOS : public CTraceFilterSkipTwoEntities
{
public:
	CTraceFilterLOS( IHandleEntity *pHandleEntity, int collisionGroup, IHandleEntity *pHandleEntity2 = NULL );
	bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );
};

class CTraceFilterSkipClassname : public CTraceFilterSimple
{
public:
	CTraceFilterSkipClassname( const IHandleEntity *passentity, const char *pchClassname, int collisionGroup );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

private:

	const char *m_pchClassname;
};

class CTraceFilterSkipTwoClassnames : public CTraceFilterSkipClassname
{
public:
	// It does have a base, but we'll never network anything below here..
	DECLARE_CLASS( CTraceFilterSkipTwoClassnames, CTraceFilterSkipClassname );

	CTraceFilterSkipTwoClassnames( const IHandleEntity *passentity, const char *pchClassname, const char *pchClassname2, int collisionGroup );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

private:
	const char *m_pchClassname2;
};

class CTraceFilterSimpleClassnameList : public CTraceFilterSimple
{
public:
	CTraceFilterSimpleClassnameList( const IHandleEntity *passentity, int collisionGroup );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

	void	AddClassnameToIgnore( const char *pchClassname );
private:
	CUtlVector<const char*>	m_PassClassnames;
};

class CTraceFilterChain : public CTraceFilter
{
public:
	CTraceFilterChain( ITraceFilter *pTraceFilter1, ITraceFilter *pTraceFilter2 );
	virtual bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask );

private:
	ITraceFilter	*m_pTraceFilter1;
	ITraceFilter	*m_pTraceFilter2;
};

// helper
void DebugDrawLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, int r, int g, int b, bool test, float duration );

extern ConVar r_visualizetraces;

#ifdef DETECT_TRACE_SPIKES
#define BeginDetectTraceSpike() \
	extern void DoReportExpensiveTrace( bool repeat, float time ); \
	extern float g_TraceSpikeTolerance; \
	CFastTimer spikeTimer; \
	spikeTimer.Start()

#define EndDetectTraceSpike() \
	spikeTimer.End()

#define DidTraceSpike() \
	( spikeTimer.GetDuration().GetMillisecondsF() > g_TraceSpikeTolerance )

#define ReportExpensiveTrace( repeat ) if ( DidTraceSpike() ) DoReportExpensiveTrace( repeat, spikeTimer.GetDuration().GetMillisecondsF() )

#else

#define BeginDetectTraceSpike() ((void)0)
#define EndDetectTraceSpike() ((void)0)
#define DidTraceSpike() false
#define ReportExpensiveTrace( repeat ) ((void)0)
#endif

inline void UTIL_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, 
					 const IHandleEntity *ignore, int collisionGroup, trace_t *ptr )
{
	BeginDetectTraceSpike();
	Ray_t ray;
	ray.Init( vecAbsStart, vecAbsEnd );
	CTraceFilterSimple traceFilter( ignore, collisionGroup );

	enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
	EndDetectTraceSpike();

	if( r_visualizetraces.GetBool() || DidTraceSpike() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, ( r_visualizetraces.GetBool() ) ? -1.0f : .5 );
		ReportExpensiveTrace( false );
		if ( DidTraceSpike() ) // Opimizer will remove this block
		{
			ReportExpensiveTrace( false );
			BeginDetectTraceSpike();
			Ray_t ray;
			ray.Init( vecAbsStart, vecAbsEnd );
			CTraceFilterSimple traceFilter( ignore, collisionGroup );

			enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
			EndDetectTraceSpike();
			if ( DidTraceSpike() )
			{
				ReportExpensiveTrace( true );
			}
		}
	}
}

inline void UTIL_TraceLine( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, 
					 ITraceFilter *pFilter, trace_t *ptr )
{
	BeginDetectTraceSpike();
	Ray_t ray;
	ray.Init( vecAbsStart, vecAbsEnd );

	enginetrace->TraceRay( ray, mask, pFilter, ptr );
	EndDetectTraceSpike();

	if( r_visualizetraces.GetBool() || DidTraceSpike() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, ( r_visualizetraces.GetBool() ) ? -1.0f : .5 );
		ReportExpensiveTrace( false );
		if ( DidTraceSpike() ) // Opimizer will remove this block
		{
			BeginDetectTraceSpike();
			Ray_t ray;
			ray.Init( vecAbsStart, vecAbsEnd );

			enginetrace->TraceRay( ray, mask, pFilter, ptr );
			EndDetectTraceSpike();

			if ( DidTraceSpike() )
			{
				ReportExpensiveTrace( true );
			}
		}
	}
}

inline void UTIL_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, 
					 const Vector &hullMax,	unsigned int mask, const IHandleEntity *ignore, 
					 int collisionGroup, trace_t *ptr )
{
	BeginDetectTraceSpike();
	Ray_t ray;
	ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax );
	CTraceFilterSimple traceFilter( ignore, collisionGroup );

	enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
	EndDetectTraceSpike();

	if( r_visualizetraces.GetBool() || DidTraceSpike() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 255, 0, true, ( r_visualizetraces.GetBool() ) ? -1.0f : .5 );
		ReportExpensiveTrace( false );
		if ( DidTraceSpike() ) // Opimizer will remove this block
		{
			BeginDetectTraceSpike();
			Ray_t ray;
			ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax );
			CTraceFilterSimple traceFilter( ignore, collisionGroup );

			enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
			EndDetectTraceSpike();

			if ( DidTraceSpike() )
			{
				ReportExpensiveTrace( true );
			}
		}
	}
}

inline void UTIL_TraceHull( const Vector &vecAbsStart, const Vector &vecAbsEnd, const Vector &hullMin, 
					 const Vector &hullMax,	unsigned int mask, ITraceFilter *pFilter, trace_t *ptr )
{
	BeginDetectTraceSpike();
	Ray_t ray;
	ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax );

	enginetrace->TraceRay( ray, mask, pFilter, ptr );

	EndDetectTraceSpike();
	if( r_visualizetraces.GetBool() || DidTraceSpike() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 255, 0, true, ( r_visualizetraces.GetBool() ) ? -1.0f : .5 );
		ReportExpensiveTrace( false );
		if ( DidTraceSpike() ) // Opimizer will remove this block
		{
			BeginDetectTraceSpike();
			Ray_t ray;
			ray.Init( vecAbsStart, vecAbsEnd, hullMin, hullMax );

			enginetrace->TraceRay( ray, mask, pFilter, ptr );

			EndDetectTraceSpike();
			if( DidTraceSpike() )
			{
				ReportExpensiveTrace( true );
			}
		}
	}
}

inline void UTIL_TraceRay( const Ray_t &ray, unsigned int mask, 
						  const IHandleEntity *ignore, int collisionGroup, trace_t *ptr )
{
	CTraceFilterSimple traceFilter( ignore, collisionGroup );

	enginetrace->TraceRay( ray, mask, &traceFilter, ptr );
	
	if( r_visualizetraces.GetBool() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f );
	}
}

inline void UTIL_TraceRay( const Ray_t &ray, unsigned int mask, 
						  ITraceFilter *pFilter, trace_t *ptr )
{
	enginetrace->TraceRay( ray, mask, pFilter, ptr );

	if( r_visualizetraces.GetBool() )
	{
		DebugDrawLine( ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f );
	}
}
// Sweeps a particular entity through the world
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr );
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, 
					  unsigned int mask, ITraceFilter *pFilter, trace_t *ptr );
void UTIL_TraceEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, 
					  unsigned int mask, const IHandleEntity *ignore, int collisionGroup, trace_t *ptr );

bool UTIL_EntityHasMatchingRootParent( CBaseEntity *pRootParent, CBaseEntity *pEntity );

inline int UTIL_PointContents( const Vector &vec, int contentsMask )
{
	return enginetrace->GetPointContents( vec, contentsMask );
}

// Sweeps against a particular model, using collision rules 
void UTIL_TraceModel( const Vector &vecStart, const Vector &vecEnd, const Vector &hullMin, 
					  const Vector &hullMax, CBaseEntity *pentModel, int collisionGroup, trace_t *ptr );

void UTIL_ClipTraceToPlayers( const Vector& vecAbsStart, const Vector& vecAbsEnd, unsigned int mask, ITraceFilter *filter, trace_t *tr );

// Particle effect tracer
void		UTIL_ParticleTracer( const char *pszTracerEffectName, const Vector &vecStart, const Vector &vecEnd, int iEntIndex = 0, int iAttachment = 0, bool bWhiz = false );

// Old style, non-particle system, tracers
void		UTIL_Tracer( const Vector &vecStart, const Vector &vecEnd, int iEntIndex = 0, int iAttachment = TRACER_DONT_USE_ATTACHMENT, float flVelocity = 0, bool bWhiz = false, const char *pCustomTracerName = NULL, int iParticleID = 0 );

bool		UTIL_IsLowViolence( void );
bool		UTIL_ShouldShowBlood( int bloodColor );
void		UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount );

void		UTIL_BloodImpact( const Vector &pos, const Vector &dir, int color, int amount );
void		UTIL_BloodDecalTrace( trace_t *pTrace, int bloodColor );
void		UTIL_DecalTrace( trace_t *pTrace, char const *decalName );
bool		UTIL_IsSpaceEmpty( CBaseEntity *pMainEnt, const Vector &vMin, const Vector &vMax );
bool		UTIL_IsSpaceEmpty( CBaseEntity *pMainEnt, const Vector &vMin, const Vector &vMax, unsigned int mask, ITraceFilter *pFilter );

// Search for water transition along a vertical line
float UTIL_WaterLevel( const Vector &position, float minz, float maxz );

// Like UTIL_WaterLevel, but *way* less expensive.
// I didn't replace UTIL_WaterLevel everywhere to avoid breaking anything.
float UTIL_FindWaterSurface( const Vector &position, float minz, float maxz );

void		UTIL_StringToVector( float *pVector, const char *pString );
void		UTIL_StringToFloatArray( float *pVector, int count, const char *pString );

CBasePlayer *UTIL_PlayerByIndex( int entindex );

// decodes/encodes a buffer using a 64bit ICE key (inplace)
void		UTIL_DecodeICE( unsigned char * buffer, int size, const unsigned char *key );
void		UTIL_EncodeICE( unsigned char * buffer, unsigned int size, const unsigned char *key );
unsigned short UTIL_GetAchievementEventMask( void );	

//assumes the object is already in a mostly passable space
#define FL_AXIS_DIRECTION_NONE	( 0 )
#define FL_AXIS_DIRECTION_X		( 1 << 0 )
#define FL_AXIS_DIRECTION_NX	( 1 << 1 )
#define FL_AXIS_DIRECTION_Y		( 1 << 2 )
#define FL_AXIS_DIRECTION_NY	( 1 << 3 )
#define FL_AXIS_DIRECTION_Z		( 1 << 4 )
#define FL_AXIS_DIRECTION_NZ	( 1 << 5 )

struct FindClosestPassableSpace_TraceAdapter_t;
typedef void (*FN_RayTraceAdapterFunc)( const Ray_t &ray, trace_t *pResult, FindClosestPassableSpace_TraceAdapter_t *pTraceAdapter );
typedef bool (*FN_PointIsOutsideWorld)( const Vector &vTest, FindClosestPassableSpace_TraceAdapter_t *pTraceAdapter );

//derive from this to tack on additional data to your adapted functions
struct FindClosestPassableSpace_TraceAdapter_t
{
	FN_RayTraceAdapterFunc pTraceFunc;
	FN_PointIsOutsideWorld pPointOutsideWorldFunc;

	ITraceFilter *pTraceFilter;
	unsigned int fMask;
};

bool		UTIL_FindClosestPassableSpace( const Vector &vCenter, const Vector &vExtents, const Vector &vIndecisivePush, unsigned int iIterations, Vector &vCenterOut, int nAxisRestrictionFlags, FindClosestPassableSpace_TraceAdapter_t *pTraceAdapter );
bool		UTIL_FindClosestPassableSpace( const Vector &vCenter, const Vector &vExtents, const Vector &vIndecisivePush, ITraceFilter *pTraceFilter, unsigned int fMask, unsigned int iIterations, Vector &vCenterOut, int nAxisRestrictionFlags = FL_AXIS_DIRECTION_NONE );
bool		UTIL_FindClosestPassableSpace( CBaseEntity *pEntity, const Vector &vIndecisivePush, unsigned int fMask, unsigned int iIterations, Vector &vOriginOut, Vector *pStartingPosition = NULL, int nAxisRestrictionFlags = FL_AXIS_DIRECTION_NONE );
bool		UTIL_FindClosestPassableSpace( CBaseEntity *pEntity, const Vector &vIndecisivePush, unsigned int fMask, Vector *pStartingPosition = NULL, int nAxisRestrictionFlags = FL_AXIS_DIRECTION_NONE );


//--------------------------------------------------------------------------------------------------------------
/**
 * Given a position and a ray, return the shortest distance between the two.
 * If 'pos' is beyond either end of the ray, the returned distance is negated.
 */
inline float DistanceToRay( const Vector &pos, const Vector &rayStart, const Vector &rayEnd, float *along = NULL, Vector *pointOnRay = NULL )
{
	Vector to = pos - rayStart;
	Vector dir = rayEnd - rayStart;
	float length = dir.NormalizeInPlace();

	float rangeAlong = DotProduct( dir, to );
	if (along)
	{
		*along = rangeAlong;
	}

	float range;

	if (rangeAlong < 0.0f)
	{
		// off start point
		range = -(pos - rayStart).Length();

		if (pointOnRay)
		{
			*pointOnRay = rayStart;
		}
	}
	else if (rangeAlong > length)
	{
		// off end point
		range = -(pos - rayEnd).Length();

		if (pointOnRay)
		{
			*pointOnRay = rayEnd;
		}
	}
	else // within ray bounds
	{
		Vector onRay = rayStart + rangeAlong * dir;
		range = (pos - onRay).Length();

		if (pointOnRay)
		{
			*pointOnRay = onRay;
		}
	}

	return range;
}


//--------------------------------------------------------------------------------------------------------------
/**
* Macro for creating an interface that when inherited from automatically maintains a list of instances
* that inherit from that interface.
*/

// interface for entities that want to a auto maintained global list
#define DECLARE_AUTO_LIST( interfaceName ) \
	class interfaceName; \
	abstract_class interfaceName \
	{ \
	public: \
		interfaceName( bool bAutoAdd = true ); \
		virtual ~interfaceName(); \
		virtual CBaseEntity* GetEntity( void ) = 0; \
		static void Add( interfaceName *pElement ) { m_##interfaceName##AutoList.AddToTail( pElement ); } \
		static void Remove( interfaceName *pElement ) { m_##interfaceName##AutoList.FindAndFastRemove( pElement ); } \
		static const CUtlVector< interfaceName* >& AutoList( void ) { return m_##interfaceName##AutoList; } \
	private: \
	static CUtlVector< interfaceName* > m_##interfaceName##AutoList; \
	};

// Creates a simple function for accessing the higher level entity
#define IMPLEMENT_AUTO_LIST_GET() \
	virtual CBaseEntity* GetEntity( void ) { return this; }

// Creates the auto add/remove constructor/destructor...
// Pass false to the constructor to not auto add
#define IMPLEMENT_AUTO_LIST( interfaceName ) \
	CUtlVector< class interfaceName* > interfaceName::m_##interfaceName##AutoList; \
	interfaceName::interfaceName( bool bAutoAdd ) \
	{ \
		if ( bAutoAdd ) \
		{ \
			Add( this ); \
		} \
	} \
	interfaceName::~interfaceName() \
	{ \
		Remove( this ); \
	}


//--------------------------------------------------------------------------------------------------------------
/**
 * Simple class for tracking intervals of game time.
 * Upon creation, the timer is invalidated.  To measure time intervals, start the timer via Start().
 */
class IntervalTimer
{
public:
#ifdef CLIENT_DLL
	DECLARE_PREDICTABLE();
#endif
	DECLARE_DATADESC();
	DECLARE_CLASS_NOBASE( IntervalTimer );
	DECLARE_EMBEDDED_NETWORKVAR();

	IntervalTimer( void ) : m_timestamp( -1.0f )
	{
	}

	void Reset( void )
	{
		m_timestamp = Now();
	}		

	void Start( void )
	{
		m_timestamp = Now();
	}

	void StartFromTime( float startTime )
	{
		m_timestamp = startTime;
	}

	void Invalidate( void )
	{
		m_timestamp = -1.0f;
	}		

	bool HasStarted( void ) const
	{
		return (m_timestamp > 0.0f);
	}

	/// if not started, elapsed time is very large
	float GetElapsedTime( void ) const
	{
		return (HasStarted()) ? (Now() - m_timestamp) : 99999.9f;
	}

	bool IsLessThen( float duration ) const
	{
		return (Now() - m_timestamp < duration) ? true : false;
	}

	bool IsGreaterThen( float duration ) const
	{
		return (Now() - m_timestamp > duration) ? true : false;
	}

	float GetStartTime( void ) const
	{
		return m_timestamp;
	}

protected:
	CNetworkVar( float, m_timestamp );
	float Now( void ) const;		// work-around since client header doesn't like inlined gpGlobals->curtime
};

#ifdef CLIENT_DLL
EXTERN_RECV_TABLE(DT_IntervalTimer);
#else
EXTERN_SEND_TABLE(DT_IntervalTimer);
#endif

//--------------------------------------------------------------------------------------------------------------
/**
 * Simple class for counting down a short interval of time.
 * Upon creation, the timer is invalidated.  Invalidated countdown timers are considered to have elapsed.
 */
class CountdownTimer
{
public:
#ifdef CLIENT_DLL
	DECLARE_PREDICTABLE();
#endif
	DECLARE_CLASS_NOBASE( CountdownTimer );
	DECLARE_EMBEDDED_NETWORKVAR();

	CountdownTimer( void ) : 
		m_timestamp( -1.0f), m_duration( 0.0f )
	{
	}

	void Reset( void )
	{
		m_timestamp = Now() + m_duration;
	}		

	void Start( float duration )
	{
		m_timestamp = Now() + duration;
		m_duration = duration;
	}

	void StartFromTime( float startTime, float duration )
	{
		m_timestamp = startTime + duration;
		m_duration = duration;
	}

	void Invalidate( void )
	{
		m_timestamp = -1.0f;
	}		

	bool HasStarted( void ) const
	{
		return (m_timestamp > 0.0f);
	}

	bool IsElapsed( void ) const
	{
		return (Now() > m_timestamp);
	}

	float GetElapsedTime( void ) const
	{
		return Now() - m_timestamp + m_duration;
	}

	float GetRemainingTime( void ) const
	{
		return (m_timestamp - Now());
	}

	float GetTargetTime() const
	{
		return m_timestamp;
	}

	/// return original countdown time
	float GetCountdownDuration( void ) const
	{
		return (m_timestamp > 0.0f) ? m_duration : 0.0f;
	}
	
	/// 1.0 for newly started, 0.0 for elapsed
	float GetRemainingRatio( void ) const
	{
		if ( HasStarted() )
		{
			float left = GetRemainingTime() / m_duration;
			if ( left < 0.0f )
				return 0.0f;
			if ( left > 1.0f )
				return 1.0f;
			return left;
		}
		
		return 0.0f;
	}

	float GetElapsedRatio() const
	{
		if ( HasStarted() )
		{
			float elapsed = GetElapsedTime() / m_duration;
			if ( elapsed < 0.0f )
				return 0.0f;
			if ( elapsed > 1.0f )
				return 1.0f;
			return elapsed;
		}

		return 1.0f;
	}

	// Usage:
	//    Declaration: CountdownTimer mTimer;
	//    Think function:
	//        while(mTimer.RunEvery( timerInterval ))
	//        {
	//			  do fixed-rate stuff
	//        }
	//
	//        nextThinkTime = min(nextThinkTime, mTimer.GetTargetTime());
	//
	// This avoids 'losing' ticks on a repeating timer when
	// the think rate is not a multiple of the timer duration,
	// especially since SetNextThink rounds ticks up/down, causing
	// even a timer that is running exactly at the think rate of
	// the underlying class to not elapse correctly.
	// 
	// It also makes sure that ticks are never lost
	bool RunEvery( float amount = -1.0f )
	{
		// First call starts the timer
		if(!HasStarted())
		{
			if(amount > 0.0f)
				Start( amount );

			return false;
		}

		if( IsElapsed() )
		{
			if ( amount > 0.0f )
				m_duration = amount;

			m_timestamp += m_duration;
			return true;
		}

		return false;
	}

	// Same as RunEvery() but only returns true once per 'tick', then guarantees being non-elapsed.
	// Useful when "do fixed rate stuff" is idempotent, like updating something to match
	// the current time.
	bool Interval( float amount = -1.0f )
	{
		// First call starts the timer
		if ( !HasStarted() )
		{
			if ( amount > 0.0f )
				Start( amount );

			return false;
		}

		if ( IsElapsed() )
		{
			if ( amount > 0.0f )
				m_duration = amount;

			m_timestamp += m_duration;

			// If we are still expired, add a multiple of the interval 
			// until we become non-elapsed
			float remaining = GetRemainingTime();
			if ( remaining < 0.0f)
			{
				float numIntervalsRequired = -floorf( remaining / m_duration );
				m_timestamp += m_duration * numIntervalsRequired;
			}

			// We should no longer be elapsed
			Assert( !IsElapsed() );

			return true;
		}

		return false;
	}

private:
	CNetworkVar( float, m_duration );
	CNetworkVar( float, m_timestamp );
	float Now( void ) const;		// work-around since client header doesn't like inlined gpGlobals->curtime
};

#ifdef CLIENT_DLL
EXTERN_RECV_TABLE(DT_CountdownTimer);
#else
EXTERN_SEND_TABLE(DT_CountdownTimer);
#endif


//--------------------------------------------------------------------------------------------------------------
/**
* Simple class for tracking change in values over time.
*/
#define TIMELINE_ARRAY_SIZE 64
#define TIMELINE_INTERVAL_START 0.25f

enum TimelineCompression_t
{
	TIMELINE_COMPRESSION_SUM,
	TIMELINE_COMPRESSION_COUNT_PER_INTERVAL,
	TIMELINE_COMPRESSION_AVERAGE,
	TIMELINE_COMPRESSION_AVERAGE_BLEND,

	TIMELINE_COMPRESSION_TOTAL
};

class CTimeline : public IntervalTimer
{
public:
	DECLARE_DATADESC();
	DECLARE_CLASS( CTimeline, IntervalTimer );
	DECLARE_EMBEDDED_NETWORKVAR();

	CTimeline( void )
	{
		ClearValues();
	}

	void ClearValues( void );
	void ClearAndStart( void ) { ClearValues(); Start(); }
	void StopRecording( void ) { m_bStopped = true; }
	void RecordValue( float flValue );
	void RecordFinalValue( float flValue ) { RecordValue( flValue ); StopRecording(); }

	int Count( void ) const
	{
		return m_nBucketCount;
	}

	float GetValue( int i ) const;

	float GetValueAtInterp( float fInterp ) const;

	float GetValueTime( int i ) const
	{
		Assert( i >= 0 && i < m_nBucketCount );
		return static_cast<float>( i ) * m_flInterval;
	}

	float GetInterval( void ) const
	{
		return m_flInterval;
	}

	void SetCompressionType( TimelineCompression_t nCompressionType )
	{
		m_nCompressionType = nCompressionType;
	}

	TimelineCompression_t GetCompressionType( void ) const
	{
		return m_nCompressionType;
	}

private:
	int GetCurrentBucket( void )
	{
		return static_cast<float>( Now() - m_timestamp ) / m_flInterval;
	}

	void Compress( void );

	CNetworkArray( float, m_flValues, TIMELINE_ARRAY_SIZE );
	CNetworkArray( int, m_nValueCounts, TIMELINE_ARRAY_SIZE );
	CNetworkVar( int, m_nBucketCount );
	CNetworkVar( float, m_flInterval );
	CNetworkVar( float, m_flFinalValue );
	CNetworkVar( TimelineCompression_t, m_nCompressionType );
	CNetworkVar( bool, m_bStopped );
};

#ifdef CLIENT_DLL
EXTERN_RECV_TABLE(DT_Timeline);
#else
EXTERN_SEND_TABLE(DT_Timeline);
#endif

char* ReadAndAllocStringValue( KeyValues *pSub, const char *pName, const char *pFilename = NULL );

int UTIL_StringFieldToInt( const char *szValue, const char **pValueStrings, int iNumStrings );

int UTIL_CountNumBitsSet( unsigned int nVar );
int UTIL_CountNumBitsSet( uint64 nVar );

bool UTIL_GetModDir( char *lpszTextOut, unsigned int nSize );

/*UTIL_CalcFrustumThroughPolygon - Given a frustum and a polygon, calculate how the current frustum would clip the polygon, then generate a new frustum that runs along the edge of the clipped polygon.
-returns number of planes in the output frustum, 0 if the polygon was completely clipped by the input frustum
-vFrustumOrigin can be thought of as the camera origin if your frustum is a view frustum
-planes should face inward
-iPreserveCount will preserve N planes at the end of your input frustum and ensure they're at the end of your output frustum. Assuming your input frustum is of type "Frustum", a value of 2 would preserve your near and far planes
-to ensure that your output frustum can hold the entire complex frustum we generate. Make it of size (iPolyVertCount + iCurrentFrustumPlanes + iPreserveCount). Otherwise the output frustum will be simplified to fit your maximum output by eliminating bounding planes with the clipped area.
-a lack of input frustum is considered valid input*/
int UTIL_CalcFrustumThroughConvexPolygon( const Vector *pPolyVertices, int iPolyVertCount, const Vector &vFrustumOrigin, const VPlane *pInputFrustumPlanes, int iInputFrustumPlanes, VPlane *pOutputFrustumPlanes, int iMaxOutputPlanes, int iPreserveCount );


//-----------------------------------------------------------------------------
// class CFlaggedEntitiesEnum
//-----------------------------------------------------------------------------
// enumerate entities that match a set of edict flags into a static array
class CFlaggedEntitiesEnum : public IPartitionEnumerator
{
public:
	CFlaggedEntitiesEnum( CBaseEntity **pList, int listMax, int flagMask );

	// This gets called	by the enumeration methods with each element
	// that passes the test.
	virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity );

	int GetCount() { return m_count; }
	bool AddToList( CBaseEntity *pEntity );

private:
	CBaseEntity		**m_pList;
	int				m_listMax;
	int				m_flagMask;
	int				m_count;
};

class CHurtableEntitiesEnum : public IPartitionEnumerator
{
public:
	CHurtableEntitiesEnum( CBaseEntity **pList, int listMax );

	// This gets called	by the enumeration methods with each element
	// that passes the test.
	virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity );

	int GetCount() { return m_count; }
	bool AddToList( CBaseEntity *pEntity );

private:
	CBaseEntity		**m_pList;
	int				m_listMax;
	int				m_count;
};

int			UTIL_EntitiesAlongRay( const Ray_t &ray, CFlaggedEntitiesEnum *pEnum  );

inline int UTIL_EntitiesAlongRay( CBaseEntity **pList, int listMax, const Ray_t &ray, int flagMask )
{
	CFlaggedEntitiesEnum rayEnum( pList, listMax, flagMask );
	return UTIL_EntitiesAlongRay( ray, &rayEnum );
}


#include "shareddefs.h"
#if (PREDICTION_ERROR_CHECK_LEVEL > 0)

extern void _Easy_DiffPrint( CBaseEntity *pEntity, PRINTF_FORMAT_STRING const char *szFormatSTring, ... );

#if defined( CLIENT_DLL )
extern bool _Easy_DiffPrint_InternalConditions( C_BaseEntity *pEntity );
#define _EASY_DIFFPRINT_INTERNALCONDITIONS(entity) _Easy_DiffPrint_InternalConditions( entity )
#else
#define _EASY_DIFFPRINT_INTERNALCONDITIONS(entity) true
#endif

#define EASY_DIFFPRINT_CONDITIONAL( conditions, entity, szFormatString, ... ) if( (conditions) && _EASY_DIFFPRINT_INTERNALCONDITIONS( entity ) ) { _Easy_DiffPrint( entity, szFormatString, __VA_ARGS__ ); }
#define EASY_DIFFPRINT( entity, szFormatString, ... ) EASY_DIFFPRINT_CONDITIONAL( true, entity, szFormatString, __VA_ARGS__ )

#else //#if (PREDICTION_ERROR_CHECK_LEVEL > 0)

#define EASY_DIFFPRINT_CONDITIONAL( conditions, entity, szFormatString, ... )
#define EASY_DIFFPRINT( entity, szFormatString, ... )

#endif //#if (PREDICTION_ERROR_CHECK_LEVEL > 0)

void		UTIL_GetNextCommandLength( const char *pText, int nMaxLen, int *pCommandLength, int *pNextCommandOffset );

//--------------------------------------------------------------------------------------------------------------
/**
 *  remove double spaces and empty bold/italic HTML tags from a string
 */
void UTIL_TrimEmptyWhitespaceFromHTML( OUT_Z_BYTECAP( descWriterByteSize ) wchar_t* pszDescWriter, size_t descWriterByteSize, const wchar_t* pszDescReader );
void UTIL_TrimEmptyWhitespaceFromHTML( OUT_Z_BYTECAP( descWriterByteSize ) char* pszDescWriter, size_t descWriterByteSize, const char* pszDescReader );

#endif // UTIL_SHARED_H