Counter Strike : Global Offensive Source Code
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.

239 lines
8.8 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: An event queue of AI concepts that dispatches them to appropriate characters.
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef AI_SPEECHQUEUE_H
  8. #define AI_SPEECHQUEUE_H
  9. #if defined( _WIN32 )
  10. #pragma once
  11. #endif
  12. #include "ai_speech.h"
  13. #define AI_RESPONSE_QUEUE_SIZE 64
  14. enum DeferredResponseTarget_t // possible targets for a deferred response
  15. {
  16. kDRT_ANY, // best matching respondent within range -- except for the one in the m_hTarget handle
  17. kDRT_ALL, // send to everyone in range -- except for the one in the m_hTarget handle
  18. kDRT_SPECIFIC, // a specific entity is targeted
  19. kDRT_MAX, // high water mark
  20. };
  21. // Allows you to postpone AI speech concepts to a later time, or to direct them to
  22. // a specific character, or all of them.
  23. class CResponseQueue
  24. {
  25. //////////////////// Local types ////////////////////
  26. public:
  27. // We pack up contexts to send along with the concept.
  28. // For now I'll just copy criteria sets, but it will be better to do something
  29. // more efficient in the future.
  30. typedef AI_CriteriaSet DeferredContexts_t;
  31. struct CFollowupTargetSpec_t ///< to whom a followup is directed. Can be a specific entity or something more exotic.
  32. {
  33. DeferredResponseTarget_t m_iTargetType; ///< ANY, ALL, or SPECIFIC. If specific, pass through a handle to:
  34. EHANDLE m_hHandle; ///< a specific target for the message, or a specific character to OMIT.
  35. inline bool IsValid( void ) const;
  36. // constructors/destructors
  37. explicit CFollowupTargetSpec_t(const DeferredResponseTarget_t &targetType, const EHANDLE &handle)
  38. : m_iTargetType(targetType), m_hHandle(handle)
  39. {};
  40. explicit CFollowupTargetSpec_t(const EHANDLE &handle)
  41. : m_iTargetType(kDRT_SPECIFIC), m_hHandle(handle)
  42. {};
  43. CFollowupTargetSpec_t(DeferredResponseTarget_t target) // eg, ANY, ALL, etc.
  44. : m_iTargetType(target)
  45. {
  46. AssertMsg(m_iTargetType != kDRT_SPECIFIC, "Response rule followup tried to specify an entity target, but didn't provide the target.\n" );
  47. }
  48. CFollowupTargetSpec_t(void) // default: invalid
  49. : m_iTargetType(kDRT_MAX)
  50. {};
  51. };
  52. /// A single deferred response.
  53. struct CDeferredResponse
  54. {
  55. AIConcept_t m_concept;
  56. DeferredContexts_t m_contexts; ///< contexts to send along with the concept
  57. float m_fDispatchTime;
  58. EHANDLE m_hIssuer; ///< an entity, if issued by an entity
  59. /*
  60. DeferredResponseTarget_t m_iTargetType;
  61. EHANDLE m_hTarget; // May be invalid.
  62. */
  63. CFollowupTargetSpec_t m_Target;
  64. inline void Init( const AIConcept_t &concept, const AI_CriteriaSet * RESTRICT contexts, float dtime, const CFollowupTargetSpec_t &target, CBaseEntity *pIssuer );
  65. inline bool IsQuashed() { return !m_Target.IsValid(); }
  66. void Quash(); ///< make this response invalid.
  67. };
  68. /// write
  69. static void DeferContextsFromCriteriaSet( DeferredContexts_t &contextsOut, const AI_CriteriaSet *criteriaIn );
  70. //////////////////// Methods ////////////////////
  71. public:
  72. CResponseQueue( int queueSize );
  73. /// Add a deferred response.
  74. void Add( const AIConcept_t &concept, ///< concept to dispatch
  75. const AI_CriteriaSet * RESTRICT contexts, ///< the contexts that come with it (may be NULL)
  76. float time, ///< when to dispatch it. You can specify a time of zero to mean "immediately."
  77. const CFollowupTargetSpec_t &targetspec, /// All information necessary to target this response
  78. CBaseEntity *pIssuer = NULL ///< the entity who should not respond if this is a ANY or ALL rule. (eg, don't let people talk to themselves.)
  79. );
  80. /// Remove all deferred responses matching the concept and issuer.
  81. void Remove( const AIConcept_t &concept, ///< concept to dispatch
  82. CBaseEntity * const pIssuer = NULL ///< the entity issuing the response, if one exists.
  83. ) RESTRICT;
  84. /// Remove all deferred responses queued to be spoken by given character
  85. void RemoveSpeechQueuedFor( const CBaseEntity *pSpeaker );
  86. /// Empty out all pending events
  87. void Evacuate();
  88. /// Go through and dispatch any deferred responses.
  89. void PerFrameDispatch();
  90. /// Add an expressor owner to this queue.
  91. void AddExpresserHost(CBaseEntity *host);
  92. /// Remove an expresser host from this queue.
  93. void RemoveExpresserHost(CBaseEntity *host);
  94. /// Iterate over potential expressers for this queue
  95. inline int GetNumExpresserTargets() const;
  96. inline CBaseEntity *GetExpresserHost(int which) const;
  97. protected:
  98. /// Actually send off one response to a consumer
  99. /// Return true if dispatch succeeded
  100. bool DispatchOneResponse( CDeferredResponse &response );
  101. private:
  102. /// Helper function for one case in DispatchOneResponse
  103. /// (for better organization)
  104. bool DispatchOneResponse_ThenANY( CDeferredResponse &response, AI_CriteriaSet * RESTRICT pDeferredCriteria, CBaseEntity * const RESTRICT pIssuer, float followupMaxDistSq );
  105. //////////////////// Data ////////////////////
  106. protected:
  107. typedef CUtlFixedLinkedList< CDeferredResponse > QueueType_t;
  108. QueueType_t m_Queue; // the queue of deferred responses, will eventually be sorted
  109. /// Note about the queue type: if you move to replace it with a sorted priority queue,
  110. /// make sure it is a type such that an iterator is not invalidated by inserts and deletes.
  111. /// CResponseQueue::PerFrameDispatch() iterates over the queue calling DispatchOneResponse
  112. /// on each in turn, and those responses may very easily add new events to the queue.
  113. /// A crash will result if the iterator used in CResponseQueue::PerFrameDispatch()'s loop
  114. /// becomes invalid.
  115. CUtlVector<EHANDLE> m_ExpresserTargets; // a list of legitimate expresser targets
  116. };
  117. inline void CResponseQueue::CDeferredResponse::Init(const AIConcept_t &concept, const AI_CriteriaSet * RESTRICT contexts, float dtime, const CFollowupTargetSpec_t &target, CBaseEntity *pIssuer )
  118. {
  119. m_concept = concept;
  120. m_fDispatchTime = dtime;
  121. /*
  122. m_iTargetType = targetType;
  123. m_hTarget = handle ;
  124. */
  125. m_Target = target;
  126. m_hIssuer = pIssuer;
  127. DeferContextsFromCriteriaSet(m_contexts, contexts);
  128. }
  129. int CResponseQueue::GetNumExpresserTargets() const
  130. {
  131. return m_ExpresserTargets.Count();
  132. }
  133. CBaseEntity *CResponseQueue::GetExpresserHost(int which) const
  134. {
  135. return m_ExpresserTargets[which];
  136. }
  137. // The wrapper game system that contains a response queue, and ticks it each frame.
  138. class CResponseQueueManager : public CAutoGameSystemPerFrame
  139. {
  140. public:
  141. CResponseQueueManager(char const *name) : CAutoGameSystemPerFrame( name )
  142. {
  143. m_pQueue = NULL;
  144. }
  145. virtual ~CResponseQueueManager(void);
  146. virtual void Shutdown();
  147. virtual void FrameUpdatePostEntityThink( void );
  148. virtual void LevelInitPreEntity( void );
  149. inline CResponseQueue *GetQueue(void) { Assert(m_pQueue); return m_pQueue; }
  150. protected:
  151. CResponseQueue *m_pQueue;
  152. };
  153. // Valid if the target type enum is within bounds. Furthermore if it
  154. // specifies a specific entity, that handle must be valid.
  155. bool CResponseQueue::CFollowupTargetSpec_t::IsValid( void ) const
  156. {
  157. if (m_iTargetType >= kDRT_MAX)
  158. return false;
  159. if (m_iTargetType < 0)
  160. return false;
  161. if (m_iTargetType == kDRT_SPECIFIC && !m_hHandle.IsValid())
  162. return false;
  163. return true;
  164. }
  165. extern CResponseQueueManager g_ResponseQueueManager;
  166. // Handy global helper funcs
  167. /// Automatically queue up speech to happen immediately -- calls straight through to response rules add
  168. inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say
  169. const CResponseQueue::CFollowupTargetSpec_t& targetspec, ///< kDRT_ANY, kDRT_ALL, etc
  170. CBaseEntity *pIssuer = NULL ///< if specifying ANY or ALL, use this to specify the one you *don't* want to speak
  171. )
  172. {
  173. return g_ResponseQueueManager.GetQueue()->Add( concept, NULL, 0.0f, targetspec, pIssuer );
  174. }
  175. /// Automatically queue up speech to happen immediately -- calls straight through to response rules add
  176. inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say
  177. const CResponseQueue::CFollowupTargetSpec_t& targetspec, ///< kDRT_ANY, kDRT_ALL, etc
  178. const AI_CriteriaSet &criteria, ///< criteria to pass in
  179. CBaseEntity *pIssuer = NULL ///< if specifying ANY or ALL, use this to specify the one you *don't* want to speak
  180. )
  181. {
  182. return g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, 0.0f, targetspec, pIssuer );
  183. }
  184. /// Automatically queue up speech to happen immediately -- calls straight through to response rules add
  185. inline void QueueSpeak( const AIConcept_t &concept, ///< concept name to say
  186. const EHANDLE &target, ///< which entity shall speak
  187. float delay, ///< how far in the future to speak
  188. const AI_CriteriaSet &criteria, ///< criteria to pass in
  189. CBaseEntity *pIssuer = NULL )
  190. {
  191. return g_ResponseQueueManager.GetQueue()->Add( concept, &criteria, gpGlobals->curtime + delay,
  192. CResponseQueue::CFollowupTargetSpec_t(target), pIssuer );
  193. }
  194. #endif // AI_SPEECHQUEUE_H