This repository has been archived on 2024-06-13. You can view files and clone it, but cannot push or open issues or pull requests.
2020-08-04 13:13:01 -04:00

2694 lines
97 KiB
C++

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//=============================================================================//
#ifndef BASEENTITY_H
#define BASEENTITY_H
#ifdef _WIN32
#pragma once
#endif
#define TEAMNUM_NUM_BITS 6
#include "ServerNetworkProperty.h"
#include "collisionproperty.h"
#include "engine/ivmodelinfo.h"
#include "entitylist.h"
#include "entityoutput.h"
#include "networkvar.h"
#include "shareddefs.h"
class CDamageModifier;
class CDmgAccumulator;
struct CSoundParameters;
class AI_CriteriaSet;
class IResponseSystem;
class IEntitySaveUtils;
class CRecipientFilter;
class CStudioHdr;
// Matching the high level concept is significantly better than other criteria
// FIXME: Could do this in the script file by making it required and bumping up
// weighting there instead...
#define CONCEPT_WEIGHT 5.0f
typedef CHandle<CBaseEntity> EHANDLE;
#define MANUALMODE_GETSET_PROP(type, accessorName, varName) \
private: \
type varName; \
\
public: \
inline const type &Get##accessorName##() const { return varName; } \
inline type &Get##accessorName##() { return varName; } \
inline void Set##accessorName##(const type &val) { \
varName = val; \
m_NetStateMgr.StateChanged(); \
}
#define MANUALMODE_GETSET_EHANDLE(type, accessorName, varName) \
private: \
CHandle<type> varName; \
\
public: \
inline type *Get##accessorName##() { return varName.Get(); } \
inline void Set##accessorName##(type * pType) { \
varName = pType; \
m_NetStateMgr.StateChanged(); \
}
// saverestore.h declarations
class CSaveRestoreData;
struct typedescription_t;
class ISave;
class IRestore;
class CBaseEntity;
class CEntityMapData;
class CBaseCombatWeapon;
class IPhysicsObject;
class IPhysicsShadowController;
class CBaseCombatCharacter;
class CTeam;
class Vector;
struct gamevcollisionevent_t;
class CBaseAnimating;
class CBasePlayer;
class IServerVehicle;
struct solid_t;
struct notify_system_event_params_t;
class CAI_BaseNPC;
class CAI_Senses;
class CSquadNPC;
class variant_t;
class CEventAction;
typedef struct KeyValueData_s KeyValueData;
class CUserCmd;
class CSkyCamera;
class CEntityMapData;
class INextBot;
class IHasAttributes;
typedef CUtlVector<CBaseEntity *> EntityList_t;
#if defined(HL2_DLL)
// For CLASSIFY
enum Class_T {
CLASS_NONE = 0,
CLASS_PLAYER,
CLASS_PLAYER_ALLY,
CLASS_PLAYER_ALLY_VITAL,
CLASS_ANTLION,
CLASS_BARNACLE,
CLASS_BULLSEYE,
// CLASS_BULLSQUID,
CLASS_CITIZEN_PASSIVE,
CLASS_CITIZEN_REBEL,
CLASS_COMBINE,
CLASS_COMBINE_GUNSHIP,
CLASS_CONSCRIPT,
CLASS_HEADCRAB,
// CLASS_HOUNDEYE,
CLASS_MANHACK,
CLASS_METROPOLICE,
CLASS_MILITARY,
CLASS_SCANNER,
CLASS_STALKER,
CLASS_VORTIGAUNT,
CLASS_ZOMBIE,
CLASS_PROTOSNIPER,
CLASS_MISSILE,
CLASS_FLARE,
CLASS_EARTH_FAUNA,
CLASS_HACKED_ROLLERMINE,
CLASS_COMBINE_HUNTER,
NUM_AI_CLASSES
};
#elif defined(HL1_DLL)
enum Class_T {
CLASS_NONE = 0,
CLASS_MACHINE,
CLASS_PLAYER,
CLASS_HUMAN_PASSIVE,
CLASS_HUMAN_MILITARY,
CLASS_ALIEN_MILITARY,
CLASS_ALIEN_MONSTER,
CLASS_ALIEN_PREY,
CLASS_ALIEN_PREDATOR,
CLASS_INSECT,
CLASS_PLAYER_ALLY,
CLASS_PLAYER_BIOWEAPON,
CLASS_ALIEN_BIOWEAPON,
NUM_AI_CLASSES
};
#elif defined(INVASION_DLL)
enum Class_T {
CLASS_NONE = 0,
CLASS_PLAYER,
CLASS_PLAYER_ALLY,
CLASS_PLAYER_ALLY_VITAL,
CLASS_ANTLION,
CLASS_BARNACLE,
CLASS_BULLSEYE,
// CLASS_BULLSQUID,
CLASS_CITIZEN_PASSIVE,
CLASS_CITIZEN_REBEL,
CLASS_COMBINE,
CLASS_COMBINE_GUNSHIP,
CLASS_CONSCRIPT,
CLASS_HEADCRAB,
// CLASS_HOUNDEYE,
CLASS_MANHACK,
CLASS_METROPOLICE,
CLASS_MILITARY,
CLASS_SCANNER,
CLASS_STALKER,
CLASS_VORTIGAUNT,
CLASS_ZOMBIE,
CLASS_PROTOSNIPER,
CLASS_MISSILE,
CLASS_FLARE,
CLASS_EARTH_FAUNA,
NUM_AI_CLASSES
};
#elif defined(CSTRIKE_DLL)
enum Class_T {
CLASS_NONE = 0,
CLASS_PLAYER,
CLASS_PLAYER_ALLY,
NUM_AI_CLASSES
};
#else
enum Class_T {
CLASS_NONE = 0,
CLASS_PLAYER,
CLASS_PLAYER_ALLY,
NUM_AI_CLASSES
};
#endif
//
// Structure passed to input handlers.
//
struct inputdata_t {
CBaseEntity *pActivator; // The entity that initially caused this chain of
// output events.
CBaseEntity *pCaller; // The entity that fired this particular output.
variant_t value; // The data parameter for this output.
int nOutputID; // The unique ID of the output that was fired.
};
// Serializable list of context as set by entity i/o and used for deducing
// proper
// speech state, et al.
struct ResponseContext_t {
DECLARE_SIMPLE_DATADESC();
string_t m_iszName;
string_t m_iszValue;
float m_fExpirationTime; // when to expire context (0 == never)
};
//-----------------------------------------------------------------------------
// Entity events... targetted to a particular entity
// Each event has a well defined structure to use for parameters
//-----------------------------------------------------------------------------
enum EntityEvent_t {
ENTITY_EVENT_WATER_TOUCH = 0, // No data needed
ENTITY_EVENT_WATER_UNTOUCH, // No data needed
ENTITY_EVENT_PARENT_CHANGED, // No data needed
};
//-----------------------------------------------------------------------------
typedef void (CBaseEntity::*BASEPTR)(void);
typedef void (CBaseEntity::*ENTITYFUNCPTR)(CBaseEntity *pOther);
typedef void (CBaseEntity::*USEPTR)(CBaseEntity *pActivator,
CBaseEntity *pCaller, USE_TYPE useType,
float value);
#define DEFINE_THINKFUNC(function) DEFINE_FUNCTION_RAW(function, BASEPTR)
#define DEFINE_ENTITYFUNC(function) DEFINE_FUNCTION_RAW(function, ENTITYFUNCPTR)
#define DEFINE_USEFUNC(function) DEFINE_FUNCTION_RAW(function, USEPTR)
// Things that toggle (buttons/triggers/doors) need this
enum TOGGLE_STATE { TS_AT_TOP, TS_AT_BOTTOM, TS_GOING_UP, TS_GOING_DOWN };
// Debug overlay bits
enum DebugOverlayBits_t {
OVERLAY_TEXT_BIT = 0x00000001, // show text debug overlay for this entity
OVERLAY_NAME_BIT = 0x00000002, // show name debug overlay for this entity
OVERLAY_BBOX_BIT = 0x00000004, // show bounding box overlay for this entity
OVERLAY_PIVOT_BIT = 0x00000008, // show pivot for this entity
OVERLAY_MESSAGE_BIT = 0x00000010, // show messages for this entity
OVERLAY_ABSBOX_BIT = 0x00000020, // show abs bounding box overlay
OVERLAY_RBOX_BIT = 0x00000040, // show the rbox overlay
OVERLAY_SHOW_BLOCKSLOS = 0x00000080, // show entities that block NPC LOS
OVERLAY_ATTACHMENTS_BIT = 0x00000100, // show attachment points
OVERLAY_AUTOAIM_BIT = 0x00000200, // Display autoaim radius
OVERLAY_NPC_SELECTED_BIT = 0x00001000, // the npc is current selected
OVERLAY_NPC_NEAREST_BIT = 0x00002000, // show the nearest node of this npc
OVERLAY_NPC_ROUTE_BIT = 0x00004000, // draw the route for this npc
OVERLAY_NPC_TRIANGULATE_BIT =
0x00008000, // draw the triangulation for this npc
OVERLAY_NPC_ZAP_BIT = 0x00010000, // destroy the NPC
OVERLAY_NPC_ENEMIES_BIT = 0x00020000, // show npc's enemies
OVERLAY_NPC_CONDITIONS_BIT = 0x00040000, // show NPC's current conditions
OVERLAY_NPC_SQUAD_BIT = 0x00080000, // show npc squads
OVERLAY_NPC_TASK_BIT = 0x00100000, // show npc task details
OVERLAY_NPC_FOCUS_BIT = 0x00200000, // show line to npc's enemy and target
OVERLAY_NPC_VIEWCONE_BIT = 0x00400000, // show npc's viewcone
OVERLAY_NPC_KILL_BIT =
0x00800000, // kill the NPC, running all appropriate AI.
OVERLAY_WC_CHANGE_ENTITY = 0x01000000, // object changed during WC edit
OVERLAY_BUDDHA_MODE = 0x02000000, // take damage but don't die
OVERLAY_NPC_STEERING_REGULATIONS =
0x04000000, // Show the steering regulations associated with the NPC
OVERLAY_TASK_TEXT_BIT =
0x08000000, // show task and schedule names when they start
OVERLAY_PROP_DEBUG = 0x10000000,
OVERLAY_NPC_RELATION_BIT =
0x20000000, // show relationships between target and all children
OVERLAY_VIEWOFFSET = 0x40000000, // show view offset
};
struct TimedOverlay_t;
/* ========= CBaseEntity ========
All objects in the game are derived from this.
a list of all CBaseEntitys is kept in gEntList
================================ */
// creates an entity by string name, but does not spawn it
// If iForceEdictIndex is not -1, then it will use the edict by that index. If
// the index is invalid or there is already an edict using that index, it will
// error out.
CBaseEntity *CreateEntityByName(const char *className,
int iForceEdictIndex = -1);
CBaseNetworkable *CreateNetworkableByName(const char *className);
// creates an entity and calls all the necessary spawn functions
extern void SpawnEntityByName(const char *className,
CEntityMapData *mapData = NULL);
// calls the spawn functions for an entity
extern int DispatchSpawn(CBaseEntity *pEntity);
inline CBaseEntity *GetContainingEntity(edict_t *pent);
//-----------------------------------------------------------------------------
// Purpose: think contexts
//-----------------------------------------------------------------------------
struct thinkfunc_t {
BASEPTR m_pfnThink;
string_t m_iszContext;
int m_nNextThinkTick;
int m_nLastThinkTick;
DECLARE_SIMPLE_DATADESC();
};
struct EmitSound_t;
struct rotatingpushmove_t;
#define CREATE_PREDICTED_ENTITY(className) \
CBaseEntity::CreatePredictedEntityByName(className, __FILE__, __LINE__);
//
// Base Entity. All entity types derive from this
//
class CBaseEntity : public IServerEntity {
public:
DECLARE_CLASS_NOBASE(CBaseEntity);
//----------------------------------------
// Class vars and functions
//----------------------------------------
static inline void Debug_Pause(bool bPause);
static inline bool Debug_IsPaused(void);
static inline void Debug_SetSteps(int nSteps);
static inline bool Debug_ShouldStep(void);
static inline bool Debug_Step(void);
static bool m_bInDebugSelect;
static int m_nDebugPlayer;
protected:
static bool m_bDebugPause; // Whether entity i/o is paused for debugging.
static int m_nDebugSteps; // Number of entity outputs to fire before
// pausing again.
static bool sm_bDisableTouchFuncs; // Disables PhysicsTouch and
// PhysicsStartTouch function calls
public:
static bool sm_bAccurateTriggerBboxChecks; // SOLID_BBOX entities do a
// fully accurate trigger vs
// bbox check when this is set
public:
// If bServerOnly is true, then the ent never goes to the client. This is
// used by logical entities.
CBaseEntity(bool bServerOnly = false);
virtual ~CBaseEntity();
// prediction system
DECLARE_PREDICTABLE();
// network data
DECLARE_SERVERCLASS();
// data description
DECLARE_DATADESC();
// memory handling
void *operator new(size_t stAllocateBlock);
void *operator new(size_t stAllocateBlock, int nBlockUse,
const char *pFileName, int nLine);
void operator delete(void *pMem);
void operator delete(void *pMem, int nBlockUse, const char *pFileName,
int nLine) {
operator delete(pMem);
}
// Class factory
static CBaseEntity *CreatePredictedEntityByName(const char *classname,
const char *module,
int line,
bool persist = false);
// IHandleEntity overrides.
public:
virtual void SetRefEHandle(const CBaseHandle &handle);
virtual const CBaseHandle &GetRefEHandle() const;
// IServerUnknown overrides
virtual ICollideable *GetCollideable();
virtual IServerNetworkable *GetNetworkable();
virtual CBaseEntity *GetBaseEntity();
// IServerEntity overrides.
public:
virtual void SetModelIndex(int index);
virtual int GetModelIndex(void) const;
virtual string_t GetModelName(void) const;
void ClearModelIndexOverrides(void);
virtual void SetModelIndexOverride(int index, int nValue);
public:
// virtual methods for derived classes to override
virtual bool TestCollision(const Ray_t &ray, unsigned int mask,
trace_t &trace);
virtual bool TestHitboxes(const Ray_t &ray, unsigned int fContentsMask,
trace_t &tr);
virtual void ComputeWorldSpaceSurroundingBox(Vector *pWorldMins,
Vector *pWorldMaxs);
// non-virtual methods. Don't override these!
public:
// An inline version the game code can use
CCollisionProperty *CollisionProp();
const CCollisionProperty *CollisionProp() const;
CServerNetworkProperty *NetworkProp();
const CServerNetworkProperty *NetworkProp() const;
bool IsCurrentlyTouching(void) const;
const Vector &GetAbsOrigin(void) const;
const QAngle &GetAbsAngles(void) const;
SolidType_t GetSolid() const;
int GetSolidFlags(void) const;
int GetEFlags() const;
void SetEFlags(int iEFlags);
void AddEFlags(int nEFlagMask);
void RemoveEFlags(int nEFlagMask);
bool IsEFlagSet(int nEFlagMask) const;
// Quick way to ask if we have a player entity as a child anywhere in our
// hierarchy.
void RecalcHasPlayerChildBit();
bool DoesHavePlayerChild();
bool IsTransparent() const;
void SetNavIgnore(float duration = FLT_MAX);
void ClearNavIgnore();
bool IsNavIgnored() const;
// Is the entity floating?
bool IsFloating();
// Called by physics to see if we should avoid a collision test....
virtual bool ShouldCollide(int collisionGroup, int contentsMask) const;
// Move type / move collide
MoveType_t GetMoveType() const;
MoveCollide_t GetMoveCollide() const;
void SetMoveType(MoveType_t val,
MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT);
void SetMoveCollide(MoveCollide_t val);
// Returns the entity-to-world transform
matrix3x4_t &EntityToWorldTransform();
const matrix3x4_t &EntityToWorldTransform() const;
// Some helper methods that transform a point from entity space to world
// space + back
void EntityToWorldSpace(const Vector &in, Vector *pOut) const;
void WorldToEntitySpace(const Vector &in, Vector *pOut) const;
// This function gets your parent's transform. If you're parented to an
// attachment, this calculates the attachment's transform and gives you
// that.
//
// You must pass in tempMatrix for scratch space - it may need to fill that
// in and return it instead of pointing you right at a variable in your
// parent.
matrix3x4_t &GetParentToWorldTransform(matrix3x4_t &tempMatrix);
// Externalized data objects ( see sharreddefs.h for DataObjectType_t )
bool HasDataObjectType(int type) const;
void AddDataObjectType(int type);
void RemoveDataObjectType(int type);
void *GetDataObject(int type);
void *CreateDataObject(int type);
void DestroyDataObject(int type);
void DestroyAllDataObjects(void);
public:
void SetScaledPhysics(IPhysicsObject *pNewObject);
// virtual methods; you can override these
public:
// Owner entity.
// FIXME: These are virtual only because of CNodeEnt
CBaseEntity *GetOwnerEntity() const;
virtual void SetOwnerEntity(CBaseEntity *pOwner);
void SetEffectEntity(CBaseEntity *pEffectEnt);
CBaseEntity *GetEffectEntity() const;
// Only CBaseEntity implements these. CheckTransmit calls the virtual
// ShouldTransmit to see if the entity wants to be sent. If so, it calls
// SetTransmit, which will mark any dependents for transmission too.
virtual int ShouldTransmit(const CCheckTransmitInfo *pInfo);
// update the global transmit state if a transmission rule changed
int SetTransmitState(int nFlag);
int GetTransmitState(void);
int DispatchUpdateTransmitState();
// Do NOT call this directly. Use DispatchUpdateTransmitState.
virtual int UpdateTransmitState();
// Entities (like ropes) use this to own the transmit state of another
// entity by forcing it to not call UpdateTransmitState.
void IncrementTransmitStateOwnedCounter();
void DecrementTransmitStateOwnedCounter();
// This marks the entity for transmission and passes the SetTransmit call to
// any dependents.
virtual void SetTransmit(CCheckTransmitInfo *pInfo, bool bAlways);
// This function finds out if the entity is in the 3D skybox. If so, it sets
// the EFL_IN_SKYBOX flag so the entity gets transmitted to all the clients.
// Entities usually call this during their Activate().
// Returns true if the entity is in the skybox (and EFL_IN_SKYBOX was set).
bool DetectInSkybox();
// Returns which skybox the entity is in
CSkyCamera *GetEntitySkybox();
bool IsSimulatedEveryTick() const;
bool IsAnimatedEveryTick() const;
void SetSimulatedEveryTick(bool sim);
void SetAnimatedEveryTick(bool anim);
public:
virtual const char *GetTracerType(void);
// returns a pointer to the entities edict, if it has one. should be
// removed!
inline edict_t *edict(void) { return NetworkProp()->edict(); }
inline const edict_t *edict(void) const { return NetworkProp()->edict(); }
inline int entindex() const { return m_Network.entindex(); };
inline int GetSoundSourceIndex() const { return entindex(); }
// These methods encapsulate MOVETYPE_FOLLOW, which became obsolete
void FollowEntity(CBaseEntity *pBaseEntity, bool bBoneMerge = true);
void StopFollowingEntity(); // will also change to MOVETYPE_NONE
bool IsFollowingEntity();
CBaseEntity *GetFollowedEntity();
// initialization
virtual void Spawn(void);
virtual void Precache(void) {}
virtual void SetModel(const char *szModelName);
protected:
// Notification on model load. May be called multiple times for dynamic
// models. Implementations must call BaseClass::OnNewModel and pass return
// value through.
virtual CStudioHdr *OnNewModel();
public:
virtual void PostConstructor(const char *szClassname);
virtual void PostClientActive(void);
virtual void ParseMapData(CEntityMapData *mapData);
virtual bool KeyValue(const char *szKeyName, const char *szValue);
virtual bool KeyValue(const char *szKeyName, float flValue);
virtual bool KeyValue(const char *szKeyName, const Vector &vecValue);
virtual bool GetKeyValue(const char *szKeyName, char *szValue, int iMaxLen);
void ValidateEntityConnections();
void FireNamedOutput(const char *pszOutput, variant_t variant,
CBaseEntity *pActivator, CBaseEntity *pCaller,
float flDelay = 0.0f);
// Activate - called for each entity after each load game and level load
virtual void Activate(void);
// Hierarchy traversal
CBaseEntity *GetMoveParent(void);
CBaseEntity *GetRootMoveParent();
CBaseEntity *FirstMoveChild(void);
CBaseEntity *NextMovePeer(void);
void SetName(string_t newTarget);
void SetParent(string_t newParent, CBaseEntity *pActivator,
int iAttachment = -1);
// Set the movement parent. Your local origin and angles will become
// relative to this parent. If iAttachment is a valid attachment on the
// parent, then your local origin and angles are relative to the attachment
// on this entity. If iAttachment == -1, it'll preserve the current
// m_iParentAttachment.
virtual void SetParent(CBaseEntity *pNewParent, int iAttachment = -1);
CBaseEntity *GetParent();
int GetParentAttachment();
string_t GetEntityName();
bool NameMatches(const char *pszNameOrWildcard);
bool ClassMatches(const char *pszClassOrWildcard);
bool NameMatches(string_t nameStr);
bool ClassMatches(string_t nameStr);
private:
bool NameMatchesComplex(const char *pszNameOrWildcard);
bool ClassMatchesComplex(const char *pszClassOrWildcard);
void TransformStepData_WorldToParent(CBaseEntity *pParent);
void TransformStepData_ParentToParent(CBaseEntity *pOldParent,
CBaseEntity *pNewParent);
void TransformStepData_ParentToWorld(CBaseEntity *pParent);
public:
int GetSpawnFlags(void) const;
void AddSpawnFlags(int nFlags);
void RemoveSpawnFlags(int nFlags);
void ClearSpawnFlags(void);
bool HasSpawnFlags(int nFlags) const;
int GetEffects(void) const;
void AddEffects(int nEffects);
void RemoveEffects(int nEffects);
void ClearEffects(void);
void SetEffects(int nEffects);
bool IsEffectActive(int nEffects) const;
// makes the entity inactive
void MakeDormant(void);
int IsDormant(void);
void RemoveDeferred(void); // Sets the entity invisible, and makes it
// remove itself on the next frame
// checks to see if the entity is marked for deletion
bool IsMarkedForDeletion(void);
// capabilities
virtual int ObjectCaps(void);
// Verifies that the data description is valid in debug builds.
#ifdef _DEBUG
void ValidateDataDescription(void);
#endif // _DEBUG
// handles an input (usually caused by outputs)
// returns true if the the value in the pass in should be set, false if the
// input is to be ignored
virtual bool AcceptInput(const char *szInputName, CBaseEntity *pActivator,
CBaseEntity *pCaller, variant_t Value,
int outputID);
//
// Input handlers.
//
void InputAlternativeSorting(inputdata_t &inputdata);
void InputAlpha(inputdata_t &inputdata);
void InputColor(inputdata_t &inputdata);
void InputSetParent(inputdata_t &inputdata);
void SetParentAttachment(const char *szInputName, const char *szAttachment,
bool bMaintainOffset);
void InputSetParentAttachment(inputdata_t &inputdata);
void InputSetParentAttachmentMaintainOffset(inputdata_t &inputdata);
void InputClearParent(inputdata_t &inputdata);
void InputSetTeam(inputdata_t &inputdata);
void InputUse(inputdata_t &inputdata);
void InputKill(inputdata_t &inputdata);
void InputKillHierarchy(inputdata_t &inputdata);
void InputSetDamageFilter(inputdata_t &inputdata);
void InputDispatchEffect(inputdata_t &inputdata);
void InputEnableDamageForces(inputdata_t &inputdata);
void InputDisableDamageForces(inputdata_t &inputdata);
void InputAddContext(inputdata_t &inputdata);
void InputRemoveContext(inputdata_t &inputdata);
void InputClearContext(inputdata_t &inputdata);
void InputDispatchResponse(inputdata_t &inputdata);
void InputDisableShadow(inputdata_t &inputdata);
void InputEnableShadow(inputdata_t &inputdata);
void InputAddOutput(inputdata_t &inputdata);
void InputFireUser1(inputdata_t &inputdata);
void InputFireUser2(inputdata_t &inputdata);
void InputFireUser3(inputdata_t &inputdata);
void InputFireUser4(inputdata_t &inputdata);
// Returns the origin at which to play an inputted dispatcheffect
virtual void GetInputDispatchEffectPosition(const char *sInputString,
Vector &pOrigin,
QAngle &pAngles);
// tries to read a field from the entities data description - result is
// placed in variant_t
bool ReadKeyField(const char *varName, variant_t *var);
// classname access
void SetClassname(const char *className);
const char *GetClassname();
// Debug Overlays
void EntityText(int text_offset, const char *text, float flDuration,
int r = 255, int g = 255, int b = 255, int a = 255);
const char *GetDebugName(
void); // do not make this virtual -- designed to handle NULL this
virtual void DrawDebugGeometryOverlays(void);
virtual int DrawDebugTextOverlays(void);
void DrawTimedOverlays(void);
void DrawBBoxOverlay(float flDuration = 0.0f);
void DrawAbsBoxOverlay();
void DrawRBoxOverlay();
void DrawInputOverlay(const char *szInputName, CBaseEntity *pCaller,
variant_t Value);
void DrawOutputOverlay(CEventAction *ev);
void SendDebugPivotOverlay(void);
void AddTimedOverlay(const char *msg, int endTime);
void SetSolid(SolidType_t val);
// save/restore
// only overload these if you have special data to serialize
virtual int Save(ISave &save);
virtual int Restore(IRestore &restore);
virtual bool ShouldSavePhysics();
// handler to reset stuff before you are restored
// NOTE: Always chain to base class when implementing this!
virtual void OnSave(IEntitySaveUtils *pSaveUtils);
// handler to reset stuff after you are restored
// called after all entities have been loaded from all affected levels
// called before activate
// NOTE: Always chain to base class when implementing this!
virtual void OnRestore();
int GetTextureFrameIndex(void);
void SetTextureFrameIndex(int iIndex);
// Entities block Line-Of-Sight for NPCs by default.
// Set this to false if you want to change this behavior.
void SetBlocksLOS(bool bBlocksLOS);
bool BlocksLOS(void);
void SetAIWalkable(bool bBlocksLOS);
bool IsAIWalkable(void);
private:
int SaveDataDescBlock(ISave &save, datamap_t *dmap);
int RestoreDataDescBlock(IRestore &restore, datamap_t *dmap);
public:
// Networking related methods
void NetworkStateChanged();
void NetworkStateChanged(void *pVar);
public:
void CalcAbsolutePosition();
// returns the edict index the entity requires when used in save/restore (eg
// players, world) -1 means it doesn't require any special index
virtual int RequiredEdictIndex(void) { return -1; }
// interface function pts
void (CBaseEntity::*m_pfnMoveDone)(void);
virtual void MoveDone(void) {
if (m_pfnMoveDone) (this->*m_pfnMoveDone)();
};
// Why do we have two separate static Instance functions?
static CBaseEntity *Instance(const CBaseHandle &hEnt);
static CBaseEntity *Instance(const edict_t *pent);
static CBaseEntity *Instance(edict_t *pent);
static CBaseEntity *Instance(int iEnt);
// Think function handling
void (CBaseEntity::*m_pfnThink)(void);
virtual void Think(void) {
if (m_pfnThink) (this->*m_pfnThink)();
};
// Think functions with contexts
int RegisterThinkContext(const char *szContext);
BASEPTR ThinkSet(BASEPTR func, float flNextThinkTime = 0,
const char *szContext = NULL);
void SetNextThink(float nextThinkTime, const char *szContext = NULL);
float GetNextThink(const char *szContext = NULL);
float GetLastThink(const char *szContext = NULL);
int GetNextThinkTick(const char *szContext = NULL);
int GetLastThinkTick(const char *szContext = NULL);
float GetAnimTime() const;
void SetAnimTime(float at);
float GetSimulationTime() const;
void SetSimulationTime(float st);
void SetRenderMode(RenderMode_t nRenderMode);
RenderMode_t GetRenderMode() const;
private:
// NOTE: Keep this near vtable so it's in cache with vtable.
CServerNetworkProperty m_Network;
public:
// members
string_t m_iClassname; // identifier for entity creation and save/restore
string_t m_iGlobalname; // identifier for carrying entity across level
// transitions
string_t m_iParent; // the name of the entities parent; linked into
// m_pParent during Activate()
int m_iHammerID; // Hammer unique edit id number
public:
// was pev->speed
float m_flSpeed;
// was pev->renderfx
CNetworkVar(unsigned char, m_nRenderFX);
// was pev->rendermode
CNetworkVar(unsigned char, m_nRenderMode);
CNetworkVar(short, m_nModelIndex);
#ifdef TF_DLL
CNetworkArray(int, m_nModelIndexOverrides,
MAX_VISION_MODES); // used to override the base model index
// on the client if necessary
#endif
// was pev->rendercolor
CNetworkColor32(m_clrRender);
const color32 GetRenderColor() const;
void SetRenderColor(byte r, byte g, byte b);
void SetRenderColor(byte r, byte g, byte b, byte a);
void SetRenderColorR(byte r);
void SetRenderColorG(byte g);
void SetRenderColorB(byte b);
void SetRenderColorA(byte a);
// was pev->animtime: consider moving to CBaseAnimating
float m_flPrevAnimTime;
CNetworkVar(float,
m_flAnimTime); // this is the point in time that the client
// will interpolate to position,angle,frame,etc.
CNetworkVar(float, m_flSimulationTime);
void IncrementInterpolationFrame(); // Call this to cause a discontinuity
// (teleport)
CNetworkVar(int, m_ubInterpolationFrame);
int m_nLastThinkTick;
#if !defined(NO_ENTITY_PREDICTION)
// Certain entities (projectiles) can be created on the client and thus need
// a matching id number
CNetworkVar(CPredictableId, m_PredictableID);
#endif
// used so we know when things are no longer touching
int touchStamp;
protected:
// think function handling
enum thinkmethods_t {
THINK_FIRE_ALL_FUNCTIONS,
THINK_FIRE_BASE_ONLY,
THINK_FIRE_ALL_BUT_BASE,
};
int GetIndexForThinkContext(const char *pszContext);
CUtlVector<thinkfunc_t> m_aThinkFunctions;
#ifdef _DEBUG
int m_iCurrentThinkContext;
#endif
void RemoveExpiredConcepts(void);
int GetContextCount()
const; // Call RemoveExpiredConcepts to clean out expired concepts
const char *GetContextName(
int index) const; // note: context may be expired
const char *GetContextValue(
int index) const; // note: context may be expired
bool ContextExpired(int index) const;
int FindContextByName(const char *name) const;
public:
void AddContext(const char *nameandvalue);
protected:
CUtlVector<ResponseContext_t> m_ResponseContexts;
// Map defined context sets
string_t m_iszResponseContext;
private:
CBaseEntity(CBaseEntity &);
// list handling
friend class CGlobalEntityList;
friend class CThinkSyncTester;
// was pev->nextthink
CNetworkVarForDerived(int, m_nNextThinkTick);
// was pev->effects
CNetworkVar(int, m_fEffects);
////////////////////////////////////////////////////////////////////////////
public:
// Returns a CBaseAnimating if the entity is derived from CBaseAnimating.
virtual CBaseAnimating *GetBaseAnimating() { return 0; }
virtual IResponseSystem *GetResponseSystem();
virtual void DispatchResponse(const char *conceptName);
// Classify - returns the type of group (i.e, "houndeye", or "human
// military" so that NPCs with different classnames still realize that they
// are teammates. (overridden for NPCs that form groups)
virtual Class_T Classify(void);
virtual void DeathNotice(CBaseEntity *pVictim) {
} // NPC maker children use this to tell the NPC maker that they have died.
virtual bool ShouldAttractAutoAim(CBaseEntity *pAimingEnt) {
return ((GetFlags() & FL_AIMTARGET) != 0);
}
virtual float GetAutoAimRadius();
virtual Vector GetAutoAimCenter() { return WorldSpaceCenter(); }
virtual ITraceFilter *GetBeamTraceFilter(void);
// Call this to do a TraceAttack on an entity, performs filtering. Don't
// call TraceAttack() directly except when chaining up to base class
void DispatchTraceAttack(const CTakeDamageInfo &info, const Vector &vecDir,
trace_t *ptr,
CDmgAccumulator *pAccumulator = NULL);
virtual bool PassesDamageFilter(const CTakeDamageInfo &info);
protected:
virtual void TraceAttack(const CTakeDamageInfo &info, const Vector &vecDir,
trace_t *ptr,
CDmgAccumulator *pAccumulator = NULL);
public:
virtual bool CanBeHitByMeleeAttack(CBaseEntity *pAttacker) { return true; }
// returns the amount of damage inflicted
virtual int OnTakeDamage(const CTakeDamageInfo &info);
// This is what you should call to apply damage to an entity.
int TakeDamage(const CTakeDamageInfo &info);
virtual void AdjustDamageDirection(const CTakeDamageInfo &info, Vector &dir,
CBaseEntity *pEnt) {}
virtual int TakeHealth(float flHealth, int bitsDamageType);
virtual bool IsAlive(void);
// Entity killed (only fired once)
virtual void Event_Killed(const CTakeDamageInfo &info);
void SendOnKilledGameEvent(const CTakeDamageInfo &info);
// Notifier that I've killed some other entity. (called from Victim's
// Event_Killed).
virtual void Event_KilledOther(CBaseEntity *pVictim,
const CTakeDamageInfo &info) {
return;
}
// UNDONE: Make this data?
virtual int BloodColor(void);
void TraceBleed(float flDamage, const Vector &vecDir, trace_t *ptr,
int bitsDamageType);
virtual bool IsTriggered(CBaseEntity *pActivator) { return true; }
virtual bool IsNPC(void) const { return false; }
CAI_BaseNPC *MyNPCPointer(void);
virtual CBaseCombatCharacter *MyCombatCharacterPointer(void) {
return NULL;
}
virtual INextBot *MyNextBotPointer(void) { return NULL; }
virtual float GetDelay(void) { return 0; }
virtual bool IsMoving(void);
bool IsWorld() { return entindex() == 0; }
virtual char const *DamageDecal(int bitsDamageType, int gameMaterial);
virtual void DecalTrace(trace_t *pTrace, char const *decalName);
virtual void ImpactTrace(trace_t *pTrace, int iDamageType,
const char *pCustomImpactName = NULL);
void AddPoints(int score, bool bAllowNegativeScore);
void AddPointsToTeam(int score, bool bAllowNegativeScore);
void RemoveAllDecals(void);
virtual bool OnControls(CBaseEntity *pControls) { return false; }
virtual bool HasTarget(string_t targetname);
virtual bool IsPlayer(void) const { return false; }
virtual bool IsNetClient(void) const { return false; }
virtual bool IsTemplate(void) { return false; }
virtual bool IsBaseObject(void) const { return false; }
virtual bool IsBaseTrain(void) const { return false; }
bool IsBSPModel() const;
bool IsCombatCharacter() {
return MyCombatCharacterPointer() == NULL ? false : true;
}
bool IsInWorld(void) const;
virtual bool IsCombatItem(void) const { return false; }
virtual bool IsBaseCombatWeapon(void) const { return false; }
virtual bool IsWearable(void) const { return false; }
virtual CBaseCombatWeapon *MyCombatWeaponPointer(void) { return NULL; }
// If this is a vehicle, returns the vehicle interface
virtual IServerVehicle *GetServerVehicle() { return NULL; }
// UNDONE: Make this data instead of procedural?
virtual bool IsViewable(void); // is this something that would be looked at
// (model, sprite, etc.)?
// Team Handling
CTeam *GetTeam(void) const; // Get the Team this entity is on
int GetTeamNumber(
void) const; // Get the Team number of the team this entity is on
virtual void ChangeTeam(int iTeamNum); // Assign this entity to a team.
bool IsInTeam(CTeam *pTeam)
const; // Returns true if this entity's in the specified team
bool InSameTeam(
CBaseEntity *pEntity) const; // Returns true if the specified entity is
// on the same team as this one
bool IsInAnyTeam(void) const; // Returns true if this entity is in any team
const char *TeamID(
void) const; // Returns the name of the team this entity is on.
// Entity events... these are events targetted to a particular entity
// Each event defines its own well-defined event data structure
virtual void OnEntityEvent(EntityEvent_t event, void *pEventData);
// can stand on this entity?
bool IsStandable() const;
// UNDONE: Do these three functions actually need to be virtual???
virtual bool CanStandOn(CBaseEntity *pSurface) const {
return (pSurface && !pSurface->IsStandable()) ? false : true;
}
virtual bool CanStandOn(edict_t *ent) const {
return CanStandOn(GetContainingEntity(ent));
}
virtual CBaseEntity *GetEnemy(void) { return NULL; }
virtual CBaseEntity *GetEnemy(void) const { return NULL; }
void ViewPunch(const QAngle &angleOffset);
void VelocityPunch(const Vector &vecForce);
CBaseEntity *GetNextTarget(void);
// fundamental callbacks
void (CBaseEntity ::*m_pfnTouch)(CBaseEntity *pOther);
void (CBaseEntity ::*m_pfnUse)(CBaseEntity *pActivator,
CBaseEntity *pCaller, USE_TYPE useType,
float value);
void (CBaseEntity ::*m_pfnBlocked)(CBaseEntity *pOther);
virtual void Use(CBaseEntity *pActivator, CBaseEntity *pCaller,
USE_TYPE useType, float value);
virtual void StartTouch(CBaseEntity *pOther);
virtual void Touch(CBaseEntity *pOther);
virtual void EndTouch(CBaseEntity *pOther);
virtual void StartBlocked(CBaseEntity *pOther) {}
virtual void Blocked(CBaseEntity *pOther);
virtual void EndBlocked(void) {}
// Physics simulation
virtual void PhysicsSimulate(void);
public:
// HACKHACK:Get the trace_t from the last physics touch call (replaces the
// even-hackier global trace vars)
static const trace_t &GetTouchTrace(void);
// FIXME: Should be private, but I can't make em private just yet
void PhysicsImpact(CBaseEntity *other, trace_t &trace);
void PhysicsMarkEntitiesAsTouching(CBaseEntity *other, trace_t &trace);
void PhysicsMarkEntitiesAsTouchingEventDriven(CBaseEntity *other,
trace_t &trace);
void PhysicsTouchTriggers(const Vector *pPrevAbsOrigin = NULL);
// Physics helper
static void PhysicsRemoveTouchedList(CBaseEntity *ent);
static void PhysicsNotifyOtherOfUntouch(CBaseEntity *ent,
CBaseEntity *other);
static void PhysicsRemoveToucher(CBaseEntity *other, touchlink_t *link);
groundlink_t *AddEntityToGroundList(CBaseEntity *other);
void PhysicsStartGroundContact(CBaseEntity *pentOther);
static void PhysicsNotifyOtherOfGroundRemoval(CBaseEntity *ent,
CBaseEntity *other);
static void PhysicsRemoveGround(CBaseEntity *other, groundlink_t *link);
static void PhysicsRemoveGroundList(CBaseEntity *ent);
void StartGroundContact(CBaseEntity *ground);
void EndGroundContact(CBaseEntity *ground);
void SetGroundChangeTime(float flTime);
float GetGroundChangeTime(void);
// Remove this as ground entity for all object resting on this object
void WakeRestingObjects();
bool HasNPCsOnIt();
virtual void UpdateOnRemove(void);
virtual void StopLoopingSounds(void) {}
// common member functions
void SUB_Remove(void);
void SUB_DoNothing(void);
void SUB_StartFadeOut(float delay = 10.0f, bool bNotSolid = true);
void SUB_StartFadeOutInstant();
void SUB_FadeOut(void);
void SUB_Vanish(void);
void SUB_CallUseToggle(void) { this->Use(this, this, USE_TOGGLE, 0); }
void SUB_PerformFadeOut(void);
virtual bool SUB_AllowedToFade(void);
// change position, velocity, orientation instantly
// passing NULL means no change
virtual void Teleport(const Vector *newPosition, const QAngle *newAngles,
const Vector *newVelocity);
// notify that another entity (that you were watching) was teleported
virtual void NotifySystemEvent(CBaseEntity *pNotify,
notify_system_event_t eventType,
const notify_system_event_params_t &params);
int ShouldToggle(USE_TYPE useType, int currentState);
// UNDONE: Move these virtuals to CBaseCombatCharacter?
virtual void MakeTracer(const Vector &vecTracerSrc, const trace_t &tr,
int iTracerType);
virtual int GetTracerAttachment(void);
virtual void FireBullets(const FireBulletsInfo_t &info);
virtual void DoImpactEffect(
trace_t &tr,
int nDamageType); // give shooter a chance to do a custom impact.
// OLD VERSION! Use the struct version
void FireBullets(int cShots, const Vector &vecSrc,
const Vector &vecDirShooting, const Vector &vecSpread,
float flDistance, int iAmmoType, int iTracerFreq = 4,
int firingEntID = -1, int attachmentID = -1,
int iDamage = 0, CBaseEntity *pAttacker = NULL,
bool bFirstShotAccurate = false,
bool bPrimaryAttack = true);
virtual void ModifyFireBulletsDamage(CTakeDamageInfo *dmgInfo) {}
virtual CBaseEntity *Respawn(void) { return NULL; }
// Method used to deal with attacks passing through triggers
void TraceAttackToTriggers(const CTakeDamageInfo &info, const Vector &start,
const Vector &end, const Vector &dir);
// Do the bounding boxes of these two intersect?
bool Intersects(CBaseEntity *pOther);
virtual bool IsLockedByMaster(void) { return false; }
// Health accessors.
virtual int GetMaxHealth() const { return m_iMaxHealth; }
void SetMaxHealth(int amt) { m_iMaxHealth = amt; }
int GetHealth() const { return m_iHealth; }
void SetHealth(int amt) { m_iHealth = amt; }
float HealthFraction() const;
// Ugly code to lookup all functions to make sure they are in the table when
// set.
#ifdef _DEBUG
#ifdef GNUC
#define ENTITYFUNCPTR_SIZE 8
#else
#define ENTITYFUNCPTR_SIZE 4
#endif
void FunctionCheck(void *pFunction, const char *name);
ENTITYFUNCPTR TouchSet(ENTITYFUNCPTR func, char *name) {
COMPILE_TIME_ASSERT(sizeof(func) == ENTITYFUNCPTR_SIZE);
m_pfnTouch = func;
FunctionCheck(*(reinterpret_cast<void **>(&m_pfnTouch)), name);
return func;
}
USEPTR UseSet(USEPTR func, char *name) {
COMPILE_TIME_ASSERT(sizeof(func) == ENTITYFUNCPTR_SIZE);
m_pfnUse = func;
FunctionCheck(*(reinterpret_cast<void **>(&m_pfnUse)), name);
return func;
}
ENTITYFUNCPTR BlockedSet(ENTITYFUNCPTR func, char *name) {
COMPILE_TIME_ASSERT(sizeof(func) == ENTITYFUNCPTR_SIZE);
m_pfnBlocked = func;
FunctionCheck(*(reinterpret_cast<void **>(&m_pfnBlocked)), name);
return func;
}
#endif // _DEBUG
virtual void ModifyOrAppendCriteria(AI_CriteriaSet &set);
void AppendContextToCriteria(AI_CriteriaSet &set, const char *prefix = "");
void DumpResponseCriteria(void);
// Return the IHasAttributes interface for this base entity. Removes the
// need for:
// dynamic_cast< IHasAttributes * >( pEntity );
// Which is remarkably slow.
// GetAttribInterface( CBaseEntity *pEntity ) in attribute_manager.h uses
// this function, tests for NULL, and Asserts m_pAttributes ==
// dynamic_cast.
inline IHasAttributes *GetHasAttributesInterfacePtr() const {
return m_pAttributes;
}
protected:
// NOTE: m_pAttributes needs to be set in the leaf class constructor.
IHasAttributes *m_pAttributes;
private:
friend class CAI_Senses;
CBaseEntity *m_pLink; // used for temporary link-list operations.
public:
// variables promoted from edict_t
string_t m_target;
CNetworkVarForDerived(
int, m_iMaxHealth); // CBaseEntity doesn't care about changes to this
// variable, but there are derived classes that do.
CNetworkVarForDerived(int, m_iHealth);
CNetworkVarForDerived(char, m_lifeState);
CNetworkVarForDerived(char, m_takedamage);
// Damage filtering
string_t m_iszDamageFilterName; // The name of the entity to use as our
// damage filter.
EHANDLE m_hDamageFilter; // The entity that controls who can damage us.
// Debugging / devolopment fields
int m_debugOverlays; // For debug only (bitfields)
TimedOverlay_t *m_pTimedOverlay; // For debug only
// virtual functions used by a few classes
// creates an entity of a specified class, by name
static CBaseEntity *Create(const char *szName, const Vector &vecOrigin,
const QAngle &vecAngles,
CBaseEntity *pOwner = NULL);
static CBaseEntity *CreateNoSpawn(const char *szName,
const Vector &vecOrigin,
const QAngle &vecAngles,
CBaseEntity *pOwner = NULL);
// Collision group accessors
int GetCollisionGroup() const;
void SetCollisionGroup(int collisionGroup);
void CollisionRulesChanged();
// Damage accessors
virtual int GetDamageType() const;
virtual float GetDamage() { return 0; }
virtual void SetDamage(float flDamage) {}
virtual Vector EyePosition(void); // position of eyes
virtual const QAngle &EyeAngles(void); // Direction of eyes in world space
virtual const QAngle &LocalEyeAngles(void); // Direction of eyes
virtual Vector EarPosition(void); // position of ears
Vector EyePosition(void) const; // position of eyes
const QAngle &EyeAngles(void) const; // Direction of eyes in world space
const QAngle &LocalEyeAngles(void) const; // Direction of eyes
Vector EarPosition(void) const; // position of ears
virtual Vector BodyTarget(const Vector &posSrc,
bool bNoisy = true); // position to shoot at
virtual Vector HeadTarget(const Vector &posSrc);
virtual void GetVectors(Vector *forward, Vector *right, Vector *up) const;
virtual const Vector &GetViewOffset() const;
virtual void SetViewOffset(const Vector &v);
// NOTE: Setting the abs velocity in either space will cause a recomputation
// in the other space, so setting the abs velocity will also set the local
// vel
void SetLocalVelocity(const Vector &vecVelocity);
void ApplyLocalVelocityImpulse(const Vector &vecImpulse);
void SetAbsVelocity(const Vector &vecVelocity);
void ApplyAbsVelocityImpulse(const Vector &vecImpulse);
void ApplyLocalAngularVelocityImpulse(const AngularImpulse &angImpulse);
const Vector &GetLocalVelocity() const;
const Vector &GetAbsVelocity() const;
// NOTE: Setting the abs velocity in either space will cause a recomputation
// in the other space, so setting the abs velocity will also set the local
// vel
void SetLocalAngularVelocity(const QAngle &vecAngVelocity);
const QAngle &GetLocalAngularVelocity() const;
// FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular
// velocity representation, we can't actually solve this problem
// void SetAbsAngularVelocity( const QAngle &vecAngVelocity
//); const QAngle& GetAbsAngularVelocity( ) const;
const Vector &GetBaseVelocity() const;
void SetBaseVelocity(const Vector &v);
virtual Vector GetSmoothedVelocity(void);
// FIXME: Figure out what to do about this
virtual void GetVelocity(Vector *vVelocity,
AngularImpulse *vAngVelocity = NULL);
float GetGravity(void) const;
void SetGravity(float gravity);
float GetFriction(void) const;
void SetFriction(float flFriction);
virtual bool FVisible(CBaseEntity *pEntity, int traceMask = MASK_BLOCKLOS,
CBaseEntity **ppBlocker = NULL);
virtual bool FVisible(const Vector &vecTarget,
int traceMask = MASK_BLOCKLOS,
CBaseEntity **ppBlocker = NULL);
virtual bool CanBeSeenBy(CAI_BaseNPC *pNPC) {
return true;
} // allows entities to be 'invisible' to NPC senses.
// This function returns a value that scales all damage done by this entity.
// Use CDamageModifier to hook in damage modifiers on a guy.
virtual float GetAttackDamageScale(CBaseEntity *pVictim);
// This returns a value that scales all damage done to this entity
// Use CDamageModifier to hook in damage modifiers on a guy.
virtual float GetReceivedDamageScale(CBaseEntity *pAttacker);
void SetCheckUntouch(bool check);
bool GetCheckUntouch() const;
void SetGroundEntity(CBaseEntity *ground);
CBaseEntity *GetGroundEntity(void);
CBaseEntity *GetGroundEntity(void) const {
return const_cast<CBaseEntity *>(this)->GetGroundEntity();
}
// Gets the velocity we impart to a player standing on us
virtual void GetGroundVelocityToApply(Vector &vecGroundVel) {
vecGroundVel = vec3_origin;
}
int GetWaterLevel() const;
void SetWaterLevel(int nLevel);
int GetWaterType() const;
void SetWaterType(int nType);
virtual bool PhysicsSplash(const Vector &centerPoint, const Vector &normal,
float rawSpeed, float scaledSpeed) {
return false;
}
virtual void Splash() {}
void ClearSolidFlags(void);
void RemoveSolidFlags(int flags);
void AddSolidFlags(int flags);
bool IsSolidFlagSet(int flagMask) const;
void SetSolidFlags(int flags);
bool IsSolid() const;
void SetModelName(string_t name);
model_t *GetModel(void);
// These methods return a *world-aligned* box relative to the absorigin of
// the entity. This is used for collision purposes and is *not* guaranteed
// to surround the entire entity's visual representation
// NOTE: It is illegal to ask for the world-aligned bounds for
// SOLID_BSP objects
const Vector &WorldAlignMins() const;
const Vector &WorldAlignMaxs() const;
// This defines collision bounds in OBB space
void SetCollisionBounds(const Vector &mins, const Vector &maxs);
// NOTE: The world space center *may* move when the entity rotates.
virtual const Vector &WorldSpaceCenter() const;
const Vector &WorldAlignSize() const;
// Returns a radius of a sphere
// *centered at the world space center* bounding the collision
// representation of the entity. NOTE: The world space center *may* move
// when the entity rotates.
float BoundingRadius() const;
bool IsPointSized() const;
// NOTE: Setting the abs origin or angles will cause the local origin +
// angles to be set also
void SetAbsOrigin(const Vector &origin);
void SetAbsAngles(const QAngle &angles);
// Origin and angles in local space ( relative to parent )
// NOTE: Setting the local origin or angles will cause the abs origin +
// angles to be set also
void SetLocalOrigin(const Vector &origin);
const Vector &GetLocalOrigin(void) const;
void SetLocalAngles(const QAngle &angles);
const QAngle &GetLocalAngles(void) const;
void SetElasticity(float flElasticity);
float GetElasticity(void) const;
void SetShadowCastDistance(float flDistance);
float GetShadowCastDistance(void) const;
void SetShadowCastDistance(float flDesiredDistance, float flDelay);
float GetLocalTime(void) const;
void IncrementLocalTime(float flTimeDelta);
float GetMoveDoneTime() const;
void SetMoveDoneTime(float flTime);
// Used by the PAS filters to ask the entity where in world space the sounds
// it emits come from. This is used right now because if you have something
// sitting on an incline, using our axis-aligned bounding boxes can return a
// position in solid space, so you won't hear sounds emitted by the object.
// For now, we're hacking around it by moving the sound emission origin up
// on certain objects like vehicles.
//
// When OBBs get in, this can probably go away.
virtual Vector GetSoundEmissionOrigin() const;
void AddFlag(int flags);
void RemoveFlag(int flagsToRemove);
void ToggleFlag(int flagToToggle);
int GetFlags(void) const;
void ClearFlags(void);
// Sets the local position from a transform
void SetLocalTransform(const matrix3x4_t &localTransform);
// See CSoundEmitterSystem
void EmitSound(
const char *soundname, float soundtime = 0.0f,
float *duration = NULL); // Override for doing the general case of
// CPASAttenuationFilter filter( this ), and
// EmitSound( filter, entindex(), etc. );
void EmitSound(
const char *soundname, HSOUNDSCRIPTHANDLE &handle,
float soundtime = 0.0f,
float *duration = NULL); // Override for doing the general case of
// CPASAttenuationFilter filter( this ), and
// EmitSound( filter, entindex(), etc. );
void StopSound(const char *soundname);
void StopSound(const char *soundname, HSOUNDSCRIPTHANDLE &handle);
void GenderExpandString(char const *in, char *out, int maxlen);
virtual void ModifyEmitSoundParams(EmitSound_t &params);
static float GetSoundDuration(const char *soundname,
char const *actormodel);
static bool GetParametersForSound(const char *soundname,
CSoundParameters &params,
char const *actormodel);
static bool GetParametersForSound(const char *soundname,
HSOUNDSCRIPTHANDLE &handle,
CSoundParameters &params,
char const *actormodel);
static void EmitSound(IRecipientFilter &filter, int iEntIndex,
const char *soundname, const Vector *pOrigin = NULL,
float soundtime = 0.0f, float *duration = NULL);
static void EmitSound(IRecipientFilter &filter, int iEntIndex,
const char *soundname, HSOUNDSCRIPTHANDLE &handle,
const Vector *pOrigin = NULL, float soundtime = 0.0f,
float *duration = NULL);
static void StopSound(int iEntIndex, const char *soundname);
static soundlevel_t LookupSoundLevel(const char *soundname);
static soundlevel_t LookupSoundLevel(const char *soundname,
HSOUNDSCRIPTHANDLE &handle);
static void EmitSound(IRecipientFilter &filter, int iEntIndex,
const EmitSound_t &params);
static void EmitSound(IRecipientFilter &filter, int iEntIndex,
const EmitSound_t &params,
HSOUNDSCRIPTHANDLE &handle);
static void StopSound(int iEntIndex, int iChannel, const char *pSample);
static void EmitAmbientSound(int entindex, const Vector &origin,
const char *soundname, int flags = 0,
float soundtime = 0.0f,
float *duration = NULL);
// These files need to be listed in scripts/game_sounds_manifest.txt
static HSOUNDSCRIPTHANDLE PrecacheScriptSound(const char *soundname);
static void PrefetchScriptSound(const char *soundname);
// For each client who appears to be a valid recipient, checks the client
// has disabled CC and if so, removes them from
// the recipient list.
static void RemoveRecipientsIfNotCloseCaptioning(CRecipientFilter &filter);
static void EmitCloseCaption(IRecipientFilter &filter, int entindex,
char const *token,
CUtlVector<Vector> &soundorigins,
float duration, bool warnifmissing = false);
static void EmitSentenceByIndex(IRecipientFilter &filter, int iEntIndex,
int iChannel, int iSentenceIndex,
float flVolume, soundlevel_t iSoundlevel,
int iFlags = 0, int iPitch = PITCH_NORM,
const Vector *pOrigin = NULL,
const Vector *pDirection = NULL,
bool bUpdatePositions = true,
float soundtime = 0.0f);
static bool IsPrecacheAllowed();
static void SetAllowPrecache(bool allow);
static bool m_bAllowPrecache;
static bool IsSimulatingOnAlternateTicks();
virtual bool IsDeflectable() { return false; }
virtual void Deflected(CBaseEntity *pDeflectedBy, Vector &vecDir) {}
// void Relink() {}
public:
// VPHYSICS Integration -----------------------------------------------
//
// --------------------------------------------------------------------
// UNDONE: Move to IEntityVPhysics? or VPhysicsProp() ?
// Called after spawn, and in the case of self-managing objects, after load
virtual bool CreateVPhysics();
// Convenience routines to init the vphysics simulation for this object.
// This creates a static object. Something that behaves like world geometry
// - solid, but never moves
IPhysicsObject *VPhysicsInitStatic(void);
// This creates a normal vphysics simulated object - physics determines
// where it goes (gravity, friction, etc) and the entity receives updates
// from vphysics. SetAbsOrigin(), etc do not affect the object!
IPhysicsObject *VPhysicsInitNormal(SolidType_t solidType, int nSolidFlags,
bool createAsleep,
solid_t *pSolid = NULL);
// This creates a vphysics object with a shadow controller that follows the
// AI Move the object to where it should be and call
// UpdatePhysicsShadowToCurrentPosition()
IPhysicsObject *VPhysicsInitShadow(bool allowPhysicsMovement,
bool allowPhysicsRotation,
solid_t *pSolid = NULL);
// Force a non-solid (ie. solid_trigger) physics object to collide with
// other entities.
virtual bool ForceVPhysicsCollide(CBaseEntity *pEntity) { return false; }
private:
// called by all vphysics inits
bool VPhysicsInitSetup();
public:
void VPhysicsSetObject(IPhysicsObject *pPhysics);
// destroy and remove the physics object for this entity
virtual void VPhysicsDestroyObject(void);
void VPhysicsSwapObject(IPhysicsObject *pSwap);
inline IPhysicsObject *VPhysicsGetObject(void) const {
return m_pPhysicsObject;
}
virtual void VPhysicsUpdate(IPhysicsObject *pPhysics);
void VPhysicsUpdatePusher(IPhysicsObject *pPhysics);
// react physically to damage (called from CBaseEntity::OnTakeDamage() by
// default)
virtual int VPhysicsTakeDamage(const CTakeDamageInfo &info);
virtual void VPhysicsShadowCollision(int index,
gamevcollisionevent_t *pEvent);
virtual void VPhysicsShadowUpdate(IPhysicsObject *pPhysics) {}
virtual void VPhysicsCollision(int index, gamevcollisionevent_t *pEvent);
virtual void VPhysicsFriction(IPhysicsObject *pObject, float energy,
int surfaceProps, int surfacePropsHit);
// update the shadow so it will coincide with the current AI position at
// some time in the future (or 0 for now)
virtual void UpdatePhysicsShadowToCurrentPosition(float deltaTime);
virtual int VPhysicsGetObjectList(IPhysicsObject **pList, int listMax);
virtual bool VPhysicsIsFlesh(void);
// --------------------------------------------------------------------
public:
#if !defined(NO_ENTITY_PREDICTION)
// The player drives simulation of this entity
void SetPlayerSimulated(CBasePlayer *pOwner);
void UnsetPlayerSimulated(void);
bool IsPlayerSimulated(void) const;
CBasePlayer *GetSimulatingPlayer(void);
#endif
// FIXME: Make these private!
void PhysicsCheckForEntityUntouch(void);
bool PhysicsRunThink(thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS);
bool PhysicsRunSpecificThink(int nContextIndex, BASEPTR thinkFunc);
bool PhysicsTestEntityPosition(CBaseEntity **ppEntity = NULL);
void PhysicsPushEntity(const Vector &push, trace_t *pTrace);
bool PhysicsCheckWater(void);
void PhysicsCheckWaterTransition(void);
void PhysicsStepRecheckGround();
// Computes the water level + type
void UpdateWaterState();
bool IsEdictFree() const { return edict()->IsFree(); }
// Callbacks for the physgun/cannon picking up an entity
virtual CBasePlayer *HasPhysicsAttacker(float dt) { return NULL; }
// UNDONE: Make this data?
virtual unsigned int PhysicsSolidMaskForEntity(void) const;
// Computes the abs position of a point specified in local space
void ComputeAbsPosition(const Vector &vecLocalPosition,
Vector *pAbsPosition);
// Computes the abs position of a direction specified in local space
void ComputeAbsDirection(const Vector &vecLocalDirection,
Vector *pAbsDirection);
void SetPredictionEligible(bool canpredict);
protected:
// Invalidates the abs state of all children
void InvalidatePhysicsRecursive(int nChangeFlags);
int PhysicsClipVelocity(const Vector &in, const Vector &normal, Vector &out,
float overbounce);
void PhysicsRelinkChildren(float dt);
// Performs the collision resolution for fliers.
void PerformFlyCollisionResolution(trace_t &trace, Vector &move);
void ResolveFlyCollisionBounce(trace_t &trace, Vector &vecVelocity,
float flMinTotalElasticity = 0.0f);
void ResolveFlyCollisionSlide(trace_t &trace, Vector &vecVelocity);
virtual void ResolveFlyCollisionCustom(trace_t &trace, Vector &vecVelocity);
private:
// Physics-related private methods
void PhysicsStep(void);
void PhysicsPusher(void);
void PhysicsNone(void);
void PhysicsNoclip(void);
void PhysicsStepRunTimestep(float timestep);
void PhysicsToss(void);
void PhysicsCustom(void);
void PerformPush(float movetime);
// Simulation in local space of rigid children
void PhysicsRigidChild(void);
// Computes the base velocity
void UpdateBaseVelocity(void);
// Implement this if you use MOVETYPE_CUSTOM
virtual void PerformCustomPhysics(Vector *pNewPosition,
Vector *pNewVelocity, QAngle *pNewAngles,
QAngle *pNewAngVelocity);
void PhysicsDispatchThink(BASEPTR thinkFunc);
touchlink_t *PhysicsMarkEntityAsTouched(CBaseEntity *other);
void PhysicsTouch(CBaseEntity *pentOther);
void PhysicsStartTouch(CBaseEntity *pentOther);
CBaseEntity *PhysicsPushMove(float movetime);
CBaseEntity *PhysicsPushRotate(float movetime);
CBaseEntity *PhysicsCheckRotateMove(rotatingpushmove_t &rotPushmove,
CBaseEntity **pPusherList,
int pusherListCount);
CBaseEntity *PhysicsCheckPushMove(const Vector &move,
CBaseEntity **pPusherList,
int pusherListCount);
int PhysicsTryMove(float flTime, trace_t *steptrace);
void PhysicsCheckVelocity(void);
void PhysicsAddHalfGravity(float timestep);
void PhysicsAddGravityMove(Vector &move);
void CalcAbsoluteVelocity();
void CalcAbsoluteAngularVelocity();
// Checks a sweep without actually performing the move
void PhysicsCheckSweep(const Vector &vecAbsStart, const Vector &vecAbsDelta,
trace_t *pTrace);
// Computes new angles based on the angular velocity
void SimulateAngles(float flFrameTime);
void CheckStepSimulationChanged();
// Run regular think and latch off angle/origin changes so we can
// interpolate them on the server to fake simulation
void StepSimulationThink(float dt);
// Compute network origin
private:
void ComputeStepSimulationNetwork(StepSimulationData *step);
public:
bool UseStepSimulationNetworkOrigin(const Vector **out_v);
bool UseStepSimulationNetworkAngles(const QAngle **out_a);
public:
// Add a discontinuity to a step
bool AddStepDiscontinuity(float flTime, const Vector &vecOrigin,
const QAngle &vecAngles);
int GetFirstThinkTick(); // get first tick thinking on any context
private:
// origin and angles to use in step calculations
virtual Vector GetStepOrigin(void) const;
virtual QAngle GetStepAngles(void) const;
// These set entity flags (EFL_*) to help optimize queries
void CheckHasThinkFunction(bool isThinkingHint = false);
void CheckHasGamePhysicsSimulation();
bool WillThink();
bool WillSimulateGamePhysics();
friend class CPushBlockerEnum;
// Sets/Gets the next think based on context index
void SetNextThink(int nContextIndex, float thinkTime);
void SetLastThink(int nContextIndex, float thinkTime);
float GetNextThink(int nContextIndex) const;
int GetNextThinkTick(int nContextIndex) const;
// Shot statistics
void UpdateShotStatistics(const trace_t &tr);
// Handle shot entering water
bool HandleShotImpactingWater(const FireBulletsInfo_t &info,
const Vector &vecEnd,
ITraceFilter *pTraceFilter,
Vector *pVecTracerDest);
// Handle shot entering water
void HandleShotImpactingGlass(const FireBulletsInfo_t &info,
const trace_t &tr, const Vector &vecDir,
ITraceFilter *pTraceFilter);
// Should we draw bubbles underwater?
bool ShouldDrawUnderwaterBulletBubbles();
// Computes the tracer start position
void ComputeTracerStartPosition(const Vector &vecShotSrc,
Vector *pVecTracerStart);
// Computes the tracer start position
void CreateBubbleTrailTracer(const Vector &vecShotSrc,
const Vector &vecShotEnd,
const Vector &vecShotDir);
virtual bool ShouldDrawWaterImpacts() { return true; }
// Changes shadow cast distance over time
void ShadowCastDistThink();
// Precache model sounds + particles
static void PrecacheModelComponents(int nModelIndex);
static void PrecacheSoundHelper(const char *pName);
protected:
// Which frame did I simulate?
int m_nSimulationTick;
// FIXME: Make this private! Still too many references to do so...
CNetworkVar(int, m_spawnflags);
private:
int m_iEFlags; // entity flags EFL_*
// was pev->flags
CNetworkVarForDerived(int, m_fFlags);
string_t m_iName; // name used to identify this entity
// Damage modifiers
friend class CDamageModifier;
CUtlLinkedList<CDamageModifier *, int> m_DamageModifiers;
EHANDLE m_pParent; // for movement hierarchy
byte m_nTransmitStateOwnedCounter;
CNetworkVar(unsigned char,
m_iParentAttachment); // 0 if we're relative to the parent's
// absorigin and absangles.
CNetworkVar(unsigned char, m_MoveType); // One of the MOVETYPE_ defines.
CNetworkVar(unsigned char, m_MoveCollide);
// Our immediate parent in the movement hierarchy.
// FIXME: clarify m_pParent vs. m_pMoveParent
CNetworkHandle(CBaseEntity, m_hMoveParent);
// cached child list
EHANDLE m_hMoveChild;
// generated from m_pMoveParent
EHANDLE m_hMovePeer;
friend class CCollisionProperty;
friend class CServerNetworkProperty;
CNetworkVarEmbedded(CCollisionProperty, m_Collision);
CNetworkHandle(CBaseEntity, m_hOwnerEntity); // only used to point to an
// edict it won't collide with
CNetworkHandle(CBaseEntity, m_hEffectEntity); // Fire/Dissolve entity.
CNetworkVar(int, m_CollisionGroup); // used to cull collision tests
IPhysicsObject *m_pPhysicsObject; // pointer to the entity's physics object
// (vphysics.dll)
CNetworkVar(float, m_flShadowCastDistance);
float m_flDesiredShadowCastDistance;
// Team handling
int m_iInitialTeamNum; // Team number of this entity's team read from file
CNetworkVar(int, m_iTeamNum); // Team number of this entity's team.
// Sets water type + level for physics objects
unsigned char m_nWaterTouch;
unsigned char m_nSlimeTouch;
unsigned char m_nWaterType;
CNetworkVarForDerived(unsigned char, m_nWaterLevel);
float m_flNavIgnoreUntilTime;
CNetworkHandleForDerived(CBaseEntity, m_hGroundEntity);
float m_flGroundChangeTime; // Time that the ground entity changed
string_t m_ModelName;
// Velocity of the thing we're standing on (world space)
CNetworkVarForDerived(Vector, m_vecBaseVelocity);
// Global velocity
Vector m_vecAbsVelocity;
// Local angular velocity
QAngle m_vecAngVelocity;
// Global angular velocity
// QAngle m_vecAbsAngVelocity;
// local coordinate frame of entity
matrix3x4_t m_rgflCoordinateFrame;
// Physics state
EHANDLE m_pBlocker;
// was pev->gravity;
float m_flGravity; // rename to m_flGravityScale;
// was pev->friction
CNetworkVarForDerived(float, m_flFriction);
CNetworkVar(float, m_flElasticity);
// was pev->ltime
float m_flLocalTime;
// local time at the beginning of this frame
float m_flVPhysicsUpdateLocalTime;
// local time the movement has ended
float m_flMoveDoneTime;
// A counter to help quickly build a list of potentially pushed objects for
// physics
int m_nPushEnumCount;
Vector m_vecAbsOrigin;
CNetworkVectorForDerived(m_vecVelocity);
// Adrian
CNetworkVar(unsigned char, m_iTextureFrameIndex);
CNetworkVar(bool, m_bSimulatedEveryTick);
CNetworkVar(bool, m_bAnimatedEveryTick);
CNetworkVar(bool, m_bAlternateSorting);
// User outputs. Fired when the "FireInputX" input is triggered.
COutputEvent m_OnUser1;
COutputEvent m_OnUser2;
COutputEvent m_OnUser3;
COutputEvent m_OnUser4;
QAngle m_angAbsRotation;
CNetworkVector(m_vecOrigin);
CNetworkQAngle(m_angRotation);
CBaseHandle m_RefEHandle;
// was pev->view_ofs ( FIXME: Move somewhere up the hierarch,
// CBaseAnimating, etc. )
CNetworkVectorForDerived(m_vecViewOffset);
private:
// dynamic model state tracking
bool m_bDynamicModelAllowed;
bool m_bDynamicModelPending;
bool m_bDynamicModelSetBounds;
void OnModelLoadComplete(const model_t *model);
friend class CBaseEntityModelLoadProxy;
protected:
void EnableDynamicModels() { m_bDynamicModelAllowed = true; }
public:
bool IsDynamicModelLoading() const { return m_bDynamicModelPending; }
void SetCollisionBoundsFromModel();
#if !defined(NO_ENTITY_PREDICTION)
CNetworkVar(bool, m_bIsPlayerSimulated);
// Player who is driving my simulation
CHandle<CBasePlayer> m_hPlayerSimulationOwner;
#endif
int m_fDataObjectTypes;
// So it can get at the physics methods
friend class CCollisionEvent;
// Methods shared by client and server
public:
void SetSize(const Vector &vecMin,
const Vector &vecMax); // UTIL_SetSize( this, mins, maxs );
static int PrecacheModel(const char *name, bool bPreload = true);
static bool PrecacheSound(const char *name);
static void PrefetchSound(const char *name);
void Remove(); // UTIL_Remove( this );
private:
// This is a random seed used by the networking code to allow client - side
// prediction code
// randon number generators to spit out the same random numbers on both
// sides for a particular usercmd input.
static int m_nPredictionRandomSeed;
static int m_nPredictionRandomSeedServer;
static CBasePlayer *m_pPredictionPlayer;
// FIXME: Make hierarchy a member of CBaseEntity
// or a contained private class...
friend void UnlinkChild(CBaseEntity *pParent, CBaseEntity *pChild);
friend void LinkChild(CBaseEntity *pParent, CBaseEntity *pChild);
friend void ClearParent(CBaseEntity *pEntity);
friend void UnlinkAllChildren(CBaseEntity *pParent);
friend void UnlinkFromParent(CBaseEntity *pRemove);
friend void TransferChildren(CBaseEntity *pOldParent,
CBaseEntity *pNewParent);
public:
// Accessors for above
static int GetPredictionRandomSeed(bool bUseUnSyncedServerPlatTime = false);
static void SetPredictionRandomSeed(const CUserCmd *cmd);
static CBasePlayer *GetPredictionPlayer(void);
static void SetPredictionPlayer(CBasePlayer *player);
// For debugging shared code
static bool IsServer(void) { return true; }
static bool IsClient(void) { return false; }
static char const *GetDLLType(void) { return "server"; }
// Used to access m_vecAbsOrigin during restore when it's unsafe to call
// GetAbsOrigin.
friend class CPlayerRestoreHelper;
static bool s_bAbsQueriesValid;
// Call this when hierarchy is not completely set up (such as during
// Restore) to throw asserts when people call GetAbsAnything.
static inline void SetAbsQueriesValid(bool bValid) {
s_bAbsQueriesValid = bValid;
}
static inline bool IsAbsQueriesValid() { return s_bAbsQueriesValid; }
virtual bool ShouldBlockNav() const { return true; }
};
// Send tables exposed in this module.
EXTERN_SEND_TABLE(DT_Edict);
EXTERN_SEND_TABLE(DT_BaseEntity);
// Ugly technique to override base member functions
// Normally it's illegal to cast a pointer to a member function of a derived
// class to a pointer to a member function of a base class. static_cast is a
// sleezy way around that problem.
#ifdef _DEBUG
#define SetTouch(a) \
TouchSet(static_cast<void (CBaseEntity::*)(CBaseEntity *)>(a), #a)
#define SetUse(a) \
UseSet(static_cast<void (CBaseEntity::*)( \
CBaseEntity * pActivator, CBaseEntity * pCaller, \
USE_TYPE useType, float value)>(a), \
#a)
#define SetBlocked(a) \
BlockedSet(static_cast<void (CBaseEntity::*)(CBaseEntity *)>(a), #a)
#else
#define SetTouch(a) \
m_pfnTouch = static_cast<void (CBaseEntity::*)(CBaseEntity *)>(a)
#define SetUse(a) \
m_pfnUse = static_cast<void (CBaseEntity::*)( \
CBaseEntity * pActivator, CBaseEntity * pCaller, USE_TYPE useType, \
float value)>(a)
#define SetBlocked(a) \
m_pfnBlocked = static_cast<void (CBaseEntity::*)(CBaseEntity *)>(a)
#endif
// handling entity/edict transforms
inline CBaseEntity *GetContainingEntity(edict_t *pent) {
if (pent && pent->GetUnknown()) {
return pent->GetUnknown()->GetBaseEntity();
}
return NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Pauses or resumes entity i/o events. When paused, no outputs will
// fire unless Debug_SetSteps is called with a nonzero step
//value.
// Input : bPause - true to pause, false to resume.
//-----------------------------------------------------------------------------
inline void CBaseEntity::Debug_Pause(bool bPause) {
CBaseEntity::m_bDebugPause = bPause;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if entity i/o is paused, false if not.
//-----------------------------------------------------------------------------
inline bool CBaseEntity::Debug_IsPaused(void) {
return (CBaseEntity::m_bDebugPause);
}
//-----------------------------------------------------------------------------
// Purpose: Decrements the debug step counter. Used when the entity i/o system
// is in single step mode, this is called every time an output
//is fired.
// Output : Returns true on to continue firing outputs, false to stop.
//-----------------------------------------------------------------------------
inline bool CBaseEntity::Debug_Step(void) {
if (CBaseEntity::m_nDebugSteps > 0) {
CBaseEntity::m_nDebugSteps--;
}
return (CBaseEntity::m_nDebugSteps > 0);
}
//-----------------------------------------------------------------------------
// Purpose: Sets the number of entity outputs to allow to fire before pausing
// the entity i/o system.
// Input : nSteps - Number of steps to execute.
//-----------------------------------------------------------------------------
inline void CBaseEntity::Debug_SetSteps(int nSteps) {
CBaseEntity::m_nDebugSteps = nSteps;
}
//-----------------------------------------------------------------------------
// Purpose: Returns true if we should allow outputs to be fired, false if not.
//-----------------------------------------------------------------------------
inline bool CBaseEntity::Debug_ShouldStep(void) {
return (!CBaseEntity::m_bDebugPause || CBaseEntity::m_nDebugSteps > 0);
}
//-----------------------------------------------------------------------------
// Methods relating to traversing hierarchy
//-----------------------------------------------------------------------------
inline CBaseEntity *CBaseEntity::GetMoveParent(void) {
return m_hMoveParent.Get();
}
inline CBaseEntity *CBaseEntity::FirstMoveChild(void) {
return m_hMoveChild.Get();
}
inline CBaseEntity *CBaseEntity::NextMovePeer(void) {
return m_hMovePeer.Get();
}
// FIXME: Remove this! There shouldn't be a difference between moveparent +
// parent
inline CBaseEntity *CBaseEntity::GetParent() { return m_pParent.Get(); }
inline int CBaseEntity::GetParentAttachment() { return m_iParentAttachment; }
//-----------------------------------------------------------------------------
// Inline methods
//-----------------------------------------------------------------------------
inline string_t CBaseEntity::GetEntityName() { return m_iName; }
inline void CBaseEntity::SetName(string_t newName) { m_iName = newName; }
inline bool CBaseEntity::NameMatches(const char *pszNameOrWildcard) {
if (IDENT_STRINGS(m_iName, pszNameOrWildcard)) return true;
return NameMatchesComplex(pszNameOrWildcard);
}
inline bool CBaseEntity::NameMatches(string_t nameStr) {
if (IDENT_STRINGS(m_iName, nameStr)) return true;
return NameMatchesComplex(STRING(nameStr));
}
inline bool CBaseEntity::ClassMatches(const char *pszClassOrWildcard) {
if (IDENT_STRINGS(m_iClassname, pszClassOrWildcard)) return true;
return ClassMatchesComplex(pszClassOrWildcard);
}
inline const char *CBaseEntity::GetClassname() { return STRING(m_iClassname); }
inline bool CBaseEntity::ClassMatches(string_t nameStr) {
if (IDENT_STRINGS(m_iClassname, nameStr)) return true;
return ClassMatchesComplex(STRING(nameStr));
}
inline int CBaseEntity::GetSpawnFlags(void) const { return m_spawnflags; }
inline void CBaseEntity::AddSpawnFlags(int nFlags) { m_spawnflags |= nFlags; }
inline void CBaseEntity::RemoveSpawnFlags(int nFlags) {
m_spawnflags &= ~nFlags;
}
inline void CBaseEntity::ClearSpawnFlags(void) { m_spawnflags = 0; }
inline bool CBaseEntity::HasSpawnFlags(int nFlags) const {
return (m_spawnflags & nFlags) != 0;
}
//-----------------------------------------------------------------------------
// checks to see if the entity is marked for deletion
//-----------------------------------------------------------------------------
inline bool CBaseEntity::IsMarkedForDeletion(void) {
return (m_iEFlags & EFL_KILLME);
}
//-----------------------------------------------------------------------------
// EFlags
//-----------------------------------------------------------------------------
inline int CBaseEntity::GetEFlags() const { return m_iEFlags; }
inline void CBaseEntity::SetEFlags(int iEFlags) {
m_iEFlags = iEFlags;
if (iEFlags & (EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX)) {
DispatchUpdateTransmitState();
}
}
inline void CBaseEntity::AddEFlags(int nEFlagMask) {
m_iEFlags |= nEFlagMask;
if (nEFlagMask & (EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX)) {
DispatchUpdateTransmitState();
}
}
inline void CBaseEntity::RemoveEFlags(int nEFlagMask) {
m_iEFlags &= ~nEFlagMask;
if (nEFlagMask & (EFL_FORCE_CHECK_TRANSMIT | EFL_IN_SKYBOX))
DispatchUpdateTransmitState();
}
inline bool CBaseEntity::IsEFlagSet(int nEFlagMask) const {
return (m_iEFlags & nEFlagMask) != 0;
}
inline void CBaseEntity::SetNavIgnore(float duration) {
float flNavIgnoreUntilTime =
(duration == FLT_MAX) ? FLT_MAX : gpGlobals->curtime + duration;
if (flNavIgnoreUntilTime > m_flNavIgnoreUntilTime)
m_flNavIgnoreUntilTime = flNavIgnoreUntilTime;
}
inline void CBaseEntity::ClearNavIgnore() { m_flNavIgnoreUntilTime = 0; }
inline bool CBaseEntity::IsNavIgnored() const {
return (gpGlobals->curtime <= m_flNavIgnoreUntilTime);
}
inline bool CBaseEntity::GetCheckUntouch() const {
return IsEFlagSet(EFL_CHECK_UNTOUCH);
}
//-----------------------------------------------------------------------------
// Network state optimization
//-----------------------------------------------------------------------------
inline CBaseCombatCharacter *ToBaseCombatCharacter(CBaseEntity *pEntity) {
if (!pEntity) return NULL;
return pEntity->MyCombatCharacterPointer();
}
//-----------------------------------------------------------------------------
// Physics state accessor methods
//-----------------------------------------------------------------------------
inline const Vector &CBaseEntity::GetLocalOrigin(void) const {
return m_vecOrigin.Get();
}
inline const QAngle &CBaseEntity::GetLocalAngles(void) const {
return m_angRotation.Get();
}
inline const Vector &CBaseEntity::GetAbsOrigin(void) const {
Assert(CBaseEntity::IsAbsQueriesValid());
if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) {
const_cast<CBaseEntity *>(this)->CalcAbsolutePosition();
}
return m_vecAbsOrigin;
}
inline const QAngle &CBaseEntity::GetAbsAngles(void) const {
Assert(CBaseEntity::IsAbsQueriesValid());
if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) {
const_cast<CBaseEntity *>(this)->CalcAbsolutePosition();
}
return m_angAbsRotation;
}
//-----------------------------------------------------------------------------
// Returns the entity-to-world transform
//-----------------------------------------------------------------------------
inline matrix3x4_t &CBaseEntity::EntityToWorldTransform() {
Assert(CBaseEntity::IsAbsQueriesValid());
if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) {
CalcAbsolutePosition();
}
return m_rgflCoordinateFrame;
}
inline const matrix3x4_t &CBaseEntity::EntityToWorldTransform() const {
Assert(CBaseEntity::IsAbsQueriesValid());
if (IsEFlagSet(EFL_DIRTY_ABSTRANSFORM)) {
const_cast<CBaseEntity *>(this)->CalcAbsolutePosition();
}
return m_rgflCoordinateFrame;
}
//-----------------------------------------------------------------------------
// Some helper methods that transform a point from entity space to world space +
// back
//-----------------------------------------------------------------------------
inline void CBaseEntity::EntityToWorldSpace(const Vector &in,
Vector *pOut) const {
if (GetAbsAngles() == vec3_angle) {
VectorAdd(in, GetAbsOrigin(), *pOut);
} else {
VectorTransform(in, EntityToWorldTransform(), *pOut);
}
}
inline void CBaseEntity::WorldToEntitySpace(const Vector &in,
Vector *pOut) const {
if (GetAbsAngles() == vec3_angle) {
VectorSubtract(in, GetAbsOrigin(), *pOut);
} else {
VectorITransform(in, EntityToWorldTransform(), *pOut);
}
}
//-----------------------------------------------------------------------------
// Velocity
//-----------------------------------------------------------------------------
inline Vector CBaseEntity::GetSmoothedVelocity(void) {
Vector vel;
GetVelocity(&vel, NULL);
return vel;
}
inline const Vector &CBaseEntity::GetLocalVelocity() const {
return m_vecVelocity.Get();
}
inline const Vector &CBaseEntity::GetAbsVelocity() const {
Assert(CBaseEntity::IsAbsQueriesValid());
if (IsEFlagSet(EFL_DIRTY_ABSVELOCITY)) {
const_cast<CBaseEntity *>(this)->CalcAbsoluteVelocity();
}
return m_vecAbsVelocity;
}
inline const QAngle &CBaseEntity::GetLocalAngularVelocity() const {
return m_vecAngVelocity;
}
/*
// FIXME: While we're using (dPitch, dYaw, dRoll) as our local angular velocity
// representation, we can't actually solve this problem
inline const QAngle &CBaseEntity::GetAbsAngularVelocity( ) const
{
if (IsEFlagSet(EFL_DIRTY_ABSANGVELOCITY))
{
const_cast<CBaseEntity*>(this)->CalcAbsoluteAngularVelocity();
}
return m_vecAbsAngVelocity;
}
*/
inline const Vector &CBaseEntity::GetBaseVelocity() const {
return m_vecBaseVelocity.Get();
}
inline void CBaseEntity::SetBaseVelocity(const Vector &v) {
m_vecBaseVelocity = v;
}
inline float CBaseEntity::GetGravity(void) const { return m_flGravity; }
inline void CBaseEntity::SetGravity(float gravity) { m_flGravity = gravity; }
inline float CBaseEntity::GetFriction(void) const { return m_flFriction; }
inline void CBaseEntity::SetFriction(float flFriction) {
m_flFriction = flFriction;
}
inline void CBaseEntity::SetElasticity(float flElasticity) {
m_flElasticity = flElasticity;
}
inline float CBaseEntity::GetElasticity(void) const { return m_flElasticity; }
inline void CBaseEntity::SetShadowCastDistance(float flDistance) {
m_flShadowCastDistance = flDistance;
}
inline float CBaseEntity::GetShadowCastDistance(void) const {
return m_flShadowCastDistance;
}
inline float CBaseEntity::GetLocalTime(void) const { return m_flLocalTime; }
inline void CBaseEntity::IncrementLocalTime(float flTimeDelta) {
m_flLocalTime += flTimeDelta;
}
inline float CBaseEntity::GetMoveDoneTime() const {
return (m_flMoveDoneTime >= 0) ? m_flMoveDoneTime - GetLocalTime() : -1;
}
inline CBaseEntity *CBaseEntity::Instance(const edict_t *pent) {
return GetContainingEntity(const_cast<edict_t *>(pent));
}
inline CBaseEntity *CBaseEntity::Instance(edict_t *pent) {
if (!pent) {
pent = INDEXENT(0);
}
return GetContainingEntity(pent);
}
inline CBaseEntity *CBaseEntity::Instance(int iEnt) {
return Instance(INDEXENT(iEnt));
}
inline int CBaseEntity::GetWaterLevel() const { return m_nWaterLevel; }
inline void CBaseEntity::SetWaterLevel(int nLevel) { m_nWaterLevel = nLevel; }
inline const color32 CBaseEntity::GetRenderColor() const {
return m_clrRender.Get();
}
inline void CBaseEntity::SetRenderColor(byte r, byte g, byte b) {
m_clrRender.Init(r, g, b);
}
inline void CBaseEntity::SetRenderColor(byte r, byte g, byte b, byte a) {
m_clrRender.Init(r, g, b, a);
}
inline void CBaseEntity::SetRenderColorR(byte r) { m_clrRender.SetR(r); }
inline void CBaseEntity::SetRenderColorG(byte g) { m_clrRender.SetG(g); }
inline void CBaseEntity::SetRenderColorB(byte b) { m_clrRender.SetB(b); }
inline void CBaseEntity::SetRenderColorA(byte a) { m_clrRender.SetA(a); }
inline void CBaseEntity::SetMoveCollide(MoveCollide_t val) {
m_MoveCollide = val;
}
inline bool CBaseEntity::IsTransparent() const {
return m_nRenderMode != kRenderNormal;
}
inline int CBaseEntity::GetTextureFrameIndex(void) {
return m_iTextureFrameIndex;
}
inline void CBaseEntity::SetTextureFrameIndex(int iIndex) {
m_iTextureFrameIndex = iIndex;
}
//-----------------------------------------------------------------------------
// An inline version the game code can use
//-----------------------------------------------------------------------------
inline CCollisionProperty *CBaseEntity::CollisionProp() { return &m_Collision; }
inline const CCollisionProperty *CBaseEntity::CollisionProp() const {
return &m_Collision;
}
inline CServerNetworkProperty *CBaseEntity::NetworkProp() { return &m_Network; }
inline const CServerNetworkProperty *CBaseEntity::NetworkProp() const {
return &m_Network;
}
inline void CBaseEntity::ClearSolidFlags(void) {
CollisionProp()->ClearSolidFlags();
}
inline void CBaseEntity::RemoveSolidFlags(int flags) {
CollisionProp()->RemoveSolidFlags(flags);
}
inline void CBaseEntity::AddSolidFlags(int flags) {
CollisionProp()->AddSolidFlags(flags);
}
inline int CBaseEntity::GetSolidFlags(void) const {
return CollisionProp()->GetSolidFlags();
}
inline bool CBaseEntity::IsSolidFlagSet(int flagMask) const {
return CollisionProp()->IsSolidFlagSet(flagMask);
}
inline bool CBaseEntity::IsSolid() const { return CollisionProp()->IsSolid(); }
inline void CBaseEntity::SetSolid(SolidType_t val) {
CollisionProp()->SetSolid(val);
}
inline void CBaseEntity::SetSolidFlags(int flags) {
CollisionProp()->SetSolidFlags(flags);
}
inline SolidType_t CBaseEntity::GetSolid() const {
return CollisionProp()->GetSolid();
}
//-----------------------------------------------------------------------------
// Methods related to IServerUnknown
//-----------------------------------------------------------------------------
inline ICollideable *CBaseEntity::GetCollideable() { return &m_Collision; }
inline IServerNetworkable *CBaseEntity::GetNetworkable() { return &m_Network; }
inline CBaseEntity *CBaseEntity::GetBaseEntity() { return this; }
//-----------------------------------------------------------------------------
// Model related methods
//-----------------------------------------------------------------------------
inline void CBaseEntity::SetModelName(string_t name) {
m_ModelName = name;
DispatchUpdateTransmitState();
}
inline string_t CBaseEntity::GetModelName(void) const { return m_ModelName; }
inline int CBaseEntity::GetModelIndex(void) const { return m_nModelIndex; }
//-----------------------------------------------------------------------------
// Methods relating to bounds
//-----------------------------------------------------------------------------
inline const Vector &CBaseEntity::WorldAlignMins() const {
Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace());
Assert(CollisionProp()->GetCollisionAngles() == vec3_angle);
return CollisionProp()->OBBMins();
}
inline const Vector &CBaseEntity::WorldAlignMaxs() const {
Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace());
Assert(CollisionProp()->GetCollisionAngles() == vec3_angle);
return CollisionProp()->OBBMaxs();
}
inline const Vector &CBaseEntity::WorldAlignSize() const {
Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace());
Assert(CollisionProp()->GetCollisionAngles() == vec3_angle);
return CollisionProp()->OBBSize();
}
// Returns a radius of a sphere *centered at the world space center*
// bounding the collision representation of the entity
inline float CBaseEntity::BoundingRadius() const {
return CollisionProp()->BoundingRadius();
}
inline bool CBaseEntity::IsPointSized() const {
return CollisionProp()->BoundingRadius() == 0.0f;
}
inline void CBaseEntity::SetRenderMode(RenderMode_t nRenderMode) {
m_nRenderMode = nRenderMode;
}
inline RenderMode_t CBaseEntity::GetRenderMode() const {
return (RenderMode_t)m_nRenderMode.Get();
}
//-----------------------------------------------------------------------------
// Methods to cast away const
//-----------------------------------------------------------------------------
inline Vector CBaseEntity::EyePosition(void) const {
return const_cast<CBaseEntity *>(this)->EyePosition();
}
inline const QAngle &CBaseEntity::EyeAngles(
void) const // Direction of eyes in world space
{
return const_cast<CBaseEntity *>(this)->EyeAngles();
}
inline const QAngle &CBaseEntity::LocalEyeAngles(
void) const // Direction of eyes
{
return const_cast<CBaseEntity *>(this)->LocalEyeAngles();
}
inline Vector CBaseEntity::EarPosition(void) const // position of ears
{
return const_cast<CBaseEntity *>(this)->EarPosition();
}
//-----------------------------------------------------------------------------
// Methods relating to networking
//-----------------------------------------------------------------------------
inline void CBaseEntity::NetworkStateChanged() {
NetworkProp()->NetworkStateChanged();
}
inline void CBaseEntity::NetworkStateChanged(void *pVar) {
// Make sure it's a semi-reasonable pointer.
Assert((char *)pVar > (char *)this);
Assert((char *)pVar - (char *)this < 32768);
// Good, they passed an offset so we can track this variable's change
// and avoid sending the whole entity.
NetworkProp()->NetworkStateChanged((char *)pVar - (char *)this);
}
//-----------------------------------------------------------------------------
// IHandleEntity overrides.
//-----------------------------------------------------------------------------
inline const CBaseHandle &CBaseEntity::GetRefEHandle() const {
return m_RefEHandle;
}
inline void CBaseEntity::IncrementTransmitStateOwnedCounter() {
Assert(m_nTransmitStateOwnedCounter != 255);
m_nTransmitStateOwnedCounter++;
}
inline void CBaseEntity::DecrementTransmitStateOwnedCounter() {
Assert(m_nTransmitStateOwnedCounter != 0);
m_nTransmitStateOwnedCounter--;
}
//-----------------------------------------------------------------------------
// Bullet firing (legacy)...
//-----------------------------------------------------------------------------
inline void CBaseEntity::FireBullets(
int cShots, const Vector &vecSrc, const Vector &vecDirShooting,
const Vector &vecSpread, float flDistance, int iAmmoType, int iTracerFreq,
int firingEntID, int attachmentID, int iDamage, CBaseEntity *pAttacker,
bool bFirstShotAccurate, bool bPrimaryAttack) {
FireBulletsInfo_t info;
info.m_iShots = cShots;
info.m_vecSrc = vecSrc;
info.m_vecDirShooting = vecDirShooting;
info.m_vecSpread = vecSpread;
info.m_flDistance = flDistance;
info.m_iAmmoType = iAmmoType;
info.m_iTracerFreq = iTracerFreq;
info.m_flDamage = iDamage;
info.m_pAttacker = pAttacker;
info.m_nFlags = bFirstShotAccurate ? FIRE_BULLETS_FIRST_SHOT_ACCURATE : 0;
info.m_bPrimaryAttack = bPrimaryAttack;
FireBullets(info);
}
// Ugly technique to override base member functions
// Normally it's illegal to cast a pointer to a member function of a derived
// class to a pointer to a member function of a base class. static_cast is a
// sleezy way around that problem.
#define SetThink(a) \
ThinkSet(static_cast<void (CBaseEntity::*)(void)>(a), 0, NULL)
#define SetContextThink(a, b, context) \
ThinkSet(static_cast<void (CBaseEntity::*)(void)>(a), (b), context)
#ifdef _DEBUG
#define SetMoveDone(a) \
do { \
m_pfnMoveDone = static_cast<void (CBaseEntity::*)(void)>(a); \
FunctionCheck( \
(void *)*((int *)((char *)this + \
(offsetof(CBaseEntity, m_pfnMoveDone)))), \
"BaseMoveFunc"); \
} while (0)
#else
#define SetMoveDone(a) \
(void)(m_pfnMoveDone = static_cast<void (CBaseEntity::*)(void)>(a))
#endif
inline bool FClassnameIs(CBaseEntity *pEntity, const char *szClassname) {
return pEntity->ClassMatches(szClassname);
}
class CPointEntity : public CBaseEntity {
public:
DECLARE_CLASS(CPointEntity, CBaseEntity);
void Spawn(void);
virtual int ObjectCaps(void) {
return BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION;
}
virtual bool KeyValue(const char *szKeyName, const char *szValue);
private:
};
// Has a position + size
class CServerOnlyEntity : public CBaseEntity {
DECLARE_CLASS(CServerOnlyEntity, CBaseEntity);
public:
CServerOnlyEntity() : CBaseEntity(true) {}
virtual int ObjectCaps(void) {
return (BaseClass::ObjectCaps() & ~FCAP_ACROSS_TRANSITION);
}
};
// Has only a position, no size
class CServerOnlyPointEntity : public CServerOnlyEntity {
DECLARE_CLASS(CServerOnlyPointEntity, CServerOnlyEntity);
public:
virtual bool KeyValue(const char *szKeyName, const char *szValue);
};
// Has no position or size
class CLogicalEntity : public CServerOnlyEntity {
DECLARE_CLASS(CLogicalEntity, CServerOnlyEntity);
public:
virtual bool KeyValue(const char *szKeyName, const char *szValue);
};
// Network proxy functions
void SendProxy_Origin(const SendProp *pProp, const void *pStruct,
const void *pData, DVariant *pOut, int iElement,
int objectID);
void SendProxy_OriginXY(const SendProp *pProp, const void *pStruct,
const void *pData, DVariant *pOut, int iElement,
int objectID);
void SendProxy_OriginZ(const SendProp *pProp, const void *pStruct,
const void *pData, DVariant *pOut, int iElement,
int objectID);
#endif // BASEENTITY_H