//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #ifndef PROPS_H #define PROPS_H #ifdef _WIN32 #pragma once #endif #include "baseanimating.h" #include "physics_bone_follower.h" #include "player_pickup.h" #include "positionwatcher.h" #include "props_shared.h" //============================================================================================================= // PROP TYPES //============================================================================================================= //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CBaseProp : public CBaseAnimating { DECLARE_CLASS(CBaseProp, CBaseAnimating); public: void Spawn(void); void Precache(void); void Activate(void); bool KeyValue(const char *szKeyName, const char *szValue); void CalculateBlockLOS(void); int ParsePropData(void); void DrawDebugGeometryOverlays(void); // Don't treat as a live target virtual bool IsAlive(void) { return false; } virtual bool OverridePropdata() { return true; } }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CBreakableProp : public CBaseProp, public IBreakableWithPropData, public CDefaultPlayerPickupVPhysics { public: CBreakableProp(); DECLARE_CLASS(CBreakableProp, CBaseProp); DECLARE_SERVERCLASS(); DECLARE_DATADESC(); virtual void Spawn(); virtual void Precache(); virtual float GetAutoAimRadius() { return 24.0f; } void BreakablePropTouch(CBaseEntity *pOther); virtual int OnTakeDamage(const CTakeDamageInfo &info); void Event_Killed(const CTakeDamageInfo &info); void Break(CBaseEntity *pBreaker, const CTakeDamageInfo &info); void BreakThink(void); void AnimateThink(void); virtual void PlayPuntSound(); void InputBreak(inputdata_t &inputdata); void InputAddHealth(inputdata_t &inputdata); void InputRemoveHealth(inputdata_t &inputdata); void InputSetHealth(inputdata_t &inputdata); int GetNumBreakableChunks(void) { return m_iNumBreakableChunks; } virtual bool OverridePropdata() { return false; } virtual IPhysicsObject *GetRootPhysicsObjectForBreak(); bool PropDataOverrodeBlockLOS(void) { return m_bBlockLOSSetByPropData; } bool PropDataOverrodeAIWalkable(void) { return m_bIsWalkableSetByPropData; } virtual bool HasPreferredCarryAnglesForPlayer(CBasePlayer *pPlayer) { if (HasInteraction(PROPINTER_PHYSGUN_LAUNCH_SPIN_Z)) return true; return false; } virtual QAngle PreferredCarryAngles(void) { return m_preferredCarryAngles; } virtual void Ignite(float flFlameLifetime, bool bNPCOnly, float flSize = 0.0f, bool bCalledByLevelDesigner = false); // Specific interactions void HandleFirstCollisionInteractions(int index, gamevcollisionevent_t *pEvent); void HandleInteractionStick(int index, gamevcollisionevent_t *pEvent); void StickAtPosition(const Vector &stickPosition, const Vector &savePosition, const QAngle &saveAngles); // Disable auto fading under dx7 or when level fades are specified void DisableAutoFade(); public: COutputEvent m_OnBreak; COutputFloat m_OnHealthChanged; COutputEvent m_OnTakeDamage; float m_impactEnergyScale; int m_iMinHealthDmg; QAngle m_preferredCarryAngles; public: // IBreakableWithPropData void SetDmgModBullet(float flDmgMod) { m_flDmgModBullet = flDmgMod; } void SetDmgModClub(float flDmgMod) { m_flDmgModClub = flDmgMod; } void SetDmgModExplosive(float flDmgMod) { m_flDmgModExplosive = flDmgMod; } float GetDmgModBullet(void) { return m_flDmgModBullet; } float GetDmgModClub(void) { return m_flDmgModClub; } float GetDmgModExplosive(void) { return m_flDmgModExplosive; } void SetExplosiveRadius(float flRadius) { m_explodeRadius = flRadius; } void SetExplosiveDamage(float flDamage) { m_explodeDamage = flDamage; } float GetExplosiveRadius(void) { return m_explodeRadius; } float GetExplosiveDamage(void) { return m_explodeDamage; } void SetPhysicsDamageTable(string_t iszTableName) { m_iszPhysicsDamageTableName = iszTableName; } string_t GetPhysicsDamageTable(void) { return m_iszPhysicsDamageTableName; } void SetBreakableModel(string_t iszModel) { m_iszBreakableModel = iszModel; } string_t GetBreakableModel(void) { return m_iszBreakableModel; } void SetBreakableSkin(int iSkin) { m_iBreakableSkin = iSkin; } int GetBreakableSkin(void) { return m_iBreakableSkin; } void SetBreakableCount(int iCount) { m_iBreakableCount = iCount; } int GetBreakableCount(void) { return m_iBreakableCount; } void SetMaxBreakableSize(int iSize) { m_iMaxBreakableSize = iSize; } int GetMaxBreakableSize(void) { return m_iMaxBreakableSize; } void SetPropDataBlocksLOS(bool bBlocksLOS) { m_bBlockLOSSetByPropData = true; SetBlocksLOS(bBlocksLOS); } void SetPropDataIsAIWalkable(bool b) { m_bIsWalkableSetByPropData = true; SetAIWalkable(b); } void SetBasePropData(string_t iszBase) { m_iszBasePropData = iszBase; } string_t GetBasePropData(void) { return m_iszBasePropData; } void SetInteraction(propdata_interactions_t Interaction) { m_iInteractions |= (1 << Interaction); } void RemoveInteraction(propdata_interactions_t Interaction) { m_iInteractions &= ~(1 << Interaction); } bool HasInteraction(propdata_interactions_t Interaction) { return (m_iInteractions & (1 << Interaction)) != 0; } void SetMultiplayerBreakMode(mp_break_t mode) { m_mpBreakMode = mode; } mp_break_t GetMultiplayerBreakMode(void) const { return m_mpBreakMode; } // derived by multiplayer phys props: virtual void SetPhysicsMode(int iMode) {} virtual int GetPhysicsMode() { return PHYSICS_MULTIPLAYER_SOLID; } // Copy fade from another breakable prop void CopyFadeFrom(CBreakableProp *pSource); protected: bool UpdateHealth(int iNewHealth, CBaseEntity *pActivator); virtual void OnBreak(const Vector &vecVelocity, const AngularImpulse &angVel, CBaseEntity *pBreaker) {} protected: unsigned int m_createTick; float m_flPressureDelay; EHANDLE m_hBreaker; PerformanceMode_t m_PerformanceMode; // Prop data storage float m_flDmgModBullet; float m_flDmgModClub; float m_flDmgModExplosive; string_t m_iszPhysicsDamageTableName; string_t m_iszBreakableModel; int m_iBreakableSkin; int m_iBreakableCount; int m_iMaxBreakableSize; string_t m_iszBasePropData; int m_iInteractions; float m_explodeDamage; float m_explodeRadius; string_t m_iszBreakModelMessage; // Count of how many pieces we'll break into, custom or generic int m_iNumBreakableChunks; void SetEnableMotionPosition(const Vector &position, const QAngle &angles); bool GetEnableMotionPosition(Vector *pPosition, QAngle *pAngles); void ClearEnableMotionPosition(); private: CBaseEntity *FindEnableMotionFixup(); public: virtual bool OnAttemptPhysGunPickup(CBasePlayer *pPhysGunUser, PhysGunPickup_t reason); virtual void OnPhysGunPickup(CBasePlayer *pPhysGunUser, PhysGunPickup_t reason); virtual void OnPhysGunDrop(CBasePlayer *pPhysGunUser, PhysGunDrop_t reason); virtual AngularImpulse PhysGunLaunchAngularImpulse(); virtual CBasePlayer *HasPhysicsAttacker(float dt); #ifdef HL2_EPISODIC void CreateFlare(float flLifetime); #endif // HL2_EPISODIC protected: void SetPhysicsAttacker(CBasePlayer *pEntity, float flTime); void CheckRemoveRagdolls(); private: void InputEnablePhyscannonPickup(inputdata_t &inputdata); void InputDisablePhyscannonPickup(inputdata_t &inputdata); void InputEnablePuntSound(inputdata_t &inputdata) { m_bUsePuntSound = true; } void InputDisablePuntSound(inputdata_t &inputdata) { m_bUsePuntSound = false; } // Prevents fade scale from happening void ForceFadeScaleToAlwaysVisible(); void RampToDefaultFadeScale(); private: enum PhysgunState_t { PHYSGUN_MUST_BE_DETACHED = 0, PHYSGUN_IS_DETACHING, PHYSGUN_CAN_BE_GRABBED, PHYSGUN_ANIMATE_ON_PULL, PHYSGUN_ANIMATE_IS_ANIMATING, PHYSGUN_ANIMATE_FINISHED, PHYSGUN_ANIMATE_IS_PRE_ANIMATING, PHYSGUN_ANIMATE_IS_POST_ANIMATING, }; CHandle m_hPhysicsAttacker; float m_flLastPhysicsInfluenceTime; bool m_bBlockLOSSetByPropData; bool m_bIsWalkableSetByPropData; bool m_bOriginalBlockLOS; // BlockLOS state before physgun pickup char m_nPhysgunState; // Ripped-off state COutputEvent m_OnPhysCannonDetach; // We've ripped it off! COutputEvent m_OnPhysCannonAnimatePreStarted; // Started playing the // pre-pull animation COutputEvent m_OnPhysCannonAnimatePullStarted; // Player started the pull anim COutputEvent m_OnPhysCannonAnimatePostStarted; // Started playing the // post-pull animation COutputEvent m_OnPhysCannonPullAnimFinished; // We've had our pull anim finished, or // the post-pull has finished if there // is one float m_flDefaultFadeScale; // Things may temporarily change the fade scale, // but this is its steady-state condition mp_break_t m_mpBreakMode; EHANDLE m_hLastAttacker; // Last attacker that harmed me. EHANDLE m_hFlareEnt; string_t m_iszPuntSound; bool m_bUsePuntSound; }; // Spawnflags #define SF_DYNAMICPROP_USEHITBOX_FOR_RENDERBOX 64 #define SF_DYNAMICPROP_NO_VPHYSICS 128 #define SF_DYNAMICPROP_DISABLE_COLLISION 256 //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- class CDynamicProp : public CBreakableProp, public IPositionWatcher { DECLARE_CLASS(CDynamicProp, CBreakableProp); public: DECLARE_SERVERCLASS(); DECLARE_DATADESC(); CDynamicProp(); void Spawn(void); bool CreateVPhysics(void); void CreateBoneFollowers(); void UpdateOnRemove(void); void AnimThink(void); void PropSetSequence(int nSequence); void OnRestore(void); bool OverridePropdata(void); void HandleAnimEvent(animevent_t *pEvent); // baseentity - watch dynamic hierarchy updates virtual void SetParent(CBaseEntity *pNewParent, int iAttachment = -1); bool TestCollision(const Ray_t &ray, unsigned int mask, trace_t &trace); // breakable prop virtual IPhysicsObject *GetRootPhysicsObjectForBreak(); // IPositionWatcher virtual void NotifyPositionChanged(CBaseEntity *pEntity); // Input handlers void InputSetAnimation(inputdata_t &inputdata); void InputSetDefaultAnimation(inputdata_t &inputdata); void InputTurnOn(inputdata_t &inputdata); void InputTurnOff(inputdata_t &inputdata); void InputDisableCollision(inputdata_t &inputdata); void InputEnableCollision(inputdata_t &inputdata); void InputSetPlaybackRate(inputdata_t &inputdata); COutputEvent m_pOutputAnimBegun; COutputEvent m_pOutputAnimOver; string_t m_iszDefaultAnim; int m_iGoalSequence; int m_iTransitionDirection; // Random animations bool m_bRandomAnimator; float m_flNextRandAnim; float m_flMinRandAnimTime; float m_flMaxRandAnimTime; short m_nPendingSequence; bool m_bStartDisabled; bool m_bDisableBoneFollowers; CNetworkVar(bool, m_bUseHitboxesForRenderBox); protected: void FinishSetSequence(int nSequence); void PropSetAnim(const char *szAnim); void BoneFollowerHierarchyChanged(); // Contained Bone Follower manager CBoneFollowerManager m_BoneFollowerManager; }; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- DECLARE_AUTO_LIST(IPhysicsPropAutoList); class CPhysicsProp : public CBreakableProp, public IPhysicsPropAutoList { DECLARE_CLASS(CPhysicsProp, CBreakableProp); DECLARE_SERVERCLASS(); public: ~CPhysicsProp(); CPhysicsProp(void) {} void Spawn(void); void Precache(); bool CreateVPhysics(void); bool OverridePropdata(void); virtual void VPhysicsUpdate(IPhysicsObject *pPhysics); virtual void VPhysicsCollision(int index, gamevcollisionevent_t *pEvent); void InputWake(inputdata_t &inputdata); void InputSleep(inputdata_t &inputdata); void InputEnableMotion(inputdata_t &inputdata); void InputDisableMotion(inputdata_t &inputdata); void InputDisableFloating(inputdata_t &inputdata); void EnableMotion(void); bool CanBePickedUpByPhyscannon(void); void OnPhysGunPickup(CBasePlayer *pPhysGunUser, PhysGunPickup_t reason); void OnPhysGunDrop(CBasePlayer *pPhysGunUser, PhysGunDrop_t reason); bool GetPropDataAngles(const char *pKeyName, QAngle &vecAngles); float GetCarryDistanceOffset(void); int ObjectCaps(); void Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value); void GetMassCenter(Vector *pMassCenter); float GetMass() const; void ClearFlagsThink(void); virtual int OnTakeDamage(const CTakeDamageInfo &info); int DrawDebugTextOverlays(void); bool IsGib(); DECLARE_DATADESC(); // Specific interactions void HandleAnyCollisionInteractions(int index, gamevcollisionevent_t *pEvent); string_t GetPhysOverrideScript(void) { return m_iszOverrideScript; } float GetMassScale(void) { return m_massScale; } private: // Compute impulse to apply to the enabled entity. void ComputeEnablingImpulse(int index, gamevcollisionevent_t *pEvent); COutputEvent m_MotionEnabled; COutputEvent m_OnAwakened; COutputEvent m_OnPhysGunPickup; COutputEvent m_OnPhysGunPunt; COutputEvent m_OnPhysGunOnlyPickup; COutputEvent m_OnPhysGunDrop; COutputEvent m_OnPlayerUse; COutputEvent m_OnPlayerPickup; COutputEvent m_OnOutOfWorld; float m_massScale; float m_inertiaScale; int m_damageType; string_t m_iszOverrideScript; int m_damageToEnableMotion; float m_flForceToEnableMotion; bool m_bThrownByPlayer; bool m_bFirstCollisionAfterLaunch; protected: CNetworkVar(bool, m_bAwake); }; // An interface so that objects parented to props can receive collision // interaction events. enum parentCollisionInteraction_t { COLLISIONINTER_PARENT_FIRST_IMPACT = 1, }; abstract_class IParentPropInteraction { public: virtual void OnParentCollisionInteraction( parentCollisionInteraction_t eType, int index, gamevcollisionevent_t *pEvent) = 0; virtual void OnParentPhysGunDrop(CBasePlayer * pPhysGunUser, PhysGunDrop_t Reason) = 0; }; // Used by prop_physics_create and the server benchmark. // pModelName should not include the "models/" prefix. CPhysicsProp *CreatePhysicsProp(const char *pModelName, const Vector &vTraceStart, const Vector &vTraceEnd, const IHandleEntity *pTraceIgnore, bool bRequireVCollide, const char *pClassName = "physics_prop"); bool UTIL_CreateScaledPhysObject(CBaseAnimating *pInstance, float flScale); float GetBreakableDamage(const CTakeDamageInfo &inputInfo, IBreakableWithPropData *pProp = NULL); int PropBreakablePrecacheAll(string_t modelName); extern ConVar func_breakdmg_bullet; extern ConVar func_breakdmg_club; extern ConVar func_breakdmg_explosive; #endif // PROPS_H