Counter Strike : Global Offensive Source Code
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.

854 lines
22 KiB

  1. //========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "SoundEmitterSystem/isoundemittersystembase.h"
  8. #include "ai_responsesystem.h"
  9. #include "igamesystem.h"
  10. #include "ai_criteria.h"
  11. #include <keyvalues.h>
  12. #include "filesystem.h"
  13. #include "utldict.h"
  14. #include "ai_speech.h"
  15. #include "tier0/icommandline.h"
  16. #include <ctype.h>
  17. #include "sceneentity.h"
  18. #include "isaverestore.h"
  19. #include "utlbuffer.h"
  20. #include "stringpool.h"
  21. #include "fmtstr.h"
  22. #include "multiplay_gamerules.h"
  23. #include "characterset.h"
  24. #include "responserules/response_host_interface.h"
  25. #include "responserules/response_types_internal.h"
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. using namespace ResponseRules;
  29. extern ConVar rr_debugresponses; // ( "rr_debugresponses", "0", FCVAR_NONE, "Show verbose matching output (1 for simple, 2 for rule scoring, 3 for noisy). If set to 4, it will only show response success/failure for npc_selected NPCs." );
  30. extern ConVar rr_debugrule; // ( "rr_debugrule", "", FCVAR_NONE, "If set to the name of the rule, that rule's score will be shown whenever a concept is passed into the response rules system.");
  31. extern ConVar rr_dumpresponses; // ( "rr_dumpresponses", "0", FCVAR_NONE, "Dump all response_rules.txt and rules (requires restart)" );
  32. extern ConVar rr_debugresponseconcept; // ( "rr_debugresponseconcept", "", FCVAR_NONE, "If set, rr_debugresponses will print only responses testing for the specified concept" );
  33. static characterset_t g_BreakSetIncludingColons;
  34. // Simple class to initialize breakset
  35. class CBreakInit
  36. {
  37. public:
  38. CBreakInit()
  39. {
  40. CharacterSetBuild( &g_BreakSetIncludingColons, "{}()':" );
  41. }
  42. } g_BreakInit;
  43. inline char rr_tolower( char c )
  44. {
  45. if ( c >= 'A' && c <= 'Z' )
  46. return c - 'A' + 'a';
  47. return c;
  48. }
  49. // BUG BUG: Note that this function doesn't check for data overruns!!!
  50. // Also, this function lowercases the token as it parses!!!
  51. inline const char *RR_Parse(const char *data, char *token )
  52. {
  53. unsigned char c;
  54. int len;
  55. characterset_t *breaks = &g_BreakSetIncludingColons;
  56. len = 0;
  57. token[0] = 0;
  58. if (!data)
  59. return NULL;
  60. // skip whitespace
  61. skipwhite:
  62. while ( (c = *data) <= ' ')
  63. {
  64. if (c == 0)
  65. return NULL; // end of file;
  66. data++;
  67. }
  68. // skip // comments
  69. if (c=='/' && data[1] == '/')
  70. {
  71. while (*data && *data != '\n')
  72. data++;
  73. goto skipwhite;
  74. }
  75. // handle quoted strings specially
  76. if (c == '\"')
  77. {
  78. data++;
  79. while (1)
  80. {
  81. c = rr_tolower( *data++ );
  82. if (c=='\"' || !c)
  83. {
  84. token[len] = 0;
  85. return data;
  86. }
  87. token[len] = c;
  88. len++;
  89. }
  90. }
  91. // parse single characters
  92. if ( IN_CHARACTERSET( *breaks, c ) )
  93. {
  94. token[len] = c;
  95. len++;
  96. token[len] = 0;
  97. return data+1;
  98. }
  99. // parse a regular word
  100. do
  101. {
  102. token[len] = rr_tolower( c );
  103. data++;
  104. len++;
  105. c = rr_tolower( *data );
  106. if ( IN_CHARACTERSET( *breaks, c ) )
  107. break;
  108. } while (c>32);
  109. token[len] = 0;
  110. return data;
  111. }
  112. namespace ResponseRules
  113. {
  114. extern const char *ResponseCopyString( const char *in );
  115. }
  116. // Host functions required by the ResponseRules::IEngineEmulator interface
  117. class CResponseRulesToEngineInterface : public ResponseRules::IEngineEmulator
  118. {
  119. /// Given an input text buffer data pointer, parses a single token into the variable token and returns the new
  120. /// reading position
  121. virtual const char *ParseFile( const char *data, char *token, int maxlen )
  122. {
  123. NOTE_UNUSED( maxlen );
  124. return RR_Parse( data, token );
  125. }
  126. /// Return a pointer to an IFileSystem we can use to read and process scripts.
  127. virtual IFileSystem *GetFilesystem()
  128. {
  129. return filesystem;
  130. }
  131. /// Return a pointer to an instance of an IUniformRandomStream
  132. virtual IUniformRandomStream *GetRandomStream()
  133. {
  134. return random;
  135. }
  136. /// Return a pointer to a tier0 ICommandLine
  137. virtual ICommandLine *GetCommandLine()
  138. {
  139. return CommandLine();
  140. }
  141. /// Emulates the server's UTIL_LoadFileForMe
  142. virtual byte *LoadFileForMe( const char *filename, int *pLength )
  143. {
  144. return UTIL_LoadFileForMe( filename, pLength );
  145. }
  146. /// Emulates the server's UTIL_FreeFile
  147. virtual void FreeFile( byte *buffer )
  148. {
  149. return UTIL_FreeFile( buffer );
  150. }
  151. };
  152. CResponseRulesToEngineInterface g_ResponseRulesEngineWrapper;
  153. IEngineEmulator *IEngineEmulator::s_pSingleton = &g_ResponseRulesEngineWrapper;
  154. BEGIN_SIMPLE_DATADESC( ParserResponse )
  155. // DEFINE_FIELD( type, FIELD_INTEGER ),
  156. // DEFINE_ARRAY( value, FIELD_CHARACTER ),
  157. // DEFINE_FIELD( weight, FIELD_FLOAT ),
  158. DEFINE_FIELD( depletioncount, FIELD_CHARACTER ),
  159. // DEFINE_FIELD( first, FIELD_BOOLEAN ),
  160. // DEFINE_FIELD( last, FIELD_BOOLEAN ),
  161. END_DATADESC()
  162. BEGIN_SIMPLE_DATADESC( ResponseGroup )
  163. // DEFINE_FIELD( group, FIELD_UTLVECTOR ),
  164. // DEFINE_FIELD( rp, FIELD_EMBEDDED ),
  165. // DEFINE_FIELD( m_bDepleteBeforeRepeat, FIELD_BOOLEAN ),
  166. DEFINE_FIELD( m_nDepletionCount, FIELD_CHARACTER ),
  167. // DEFINE_FIELD( m_bHasFirst, FIELD_BOOLEAN ),
  168. // DEFINE_FIELD( m_bHasLast, FIELD_BOOLEAN ),
  169. // DEFINE_FIELD( m_bSequential, FIELD_BOOLEAN ),
  170. // DEFINE_FIELD( m_bNoRepeat, FIELD_BOOLEAN ),
  171. DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ),
  172. DEFINE_FIELD( m_nCurrentIndex, FIELD_CHARACTER ),
  173. END_DATADESC()
  174. /// Add some game-specific code to the basic response system
  175. /// (eg, the scene precacher, which requires the client and server
  176. /// to work)
  177. class CGameResponseSystem : public CResponseSystem
  178. {
  179. public:
  180. CGameResponseSystem();
  181. virtual void Precache();
  182. virtual void PrecacheResponses( bool bEnable )
  183. {
  184. m_bPrecache = bEnable;
  185. }
  186. bool ShouldPrecache() { return m_bPrecache; }
  187. protected:
  188. bool m_bPrecache;
  189. };
  190. //-----------------------------------------------------------------------------
  191. // Purpose:
  192. //-----------------------------------------------------------------------------
  193. CGameResponseSystem::CGameResponseSystem() : m_bPrecache(true)
  194. {};
  195. //-----------------------------------------------------------------------------
  196. // Purpose:
  197. //-----------------------------------------------------------------------------
  198. static void TouchFile( char const *pchFileName )
  199. {
  200. IEngineEmulator::Get()->GetFilesystem()->Size( pchFileName );
  201. }
  202. void CGameResponseSystem::Precache()
  203. {
  204. bool bTouchFiles = CommandLine()->FindParm( "-makereslists" ) != 0;
  205. // enumerate and mark all the scripts so we know they're referenced
  206. for ( int i = 0; i < (int)m_Responses.Count(); i++ )
  207. {
  208. ResponseGroup &group = m_Responses[i];
  209. for ( int j = 0; j < group.group.Count(); j++)
  210. {
  211. ParserResponse &response = group.group[j];
  212. switch ( response.type )
  213. {
  214. default:
  215. break;
  216. case RESPONSE_SCENE:
  217. {
  218. // fixup $gender references
  219. char file[_MAX_PATH];
  220. Q_strncpy( file, response.value, sizeof(file) );
  221. char *gender = strstr( file, "$gender" );
  222. if ( gender )
  223. {
  224. // replace with male & female
  225. const char *postGender = gender + strlen("$gender");
  226. *gender = 0;
  227. char genderFile[_MAX_PATH];
  228. // male
  229. Q_snprintf( genderFile, sizeof(genderFile), "%smale%s", file, postGender);
  230. PrecacheInstancedScene( genderFile );
  231. if ( bTouchFiles )
  232. {
  233. TouchFile( genderFile );
  234. }
  235. Q_snprintf( genderFile, sizeof(genderFile), "%sfemale%s", file, postGender);
  236. PrecacheInstancedScene( genderFile );
  237. if ( bTouchFiles )
  238. {
  239. TouchFile( genderFile );
  240. }
  241. }
  242. else
  243. {
  244. PrecacheInstancedScene( file );
  245. if ( bTouchFiles )
  246. {
  247. TouchFile( file );
  248. }
  249. }
  250. }
  251. break;
  252. case RESPONSE_SPEAK:
  253. {
  254. CBaseEntity::PrecacheScriptSound( response.value );
  255. }
  256. break;
  257. }
  258. }
  259. }
  260. }
  261. //-----------------------------------------------------------------------------
  262. // Purpose: A special purpose response system associated with a custom entity
  263. //-----------------------------------------------------------------------------
  264. class CInstancedResponseSystem : public CGameResponseSystem
  265. {
  266. typedef CGameResponseSystem BaseClass;
  267. public:
  268. CInstancedResponseSystem( const char *scriptfile ) :
  269. m_pszScriptFile( 0 )
  270. {
  271. Assert( scriptfile );
  272. int len = Q_strlen( scriptfile ) + 1;
  273. m_pszScriptFile = new char[ len ];
  274. Assert( m_pszScriptFile );
  275. Q_strncpy( m_pszScriptFile, scriptfile, len );
  276. }
  277. ~CInstancedResponseSystem()
  278. {
  279. delete[] m_pszScriptFile;
  280. }
  281. virtual const char *GetScriptFile( void )
  282. {
  283. Assert( m_pszScriptFile );
  284. return m_pszScriptFile;
  285. }
  286. // CAutoGameSystem
  287. virtual bool Init()
  288. {
  289. const char *basescript = GetScriptFile();
  290. LoadRuleSet( basescript );
  291. return true;
  292. }
  293. virtual void LevelInitPostEntity()
  294. {
  295. ResetResponseGroups();
  296. }
  297. virtual void Release()
  298. {
  299. Clear();
  300. delete this;
  301. }
  302. private:
  303. char *m_pszScriptFile;
  304. };
  305. //-----------------------------------------------------------------------------
  306. // Purpose: The default response system for expressive AIs
  307. //-----------------------------------------------------------------------------
  308. class CDefaultResponseSystem : public CGameResponseSystem, public CAutoGameSystem
  309. {
  310. typedef CAutoGameSystem BaseClass;
  311. public:
  312. CDefaultResponseSystem() : CAutoGameSystem( "CDefaultResponseSystem" )
  313. {
  314. }
  315. virtual const char *GetScriptFile( void )
  316. {
  317. return "scripts/talker/response_rules.txt";
  318. }
  319. // CAutoServerSystem
  320. virtual bool Init();
  321. virtual void Shutdown();
  322. virtual void LevelInitPostEntity()
  323. {
  324. }
  325. virtual void Release()
  326. {
  327. Assert( 0 );
  328. }
  329. void AddInstancedResponseSystem( const char *scriptfile, CInstancedResponseSystem *sys )
  330. {
  331. m_InstancedSystems.Insert( scriptfile, sys );
  332. }
  333. CInstancedResponseSystem *FindResponseSystem( const char *scriptfile )
  334. {
  335. int idx = m_InstancedSystems.Find( scriptfile );
  336. if ( idx == m_InstancedSystems.InvalidIndex() )
  337. return NULL;
  338. return m_InstancedSystems[ idx ];
  339. }
  340. IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile )
  341. {
  342. COM_TimestampedLog( "PrecacheCustomResponseSystem %s - Start", scriptfile );
  343. CInstancedResponseSystem *sys = ( CInstancedResponseSystem * )FindResponseSystem( scriptfile );
  344. if ( !sys )
  345. {
  346. sys = new CInstancedResponseSystem( scriptfile );
  347. if ( !sys )
  348. {
  349. Error( "Failed to load response system data from %s", scriptfile );
  350. }
  351. if ( !sys->Init() )
  352. {
  353. Error( "CInstancedResponseSystem: Failed to init response system from %s!", scriptfile );
  354. }
  355. AddInstancedResponseSystem( scriptfile, sys );
  356. }
  357. sys->Precache();
  358. COM_TimestampedLog( "PrecacheCustomResponseSystem %s - Finish", scriptfile );
  359. return ( IResponseSystem * )sys;
  360. }
  361. IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore );
  362. void DestroyCustomResponseSystems();
  363. virtual void LevelInitPreEntity()
  364. {
  365. // This will precache the default system
  366. // All user installed systems are init'd by PrecacheCustomResponseSystem which will call sys->Precache() on the ones being used
  367. // FIXME: This is SLOW the first time you run the engine (can take 3 - 10 seconds!!!)
  368. if ( ShouldPrecache() )
  369. {
  370. Precache();
  371. }
  372. ResetResponseGroups();
  373. }
  374. void ReloadAllResponseSystems()
  375. {
  376. Clear();
  377. Init();
  378. int c = m_InstancedSystems.Count();
  379. for ( int i = c - 1 ; i >= 0; i-- )
  380. {
  381. CInstancedResponseSystem *sys = m_InstancedSystems[ i ];
  382. if ( !IsCustomManagable() )
  383. {
  384. sys->Clear();
  385. sys->Init();
  386. }
  387. else
  388. {
  389. // Custom reponse rules will manage/reload themselves - remove them.
  390. m_InstancedSystems.RemoveAt( i );
  391. }
  392. }
  393. // precache sounds in case we added new ones
  394. Precache();
  395. }
  396. private:
  397. void ClearInstanced()
  398. {
  399. int c = m_InstancedSystems.Count();
  400. for ( int i = c - 1 ; i >= 0; i-- )
  401. {
  402. CInstancedResponseSystem *sys = m_InstancedSystems[ i ];
  403. sys->Release();
  404. }
  405. m_InstancedSystems.RemoveAll();
  406. }
  407. CUtlDict< CInstancedResponseSystem *, int > m_InstancedSystems;
  408. friend void CC_RR_DumpHashInfo( const CCommand &args );
  409. };
  410. IResponseSystem *CDefaultResponseSystem::BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore )
  411. {
  412. // Create a instanced response system.
  413. CInstancedResponseSystem *pCustomSystem = new CInstancedResponseSystem( pszCustomName );
  414. if ( !pCustomSystem )
  415. {
  416. Error( "BuildCustomResponseSystemGivenCriterea: Failed to create custom response system %s!", pszCustomName );
  417. }
  418. pCustomSystem->Clear();
  419. // Copy the relevant rules and data.
  420. /*
  421. int nRuleCount = m_Rules.Count();
  422. for ( int iRule = 0; iRule < nRuleCount; ++iRule )
  423. */
  424. for ( ResponseRulePartition::tIndex iIdx = m_RulePartitions.First() ;
  425. m_RulePartitions.IsValid(iIdx) ;
  426. iIdx = m_RulePartitions.Next( iIdx ) )
  427. {
  428. Rule *pRule = &m_RulePartitions[iIdx];
  429. if ( pRule )
  430. {
  431. float flScore = 0.0f;
  432. int nCriteriaCount = pRule->m_Criteria.Count();
  433. for ( int iCriteria = 0; iCriteria < nCriteriaCount; ++iCriteria )
  434. {
  435. int iRuleCriteria = pRule->m_Criteria[iCriteria];
  436. flScore += LookForCriteria( criteriaSet, iRuleCriteria );
  437. if ( flScore >= flCriteriaScore )
  438. {
  439. CopyRuleFrom( pRule, iIdx, pCustomSystem );
  440. break;
  441. }
  442. }
  443. }
  444. }
  445. // Set as a custom response system.
  446. m_bCustomManagable = true;
  447. AddInstancedResponseSystem( pszCustomName, pCustomSystem );
  448. // pCustomSystem->DumpDictionary( pszCustomName );
  449. return pCustomSystem;
  450. }
  451. void CDefaultResponseSystem::DestroyCustomResponseSystems()
  452. {
  453. ClearInstanced();
  454. }
  455. static CDefaultResponseSystem defaultresponsesytem;
  456. IResponseSystem *g_pResponseSystem = &defaultresponsesytem;
  457. CON_COMMAND_F( rr_reloadresponsesystems, "Reload all response system scripts.", FCVAR_CHEAT )
  458. {
  459. defaultresponsesytem.ReloadAllResponseSystems();
  460. }
  461. static short RESPONSESYSTEM_SAVE_RESTORE_VERSION = 1;
  462. // note: this won't save/restore settings from instanced response systems. Could add that with a CDefSaveRestoreOps implementation if needed
  463. //
  464. class CDefaultResponseSystemSaveRestoreBlockHandler : public CDefSaveRestoreBlockHandler
  465. {
  466. public:
  467. const char *GetBlockName()
  468. {
  469. return "ResponseSystem";
  470. }
  471. void WriteSaveHeaders( ISave *pSave )
  472. {
  473. pSave->WriteShort( &RESPONSESYSTEM_SAVE_RESTORE_VERSION );
  474. }
  475. void ReadRestoreHeaders( IRestore *pRestore )
  476. {
  477. // No reason why any future version shouldn't try to retain backward compatability. The default here is to not do so.
  478. short version;
  479. pRestore->ReadShort( &version );
  480. m_fDoLoad = ( version == RESPONSESYSTEM_SAVE_RESTORE_VERSION );
  481. }
  482. void Save( ISave *pSave )
  483. {
  484. CDefaultResponseSystem& rs = defaultresponsesytem;
  485. int count = rs.m_Responses.Count();
  486. pSave->WriteInt( &count );
  487. for ( int i = 0; i < count; ++i )
  488. {
  489. pSave->StartBlock( "ResponseGroup" );
  490. pSave->WriteString( rs.m_Responses.GetElementName( i ) );
  491. const ResponseGroup *group = &rs.m_Responses[ i ];
  492. pSave->WriteAll( group );
  493. short groupCount = group->group.Count();
  494. pSave->WriteShort( &groupCount );
  495. for ( int j = 0; j < groupCount; ++j )
  496. {
  497. const ParserResponse *response = &group->group[ j ];
  498. pSave->StartBlock( "Response" );
  499. pSave->WriteString( response->value );
  500. pSave->WriteAll( response );
  501. pSave->EndBlock();
  502. }
  503. pSave->EndBlock();
  504. }
  505. }
  506. void Restore( IRestore *pRestore, bool createPlayers )
  507. {
  508. if ( !m_fDoLoad )
  509. return;
  510. CDefaultResponseSystem& rs = defaultresponsesytem;
  511. int count = pRestore->ReadInt();
  512. for ( int i = 0; i < count; ++i )
  513. {
  514. char szResponseGroupBlockName[SIZE_BLOCK_NAME_BUF];
  515. pRestore->StartBlock( szResponseGroupBlockName );
  516. if ( !Q_stricmp( szResponseGroupBlockName, "ResponseGroup" ) )
  517. {
  518. char groupname[ 256 ];
  519. pRestore->ReadString( groupname, sizeof( groupname ), 0 );
  520. // Try and find it
  521. int idx = rs.m_Responses.Find( groupname );
  522. if ( idx != rs.m_Responses.InvalidIndex() )
  523. {
  524. ResponseGroup *group = &rs.m_Responses[ idx ];
  525. pRestore->ReadAll( group );
  526. short groupCount = pRestore->ReadShort();
  527. for ( int j = 0; j < groupCount; ++j )
  528. {
  529. char szResponseBlockName[SIZE_BLOCK_NAME_BUF];
  530. char responsename[ 256 ];
  531. pRestore->StartBlock( szResponseBlockName );
  532. if ( !Q_stricmp( szResponseBlockName, "Response" ) )
  533. {
  534. pRestore->ReadString( responsename, sizeof( responsename ), 0 );
  535. // Find it by name
  536. int ri;
  537. for ( ri = 0; ri < group->group.Count(); ++ri )
  538. {
  539. ParserResponse *response = &group->group[ ri ];
  540. if ( !Q_stricmp( response->value, responsename ) )
  541. {
  542. break;
  543. }
  544. }
  545. if ( ri < group->group.Count() )
  546. {
  547. ParserResponse *response = &group->group[ ri ];
  548. pRestore->ReadAll( response );
  549. }
  550. }
  551. pRestore->EndBlock();
  552. }
  553. }
  554. }
  555. pRestore->EndBlock();
  556. }
  557. }
  558. private:
  559. bool m_fDoLoad;
  560. } g_DefaultResponseSystemSaveRestoreBlockHandler;
  561. ISaveRestoreBlockHandler *GetDefaultResponseSystemSaveRestoreBlockHandler()
  562. {
  563. return &g_DefaultResponseSystemSaveRestoreBlockHandler;
  564. }
  565. //-----------------------------------------------------------------------------
  566. // CResponseSystemSaveRestoreOps
  567. //
  568. // Purpose: Handles save and load for instanced response systems...
  569. //
  570. // BUGBUG: This will save the same response system to file multiple times for "shared" response systems and
  571. // therefore it'll restore the same data onto the same pointer N times on reload (probably benign for now, but we could
  572. // write code to save/restore the instanced ones by filename in the block handler above maybe?
  573. //-----------------------------------------------------------------------------
  574. class CResponseSystemSaveRestoreOps : public CDefSaveRestoreOps
  575. {
  576. public:
  577. virtual void Save( const SaveRestoreFieldInfo_t &fieldInfo, ISave *pSave )
  578. {
  579. CResponseSystem *pRS = *(CResponseSystem **)fieldInfo.pField;
  580. if ( !pRS || pRS == &defaultresponsesytem )
  581. return;
  582. int count = pRS->m_Responses.Count();
  583. pSave->WriteInt( &count );
  584. for ( int i = 0; i < count; ++i )
  585. {
  586. pSave->StartBlock( "ResponseGroup" );
  587. pSave->WriteString( pRS->m_Responses.GetElementName( i ) );
  588. const ResponseGroup *group = &pRS->m_Responses[ i ];
  589. pSave->WriteAll( group );
  590. short groupCount = group->group.Count();
  591. pSave->WriteShort( &groupCount );
  592. for ( int j = 0; j < groupCount; ++j )
  593. {
  594. const ParserResponse *response = &group->group[ j ];
  595. pSave->StartBlock( "Response" );
  596. pSave->WriteString( response->value );
  597. pSave->WriteAll( response );
  598. pSave->EndBlock();
  599. }
  600. pSave->EndBlock();
  601. }
  602. }
  603. virtual void Restore( const SaveRestoreFieldInfo_t &fieldInfo, IRestore *pRestore )
  604. {
  605. CResponseSystem *pRS = *(CResponseSystem **)fieldInfo.pField;
  606. if ( !pRS || pRS == &defaultresponsesytem )
  607. return;
  608. int count = pRestore->ReadInt();
  609. for ( int i = 0; i < count; ++i )
  610. {
  611. char szResponseGroupBlockName[SIZE_BLOCK_NAME_BUF];
  612. pRestore->StartBlock( szResponseGroupBlockName );
  613. if ( !Q_stricmp( szResponseGroupBlockName, "ResponseGroup" ) )
  614. {
  615. char groupname[ 256 ];
  616. pRestore->ReadString( groupname, sizeof( groupname ), 0 );
  617. // Try and find it
  618. int idx = pRS->m_Responses.Find( groupname );
  619. if ( idx != pRS->m_Responses.InvalidIndex() )
  620. {
  621. ResponseGroup *group = &pRS->m_Responses[ idx ];
  622. pRestore->ReadAll( group );
  623. short groupCount = pRestore->ReadShort();
  624. for ( int j = 0; j < groupCount; ++j )
  625. {
  626. char szResponseBlockName[SIZE_BLOCK_NAME_BUF];
  627. char responsename[ 256 ];
  628. pRestore->StartBlock( szResponseBlockName );
  629. if ( !Q_stricmp( szResponseBlockName, "Response" ) )
  630. {
  631. pRestore->ReadString( responsename, sizeof( responsename ), 0 );
  632. // Find it by name
  633. int ri;
  634. for ( ri = 0; ri < group->group.Count(); ++ri )
  635. {
  636. ParserResponse *response = &group->group[ ri ];
  637. if ( !Q_stricmp( response->value, responsename ) )
  638. {
  639. break;
  640. }
  641. }
  642. if ( ri < group->group.Count() )
  643. {
  644. ParserResponse *response = &group->group[ ri ];
  645. pRestore->ReadAll( response );
  646. }
  647. }
  648. pRestore->EndBlock();
  649. }
  650. }
  651. }
  652. pRestore->EndBlock();
  653. }
  654. }
  655. } g_ResponseSystemSaveRestoreOps;
  656. ISaveRestoreOps *responseSystemSaveRestoreOps = &g_ResponseSystemSaveRestoreOps;
  657. //-----------------------------------------------------------------------------
  658. // Purpose:
  659. // Output : Returns true on success, false on failure.
  660. //-----------------------------------------------------------------------------
  661. bool CDefaultResponseSystem::Init()
  662. {
  663. /*
  664. Warning( "sizeof( Response ) == %d\n", sizeof( Response ) );
  665. Warning( "sizeof( ResponseGroup ) == %d\n", sizeof( ResponseGroup ) );
  666. Warning( "sizeof( Criteria ) == %d\n", sizeof( Criteria ) );
  667. Warning( "sizeof( AI_ResponseParams ) == %d\n", sizeof( AI_ResponseParams ) );
  668. */
  669. const char *basescript = GetScriptFile();
  670. LoadRuleSet( basescript );
  671. return true;
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Purpose:
  675. //-----------------------------------------------------------------------------
  676. void CDefaultResponseSystem::Shutdown()
  677. {
  678. // Wipe instanced versions
  679. ClearInstanced();
  680. // Clear outselves
  681. Clear();
  682. // IServerSystem chain
  683. BaseClass::Shutdown();
  684. }
  685. //-----------------------------------------------------------------------------
  686. // Purpose: Instance a custom response system
  687. // Input : *scriptfile -
  688. // Output : IResponseSystem
  689. //-----------------------------------------------------------------------------
  690. IResponseSystem *PrecacheCustomResponseSystem( const char *scriptfile )
  691. {
  692. return defaultresponsesytem.PrecacheCustomResponseSystem( scriptfile );
  693. }
  694. //-----------------------------------------------------------------------------
  695. // Purpose: Instance a custom response system
  696. // Input : *scriptfile -
  697. // set -
  698. // Output : IResponseSystem
  699. //-----------------------------------------------------------------------------
  700. IResponseSystem *BuildCustomResponseSystemGivenCriteria( const char *pszBaseFile, const char *pszCustomName, AI_CriteriaSet &criteriaSet, float flCriteriaScore )
  701. {
  702. return defaultresponsesytem.BuildCustomResponseSystemGivenCriteria( pszBaseFile, pszCustomName, criteriaSet, flCriteriaScore );
  703. }
  704. //-----------------------------------------------------------------------------
  705. // Purpose:
  706. //-----------------------------------------------------------------------------
  707. void DestroyCustomResponseSystems()
  708. {
  709. defaultresponsesytem.DestroyCustomResponseSystems();
  710. }