This commit is contained in:
nephacks
2025-06-04 03:22:50 +02:00
parent f234f23848
commit f12416cffd
14243 changed files with 6446499 additions and 26 deletions

View 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

View 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