2022-12-17 13:32:43 +01:00
|
|
|
/***
|
2013-08-30 13:34:05 -07:00
|
|
|
*
|
|
|
|
* Copyright (c) 1996-2001, Valve LLC. All rights reserved.
|
|
|
|
*
|
|
|
|
* This product contains software technology licensed from Id
|
|
|
|
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
|
|
|
|
* All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Use, distribution, and modification of this source code and/or resulting
|
|
|
|
* object code is restricted to non-commercial enhancements to products from
|
|
|
|
* Valve LLC. All other use, distribution, or modification is prohibited
|
|
|
|
* without written permission from Valve LLC.
|
|
|
|
*
|
|
|
|
****/
|
2021-11-18 19:48:34 +01:00
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2021-11-18 20:33:58 +01:00
|
|
|
#include "Platform.h"
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// Misc utility code
|
|
|
|
//
|
|
|
|
#include "activity.h"
|
|
|
|
#include "enginecallback.h"
|
2021-11-18 18:59:23 +01:00
|
|
|
|
2022-10-07 16:31:04 +02:00
|
|
|
class CBaseEntity;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline void MESSAGE_BEGIN(int msg_dest, int msg_type, const float* pOrigin, entvars_t* ent); // implementation later in this file
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 20:40:56 +01:00
|
|
|
inline globalvars_t* gpGlobals = nullptr;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Use this instead of ALLOC_STRING on constant strings
|
2021-11-28 16:54:48 +01:00
|
|
|
#define STRING(offset) ((const char*)(gpGlobals->pStringBase + (unsigned int)(offset)))
|
|
|
|
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline edict_t* FIND_ENTITY_BY_CLASSNAME(edict_t* entStart, const char* pszName)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
return FIND_ENTITY_BY_STRING(entStart, "classname", pszName);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline edict_t* FIND_ENTITY_BY_TARGETNAME(edict_t* entStart, const char* pszName)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
return FIND_ENTITY_BY_STRING(entStart, "targetname", pszName);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// for doing a reverse lookup. Say you have a door, and want to find its button.
|
2021-11-28 16:54:48 +01:00
|
|
|
inline edict_t* FIND_ENTITY_BY_TARGET(edict_t* entStart, const char* pszName)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
return FIND_ENTITY_BY_STRING(entStart, "target", pszName);
|
2021-11-28 16:54:48 +01:00
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Keeps clutter down a bit, when writing key-value pairs
|
|
|
|
#define WRITEKEY_INT(pf, szKeyName, iKeyValue) ENGINE_FPRINTF(pf, "\"%s\" \"%d\"\n", szKeyName, iKeyValue)
|
2021-11-28 16:54:48 +01:00
|
|
|
#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)
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Keeps clutter down a bit, when using a float as a bit-vector
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SetBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) | (bits))
|
|
|
|
#define ClearBits(flBitVector, bits) ((flBitVector) = (int)(flBitVector) & ~(bits))
|
|
|
|
#define FBitSet(flBitVector, bit) (((int)(flBitVector) & (bit)) != 0)
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Makes these more explicit, and easier to find
|
|
|
|
#define FILE_GLOBAL static
|
|
|
|
#define DLL_GLOBAL
|
|
|
|
|
|
|
|
// Until we figure out why "const" gives the compiler problems, we'll just have to use
|
|
|
|
// this bogus "empty" define to mark things as constant.
|
|
|
|
#define CONSTANT
|
|
|
|
|
|
|
|
// More explicit than "int"
|
|
|
|
typedef int EOFFSET;
|
|
|
|
|
|
|
|
// In case this ever changes
|
2021-11-28 16:54:48 +01:00
|
|
|
#define M_PI 3.14159265358979323846
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Keeps clutter down a bit, when declaring external entity/global method prototypes
|
2021-11-28 16:54:48 +01:00
|
|
|
#define DECLARE_GLOBAL_METHOD(MethodName) extern void DLLEXPORT MethodName()
|
|
|
|
#define GLOBAL_METHOD(funcname) void DLLEXPORT funcname()
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// This is the glue that hooks .MAP entity class names to our CPP classes
|
|
|
|
// The _declspec forces them to be exported by name so we can do a lookup with GetProcAddress()
|
|
|
|
// The function is used to intialize / allocate the object for the entity
|
2021-11-28 16:54:48 +01:00
|
|
|
#define LINK_ENTITY_TO_CLASS(mapClassName, DLLClassName) \
|
|
|
|
extern "C" DLLEXPORT void mapClassName(entvars_t* pev); \
|
|
|
|
void mapClassName(entvars_t* pev) { GetClassPtr((DLLClassName*)pev); }
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2022-10-07 16:31:04 +02:00
|
|
|
/**
|
|
|
|
* @brief Gets the list of entities.
|
|
|
|
* Will return @c nullptr if there is no map loaded.
|
|
|
|
*/
|
|
|
|
edict_t* UTIL_GetEntityList();
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Gets the local player in singleplayer, or @c nullptr in multiplayer.
|
|
|
|
*/
|
|
|
|
CBaseEntity* UTIL_GetLocalPlayer();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// Conversion among the three types of "entity", including identity-conversions.
|
|
|
|
//
|
|
|
|
#ifdef DEBUG
|
2021-11-28 16:54:48 +01:00
|
|
|
extern edict_t* DBG_EntOfVars(const entvars_t* pev);
|
|
|
|
inline edict_t* ENT(const entvars_t* pev) { return DBG_EntOfVars(pev); }
|
2013-08-30 13:34:05 -07:00
|
|
|
#else
|
2021-11-28 16:54:48 +01:00
|
|
|
inline edict_t* ENT(const entvars_t* pev)
|
|
|
|
{
|
|
|
|
return pev->pContainingEntity;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
#endif
|
2021-11-28 16:54:48 +01:00
|
|
|
inline edict_t* ENT(edict_t* pent)
|
|
|
|
{
|
|
|
|
return pent;
|
|
|
|
}
|
|
|
|
inline edict_t* ENT(EOFFSET eoffset) { return (*g_engfuncs.pfnPEntityOfEntOffset)(eoffset); }
|
|
|
|
inline EOFFSET OFFSET(const edict_t* pent)
|
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
#if _DEBUG
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pent)
|
|
|
|
ALERT(at_error, "Bad ent in OFFSET()\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
#endif
|
2021-11-28 16:54:48 +01:00
|
|
|
return (*g_engfuncs.pfnEntOffsetOfPEntity)(pent);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
2021-11-28 16:54:48 +01:00
|
|
|
inline EOFFSET OFFSET(entvars_t* pev)
|
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
#if _DEBUG
|
2021-11-28 16:54:48 +01:00
|
|
|
if (!pev)
|
|
|
|
ALERT(at_error, "Bad pev in OFFSET()\n");
|
2013-08-30 13:34:05 -07:00
|
|
|
#endif
|
2021-11-28 16:54:48 +01:00
|
|
|
return OFFSET(ENT(pev));
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline entvars_t* VARS(edict_t* pent)
|
|
|
|
{
|
|
|
|
if (!pent)
|
2013-08-30 13:34:05 -07:00
|
|
|
return NULL;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
return &pent->v;
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
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)
|
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
(*g_engfuncs.pfnMessageBegin)(msg_dest, msg_type, pOrigin, ENT(ent));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Testing the three types of "entity" for nullity
|
|
|
|
#define eoNullEntity 0
|
2021-11-28 16:54:48 +01:00
|
|
|
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)); }
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Testing strings for nullity
|
|
|
|
#define iStringNull 0
|
2021-11-28 16:54:48 +01:00
|
|
|
inline bool FStringNull(int iString)
|
|
|
|
{
|
|
|
|
return iString == iStringNull;
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
#define cchMapNameMost 32
|
|
|
|
|
|
|
|
// Dot products for view cone checking
|
2021-11-28 16:54:48 +01:00
|
|
|
#define VIEW_FIELD_FULL (float)-1.0 // +-180 degrees
|
|
|
|
#define VIEW_FIELD_WIDE (float)-0.7 // +-135 degrees 0.1 // +-85 degrees, used for full FOV checks
|
|
|
|
#define VIEW_FIELD_NARROW (float)0.7 // +-45 degrees, more narrow check used to set up ranged attacks
|
|
|
|
#define VIEW_FIELD_ULTRA_NARROW (float)0.9 // +-25 degrees, more narrow check used to set up ranged attacks
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// All monsters need this data
|
2021-11-28 16:54:48 +01:00
|
|
|
#define DONT_BLEED -1
|
|
|
|
#define BLOOD_COLOR_RED (byte)247
|
|
|
|
#define BLOOD_COLOR_YELLOW (byte)195
|
|
|
|
#define BLOOD_COLOR_GREEN BLOOD_COLOR_YELLOW
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
typedef enum
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
|
|
|
|
MONSTERSTATE_NONE = 0,
|
|
|
|
MONSTERSTATE_IDLE,
|
|
|
|
MONSTERSTATE_COMBAT,
|
|
|
|
MONSTERSTATE_ALERT,
|
|
|
|
MONSTERSTATE_HUNT,
|
|
|
|
MONSTERSTATE_PRONE,
|
|
|
|
MONSTERSTATE_SCRIPT,
|
|
|
|
MONSTERSTATE_PLAYDEAD,
|
|
|
|
MONSTERSTATE_DEAD
|
|
|
|
|
|
|
|
} MONSTERSTATE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Things that toggle (buttons/triggers/doors) need this
|
|
|
|
typedef enum
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
2013-08-30 13:34:05 -07:00
|
|
|
TS_AT_TOP,
|
|
|
|
TS_AT_BOTTOM,
|
|
|
|
TS_GOING_UP,
|
|
|
|
TS_GOING_DOWN
|
2021-11-28 16:54:48 +01:00
|
|
|
} TOGGLE_STATE;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Misc useful
|
2021-11-28 16:54:48 +01:00
|
|
|
inline bool FStrEq(const char* sz1, const char* sz2)
|
|
|
|
{
|
|
|
|
return (strcmp(sz1, sz2) == 0);
|
|
|
|
}
|
2021-11-19 14:31:11 +01:00
|
|
|
inline bool FClassnameIs(edict_t* pent, const char* szClassname)
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
return FStrEq(STRING(VARS(pent)->classname), szClassname);
|
|
|
|
}
|
2021-11-19 14:31:11 +01:00
|
|
|
inline bool FClassnameIs(entvars_t* pev, const char* szClassname)
|
2021-11-28 16:54:48 +01:00
|
|
|
{
|
|
|
|
return FStrEq(STRING(pev->classname), szClassname);
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Misc. Prototypes
|
2021-11-28 16:54:48 +01:00
|
|
|
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_FindEntityGeneric(const char* szName, Vector& vecSrc, float flRadius);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// returns a CBaseEntity pointer to a player by index. Only returns if the player is spawned and connected
|
|
|
|
// otherwise returns NULL
|
|
|
|
// Index is 1 based
|
2021-11-28 16:54:48 +01:00
|
|
|
extern CBaseEntity* UTIL_PlayerByIndex(int playerIndex);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define UTIL_EntitiesInPVS(pent) (*g_engfuncs.pfnEntitiesInPVS)(pent)
|
|
|
|
extern void UTIL_MakeVectors(const Vector& vecAngles);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Pass in an array of pointers and an array size, it fills the array and returns the number inserted
|
2021-11-28 16:54:48 +01:00
|
|
|
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);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline void UTIL_MakeVectorsPrivate(const Vector& vecAngles, float* p_vForward, float* p_vRight, float* p_vUp)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
g_engfuncs.pfnAngleVectors(vecAngles, p_vForward, p_vRight, p_vUp);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
extern void UTIL_MakeAimVectors(const Vector& vecAngles); // like MakeVectors, but assumes pitch isn't inverted
|
|
|
|
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, unsigned int ulColor, unsigned int ulCount);
|
|
|
|
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);
|
|
|
|
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();
|
|
|
|
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 bool 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();
|
|
|
|
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(const 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);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Use for ease-in, ease-out style interpolation (accel/decel)
|
2021-11-28 16:54:48 +01:00
|
|
|
extern float UTIL_SplineFraction(float value, float scale);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Search for water transition along a vertical line
|
2021-11-28 16:54:48 +01:00
|
|
|
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);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// allows precacheing of other entities
|
2021-11-28 16:54:48 +01:00
|
|
|
extern void UTIL_PrecacheOther(const char* szClassname);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// prints a message to each client
|
2021-11-28 16:54:48 +01:00
|
|
|
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);
|
|
|
|
inline void UTIL_CenterPrintAll(const char* msg_name, const char* param1 = NULL, const char* param2 = NULL, const char* param3 = NULL, const char* param4 = NULL)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_ClientPrintAll(HUD_PRINTCENTER, msg_name, param1, param2, param3, param4);
|
2013-08-30 13:34:05 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
class CBasePlayerItem;
|
|
|
|
class CBasePlayer;
|
|
|
|
|
|
|
|
// prints messages through the HUD
|
2021-11-28 16:54:48 +01:00
|
|
|
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);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// prints a message to the HUD say (chat)
|
2021-11-28 16:54:48 +01:00
|
|
|
extern void UTIL_SayText(const char* pText, CBaseEntity* pEntity);
|
|
|
|
extern void UTIL_SayTextAll(const char* pText, CBaseEntity* pEntity);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
typedef struct hudtextparms_s
|
|
|
|
{
|
2021-11-28 16:54:48 +01:00
|
|
|
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;
|
2013-08-30 13:34:05 -07:00
|
|
|
} hudtextparms_t;
|
|
|
|
|
|
|
|
// prints as transparent 'title' to the HUD
|
2021-11-28 16:54:48 +01:00
|
|
|
extern void UTIL_HudMessageAll(const hudtextparms_t& textparms, const char* pMessage);
|
|
|
|
extern void UTIL_HudMessage(CBaseEntity* pEntity, const hudtextparms_t& textparms, const char* pMessage);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// for handy use with ClientPrint params
|
2021-11-28 16:54:48 +01:00
|
|
|
extern char* UTIL_dtos1(int d);
|
|
|
|
extern char* UTIL_dtos2(int d);
|
|
|
|
extern char* UTIL_dtos3(int d);
|
|
|
|
extern char* UTIL_dtos4(int d);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Writes message to console with timestamp and FragLog header.
|
2021-11-28 16:54:48 +01:00
|
|
|
extern void UTIL_LogPrintf(const char* fmt, ...);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
// Sorta like FInViewCone, but for nonmonsters.
|
|
|
|
extern float UTIL_DotPoints(const Vector& vecSrc, const Vector& vecCheck, const Vector& vecDir);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2024-08-27 23:57:48 +02:00
|
|
|
extern void UTIL_StripToken(const char* pKey, char* pDest, int nLen); // for redundant keynames
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// Misc functions
|
|
|
|
extern void SetMovedir(entvars_t* pev);
|
2021-11-28 16:54:48 +01:00
|
|
|
extern Vector VecBModelOrigin(entvars_t* pevBModel);
|
|
|
|
extern int BuildChangeList(LEVELLIST* pLevelList, int maxList);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// How did I ever live without ASSERT?
|
|
|
|
//
|
2021-11-28 16:54:48 +01:00
|
|
|
#ifdef DEBUG
|
2021-11-19 14:31:11 +01:00
|
|
|
void DBG_AssertFunction(bool fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage);
|
2021-11-28 16:54:48 +01:00
|
|
|
#define ASSERT(f) DBG_AssertFunction(f, #f, __FILE__, __LINE__, NULL)
|
|
|
|
#define ASSERTSZ(f, sz) DBG_AssertFunction(f, #f, __FILE__, __LINE__, sz)
|
|
|
|
#else // !DEBUG
|
2013-08-30 13:34:05 -07:00
|
|
|
#define ASSERT(f)
|
|
|
|
#define ASSERTSZ(f, sz)
|
2021-11-28 16:54:48 +01:00
|
|
|
#endif // !DEBUG
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
//
|
|
|
|
// Constants that were used only by QC (maybe not used at all now)
|
|
|
|
//
|
|
|
|
// Un-comment only as needed
|
|
|
|
//
|
2021-11-28 16:54:48 +01:00
|
|
|
#define LANGUAGE_ENGLISH 0
|
|
|
|
#define LANGUAGE_GERMAN 1
|
|
|
|
#define LANGUAGE_FRENCH 2
|
|
|
|
#define LANGUAGE_BRITISH 3
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 20:40:56 +01:00
|
|
|
inline DLL_GLOBAL int g_Language;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define AMBIENT_SOUND_STATIC 0 // medium radius attenuation
|
|
|
|
#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
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SPEAKER_START_SILENT 1 // wait for trigger 'on' to start announcements
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SND_SPAWNING (1 << 8) // duplicated in protocol.h we're spawing, used in some cases for ambients
|
|
|
|
#define SND_STOP (1 << 5) // duplicated in protocol.h stop sound
|
|
|
|
#define SND_CHANGE_VOL (1 << 6) // duplicated in protocol.h change sound vol
|
|
|
|
#define SND_CHANGE_PITCH (1 << 7) // duplicated in protocol.h change sound pitch
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define LFO_SQUARE 1
|
|
|
|
#define LFO_TRIANGLE 2
|
|
|
|
#define LFO_RANDOM 3
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// func_rotating
|
2021-11-28 16:54:48 +01:00
|
|
|
#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
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_BRUSH_ROTATE_SMALLRADIUS 128
|
2013-08-30 13:34:05 -07:00
|
|
|
#define SF_BRUSH_ROTATE_MEDIUMRADIUS 256
|
|
|
|
#define SF_BRUSH_ROTATE_LARGERADIUS 512
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define PUSH_BLOCK_ONLY_X 1
|
|
|
|
#define PUSH_BLOCK_ONLY_Y 2
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SVC_TEMPENTITY 23
|
|
|
|
#define SVC_INTERMISSION 30
|
|
|
|
#define SVC_CDTRACK 32
|
|
|
|
#define SVC_WEAPONANIM 35
|
|
|
|
#define SVC_ROOMTYPE 37
|
|
|
|
#define SVC_DIRECTOR 51
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// triggers
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_TRIGGER_ALLOWMONSTERS 1 // monsters allowed to fire this trigger
|
|
|
|
#define SF_TRIGGER_NOCLIENTS 2 // players not allowed to fire this trigger
|
|
|
|
#define SF_TRIGGER_PUSHABLES 4 // only pushables can fire this trigger
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// func breakable
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_BREAK_TRIGGER_ONLY 1 // may only be broken by trigger
|
|
|
|
#define SF_BREAK_TOUCH 2 // can be 'crashed through' by running player (plate glass)
|
|
|
|
#define SF_BREAK_PRESSURE 4 // can be broken by a player standing on it
|
|
|
|
#define SF_BREAK_CROWBAR 256 // instant break if hit with crowbar
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// func_pushable (it's also func_breakable, so don't collide with those flags)
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_PUSH_BREAKABLE 128
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_LIGHT_START_OFF 1
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SPAWNFLAG_NOMESSAGE 1
|
|
|
|
#define SPAWNFLAG_NOTOUCH 1
|
|
|
|
#define SPAWNFLAG_DROIDONLY 4
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SPAWNFLAG_USEONLY 1 // can't be touched, must be used (buttons)
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define TELE_PLAYER_ONLY 1
|
|
|
|
#define TELE_SILENT 2
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define SF_TRIG_PUSH_ONCE 1
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
|
|
|
// Sound Utilities
|
|
|
|
|
|
|
|
// sentence groups
|
|
|
|
#define CBSENTENCENAME_MAX 16
|
2024-08-28 08:59:21 +02:00
|
|
|
#define CVOXFILESENTENCEMAX 2048 // max number of sentences in game. NOTE: this must match \
|
2021-11-28 16:54:48 +01:00
|
|
|
// CVOXFILESENTENCEMAX in engine\sound.h!!!
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
extern char gszallsentencenames[CVOXFILESENTENCEMAX][CBSENTENCENAME_MAX];
|
|
|
|
extern int gcallsentences;
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int USENTENCEG_Pick(int isentenceg, char* szfound);
|
|
|
|
int USENTENCEG_PickSequential(int isentenceg, char* szfound, int ipick, bool freset);
|
|
|
|
void USENTENCEG_InitLRU(unsigned char* plru, int count);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
void SENTENCEG_Init();
|
2021-11-28 16:54:48 +01:00
|
|
|
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, bool freset);
|
|
|
|
int SENTENCEG_GetIndex(const char* szrootname);
|
|
|
|
int SENTENCEG_Lookup(const char* sample, char* sentencenum);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
void TEXTURETYPE_Init();
|
2021-11-28 16:54:48 +01:00
|
|
|
char TEXTURETYPE_Find(char* name);
|
|
|
|
float TEXTURETYPE_PlaySound(TraceResult* ptr, Vector vecSrc, Vector vecEnd, int iBulletType);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
// NOTE: use EMIT_SOUND_DYN to set the pitch of a sound. Pitch of 100
|
|
|
|
// is no pitch shift. Pitch > 100 up to 255 is a higher pitch, pitch < 100
|
|
|
|
// down to 1 is a lower pitch. 150 to 70 is the realistic range.
|
|
|
|
// EMIT_SOUND_DYN with pitch != 100 should be used sparingly, as it's not quite as
|
|
|
|
// fast as EMIT_SOUND (the pitchshift mixer is not native coded).
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void EMIT_SOUND_DYN(edict_t* entity, int channel, const char* sample, float volume, float attenuation,
|
|
|
|
int flags, int pitch);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline void EMIT_SOUND(edict_t* entity, int channel, const char* sample, float volume, float attenuation)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
EMIT_SOUND_DYN(entity, channel, sample, volume, attenuation, 0, PITCH_NORM);
|
|
|
|
}
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
inline void STOP_SOUND(edict_t* entity, int channel, const char* sample)
|
2013-08-30 13:34:05 -07:00
|
|
|
{
|
|
|
|
EMIT_SOUND_DYN(entity, channel, sample, 0, 0, SND_STOP, PITCH_NORM);
|
|
|
|
}
|
|
|
|
|
2022-01-24 12:27:27 +01:00
|
|
|
/**
|
|
|
|
* @brief Just like @see EMIT_SOUND_DYN, but will skip the current host player if they have cl_lw turned on.
|
|
|
|
* @details entity must be the current host entity for this to work, and must be called only inside a player's PostThink method.
|
|
|
|
*/
|
|
|
|
void EMIT_SOUND_PREDICTED(edict_t* entity, int channel, const char* sample, float volume, float attenuation,
|
|
|
|
int flags, int pitch);
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
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);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define PRECACHE_SOUND_ARRAY(a) \
|
|
|
|
{ \
|
|
|
|
for (int i = 0; i < ARRAYSIZE(a); i++) \
|
|
|
|
PRECACHE_SOUND((char*)a[i]); \
|
|
|
|
}
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define EMIT_SOUND_ARRAY_DYN(chan, array) \
|
|
|
|
EMIT_SOUND_DYN(ENT(pev), chan, array[RANDOM_LONG(0, ARRAYSIZE(array) - 1)], 1.0, ATTN_NORM, 0, RANDOM_LONG(95, 105));
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define RANDOM_SOUND_ARRAY(array) (array)[RANDOM_LONG(0, ARRAYSIZE((array)) - 1)]
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define PLAYBACK_EVENT(flags, who, index) PLAYBACK_EVENT_FULL(flags, who, index, 0, g_vecZero, 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, g_vecZero, g_vecZero, 0.0, 0.0, 0, 0, 0, 0);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
#define GROUP_OP_AND 0
|
|
|
|
#define GROUP_OP_NAND 1
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 20:40:56 +01:00
|
|
|
inline int g_groupmask = 0;
|
|
|
|
inline int g_groupop = 0;
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
class UTIL_GroupTrace
|
|
|
|
{
|
|
|
|
public:
|
2021-11-28 16:54:48 +01:00
|
|
|
UTIL_GroupTrace(int groupmask, int op);
|
2021-03-05 20:54:33 +01:00
|
|
|
~UTIL_GroupTrace();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
int m_oldgroupmask, m_oldgroupop;
|
|
|
|
};
|
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
void UTIL_SetGroupTrace(int groupmask, int op);
|
2021-03-05 20:54:33 +01:00
|
|
|
void UTIL_UnsetGroupTrace();
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-11-28 16:54:48 +01:00
|
|
|
int UTIL_SharedRandomLong(unsigned int seed, int low, int high);
|
|
|
|
float UTIL_SharedRandomFloat(unsigned int seed, float low, float high);
|
2013-08-30 13:34:05 -07:00
|
|
|
|
2021-03-05 20:54:33 +01:00
|
|
|
float UTIL_WeaponTimeBase();
|
2021-03-16 13:52:59 +01:00
|
|
|
|
|
|
|
CBaseEntity* UTIL_FindEntityForward(CBaseEntity* pMe);
|
2022-01-23 16:02:43 +01:00
|
|
|
|
2022-02-28 21:29:58 +01:00
|
|
|
constexpr bool UTIL_IsServer()
|
2022-01-23 16:02:43 +01:00
|
|
|
{
|
2022-02-28 21:29:58 +01:00
|
|
|
#ifdef CLIENT_DLL
|
2022-01-23 16:02:43 +01:00
|
|
|
return false;
|
|
|
|
#else
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
}
|
2022-03-01 13:55:56 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Helper type to run a function when the helper is destroyed.
|
|
|
|
* Useful for running cleanup on scope exit and function return.
|
|
|
|
*/
|
2022-08-04 12:30:11 +02:00
|
|
|
template <typename Func>
|
2022-03-01 13:55:56 +01:00
|
|
|
struct CallOnDestroy
|
|
|
|
{
|
|
|
|
const Func Function;
|
|
|
|
|
2022-03-03 13:58:58 +01:00
|
|
|
explicit CallOnDestroy(Func&& function)
|
2022-03-01 13:55:56 +01:00
|
|
|
: Function(function)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
~CallOnDestroy()
|
|
|
|
{
|
|
|
|
Function();
|
|
|
|
}
|
|
|
|
};
|