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.
293 lines
12 KiB
293 lines
12 KiB
//========= 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
|
|
class 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<CRR_Response> *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 ) || V_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, PRINTF_FORMAT_STRING const char *fmt, ... ) FMTFUNCTION( 3, 4 );
|
|
|
|
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( PRINTF_FORMAT_STRING const char *fmt, ... ) FMTFUNCTION( 2, 3 );
|
|
|
|
CUtlDict< ResponseGroup, short > m_Responses;
|
|
CUtlDict< Criteria, short > m_Criteria;
|
|
// CUtlDict< Rule, short > m_Rules;
|
|
ResponseRulePartition m_RulePartitions;
|
|
CUtlDict< Enumeration, short > m_Enumerations;
|
|
|
|
CUtlVector<int> 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
|