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.

638 lines
24 KiB

  1. //========= Copyright (c) 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #ifndef AI_SPEECH_H
  8. #define AI_SPEECH_H
  9. #include "utlmap.h"
  10. #include "soundflags.h"
  11. #include "ai_responsesystem.h"
  12. #include "utldict.h"
  13. #include "ai_speechconcept.h"
  14. #if defined( _WIN32 )
  15. #pragma once
  16. #endif
  17. class KeyValues;
  18. using ResponseRules::ResponseType_t;
  19. using ResponseRules::AI_ResponseFollowup;
  20. //-----------------------------------------------------------------------------
  21. // Purpose: Used to share a global resource or prevent a system stepping on
  22. // own toes.
  23. //-----------------------------------------------------------------------------
  24. class CAI_TimedSemaphore
  25. {
  26. public:
  27. CAI_TimedSemaphore()
  28. : m_ReleaseTime( 0 )
  29. {
  30. m_hCurrentTalker = NULL;
  31. }
  32. void Acquire( float time, CBaseEntity *pTalker ) { m_ReleaseTime = gpGlobals->curtime + time; m_hCurrentTalker = pTalker; }
  33. void Release() { m_ReleaseTime = 0; m_hCurrentTalker = NULL; }
  34. // Current owner of the semaphore is always allowed to talk
  35. bool IsAvailable( CBaseEntity *pTalker ) const { return ((gpGlobals->curtime > m_ReleaseTime) || (m_hCurrentTalker == pTalker)); }
  36. float GetReleaseTime() const { return m_ReleaseTime; }
  37. CBaseEntity *GetOwner() { return m_hCurrentTalker; }
  38. private:
  39. float m_ReleaseTime;
  40. EHANDLE m_hCurrentTalker;
  41. };
  42. //-----------------------------------------------------------------------------
  43. extern CAI_TimedSemaphore g_AIFriendliesTalkSemaphore;
  44. extern CAI_TimedSemaphore g_AIFoesTalkSemaphore;
  45. #define GetSpeechSemaphore( pNpc ) (((pNpc)->IsPlayerAlly()) ? &g_AIFriendliesTalkSemaphore : &g_AIFoesTalkSemaphore )
  46. //-----------------------------------------------------------------------------
  47. // Basic speech system types
  48. //-----------------------------------------------------------------------------
  49. //-------------------------------------
  50. // Constants
  51. const float AIS_NO_DELAY = 0;
  52. const soundlevel_t AIS_DEF_SNDLVL = SNDLVL_TALKING;
  53. #define AI_NULL_CONCEPT NULL
  54. #define AI_NULL_SENTENCE NULL
  55. // Sentence prefix constants
  56. #define AI_SP_SPECIFIC_SENTENCE '!'
  57. #define AI_SP_WAVFILE '^'
  58. #define AI_SP_SCENE_GROUP '='
  59. #define AI_SP_SPECIFIC_SCENE '?'
  60. #define AI_SPECIFIC_SENTENCE(str_constant) "!" str_constant
  61. #define AI_WAVFILE(str_constant) "^" str_constant
  62. // @Note (toml 09-12-02): as scene groups are not currently implemented, the string is a semi-colon delimited list
  63. #define AI_SCENE_GROUP(str_constant) "=" str_constant
  64. #define AI_SPECIFIC_SCENE(str_constant) "?" str_constant
  65. // Designer overriding modifiers
  66. #define AI_SPECIFIC_SCENE_MODIFIER "scene:"
  67. //-------------------------------------
  68. //-------------------------------------
  69. // An id that represents the core meaning of a spoken phrase,
  70. // eventually to be mapped to a sentence group or scene
  71. #if AI_CONCEPTS_ARE_STRINGS
  72. typedef const char *AIConcept_t;
  73. inline bool CompareConcepts( AIConcept_t c1, AIConcept_t c2 )
  74. {
  75. return ( (void *)c1 == (void *)c2 || ( c1 && c2 && Q_stricmp( c1, c2 ) == 0 ) );
  76. }
  77. #else
  78. typedef CAI_Concept AIConcept_t;
  79. inline bool CompareConcepts( AIConcept_t c1, AIConcept_t c2 )
  80. {
  81. return c1.m_iConcept == c2.m_iConcept;
  82. }
  83. #endif
  84. //-----------------------------------------------------------------------------
  85. // CAI_Expresser
  86. //
  87. // Purpose: Provides the functionality of going from abstract concept ("hello")
  88. // to specific sentence/scene/wave
  89. //
  90. //-------------------------------------
  91. // Sink supports behavior control and receives notifications of internal events
  92. class CAI_ExpresserSink
  93. {
  94. public:
  95. virtual void OnSpokeConcept( AIConcept_t concept, AI_Response *response ) {};
  96. virtual void OnStartSpeaking() {}
  97. virtual bool UseSemaphore() { return true; }
  98. };
  99. struct ConceptHistory_t
  100. {
  101. DECLARE_SIMPLE_DATADESC();
  102. ConceptHistory_t(float timeSpoken = -1 )
  103. : timeSpoken( timeSpoken ), m_response( )
  104. {
  105. }
  106. ConceptHistory_t( const ConceptHistory_t& src );
  107. ConceptHistory_t& operator = ( const ConceptHistory_t& src );
  108. ~ConceptHistory_t();
  109. float timeSpoken;
  110. AI_Response m_response;
  111. };
  112. //-------------------------------------
  113. class CAI_Expresser : public ResponseRules::IResponseFilter
  114. {
  115. public:
  116. CAI_Expresser( CBaseFlex *pOuter = NULL );
  117. ~CAI_Expresser();
  118. // --------------------------------
  119. bool Connect( CAI_ExpresserSink *pSink ) { m_pSink = pSink; return true; }
  120. bool Disconnect( CAI_ExpresserSink *pSink ) { m_pSink = NULL; return true;}
  121. void TestAllResponses();
  122. // --------------------------------
  123. bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
  124. bool Speak( AIConcept_t &concept, AI_CriteriaSet *criteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
  125. // Given modifiers (which are colon-delimited strings), fill out a criteria set including this
  126. // character's contexts and the ones in the modifier. This lets us hang on to them after a call
  127. // to SpeakFindResponse.
  128. void GatherCriteria( AI_CriteriaSet *outputCritera, const AIConcept_t &concept, const char *modifiers );
  129. // These two methods allow looking up a response and dispatching it to be two different steps
  130. // AI_Response *SpeakFindResponse( AIConcept_t concept, const char *modifiers = NULL );
  131. // AI_Response *SpeakFindResponse( AIConcept_t &concept, AI_CriteriaSet *criteria );
  132. // Find the appropriate response for the given concept. Return false if none found.
  133. // Fills out the response object that you provide.
  134. bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *modifiers = NULL );
  135. virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL );
  136. float GetResponseDuration( AI_Response *response );
  137. virtual int SpeakRawSentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL );
  138. bool SemaphoreIsAvailable( CBaseEntity *pTalker );
  139. float GetSemaphoreAvailableTime( CBaseEntity *pTalker );
  140. virtual void OnSpeechFinished() {};
  141. // This function can be overriden by games to suppress speech altogether during glue screens, etc
  142. static bool IsSpeechGloballySuppressed();
  143. // --------------------------------
  144. virtual bool IsSpeaking();
  145. bool CanSpeak();
  146. bool CanSpeakAfterMyself();
  147. float GetTimeSpeechComplete() const { return m_flStopTalkTime; }
  148. void BlockSpeechUntil( float time );
  149. // --------------------------------
  150. bool CanSpeakConcept( AIConcept_t concept );
  151. bool SpokeConcept( AIConcept_t concept );
  152. float GetTimeSpokeConcept( AIConcept_t concept ); // returns -1 if never
  153. void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true );
  154. void ClearSpokeConcept( AIConcept_t concept );
  155. // --------------------------------
  156. void SetVoicePitch( int voicePitch ) { m_voicePitch = voicePitch; }
  157. int GetVoicePitch() const;
  158. void NoteSpeaking( float duration, float delay = 0 );
  159. // Force the NPC to release the semaphore & clear next speech time
  160. void ForceNotSpeaking( void );
  161. // helper used in dealing with RESPONSE_ENTITYIO
  162. // response is the output of AI_Response::GetName
  163. // note: the response string will get stomped on (by strtok)
  164. // returns false on failure (eg, couldn't match parse contents)
  165. static bool FireEntIOFromResponse( char *response, CBaseEntity *pInitiator );
  166. protected:
  167. CAI_TimedSemaphore *GetMySpeechSemaphore( CBaseEntity *pNpc );
  168. bool SpeakRawScene( const char *pszScene, float delay, AI_Response *response, IRecipientFilter *filter = NULL );
  169. // This will create a fake .vcd/CChoreoScene to wrap the sound to be played
  170. bool SpeakAutoGeneratedScene( char const *soundname, float delay );
  171. void DumpHistories();
  172. void SpeechMsg( CBaseEntity *pFlex, const char *pszFormat, ... );
  173. // --------------------------------
  174. CAI_ExpresserSink *GetSink() { return m_pSink; }
  175. private:
  176. // --------------------------------
  177. virtual bool IsValidResponse( ResponseType_t type, const char *pszValue );
  178. // --------------------------------
  179. CAI_ExpresserSink *m_pSink;
  180. // --------------------------------
  181. //
  182. // Speech concept data structures
  183. //
  184. CUtlDict< ConceptHistory_t, int > m_ConceptHistories;
  185. // --------------------------------
  186. //
  187. // Speaking states
  188. //
  189. float m_flStopTalkTime; // when in the future that I'll be done saying this sentence.
  190. float m_flStopTalkTimeWithoutDelay; // same as the above, but minus the delay before other people can speak
  191. float m_flBlockedTalkTime;
  192. int m_voicePitch; // pitch of voice for this head
  193. float m_flLastTimeAcceptedSpeak; // because speech may not be blocked until NoteSpeaking called by scene ent, this handles in-think blocking
  194. DECLARE_SIMPLE_DATADESC();
  195. // --------------------------------
  196. //
  197. public:
  198. void SetOuter( CBaseFlex *pOuter );
  199. CBaseFlex * GetOuter() { return m_pOuter; }
  200. const CBaseFlex * GetOuter() const { return m_pOuter; }
  201. private:
  202. CHandle<CBaseFlex> m_pOuter;
  203. };
  204. //-----------------------------------------------------------------------------
  205. //
  206. // An NPC base class to assist a branch of the inheritance graph
  207. // in utilizing CAI_Expresser
  208. //
  209. template <class BASE_NPC>
  210. class CAI_ExpresserHost : public BASE_NPC, protected CAI_ExpresserSink
  211. {
  212. DECLARE_CLASS_NOFRIEND( CAI_ExpresserHost, BASE_NPC );
  213. public:
  214. virtual void NoteSpeaking( float duration, float delay );
  215. virtual bool Speak( AIConcept_t concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
  216. virtual bool Speak( AIConcept_t concept, AI_CriteriaSet *pCriteria, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
  217. void GatherCriteria( AI_CriteriaSet *outputCritera, const AIConcept_t &concept, const char *modifiers );
  218. // These two methods allow looking up a response and dispatching it to be two different steps
  219. // AI_Response * SpeakFindResponse( AIConcept_t concept, const char *modifiers = NULL );
  220. // AI_Response *SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria );
  221. // AI_Response *SpeakFindResponse( AIConcept_t concept );
  222. // Find the appropriate response for the given concept. Return false if none found.
  223. // Fills out the response object that you provide.
  224. bool FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria = NULL );
  225. bool SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria = NULL );
  226. virtual void PostSpeakDispatchResponse( AIConcept_t concept, AI_Response *response ) { return; }
  227. float GetResponseDuration( AI_Response *response );
  228. float GetTimeSpeechComplete() const { return this->GetExpresser()->GetTimeSpeechComplete(); }
  229. bool IsSpeaking() { return this->GetExpresser()->IsSpeaking(); }
  230. bool CanSpeak() { return this->GetExpresser()->CanSpeak(); }
  231. bool CanSpeakAfterMyself() { return this->GetExpresser()->CanSpeakAfterMyself(); }
  232. void SetSpokeConcept( AIConcept_t concept, AI_Response *response, bool bCallback = true ) { this->GetExpresser()->SetSpokeConcept( concept, response, bCallback ); }
  233. float GetTimeSpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->GetTimeSpokeConcept( concept ); }
  234. bool SpokeConcept( AIConcept_t concept ) { return this->GetExpresser()->SpokeConcept( concept ); }
  235. protected:
  236. int PlaySentence( const char *pszSentence, float delay, float volume = VOL_NORM, soundlevel_t soundlevel = SNDLVL_TALKING, CBaseEntity *pListener = NULL );
  237. virtual void ModifyOrAppendCriteria( AI_CriteriaSet& set );
  238. virtual ResponseRules::IResponseSystem *GetResponseSystem();
  239. // Override of base entity response input handler
  240. virtual void DispatchResponse( const char *conceptName );
  241. };
  242. //-----------------------------------------------------------------------------
  243. //-----------------------------------------------------------------------------
  244. template <class BASE_NPC>
  245. inline void CAI_ExpresserHost<BASE_NPC>::NoteSpeaking( float duration, float delay )
  246. {
  247. this->GetExpresser()->NoteSpeaking( duration, delay );
  248. }
  249. //-----------------------------------------------------------------------------
  250. //-----------------------------------------------------------------------------
  251. template <class BASE_NPC>
  252. inline bool CAI_ExpresserHost<BASE_NPC>::Speak( AIConcept_t concept, const char *modifiers /*= NULL*/, char *pszOutResponseChosen /*=NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ )
  253. {
  254. AssertOnce( this->GetExpresser()->GetOuter() == this );
  255. return this->GetExpresser()->Speak( concept, modifiers, pszOutResponseChosen, bufsize, filter );
  256. }
  257. //-----------------------------------------------------------------------------
  258. //-----------------------------------------------------------------------------
  259. template <class BASE_NPC>
  260. inline bool CAI_ExpresserHost<BASE_NPC>::Speak( AIConcept_t concept, AI_CriteriaSet *pCriteria, char *pszOutResponseChosen /*=NULL*/, size_t bufsize /* = 0 */, IRecipientFilter *filter /* = NULL */ )
  261. {
  262. AssertOnce( this->GetExpresser()->GetOuter() == this );
  263. CAI_Expresser * const RESTRICT pExpresser = this->GetExpresser();
  264. concept.SetSpeaker( this );
  265. // add in any local criteria to the one passed on the command line.
  266. pExpresser->GatherCriteria( pCriteria, concept, NULL );
  267. // call the "I have aleady gathered criteria" version of Expresser::Speak
  268. return pExpresser->Speak( concept, pCriteria, pszOutResponseChosen, bufsize, filter );
  269. }
  270. //-----------------------------------------------------------------------------
  271. //-----------------------------------------------------------------------------
  272. template <class BASE_NPC>
  273. inline int CAI_ExpresserHost<BASE_NPC>::PlaySentence( const char *pszSentence, float delay, float volume, soundlevel_t soundlevel, CBaseEntity *pListener )
  274. {
  275. return this->GetExpresser()->SpeakRawSentence( pszSentence, delay, volume, soundlevel, pListener );
  276. }
  277. //-----------------------------------------------------------------------------
  278. //-----------------------------------------------------------------------------
  279. extern void CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( CAI_BaseNPC *pSpeaker, AI_CriteriaSet& criteriaSet );
  280. template <class BASE_NPC>
  281. inline void CAI_ExpresserHost<BASE_NPC>::ModifyOrAppendCriteria( AI_CriteriaSet& criteriaSet )
  282. {
  283. BaseClass::ModifyOrAppendCriteria( criteriaSet );
  284. #ifndef TERROR // no such thing as NPC pointers in L4D
  285. if ( this->MyNPCPointer() )
  286. {
  287. CAI_ExpresserHost_NPC_DoModifyOrAppendCriteria( this->MyNPCPointer(), criteriaSet );
  288. }
  289. #endif
  290. }
  291. //-----------------------------------------------------------------------------
  292. //-----------------------------------------------------------------------------
  293. template <class BASE_NPC>
  294. inline ResponseRules::IResponseSystem *CAI_ExpresserHost<BASE_NPC>::GetResponseSystem()
  295. {
  296. extern ResponseRules::IResponseSystem *g_pResponseSystem;
  297. // Expressive NPC's use the general response system
  298. return g_pResponseSystem;
  299. }
  300. //-----------------------------------------------------------------------------
  301. //-----------------------------------------------------------------------------
  302. template <class BASE_NPC>
  303. inline void CAI_ExpresserHost<BASE_NPC>::GatherCriteria( AI_CriteriaSet *outputCriteria, const AIConcept_t &concept, const char *modifiers )
  304. {
  305. return this->GetExpresser()->GatherCriteria( outputCriteria, concept, modifiers );
  306. }
  307. #if 0
  308. //-----------------------------------------------------------------------------
  309. //-----------------------------------------------------------------------------
  310. template <class BASE_NPC>
  311. inline AI_Response *CAI_ExpresserHost<BASE_NPC>::SpeakFindResponse( AIConcept_t concept, const char *modifiers /*= NULL*/ )
  312. {
  313. return this->GetExpresser()->SpeakFindResponse( concept, modifiers );
  314. }
  315. #endif
  316. #if 0
  317. //-----------------------------------------------------------------------------
  318. //-----------------------------------------------------------------------------
  319. template <class BASE_NPC>
  320. inline AI_Response *CAI_ExpresserHost<BASE_NPC>::SpeakFindResponse( AIConcept_t concept, AI_CriteriaSet *criteria /*= NULL*/ )
  321. {
  322. return this->GetExpresser()->SpeakFindResponse( concept, criteria );
  323. }
  324. //-----------------------------------------------------------------------------
  325. // In this case we clearly don't care to hang on to the criteria, so make a convenience
  326. // class that generates a one off.
  327. //-----------------------------------------------------------------------------
  328. template <class BASE_NPC>
  329. inline AI_Response * CAI_ExpresserHost<BASE_NPC>::SpeakFindResponse( AIConcept_t concept )
  330. {
  331. AI_CriteriaSet criteria;
  332. GatherCriteria( &criteria, concept, NULL );
  333. return this->GetExpresser()->SpeakFindResponse( concept, &criteria );
  334. }
  335. #endif
  336. //-----------------------------------------------------------------------------
  337. //-----------------------------------------------------------------------------
  338. template <class BASE_NPC>
  339. inline bool CAI_ExpresserHost<BASE_NPC>::FindResponse( AI_Response &outResponse, AIConcept_t &concept, AI_CriteriaSet *criteria )
  340. {
  341. return this->GetExpresser()->FindResponse( outResponse, concept, criteria );
  342. }
  343. //-----------------------------------------------------------------------------
  344. //-----------------------------------------------------------------------------
  345. template <class BASE_NPC>
  346. inline bool CAI_ExpresserHost<BASE_NPC>::SpeakDispatchResponse( AIConcept_t concept, AI_Response *response, AI_CriteriaSet *criteria )
  347. {
  348. if ( this->GetExpresser()->SpeakDispatchResponse( concept, response, criteria ) )
  349. {
  350. PostSpeakDispatchResponse( concept, response );
  351. return true;
  352. }
  353. return false;
  354. }
  355. //-----------------------------------------------------------------------------
  356. //-----------------------------------------------------------------------------
  357. template <class BASE_NPC>
  358. inline float CAI_ExpresserHost<BASE_NPC>::GetResponseDuration( AI_Response *response )
  359. {
  360. return this->GetExpresser()->GetResponseDuration( response );
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Override of base entity response input handler
  364. //-----------------------------------------------------------------------------
  365. template <class BASE_NPC>
  366. inline void CAI_ExpresserHost<BASE_NPC>::DispatchResponse( const char *conceptName )
  367. {
  368. Speak( (AIConcept_t)conceptName );
  369. }
  370. //-----------------------------------------------------------------------------
  371. /// A shim under CAI_ExpresserHost you can use when deriving a new expresser
  372. /// host type under CAI_BaseNPC. This does the extra step of declaring an m_pExpresser
  373. /// member and initializing it from CreateComponents(). If your BASE_NPC class isn't
  374. /// actually an NPC, then CreateComponents() never gets called and you won't have
  375. /// an expresser created.
  376. /// Note: you still need to add m_pExpresser to the Datadesc for your derived type.
  377. /// This is because I couldn't figure out how to make a templatized datadesc declaration
  378. /// that works generically on the template type.
  379. template <class BASE_NPC, class EXPRESSER_TYPE>
  380. class CAI_ExpresserHostWithData : public CAI_ExpresserHost<BASE_NPC>
  381. {
  382. DECLARE_CLASS_NOFRIEND( CAI_ExpresserHostWithData, CAI_ExpresserHost<BASE_NPC> );
  383. public:
  384. CAI_ExpresserHostWithData( ) : m_pExpresser(NULL) {};
  385. virtual CAI_Expresser *GetExpresser() { return m_pExpresser; }
  386. const CAI_Expresser *GetExpresser() const { return m_pExpresser; }
  387. virtual bool CreateComponents()
  388. {
  389. return BaseClass::CreateComponents() && ( CreateExpresser() != NULL );
  390. }
  391. protected:
  392. EXPRESSER_TYPE *CreateExpresser( void )
  393. {
  394. AssertMsg1( m_pExpresser == NULL, "Tried to double-initialize expresser in %s\n", this->GetDebugName() );
  395. m_pExpresser = new EXPRESSER_TYPE(this);
  396. if ( !m_pExpresser)
  397. {
  398. AssertMsg1( false, "Creating an expresser failed in %s\n", this->GetDebugName() );
  399. return NULL;
  400. }
  401. m_pExpresser->Connect(this);
  402. return m_pExpresser;
  403. }
  404. virtual ~CAI_ExpresserHostWithData( void )
  405. {
  406. delete m_pExpresser;
  407. m_pExpresser = NULL;
  408. }
  409. EXPRESSER_TYPE *m_pExpresser;
  410. };
  411. /// response rules
  412. namespace RR
  413. {
  414. /// some applycontext clauses have operators preceding them,
  415. /// like ++1 which means "take the current value and increment it
  416. /// by one". These classes detect these cases and do the appropriate
  417. /// thing.
  418. class CApplyContextOperator
  419. {
  420. public:
  421. inline CApplyContextOperator( int nSkipChars ) : m_nSkipChars(nSkipChars) {};
  422. /// perform whatever this operator does upon the given context value.
  423. /// Default op is simply to copy old to new.
  424. /// pOldValue should be the currently set value of the context. May be NULL meaning no prior value.
  425. /// pOperator the value that applycontext says to set
  426. /// pNewValue a pointer to a buffer where the real new value will be writ.
  427. /// returns true on success; false on failure (eg, tried to increment a
  428. /// non-numeric value).
  429. virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize );
  430. /// This is the function that should be called from outside,
  431. /// fed the input string, it'll select the right operator
  432. /// to apply.
  433. static CApplyContextOperator *FindOperator( const char *pContextString );
  434. protected:
  435. int m_nSkipChars; // how many chars to "skip" in the value string to get past the op specifier to the actual value
  436. // eg, "++3" has a m_nSkipChars of 2, because the op string "++" is two characters.
  437. };
  438. class CIncrementOperator : public CApplyContextOperator
  439. {
  440. public:
  441. inline CIncrementOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {};
  442. virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize );
  443. };
  444. class CDecrementOperator : public CApplyContextOperator
  445. {
  446. public:
  447. inline CDecrementOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {};
  448. virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize );
  449. };
  450. class CToggleOperator : public CApplyContextOperator
  451. {
  452. public:
  453. inline CToggleOperator( int nSkipChars ) : CApplyContextOperator(nSkipChars) {};
  454. virtual bool Apply( const char *pOldValue, const char *pOperator, char *pNewValue, int pNewValBufSize );
  455. };
  456. // the singleton operators
  457. extern CApplyContextOperator sm_OpCopy;
  458. extern CIncrementOperator sm_OpIncrement;
  459. extern CDecrementOperator sm_OpDecrement;
  460. extern CToggleOperator sm_OpToggle;
  461. };
  462. //-----------------------------------------------------------------------------
  463. #include "ai_speechqueue.h"
  464. //-----------------------------------------------------------------------------
  465. // A kind of AI Expresser that can dispatch a follow-up speech event when it
  466. // finishes speaking.
  467. //-----------------------------------------------------------------------------
  468. class CAI_ExpresserWithFollowup : public CAI_Expresser
  469. {
  470. public:
  471. CAI_ExpresserWithFollowup( CBaseFlex *pOuter = NULL ) : CAI_Expresser(pOuter),
  472. m_pPostponedFollowup(NULL)
  473. {};
  474. virtual bool Speak( AIConcept_t &concept, const char *modifiers = NULL, char *pszOutResponseChosen = NULL, size_t bufsize = 0, IRecipientFilter *filter = NULL );
  475. virtual bool SpeakDispatchResponse( AIConcept_t &concept, AI_Response *response, AI_CriteriaSet *criteria, IRecipientFilter *filter = NULL );
  476. virtual void SpeakDispatchFollowup( AI_ResponseFollowup &followup );
  477. virtual void OnSpeechFinished();
  478. typedef CAI_Expresser BaseClass;
  479. protected:
  480. static void DispatchFollowupThroughQueue( const AIConcept_t &concept,
  481. const char *criteriaStr,
  482. const CResponseQueue::CFollowupTargetSpec_t &target,
  483. float delay,
  484. CBaseEntity * RESTRICT pOuter );
  485. AI_ResponseFollowup *m_pPostponedFollowup; // TODO: save/restore
  486. CResponseQueue::CFollowupTargetSpec_t m_followupTarget;
  487. };
  488. class CMultiplayer_Expresser : public CAI_ExpresserWithFollowup
  489. {
  490. public:
  491. CMultiplayer_Expresser( CBaseFlex *pOuter = NULL );
  492. //~CMultiplayer_Expresser();
  493. virtual bool IsSpeaking();
  494. void AllowMultipleScenes();
  495. void DisallowMultipleScenes();
  496. private:
  497. bool m_bAllowMultipleScenes;
  498. };
  499. #endif // AI_SPEECH_H