From 39ed87570bdb2f86969d4be821c94b722dc71179 Mon Sep 17 00:00:00 2001 From: Joe Ludwig Date: Wed, 26 Jun 2013 15:22:04 -0700 Subject: First version of the SOurce SDK 2013 --- mp/src/game/server/AI_Criteria.cpp | 516 +++++++++++++++++++++++++++++++++++++ 1 file changed, 516 insertions(+) create mode 100644 mp/src/game/server/AI_Criteria.cpp (limited to 'mp/src/game/server/AI_Criteria.cpp') diff --git a/mp/src/game/server/AI_Criteria.cpp b/mp/src/game/server/AI_Criteria.cpp new file mode 100644 index 00000000..6b523970 --- /dev/null +++ b/mp/src/game/server/AI_Criteria.cpp @@ -0,0 +1,516 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//=============================================================================// +#include "cbase.h" +#include "AI_Criteria.h" +#include "ai_speech.h" +#include +#include "engine/IEngineSound.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +AI_CriteriaSet::AI_CriteriaSet() : m_Lookup( 0, 0, CritEntry_t::LessFunc ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : src - +//----------------------------------------------------------------------------- +AI_CriteriaSet::AI_CriteriaSet( const AI_CriteriaSet& src ) : m_Lookup( 0, 0, CritEntry_t::LessFunc ) +{ + m_Lookup.Purge(); + for ( short i = src.m_Lookup.FirstInorder(); + i != src.m_Lookup.InvalidIndex(); + i = src.m_Lookup.NextInorder( i ) ) + { + m_Lookup.Insert( src.m_Lookup[ i ] ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +AI_CriteriaSet::~AI_CriteriaSet() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *criteria - +// "" - +// 1.0f - +//----------------------------------------------------------------------------- +void AI_CriteriaSet::AppendCriteria( const char *criteria, const char *value /*= ""*/, float weight /*= 1.0f*/ ) +{ + // Note: value pointer may come from an entry inside m_Lookup! + // that value string must be copied out before any modification + // to the m_Lookup struct which could make the pointer invalid + int idx = FindCriterionIndex( criteria ); + if ( idx == -1 ) + { + CritEntry_t entry; + entry.criterianame = criteria; + MEM_ALLOC_CREDIT(); + entry.SetValue(value); + entry.weight = weight; + m_Lookup.Insert( entry ); + } + else + { + CritEntry_t *entry = &m_Lookup[ idx ]; + entry->SetValue( value ); + entry->weight = weight; + } +} + + +//----------------------------------------------------------------------------- +// Removes criteria in a set +//----------------------------------------------------------------------------- +void AI_CriteriaSet::RemoveCriteria( const char *criteria ) +{ + int idx = FindCriterionIndex( criteria ); + if ( idx == -1 ) + return; + + m_Lookup.RemoveAt( idx ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : int +//----------------------------------------------------------------------------- +int AI_CriteriaSet::GetCount() const +{ + return m_Lookup.Count(); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *name - +// Output : int +//----------------------------------------------------------------------------- +int AI_CriteriaSet::FindCriterionIndex( const char *name ) const +{ + CritEntry_t search; + search.criterianame = name; + int idx = m_Lookup.Find( search ); + if ( idx == m_Lookup.InvalidIndex() ) + return -1; + + return idx; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : char const +//----------------------------------------------------------------------------- +const char *AI_CriteriaSet::GetName( int index ) const +{ + static char namebuf[ 128 ]; + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return ""; + + const CritEntry_t *entry = &m_Lookup[ index ]; + Q_strncpy( namebuf, entry->criterianame.String(), sizeof( namebuf ) ); + return namebuf; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : char const +//----------------------------------------------------------------------------- +const char *AI_CriteriaSet::GetValue( int index ) const +{ + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return ""; + + const CritEntry_t *entry = &m_Lookup[ index ]; + return entry->value ? entry->value : ""; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : index - +// Output : float +//----------------------------------------------------------------------------- +float AI_CriteriaSet::GetWeight( int index ) const +{ + if ( index < 0 || index >= (int)m_Lookup.Count() ) + return 1.0f; + + const CritEntry_t *entry = &m_Lookup[ index ]; + return entry->weight; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AI_CriteriaSet::Describe() +{ + for ( short i = m_Lookup.FirstInorder(); i != m_Lookup.InvalidIndex(); i = m_Lookup.NextInorder( i ) ) + { + + CritEntry_t *entry = &m_Lookup[ i ]; + + if ( entry->weight != 1.0f ) + { + DevMsg( " %20s = '%s' (weight %f)\n", entry->criterianame.String(), entry->value ? entry->value : "", entry->weight ); + } + else + { + DevMsg( " %20s = '%s'\n", entry->criterianame.String(), entry->value ? entry->value : "" ); + } + } +} + +BEGIN_SIMPLE_DATADESC( AI_ResponseParams ) + DEFINE_FIELD( flags, FIELD_SHORT ), + DEFINE_FIELD( odds, FIELD_SHORT ), + DEFINE_FIELD( soundlevel, FIELD_CHARACTER ), + DEFINE_FIELD( delay, FIELD_INTEGER ), // These are compressed down to two float16s, so treat as an INT for saverestore + DEFINE_FIELD( respeakdelay, FIELD_INTEGER ), // +END_DATADESC() + +BEGIN_SIMPLE_DATADESC( AI_Response ) + DEFINE_FIELD( m_Type, FIELD_CHARACTER ), + DEFINE_ARRAY( m_szResponseName, FIELD_CHARACTER, AI_Response::MAX_RESPONSE_NAME ), + DEFINE_ARRAY( m_szMatchingRule, FIELD_CHARACTER, AI_Response::MAX_RULE_NAME ), + // DEFINE_FIELD( m_pCriteria, FIELD_??? ), // Don't need to save this probably + DEFINE_EMBEDDED( m_Params ), +END_DATADESC() + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +AI_Response::AI_Response() +{ + m_Type = RESPONSE_NONE; + m_szResponseName[0] = 0; + m_pCriteria = NULL; + m_szMatchingRule[0]=0; + m_szContext = NULL; + m_bApplyContextToWorld = false; +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +AI_Response::AI_Response( const AI_Response &from ) +{ + Assert( (void*)(&m_Type) == (void*)this ); + m_pCriteria = NULL; + memcpy( this, &from, sizeof(*this) ); + m_pCriteria = NULL; + m_szContext = NULL; + SetContext( from.m_szContext ); + m_bApplyContextToWorld = from.m_bApplyContextToWorld; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +AI_Response::~AI_Response() +{ + delete m_pCriteria; + delete[] m_szContext; +} + +//----------------------------------------------------------------------------- +AI_Response &AI_Response::operator=( const AI_Response &from ) +{ + Assert( (void*)(&m_Type) == (void*)this ); + delete m_pCriteria; + m_pCriteria = NULL; + memcpy( this, &from, sizeof(*this) ); + m_pCriteria = NULL; + m_szContext = NULL; + SetContext( from.m_szContext ); + m_bApplyContextToWorld = from.m_bApplyContextToWorld; + return *this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *response - +// *criteria - +//----------------------------------------------------------------------------- +void AI_Response::Init( ResponseType_t type, const char *responseName, const AI_CriteriaSet& criteria, const AI_ResponseParams& responseparams, const char *ruleName, const char *applyContext, bool bApplyContextToWorld ) +{ + m_Type = type; + Q_strncpy( m_szResponseName, responseName, sizeof( m_szResponseName ) ); + // Copy underlying criteria + m_pCriteria = new AI_CriteriaSet( criteria ); + Q_strncpy( m_szMatchingRule, ruleName ? ruleName : "NULL", sizeof( m_szMatchingRule ) ); + m_Params = responseparams; + SetContext( applyContext ); + m_bApplyContextToWorld = bApplyContextToWorld; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AI_Response::Describe() +{ + if ( m_pCriteria ) + { + DevMsg( "Search criteria:\n" ); + m_pCriteria->Describe(); + } + if ( m_szMatchingRule[ 0 ] ) + { + DevMsg( "Matched rule '%s', ", m_szMatchingRule ); + } + if ( m_szContext ) + { + DevMsg( "Contexts to set '%s' on %s, ", m_szContext, m_bApplyContextToWorld ? "world" : "speaker" ); + } + + DevMsg( "response %s = '%s'\n", DescribeResponse( (ResponseType_t)m_Type ), m_szResponseName ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void AI_Response::GetName( char *buf, size_t buflen ) const +{ + Q_strncpy( buf, m_szResponseName, buflen ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +// Output : char const +//----------------------------------------------------------------------------- +void AI_Response::GetResponse( char *buf, size_t buflen ) const +{ + GetName( buf, buflen ); +} +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +// Output : char const +//----------------------------------------------------------------------------- +const char *AI_Response::DescribeResponse( ResponseType_t type ) +{ + if ( (int)type < 0 || (int)type >= NUM_RESPONSES ) + { + Assert( 0 ); + return "???AI_Response bogus index"; + } + + switch( type ) + { + default: + { + Assert( 0 ); + } + // Fall through + case RESPONSE_NONE: + return "RESPONSE_NONE"; + case RESPONSE_SPEAK: + return "RESPONSE_SPEAK"; + case RESPONSE_SENTENCE: + return "RESPONSE_SENTENCE"; + case RESPONSE_SCENE: + return "RESPONSE_SCENE"; + case RESPONSE_RESPONSE: + return "RESPONSE_RESPONSE"; + case RESPONSE_PRINT: + return "RESPONSE_PRINT"; + } + + return "RESPONSE_NONE"; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const AI_CriteriaSet +//----------------------------------------------------------------------------- +const AI_CriteriaSet *AI_Response::GetCriteria() +{ + return m_pCriteria; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void AI_Response::Release() +{ + delete this; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : soundlevel_t +//----------------------------------------------------------------------------- +soundlevel_t AI_Response::GetSoundLevel() const +{ + if ( m_Params.flags & AI_ResponseParams::RG_SOUNDLEVEL ) + { + return (soundlevel_t)m_Params.soundlevel; + } + + return SNDLVL_TALKING; +} + +float AI_Response::GetRespeakDelay( void ) const +{ + if ( m_Params.flags & AI_ResponseParams::RG_RESPEAKDELAY ) + { + interval_t temp; + m_Params.respeakdelay.ToInterval( temp ); + return RandomInterval( temp ); + } + + return 0.0f; +} + +float AI_Response::GetWeaponDelay( void ) const +{ + if ( m_Params.flags & AI_ResponseParams::RG_WEAPONDELAY ) + { + interval_t temp; + m_Params.weapondelay.ToInterval( temp ); + return RandomInterval( temp ); + } + + return 0.0f; +} + +bool AI_Response::GetSpeakOnce( void ) const +{ + if ( m_Params.flags & AI_ResponseParams::RG_SPEAKONCE ) + { + return true; + } + + return false; +} + +bool AI_Response::ShouldntUseScene( void ) const +{ + return ( m_Params.flags & AI_ResponseParams::RG_DONT_USE_SCENE ) != 0; +} + +bool AI_Response::ShouldBreakOnNonIdle( void ) const +{ + return ( m_Params.flags & AI_ResponseParams::RG_STOP_ON_NONIDLE ) != 0; +} + +int AI_Response::GetOdds( void ) const +{ + if ( m_Params.flags & AI_ResponseParams::RG_ODDS ) + { + return m_Params.odds; + } + return 100; +} + +float AI_Response::GetDelay() const +{ + if ( m_Params.flags & AI_ResponseParams::RG_DELAYAFTERSPEAK ) + { + interval_t temp; + m_Params.delay.ToInterval( temp ); + return RandomInterval( temp ); + } + return 0.0f; +} + +float AI_Response::GetPreDelay() const +{ + if ( m_Params.flags & AI_ResponseParams::RG_DELAYBEFORESPEAK ) + { + interval_t temp; + m_Params.predelay.ToInterval( temp ); + return RandomInterval( temp ); + } + return 0.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets context string +// Output : void +//----------------------------------------------------------------------------- +void AI_Response::SetContext( const char *context ) +{ + delete[] m_szContext; + m_szContext = NULL; + + if ( context ) + { + int len = Q_strlen( context ); + m_szContext = new char[ len + 1 ]; + Q_memcpy( m_szContext, context, len ); + m_szContext[ len ] = 0; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *raw - +// *key - +// keylen - +// *value - +// valuelen - +// *duration - +// Output : static bool +//----------------------------------------------------------------------------- +const char *SplitContext( const char *raw, char *key, int keylen, char *value, int valuelen, float *duration ) +{ + char *colon1 = Q_strstr( raw, ":" ); + if ( !colon1 ) + { + DevMsg( "SplitContext: warning, ignoring context '%s', missing colon separator!\n", raw ); + *key = *value = 0; + return NULL; + } + + int len = colon1 - raw; + Q_strncpy( key, raw, MIN( len + 1, keylen ) ); + key[ MIN( len, keylen - 1 ) ] = 0; + + bool last = false; + char *end = Q_strstr( colon1 + 1, "," ); + if ( !end ) + { + int remaining = Q_strlen( colon1 + 1 ); + end = colon1 + 1 + remaining; + last = true; + } + + char *colon2 = Q_strstr( colon1 + 1, ":" ); + if ( colon2 && ( colon2 < end ) ) + { + if ( duration ) + *duration = atof( colon2 + 1 ); + + len = MIN( colon2 - ( colon1 + 1 ), valuelen - 1 ); + Q_strncpy( value, colon1 + 1, len + 1 ); + value[ len ] = 0; + } + else + { + if ( duration ) + *duration = 0.0; + + len = MIN( end - ( colon1 + 1 ), valuelen - 1 ); + Q_strncpy( value, colon1 + 1, len + 1 ); + value[ len ] = 0; + } + + return last ? NULL : end + 1; +} -- cgit v1.2.3