607 lines
23 KiB
C++
607 lines
23 KiB
C++
//========= Copyright 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 "cmodel.h"
|
|
#include "engine/IEngineTrace.h"
|
|
#include "engine/IStaticPropMgr.h"
|
|
#include "mathlib/vector.h"
|
|
#include "networkvar.h"
|
|
#include "shared_classnames.h"
|
|
#include "utlvector.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);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// 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
|
|
if (staticpropmgr->IsStaticProp(pHandleEntity)) return NULL;
|
|
|
|
IServerUnknown *pUnk = (IServerUnknown *)pHandleEntity;
|
|
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; }
|
|
|
|
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,
|
|
const IHandleEntity *passentity2,
|
|
int collisionGroup);
|
|
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);
|
|
|
|
protected:
|
|
CUtlVector<IHandleEntity *> m_PassEntities;
|
|
};
|
|
|
|
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,
|
|
int collisionGroup)
|
|
: 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;
|
|
|
|
inline void UTIL_TraceLine(const Vector &vecAbsStart, const Vector &vecAbsEnd,
|
|
unsigned int mask, const IHandleEntity *ignore,
|
|
int collisionGroup, trace_t *ptr) {
|
|
Ray_t ray;
|
|
ray.Init(vecAbsStart, vecAbsEnd);
|
|
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_TraceLine(const Vector &vecAbsStart, const Vector &vecAbsEnd,
|
|
unsigned int mask, ITraceFilter *pFilter,
|
|
trace_t *ptr) {
|
|
Ray_t ray;
|
|
ray.Init(vecAbsStart, vecAbsEnd);
|
|
|
|
enginetrace->TraceRay(ray, mask, pFilter, ptr);
|
|
|
|
if (r_visualizetraces.GetBool()) {
|
|
DebugDrawLine(ptr->startpos, ptr->endpos, 255, 0, 0, true, -1.0f);
|
|
}
|
|
}
|
|
|
|
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) {
|
|
Ray_t ray;
|
|
ray.Init(vecAbsStart, vecAbsEnd, hullMin, hullMax);
|
|
CTraceFilterSimple traceFilter(ignore, collisionGroup);
|
|
|
|
enginetrace->TraceRay(ray, mask, &traceFilter, ptr);
|
|
|
|
if (r_visualizetraces.GetBool()) {
|
|
DebugDrawLine(ptr->startpos, ptr->endpos, 255, 255, 0, true, -1.0f);
|
|
}
|
|
}
|
|
|
|
inline void UTIL_TraceHull(const Vector &vecAbsStart, const Vector &vecAbsEnd,
|
|
const Vector &hullMin, const Vector &hullMax,
|
|
unsigned int mask, ITraceFilter *pFilter,
|
|
trace_t *ptr) {
|
|
Ray_t ray;
|
|
ray.Init(vecAbsStart, vecAbsEnd, hullMin, hullMax);
|
|
|
|
enginetrace->TraceRay(ray, mask, pFilter, ptr);
|
|
|
|
if (r_visualizetraces.GetBool()) {
|
|
DebugDrawLine(ptr->startpos, ptr->endpos, 255, 255, 0, true, -1.0f);
|
|
}
|
|
}
|
|
|
|
inline void UTIL_TraceRay(const Ray_t &ray, unsigned int mask,
|
|
const IHandleEntity *ignore, int collisionGroup,
|
|
trace_t *ptr,
|
|
ShouldHitFunc_t pExtraShouldHitCheckFn = NULL) {
|
|
CTraceFilterSimple traceFilter(ignore, collisionGroup,
|
|
pExtraShouldHitCheckFn);
|
|
|
|
enginetrace->TraceRay(ray, mask, &traceFilter, 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) {
|
|
return enginetrace->GetPointContents(vec);
|
|
}
|
|
|
|
// 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);
|
|
|
|
void UTIL_StringToVector(float *pVector, const char *pString);
|
|
void UTIL_StringToIntArray(int *pVector, int count, const char *pString);
|
|
void UTIL_StringToFloatArray(float *pVector, int count, const char *pString);
|
|
void UTIL_StringToColor32(color32 *color, const char *pString);
|
|
|
|
CBasePlayer *UTIL_PlayerByIndex(int entindex);
|
|
|
|
//=============================================================================
|
|
// HPE_BEGIN:
|
|
// [menglish] Added UTIL function for events in client win_panel which transmit
|
|
// the player as a user ID
|
|
//=============================================================================
|
|
CBasePlayer *UTIL_PlayerByUserId(int userID);
|
|
//=============================================================================
|
|
// HPE_END
|
|
//=============================================================================
|
|
|
|
// decodes a buffer using a 64bit ICE key (inplace)
|
|
void UTIL_DecodeICE(unsigned char *buffer, int size, const unsigned char *key);
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
/**
|
|
* 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(); \
|
|
static void AddToAutoList(interfaceName *pElement) { \
|
|
m_##interfaceName##AutoList.AddToTail(pElement); \
|
|
} \
|
|
static void RemoveFromAutoList(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 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) { \
|
|
AddToAutoList(this); \
|
|
} \
|
|
} \
|
|
interfaceName::~interfaceName() { RemoveFromAutoList(this); }
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
// This would do the same thing without requiring casts all over the place. Yes,
|
|
// it's a template, but DECLARE_AUTO_LIST requires a CUtlVector<T> anyway. TODO
|
|
// ask about replacing the macros with this.
|
|
// template<class T>
|
|
// class AutoList {
|
|
// public:
|
|
// typedef CUtlVector<T*> AutoListType;
|
|
// static AutoListType& All() { return m_autolist; }
|
|
// protected:
|
|
// AutoList() { m_autolist.AddToTail(static_cast<T*>(this)); }
|
|
// virtual ~AutoList() {
|
|
//m_autolist.FindAndFastRemove(static_cast<T*>(this)); } private: static
|
|
//AutoListType m_autolist;
|
|
//};
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
/**
|
|
* 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:
|
|
IntervalTimer(void) { m_timestamp = -1.0f; }
|
|
|
|
void Reset(void) { m_timestamp = Now(); }
|
|
|
|
void Start(void) { m_timestamp = Now(); }
|
|
|
|
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;
|
|
}
|
|
|
|
private:
|
|
float m_timestamp;
|
|
float Now(void) const; // work-around since client header doesn't like
|
|
// inlined gpGlobals->curtime
|
|
};
|
|
|
|
//--------------------------------------------------------------------------------------------------------------
|
|
/**
|
|
* 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:
|
|
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 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()); }
|
|
|
|
/// return original countdown time
|
|
float GetCountdownDuration(void) const {
|
|
return (m_timestamp > 0.0f) ? m_duration : 0.0f;
|
|
}
|
|
|
|
private:
|
|
float m_duration;
|
|
float m_timestamp;
|
|
virtual float Now(void) const; // work-around since client header doesn't
|
|
// like inlined gpGlobals->curtime
|
|
};
|
|
|
|
class RealTimeCountdownTimer : public CountdownTimer {
|
|
virtual float Now(void) const OVERRIDE { return Plat_FloatTime(); }
|
|
};
|
|
|
|
char *ReadAndAllocStringValue(KeyValues *pSub, const char *pName,
|
|
const char *pFilename = NULL);
|
|
|
|
int UTIL_StringFieldToInt(const char *szValue, const char **pValueStrings,
|
|
int iNumStrings);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Holidays
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Used at level change and round start to re-calculate which holiday is active
|
|
void UTIL_CalculateHolidays();
|
|
|
|
bool UTIL_IsHolidayActive(/*EHoliday*/ int eHoliday);
|
|
/*EHoliday*/ int UTIL_GetHolidayForString(const char *pszHolidayName);
|
|
|
|
// This will return the first active holiday string it can find. In the case of
|
|
// multiple holidays overlapping, the list order will act as priority.
|
|
const char *UTIL_GetActiveHolidayString();
|
|
|
|
#endif // UTIL_SHARED_H
|