// ai_addon.h #ifndef AI_ADDON_H #define AI_ADDON_H #ifdef _WIN32 #pragma once #endif #include "tier1/utlvector.h" #include "baseanimating.h" #include "ai_agent.h" #include "ai_behavior.h" #include "player_pickup.h" #include "IEffects.h" class CAI_BaseNPC; #define INVALID_ADDON_ATTACHMENT_ID -1 int GetIDForAttachmentName( char *pszAttachmentName ); int GetNumAddOnAttachmentPoints(); bool IsAddOnAttachmentAvailable( CAI_BaseNPC *pHost, char *pszAttachmentName ); int CountAddOns( CAI_BaseNPC *pHost ); //========================================================= //========================================================= class CAI_AddOn : public CBaseAnimating, public CAI_Agent, public CDefaultPlayerPickupVPhysics { public: DECLARE_CLASS( CAI_AddOn, CBaseAnimating ); //--------------------------------- // CTor/DTor //--------------------------------- CAI_AddOn() { m_iAttachmentID = INVALID_ADDON_ATTACHMENT_ID; } //--------------------------------- // Precache/Spawn/etc //--------------------------------- virtual void Precache(); virtual void Spawn(); virtual void UpdateOnRemove(); const char *GetDebugName() { return CBaseEntity::GetDebugName(); } int entindex() { return CBaseEntity::entindex(); } virtual int DrawDebugTextOverlays(void); //--------------------------------- //--------------------------------- bool SUB_AllowedToFade( void ) { return true; } int Save( ISave &save ) { int result = CBaseAnimating::Save( save ); if ( result ) { result = CAI_Agent::Save( save ); } return result; } //------------------------------------- int Restore( IRestore &restore ) { int result = CBaseAnimating::Restore( restore ); if ( result ) { result = CAI_Agent::Restore( restore ); } return result; } //--------------------------------- // Agent stuff //--------------------------------- virtual void GatherConditions(); virtual int SelectSchedule(); virtual void StartTask( const Task_t *pTask ); virtual void RunTask( const Task_t *pTask ); //--------------------------------- // Install/Remove AddOns //--------------------------------- virtual bool Install( CAI_BaseNPC *pHost, bool bRemoveOnFail = true ); void SetPhysReplacement( CBaseEntity *pEntity ); bool Attach( CAI_BaseNPC *pHost ); void Dettach( void ); virtual void Remove() { Unbind(); Dettach(); } virtual void Bind() {} virtual void Unbind() {} //--------------------------------- // Hosts/Outer accessors //--------------------------------- CAI_BaseNPC *GetNPCHost(); CBaseEntity *GetHostEnemy(); //--------------------------------- // Thinking //--------------------------------- void DispatchAddOnThink(); virtual float GetThinkInterval() { return 0.1f; } //--------------------------------- // Appearance & Position //--------------------------------- virtual void PickAttachment( CAI_BaseNPC *pHost, char *pchAttachment ) = 0; virtual char *GetAddOnModelName() = 0; virtual Vector GetAttachOffset( QAngle &attachmentAngles ) { return vec3_origin; } virtual QAngle GetAttachOrientation( QAngle &attachmentAngles ) { return attachmentAngles; } virtual QAngle GetLocalOrientation( void ); int GetAttachmentID() { return m_iAttachmentID; } virtual void EjectFromHost(); //--------------------------------- // Entity I/O //--------------------------------- void InputInstall( inputdata_t &data ); void InputRemove( inputdata_t &data ); //--------------------------------- // Schedule/Task/Conditions //--------------------------------- enum { TASK_ADDON_WAIT = NEXT_TASK, TASK_ADDON_WAIT_RANDOM, NEXT_TASK, }; enum { COND_ADDON_LOST_HOST = NEXT_CONDITION, NEXT_CONDITION, }; enum { SCHED_ADDON_NO_OWNER = NEXT_SCHEDULE, NEXT_SCHEDULE, }; DECLARE_DATADESC(); protected: CHandle m_hNPCHost; CHandle m_hPhysReplacement; int m_iPhysReplacementSolidFlags; int m_iPhysReplacementMoveType; QAngle m_angPhysReplacementLocalOrientation; Vector m_vecPhysReplacementDetatchForce; bool m_bWasAttached; private: //--------------------------------- // Fields used by AI //--------------------------------- float m_flWaitFinished; // Same as for AI_BaseNPC int m_iAttachmentID; // Which attachment point am I connected to on my host's model? float m_flNextAttachTime; public: //--------------------------------- // Hammer keyfields //--------------------------------- DEFINE_AGENT(); }; //========================================================= //========================================================= class CAI_AddOnBehaviorBase : public CAI_SimpleBehavior { public: virtual bool ShouldNPCSave() { return false; } virtual CAI_AddOn **GetAddOnsBase() { return NULL; } const CAI_AddOn **GetAddOnsBase() const { return (const CAI_AddOn **)const_cast(this)->GetAddOnsBase(); } virtual int NumAddOns() const { return 0; } }; template class CAI_AddOnBehavior : public CAI_AddOnBehaviorBase { public: virtual int BindAddOn( ADDON *pAddOn ) { Assert( m_AddOns.Find( pAddOn ) == m_AddOns.InvalidIndex() ); Assert( static_cast(pAddOn) ); // Satic cast is used to trap improper inheritance m_AddOns.AddToTail( pAddOn ); return m_AddOns.Count(); } virtual int UnbindAddOn( ADDON *pAddOn ) { Assert( m_AddOns.Find( pAddOn ) != m_AddOns.InvalidIndex() ); m_AddOns.FindAndRemove( pAddOn ); return m_AddOns.Count(); } virtual CAI_AddOn **GetAddOnsBase() { return (CAI_AddOn **)m_AddOns.Base(); } virtual ADDON **GetAddOns() { return m_AddOns.Base(); } virtual int NumAddOns() const { return m_AddOns.Count(); } protected: CUtlVector m_AddOns; }; //========================================================= //========================================================= template class CAI_AddOnBehaviorConnector : public ADDON { DECLARE_CLASS( CAI_AddOnBehaviorConnector, ADDON ); virtual int ObjectCaps( void ) { return BaseClass::ObjectCaps() | FCAP_IMPULSE_USE; } virtual void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { CBasePlayer *pPlayer = ToBasePlayer( pActivator ); if ( pPlayer == NULL ) return; if ( this->m_bWasAttached ) { this->Remove(); g_pEffects->Sparks( this->GetAbsOrigin(), 2, 2 ); } pPlayer->PickupObject( this ); } virtual void Bind() { if ( this->m_hNPCHost ) { BEHAVIOR *pBehavior; if ( !this->m_hNPCHost->GetBehavior( &pBehavior ) ) { pBehavior = new BEHAVIOR; this->m_hNPCHost->AddBehavior( pBehavior ); } pBehavior->BindAddOn( this ); } } virtual void Unbind() { if ( this->m_hNPCHost ) { BEHAVIOR *pBehavior; if ( this->m_hNPCHost->GetBehavior( &pBehavior ) ) { if ( pBehavior->UnbindAddOn( this ) == 0 ) { this->m_hNPCHost->RemoveAndDestroyBehavior( pBehavior ); } } } } //------------------------------------- int Save( ISave &save ) { int result = BaseClass::Save( save ); if ( result ) { bool bSaved = false; BEHAVIOR *pBehavior; if ( this->m_hNPCHost && this->m_hNPCHost->GetBehavior( &pBehavior ) ) { bSaved = true; CAI_BehaviorBase::SaveBehaviors( save, pBehavior, (CAI_BehaviorBase **)&pBehavior, 1, false ); } if ( !bSaved ) { CAI_BehaviorBase::SaveBehaviors( save, NULL, NULL, 0 ); } } return result; } //------------------------------------- int Restore( IRestore &restore ) { int result = BaseClass::Restore( restore ); if ( result ) { Bind(); BEHAVIOR *pBehavior; if ( this->m_hNPCHost && this->m_hNPCHost->GetBehavior( &pBehavior ) ) { CAI_BehaviorBase::RestoreBehaviors( restore, (CAI_BehaviorBase **)&pBehavior, 1, false ); } else { CAI_BehaviorBase::RestoreBehaviors( restore, NULL, 0,false ); } } return result; } }; #define LINK_ENTITY_TO_ADDON_AND_BEHAVIOR( mapClassName, DLLClassName, BehaviorName ) \ typedef CAI_AddOnBehaviorConnector DLLClassName##_##BehaviorName##_Binder; \ LINK_ENTITY_TO_CLASS( mapClassName, DLLClassName##_##BehaviorName##_Binder ) #endif // AI_ADDON_H