//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: A base class for the client-side representation of entities. // // This class encompasses both entities that are created on the //server and networked to the client AND entities that are created on the // client. // // $NoKeywords: $ //===========================================================================// #ifndef C_BASEENTITY_H #define C_BASEENTITY_H #ifdef _WIN32 #pragma once #endif #include "../../public/client_class.h" #include "../../public/engine/ivmodelinfo.h" #include "../../public/engine/ivmodelrender.h" #include "../../public/iclientunknown.h" #include "../../public/mathlib/vector.h" #include "../shared/ehandle.h" #include "client_thinklist.h" #include "icliententityinternal.h" #include "iclientshadowmgr.h" #if !defined(NO_ENTITY_PREDICTION) #include "../shared/predictableid.h" #endif #include "../../public/networkvar.h" #include "../../public/soundflags.h" #include "../shared/shareddefs.h" #include "collisionproperty.h" #include "interpolatedvar.h" #include "particle_property.h" #include "tier0/threadtools.h" #include "toolframework/itoolentity.h" class C_Team; class IPhysicsObject; class IClientVehicle; class CPredictionCopy; class C_BasePlayer; struct studiohdr_t; class CStudioHdr; class CDamageModifier; class IRecipientFilter; class CUserCmd; struct solid_t; class ISave; class IRestore; class C_BaseAnimating; class C_AI_BaseNPC; struct EmitSound_t; class C_RecipientFilter; class CTakeDamageInfo; class C_BaseCombatCharacter; class CEntityMapData; class ConVar; class CDmgAccumulator; class IHasAttributes; struct CSoundParameters; typedef unsigned int AimEntsListHandle_t; #define INVALID_AIMENTS_LIST_HANDLE (AimEntsListHandle_t) ~0 extern void RecvProxy_IntToColor32(const CRecvProxyData *pData, void *pStruct, void *pOut); extern void RecvProxy_LocalVelocity(const CRecvProxyData *pData, void *pStruct, void *pOut); enum CollideType_t { ENTITY_SHOULD_NOT_COLLIDE = 0, ENTITY_SHOULD_COLLIDE, ENTITY_SHOULD_RESPOND }; class VarMapEntry_t { public: unsigned short type; unsigned short m_bNeedsToInterpolate; // Set to false when this var doesn't // need Interpolate() called on it anymore. void *data; IInterpolatedVar *watcher; }; struct VarMapping_t { VarMapping_t() { m_nInterpolatedEntries = 0; } CUtlVector m_Entries; int m_nInterpolatedEntries; float m_lastInterpolationTime; }; #define DECLARE_INTERPOLATION() // How many data slots to use when in multiplayer. #define MULTIPLAYER_BACKUP 90 struct serialentity_t; typedef CHandle EHANDLE; // The client's version of EHANDLE. typedef void (C_BaseEntity::*BASEPTR)(void); typedef void (C_BaseEntity::*ENTITYFUNCPTR)(C_BaseEntity *pOther); // For entity creation on the client typedef C_BaseEntity *(*DISPATCHFUNCTION)(void); #include "groundlink.h" #include "touchlink.h" #if !defined(NO_ENTITY_PREDICTION) //----------------------------------------------------------------------------- // Purpose: For fully client side entities we use this information to determine // authoritatively if the server has acknowledged creating this entity, etc. //----------------------------------------------------------------------------- struct PredictionContext { PredictionContext() { m_bActive = false; m_nCreationCommandNumber = -1; m_pszCreationModule = NULL; m_nCreationLineNumber = 0; m_hServerEntity = NULL; } // The command_number of the usercmd which created this entity bool m_bActive; int m_nCreationCommandNumber; char const *m_pszCreationModule; int m_nCreationLineNumber; // The entity to whom we are attached CHandle m_hServerEntity; }; #endif //----------------------------------------------------------------------------- // Purpose: think contexts //----------------------------------------------------------------------------- struct thinkfunc_t { BASEPTR m_pfnThink; string_t m_iszContext; int m_nNextThinkTick; int m_nLastThinkTick; }; #define CREATE_PREDICTED_ENTITY(className) \ C_BaseEntity::CreatePredictedEntityByName(className, __FILE__, __LINE__); // Entity flags that only exist on the client. #define ENTCLIENTFLAG_GETTINGSHADOWRENDERBOUNDS \ 0x0001 // Tells us if we're getting the real ent render bounds or the // shadow render bounds. #define ENTCLIENTFLAG_DONTUSEIK \ 0x0002 // Don't use IK on this entity even if its model has IK. #define ENTCLIENTFLAG_ALWAYS_INTERPOLATE 0x0004 // Used by view models. //----------------------------------------------------------------------------- // Purpose: Base client side entity object //----------------------------------------------------------------------------- class C_BaseEntity : public IClientEntity { // Construction DECLARE_CLASS_NOBASE(C_BaseEntity); friend class CPrediction; friend void cc_cl_interp_all_changed(IConVar *pConVar, const char *pOldString, float flOldValue); public: DECLARE_DATADESC(); DECLARE_CLIENTCLASS(); DECLARE_PREDICTABLE(); C_BaseEntity(); virtual ~C_BaseEntity(); static C_BaseEntity *CreatePredictedEntityByName(const char *classname, const char *module, int line, bool persist = false); // FireBullets uses shared code for prediction. virtual void FireBullets(const FireBulletsInfo_t &info); virtual void ModifyFireBulletsDamage(CTakeDamageInfo *dmgInfo) {} virtual bool ShouldDrawUnderwaterBulletBubbles(); virtual bool ShouldDrawWaterImpacts(void) { return true; } virtual bool HandleShotImpactingWater(const FireBulletsInfo_t &info, const Vector &vecEnd, ITraceFilter *pTraceFilter, Vector *pVecTracerDest); virtual ITraceFilter *GetBeamTraceFilter(void); virtual void DispatchTraceAttack(const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL); virtual void TraceAttack(const CTakeDamageInfo &info, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator = NULL); virtual void DoImpactEffect(trace_t &tr, int nDamageType); virtual void MakeTracer(const Vector &vecTracerSrc, const trace_t &tr, int iTracerType); virtual int GetTracerAttachment(void); void ComputeTracerStartPosition(const Vector &vecShotSrc, Vector *pVecTracerStart); void TraceBleed(float flDamage, const Vector &vecDir, trace_t *ptr, int bitsDamageType); virtual int BloodColor(); virtual const char *GetTracerType(); virtual void Spawn(void); virtual void SpawnClientEntity(void); virtual void Precache(void); virtual void Activate(); 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); // 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); void Interp_SetupMappings(VarMapping_t *map); // Returns 1 if there are no more changes (ie: we could call // RemoveFromInterpolationList). int Interp_Interpolate(VarMapping_t *map, float currentTime); void Interp_RestoreToLastNetworked(VarMapping_t *map); void Interp_UpdateInterpolationAmounts(VarMapping_t *map); void Interp_HierarchyUpdateInterpolationAmounts(); // Called by the CLIENTCLASS macros. virtual bool Init(int entnum, int iSerialNum); // Called in the destructor to shutdown everything. void Term(); // memory handling, uses calloc so members are zero'd out on instantiation void *operator new(size_t stAllocateBlock); void *operator new[](size_t stAllocateBlock); void *operator new(size_t stAllocateBlock, int nBlockUse, const char *pFileName, int nLine); 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); } // This just picks one of the routes to IClientUnknown. IClientUnknown *GetIClientUnknown() { return this; } virtual C_BaseAnimating *GetBaseAnimating() { return NULL; } virtual void SetClassname(const char *className); string_t m_iClassname; // IClientUnknown overrides. public: virtual void SetRefEHandle(const CBaseHandle &handle); virtual const CBaseHandle &GetRefEHandle() const; void SetToolHandle(HTOOLHANDLE handle); HTOOLHANDLE GetToolHandle() const; void EnableInToolView(bool bEnable); bool IsEnabledInToolView() const; void SetToolRecording(bool recording); bool IsToolRecording() const; bool HasRecordedThisFrame() const; virtual void RecordToolMessage(); // used to exclude entities from being recorded in the SFM tools void DontRecordInTools(); bool ShouldRecordInTools() const; virtual void Release(); virtual ICollideable *GetCollideable() { return &m_Collision; } virtual IClientNetworkable *GetClientNetworkable() { return this; } virtual IClientRenderable *GetClientRenderable() { return this; } virtual IClientEntity *GetIClientEntity() { return this; } virtual C_BaseEntity *GetBaseEntity() { return this; } virtual IClientThinkable *GetClientThinkable() { return this; } // Methods of IClientRenderable public: virtual const Vector &GetRenderOrigin(void); virtual const QAngle &GetRenderAngles(void); virtual Vector GetObserverCamOrigin(void) { return GetRenderOrigin(); } // Return the origin for player observers tracking this target virtual const matrix3x4_t &RenderableToWorldTransform(); virtual bool IsTransparent(void); virtual bool IsTwoPass(void); virtual bool UsesPowerOfTwoFrameBufferTexture(); virtual bool UsesFullFrameBufferTexture(); virtual bool IgnoresZBuffer(void) const; virtual const model_t *GetModel(void) const; virtual int DrawModel(int flags); virtual void ComputeFxBlend(void); virtual int GetFxBlend(void); virtual bool LODTest() { return true; } // NOTE: UNUSED virtual void GetRenderBounds(Vector &mins, Vector &maxs); virtual IPVSNotify *GetPVSNotifyInterface(); virtual void GetRenderBoundsWorldspace(Vector &absMins, Vector &absMaxs); virtual void GetShadowRenderBounds(Vector &mins, Vector &maxs, ShadowType_t shadowType); // Determine the color modulation amount virtual void GetColorModulation(float *color); virtual void OnThreadedDrawSetup() {} public: virtual bool TestCollision(const Ray_t &ray, unsigned int fContentsMask, trace_t &tr); virtual bool TestHitboxes(const Ray_t &ray, unsigned int fContentsMask, trace_t &tr); // To mimic server call convention C_BaseEntity *GetOwnerEntity(void) const; void SetOwnerEntity(C_BaseEntity *pOwner); C_BaseEntity *GetEffectEntity(void) const; void SetEffectEntity(C_BaseEntity *pEffectEnt); // 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(void); // IClientNetworkable implementation. public: virtual void NotifyShouldTransmit(ShouldTransmitState_t state); // save out interpolated values virtual void PreDataUpdate(DataUpdateType_t updateType); virtual void PostDataUpdate(DataUpdateType_t updateType); virtual void OnDataUnchangedInPVS(); virtual void ValidateModelIndex(void); // pvs info. NOTE: Do not override these!! virtual void SetDormant(bool bDormant); virtual bool IsDormant(void); // Tells the entity that it's about to be destroyed due to the client // receiving an uncompressed update that's caused it to destroy all entities // & recreate them. virtual void SetDestroyedOnRecreateEntities(void); virtual int GetEFlags() const; virtual void SetEFlags(int iEFlags); void AddEFlags(int nEFlagMask); void RemoveEFlags(int nEFlagMask); bool IsEFlagSet(int nEFlagMask) const; // checks to see if the entity is marked for deletion bool IsMarkedForDeletion(void); virtual int entindex(void) const; // This works for client-only entities and returns the GetEntryIndex() of // the entity's handle, so the sound system can get an IClientEntity from // it. int GetSoundSourceIndex() const; // Server to client message received virtual void ReceiveMessage(int classID, bf_read &msg); virtual void *GetDataTableBasePtr(); // IClientThinkable. public: // Called whenever you registered for a think message (with // SetNextClientThink). virtual void ClientThink(); virtual ClientThinkHandle_t GetThinkHandle(); virtual void SetThinkHandle(ClientThinkHandle_t hThink); public: void AddVar(void *data, IInterpolatedVar *watcher, int type, bool bSetup = false); void RemoveVar(void *data, bool bAssert = true); VarMapping_t *GetVarMapping(); VarMapping_t m_VarMap; public: // An inline version the game code can use CCollisionProperty *CollisionProp(); const CCollisionProperty *CollisionProp() const; CParticleProperty *ParticleProp(); const CParticleProperty *ParticleProp() const; // Simply here for game shared bool IsFloating(); virtual bool ShouldSavePhysics(); // save/restore stuff virtual void OnSave(); virtual void OnRestore(); // capabilities for save/restore virtual int ObjectCaps(void); // only overload these if you have special data to serialize virtual int Save(ISave &save); virtual int Restore(IRestore &restore); private: int SaveDataDescBlock(ISave &save, datamap_t *dmap); int RestoreDataDescBlock(IRestore &restore, datamap_t *dmap); // Called after restoring data into prediction slots. This function is used // in place of proxies on the variables, so if some variable like // m_nModelIndex needs to update other state (like the model pointer), it is // done here. void OnPostRestoreData(); public: // 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 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); 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); // Purpose: My physics object has been updated, react or extract data virtual void VPhysicsUpdate(IPhysicsObject *pPhysics); inline IPhysicsObject *VPhysicsGetObject(void) const { return m_pPhysicsObject; } virtual int VPhysicsGetObjectList(IPhysicsObject **pList, int listMax); virtual bool VPhysicsIsFlesh(void); // IClientEntity implementation. public: virtual bool SetupBones(matrix3x4_t *pBoneToWorldOut, int nMaxBones, int boneMask, float currentTime); virtual void SetupWeights(const matrix3x4_t *pBoneToWorld, int nFlexWeightCount, float *pFlexWeights, float *pFlexDelayedWeights); virtual bool UsesFlexDelayedWeights() { return false; } virtual void DoAnimationEvents(void); // Add entity to visible entities list? virtual void AddEntity(void); virtual const Vector &GetAbsOrigin(void) const; virtual const QAngle &GetAbsAngles(void) const; const Vector &GetNetworkOrigin() const; const QAngle &GetNetworkAngles() const; void SetNetworkOrigin(const Vector &org); void SetNetworkAngles(const QAngle &ang); const Vector &GetLocalOrigin(void) const; void SetLocalOrigin(const Vector &origin); vec_t GetLocalOriginDim(int iDim) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here. void SetLocalOriginDim(int iDim, vec_t flValue); const QAngle &GetLocalAngles(void) const; void SetLocalAngles(const QAngle &angles); vec_t GetLocalAnglesDim(int iDim) const; // You can use the X_INDEX, Y_INDEX, and Z_INDEX defines here. void SetLocalAnglesDim(int iDim, vec_t flValue); virtual const Vector &GetPrevLocalOrigin() const; virtual const QAngle &GetPrevLocalAngles() const; void SetLocalTransform(const matrix3x4_t &localTransform); void SetModelName(string_t name); string_t GetModelName(void) const; int GetModelIndex(void) const; void SetModelIndex(int index); virtual int CalcOverrideModelIndex() { return -1; } // 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 virtual const Vector &WorldAlignMins() const; virtual const Vector &WorldAlignMaxs() const; // This defines collision bounds *in whatever space is currently defined by // the solid type* // SOLID_BBOX: World Align // SOLID_OBB: Entity space // SOLID_BSP: Entity space // SOLID_VPHYSICS Not used void SetCollisionBounds(const Vector &mins, const Vector &maxs); // NOTE: These use the collision OBB to compute a reasonable center point // for the entity virtual const Vector &WorldSpaceCenter() const; // FIXME: Do we want this? const Vector &WorldAlignSize() const; bool IsPointSized() 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; // Used when the collision prop is told to ask game code for the world-space // surrounding box virtual void ComputeWorldSpaceSurroundingBox(Vector *pVecWorldMins, Vector *pVecWorldMaxs); virtual float GetHealthBarHeightOffset() const { return 0.f; } // 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); void GetVectors(Vector *forward, Vector *right, Vector *up) const; // Sets abs angles, but also sets local angles to be appropriate void SetAbsOrigin(const Vector &origin); void SetAbsAngles(const QAngle &angles); void AddFlag(int flags); void RemoveFlag(int flagsToRemove); void ToggleFlag(int flagToToggle); int GetFlags(void) const; void ClearFlags(); MoveType_t GetMoveType(void) const; MoveCollide_t GetMoveCollide(void) const; virtual SolidType_t GetSolid(void) const; virtual int GetSolidFlags(void) const; bool IsSolidFlagSet(int flagMask) const; void SetSolidFlags(int nFlags); void AddSolidFlags(int nFlags); void RemoveSolidFlags(int nFlags); bool IsSolid() const; virtual class CMouthInfo *GetMouth(void); // Retrieve sound spatialization info for the specified sound on this entity // Return false to indicate sound is not audible virtual bool GetSoundSpatialization(SpatializationInfo_t &info); // Attachments virtual int LookupAttachment(const char *pAttachmentName) { return -1; } virtual bool GetAttachment(int number, matrix3x4_t &matrix); virtual bool GetAttachment(int number, Vector &origin); virtual bool GetAttachment(int number, Vector &origin, QAngle &angles); virtual bool GetAttachmentVelocity(int number, Vector &originVel, Quaternion &angleVel); // Team handling virtual C_Team *GetTeam(void); virtual int GetTeamNumber(void) const; virtual void ChangeTeam(int iTeamNum); // Assign this entity to a team. virtual int GetRenderTeamNumber(void); virtual bool InSameTeam( C_BaseEntity *pEntity); // Returns true if the specified entity is on // the same team as this one virtual bool InLocalTeam(void); // ID Target handling virtual bool IsValidIDTarget(void) { return false; } virtual const char *GetIDString(void) { return ""; }; // See CSoundEmitterSystem virtual void ModifyEmitSoundParams(EmitSound_t ¶ms); void EmitSound( const char *soundname, float soundtime = 0.0f, float *duration = NULL); // Override for doing the general case of // CPASAttenuationFilter( 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( 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); static float GetSoundDuration(const char *soundname, char const *actormodel); static bool GetParametersForSound(const char *soundname, CSoundParameters ¶ms, const char *actormodel); static bool GetParametersForSound(const char *soundname, HSOUNDSCRIPTHANDLE &handle, CSoundParameters ¶ms, const char *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 ¶ms); static void EmitSound(IRecipientFilter &filter, int iEntIndex, const EmitSound_t ¶ms, 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(C_RecipientFilter &filter); static void EmitCloseCaption(IRecipientFilter &filter, int entindex, char const *token, CUtlVector &soundorigins, float duration, bool warnifmissing = false); // Moves all aiments into their correct position for the frame static void MarkAimEntsDirty(); static void CalcAimEntPositions(); static bool IsPrecacheAllowed(); static void SetAllowPrecache(bool allow); static bool m_bAllowPrecache; static bool IsSimulatingOnAlternateTicks(); // C_BaseEntity local functions public: void UpdatePartitionListEntry(); // This can be used to setup the entity as a client-only entity. // Override this to perform per-entity clientside setup virtual bool InitializeAsClientEntity(const char *pszModelName, RenderGroup_t renderGroup); // This function gets called on all client entities once per simulation // phase. It dispatches events like OnDataChanged(), and calls the legacy // function AddEntity(). virtual void Simulate(); // This event is triggered during the simulation phase if an entity's data // has changed. It is better to hook this instead of PostDataUpdate() // because in PostDataUpdate(), server entity origins are incorrect and // attachment points can't be used. virtual void OnDataChanged(DataUpdateType_t type); // This is called once per frame before any data is read in from the server. virtual void OnPreDataChanged(DataUpdateType_t type); bool IsStandable() const; bool IsBSPModel() const; // If this is a vehicle, returns the vehicle interface virtual IClientVehicle *GetClientVehicle() { return NULL; } // Returns the aiment render origin + angles virtual void GetAimEntOrigin(IClientEntity *pAttachedTo, Vector *pAbsOrigin, QAngle *pAbsAngles); // get network origin from previous update virtual const Vector &GetOldOrigin(); // Methods relating to traversing hierarchy C_BaseEntity *GetMoveParent(void) const; C_BaseEntity *GetRootMoveParent(); C_BaseEntity *FirstMoveChild(void) const; C_BaseEntity *NextMovePeer(void) const; inline ClientEntityHandle_t GetClientHandle() const { return ClientEntityHandle_t(m_RefEHandle); } inline bool IsServerEntity(void); virtual RenderGroup_t GetRenderGroup(); virtual void GetToolRecordingState(KeyValues *msg); virtual void CleanupToolRecordingState(KeyValues *msg); // The value returned by here determines whether or not (and how) the entity // is put into the spatial partition. virtual CollideType_t GetCollideType(void); virtual bool ShouldDraw(); inline bool IsVisible() const { return m_hRender != INVALID_CLIENT_RENDER_HANDLE; } virtual void UpdateVisibility(); // Returns true if the entity changes its position every frame on the server // but it doesn't set animtime. In that case, the client returns true here // so it copies the server time to animtime in OnDataChanged and the // position history is correct for interpolation. virtual bool IsSelfAnimating(); // Set appropriate flags and store off data when these fields are about to // change virtual void OnLatchInterpolatedVariables(int flags); // For predictable entities, stores last networked value void OnStoreLastNetworkedValue(); // Initialize things given a new model. virtual CStudioHdr *OnNewModel(); virtual void OnNewParticleEffect(const char *pszParticleName, CNewParticleEffect *pNewParticleEffect); bool IsSimulatedEveryTick() const; bool IsAnimatedEveryTick() const; void SetSimulatedEveryTick(bool sim); void SetAnimatedEveryTick(bool anim); void Interp_Reset(VarMapping_t *map); virtual void ResetLatched(); float GetInterpolationAmount(int flags); float GetLastChangeTime(int flags); // Interpolate the position for rendering virtual bool Interpolate(float currentTime); // Did the object move so far that it shouldn't interpolate? bool Teleported(void); // Is this a submodel of the world ( *1 etc. in name ) ( brush models only ) virtual bool IsSubModel(void); // Deal with EF_* flags virtual void CreateLightEffects(void); void AddToAimEntsList(); void RemoveFromAimEntsList(); // Reset internal fields virtual void Clear(void); // Helper to draw raw brush models virtual int DrawBrushModel(bool bTranslucent, int nFlags, bool bTwoPass); // returns the material animation start time virtual float GetTextureAnimationStartTime(); // Indicates that a texture animation has wrapped virtual void TextureAnimationWrapped(); // Set the next think time. Pass in CLIENT_THINK_ALWAYS to have Think() // called each frame. virtual void SetNextClientThink(float nextThinkTime); // anything that has health can override this... virtual void SetHealth(int iHealth) {} virtual int GetHealth() const { return 0; } virtual int GetMaxHealth() const { return 1; } virtual bool IsVisibleToTargetID(void) const { return false; } virtual bool IsHealthBarVisible(void) const { return false; } // Returns the health fraction float HealthFraction() const; // Should this object cast shadows? virtual ShadowType_t ShadowCastType(); // Should this object receive shadows? virtual bool ShouldReceiveProjectedTextures(int flags); // Shadow-related methods virtual bool IsShadowDirty(); virtual void MarkShadowDirty(bool bDirty); virtual IClientRenderable *GetShadowParent(); virtual IClientRenderable *FirstShadowChild(); virtual IClientRenderable *NextShadowPeer(); // Sets up a render handle so the leaf system will draw this entity. void AddToLeafSystem(); void AddToLeafSystem(RenderGroup_t group); // remove entity form leaf system again void RemoveFromLeafSystem(); // A method to apply a decal to an entity virtual void AddDecal(const Vector &rayStart, const Vector &rayEnd, const Vector &decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t &tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS); virtual void AddColoredDecal(const Vector &rayStart, const Vector &rayEnd, const Vector &decalCenter, int hitbox, int decalIndex, bool doTrace, trace_t &tr, Color cColor, int maxLODToDecal = ADDDECAL_TO_ALL_LODS); // A method to remove all decals from an entity void RemoveAllDecals(void); // Is this a brush model? bool IsBrushModel() const; // A random value 0-1 used by proxies to make sure they're not all in sync float ProxyRandomValue() const { return m_flProxyRandomValue; } // The spawn time of this entity float SpawnTime() const { return m_flSpawnTime; } virtual bool IsClientCreated(void) const; virtual void UpdateOnRemove(void); virtual void SUB_Remove(void); // Prediction stuff ///////////////// void CheckInitPredictable(const char *context); void AllocateIntermediateData(void); void DestroyIntermediateData(void); void ShiftIntermediateDataForward(int slots_to_remove, int previous_last_slot); void *GetPredictedFrame(int framenumber); void *GetOriginalNetworkDataObject(void); bool IsIntermediateDataAllocated(void) const; void InitPredictable(void); void ShutdownPredictable(void); virtual void SetPredictable(bool state); bool GetPredictable(void) const; void PreEntityPacketReceived(int commands_acknowledged); void PostEntityPacketReceived(void); bool PostNetworkDataReceived(int commands_acknowledged); bool GetPredictionEligible(void) const; void SetPredictionEligible(bool canpredict); enum { SLOT_ORIGINALDATA = -1, }; int SaveData(const char *context, int slot, int type); virtual int RestoreData(const char *context, int slot, int type); 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); virtual bool ShouldPredict(void) { return false; }; // interface function pointers void (C_BaseEntity::*m_pfnThink)(void); virtual void Think(void) { AssertMsg(m_pfnThink != &C_BaseEntity::Think, "Infinite recursion is infinitely bad."); if (m_pfnThink) { (this->*m_pfnThink)(); } } void PhysicsDispatchThink(BASEPTR thinkFunc); // Toggle the visualization of the entity's abs/bbox enum { VISUALIZE_COLLISION_BOUNDS = 0x1, VISUALIZE_SURROUNDING_BOUNDS = 0x2, VISUALIZE_RENDER_BOUNDS = 0x4, }; void ToggleBBoxVisualization(int fVisFlags); void DrawBBoxVisualizations(void); // Methods implemented on both client and server public: void SetSize(const Vector &vecMin, const Vector &vecMax); // UTIL_SetSize( pev, mins, maxs ); char const *GetClassname(void); char const *GetDebugName(void); static int PrecacheModel(const char *name); static bool PrecacheSound(const char *name); static void PrefetchSound(const char *name); void Remove(); // UTIL_Remove( this ); public: // Returns the attachment point index on our parent that our transform is // relative to. 0 if we're relative to the parent's absorigin and absangles. unsigned char GetParentAttachment() const; // 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); // Determine approximate velocity based on updates from server void EstimateAbsVelocity(Vector &vel); #if !defined(NO_ENTITY_PREDICTION) // The player drives simulation of this entity void SetPlayerSimulated(C_BasePlayer *pOwner); bool IsPlayerSimulated(void) const; CBasePlayer *GetSimulatingPlayer(void); void UnsetPlayerSimulated(void); #endif // Sorry folks, here lies TF2-specific stuff that really has no other place // to go virtual bool CanBePoweredUp(void) { return false; } virtual bool AttemptToPowerup(int iPowerup, float flTime, float flAmount = 0, C_BaseEntity *pAttacker = NULL, CDamageModifier *pDamageModifier = NULL) { return false; } void SetCheckUntouch(bool check); bool GetCheckUntouch() const; virtual bool IsCurrentlyTouching(void) const; virtual void StartTouch(C_BaseEntity *pOther); virtual void Touch(C_BaseEntity *pOther); virtual void EndTouch(C_BaseEntity *pOther); void (C_BaseEntity ::*m_pfnTouch)(C_BaseEntity *pOther); void PhysicsStep(void); protected: static bool sm_bDisableTouchFuncs; // Disables PhysicsTouch and // PhysicsStartTouch function calls public: touchlink_t *PhysicsMarkEntityAsTouched(C_BaseEntity *other); void PhysicsTouch(C_BaseEntity *pentOther); void PhysicsStartTouch(C_BaseEntity *pentOther); // 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(C_BaseEntity *other, trace_t &trace); void PhysicsMarkEntitiesAsTouching(C_BaseEntity *other, trace_t &trace); void PhysicsMarkEntitiesAsTouchingEventDriven(C_BaseEntity *other, trace_t &trace); // Physics helper static void PhysicsRemoveTouchedList(C_BaseEntity *ent); static void PhysicsNotifyOtherOfUntouch(C_BaseEntity *ent, C_BaseEntity *other); static void PhysicsRemoveToucher(C_BaseEntity *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(); bool PhysicsCheckWater(void); void PhysicsCheckVelocity(void); void PhysicsAddHalfGravity(float timestep); void PhysicsAddGravityMove(Vector &move); virtual unsigned int PhysicsSolidMaskForEntity(void) const; void SetGroundEntity(C_BaseEntity *ground); C_BaseEntity *GetGroundEntity(void); void PhysicsPushEntity(const Vector &push, trace_t *pTrace); void PhysicsCheckWaterTransition(void); // 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); void ResolveFlyCollisionCustom(trace_t &trace, Vector &vecVelocity); void PhysicsCheckForEntityUntouch(void); // Creates the shadow (if it doesn't already exist) based on shadow cast // type void CreateShadow(); // Destroys the shadow; causes its type to be recomputed if the entity // doesn't go away immediately. void DestroyShadow(); protected: // think function handling enum thinkmethods_t { THINK_FIRE_ALL_FUNCTIONS, THINK_FIRE_BASE_ONLY, THINK_FIRE_ALL_BUT_BASE, }; public: // Unlinks from hierarchy // 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. void SetParent(C_BaseEntity *pParentEntity, int iParentAttachment = 0); bool PhysicsRunThink(thinkmethods_t thinkMethod = THINK_FIRE_ALL_FUNCTIONS); bool PhysicsRunSpecificThink(int nContextIndex, BASEPTR thinkFunc); virtual void PhysicsSimulate(void); virtual bool IsAlive(void); bool IsInWorld(void) { return true; } bool IsWorld() { return entindex() == 0; } ///////////////// virtual bool IsPlayer(void) const { return false; }; virtual bool IsBaseCombatCharacter(void) { return false; }; virtual C_BaseCombatCharacter *MyCombatCharacterPointer(void) { return NULL; } virtual bool IsNPC(void) { return false; } C_AI_BaseNPC *MyNPCPointer(void); virtual bool IsNextBot() { return false; } // TF2 specific virtual bool IsBaseObject(void) const { return false; } virtual bool IsBaseCombatWeapon(void) const { return false; } virtual class C_BaseCombatWeapon *MyCombatWeaponPointer() { return NULL; } virtual bool IsCombatItem(void) const { return false; } virtual bool IsBaseTrain(void) const { return false; } // Returns the eye point + angles (used for viewing + shooting) virtual Vector EyePosition(void); virtual const QAngle &EyeAngles(void); // Direction of eyes virtual const QAngle &LocalEyeAngles( void); // Direction of eyes in local space (pl.v_angle) // position of ears virtual Vector EarPosition(void); 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 // Called by physics to see if we should avoid a collision test.... virtual bool ShouldCollide(int collisionGroup, int contentsMask) const; // Sets physics parameters void SetFriction(float flFriction); void SetGravity(float flGravity); float GetGravity(void) const; // Sets the model from a model index void SetModelByIndex(int nModelIndex); // Set model... (NOTE: Should only be used by client-only entities // Returns false if the model name is bogus or otherwise can't be loaded bool SetModel(const char *pModelName); void SetModelPointer(const model_t *pModel); // Access movetype and solid. void SetMoveType( MoveType_t val, MoveCollide_t moveCollide = MOVECOLLIDE_DEFAULT); // Set to one of the MOVETYPE_ defines. void SetMoveCollide( MoveCollide_t val); // Set to one of the MOVECOLLIDE_ defines. void SetSolid(SolidType_t val); // Set to one of the SOLID_ defines. // 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 SetAbsVelocity(const Vector &vecVelocity); const Vector &GetLocalVelocity() const; const Vector &GetAbsVelocity() const; void ApplyLocalVelocityImpulse(const Vector &vecImpulse); void ApplyAbsVelocityImpulse(const Vector &vecImpulse); void ApplyLocalAngularVelocityImpulse(const AngularImpulse &angImpulse); // 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; // void SetAbsAngularVelocity( const QAngle &vecAngAbsVelocity //); const QAngle& GetAbsAngularVelocity( ) const; const Vector &GetBaseVelocity() const; void SetBaseVelocity(const Vector &v); virtual const Vector &GetViewOffset() const; virtual void SetViewOffset(const Vector &v); #ifdef SIXENSE const Vector &GetEyeOffset() const; void SetEyeOffset(const Vector &v); const QAngle &GetEyeAngleOffset() const; void SetEyeAngleOffset(const QAngle &qa); #endif // Invalidates the abs state of all children void InvalidatePhysicsRecursive(int nChangeFlags); ClientRenderHandle_t GetRenderHandle() const; void SetRemovalFlag(bool bRemove); // Effects... bool IsEffectActive(int nEffectMask) const; void AddEffects(int nEffects); void RemoveEffects(int nEffects); int GetEffects(void) const; void ClearEffects(void); void SetEffects(int nEffects); // 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); // 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(); // For shadows rendering the correct body + sequence... virtual int GetBody() { return 0; } virtual int GetSkin() { return 0; } // Stubs on client void NetworkStateManualMode(bool activate) {} void NetworkStateChanged() {} void NetworkStateChanged(void *pVar) {} void NetworkStateSetUpdateInterval(float N) {} void NetworkStateForceUpdate() {} // 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); // These set entity flags (EFL_*) to help optimize queries void CheckHasThinkFunction(bool isThinkingHint = false); void CheckHasGamePhysicsSimulation(); bool WillThink(); bool WillSimulateGamePhysics(); int GetFirstThinkTick(); // get first tick thinking on any context float GetAnimTime() const; void SetAnimTime(float at); float GetSimulationTime() const; void SetSimulationTime(float st); float GetCreateTime() { return m_flCreateTime; } void SetCreateTime(float flCreateTime) { m_flCreateTime = flCreateTime; } int GetCreationTick() const; #ifdef _DEBUG void FunctionCheck(void *pFunction, const char *name); ENTITYFUNCPTR TouchSet(ENTITYFUNCPTR func, char *name) { // COMPILE_TIME_ASSERT( sizeof(func) == 4 ); m_pfnTouch = func; // FunctionCheck( *(reinterpret_cast(&m_pfnTouch)), name ); return func; } #endif // Gets the model instance + shadow handle virtual ModelInstanceHandle_t GetModelInstance() { return m_ModelInstance; } void SetModelInstance(ModelInstanceHandle_t hInstance) { m_ModelInstance = hInstance; } bool SnatchModelInstance(C_BaseEntity *pToEntity); virtual ClientShadowHandle_t GetShadowHandle() const { return m_ShadowHandle; } virtual ClientRenderHandle_t &RenderHandle(); void CreateModelInstance(); // Sets the origin + angles to match the last position received void MoveToLastReceivedPosition(bool force = false); // 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; // Only meant to be called from subclasses void DestroyModelInstance(); // Interpolate entity static void ProcessTeleportList(); static void ProcessInterpolatedList(); static void CheckInterpolatedVarParanoidMeasurement(); // overrideable rules if an entity should interpolate virtual bool ShouldInterpolate(); // Call this in OnDataChanged if you don't chain it down! void MarkMessageReceived(); // Gets the last message time float GetLastMessageTime() const { return m_flLastMessageTime; } // For non-players int PhysicsClipVelocity(const Vector &in, const Vector &normal, Vector &out, float overbounce); // Allow entities to perform client-side fades virtual unsigned char GetClientSideFade() { return 255; } protected: // Two part guts of Interpolate(). Shared with C_BaseAnimating. enum { INTERPOLATE_STOP = 0, INTERPOLATE_CONTINUE }; // Returns INTERPOLATE_STOP or INTERPOLATE_CONTINUE. // bNoMoreChanges is set to 1 if you can call RemoveFromInterpolationList on // the entity. int BaseInterpolatePart1(float ¤tTime, Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int &bNoMoreChanges); void BaseInterpolatePart2(Vector &oldOrigin, QAngle &oldAngles, Vector &oldVel, int nChangeFlags); public: // Accessors for above static int GetPredictionRandomSeed(bool bUseUnSyncedServerPlatTime = false); static void SetPredictionRandomSeed(const CUserCmd *cmd); static C_BasePlayer *GetPredictionPlayer(void); static void SetPredictionPlayer(C_BasePlayer *player); static void CheckCLInterpChanged(); // Collision group accessors int GetCollisionGroup() const; void SetCollisionGroup(int collisionGroup); void CollisionRulesChanged(); static C_BaseEntity *Instance(int iEnt); // Doesn't do much, but helps with trace results static C_BaseEntity *Instance(IClientEntity *ent); static C_BaseEntity *Instance(CBaseHandle hEnt); // For debugging shared code static bool IsServer(void); static bool IsClient(void); static char const *GetDLLType(void); static void SetAbsQueriesValid(bool bValid); static bool IsAbsQueriesValid(void); // Enable/disable abs recomputations on a stack. static void PushEnableAbsRecomputations(bool bEnable); static void PopEnableAbsRecomputations(); // This requires the abs recomputation stack to be empty and just sets the // global state. It should only be used at the scope of the frame loop. static void EnableAbsRecomputations(bool bEnable); static bool IsAbsRecomputationsEnabled(void); // Bloat the culling bbox past the parent ent's bbox in local space if // EF_BONEMERGE_FASTCULL is set. virtual void BoneMergeFastCullBloat(Vector &localMins, Vector &localMaxs, const Vector &thisEntityMins, const Vector &thisEntityMaxs) const; // Accessors for color. 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); void SetRenderMode(RenderMode_t nRenderMode, bool bForceUpdate = false); RenderMode_t GetRenderMode() const; public: // Determine what entity this corresponds to int index; // Render information unsigned char m_nRenderFX; unsigned char m_nRenderFXBlend; // Entity flags that are only for the client (ENTCLIENTFLAG_ defines). unsigned short m_EntClientFlags; CNetworkColor32(m_clrRender); private: // Model for rendering const model_t *model; public: // Time animation sequence or frame was last changed float m_flAnimTime; float m_flOldAnimTime; float m_flSimulationTime; float m_flOldSimulationTime; float m_flCreateTime; byte m_ubInterpolationFrame; byte m_ubOldInterpolationFrame; private: // Effects to apply int m_fEffects; unsigned char m_nRenderMode; unsigned char m_nOldRenderMode; public: // Used to store the state we were added to the BSP as, so it can // reinsert the entity if the state changes. ClientRenderHandle_t m_hRender; // link into spatial partition // Interpolation says don't draw yet bool m_bReadyToDraw; // Should we be interpolating? static bool IsInterpolationEnabled(); // Should we interpolate this tick? (Used to be EF_NOINTERP) bool IsNoInterpolationFrame(); // int m_nNextThinkTick; int m_nLastThinkTick; // Object model index short m_nModelIndex; #ifdef TF_CLIENT_DLL int m_nModelIndexOverrides[MAX_VISION_MODES]; #endif char m_takedamage; char m_lifeState; int m_iHealth; // was pev->speed float m_flSpeed; // Team Handling int m_iTeamNum; #if !defined(NO_ENTITY_PREDICTION) // Certain entities (projectiles) can be created on the client CPredictableId m_PredictableID; PredictionContext *m_pPredictionContext; #endif // used so we know when things are no longer touching int touchStamp; // Called after predicted entity has been acknowledged so that no longer // needed entity can // be deleted // Return true to force deletion right now, regardless of isbeingremoved virtual bool OnPredictedEntityRemove(bool isbeingremoved, C_BaseEntity *predicted); bool IsDormantPredictable(void) const; bool BecameDormantThisPacket(void) const; void SetDormantPredictable(bool dormant); int GetWaterLevel() const; void SetWaterLevel(int nLevel); int GetWaterType() const; void SetWaterType(int nType); float GetElasticity(void) const; int GetTextureFrameIndex(void); void SetTextureFrameIndex(int iIndex); virtual bool GetShadowCastDistance(float *pDist, ShadowType_t shadowType) const; virtual bool GetShadowCastDirection(Vector *pDirection, ShadowType_t shadowType) const; virtual C_BaseEntity *GetShadowUseOtherEntity(void) const; virtual void SetShadowUseOtherEntity(C_BaseEntity *pEntity); CInterpolatedVar &GetRotationInterpolator(); CInterpolatedVar &GetOriginInterpolator(); virtual bool AddRagdollToFadeQueue(void) { return true; } // Dirty bits void MarkRenderHandleDirty(); // used by SourceTV since move-parents may be missing when child spawns. void HierarchyUpdateMoveParent(); virtual bool IsDeflectable() { return false; } bool IsCombatCharacter() { return MyCombatCharacterPointer() == NULL ? false : true; } protected: int m_nFXComputeFrame; // FIXME: Should I move the functions handling these out of C_ClientEntity // and into C_BaseEntity? Then we could make these private. // Client handle CBaseHandle m_RefEHandle; // Reference ehandle. Used to generate ehandles // off this entity. private: // Set by tools if this entity should route "info" to various tools // listening to HTOOLENTITIES #ifndef NO_TOOLFRAMEWORK bool m_bEnabledInToolView; bool m_bToolRecording; HTOOLHANDLE m_ToolHandle; int m_nLastRecordedFrame; bool m_bRecordInTools; // should this entity be recorded in the tools (we // exclude some things like models for menus) #endif protected: // pointer to the entity's physics object (vphysics.dll) IPhysicsObject *m_pPhysicsObject; #if !defined(NO_ENTITY_PREDICTION) bool m_bPredictionEligible; #endif int m_nSimulationTick; // Think contexts int GetIndexForThinkContext(const char *pszContext); CUtlVector m_aThinkFunctions; int m_iCurrentThinkContext; // Object eye position Vector m_vecViewOffset; #if defined(SIXENSE) Vector m_vecEyeOffset; QAngle m_EyeAngleOffset; #endif // Allow studio models to tell us what their m_nBody value is virtual int GetStudioBody(void) { return 0; } public: // This can be used to setup the entity as a client-only entity. It gets an // entity handle, a render handle, and is put into the spatial partition. bool InitializeAsClientEntityByIndex(int iIndex, RenderGroup_t renderGroup); void TrackAngRotation(bool bTrack); private: friend void OnRenderStart(); // Figure out the smoothly interpolated origin for all server entities. // Happens right before letting all entities simulate. static void InterpolateServerEntities(); // Check which entities want to be drawn and add them to the leaf system. static void AddVisibleEntities(); // For entities marked for recording, post bone messages to IToolSystems static void ToolRecordEntities(); // Computes the base velocity void UpdateBaseVelocity(void); // Physics-related private methods void PhysicsPusher(void); void PhysicsNone(void); void PhysicsNoclip(void); void PhysicsParent(void); void PhysicsStepRunTimestep(float timestep); void PhysicsToss(void); void PhysicsCustom(void); // Simulation in local space of rigid children void PhysicsRigidChild(void); // Computes absolute position based on hierarchy void CalcAbsolutePosition(); void CalcAbsoluteVelocity(); // Computes new angles based on the angular velocity void SimulateAngles(float flFrameTime); // Implement this if you use MOVETYPE_CUSTOM virtual void PerformCustomPhysics(Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity); // methods related to decal adding void AddStudioDecal(const Ray_t &ray, int hitbox, int decalIndex, bool doTrace, trace_t &tr, int maxLODToDecal = ADDDECAL_TO_ALL_LODS); void AddColoredStudioDecal(const Ray_t &ray, int hitbox, int decalIndex, bool doTrace, trace_t &tr, Color cColor, int maxLODToDecal); void AddBrushModelDecal(const Ray_t &ray, const Vector &decalCenter, int decalIndex, bool doTrace, trace_t &tr); void ComputePackedOffsets(void); int ComputePackedSize_R(datamap_t *map); int GetIntermediateDataSize(void); void UnlinkChild(C_BaseEntity *pParent, C_BaseEntity *pChild); void LinkChild(C_BaseEntity *pParent, C_BaseEntity *pChild); void HierarchySetParent(C_BaseEntity *pNewParent); void UnlinkFromHierarchy(); // Computes the water level + type void UpdateWaterState(); // Checks a sweep without actually performing the move void PhysicsCheckSweep(const Vector &vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace); // FIXME: REMOVE!!! void MoveToAimEnt(); // 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; // Object velocity Vector m_vecVelocity; CInterpolatedVar m_iv_vecVelocity; Vector m_vecAbsVelocity; // was pev->avelocity QAngle m_vecAngVelocity; // QAngle m_vecAbsAngVelocity; #if !defined(NO_ENTITY_PREDICTION) // It's still in the list for "fixup purposes" and simulation, but don't try // to render it any more... bool m_bDormantPredictable; // So we can clean it up int m_nIncomingPacketEntityBecameDormant; #endif // The spawn time of the entity float m_flSpawnTime; // Timestamp of message arrival float m_flLastMessageTime; // Base velocity Vector m_vecBaseVelocity; // Gravity multiplier float m_flGravity; // Model instance data.. ModelInstanceHandle_t m_ModelInstance; // Shadow data ClientShadowHandle_t m_ShadowHandle; // A random value used by material proxies for each model instance. float m_flProxyRandomValue; ClientThinkHandle_t m_hThink; int m_iEFlags; // entity flags EFL_* // Object movetype unsigned char m_MoveType; unsigned char m_MoveCollide; unsigned char m_iParentAttachment; // 0 if we're relative to the parent's // absorigin and absangles. unsigned char m_iOldParentAttachment; unsigned char m_nWaterLevel; unsigned char m_nWaterType; // For client/server entities, true if the entity goes outside the PVS. // Unused for client only entities. bool m_bDormant; // Prediction system bool m_bPredictable; // Hierarchy CHandle m_pMoveParent; CHandle m_pMoveChild; CHandle m_pMovePeer; CHandle m_pMovePrevPeer; // The moveparent received from networking data CHandle m_hNetworkMoveParent; CHandle m_hOldMoveParent; string_t m_ModelName; CNetworkVarEmbedded(CCollisionProperty, m_Collision); CNetworkVarEmbedded(CParticleProperty, m_Particles); // Physics state float m_flElasticity; float m_flShadowCastDistance; EHANDLE m_ShadowDirUseOtherEntity; EHANDLE m_hGroundEntity; float m_flGroundChangeTime; // Friction. float m_flFriction; Vector m_vecAbsOrigin; // Object orientation QAngle m_angAbsRotation; Vector m_vecOldOrigin; QAngle m_vecOldAngRotation; Vector m_vecOrigin; CInterpolatedVar m_iv_vecOrigin; QAngle m_angRotation; CInterpolatedVar m_iv_angRotation; // Specifies the entity-to-world transform matrix3x4_t m_rgflCoordinateFrame; // Last values to come over the wire. Used for interpolation. Vector m_vecNetworkOrigin; QAngle m_angNetworkAngles; // Behavior flags int m_fFlags; // used to cull collision tests int m_CollisionGroup; #if !defined(NO_ENTITY_PREDICTION) // For storing prediction results and pristine network state byte *m_pIntermediateData[MULTIPLAYER_BACKUP]; byte *m_pOriginalData; int m_nIntermediateDataCount; bool m_bIsPlayerSimulated; #endif CNetworkVar(bool, m_bSimulatedEveryTick); CNetworkVar(bool, m_bAnimatedEveryTick); CNetworkVar(bool, m_bAlternateSorting); // Adrian unsigned char m_iTextureFrameIndex; // Bbox visualization unsigned char m_fBBoxVisFlags; // The list that holds OnDataChanged events uses this to make sure we don't // get multiple OnDataChanged calls in the same frame if the client receives // multiple packets. int m_DataChangeEventRef; #if !defined(NO_ENTITY_PREDICTION) // Player who is driving my simulation CHandle m_hPlayerSimulationOwner; #endif // The owner! EHANDLE m_hOwnerEntity; EHANDLE m_hEffectEntity; // 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 C_BasePlayer *m_pPredictionPlayer; static bool s_bAbsQueriesValid; static bool s_bAbsRecomputationEnabled; static bool s_bInterpolate; int m_fDataObjectTypes; AimEntsListHandle_t m_AimEntsListHandle; int m_nCreationTick; public: float m_fRenderingClipPlane[4]; // world space clip plane when drawing bool m_bEnableRenderingClipPlane; // true to use the custom clip plane when // drawing float *GetRenderClipPlane( void); // Rendering clip plane, should be 4 floats, return value of // NULL indicates a disabled render clip plane protected: void AddToInterpolationList(); void RemoveFromInterpolationList(); unsigned short m_InterpolationListEntry; // Entry into g_InterpolationList (or // g_InterpolationList.InvalidIndex if not in // the list). void AddToTeleportList(); void RemoveFromTeleportList(); unsigned short m_TeleportListEntry; CThreadFastMutex m_CalcAbsolutePositionMutex; CThreadFastMutex m_CalcAbsoluteVelocityMutex; #ifdef TF_CLIENT_DLL // TF prevents drawing of any entity attached to players that aren't items // in the inventory of the player. This is to prevent servers creating fake // cosmetic items and attaching them to players. public: virtual bool ValidateEntityAttachedToPlayer(bool &bShouldRetry); bool EntityDeemedInvalid(void) { return (m_bValidatedOwner && m_bDeemedInvalid); } protected: bool m_bValidatedOwner; bool m_bDeemedInvalid; bool m_bWasDeemedInvalid; RenderMode_t m_PreviousRenderMode; color32 m_PreviousRenderColor; #endif }; EXTERN_RECV_TABLE(DT_BaseEntity); inline bool FClassnameIs(C_BaseEntity *pEntity, const char *szClassname) { Assert(pEntity); if (pEntity == NULL) return false; return !strcmp(pEntity->GetClassname(), szClassname) ? true : false; } #define SetThink(a) \ ThinkSet(static_cast(a), 0, NULL) #define SetContextThink(a, b, context) \ ThinkSet(static_cast(a), (b), context) #ifdef _DEBUG #define SetTouch(a) \ TouchSet(static_cast(a), #a) #else #define SetTouch(a) \ m_pfnTouch = static_cast(a) #endif //----------------------------------------------------------------------------- // An inline version the game code can use //----------------------------------------------------------------------------- inline CCollisionProperty *C_BaseEntity::CollisionProp() { return &m_Collision; } inline const CCollisionProperty *C_BaseEntity::CollisionProp() const { return &m_Collision; } //----------------------------------------------------------------------------- // An inline version the game code can use //----------------------------------------------------------------------------- inline CParticleProperty *C_BaseEntity::ParticleProp() { return &m_Particles; } inline const CParticleProperty *C_BaseEntity::ParticleProp() const { return &m_Particles; } //----------------------------------------------------------------------------- // Purpose: Returns whether this entity was created on the client. //----------------------------------------------------------------------------- inline bool C_BaseEntity::IsServerEntity(void) { return index != -1; } //----------------------------------------------------------------------------- // Inline methods //----------------------------------------------------------------------------- inline matrix3x4_t &C_BaseEntity::EntityToWorldTransform() { Assert(s_bAbsQueriesValid); CalcAbsolutePosition(); return m_rgflCoordinateFrame; } inline const matrix3x4_t &C_BaseEntity::EntityToWorldTransform() const { Assert(s_bAbsQueriesValid); const_cast(this)->CalcAbsolutePosition(); return m_rgflCoordinateFrame; } inline const Vector &C_BaseEntity::GetNetworkOrigin() const { return m_vecNetworkOrigin; } inline const QAngle &C_BaseEntity::GetNetworkAngles() const { return m_angNetworkAngles; } inline const model_t *C_BaseEntity::GetModel(void) const { return model; } inline int C_BaseEntity::GetModelIndex(void) const { return m_nModelIndex; } //----------------------------------------------------------------------------- // Some helper methods that transform a point from entity space to world space + // back //----------------------------------------------------------------------------- inline void C_BaseEntity::EntityToWorldSpace(const Vector &in, Vector *pOut) const { if (GetAbsAngles() == vec3_angle) { VectorAdd(in, GetAbsOrigin(), *pOut); } else { VectorTransform(in, EntityToWorldTransform(), *pOut); } } inline void C_BaseEntity::WorldToEntitySpace(const Vector &in, Vector *pOut) const { if (GetAbsAngles() == vec3_angle) { VectorSubtract(in, GetAbsOrigin(), *pOut); } else { VectorITransform(in, EntityToWorldTransform(), *pOut); } } inline const Vector &C_BaseEntity::GetAbsVelocity() const { Assert(s_bAbsQueriesValid); const_cast(this)->CalcAbsoluteVelocity(); return m_vecAbsVelocity; } inline C_BaseEntity *C_BaseEntity::Instance(IClientEntity *ent) { return ent ? ent->GetBaseEntity() : NULL; } // For debugging shared code inline bool C_BaseEntity::IsServer(void) { return false; } inline bool C_BaseEntity::IsClient(void) { return true; } inline const char *C_BaseEntity::GetDLLType(void) { return "client"; } //----------------------------------------------------------------------------- // Methods relating to solid type + flags //----------------------------------------------------------------------------- inline void C_BaseEntity::SetSolidFlags(int nFlags) { CollisionProp()->SetSolidFlags(nFlags); } inline bool C_BaseEntity::IsSolidFlagSet(int flagMask) const { return CollisionProp()->IsSolidFlagSet(flagMask); } inline int C_BaseEntity::GetSolidFlags(void) const { return CollisionProp()->GetSolidFlags(); } inline void C_BaseEntity::AddSolidFlags(int nFlags) { CollisionProp()->AddSolidFlags(nFlags); } inline void C_BaseEntity::RemoveSolidFlags(int nFlags) { CollisionProp()->RemoveSolidFlags(nFlags); } inline bool C_BaseEntity::IsSolid() const { return CollisionProp()->IsSolid(); } inline void C_BaseEntity::SetSolid(SolidType_t val) { CollisionProp()->SetSolid(val); } inline SolidType_t C_BaseEntity::GetSolid() const { return CollisionProp()->GetSolid(); } inline void C_BaseEntity::SetCollisionBounds(const Vector &mins, const Vector &maxs) { CollisionProp()->SetCollisionBounds(mins, maxs); } //----------------------------------------------------------------------------- // Methods relating to bounds //----------------------------------------------------------------------------- inline const Vector &C_BaseEntity::WorldAlignMins() const { Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace()); Assert(CollisionProp()->GetCollisionAngles() == vec3_angle); return CollisionProp()->OBBMins(); } inline const Vector &C_BaseEntity::WorldAlignMaxs() const { Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace()); Assert(CollisionProp()->GetCollisionAngles() == vec3_angle); return CollisionProp()->OBBMaxs(); } inline const Vector &C_BaseEntity::WorldAlignSize() const { Assert(!CollisionProp()->IsBoundsDefinedInEntitySpace()); Assert(CollisionProp()->GetCollisionAngles() == vec3_angle); return CollisionProp()->OBBSize(); } inline float CBaseEntity::BoundingRadius() const { return CollisionProp()->BoundingRadius(); } inline bool CBaseEntity::IsPointSized() const { return CollisionProp()->BoundingRadius() == 0.0f; } //----------------------------------------------------------------------------- // Methods relating to traversing hierarchy //----------------------------------------------------------------------------- inline C_BaseEntity *C_BaseEntity::GetMoveParent(void) const { return m_pMoveParent; } inline C_BaseEntity *C_BaseEntity::FirstMoveChild(void) const { return m_pMoveChild; } inline C_BaseEntity *C_BaseEntity::NextMovePeer(void) const { return m_pMovePeer; } //----------------------------------------------------------------------------- // Velocity //----------------------------------------------------------------------------- inline const Vector &C_BaseEntity::GetLocalVelocity() const { return m_vecVelocity; } inline const QAngle &C_BaseEntity::GetLocalAngularVelocity() const { return m_vecAngVelocity; } inline const Vector &C_BaseEntity::GetBaseVelocity() const { return m_vecBaseVelocity; } inline void C_BaseEntity::SetBaseVelocity(const Vector &v) { m_vecBaseVelocity = v; } inline void C_BaseEntity::SetFriction(float flFriction) { m_flFriction = flFriction; } inline void C_BaseEntity::SetGravity(float flGravity) { m_flGravity = flGravity; } inline float C_BaseEntity::GetGravity(void) const { return m_flGravity; } inline int C_BaseEntity::GetWaterLevel() const { return m_nWaterLevel; } inline void C_BaseEntity::SetWaterLevel(int nLevel) { m_nWaterLevel = nLevel; } inline float C_BaseEntity::GetElasticity(void) const { return m_flElasticity; } inline const color32 CBaseEntity::GetRenderColor() const { return m_clrRender.Get(); } inline void C_BaseEntity::SetRenderColor(byte r, byte g, byte b) { color32 clr = {r, g, b, m_clrRender->a}; m_clrRender = clr; } inline void C_BaseEntity::SetRenderColor(byte r, byte g, byte b, byte a) { color32 clr = {r, g, b, a}; m_clrRender = clr; } inline void C_BaseEntity::SetRenderColorR(byte r) { SetRenderColor(r, GetRenderColor().g, GetRenderColor().b); } inline void C_BaseEntity::SetRenderColorG(byte g) { SetRenderColor(GetRenderColor().r, g, GetRenderColor().b); } inline void C_BaseEntity::SetRenderColorB(byte b) { SetRenderColor(GetRenderColor().r, GetRenderColor().g, b); } inline void C_BaseEntity::SetRenderColorA(byte a) { SetRenderColor(GetRenderColor().r, GetRenderColor().g, GetRenderColor().b, a); } inline RenderMode_t CBaseEntity::GetRenderMode() const { return (RenderMode_t)m_nRenderMode; } //----------------------------------------------------------------------------- // checks to see if the entity is marked for deletion //----------------------------------------------------------------------------- inline bool C_BaseEntity::IsMarkedForDeletion(void) { return (m_iEFlags & EFL_KILLME); } inline void C_BaseEntity::AddEFlags(int nEFlagMask) { m_iEFlags |= nEFlagMask; } inline void C_BaseEntity::RemoveEFlags(int nEFlagMask) { m_iEFlags &= ~nEFlagMask; } inline bool CBaseEntity::IsEFlagSet(int nEFlagMask) const { return (m_iEFlags & nEFlagMask) != 0; } inline unsigned char CBaseEntity::GetParentAttachment() const { return m_iParentAttachment; } inline ClientRenderHandle_t CBaseEntity::GetRenderHandle() const { return m_hRender; } inline ClientRenderHandle_t &CBaseEntity::RenderHandle() { return m_hRender; } #ifdef SIXENSE inline const Vector &CBaseEntity::GetEyeOffset() const { return m_vecEyeOffset; } inline void CBaseEntity::SetEyeOffset(const Vector &v) { m_vecEyeOffset = v; } inline const QAngle &CBaseEntity::GetEyeAngleOffset() const { return m_EyeAngleOffset; } inline void CBaseEntity::SetEyeAngleOffset(const QAngle &qa) { m_EyeAngleOffset = qa; } #endif //----------------------------------------------------------------------------- // Methods to cast away const //----------------------------------------------------------------------------- inline Vector C_BaseEntity::EyePosition(void) const { return const_cast(this)->EyePosition(); } inline const QAngle &C_BaseEntity::EyeAngles( void) const // Direction of eyes in world space { return const_cast(this)->EyeAngles(); } inline const QAngle &C_BaseEntity::LocalEyeAngles( void) const // Direction of eyes { return const_cast(this)->LocalEyeAngles(); } inline Vector C_BaseEntity::EarPosition(void) const // position of ears { return const_cast(this)->EarPosition(); } inline VarMapping_t *C_BaseEntity::GetVarMapping() { return &m_VarMap; } //----------------------------------------------------------------------------- // Should we be interpolating? //----------------------------------------------------------------------------- inline bool C_BaseEntity::IsInterpolationEnabled() { return s_bInterpolate; } //----------------------------------------------------------------------------- // Should we be interpolating during this frame? (was EF_NOINTERP) //----------------------------------------------------------------------------- inline bool C_BaseEntity::IsNoInterpolationFrame() { return m_ubOldInterpolationFrame != m_ubInterpolationFrame; } //----------------------------------------------------------------------------- // Purpose: // Input : handle - // Output : inline void //----------------------------------------------------------------------------- inline void C_BaseEntity::SetToolHandle(HTOOLHANDLE handle) { #ifndef NO_TOOLFRAMEWORK m_ToolHandle = handle; #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : inline HTOOLHANDLE //----------------------------------------------------------------------------- inline HTOOLHANDLE C_BaseEntity::GetToolHandle() const { #ifndef NO_TOOLFRAMEWORK return m_ToolHandle; #else return (HTOOLHANDLE)0; #endif } //----------------------------------------------------------------------------- // //----------------------------------------------------------------------------- inline bool C_BaseEntity::IsEnabledInToolView() const { #ifndef NO_TOOLFRAMEWORK return m_bEnabledInToolView; #else return false; #endif } //----------------------------------------------------------------------------- // Purpose: // Input : - // Output : inline bool //----------------------------------------------------------------------------- inline bool C_BaseEntity::ShouldRecordInTools() const { #ifndef NO_TOOLFRAMEWORK return m_bRecordInTools; #else return true; #endif } C_BaseEntity *CreateEntityByName(const char *className); #endif // C_BASEENTITY_H