//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: The robots for use in the Robot Destruction TF2 game mode. // //=========================================================================// #ifndef ROBOT_DESTRUCTION_ROBOT_H #define ROBOT_DESTRUCTION_ROBOT_H #pragma once #include "cbase.h" #ifdef GAME_DLL #include "tf_shareddefs.h" #include "pathtrack.h" #include "NextBotGroundLocomotion.h" #include "NextBotIntentionInterface.h" #include "NextBotBehavior.h" #include "NextBot.h" #include "../server/NextBot/Path/NextBotPathFollow.h" #include "../server/NextBot/Path/NextBotPath.h" #include "../server/tf/halloween/headless_hatman_body.h" #include "tf_obj_dispenser.h" #else #include "c_obj_dispenser.h" #endif #ifdef CLIENT_DLL #define CTFRobotDestruction_Robot C_TFRobotDestruction_Robot #define CRobotDispenser C_RobotDispenser #endif #include "props_shared.h" enum eRobotType { ROBOT_TYPE_FRUSTUM = 0, ROBOT_TYPE_SPHERE, ROBOT_TYPE_KING, NUM_ROBOT_TYPES }; enum eRobotUIState { ROBOT_STATE_INACIVE = 0, ROBOT_STATE_ACTIVE, ROBOT_STATE_DEAD, ROBOT_STATE_SHIELDED, NUM_ROBOT_STATES }; struct RobotData_t { public: enum EStringDataKey_t { MODEL_KEY = 0, DAMAGED_MODEL_KEY, HURT_SOUND_KEY, DEATH_SOUND_KEY, COLLIDE_SOUND_KEY, IDLE_SOUND_KEY }; enum EFloatDataKey_t { HEALTH_BAR_OFFSET_KEY }; RobotData_t( const char* pszModelName , const char* pszDamagedModelName , const char *pszHurtSound , const char *pszDeathSound , const char *pszCollideSound , const char *pszIdleSound , float flHealthBarOffset ) { m_stringMap.SetLessFunc( DefLessFunc(int) ); m_floatMap.SetLessFunc( DefLessFunc(int) ); m_stringMap.Insert( MODEL_KEY, pszModelName ); m_stringMap.Insert( DAMAGED_MODEL_KEY, pszDamagedModelName ); m_stringMap.Insert( HURT_SOUND_KEY, pszHurtSound ); m_stringMap.Insert( DEATH_SOUND_KEY, pszDeathSound ); m_stringMap.Insert( COLLIDE_SOUND_KEY, pszCollideSound ); m_stringMap.Insert( IDLE_SOUND_KEY, pszIdleSound ); m_floatMap.Insert( HEALTH_BAR_OFFSET_KEY, flHealthBarOffset ); } const char* GetStringData( EStringDataKey_t key ) const { return GetData< const char * >( m_stringMap, (int)key ); } float GetFloatData( EFloatDataKey_t key ) const { return GetData< float >( m_floatMap, (int)key ); } void Precache(); private: template< typename T > T GetData( const CUtlMap< int, T >& map, int nKey ) const { int nIndex = map.Find( nKey ); if ( nIndex != map.InvalidIndex() ) { return map.Element( nIndex ); } AssertMsg1( 0, "No entry for key %d", nKey ); return T(0); } CUtlMap< int, const char * > m_stringMap; CUtlMap< int, float > m_floatMap; }; class CTFRobotDestruction_Robot; #ifdef GAME_DLL struct RobotSpawnData_t { RobotSpawnData_t() : m_eType( ROBOT_TYPE_FRUSTUM ) , m_nRobotHealth( 100 ) , m_nPoints( 0 ) , m_nNumGibs( 0 ) , m_pszPathName( NULL ) , m_pszGroupName( NULL ) {} RobotSpawnData_t &operator=( const RobotSpawnData_t& rhs ) { m_eType = rhs.m_eType; m_nRobotHealth = rhs.m_nRobotHealth; m_nPoints = rhs.m_nPoints; m_nNumGibs = rhs.m_nNumGibs; m_pszPathName = rhs.m_pszPathName; m_pszGroupName = rhs.m_pszGroupName; return *this; } eRobotType m_eType; int m_nRobotHealth; int m_nPoints; int m_nNumGibs; const char *m_pszPathName; const char *m_pszGroupName; }; //---------------------------------------------------------------------------- class CRobotLocomotion : public NextBotGroundLocomotion { public: CRobotLocomotion( INextBot *bot ) : NextBotGroundLocomotion( bot ) { } virtual ~CRobotLocomotion() { } virtual float GetGroundSpeed() const OVERRIDE; virtual float GetRunSpeed( void ) const OVERRIDE; // get maximum running speed virtual float GetStepHeight( void ) const OVERRIDE; // if delta Z is greater than this, we have to jump to get up virtual float GetMaxJumpHeight( void ) const OVERRIDE; // return maximum height of a jump virtual bool ShouldCollideWith( const CBaseEntity *object ) const OVERRIDE; private: virtual float GetMaxYawRate( void ) const OVERRIDE; // return max rate of yaw rotation }; //---------------------------------------------------------------------------- class CRobotIntention : public IIntention { public: CRobotIntention( class CTFRobotDestruction_Robot *me ); virtual ~CRobotIntention(); virtual void Reset( void ) OVERRIDE; virtual void Update( void ) OVERRIDE; virtual QueryResultType IsPositionAllowed( const INextBot *me, const Vector &pos ) const OVERRIDE; // is the a place we can be? virtual INextBotEventResponder *FirstContainedResponder( void ) const OVERRIDE { return m_behavior; } virtual INextBotEventResponder *NextContainedResponder( INextBotEventResponder *current ) const OVERRIDE { return NULL; } private: Behavior< CTFRobotDestruction_Robot > *m_behavior; }; //--------------------------------------------------------------------------------------------- class CRobotBehavior : public Action< CTFRobotDestruction_Robot > { public: virtual Action< CTFRobotDestruction_Robot > *InitialContainedAction( CTFRobotDestruction_Robot *me ) OVERRIDE; virtual ActionResult< CTFRobotDestruction_Robot > OnStart( CTFRobotDestruction_Robot *me, Action< CTFRobotDestruction_Robot > *priorAction ) OVERRIDE; virtual ActionResult< CTFRobotDestruction_Robot > Update( CTFRobotDestruction_Robot *me, float interval ) OVERRIDE; virtual EventDesiredResult< CTFRobotDestruction_Robot > OnInjured( CTFRobotDestruction_Robot *me, const CTakeDamageInfo &info ); EventDesiredResult< CTFRobotDestruction_Robot > OnContact( CTFRobotDestruction_Robot *me, CBaseEntity *pOther, CGameTrace *result = NULL ); virtual const char *GetName( void ) const { return "RobotBehavior"; } // return name of this action private: CountdownTimer m_SpeakTimer; CountdownTimer m_IdleSpeakTimer; }; #endif class CRobotDispenser : #ifdef GAME_DLL public CObjectDispenser #else public C_ObjectDispenser #endif { #ifdef GAME_DLL DECLARE_CLASS( CRobotDispenser, CObjectDispenser ) #else DECLARE_CLASS( CRobotDispenser, C_ObjectDispenser ) #endif DECLARE_NETWORKCLASS(); DECLARE_DATADESC(); public: #ifdef GAME_DLL CRobotDispenser(); virtual void Spawn( void ) OVERRIDE; virtual void OnGoActive( void ) OVERRIDE; virtual void GetControlPanelInfo( int nPanelIndex, const char *&pPanelName ) OVERRIDE; virtual void SetModel( const char *pModel ) OVERRIDE; virtual float GetDispenserRadius( void ) OVERRIDE { return 128; } virtual float GetHealRate() const OVERRIDE { return 5.f; } virtual int DispenseMetal( CTFPlayer * ) OVERRIDE { return 0; } virtual bool DispenseAmmo( CTFPlayer * ) OVERRIDE { return false; } private: virtual void PlayActiveSound() OVERRIDE { /*DO NOTHING*/ } #endif }; class CTFRobotDestruction_RobotAnimController { public: CTFRobotDestruction_RobotAnimController( CTFRobotDestruction_Robot *pOuter ); void Update(); void Impulse( const Vector& vecImpulse ); private: void Approach( Vector& vecIn, const Vector& vecTarget, float flRate ); void GetPoseParams(); Vector m_vecOldOrigin; Vector m_vecLean; Vector m_vecImpulse; CTFRobotDestruction_Robot *m_pOuter; struct PoseParams_t { int m_nMoveX; int m_nMoveY; } m_poseParams; }; #ifdef GAME_DLL typedef NextBotCombatCharacter RobotBaseClass; #else typedef CBaseCombatCharacter RobotBaseClass; #endif class CTFRobotDestruction_Robot : public RobotBaseClass #ifdef CLIENT_DLL , public CGameEventListener #endif { DECLARE_DATADESC(); DECLARE_CLASS( CTFRobotDestruction_Robot, RobotBaseClass ) DECLARE_NETWORKCLASS(); public: CTFRobotDestruction_Robot( void ); virtual ~CTFRobotDestruction_Robot( void ); static void StaticPrecache( void ); virtual void Precache( void ) OVERRIDE; virtual void Spawn( void ) OVERRIDE; virtual bool ShouldCollide( int collisionGroup, int contentsMask ) const OVERRIDE; #ifdef CLIENT_DLL virtual float GetHealthBarHeightOffset( void ) const OVERRIDE; virtual void OnDataChanged( DataUpdateType_t type ) OVERRIDE; virtual int GetHealth( void ) const OVERRIDE { return m_iHealth; } virtual int GetMaxHealth( void ) const OVERRIDE { return m_iMaxHealth; } virtual bool IsHealthBarVisible( void ) const OVERRIDE { return true; } virtual void UpdateClientSideAnimation( void ) OVERRIDE; virtual void FireGameEvent( IGameEvent *event ) OVERRIDE; virtual CStudioHdr* OnNewModel() OVERRIDE; virtual void FireEvent( const Vector& origin, const QAngle& angles, int event, const char *options ) OVERRIDE; void UpdateDamagedEffects( void ); #else virtual void HandleAnimEvent( animevent_t *pEvent ) OVERRIDE; virtual bool IsRemovedOnReset( void ) const { return false; } virtual void UpdateOnRemove( void ) OVERRIDE; virtual void Event_Killed( const CTakeDamageInfo &info ) OVERRIDE; virtual int OnTakeDamage( const CTakeDamageInfo &info ) OVERRIDE; virtual void TraceAttack( const CTakeDamageInfo &inputInfo, const Vector &vecDir, trace_t *ptr, CDmgAccumulator *pAccumulator ) OVERRIDE; virtual void UpdateAnimsThink( void ); void RepairSelfThink( void ); bool GetShieldedState( void ) const { return m_bShielded; } CPathTrack *GetNextPath( void ) const { return m_hNextPath; } void ArriveAtPath( void ); void SetRobotSpawnData( const RobotSpawnData_t& data ) { m_spawnData = data; m_eType = data.m_eType; } const RobotSpawnData_t &GetRobotSpawnData() const { return m_spawnData; } void SetGroup( class CTFRobotDestruction_RobotGroup* pGroup ) { m_hGroup.Set( pGroup ); } void SetSpawn( class CTFRobotDestruction_RobotSpawn* pSpawn ) { m_hSpawn.Set( pSpawn ); } void EnableUber( void ); void DisableUber( void ); // INextBot virtual CRobotIntention *GetIntentionInterface( void ) const { return m_intention; } virtual CRobotLocomotion *GetLocomotionInterface( void ) const { return m_locomotor; } virtual CHeadlessHatmanBody *GetBodyInterface( void ) const { return m_body; } void SetNewActivity( Activity activity ); void SetIsPanicked( bool bPanicked ) { m_bIsPanicked = bPanicked; } bool GetIsPanicked( void ) const { return m_bIsPanicked; } //Inputs void InputStopAndUseComputer( inputdata_t &inputdata ); private: void PlayDeathEffects( void ); void ModifyDamage( CTakeDamageInfo *info ) const; void SpewBars( int nNumToSpew ); void SpewBarsThink( void ); void SelfDestructThink( void ); void SpewGibs( void ); #endif private: int m_iHealth; int m_iMaxHealth; CUtlVector m_aGibs; CUtlVector m_aSpawnProps; CTFRobotDestruction_RobotAnimController m_animController; CNetworkVar( bool, m_bShielded ); CNetworkVar( eRobotType, m_eType ); #ifdef CLIENT_DLL HPARTICLEFFECT m_hDamagedParticleEffect; #else CRobotDispenser *m_pDispenser; RobotSpawnData_t m_spawnData; CHandle< CPathTrack > m_hNextPath; int m_nPointsSpewed; IMPLEMENT_NETWORK_VAR_FOR_DERIVED( m_iHealth ); CHandle< CTFRobotDestruction_RobotGroup > m_hGroup; CHandle< CTFRobotDestruction_RobotSpawn > m_hSpawn; CRobotIntention *m_intention; CRobotLocomotion *m_locomotor; CHeadlessHatmanBody *m_body; bool m_bIsPanicked; #endif }; #ifdef GAME_DLL //-------------------------------------------------------------------------------------------------------------- class CRobotPathCost : public IPathCost { public: CRobotPathCost( CTFRobotDestruction_Robot *me ) { m_me = me; } // return the cost (weighted distance between) of moving from "fromArea" to "area", or -1 if the move is not allowed virtual float operator()( CNavArea *area, CNavArea *fromArea, const CNavLadder *ladder, const CFuncElevator *elevator, float length ) const { if ( fromArea == NULL ) { // first area in path, no cost return 0.0f; } else { if ( !m_me->GetLocomotionInterface()->IsAreaTraversable( area ) ) { // our locomotor says we can't move here return -1.0f; } // compute distance traveled along path so far float dist; if ( ladder ) { dist = ladder->m_length; } else if ( length > 0.0 ) { // optimization to avoid recomputing length dist = length; } else { dist = ( area->GetCenter() - fromArea->GetCenter() ).Length(); } // check height change float deltaZ = fromArea->ComputeAdjacentConnectionHeightChange( area ); if ( deltaZ >= m_me->GetLocomotionInterface()->GetStepHeight() ) { if ( deltaZ >= m_me->GetLocomotionInterface()->GetMaxJumpHeight() ) { // too high to reach return -1.0f; } // jumping is slower than flat ground const float jumpPenalty = 5.0f; dist += jumpPenalty * dist; } else if ( deltaZ < -m_me->GetLocomotionInterface()->GetDeathDropHeight() ) { // too far to drop return -1.0f; } return dist + fromArea->GetCostSoFar(); } } CTFRobotDestruction_Robot *m_me; }; #endif // GAME_DLL #endif // ROBOT_DESTRUCTION_ROBOT_H