initial
This commit is contained in:
293
common/responserules/response_system.h
Normal file
293
common/responserules/response_system.h
Normal file
@@ -0,0 +1,293 @@
|
||||
//========= Copyright <20> 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
|
||||
543
common/responserules/response_types_internal.h
Normal file
543
common/responserules/response_types_internal.h
Normal file
@@ -0,0 +1,543 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose: Core types for the response rules -- criteria, responses, rules, and matchers.
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef RESPONSE_TYPES_INTERNAL_H
|
||||
#define RESPONSE_TYPES_INTERNAL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "responserules/response_types.h"
|
||||
#include "utldict.h"
|
||||
|
||||
|
||||
namespace ResponseRules
|
||||
{
|
||||
|
||||
const char *ResponseCopyString( const char *in );
|
||||
|
||||
inline unsigned FASTCALL HashStringConventional( const char *pszKey )
|
||||
{
|
||||
unsigned hash = 0xAAAAAAAA; // Alternating 1's and 0's to maximize the effect of the later multiply and add
|
||||
|
||||
for( ; *pszKey ; pszKey++ )
|
||||
{
|
||||
hash = ( ( hash << 5 ) + hash ) + (uint8)(*pszKey);
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// Note: HashString causes collisions!!!
|
||||
#define RR_HASH HashStringConventional
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
class Matcher
|
||||
{
|
||||
public:
|
||||
Matcher();
|
||||
|
||||
void Describe( void );
|
||||
|
||||
float maxval;
|
||||
float minval;
|
||||
|
||||
bool valid : 1; //1
|
||||
bool isnumeric : 1; //2
|
||||
bool notequal : 1; //3
|
||||
bool usemin : 1; //4
|
||||
bool minequals : 1; //5
|
||||
bool usemax : 1; //6
|
||||
bool maxequals : 1; //7
|
||||
|
||||
void SetToken( char const *s );
|
||||
|
||||
char const *GetToken();
|
||||
|
||||
void SetRaw( char const *raw );
|
||||
|
||||
char const *GetRaw();
|
||||
|
||||
private:
|
||||
CUtlSymbol token;
|
||||
CUtlSymbol rawtoken;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
struct Criteria
|
||||
{
|
||||
Criteria();
|
||||
Criteria& operator =(const Criteria& src );
|
||||
|
||||
Criteria(const Criteria& src );
|
||||
~Criteria();
|
||||
|
||||
// Does this criterion recursively contain more criteria?
|
||||
inline bool IsSubCriteriaType() const
|
||||
{
|
||||
return ( subcriteria.Count() > 0 ) ? true : false;
|
||||
}
|
||||
|
||||
// const char *name;
|
||||
CUtlSymbol nameSym;
|
||||
const char *value;
|
||||
float16 weight;
|
||||
bool required;
|
||||
|
||||
Matcher matcher;
|
||||
|
||||
// Indices into sub criteria
|
||||
CUtlVectorConservative< unsigned short > subcriteria;
|
||||
};
|
||||
|
||||
#pragma pack(push,1)
|
||||
/// This is a response block as read from the file,
|
||||
/// different from CRR_Response which is what is handed
|
||||
/// back to queries.
|
||||
struct ParserResponse
|
||||
{
|
||||
DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE();
|
||||
|
||||
ParserResponse();
|
||||
ParserResponse( const ParserResponse& src );
|
||||
ParserResponse& operator =( const ParserResponse& src );
|
||||
~ParserResponse();
|
||||
|
||||
ResponseType_t GetType() { return (ResponseType_t)type; }
|
||||
|
||||
ResponseParams params;
|
||||
|
||||
const char *value; // fixed up value spot // 4
|
||||
float16 weight; // 6
|
||||
|
||||
byte depletioncount; // 7
|
||||
byte type : 6; // 8
|
||||
byte first : 1; //
|
||||
byte last : 1; //
|
||||
|
||||
ALIGN32 AI_ResponseFollowup m_followup; // info on whether I should force the other guy to say something
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct ResponseGroup
|
||||
{
|
||||
DECLARE_SIMPLE_DATADESC_INSIDE_NAMESPACE();
|
||||
|
||||
ResponseGroup()
|
||||
{
|
||||
// By default visit all nodes before repeating
|
||||
m_bSequential = false;
|
||||
m_bNoRepeat = false;
|
||||
m_bEnabled = true;
|
||||
m_nCurrentIndex = 0;
|
||||
m_bDepleteBeforeRepeat = true;
|
||||
m_nDepletionCount = 1;
|
||||
m_bHasFirst = false;
|
||||
m_bHasLast = false;
|
||||
}
|
||||
|
||||
ResponseGroup( const ResponseGroup& src )
|
||||
{
|
||||
int c = src.group.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
group.AddToTail( src.group[ i ] );
|
||||
}
|
||||
|
||||
m_bDepleteBeforeRepeat = src.m_bDepleteBeforeRepeat;
|
||||
m_nDepletionCount = src.m_nDepletionCount;
|
||||
m_bHasFirst = src.m_bHasFirst;
|
||||
m_bHasLast = src.m_bHasLast;
|
||||
m_bSequential = src.m_bSequential;
|
||||
m_bNoRepeat = src.m_bNoRepeat;
|
||||
m_bEnabled = src.m_bEnabled;
|
||||
m_nCurrentIndex = src.m_nCurrentIndex;
|
||||
}
|
||||
|
||||
ResponseGroup& operator=( const ResponseGroup& src )
|
||||
{
|
||||
if ( this == &src )
|
||||
return *this;
|
||||
int c = src.group.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
group.AddToTail( src.group[ i ] );
|
||||
}
|
||||
|
||||
m_bDepleteBeforeRepeat = src.m_bDepleteBeforeRepeat;
|
||||
m_nDepletionCount = src.m_nDepletionCount;
|
||||
m_bHasFirst = src.m_bHasFirst;
|
||||
m_bHasLast = src.m_bHasLast;
|
||||
m_bSequential = src.m_bSequential;
|
||||
m_bNoRepeat = src.m_bNoRepeat;
|
||||
m_bEnabled = src.m_bEnabled;
|
||||
m_nCurrentIndex = src.m_nCurrentIndex;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool HasUndepletedChoices() const
|
||||
{
|
||||
if ( !m_bDepleteBeforeRepeat )
|
||||
return true;
|
||||
|
||||
int c = group.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
if ( group[ i ].depletioncount != m_nDepletionCount )
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MarkResponseUsed( int idx )
|
||||
{
|
||||
if ( !m_bDepleteBeforeRepeat )
|
||||
return;
|
||||
|
||||
if ( idx < 0 || idx >= group.Count() )
|
||||
{
|
||||
Assert( 0 );
|
||||
return;
|
||||
}
|
||||
|
||||
group[ idx ].depletioncount = m_nDepletionCount;
|
||||
}
|
||||
|
||||
void ResetDepletionCount()
|
||||
{
|
||||
if ( !m_bDepleteBeforeRepeat )
|
||||
return;
|
||||
++m_nDepletionCount;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
ResetDepletionCount();
|
||||
SetEnabled( true );
|
||||
SetCurrentIndex( 0 );
|
||||
m_nDepletionCount = 1;
|
||||
|
||||
for ( int i = 0; i < group.Count(); ++i )
|
||||
{
|
||||
group[ i ].depletioncount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasUndepletedFirst( int& index )
|
||||
{
|
||||
index = -1;
|
||||
|
||||
if ( !m_bDepleteBeforeRepeat )
|
||||
return false;
|
||||
|
||||
int c = group.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
ParserResponse *r = &group[ i ];
|
||||
|
||||
if ( ( r->depletioncount != m_nDepletionCount ) && r->first )
|
||||
{
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HasUndepletedLast( int& index )
|
||||
{
|
||||
index = -1;
|
||||
|
||||
if ( !m_bDepleteBeforeRepeat )
|
||||
return false;
|
||||
|
||||
int c = group.Count();
|
||||
for ( int i = 0; i < c; i++ )
|
||||
{
|
||||
ParserResponse *r = &group[ i ];
|
||||
|
||||
if ( ( r->depletioncount != m_nDepletionCount ) && r->last )
|
||||
{
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShouldCheckRepeats() const { return m_bDepleteBeforeRepeat; }
|
||||
int GetDepletionCount() const { return m_nDepletionCount; }
|
||||
|
||||
bool IsSequential() const { return m_bSequential; }
|
||||
void SetSequential( bool seq ) { m_bSequential = seq; }
|
||||
|
||||
bool IsNoRepeat() const { return m_bNoRepeat; }
|
||||
void SetNoRepeat( bool norepeat ) { m_bNoRepeat = norepeat; }
|
||||
|
||||
bool IsEnabled() const { return m_bEnabled; }
|
||||
void SetEnabled( bool enabled ) { m_bEnabled = enabled; }
|
||||
|
||||
int GetCurrentIndex() const { return m_nCurrentIndex; }
|
||||
void SetCurrentIndex( byte idx ) { m_nCurrentIndex = idx; }
|
||||
|
||||
CUtlVector< ParserResponse > group;
|
||||
|
||||
bool m_bEnabled;
|
||||
|
||||
byte m_nCurrentIndex;
|
||||
// Invalidation counter
|
||||
byte m_nDepletionCount;
|
||||
|
||||
// Use all slots before repeating any
|
||||
bool m_bDepleteBeforeRepeat : 1;
|
||||
bool m_bHasFirst : 1;
|
||||
bool m_bHasLast : 1;
|
||||
bool m_bSequential : 1;
|
||||
bool m_bNoRepeat : 1;
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct Rule
|
||||
{
|
||||
Rule();
|
||||
Rule( const Rule& src );
|
||||
~Rule();
|
||||
Rule& operator =( const Rule& src );
|
||||
|
||||
void SetContext( const char *context );
|
||||
|
||||
const char *GetContext( void ) const { return m_szContext; }
|
||||
|
||||
inline bool IsEnabled() const { return m_bEnabled; }
|
||||
inline void Disable() { m_bEnabled = false; }
|
||||
inline bool IsMatchOnce() const { return m_bMatchOnce; }
|
||||
inline bool IsApplyContextToWorld() const { return m_bApplyContextToWorld; }
|
||||
|
||||
const char *GetValueForRuleCriterionByName( CResponseSystem *pSystem, const CUtlSymbol &pCritNameSym );
|
||||
const Criteria *GetPointerForRuleCriterionByName( CResponseSystem *pSystem, const CUtlSymbol &pCritNameSym );
|
||||
|
||||
// Indices into underlying criteria and response dictionaries
|
||||
CUtlVectorConservative< unsigned short > m_Criteria;
|
||||
CUtlVectorConservative< unsigned short> m_Responses;
|
||||
|
||||
const char *m_szContext;
|
||||
uint8 m_nForceWeight;
|
||||
|
||||
bool m_bApplyContextToWorld : 1;
|
||||
|
||||
bool m_bMatchOnce : 1;
|
||||
bool m_bEnabled : 1;
|
||||
|
||||
private:
|
||||
// what is this, lisp?
|
||||
const char *RecursiveGetValueForRuleCriterionByName( CResponseSystem *pSystem, const Criteria *pCrit, const CUtlSymbol &pCritNameSym );
|
||||
const Criteria *RecursiveGetPointerForRuleCriterionByName( CResponseSystem *pSystem, const Criteria *pCrit, const CUtlSymbol &pCritNameSym );
|
||||
};
|
||||
#pragma pack(pop)
|
||||
|
||||
template <typename T, typename I = unsigned short>
|
||||
class CResponseDict : public CUtlMap<unsigned int, T, I>
|
||||
{
|
||||
public:
|
||||
CResponseDict() : CUtlMap<unsigned int, T, I>( DefLessFunc( unsigned int ) ), m_ReverseMap( DefLessFunc( unsigned int ) )
|
||||
{
|
||||
}
|
||||
|
||||
I Insert( const char *pName, const T &element )
|
||||
{
|
||||
char const *pString = ResponseCopyString( pName );
|
||||
unsigned int hash = RR_HASH( pString );
|
||||
m_ReverseMap.Insert( hash, pString );
|
||||
return CUtlMap<unsigned int, T, I>::Insert( hash, element );
|
||||
}
|
||||
|
||||
I Insert( const char *pName )
|
||||
{
|
||||
char const *pString = ResponseCopyString( pName );
|
||||
unsigned int hash = RR_HASH( pString );
|
||||
m_ReverseMap.Insert( hash, pString );
|
||||
return CUtlMap<unsigned int, T, I>::Insert( hash );
|
||||
}
|
||||
|
||||
I Find( char const *pName ) const
|
||||
{
|
||||
unsigned int hash = RR_HASH( pName );
|
||||
return CUtlMap<unsigned int, T, I>::Find( hash );
|
||||
}
|
||||
|
||||
const char *GetElementName( I i )
|
||||
{
|
||||
int k = this->Key( i );
|
||||
int slot = m_ReverseMap.Find( k );
|
||||
if ( slot == m_ReverseMap.InvalidIndex() )
|
||||
return "";
|
||||
return m_ReverseMap[ slot ];
|
||||
}
|
||||
|
||||
const char *GetElementName( I i ) const
|
||||
{
|
||||
int k = this->Key( i );
|
||||
int slot = m_ReverseMap.Find( k );
|
||||
if ( slot == m_ReverseMap.InvalidIndex() )
|
||||
return "";
|
||||
return m_ReverseMap[ slot ];
|
||||
}
|
||||
|
||||
private:
|
||||
CUtlMap< unsigned int, const char * > m_ReverseMap;
|
||||
|
||||
};
|
||||
|
||||
// define this to 1 to enable printing some occupancy
|
||||
// information on the response system via concommmand
|
||||
// rr_dumphashinfo
|
||||
#define RR_DUMPHASHINFO_ENABLED 0
|
||||
// The Rules are partitioned based on a variety of factors (presently,
|
||||
// speaker and concept) for faster lookup, basically a seperate-chained hash.
|
||||
struct ResponseRulePartition
|
||||
{
|
||||
ResponseRulePartition( void );
|
||||
~ResponseRulePartition();
|
||||
|
||||
typedef CResponseDict< Rule * > tRuleDict;
|
||||
typedef uint32 tIndex; // an integer that can be used to find any rule in the dict
|
||||
|
||||
/// get the appropriate m_rules dict for the provided rule
|
||||
tRuleDict &GetDictForRule( CResponseSystem *pSystem, Rule *pRule );
|
||||
|
||||
/// get all bucket full of rules that might possibly match the given criteria.
|
||||
/// (right now they are bucketed such that all rules that can possibly match a
|
||||
/// criteria are in one of two dictionaries)
|
||||
void GetDictsForCriteria( CUtlVectorFixed< ResponseRulePartition::tRuleDict *, 2 > *pResult, const CriteriaSet &criteria );
|
||||
|
||||
// dump everything.
|
||||
void RemoveAll();
|
||||
|
||||
inline Rule &operator[]( tIndex idx );
|
||||
int Count( void ); // number of elements inside, but you can't iterate from 0 to this
|
||||
char const *GetElementName( const tIndex &i ) const;
|
||||
|
||||
/// given a dictionary and an element number inside that dict,
|
||||
/// return a tIndex
|
||||
tIndex IndexFromDictElem( tRuleDict* pDict, int elem );
|
||||
|
||||
// for iteration:
|
||||
inline tIndex First( void );
|
||||
inline tIndex Next( const tIndex &idx );
|
||||
inline bool IsValid( const tIndex &idx ) const;
|
||||
inline static tIndex InvalidIdx( void )
|
||||
{
|
||||
return ((tIndex) -1);
|
||||
}
|
||||
|
||||
// used only for debug prints, do not rely on them otherwise
|
||||
inline unsigned int BucketFromIdx( const tIndex &idx ) const ;
|
||||
inline unsigned int PartFromIdx( const tIndex &idx ) const ;
|
||||
|
||||
enum {
|
||||
N_RESPONSE_PARTITIONS = 256,
|
||||
kIDX_ELEM_MASK = 0xFFF, ///< this is used to mask the element number part of a ResponseRulePartition::tIndex
|
||||
};
|
||||
|
||||
#if RR_DUMPHASHINFO_ENABLED
|
||||
void PrintBucketInfo( CResponseSystem *pSys );
|
||||
#endif
|
||||
|
||||
private:
|
||||
tRuleDict m_RuleParts[N_RESPONSE_PARTITIONS];
|
||||
unsigned int GetBucketForSpeakerAndConcept( const char *pszSpeaker, const char *pszConcept, const char *pszSubject );
|
||||
};
|
||||
|
||||
// // // // // inline functions
|
||||
|
||||
inline ResponseRulePartition::tIndex ResponseRulePartition::First( void )
|
||||
{
|
||||
// find the first bucket that has anything
|
||||
for ( int bucket = 0 ; bucket < N_RESPONSE_PARTITIONS; bucket++ )
|
||||
{
|
||||
if ( m_RuleParts[bucket].Count() > 0 )
|
||||
return bucket << 16;
|
||||
}
|
||||
return InvalidIdx();
|
||||
}
|
||||
|
||||
inline ResponseRulePartition::tIndex ResponseRulePartition::Next( const tIndex &idx )
|
||||
{
|
||||
int bucket = BucketFromIdx( idx );
|
||||
unsigned int elem = PartFromIdx( idx );
|
||||
Assert( IsValid(idx) );
|
||||
AssertMsg( elem < kIDX_ELEM_MASK, "Too many response rules! Overflow! Doom!" );
|
||||
if ( elem + 1 < m_RuleParts[bucket].Count() )
|
||||
{
|
||||
return idx+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// walk through the other buckets, skipping empty ones, until we find one with responses and give up.
|
||||
while ( ++bucket < N_RESPONSE_PARTITIONS )
|
||||
{
|
||||
if ( m_RuleParts[bucket].Count() > 0 )
|
||||
{
|
||||
// 0th element in nth bucket
|
||||
return bucket << 16;
|
||||
}
|
||||
}
|
||||
|
||||
// out of buckets
|
||||
return InvalidIdx();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
inline Rule &ResponseRulePartition::operator[]( tIndex idx )
|
||||
{
|
||||
Assert( IsValid(idx) );
|
||||
return *m_RuleParts[ BucketFromIdx(idx) ][ PartFromIdx(idx) ] ;
|
||||
}
|
||||
|
||||
inline unsigned int ResponseRulePartition::BucketFromIdx( const tIndex &idx ) const
|
||||
{
|
||||
return idx >> 16;
|
||||
}
|
||||
|
||||
inline unsigned int ResponseRulePartition::PartFromIdx( const tIndex &idx ) const
|
||||
{
|
||||
return idx & kIDX_ELEM_MASK;
|
||||
}
|
||||
|
||||
inline bool ResponseRulePartition::IsValid( const tIndex & idx ) const
|
||||
{
|
||||
// make sure that the idx type for the dicts is still short
|
||||
COMPILE_TIME_ASSERT( sizeof(m_RuleParts[0].FirstInorder()) == 2 );
|
||||
|
||||
if ( idx == -1 )
|
||||
return false;
|
||||
|
||||
int bucket = idx >> 16;
|
||||
unsigned int elem = idx & kIDX_ELEM_MASK;
|
||||
|
||||
return ( bucket < N_RESPONSE_PARTITIONS &&
|
||||
elem < m_RuleParts[bucket].Count() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// PARSER TYPES -- these are internal to the response system, and represent
|
||||
// the objects as loaded from disk.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include "response_system.h"
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user