//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// // Author: Michael S. Booth (mike@turtlerockstudios.com), 2003 #ifndef BASE_CONTROL_H #define BASE_CONTROL_H #pragma warning( disable : 4530 ) // STL uses exceptions, but we are not compiling with them - ignore warning extern float g_BotUpkeepInterval; ///< duration between bot upkeeps extern float g_BotUpdateInterval; ///< duration between bot updates const int g_BotUpdateSkipCount = 2; ///< number of upkeep periods to skip update class CNavArea; /// TODO: move CS-specific defines into CSBot files enum { SmokeGrenadeRadius = 155, FlashbangGrenadeRadius = 115, HEGrenadeRadius = 115, }; //-------------------------------------------------------------------------------------------------------------- class CBaseGrenade; /** * An ActiveGrenade is a representation of a grenade in the world * NOTE: Currently only used for smoke grenade line-of-sight testing * @todo Use system allow bots to avoid HE and Flashbangs */ class ActiveGrenade { public: ActiveGrenade( CBaseGrenade *grenadeEntity ); void OnEntityGone( void ); ///< called when the grenade in the world goes away void Update( void ); ///< called every frame bool IsValid( void ) const ; ///< return true if this grenade is valid bool IsEntity( CBaseGrenade *grenade ) const { return (grenade == m_entity) ? true : false; } CBaseGrenade *GetEntity( void ) const { return m_entity; } const Vector &GetDetonationPosition( void ) const { return m_detonationPosition; } const Vector &GetPosition( void ) const; bool IsSmoke( void ) const { return m_isSmoke; } bool IsFlashbang( void ) const { return m_isFlashbang; } CBaseGrenade *GetGrenade( void ) { return m_entity; } float GetRadius( void ) const { return m_radius; } void SetRadius( float radius ) { m_radius = radius; } private: CBaseGrenade *m_entity; ///< the entity Vector m_detonationPosition; ///< the location where the grenade detonated (smoke) float m_dieTimestamp; ///< time this should go away after m_entity is NULL bool m_isSmoke; ///< true if this is a smoke grenade bool m_isFlashbang; ///< true if this is a flashbang grenade float m_radius; }; typedef CUtlLinkedList ActiveGrenadeList; //-------------------------------------------------------------------------------------------------------------- /** * This class manages all active bots, propagating events to them and updating them. */ class CBotManager { public: CBotManager(); virtual ~CBotManager(); CBasePlayer *AllocateAndBindBotEntity( edict_t *ed ); ///< allocate the appropriate entity for the bot and bind it to the given edict virtual CBasePlayer *AllocateBotEntity( void ) = 0; ///< factory method to allocate the appropriate entity for the bot virtual void ClientDisconnect( CBaseEntity *entity ) = 0; virtual bool ClientCommand( CBasePlayer *player, const CCommand &args ) = 0; virtual void ServerActivate( void ) = 0; virtual void ServerDeactivate( void ) = 0; virtual bool ServerCommand( const char * pcmd ) = 0; virtual void RestartRound( void ); ///< (EXTEND) invoked when a new round begins virtual void StartFrame( void ); ///< (EXTEND) called each frame virtual unsigned int GetPlayerPriority( CBasePlayer *player ) const = 0; ///< return priority of player (0 = max pri) void AddGrenade( CBaseGrenade *grenade ); ///< add an active grenade to the bot's awareness void RemoveGrenade( CBaseGrenade *grenade ); ///< the grenade entity in the world is going away void SetGrenadeRadius( CBaseGrenade *grenade, float radius ); ///< the radius of the grenade entity (or associated smoke cloud) void ValidateActiveGrenades( void ); ///< destroy any invalid active grenades void DestroyAllGrenades( void ); bool IsLineBlockedBySmoke( const Vector &from, const Vector &to, float grenadeBloat = 1.0f ); ///< return true if line intersects smoke volume, with grenade radius increased by the grenadeBloat factor bool IsInsideSmokeCloud( const Vector *pos ); ///< return true if position is inside a smoke cloud // // Invoke functor on all active grenades. // If any functor call return false, return false. Otherwise, return true. // template < typename T > bool ForEachGrenade( T &func ) { int it = m_activeGrenadeList.Head(); while( it != m_activeGrenadeList.InvalidIndex() ) { ActiveGrenade *ag = m_activeGrenadeList[ it ]; int current = it; it = m_activeGrenadeList.Next( it ); // lazy validation if (!ag->IsValid()) { m_activeGrenadeList.Remove( current ); delete ag; continue; } else { if (func( ag ) == false) { return false; } } } return true; } enum { MAX_DBG_MSG_SIZE = 1024 }; struct DebugMessage { char m_string[ MAX_DBG_MSG_SIZE ]; IntervalTimer m_age; }; // debug message history ------------------------------------------------------------------------------- int GetDebugMessageCount( void ) const; ///< get number of debug messages in history const DebugMessage *GetDebugMessage( int which = 0 ) const; ///< return the debug message emitted by the bot (0 = most recent) void ClearDebugMessages( void ); void AddDebugMessage( const char *msg ); private: ActiveGrenadeList m_activeGrenadeList;///< the list of active grenades the bots are aware of enum { MAX_DBG_MSGS = 6 }; DebugMessage m_debugMessage[ MAX_DBG_MSGS ]; ///< debug message history int m_debugMessageCount; int m_currentDebugMessage; IntervalTimer m_frameTimer; ///< for measuring each frame's duration }; inline CBasePlayer *CBotManager::AllocateAndBindBotEntity( edict_t *ed ) { CBasePlayer::s_PlayerEdict = ed; return AllocateBotEntity(); } inline int CBotManager::GetDebugMessageCount( void ) const { return m_debugMessageCount; } inline const CBotManager::DebugMessage *CBotManager::GetDebugMessage( int which ) const { if (which >= m_debugMessageCount) return NULL; int i = m_currentDebugMessage - which; if (i < 0) i += MAX_DBG_MSGS; return &m_debugMessage[ i ]; } // global singleton to create and control bots extern CBotManager *TheBots; #endif