//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: The CResponseSystem class. Don't include this header; include the response_types // into which it is transcluded. // // $NoKeywords: $ //=============================================================================// #ifndef RESPONSE_SYSTEM_H #define RESPONSE_SYSTEM_H #ifdef _WIN32 #pragma once #endif #include "utldict.h" namespace ResponseRules { typedef ResponseParams AI_ResponseParams ; #define AI_CriteriaSet ResponseRules::CriteriaSet //----------------------------------------------------------------------------- // Purpose: The database of all available responses. // The Rules are partitioned based on a variety of factors (presently, // speaker and concept) for faster lookup, basically a seperate-chained hash. //----------------------------------------------------------------------------- class CResponseSystem : public IResponseSystem { public: CResponseSystem(); ~CResponseSystem(); typedef void (CResponseSystem::*pfnResponseDispatch)( void ); typedef void (CResponseSystem::*pfnParseRuleDispatch)( Rule & ); typedef void (CResponseSystem::*pfnParseResponseDispatch)( ParserResponse &, ResponseGroup&, AI_ResponseParams * ); typedef void (CResponseSystem::*pfnParseResponseGroupDispatch) ( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); typedef CUtlMap< unsigned,pfnResponseDispatch > DispatchMap_t; typedef CUtlMap< unsigned,pfnParseRuleDispatch > ParseRuleDispatchMap_t; typedef CUtlMap< unsigned,pfnParseResponseDispatch > ParseResponseDispatchMap_t; typedef CUtlMap< unsigned,pfnParseResponseGroupDispatch > ParseResponseGroupDispatchMap_t; #pragma region IResponseSystem // IResponseSystem virtual bool FindBestResponse( const CriteriaSet& set, CRR_Response& response, IResponseFilter *pFilter = NULL ); virtual void GetAllResponses( CUtlVector *pResponses ); #pragma endregion Implement interface from IResponseSystem virtual void Release() = 0; virtual void DumpRules(); bool IsCustomManagable() { return m_bCustomManagable; } void Clear(); void DumpDictionary( const char *pszName ); protected: void BuildDispatchTables(); bool Dispatch( char const *pToken, unsigned int uiHash, DispatchMap_t &rMap ); bool DispatchParseRule( char const *pToken, unsigned int uiHash, ParseRuleDispatchMap_t &rMap, Rule &newRule ); bool DispatchParseResponse( char const *pToken, unsigned int uiHash, ParseResponseDispatchMap_t &rMap, ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); bool DispatchParseResponseGroup( char const *pToken, unsigned int uiHash, ParseResponseGroupDispatchMap_t &rMap, char const *responseGroupName, ResponseGroup& newGroup, AI_ResponseParams &groupResponseParams ); virtual const char *GetScriptFile( void ) = 0; void LoadRuleSet( const char *setname ); void ResetResponseGroups(); float LookForCriteria( const CriteriaSet &criteriaSet, int iCriteria ); float RecursiveLookForCriteria( const CriteriaSet &criteriaSet, Criteria *pParent ); public: void CopyRuleFrom( Rule *pSrcRule, ResponseRulePartition::tIndex iRule, CResponseSystem *pCustomSystem ); void CopyCriteriaFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ); void CopyResponsesFrom( Rule *pSrcRule, Rule *pDstRule, CResponseSystem *pCustomSystem ); void CopyEnumerationsFrom( CResponseSystem *pCustomSystem ); //private: struct Enumeration { float value; }; struct ResponseSearchResult { ResponseSearchResult() { group = NULL; action = NULL; } ResponseGroup *group; ParserResponse *action; }; inline bool ParseToken( void ) { if ( m_bUnget ) { m_bUnget = false; return true; } if ( m_ScriptStack.Count() <= 0 ) { Assert( 0 ); return false; } m_ScriptStack[ 0 ].currenttoken = IEngineEmulator::Get()->ParseFile( m_ScriptStack[ 0 ].currenttoken, token, sizeof( token ) ); m_ScriptStack[ 0 ].tokencount++; return m_ScriptStack[ 0 ].currenttoken != NULL ? true : false; } inline void Unget() { m_bUnget = true; } inline bool TokenWaiting( void ) { if ( m_ScriptStack.Count() <= 0 ) { Assert( 0 ); return false; } const char *p = m_ScriptStack[ 0 ].currenttoken; if ( !p ) { Error( "AI_ResponseSystem: Unxpected TokenWaiting() with NULL buffer in %s", (char * ) m_ScriptStack[ 0 ].name ); return false; } while ( *p && *p!='\n') { // Special handler for // comment blocks if ( *p == '/' && *(p+1) == '/' ) return false; if ( !V_isspace( *p ) || isalnum( *p ) ) return true; p++; } return false; } void ParseOneResponse( const char *responseGroupName, ResponseGroup& group, ResponseParams *defaultParams = NULL ); void ParseInclude( void ); void ParseResponse( void ); void ParseCriterion( void ); void ParseRule( void ); void ParseEnumeration( void ); private: void ParseRule_MatchOnce( Rule &newRule ); void ParseRule_ApplyContextToWorld( Rule &newRule ); void ParseRule_ApplyContext( Rule &newRule ); void ParseRule_Response( Rule &newRule ); //void ParseRule_ForceWeight( Rule &newRule ); void ParseRule_Criteria( Rule &newRule ); char const *m_pParseRuleName; bool m_bParseRuleValid; void ParseResponse_Weight( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_PreDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_NoDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_DefaultDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_Delay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_SpeakOnce( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_NoScene( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_StopOnNonIdle( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_Odds( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_RespeakDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_WeaponDelay( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_Soundlevel( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_DisplayFirst( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_DisplayLast( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_Fire( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponse_Then( ParserResponse &newResponse, ResponseGroup& group, AI_ResponseParams *rp ); void ParseResponseGroup_Start( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_PreDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_NoDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_DefaultDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_Delay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_SpeakOnce( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_NoScene( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_StopOnNonIdle( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_Odds( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_RespeakDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_WeaponDelay( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); void ParseResponseGroup_Soundlevel( char const *responseGroupName, ResponseGroup &newGroup, AI_ResponseParams &groupResponseParams ); public: int ParseOneCriterion( const char *criterionName ); bool Compare( const char *setValue, Criteria *c, bool verbose = false ); bool CompareUsingMatcher( const char *setValue, Matcher& m, bool verbose = false ); void ComputeMatcher( Criteria *c, Matcher& matcher ); void ResolveToken( Matcher& matcher, char *token, size_t bufsize, char const *rawtoken ); float LookupEnumeration( const char *name, bool& found ); ResponseRulePartition::tIndex FindBestMatchingRule( const CriteriaSet& set, bool verbose, float &scoreOfBestMatchingRule ); float ScoreCriteriaAgainstRule( const CriteriaSet& set, ResponseRulePartition::tRuleDict &dict, int irule, bool verbose = false ); float RecursiveScoreSubcriteriaAgainstRule( const CriteriaSet& set, Criteria *parent, bool& exclude, bool verbose /*=false*/ ); float ScoreCriteriaAgainstRuleCriteria( const CriteriaSet& set, int icriterion, bool& exclude, bool verbose = false ); void FakeDepletes( ResponseGroup *g, IResponseFilter *pFilter ); void RevertFakedDepletes( ResponseGroup *g ); bool GetBestResponse( ResponseSearchResult& result, Rule *rule, bool verbose = false, IResponseFilter *pFilter = NULL ); bool ResolveResponse( ResponseSearchResult& result, int depth, const char *name, bool verbose = false, IResponseFilter *pFilter = NULL ); int SelectWeightedResponseFromResponseGroup( ResponseGroup *g, IResponseFilter *pFilter ); void DescribeResponseGroup( ResponseGroup *group, int selected, int depth ); void DebugPrint( int depth, const char *fmt, ... ); void LoadFromBuffer( const char *scriptfile, const char *buffer ); void GetCurrentScript( char *buf, size_t buflen ); int GetCurrentToken() const; void SetCurrentScript( const char *script ); inline bool IsRootCommand( unsigned int hash ) const { int slot = m_RootCommandHashes.Find( hash ); return slot != m_RootCommandHashes.InvalidIndex(); } inline bool IsRootCommand() const { return IsRootCommand( RR_HASH( token ) ); } void PushScript( const char *scriptfile, unsigned char *buffer ); void PopScript(void); void ResponseWarning( const char *fmt, ... ); CUtlDict< ResponseGroup, short > m_Responses; CUtlDict< Criteria, short > m_Criteria; // CUtlDict< Rule, short > m_Rules; ResponseRulePartition m_RulePartitions; CUtlDict< Enumeration, short > m_Enumerations; CUtlVector m_FakedDepletes; char token[ 1204 ]; bool m_bUnget; bool m_bCustomManagable; struct ScriptEntry { unsigned char *buffer; FileNameHandle_t name; const char *currenttoken; int tokencount; }; CUtlVector< ScriptEntry > m_ScriptStack; CStringPool m_IncludedFiles; DispatchMap_t m_FileDispatch; ParseRuleDispatchMap_t m_RuleDispatch; ParseResponseDispatchMap_t m_ResponseDispatch; ParseResponseGroupDispatchMap_t m_ResponseGroupDispatch; CUtlRBTree< unsigned int > m_RootCommandHashes; // for debugging purposes only: concepts to be emitted from rr_debugresponses 2 typedef CUtlLinkedList< CRR_Concept, unsigned short, false, unsigned int > ExcludeList_t; static ExcludeList_t m_DebugExcludeList; friend class CDefaultResponseSystemSaveRestoreBlockHandler; friend class CResponseSystemSaveRestoreOps; }; // Some globals inherited from AI_Speech.h: const float AIS_DEF_MIN_DELAY = 2.8; // Minimum amount of time an NPCs will wait after someone has spoken before considering speaking again const float AIS_DEF_MAX_DELAY = 3.2; // Maximum amount of time an NPCs will wait after someone has spoken before considering speaking again } #endif // RESPONSE_SYSTEM_H