#include <string.h>
#ifndef ACTIVITY_H
#include "activity.h"
#endif

#ifndef ENGINECALLBACK_H
#include "enginecallback.h"
#endif

#ifndef UTIL_H
#define UTIL_H

inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent);
extern globalvars_t *gpGlobals;

#define STRING(offset) reinterpret_cast<const char *>(gpGlobals->pStringBase + (uintp)offset)
#define MAKE_STRING(str) (reinterpret_cast<uintp>(str) - reinterpret_cast<uintp>(STRING(0)))

inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName)
{
	return FIND_ENTITY_BY_STRING(entStart, "classname", pszName);
}

inline edict_t *FIND_ENTITY_BY_TARGETNAME(edict_t *entStart, const char *pszName)
{
	return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName);
}

inline edict_t *FIND_ENTITY_BY_TARGET(edict_t *entStart, const char *pszName)
{
	return FIND_ENTITY_BY_STRING(entStart, "target", pszName);
}

#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue)
#define WRITEKEY_FLOAT(pf, szKeyName, flKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%f\"\n", szKeyName, flKeyValue)
#define WRITEKEY_STRING(pf, szKeyName, szKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%s\"\n", szKeyName, szKeyValue)
#define WRITEKEY_VECTOR(pf, szKeyName, flX, flY, flZ) ENGINE_FPRINTF(pf, "\"%s\" \"%f %f %f\"\n", szKeyName, flX, flY, flZ)

#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits))
#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits))
#define FBitSet(flBitVector, bit) ((int)(flBitVector) & (bit))

#define FILE_GLOBAL static
#define DLL_GLOBAL
#define CONSTANT

typedef int EOFFSET;
typedef int BOOL;

#define M_PI 3.14159265358979323846

#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName(void)
#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname(void)

#ifdef _WIN32
#define LINK_ENTITY_TO_CLASS(mapClassName, DLLClassName) \
	extern "C" _declspec(dllexport) void mapClassName(entvars_t *pev); \
	void mapClassName(entvars_t *pev) { GetClassPtr((DLLClassName *)pev); }
#else
#define LINK_ENTITY_TO_CLASS(mapClassName,DLLClassName) extern "C" void mapClassName(entvars_t *pev); void mapClassName(entvars_t *pev) { GetClassPtr((DLLClassName *)pev); }
#endif

inline edict_t *ENT(const entvars_t *pev) { return pev->pContainingEntity; }
inline edict_t *ENT(edict_t *pent) { return pent; }
inline edict_t *ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); }
inline EOFFSET OFFSET(EOFFSET eoffset) { return eoffset; }
inline EOFFSET OFFSET(const edict_t *pent) { return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent); }
inline EOFFSET OFFSET(entvars_t *pev) { return OFFSET(ENT(pev)); }
inline entvars_t *VARS(entvars_t *pev) { return pev; }

inline entvars_t *VARS(edict_t *pent)
{
	if (!pent)
		return NULL;

	return &pent->v;
}

inline entvars_t *VARS(EOFFSET eoffset) { return VARS(ENT(eoffset)); }
inline int ENTINDEX(edict_t *pEdict) { return (*g_engfuncs.pfnIndexOfEdict)(pEdict); }
inline edict_t *INDEXENT(int iEdictNum) { return (*g_engfuncs.pfnPEntityOfEntIndex)(iEdictNum); }
inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float *pOrigin, entvars_t *ent) { (*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent)); }

#define eoNullEntity 0
inline BOOL FNullEnt(EOFFSET eoffset) { return eoffset == 0; }
inline BOOL FNullEnt(const edict_t *pent) { return pent == NULL || FNullEnt(OFFSET(pent)); }
inline BOOL FNullEnt(entvars_t *pev) { return pev == NULL || FNullEnt(OFFSET(pev)); }

#define iStringNull 0
inline BOOL FStringNull(int iString) { return iString == iStringNull; }

#define cchMapNameMost 32

#define VIEW_FIELD_FULL (float)-1
#define VIEW_FIELD_WIDE (float)-0.7
#define VIEW_FIELD_NARROW (float)0.7
#define VIEW_FIELD_ULTRA_NARROW (float)0.9

#define DONT_BLEED -1
#define BLOOD_COLOR_RED (BYTE)247
#define BLOOD_COLOR_YELLOW (BYTE)195
#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW

typedef enum 
{
	MONSTERSTATE_NONE = 0,
	MONSTERSTATE_IDLE,
	MONSTERSTATE_COMBAT,
	MONSTERSTATE_ALERT,
	MONSTERSTATE_HUNT,
	MONSTERSTATE_PRONE,
	MONSTERSTATE_SCRIPT,
	MONSTERSTATE_PLAYDEAD,
	MONSTERSTATE_DEAD
}
MONSTERSTATE;

//sohl start
typedef enum
{
	STATE_OFF = 0,	// disabled, inactive, invisible, closed, or stateless. Or non-alert monster.
	STATE_TURN_ON,  // door opening, env_fade fading in, etc.
	STATE_ON,		// enabled, active, visisble, or open. Or alert monster.
	STATE_TURN_OFF, // door closing, monster dying (?).
	STATE_IN_USE,	// player is in control (train/tank/barney/scientist).
					// In_Use isn't very useful, I'll probably remove it.
} STATE;
//sohl end
typedef enum
{
	TS_AT_TOP,
	TS_AT_BOTTOM,
	TS_GOING_UP,
	TS_GOING_DOWN
}

TOGGLE_STATE;

inline BOOL FStrEq(const char *sz1, const char *sz2) { return (!strcmp(sz1, sz2)); }
inline BOOL FClassnameIs(edict_t *pent, const char *szClassname) { return FStrEq(STRING(VARS(pent)->classname), szClassname); }
inline BOOL FClassnameIs(entvars_t *pev, const char *szClassname) { return FStrEq(STRING(pev->classname), szClassname); }

class CBaseEntity;

extern void UTIL_SetSize(entvars_t *pev, const Vector &vecMin, const Vector &vecMax);
extern float UTIL_VecToYaw(const Vector &vec);
extern Vector UTIL_VecToAngles(const Vector &vec);
extern float UTIL_AngleMod(float a);
extern float UTIL_AngleDiff(float destAngle, float srcAngle);

extern CBaseEntity *UTIL_FindEntityInSphere(CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius);
extern CBaseEntity *UTIL_FindEntityByString(CBaseEntity *pStartEntity, const char *szKeyword, const char *szValue);
extern CBaseEntity *UTIL_FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName);
extern CBaseEntity *UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName);
extern CBaseEntity	*UTIL_FindEntityByTargetname(CBaseEntity *pStartEntity, const char *szName, CBaseEntity *pActivator ); //sohl - zhizhangertong
extern CBaseEntity *UTIL_FindEntityGeneric(const char *szName, Vector &vecSrc, float flRadius);
extern CBaseEntity *UTIL_PlayerByIndex(int playerIndex);

#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent)

extern void UTIL_MakeVectors(const Vector &vecAngles);
extern int UTIL_MonstersInSphere(CBaseEntity **pList, int listMax, const Vector &center, float radius);
extern int UTIL_EntitiesInBox(CBaseEntity **pList, int listMax, const Vector &mins, const Vector &maxs, int flagMask);
inline void UTIL_MakeVectorsPrivate(const Vector &vecAngles, float *p_vForward, float *p_vRight, float *p_vUp) { g_engfuncs.pfnAngleVectors(vecAngles, p_vForward, p_vRight, p_vUp); }
extern void UTIL_MakeAimVectors(const Vector &vecAngles);
extern void UTIL_MakeInvVectors(const Vector &vec, globalvars_t *pgv);

extern void UTIL_SetOrigin(entvars_t *pev, const Vector &vecOrigin);
extern void UTIL_EmitAmbientSound(edict_t *entity, const Vector &vecOrigin, const char *samp, float vol, float attenuation, int fFlags, int pitch);
extern void UTIL_ParticleEffect(const Vector &vecOrigin, const Vector &vecDirection, ULONG ulColor, ULONG ulCount);
extern void UTIL_SingleScreenShake(float amplitude, float frequency, float duration, CBaseEntity *pPlayer);
extern void UTIL_ScreenShake(const Vector &center, float amplitude, float frequency, float duration, float radius);
extern void UTIL_ScreenShakeAll(const Vector &center, float amplitude, float frequency, float duration);
extern void UTIL_ShowMessage(const char *pString, CBaseEntity *pPlayer);
extern void UTIL_ShowMessageAll(const char *pString);
extern void UTIL_ScreenFadeAll(const Vector &color, float fadeTime, float holdTime, int alpha, int flags);
extern void UTIL_ScreenFade(CBaseEntity *pEntity, const Vector &color, float fadeTime, float fadeHold, int alpha, int flags);

typedef enum { ignore_monsters = 1, dont_ignore_monsters = 0, missile = 2 } IGNORE_MONSTERS;
typedef enum { ignore_glass = 1, dont_ignore_glass = 0 } IGNORE_GLASS;
extern void UTIL_TraceLine(const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr);
extern void UTIL_TraceLine(const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, IGNORE_GLASS ignoreGlass, edict_t *pentIgnore, TraceResult *ptr);
typedef enum { point_hull = 0, human_hull = 1, large_hull = 2, head_hull = 3 };
extern void UTIL_TraceHull(const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, int hullNumber, edict_t *pentIgnore, TraceResult *ptr);
extern TraceResult UTIL_GetGlobalTrace(void);
extern void UTIL_TraceModel(const Vector &vecStart, const Vector &vecEnd, int hullNumber, edict_t *pentModel, TraceResult *ptr);
extern Vector UTIL_GetAimVector(edict_t *pent, float flSpeed);
extern int UTIL_PointContents(const Vector &vec);

extern int UTIL_IsMasterTriggered(string_t sMaster, CBaseEntity *pActivator);
extern void UTIL_BloodStream(const Vector &origin, const Vector &direction, int color, int amount);
extern void UTIL_BloodDrips(const Vector &origin, const Vector &direction, int color, int amount);
extern Vector UTIL_RandomBloodVector(void);
extern BOOL UTIL_ShouldShowBlood(int bloodColor);
extern void UTIL_BloodDecalTrace(TraceResult *pTrace, int bloodColor);
extern void UTIL_DecalTrace(TraceResult *pTrace, int decalNumber);
extern void UTIL_PlayerDecalTrace(TraceResult *pTrace, int playernum, int decalNumber, BOOL bIsCustom);
extern void UTIL_GunshotDecalTrace(TraceResult *pTrace, int decalNumber);
extern void UTIL_Sparks(const Vector &position);
extern void UTIL_Ricochet(const Vector &position, float scale);
extern void UTIL_StringToVector(float *pVector, const char *pString);
extern void UTIL_StringToIntArray(int *pVector, int count, const char *pString);
extern Vector UTIL_ClampVectorToBox(const Vector &input, const Vector &clampSize);
extern float UTIL_Approach(float target, float value, float speed);
extern float UTIL_ApproachAngle(float target, float value, float speed);
extern float UTIL_AngleDistance(float next, float cur);
extern char *UTIL_VarArgs(char *format, ...);
extern void UTIL_Remove(CBaseEntity *pEntity);
extern BOOL UTIL_IsValidEntity(edict_t *pent);
extern BOOL UTIL_TeamsMatch(const char *pTeamName1, const char *pTeamName2);
extern float UTIL_SplineFraction(float value, float scale);
extern float UTIL_WaterLevel(const Vector &position, float minz, float maxz);
extern void UTIL_Bubbles(Vector mins, Vector maxs, int count);
extern void UTIL_BubbleTrail(Vector from, Vector to, int count);
extern void UTIL_PrecacheOther(const char *szClassname);
extern void UTIL_ClientPrintAll(int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL);
extern void UTIL_StringToRandomVector( float *pVector, const char *pString ); //sohl caonimabi
extern BOOL UTIL_IsFacing( entvars_t *pevTest, const Vector &reference ); //sohl caonimabi
inline float UTIL_Lerp( float lerpfactor, float A, float B ) { return A + lerpfactor*(B-A); } //sohl da sb
inline void UTIL_CenterPrintAll(const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL)
{
	UTIL_ClientPrintAll(HUD_PRINTCENTER, msg_name, param1, param2, param3, param4);
}

class CBasePlayerItem;
class CBasePlayer;

extern BOOL UTIL_GetNextBestWeapon(CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon);
extern void ClientPrint(entvars_t *client, int msg_dest, const char *msg_name, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL, const char *param4 = NULL);
extern void UTIL_SayText(const char *pText, CBaseEntity *pEntity);
extern void UTIL_SayTextAll(const char *pText, CBaseEntity *pEntity);
extern void UTIL_PlayWAV(CBasePlayer *pEntity, const char *szWAV);
extern void UTIL_PlayMP3(CBasePlayer *pEntity, const char *szMP3);
extern void UTIL_PlayTeamMP3(int iTeam, const char *szMP3);
extern void UTIL_PlayTeamWAV(int iTeam, const char *szWAV);

typedef struct hudtextparms_s
{
	float x;
	float y;
	int effect;
	byte r1, g1, b1, a1;
	byte r2, g2, b2, a2;
	float fadeinTime;
	float fadeoutTime;
	float holdTime;
	float fxTime;
	int channel;
}
hudtextparms_t;

extern void UTIL_HudMessageAll(const hudtextparms_t &textparms, const char *pMessage);
extern void UTIL_HudMessage(CBaseEntity *pEntity, const hudtextparms_t &textparms, const char *pMessage);

extern char *UTIL_dtos1(int d);
extern char *UTIL_dtos2(int d);
extern char *UTIL_dtos3(int d);
extern char *UTIL_dtos4(int d);

extern void UTIL_LogPrintf(char *fmt, ...);
extern float UTIL_DotPoints(const Vector &vecSrc, const Vector &vecCheck, const Vector &vecDir);
extern void UTIL_StripToken(const char *pKey, char *pDest);
extern char UTIL_TextureHit(TraceResult *ptrHit, Vector vecSrc, Vector vecEnd);

extern void SetMovedir(entvars_t *pev);
extern Vector GetMovedir( Vector vecAngles );//sohl added
extern Vector VecBModelOrigin(entvars_t *pevBModel);
extern int BuildChangeList(LEVELLIST *pLevelList, int maxList);

extern DLL_GLOBAL const Vector g_vecZero;

#define LANGUAGE_ENGLISH 0
#define LANGUAGE_GERMAN 1
#define LANGUAGE_FRENCH 2
#define LANGUAGE_BRITISH 3

extern DLL_GLOBAL int g_Language;

#define AMBIENT_SOUND_STATIC 0
#define AMBIENT_SOUND_EVERYWHERE 1
#define AMBIENT_SOUND_SMALLRADIUS 2
#define AMBIENT_SOUND_MEDIUMRADIUS 4
#define AMBIENT_SOUND_LARGERADIUS 8
#define AMBIENT_SOUND_START_SILENT 16
#define AMBIENT_SOUND_NOT_LOOPING 32

#define SPEAKER_START_SILENT 1

#define SND_SPAWNING (1<<8)
#define SND_STOP (1<<5)
#define SND_CHANGE_VOL (1<<6)
#define SND_CHANGE_PITCH (1<<7)

#define LFO_SQUARE 1
#define LFO_TRIANGLE 2
#define LFO_RANDOM 3

#define SF_BRUSH_ROTATE_Y_AXIS 0
#define SF_BRUSH_ROTATE_INSTANT 1
#define SF_BRUSH_ROTATE_BACKWARDS 2
#define SF_BRUSH_ROTATE_Z_AXIS 4
#define SF_BRUSH_ROTATE_X_AXIS 8
#define SF_PENDULUM_AUTO_RETURN 16
#define SF_PENDULUM_PASSABLE 32

#define SF_BRUSH_ROTATE_SMALLRADIUS	128
#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256
#define SF_BRUSH_ROTATE_LARGERADIUS 512

#define PUSH_BLOCK_ONLY_X 1
#define PUSH_BLOCK_ONLY_Y 2

#define VEC_HULL_MIN Vector(-16, -16, -36)
#define VEC_HULL_MAX Vector(16, 16, 36)
#define VEC_HUMAN_HULL_MIN Vector(-16, -16, 0)
#define VEC_HUMAN_HULL_MAX Vector(16, 16, 72)
#define VEC_HUMAN_HULL_DUCK Vector(16, 16, 36)

//#define VEC_VIEW Vector(0, 0, 17)
#define VEC_VIEW_SCOUT Vector(0, 0, 17)
#define VEC_VIEW_HEAVY Vector(0, 0, 17)
#define VEC_VIEW_SOLDIER Vector(0, 0, 17)
#define VEC_VIEW_PYRO Vector(0, 0, 18)
#define VEC_VIEW_SNIPER Vector(0, 0, 19)
#define VEC_VIEW_MEDIC Vector(0, 0, 21)
#define VEC_VIEW_ENGINEER Vector(0, 0, 17)
#define VEC_VIEW_DEMOMAN Vector(0, 0, 19)
#define VEC_VIEW_SPY Vector(0, 0, 19)

#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18)
#define VEC_DUCK_HULL_MAX Vector(16, 16, 32)
#define VEC_DUCK_VIEW Vector(0, 0, 12)

#define SVC_TEMPENTITY 23
#define SVC_INTERMISSION 30
#define SVC_CDTRACK 32
#define SVC_WEAPONANIM 35
#define SVC_ROOMTYPE 37
#define SVC_DIRECTOR 51

#define SF_TRIGGER_ALLOWMONSTERS 1
#define SF_TRIGGER_NOCLIENTS 2
#define SF_TRIGGER_PUSHABLES 4

#define SF_BREAK_TRIGGER_ONLY 1
#define SF_BREAK_TOUCH 2
#define SF_BREAK_PRESSURE 4
#define SF_BREAK_CROWBAR 256

#define SF_PUSH_BREAKABLE 128

#define SF_LIGHT_START_OFF 1

#define SPAWNFLAG_NOMESSAGE 1
#define SPAWNFLAG_NOTOUCH 1
#define SPAWNFLAG_DROIDONLY 4

#define SPAWNFLAG_USEONLY 1

#define TELE_PLAYER_ONLY 1
#define TELE_SILENT 2

#define SF_TRIG_PUSH_ONCE 1

#define CBSENTENCENAME_MAX 16
#define CVOXFILESENTENCEMAX 1536

extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX];
extern int gcallsentences;

int USENTENCEG_Pick(int isentenceg, char *szfound);
int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset);
void USENTENCEG_InitLRU(unsigned char *plru, int count);

void SENTENCEG_Init(void);
void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick);
int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlayRndSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch);
int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szrootname, float volume, float attenuation, int flags, int pitch, int ipick, int freset);
int SENTENCEG_GetIndex(const char *szrootname);
int SENTENCEG_Lookup(const char *sample, char *sentencenum);

void TEXTURETYPE_Init(void);
char TEXTURETYPE_Find(char *name);
float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int iBulletType);

void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch);

inline void EMIT_SOUND(edict_t *entity, int channel, const char *sample, float volume, float attenuation)
{
	EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM);
}

inline void STOP_SOUND(edict_t *entity, int channel, const char *sample)
{
	EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM);
}

void EMIT_SOUND_SUIT(edict_t *entity, const char *sample);
void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg);
void EMIT_GROUPNAME_SUIT(edict_t *entity, const char *groupname);

#define PRECACHE_SOUND_ARRAY(a) \
	{ for (int i = 0; i < (int)(ARRAYSIZE(a)); i++) PRECACHE_SOUND((char *) a [i]); }

#define EMIT_SOUND_ARRAY_DYN(chan, array) \
	EMIT_SOUND_DYN(ENT(pev), chan, array[RANDOM_LONG(0,A RRAYSIZE(array) - 1)], 1, ATTN_NORM, 0, RANDOM_LONG(95, 105));

#define RANDOM_SOUND_ARRAY(array) (array)[RANDOM_LONG(0, ARRAYSIZE((array)) - 1)]

#define PLAYBACK_EVENT(flags, who, index) PLAYBACK_EVENT_FULL(flags, who, index, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0);
#define PLAYBACK_EVENT_DELAY(flags, who, index, delay) PLAYBACK_EVENT_FULL(flags, who, index, delay, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0);

#define GROUP_OP_AND 0
#define GROUP_OP_NAND 1

extern int g_groupmask;
extern int g_groupop;

class UTIL_GroupTrace
{
public:
	UTIL_GroupTrace(int groupmask, int op);
	~UTIL_GroupTrace(void);

private:
	int m_oldgroupmask, m_oldgroupop;
};

void UTIL_SetGroupTrace(int groupmask, int op);
void UTIL_UnsetGroupTrace(void);

int UTIL_SharedRandomLong(unsigned int seed, int low, int high);
float UTIL_SharedRandomFloat(unsigned int seed, float low, float high);

float UTIL_WeaponTimeBase(void);

extern BOOL UTIL_IsHullDefault(Vector vecOrigin, const float BOUNDS, edict_t *pEnt);

#endif