Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

656 lines
22 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Bot radio chatter system
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. // Author: Michael S. Booth ([email protected]), 2003
  8. #ifndef CS_BOT_CHATTER_H
  9. #define CS_BOT_CHATTER_H
  10. #pragma warning( disable : 4786 ) // long STL names get truncated in browse info.
  11. #include "nav_mesh.h"
  12. #include "cs_gamestate.h"
  13. class CCSBot;
  14. class BotChatterInterface;
  15. #define MAX_PLACES_PER_MAP 64
  16. typedef unsigned int PlaceCriteria;
  17. typedef unsigned int CountCriteria;
  18. #define UNDEFINED_COUNT 0xFFFF
  19. #define COUNT_CURRENT_ENEMIES 0xFF // use the number of enemies we see right when we speak
  20. #define COUNT_MANY 4 // equal to or greater than this is "many"
  21. #define UNDEFINED_SUBJECT (-1)
  22. /// @todo Make Place a class with member fuctions for this
  23. const Vector *GetRandomSpotAtPlace( Place place );
  24. //----------------------------------------------------------------------------------------------------
  25. /**
  26. * A meme is a unit information that bots use to
  27. * transmit information to each other via the radio
  28. */
  29. class BotMeme
  30. {
  31. public:
  32. void Transmit( CCSBot *sender ) const; ///< transmit meme to other bots
  33. // It is a best practice to always have a virtual destructor in an interface
  34. // class. Otherwise if the derived classes have destructors they will not be
  35. // called.
  36. virtual ~BotMeme() {}
  37. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const = 0; ///< cause the given bot to act on this meme
  38. };
  39. //----------------------------------------------------------------------------------------------------
  40. class BotHelpMeme : public BotMeme
  41. {
  42. public:
  43. BotHelpMeme( Place place = UNDEFINED_PLACE )
  44. {
  45. m_place = place;
  46. }
  47. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  48. private:
  49. Place m_place; ///< where the help is needed
  50. };
  51. //----------------------------------------------------------------------------------------------------
  52. class BotBombsiteStatusMeme : public BotMeme
  53. {
  54. public:
  55. enum StatusType { CLEAR, PLANTED };
  56. BotBombsiteStatusMeme( int zoneIndex, StatusType status )
  57. {
  58. m_zoneIndex = zoneIndex;
  59. m_status = status;
  60. }
  61. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  62. private:
  63. int m_zoneIndex; ///< the bombsite
  64. StatusType m_status; ///< whether it is cleared or the bomb is there (planted)
  65. };
  66. //----------------------------------------------------------------------------------------------------
  67. class BotBombStatusMeme : public BotMeme
  68. {
  69. public:
  70. BotBombStatusMeme( CSGameState::BombState state, const Vector &pos )
  71. {
  72. m_state = state;
  73. m_pos = pos;
  74. }
  75. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  76. private:
  77. CSGameState::BombState m_state;
  78. Vector m_pos;
  79. };
  80. //----------------------------------------------------------------------------------------------------
  81. class BotFollowMeme : public BotMeme
  82. {
  83. public:
  84. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  85. };
  86. //----------------------------------------------------------------------------------------------------
  87. class BotDefendHereMeme : public BotMeme
  88. {
  89. public:
  90. BotDefendHereMeme( const Vector &pos )
  91. {
  92. m_pos = pos;
  93. }
  94. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  95. private:
  96. Vector m_pos;
  97. };
  98. //----------------------------------------------------------------------------------------------------
  99. class BotWhereBombMeme : public BotMeme
  100. {
  101. public:
  102. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  103. };
  104. //----------------------------------------------------------------------------------------------------
  105. class BotRequestReportMeme : public BotMeme
  106. {
  107. public:
  108. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  109. };
  110. //----------------------------------------------------------------------------------------------------
  111. class BotAllHostagesGoneMeme : public BotMeme
  112. {
  113. public:
  114. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  115. };
  116. //----------------------------------------------------------------------------------------------------
  117. class BotHostageBeingTakenMeme : public BotMeme
  118. {
  119. public:
  120. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  121. };
  122. //----------------------------------------------------------------------------------------------------
  123. class BotHeardNoiseMeme : public BotMeme
  124. {
  125. public:
  126. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  127. };
  128. //----------------------------------------------------------------------------------------------------
  129. class BotWarnSniperMeme : public BotMeme
  130. {
  131. public:
  132. virtual void Interpret( CCSBot *sender, CCSBot *receiver ) const; ///< cause the given bot to act on this meme
  133. };
  134. //----------------------------------------------------------------------------------------------------
  135. enum BotStatementType
  136. {
  137. REPORT_VISIBLE_ENEMIES,
  138. REPORT_ENEMY_ACTION,
  139. REPORT_MY_CURRENT_TASK,
  140. REPORT_MY_INTENTION,
  141. REPORT_CRITICAL_EVENT,
  142. REPORT_REQUEST_HELP,
  143. REPORT_REQUEST_INFORMATION,
  144. REPORT_ROUND_END,
  145. REPORT_MY_PLAN,
  146. REPORT_INFORMATION,
  147. REPORT_EMOTE,
  148. REPORT_ACKNOWLEDGE, ///< affirmative or negative
  149. REPORT_ENEMIES_REMAINING,
  150. REPORT_FRIENDLY_FIRE,
  151. REPORT_KILLED_FRIEND,
  152. REPORT_ENEMY_LOST,
  153. NUM_BOT_STATEMENT_TYPES
  154. };
  155. //----------------------------------------------------------------------------------------------------
  156. //----------------------------------------------------------------------------------------------------
  157. /**
  158. * BotSpeakables are the smallest unit of bot chatter.
  159. * They represent a specific wav file of a phrase, and the criteria for which it is useful
  160. */
  161. class BotSpeakable
  162. {
  163. public:
  164. BotSpeakable();
  165. ~BotSpeakable();
  166. char *m_phrase;
  167. float m_duration;
  168. PlaceCriteria m_place;
  169. CountCriteria m_count;
  170. };
  171. typedef CUtlVector< BotSpeakable * > BotSpeakableVector;
  172. typedef CUtlVector< BotSpeakableVector * > BotVoiceBankVector;
  173. //----------------------------------------------------------------------------------------------------
  174. /**
  175. * The BotPhrase class is a collection of Speakables associated with a name, ID, and criteria
  176. */
  177. class BotPhrase
  178. {
  179. public:
  180. char *GetSpeakable( int bankIndex, float *duration = NULL ) const; ///< return a random speakable and its duration in seconds that meets the current criteria
  181. // NOTE: Criteria must be set just before the GetSpeakable() call, since they are shared among all bots
  182. void ClearCriteria( void ) const;
  183. void SetPlaceCriteria( PlaceCriteria place ) const; ///< all returned phrases must have this place criteria
  184. void SetCountCriteria( CountCriteria count ) const; ///< all returned phrases must have this count criteria
  185. const char *GetName( void ) const { return m_name; }
  186. const unsigned int GetPlace( void ) const { return m_place; }
  187. RadioType GetRadioEquivalent( void ) const { return m_radioEvent; } ///< return equivalent "standard radio" event
  188. bool IsImportant( void ) const { return m_isImportant; } ///< return true if this phrase is part of an important statement
  189. bool IsPlace( void ) const { return m_isPlace; }
  190. void Randomize( void ); ///< randomly shuffle the speakable order
  191. private:
  192. friend class BotPhraseManager;
  193. BotPhrase( bool isPlace );
  194. ~BotPhrase();
  195. char *m_name;
  196. Place m_place;
  197. bool m_isPlace; ///< true if this is a Place phrase
  198. RadioType m_radioEvent; ///< equivalent radio event
  199. bool m_isImportant; ///< mission-critical statement
  200. mutable BotVoiceBankVector m_voiceBank; ///< array of voice banks (arrays of speakables)
  201. CUtlVector< int > m_count; ///< number of speakables
  202. mutable CUtlVector< int > m_index; ///< index of next speakable to return
  203. int m_numVoiceBanks; ///< number of voice banks that have been initialized
  204. void InitVoiceBank( int bankIndex ); ///< sets up the vector of voice banks for the first bankIndex voice banks
  205. mutable PlaceCriteria m_placeCriteria;
  206. mutable CountCriteria m_countCriteria;
  207. };
  208. typedef CUtlVector<BotPhrase *> BotPhraseList;
  209. inline void BotPhrase::ClearCriteria( void ) const
  210. {
  211. m_placeCriteria = ANY_PLACE;
  212. m_countCriteria = UNDEFINED_COUNT;
  213. }
  214. inline void BotPhrase::SetPlaceCriteria( PlaceCriteria place ) const
  215. {
  216. m_placeCriteria = place;
  217. }
  218. inline void BotPhrase::SetCountCriteria( CountCriteria count ) const
  219. {
  220. m_countCriteria = count;
  221. }
  222. enum BotChatterOutputType
  223. {
  224. BOT_CHATTER_RADIO,
  225. BOT_CHATTER_VOICE
  226. };
  227. typedef CUtlVector<BotChatterOutputType> BotOutputList;
  228. //----------------------------------------------------------------------------------------------------
  229. /**
  230. * The BotPhraseManager is a singleton that provides an interface to all BotPhrase collections
  231. */
  232. class BotPhraseManager
  233. {
  234. public:
  235. BotPhraseManager( void );
  236. ~BotPhraseManager();
  237. bool Initialize( const char *filename, int bankIndex ); ///< initialize phrase system from database file for a specific voice bank (0 is the default voice bank)
  238. void OnRoundRestart( void ); ///< invoked when round resets
  239. void OnMapChange( void ); ///< invoked when map changes
  240. void Reset( void );
  241. const BotPhrase *GetPhrase( const char *name ) const; ///< given a name, return the associated phrase collection
  242. const BotPhrase *GetPainPhrase( void ) const { return m_painPhrase; } ///< optimization, replaces a static pointer to the phrase
  243. const BotPhrase *GetAgreeWithPlanPhrase( void ) const { return m_agreeWithPlanPhrase; } ///< optimization, replaces a static pointer to the phrase
  244. const BotPhrase *GetPlace( const char *name ) const; ///< given a name, return the associated Place phrase collection
  245. const BotPhrase *GetPlace( unsigned int id ) const; ///< given an id, return the associated Place phrase collection
  246. const BotPhraseList *GetPlaceList( void ) const { return &m_placeList; }
  247. float GetPlaceStatementInterval( Place where ) const; ///< return time last statement of given type was emitted by a teammate for the given place
  248. void ResetPlaceStatementInterval( Place where ); ///< set time of last statement of given type was emitted by a teammate for the given place
  249. BotChatterOutputType GetOutputType( int voiceBank ) const;
  250. private:
  251. BotPhraseList m_list; ///< master list of all phrase collections
  252. BotPhraseList m_placeList; ///< master list of all Place phrases
  253. BotOutputList m_output;
  254. const BotPhrase *m_painPhrase;
  255. const BotPhrase *m_agreeWithPlanPhrase;
  256. struct PlaceTimeInfo
  257. {
  258. Place placeID;
  259. IntervalTimer timer;
  260. };
  261. mutable PlaceTimeInfo m_placeStatementHistory[ MAX_PLACES_PER_MAP ];
  262. mutable int m_placeCount;
  263. int FindPlaceIndex( Place where ) const;
  264. };
  265. inline int BotPhraseManager::FindPlaceIndex( Place where ) const
  266. {
  267. for( int i=0; i<m_placeCount; ++i )
  268. if (m_placeStatementHistory[i].placeID == where)
  269. return i;
  270. // no such place - allocate it
  271. if (m_placeCount < MAX_PLACES_PER_MAP)
  272. {
  273. m_placeStatementHistory[ ++m_placeCount ].placeID = where;
  274. m_placeStatementHistory[ ++m_placeCount ].timer.Invalidate();
  275. return m_placeCount-1;
  276. }
  277. // place directory is full
  278. return -1;
  279. }
  280. /**
  281. * Return time last statement of given type was emitted by a teammate for the given place
  282. */
  283. inline float BotPhraseManager::GetPlaceStatementInterval( Place place ) const
  284. {
  285. int index = FindPlaceIndex( place );
  286. if (index < 0)
  287. return 999999.9f;
  288. if (index >= m_placeCount)
  289. return 999999.9f;
  290. return m_placeStatementHistory[ index ].timer.GetElapsedTime();
  291. }
  292. /**
  293. * Set time of last statement of given type was emitted by a teammate for the given place
  294. */
  295. inline void BotPhraseManager::ResetPlaceStatementInterval( Place place )
  296. {
  297. int index = FindPlaceIndex( place );
  298. if (index < 0)
  299. return;
  300. if (index >= m_placeCount)
  301. return;
  302. // update entry
  303. m_placeStatementHistory[ index ].timer.Reset();
  304. }
  305. extern BotPhraseManager *TheBotPhrases;
  306. //----------------------------------------------------------------------------------------------------
  307. /**
  308. * Statements are meaningful collections of phrases
  309. */
  310. class BotStatement
  311. {
  312. public:
  313. BotStatement( BotChatterInterface *chatter, BotStatementType type, float expireDuration );
  314. ~BotStatement();
  315. BotChatterInterface *GetChatter( void ) const { return m_chatter; }
  316. CCSBot *GetOwner( void ) const;
  317. BotStatementType GetType( void ) const { return m_type; } ///< return the type of statement this is
  318. bool IsImportant( void ) const; ///< return true if this statement is "important" and not personality chatter
  319. bool HasSubject( void ) const { return (m_subject == UNDEFINED_SUBJECT) ? false : true; }
  320. void SetSubject( int playerID ) { m_subject = playerID; } ///< who this statement is about
  321. int GetSubject( void ) const { return m_subject; } ///< who this statement is about
  322. bool HasPlace( void ) const { return (GetPlace()) ? true : false; }
  323. Place GetPlace( void ) const; ///< if this statement refers to a specific place, return that place
  324. void SetPlace( Place where ) { m_place = where; } ///< explicitly set place
  325. bool HasCount( void ) const; ///< return true if this statement has an associated count
  326. bool IsRedundant( const BotStatement *say ) const; ///< return true if this statement is the same as the given one
  327. bool IsObsolete( void ) const; ///< return true if this statement is no longer appropriate to say
  328. void Convert( const BotStatement *say ); ///< possibly change what were going to say base on what teammate is saying
  329. void AppendPhrase( const BotPhrase *phrase );
  330. void SetStartTime( float timestamp ) { m_startTime = timestamp; } ///< define the earliest time this statement can be spoken
  331. float GetStartTime( void ) const { return m_startTime; }
  332. enum ConditionType
  333. {
  334. IS_IN_COMBAT,
  335. RADIO_SILENCE,
  336. ENEMIES_REMAINING,
  337. NUM_CONDITIONS
  338. };
  339. void AddCondition( ConditionType condition ); ///< conditions must be true for the statement to be spoken
  340. bool IsValid( void ) const; ///< verify all attached conditions
  341. enum ContextType
  342. {
  343. CURRENT_ENEMY_COUNT,
  344. REMAINING_ENEMY_COUNT,
  345. SHORT_DELAY,
  346. LONG_DELAY,
  347. ACCUMULATE_ENEMIES_DELAY
  348. };
  349. void AppendPhrase( ContextType contextPhrase ); ///< special phrases that depend on the context
  350. bool Update( void ); ///< emit statement over time, return false if statement is done
  351. bool IsSpeaking( void ) const { return m_isSpeaking; } ///< return true if this statement is currently being spoken
  352. float GetTimestamp( void ) const { return m_timestamp; } ///< get time statement was created (but not necessarily started talking)
  353. void AttachMeme( BotMeme *meme ); ///< attach a meme to this statement, to be transmitted to other friendly bots when spoken
  354. private:
  355. friend class BotChatterInterface;
  356. BotChatterInterface *m_chatter; ///< the chatter system this statement is part of
  357. BotStatement *m_next, *m_prev; ///< linked list hooks
  358. BotStatementType m_type; ///< what kind of statement this is
  359. int m_subject; ///< who this subject is about
  360. Place m_place; ///< explicit place - note some phrases have implicit places as well
  361. BotMeme *m_meme; ///< a statement can only have a single meme for now
  362. float m_timestamp; ///< time when message was created
  363. float m_startTime; ///< the earliest time this statement can be spoken
  364. float m_expireTime; ///< time when this statement is no longer valid
  365. float m_speakTimestamp; ///< time when message began being spoken
  366. bool m_isSpeaking; ///< true if this statement is current being spoken
  367. float m_nextTime; ///< time for next phrase to begin
  368. enum { MAX_BOT_PHRASES = 4 };
  369. struct
  370. {
  371. bool isPhrase;
  372. union
  373. {
  374. const BotPhrase *phrase;
  375. ContextType context;
  376. };
  377. }
  378. m_statement[ MAX_BOT_PHRASES ];
  379. enum { MAX_BOT_CONDITIONS = 4 };
  380. ConditionType m_condition[ MAX_BOT_CONDITIONS ]; ///< conditions that must be true for the statement to be said
  381. int m_conditionCount;
  382. int m_index; ///< m_index refers to the phrase currently being spoken, or -1 if we havent started yet
  383. int m_count;
  384. };
  385. //----------------------------------------------------------------------------------------------------
  386. /**
  387. * This class defines the interface to the bot radio chatter system
  388. */
  389. class BotChatterInterface
  390. {
  391. public:
  392. BotChatterInterface( CCSBot *me );
  393. ~BotChatterInterface( );
  394. void Reset( void ); ///< reset to initial state
  395. void Update( void ); ///< process ongoing chatter
  396. /// invoked when event occurs in the game (some events have NULL entities)
  397. void OnDeath( void ); ///< invoked when we die
  398. enum VerbosityType
  399. {
  400. NORMAL, ///< full chatter
  401. MINIMAL, ///< only scenario-critical events
  402. RADIO, ///< use the standard radio instead
  403. OFF ///< no chatter at all
  404. };
  405. VerbosityType GetVerbosity( void ) const; ///< return our current level of verbosity
  406. CCSBot *GetOwner( void ) const { return m_me; }
  407. bool IsTalking( void ) const; ///< return true if we are currently talking
  408. float GetRadioSilenceDuration( void ); ///< return time since any teammate said anything
  409. void ResetRadioSilenceDuration( void );
  410. enum { MUST_ADD = 1 };
  411. void AddStatement( BotStatement *statement, bool mustAdd = false ); ///< register a statement for speaking
  412. void RemoveStatement( BotStatement *statement ); ///< remove a statement
  413. BotStatement *GetActiveStatement( void ); ///< returns the statement that is being spoken, or is next to be spoken if no-one is speaking now
  414. BotStatement *GetStatement( void ) const; ///< returns our current statement, or NULL if we aren't speaking
  415. int GetPitch( void ) const { return m_pitch; }
  416. //-- things the bots can say ---------------------------------------------------------------------
  417. void Say( const char *phraseName, float lifetime = 3.0f, float delay = 0.0f );
  418. void AnnouncePlan( const char *phraseName, Place where );
  419. void Affirmative( void );
  420. void Negative( void );
  421. void EnemySpotted( void ); ///< report enemy sightings
  422. void KilledMyEnemy( int victimID );
  423. void EnemiesRemaining( void );
  424. void SpottedSniper( void );
  425. void FriendSpottedSniper( void );
  426. void Clear( Place where );
  427. void ReportIn( void ); ///< ask for current situation
  428. void ReportingIn( void ); ///< report current situation
  429. bool NeedBackup( void );
  430. void PinnedDown( void );
  431. void Scared( void );
  432. void HeardNoise( const Vector &pos );
  433. void FriendHeardNoise( void );
  434. void TheyPickedUpTheBomb( void );
  435. void GoingToPlantTheBomb( Place where );
  436. void BombsiteClear( int zoneIndex );
  437. void FoundPlantedBomb( int zoneIndex );
  438. void PlantingTheBomb( Place where );
  439. void SpottedBomber( CBasePlayer *bomber );
  440. void SpottedLooseBomb( CBaseEntity *bomb );
  441. void GuardingLooseBomb( CBaseEntity *bomb );
  442. void RequestBombLocation( void );
  443. #define IS_PLAN true
  444. void GuardingHostages( Place where, bool isPlan = false );
  445. void GuardingHostageEscapeZone( bool isPlan = false );
  446. void HostagesBeingTaken( void );
  447. void HostagesTaken( void );
  448. void TalkingToHostages( void );
  449. void EscortingHostages( void );
  450. void HostageDown( void );
  451. void GuardingBombsite( Place where );
  452. void CelebrateWin( void );
  453. void Encourage( const char *phraseName, float repeatInterval = 10.0f, float lifetime = 3.0f ); ///< "encourage" the player to do the scenario
  454. void KilledFriend( void );
  455. void FriendlyFire( void );
  456. bool SeesAtLeastOneEnemy( void ) const { return m_seeAtLeastOneEnemy; }
  457. private:
  458. BotStatement *m_statementList; ///< list of all active/pending messages for this bot
  459. void ReportEnemies( void ); ///< track nearby enemy count and generate enemy activity statements
  460. bool ShouldSpeak( void ) const; ///< return true if we speaking makes sense now
  461. CCSBot *m_me; ///< the bot this chatter is for
  462. bool m_seeAtLeastOneEnemy;
  463. float m_timeWhenSawFirstEnemy;
  464. bool m_reportedEnemies;
  465. bool m_requestedBombLocation; ///< true if we already asked where the bomb has been planted
  466. int m_pitch;
  467. static IntervalTimer m_radioSilenceInterval[ 2 ]; ///< one timer for each team
  468. IntervalTimer m_needBackupInterval;
  469. IntervalTimer m_spottedBomberInterval;
  470. IntervalTimer m_scaredInterval;
  471. IntervalTimer m_planInterval;
  472. CountdownTimer m_spottedLooseBombTimer;
  473. CountdownTimer m_heardNoiseTimer;
  474. CountdownTimer m_escortingHostageTimer;
  475. CountdownTimer m_warnSniperTimer;
  476. static CountdownTimer m_encourageTimer; ///< timer to know when we can "encourage" the human player again - shared by all bots
  477. };
  478. inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity( void ) const
  479. {
  480. const char *string = cv_bot_chatter.GetString();
  481. if (string == NULL)
  482. return NORMAL;
  483. if (string[0] == 'm' || string[0] == 'M')
  484. return MINIMAL;
  485. if (string[0] == 'r' || string[0] == 'R')
  486. return RADIO;
  487. if (string[0] == 'o' || string[0] == 'O')
  488. return OFF;
  489. return NORMAL;
  490. }
  491. inline bool BotChatterInterface::IsTalking( void ) const
  492. {
  493. if (m_statementList)
  494. return m_statementList->IsSpeaking();
  495. return false;
  496. }
  497. inline BotStatement *BotChatterInterface::GetStatement( void ) const
  498. {
  499. return m_statementList;
  500. }
  501. inline void BotChatterInterface::Say( const char *phraseName, float lifetime, float delay )
  502. {
  503. BotStatement *say = new BotStatement( this, REPORT_MY_INTENTION, lifetime );
  504. say->AppendPhrase( TheBotPhrases->GetPhrase( phraseName ) );
  505. if (delay > 0.0f)
  506. say->SetStartTime( gpGlobals->curtime + delay );
  507. AddStatement( say );
  508. }
  509. #endif // CS_BOT_CHATTER_H