Team Fortress 2 Source Code as on 22/4/2020
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.

2700 lines
82 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "KeyValues.h"
  9. #include "schemainitutils.h"
  10. #ifdef CLIENT_DLL
  11. #include "c_tf_player.h"
  12. #include <igameresources.h>
  13. #include "tf_gc_client.h"
  14. #else
  15. #include "tf_player.h"
  16. #include "iscorer.h"
  17. #endif // #ifdef CLIENT_DLL
  18. #include "tf_quest_restriction.h"
  19. #include "tf_gamerules.h"
  20. #include "tf_item_schema.h"
  21. #include "econ_item_system.h"
  22. #include "tf_logic_robot_destruction.h"
  23. #include "tier2/fileutils.h"
  24. #include "steamworks_gamestats.h"
  25. #include "tf_quickplay_shared.h"
  26. static const int s_nMinConnectedPlayersForQuestProgress = 2;
  27. static const int s_nMaxInputCount = 100;
  28. static const char *g_skQuestEventsFile = "tf/scripts/items/unencrypted/_quest_events.txt";
  29. template<typename CTFQuestConditionSubClass_t>
  30. CTFQuestCondition *CreateCTFQuestConditionSubClass()
  31. {
  32. return new CTFQuestConditionSubClass_t();
  33. }
  34. typedef CTFQuestCondition *(*pfnQuestCreate)();
  35. #define FIELD_NONE 0
  36. #define FIELD_PLAYER 1<<0
  37. #define FIELD_OBJECT 1<<1
  38. #define FIELD_WEAPON_NAME 1<<2
  39. #define FIELD_SCORER 1<<3
  40. #define FIELD_CUSTOM_DAMAGE 1<<4
  41. #define FIELD_WEAPON_TYPE 1<<5
  42. #define FIELD_FLAG_EVENT 1<<6
  43. #define FIELD_TEAM 1<<7
  44. #define FIELD_LOADOUT_POSITION 1<<8
  45. #define FIELD_CONDITION 1<<9
  46. #define FIELD_CRIT 1<<10
  47. #define FIELD_WEAPON_DEF_INDEX 1<<11
  48. #define FIELD_HALLOWEEN_BOSS_TYPE 1<<12
  49. #define FIELD_HALLOWEEN_MINIGAME_TYPE 1<<13
  50. #define FIELD_WEAPON_CLASS 1<<14
  51. #define FIELD_BONUSEFFECT 1<<15
  52. #define FIELD_DEFLECTED_PROJECTILE 1<<16
  53. #define FIELD_LAST_FIELD FIELD_DEFLECTED_PROJECTILE
  54. const char* k_pszQuestConditionRequiredFieldStrings[] =
  55. {
  56. "player", // FIELD_PLAYER
  57. "object_type", // FIELD_OBJECT
  58. "weapon_name", // FIELD_WEAPON_NAME
  59. "scorer", // FIELD_SCORER
  60. "custom_damage", // FIELD_CUSTOM_DAMAGE
  61. "weapon_type", // FIELD_WEAPON_TYPE
  62. "flag_event", // FIELD_FLAG_EVENT
  63. "team_restriction", // FIELD_TEAM
  64. "loadout_position", // FIELD_LOADOUT_POSITION
  65. "condition", // FIELD_CONDITION
  66. "crit_kill", // FIELD_CRIT
  67. "weapon_def_index", // FIELD_WEAPON_DEF_INDEX
  68. "halloween_boss_type", // FIELD_HALLOWEEN_BOSS_TYPE
  69. "minigame_type", // FIELD_HALLOWEEN_MINIGAME_TYPE
  70. "weapon_class", // FIELD_WEAPON_CLASS
  71. "bonuseffect", // FIELD_BONUSEFFECT
  72. "deflected_projectile", // FIELD_DEFLECTED_PROJECTILE
  73. };
  74. struct QuestConditionEntry_t;
  75. CUtlMap< const char*, QuestConditionEntry_t* > k_mapConditions( StringLessThan );
  76. struct QuestConditionEntry_t
  77. {
  78. QuestConditionEntry_t( const char* pszName, int nRequiredField, pfnQuestCreate pfnCreate )
  79. : m_nRequiredFields( nRequiredField )
  80. , m_pfnQuestCreate( pfnCreate )
  81. , m_pszFieldName( pszName )
  82. {
  83. k_mapConditions.Insert( pszName, this );
  84. }
  85. int m_nRequiredFields;
  86. pfnQuestCreate m_pfnQuestCreate;
  87. const char* m_pszFieldName;
  88. };
  89. #define REGISTER_QUEST_CONDITION_SUB_CLASS( derivedClass, condName, nCondReqFields ) QuestConditionEntry_t k_s##condName##RegisteredEntry( #condName, nCondReqFields, CreateCTFQuestConditionSubClass< derivedClass > );
  90. bool IsValidServerForQuests( CSteamID steamIDQuestOwner )
  91. {
  92. // Check if we're on beta. If so, allow it.
  93. if ( ( engine->GetAppID() == 810 || engine->GetAppID() == 440 )
  94. && ( steamIDQuestOwner.GetEUniverse() == k_EUniverseBeta || steamIDQuestOwner.GetEUniverse() == k_EUniverseDev ) )
  95. return true;
  96. // TODO Do we want to exclude quest progress after the match is over or during warm-up? We'd need another function
  97. // and to check it in appropriate spots -- this guy returning false if the match is over gives the user
  98. // "Invalid server" status on their quest display and so on.
  99. // We only allow for quests to be tracked on Valve servers -- check if we joined via MM. Don't care if the match is
  100. // still running.
  101. EMatchGroup eMatchGroup = TFGameRules()->GetCurrentMatchGroup();
  102. bool bTrustedMatch = ( eMatchGroup != k_nMatchGroup_Invalid ) && GetMatchGroupDescription( eMatchGroup )->BIsTrustedServersOnly();
  103. if ( !bTrustedMatch )
  104. return false;
  105. return true;
  106. }
  107. void GetInvalidReasonsNames( const InvalidReasonsContainer_t& invalidReasons, CUtlVector< CUtlString >& vecStrings )
  108. {
  109. static const char* arReasons[] =
  110. {
  111. "#TF_QuestInvalid_WrongMap", // INVALID_QUEST_REASON_WRONG_MAP = 0,
  112. "#TF_QuestInvalid_WrongClass", // INVALID_QUEST_REASON_WRONG_CLASS,
  113. "#TF_QuestInvalid_GameMode", // INVALID_QUEST_REASON_WRONG_GAME_MODE,
  114. "#TF_QuestInvalid_NotEnoughPlayers", // INVALID_QUEST_REASON_NOT_ENOUGH_PLAYERS,
  115. "#TF_QuestInvalid_ValveServers", // INVALID_QUEST_REASON_VALVE_SERVERS_ONLY,
  116. "#TF_QuestInvalid_MvM", // INVALID_QUEST_REASON_NO_MVM
  117. };
  118. for( int i=0; i < invalidReasons.m_bits.GetNumBits(); ++i )
  119. {
  120. if ( invalidReasons.m_bits.IsBitSet( i ) )
  121. {
  122. vecStrings.AddToTail( arReasons[i] );
  123. }
  124. }
  125. }
  126. KeyValues* GetQuestEventsKeyValues()
  127. {
  128. static KeyValues *pQuestEvents = NULL;
  129. if ( pQuestEvents == NULL )
  130. {
  131. CUtlBuffer bufRawData;
  132. bufRawData.SetBufferType( true, true );
  133. bool bReadFileOK = g_pFullFileSystem->ReadFile( g_skQuestEventsFile, NULL, bufRawData );
  134. if ( !bReadFileOK )
  135. {
  136. AssertMsg1( false, "Couldn't load quest events file: %s!", g_skQuestEventsFile );
  137. return NULL;
  138. }
  139. pQuestEvents = new KeyValues( "quest_events" );
  140. pQuestEvents->LoadFromBuffer( NULL, bufRawData );
  141. }
  142. return pQuestEvents;
  143. }
  144. // getting key of params that are unique per event
  145. void GetValidParamsKeyFromEvent( const char *pszKeyName, const char *pszRestrictionName, const char *pszEventName, KeyValues *pRequiredKeys )
  146. {
  147. KeyValues *pQuestEvents = GetQuestEventsKeyValues();
  148. if ( pQuestEvents )
  149. {
  150. KeyValues *pEvent = pQuestEvents->FindKey( pszEventName );
  151. AssertMsg1( pEvent, "Failed to find specified event name %s", pszEventName );
  152. if ( pEvent )
  153. {
  154. KeyValues *pRestriction = pEvent->FindKey( pszRestrictionName );
  155. AssertMsg2( pRestriction, "Failed to find specified restriction name %s :: %s", pszEventName, pszRestrictionName );
  156. if ( pRestriction )
  157. {
  158. KeyValues *pParamsKey = pRestriction->FindKey( pszKeyName );
  159. AssertMsg3( pParamsKey, "Failed to find specified param key name %s :: %s :: %s", pszEventName, pszRestrictionName, pszKeyName );
  160. if ( pParamsKey )
  161. {
  162. if ( pParamsKey->GetString( "uses_method", NULL ) )
  163. {
  164. KeyValues* pKVMethod = pParamsKey->FindKey( "method" );
  165. AssertMsg3( pKVMethod, "Failed to find method block in %s :: %s :: %s", pszEventName, pszRestrictionName, pszKeyName );
  166. if ( pKVMethod )
  167. {
  168. const char* pszType = pKVMethod->GetString( "type", NULL );
  169. AssertMsg3( pszType, "Missing method type in %s :: %s :: %s", pszEventName, pszRestrictionName, pszKeyName );
  170. if ( FStrEq( pszType, "weapon_def_index" ) )
  171. {
  172. KeyValues *pWeaponNames = new KeyValues( "value" );
  173. const CTFItemDefinition* pItemDef = NULL;
  174. const CEconItemSchema::SortedItemDefinitionMap_t& mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
  175. FOR_EACH_MAP( mapItems, it )
  176. {
  177. pItemDef = static_cast< const CTFItemDefinition* >( mapItems[it] );
  178. Assert( pItemDef->GetDefinitionIndex() != INVALID_ITEM_DEF_INDEX );
  179. if ( pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_PRIMARY
  180. || pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_SECONDARY
  181. || pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_MELEE
  182. || pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_PDA
  183. || pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_PDA2
  184. || pItemDef->GetDefaultLoadoutSlot() == LOADOUT_POSITION_BUILDING )
  185. {
  186. KeyValues *pNewWeapon = pWeaponNames->CreateNewKey();
  187. pNewWeapon->SetName( CFmtStr( "%d", pItemDef->GetDefinitionIndex() ) );
  188. pNewWeapon->SetString( "english_name", pItemDef->GetDefinitionName() );
  189. }
  190. }
  191. pRequiredKeys->AddSubKey( pWeaponNames );
  192. }
  193. else if ( FStrEq( pszType, "weapon_name" ) )
  194. {
  195. KeyValues *pWeaponNames = new KeyValues( "value" );
  196. // Add a few here that we magically use in the code elsewhere. Sigh...
  197. pWeaponNames->AddSubKey( new KeyValues( "obj_attachment_sapper" ) );
  198. pWeaponNames->AddSubKey( new KeyValues( "building_carried_destroyed" ) );
  199. const CEconItemDefinition* pItemDef = NULL;
  200. const CEconItemSchema::SortedItemDefinitionMap_t& mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
  201. for ( int it = mapItems.FirstInorder(); it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
  202. {
  203. pItemDef = mapItems[it];
  204. if ( pItemDef->GetIconClassname() )
  205. {
  206. pWeaponNames->AddSubKey( new KeyValues( pItemDef->GetIconClassname() ) );
  207. }
  208. }
  209. pRequiredKeys->AddSubKey( pWeaponNames );
  210. }
  211. else if ( FStrEq( pszType, "weapon_type" ) )
  212. {
  213. KeyValues *pWeaponType = new KeyValues( "value" );
  214. for ( int i=0; i<TF_WEAPON_COUNT; ++i )
  215. {
  216. const char *pszWeaponName = WeaponIdToAlias( i );
  217. KeyValues *pNewWeapon = pWeaponType->CreateNewKey();
  218. pNewWeapon->SetName( CFmtStr( "%d", i ) );
  219. pNewWeapon->SetString( "english_name", pszWeaponName );
  220. }
  221. pRequiredKeys->AddSubKey( pWeaponType );
  222. }
  223. else if ( FStrEq( pszType, "item_class" ) )
  224. {
  225. KeyValues *pItemClassNames = new KeyValues( "value" );
  226. const CEconItemDefinition* pItemDef = NULL;
  227. const CEconItemSchema::SortedItemDefinitionMap_t& mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
  228. CUtlMap< const char*, int > mapTypeNames( StringLessThan );
  229. for ( int it = mapItems.FirstInorder(); it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
  230. {
  231. pItemDef = mapItems[it];
  232. const char *pszClass = pItemDef->GetItemClass();
  233. if ( pszClass && mapTypeNames.Find( pszClass ) == mapTypeNames.InvalidIndex() )
  234. {
  235. mapTypeNames.Insert( pszClass );
  236. pItemClassNames->AddSubKey( new KeyValues( pItemDef->GetItemClass() ) );
  237. }
  238. }
  239. pRequiredKeys->AddSubKey( pItemClassNames );
  240. }
  241. else
  242. {
  243. AssertMsg5( false, "Type %s in %s :: %s :: %s didnt match any types defined in %s", pszType, pszEventName, pszRestrictionName, pszKeyName, __FUNCTION__ );
  244. }
  245. }
  246. }
  247. else
  248. {
  249. pRequiredKeys->AddSubKey( pParamsKey->MakeCopy() );
  250. }
  251. }
  252. }
  253. }
  254. }
  255. }
  256. //-----------------------------------------------------------------------------
  257. // Purpose:
  258. //-----------------------------------------------------------------------------
  259. CTFQuestCondition::CTFQuestCondition()
  260. : m_pParent( NULL )
  261. {}
  262. //-----------------------------------------------------------------------------
  263. // Purpose:
  264. //-----------------------------------------------------------------------------
  265. CTFQuestCondition::~CTFQuestCondition()
  266. {
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose:
  270. //-----------------------------------------------------------------------------
  271. bool CTFQuestCondition::BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ )
  272. {
  273. // check if restriction name matches the keyvalue name
  274. //const char *pszType = pKVItem->GetString( "type" );
  275. //SCHEMA_INIT_CHECK( FStrEq( pszType, GetConditionName() ), "%s", CFmtStr( "Invalid quest restriction name '%s' for '%s'", pszType, GetConditionName() ).Get() )
  276. return true;
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose: Print out debug text
  280. //-----------------------------------------------------------------------------
  281. void CTFQuestCondition::PrintDebugText() const
  282. {
  283. DevMsg( "'%s %s'", GetConditionName(), GetValueString() );
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose: Get the owner player
  287. //-----------------------------------------------------------------------------
  288. const CTFPlayer *CTFQuestCondition::GetQuestOwner() const
  289. {
  290. if ( m_pParent )
  291. return m_pParent->GetQuestOwner();
  292. return NULL;
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Global quest objective validation checks
  296. //-----------------------------------------------------------------------------
  297. bool CTFQuestCondition::IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  298. {
  299. if ( pOwner )
  300. {
  301. CSteamID steamIDOwner;
  302. const_cast< CTFPlayer* >( pOwner )->GetSteamID( &steamIDOwner ); // Ugh
  303. // Can only do quests on Valve servers
  304. if ( !IsValidServerForQuests( steamIDOwner ) )
  305. {
  306. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_VALVE_SERVERS_ONLY );
  307. }
  308. }
  309. // Cannot do quests in MvM
  310. if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() )
  311. {
  312. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_NO_MVM );
  313. }
  314. return true;
  315. }
  316. void CTFQuestCondition::GetValidRestrictions( CUtlVector< const char* >& vecOutValidChildren ) const
  317. {
  318. const CTFQuestCondition* pParent = this;
  319. const CTFQuestEvaluator* pEvaluatorParent = NULL;
  320. while( pParent && !pEvaluatorParent )
  321. {
  322. pEvaluatorParent = dynamic_cast< const CTFQuestEvaluator* >( pParent );
  323. pParent = pParent->GetParent();
  324. }
  325. KeyValues* pKVQuestEvents = GetQuestEventsKeyValues();
  326. KeyValues* pKVEvent = pKVQuestEvents->FindKey( pEvaluatorParent->GetEventName() );
  327. FOR_EACH_MAP( k_mapConditions, i )
  328. {
  329. QuestConditionEntry_t* pCondEntry = k_mapConditions[ i ];
  330. // All fields need to be present in the event for the condition to be a valid child
  331. bool bAnyFound = false;
  332. bool bAllFound = true;
  333. if ( pCondEntry->m_nRequiredFields != FIELD_NONE )
  334. {
  335. int nMaxCount = Q_log2( FIELD_LAST_FIELD );
  336. for( int nField = 0; nField <= nMaxCount && bAllFound; ++nField )
  337. {
  338. if ( pCondEntry->m_nRequiredFields & (1<<nField) )
  339. {
  340. bAnyFound = true;
  341. bAllFound &= pKVEvent->FindKey( k_pszQuestConditionRequiredFieldStrings[ nField ] ) != NULL;
  342. }
  343. }
  344. }
  345. else
  346. {
  347. bAllFound = true;
  348. bAnyFound = true;
  349. }
  350. if ( bAnyFound && bAllFound )
  351. {
  352. vecOutValidChildren.AddToTail( k_mapConditions.Key( i ) );
  353. }
  354. }
  355. }
  356. void CTFQuestCondition::GetValidEvaluators( CUtlVector< const char* >& vecOutValidChildren ) const
  357. {
  358. vecOutValidChildren.AddToTail( "event_listener" );
  359. vecOutValidChildren.AddToTail( "counter" );
  360. }
  361. void CTFQuestRestriction::GetValidTypes( CUtlVector< const char* >& vecOutValidChildren ) const
  362. {
  363. GetValidRestrictions( vecOutValidChildren );
  364. }
  365. void CTFQuestRestriction::GetValidChildren( CUtlVector< const char* >& vecOutValidChildren ) const
  366. {
  367. GetValidRestrictions( vecOutValidChildren );
  368. }
  369. CTFQuestEvaluator::CTFQuestEvaluator()
  370. {
  371. m_pszAction = NULL;
  372. }
  373. void CTFQuestEvaluator::GetOutputKeyValues( KeyValues *pOutputKeys )
  374. {
  375. if ( m_pszAction )
  376. {
  377. pOutputKeys->SetString( "action", m_pszAction );
  378. }
  379. }
  380. void CTFQuestEvaluator::GetValidTypes( CUtlVector< const char* >& vecOutValidChildren ) const
  381. {
  382. GetValidEvaluators( vecOutValidChildren );
  383. }
  384. void CTFQuestEvaluator::GetValidChildren( CUtlVector< const char* >& vecOutValidChildren ) const
  385. {
  386. GetValidRestrictions( vecOutValidChildren );
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose: base quest operator restriction
  390. //-----------------------------------------------------------------------------
  391. class CTFQuestOperatorRestriction: public CTFQuestRestriction
  392. {
  393. public:
  394. DECLARE_CLASS( CTFQuestOperatorRestriction, CTFQuestRestriction )
  395. virtual ~CTFQuestOperatorRestriction()
  396. {
  397. m_vecRestrictions.PurgeAndDeleteElements();
  398. }
  399. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  400. {
  401. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  402. return false;
  403. int nInputCount = 0;
  404. FOR_EACH_TRUE_SUBKEY( pKVItem, pSubKey )
  405. {
  406. if ( GetMaxInputCount() > 0 )
  407. {
  408. SCHEMA_INIT_CHECK( nInputCount < GetMaxInputCount(), "%s", CFmtStr( "Too many input for operator '%s'. expected %d input(s)", GetConditionName(), GetMaxInputCount() ).Get() );
  409. }
  410. const char *pszType = pSubKey->GetString( "type" );
  411. CTFQuestRestriction *pNewRestriction = CreateRestrictionByName( pszType, this );
  412. SCHEMA_INIT_CHECK( pNewRestriction != NULL, "%s", CFmtStr( "Failed to create quest restriction name '%s' for '%s'", pszType, GetConditionName() ).Get() );
  413. SCHEMA_INIT_CHECK( pNewRestriction->BInitFromKV( pSubKey, pVecErrors ), "Failed to init from KeyValues" );
  414. m_vecRestrictions.AddToTail( pNewRestriction );
  415. nInputCount++;
  416. }
  417. SCHEMA_INIT_CHECK( nInputCount > 0 && nInputCount <= GetMaxInputCount(), "%s", CFmtStr( "Invalid number of specified input. Expected from 0 to %d inputs.", GetMaxInputCount() ).Get() );
  418. return true;
  419. }
  420. virtual bool IsOperator() const OVERRIDE { return true; }
  421. virtual void PrintDebugText() const OVERRIDE
  422. {
  423. DevMsg( "( " );
  424. FOR_EACH_VEC( m_vecRestrictions, i )
  425. {
  426. if ( i == 0 )
  427. {
  428. m_vecRestrictions[i]->PrintDebugText();
  429. }
  430. else
  431. {
  432. DevMsg( " %s ", GetConditionName() );
  433. m_vecRestrictions[i]->PrintDebugText();
  434. }
  435. }
  436. DevMsg( " )" );
  437. }
  438. CTFQuestCondition* AddChildByName( const char *pszChildName ) OVERRIDE
  439. {
  440. if ( m_vecRestrictions.Count() >= GetMaxInputCount() )
  441. {
  442. Assert( m_vecRestrictions.Count() < GetMaxInputCount() );
  443. return NULL;
  444. }
  445. CTFQuestRestriction *pNewRestriction = CreateRestrictionByName( pszChildName, this );
  446. if ( pNewRestriction )
  447. {
  448. m_vecRestrictions.AddToTail( pNewRestriction );
  449. }
  450. return pNewRestriction;
  451. }
  452. virtual int GetChildren( CUtlVector< CTFQuestCondition* >& vecChildren ) OVERRIDE
  453. {
  454. FOR_EACH_VEC( m_vecRestrictions, i )
  455. {
  456. vecChildren.AddToTail( m_vecRestrictions[i] );
  457. }
  458. return vecChildren.Count();
  459. }
  460. bool RemoveAndDeleteChild( CTFQuestCondition *pChild ) OVERRIDE
  461. {
  462. CTFQuestRestriction *pRestrictionChild = assert_cast< CTFQuestRestriction* >( pChild );
  463. bool bRemoved = m_vecRestrictions.FindAndFastRemove( pRestrictionChild );
  464. Assert( bRemoved );
  465. if ( bRemoved )
  466. {
  467. delete pChild;
  468. }
  469. return bRemoved;
  470. }
  471. virtual int GetMaxInputCount() const OVERRIDE { return s_nMaxInputCount; }
  472. protected:
  473. CUtlVector< CTFQuestRestriction* > m_vecRestrictions;
  474. };
  475. //-----------------------------------------------------------------------------
  476. // Purpose: AND quest operator restriction
  477. //-----------------------------------------------------------------------------
  478. class CTFQuestAndOperatorRestriction : public CTFQuestOperatorRestriction
  479. {
  480. public:
  481. DECLARE_CLASS( CTFQuestAndOperatorRestriction, CTFQuestOperatorRestriction )
  482. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  483. {
  484. FOR_EACH_VEC( m_vecRestrictions, i )
  485. {
  486. if ( !m_vecRestrictions[i]->PassesRestrictions( pEvent ) )
  487. return false;
  488. }
  489. return true;
  490. }
  491. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  492. {
  493. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  494. bool bIsForLocalPlayer = false;
  495. InvalidReason operatorReasons;
  496. FOR_EACH_VEC( m_vecRestrictions, i )
  497. {
  498. bIsForLocalPlayer |= m_vecRestrictions[i]->IsValidForPlayer( pOwner, operatorReasons );
  499. }
  500. if ( bIsForLocalPlayer )
  501. {
  502. invalidReasons.m_bits.Or( operatorReasons.m_bits, &invalidReasons.m_bits );
  503. }
  504. return bIsForLocalPlayer;
  505. }
  506. };
  507. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestAndOperatorRestriction, AND, FIELD_NONE );
  508. //-----------------------------------------------------------------------------
  509. // Purpose: OR quest operator restriction
  510. //-----------------------------------------------------------------------------
  511. class CTFQuestOrOperatorRestriction : public CTFQuestOperatorRestriction
  512. {
  513. public:
  514. DECLARE_CLASS( CTFQuestOrOperatorRestriction, CTFQuestOperatorRestriction )
  515. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  516. {
  517. FOR_EACH_VEC( m_vecRestrictions, i )
  518. {
  519. if ( m_vecRestrictions[i]->PassesRestrictions( pEvent ) )
  520. return true;
  521. }
  522. return false;
  523. }
  524. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  525. {
  526. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  527. bool bIsForLocalPlayer = false;
  528. FOR_EACH_VEC( m_vecRestrictions, i )
  529. {
  530. InvalidReason operatorReason;
  531. if ( m_vecRestrictions[i]->IsValidForPlayer( pOwner, operatorReason ) )
  532. {
  533. bIsForLocalPlayer = true;
  534. invalidReasons.m_bits.Or( operatorReason.m_bits, &invalidReasons.m_bits );
  535. }
  536. }
  537. return bIsForLocalPlayer;
  538. }
  539. };
  540. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestOrOperatorRestriction, OR, FIELD_NONE );
  541. //-----------------------------------------------------------------------------
  542. // Purpose: NOT quest operator restriction
  543. //-----------------------------------------------------------------------------
  544. class CTFQuestNotOperatorRestriction : public CTFQuestOperatorRestriction
  545. {
  546. public:
  547. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  548. {
  549. return !m_vecRestrictions[0]->PassesRestrictions( pEvent );
  550. }
  551. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  552. {
  553. return false;
  554. }
  555. virtual void PrintDebugText() const OVERRIDE
  556. {
  557. CTFQuestRestriction *pRestriction = m_vecRestrictions[0];
  558. if ( pRestriction->IsOperator() )
  559. {
  560. DevMsg( "%s ", GetConditionName() );
  561. pRestriction->PrintDebugText();
  562. }
  563. else
  564. {
  565. // add () for non-operator to keep the debug text format consistent
  566. DevMsg( "%s ( ", GetConditionName() );
  567. pRestriction->PrintDebugText();
  568. DevMsg( " )" );
  569. }
  570. }
  571. protected:
  572. virtual int GetMaxInputCount() const OVERRIDE { return 1; }
  573. };
  574. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestNotOperatorRestriction, NOT, FIELD_NONE );
  575. class CTFGenericStringRestriction : public CTFQuestRestriction
  576. {
  577. public:
  578. CTFGenericStringRestriction()
  579. : m_pszKeyName( NULL )
  580. , m_pszValue( NULL )
  581. {}
  582. virtual const char *GetConditionName() const OVERRIDE { return m_pszFieldName; }
  583. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  584. {
  585. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  586. return false;
  587. m_pszKeyName = pKVItem->GetString( "key_to_lookup" );
  588. SCHEMA_INIT_CHECK( m_pszKeyName != NULL, "Missing key to lookup for generic_string restriction!" );
  589. m_pszValue = pKVItem->GetString( "value" );
  590. SCHEMA_INIT_CHECK( m_pszValue != NULL, "Missing value to compare against for generic_string restriction!" );
  591. return true;
  592. }
  593. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  594. {
  595. const char* pszValue = pEvent->GetString( m_pszKeyName );
  596. if ( pszValue )
  597. {
  598. return FStrEq( pszValue, m_pszValue );
  599. }
  600. return false;
  601. }
  602. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  603. {
  604. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  605. pOutputKeys->SetString( "key_to_lookup", m_pszKeyName );
  606. pOutputKeys->SetString( "value", m_pszValue );
  607. }
  608. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  609. {
  610. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  611. GetValidParamsKeyFromEvent( "key_to_lookup", m_pszFieldName, m_pszEventName, pRequiredKeys );
  612. GetValidParamsKeyFromEvent( "value", m_pszFieldName, m_pszEventName, pRequiredKeys );
  613. }
  614. protected:
  615. const char *m_pszKeyName;
  616. const char *m_pszValue;
  617. };
  618. class CTFGenericSubStringRestriction : public CTFGenericStringRestriction
  619. {
  620. public:
  621. CTFGenericSubStringRestriction()
  622. {}
  623. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  624. {
  625. const char* pszValue = pEvent->GetString( m_pszKeyName );
  626. if ( pszValue )
  627. {
  628. return V_stristr( pszValue, m_pszValue ) != NULL;
  629. }
  630. return false;
  631. }
  632. };
  633. class CTFWeaponClassRestriction : public CTFGenericStringRestriction
  634. {
  635. public:
  636. CTFWeaponClassRestriction()
  637. {}
  638. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  639. {
  640. const char* pszValue = pEvent->GetString( m_pszKeyName );
  641. if ( pszValue )
  642. {
  643. const CEconItemDefinition* pItemDef = GetItemSchema()->GetItemDefinition( atoi( pszValue ) );
  644. Assert( pItemDef );
  645. if ( pItemDef )
  646. {
  647. return FStrEq( pItemDef->GetItemClass(), m_pszValue );
  648. }
  649. }
  650. return false;
  651. }
  652. };
  653. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, crit_kill, FIELD_CRIT );
  654. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, weapon_def_index, FIELD_WEAPON_DEF_INDEX );
  655. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, weapon_name, FIELD_WEAPON_NAME );
  656. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, halloween_boss_type, FIELD_HALLOWEEN_BOSS_TYPE );
  657. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, minigame_type, FIELD_HALLOWEEN_MINIGAME_TYPE );
  658. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericStringRestriction, bonuseffect, FIELD_BONUSEFFECT );
  659. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFWeaponClassRestriction, weapon_class, FIELD_WEAPON_CLASS );
  660. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFGenericSubStringRestriction, deflected_projectile, FIELD_DEFLECTED_PROJECTILE );
  661. //-----------------------------------------------------------------------------
  662. // Purpose: quest player restriction
  663. //-----------------------------------------------------------------------------
  664. class CTFQuestBasePlayerRestriction : public CTFQuestRestriction
  665. {
  666. public:
  667. CTFQuestBasePlayerRestriction()
  668. : m_pszPlayerKey( NULL )
  669. , m_pszPlayerMethod( NULL )
  670. {}
  671. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  672. {
  673. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  674. return false;
  675. m_pszPlayerKey = pKVItem->GetString( "player_key", NULL );
  676. Assert( m_pszPlayerKey );
  677. SCHEMA_INIT_CHECK( m_pszPlayerKey != NULL, "missing 'player_key'" );
  678. static const char *s_pszValidGetMethod[] =
  679. {
  680. "by_id",
  681. "by_entindex",
  682. "by_cappers"
  683. };
  684. m_pszPlayerMethod = pKVItem->GetString( "get_player" );
  685. bool bIsValidMethod = false;
  686. for ( int i=0; i<ARRAYSIZE( s_pszValidGetMethod ); ++i )
  687. {
  688. if ( FStrEq( m_pszPlayerMethod, s_pszValidGetMethod[i] ) )
  689. {
  690. bIsValidMethod = true;
  691. break;
  692. }
  693. }
  694. SCHEMA_INIT_CHECK( bIsValidMethod, "Invalid 'get_player'" );
  695. return true;
  696. }
  697. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  698. {
  699. CTFPlayer *pPlayer = GetPlayerFromEvent( pEvent );
  700. if ( !pPlayer )
  701. return false;
  702. return BPlayerCheck( pPlayer, pEvent );
  703. }
  704. CTFPlayer *GetPlayerFromEvent( IGameEvent *pEvent ) const
  705. {
  706. CTFPlayer *pPlayer = NULL;
  707. if ( FStrEq( m_pszPlayerMethod, "by_id" ) )
  708. {
  709. int iPlayerID = pEvent->GetInt( m_pszPlayerKey );
  710. pPlayer = ToTFPlayer( UTIL_PlayerByUserId( iPlayerID ) );
  711. }
  712. else if ( FStrEq( m_pszPlayerMethod, "by_entindex" ) )
  713. {
  714. int iPlayerIndex = pEvent->GetInt( m_pszPlayerKey );
  715. pPlayer = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  716. }
  717. else if ( FStrEq( m_pszPlayerMethod, "by_cappers" ) )
  718. {
  719. Assert( FStrEq( m_pszPlayerKey, "cappers" ) );
  720. const CTFPlayer *pQuestOwner = GetQuestOwner();
  721. const char *cappers = pEvent->GetString( m_pszPlayerKey );
  722. for ( int i = 0; i < Q_strlen( cappers ); i++ )
  723. {
  724. int iPlayerIndex = (int)cappers[i];
  725. CTFPlayer *pCapper = ToTFPlayer( UTIL_PlayerByIndex( iPlayerIndex ) );
  726. if ( pCapper == pQuestOwner )
  727. {
  728. pPlayer = pCapper;
  729. break;
  730. }
  731. }
  732. }
  733. return pPlayer;
  734. }
  735. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  736. {
  737. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  738. GetValidParamsKeyFromEvent( "player_key", "player", m_pszEventName, pRequiredKeys );
  739. GetValidParamsKeyFromEvent( "get_player", "player", m_pszEventName, pRequiredKeys );
  740. }
  741. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  742. {
  743. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  744. pOutputKeys->SetString( "player_key", m_pszPlayerKey );
  745. pOutputKeys->SetString( "get_player", m_pszPlayerMethod );
  746. }
  747. protected:
  748. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const = 0;
  749. const char *m_pszPlayerKey;
  750. const char *m_pszPlayerMethod;
  751. };
  752. //-----------------------------------------------------------------------------
  753. // Purpose: quest player restriction
  754. //-----------------------------------------------------------------------------
  755. class CTFQuestPlayerDisguiseRestriction : public CTFQuestBasePlayerRestriction
  756. {
  757. public:
  758. CTFQuestPlayerDisguiseRestriction() {}
  759. enum EDisguiseTargetState_t
  760. {
  761. DISGUISE_STATE_OWNER_IS_PLAYER,
  762. DISGUISE_STATE_OWNER_IS_NOT_PLAYER,
  763. DISGUISE_STATE_PLAYER_IS_OWNER,
  764. DISGUISE_STATE_PLAYER_IS_NOT_OWNER,
  765. DISGUISE_STATE_DONT_CARE
  766. };
  767. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  768. {
  769. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  770. return false;
  771. m_eDisguiseState = (EDisguiseTargetState_t)pKVItem->GetInt( "disguise_target", DISGUISE_STATE_DONT_CARE );
  772. return true;
  773. }
  774. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  775. {
  776. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  777. // Disguise state
  778. {
  779. KeyValues *pKVDisguiseKeys = new KeyValues( "disguise_target" );
  780. pKVDisguiseKeys->SetString( "english_name", "Disguise" );
  781. // DISGUISE_STATE_OWNER_IS_PLAYER
  782. KeyValues * pKVDisguiseState = pKVDisguiseKeys->CreateNewKey();
  783. pKVDisguiseState->SetName( "0" );
  784. pKVDisguiseState->SetString( "english_name", "Owner disguised as the player" );
  785. // DISGUISE_STATE_OWNER_IS_NOT_PLAYER
  786. pKVDisguiseState = pKVDisguiseKeys->CreateNewKey();
  787. pKVDisguiseState->SetName( "1" );
  788. pKVDisguiseState->SetString( "english_name", "Owner NOT disguised as the player" );
  789. // DISGUISE_STATE_PLAYER_IS_OWNER
  790. pKVDisguiseState = pKVDisguiseKeys->CreateNewKey();
  791. pKVDisguiseState->SetName( "2" );
  792. pKVDisguiseState->SetString( "english_name", "Player disguised as the owner" );
  793. // DISGUISE_STATE_PLAYER_IS_NOT_OWNER
  794. pKVDisguiseState = pKVDisguiseKeys->CreateNewKey();
  795. pKVDisguiseState->SetName( "3" );
  796. pKVDisguiseState->SetString( "english_name", "Player NOT disguised as the owner" );
  797. pRequiredKeys->AddSubKey( pKVDisguiseKeys );
  798. }
  799. }
  800. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  801. {
  802. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  803. pOutputKeys->SetInt( "disguise_target", m_eDisguiseState );
  804. }
  805. protected:
  806. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  807. {
  808. // Disguise state check
  809. const CTFPlayer* pPlayerDisguiseTarget = ToTFPlayer( pPlayer->m_Shared.GetDisguiseTarget() );
  810. const CTFPlayer* pOwnerDisguiseTarget = ToTFPlayer( GetQuestOwner()->m_Shared.GetDisguiseTarget() );
  811. // owner in disguise
  812. if ( pOwnerDisguiseTarget )
  813. {
  814. // must disguise as same class to look the same
  815. if ( m_eDisguiseState == DISGUISE_STATE_OWNER_IS_PLAYER && pOwnerDisguiseTarget == pPlayer && GetQuestOwner()->m_Shared.GetDisguiseClass() == pPlayer->GetPlayerClass()->GetClassIndex() )
  816. return true;
  817. if ( m_eDisguiseState == DISGUISE_STATE_OWNER_IS_NOT_PLAYER && pOwnerDisguiseTarget != pPlayer )
  818. return true;
  819. }
  820. // player in disguise
  821. if ( pPlayerDisguiseTarget )
  822. {
  823. // must disguise as same class to look the same
  824. if ( m_eDisguiseState == DISGUISE_STATE_PLAYER_IS_OWNER && pPlayerDisguiseTarget == GetQuestOwner() && pPlayer->m_Shared.GetDisguiseClass() == GetQuestOwner()->GetPlayerClass()->GetClassIndex() )
  825. return true;
  826. if ( m_eDisguiseState == DISGUISE_STATE_PLAYER_IS_NOT_OWNER && pPlayerDisguiseTarget != GetQuestOwner() )
  827. return true;
  828. }
  829. return false;
  830. }
  831. EDisguiseTargetState_t m_eDisguiseState;
  832. };
  833. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerDisguiseRestriction, player_disguise, FIELD_PLAYER );
  834. //-----------------------------------------------------------------------------
  835. // Purpose: quest player jumping-state restriction
  836. //-----------------------------------------------------------------------------
  837. class CTFQuestPlayerJumpingRestriction : public CTFQuestBasePlayerRestriction
  838. {
  839. public:
  840. CTFQuestPlayerJumpingRestriction() {}
  841. enum EJumpingState_t
  842. {
  843. JUMPING_STATE_IS_NOT_JUMPING = 0,
  844. JUMPING_STATE_IS_JUMPING,
  845. JUMPING_STATE_IS_DOUBLE_JUMPING,
  846. JUMPING_STATE_IS_TRIPLE_JUMPING,
  847. };
  848. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  849. {
  850. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  851. return false;
  852. m_eJumpingState = (EJumpingState_t)pKVItem->GetInt( "jumping_state", JUMPING_STATE_IS_NOT_JUMPING );
  853. return true;
  854. }
  855. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  856. {
  857. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  858. // Jumping state
  859. {
  860. KeyValues *pKVJumpingKeys = new KeyValues( "jumping_state" );
  861. pKVJumpingKeys->SetString( "english_name", "Jumping" );
  862. KeyValues * pKVJumpState = pKVJumpingKeys->CreateNewKey();
  863. pKVJumpState->SetName( "0" );
  864. pKVJumpState->SetString( "english_name", "Must NOT be jumping" );
  865. pKVJumpState = pKVJumpingKeys->CreateNewKey();
  866. pKVJumpState->SetName( "1" );
  867. pKVJumpState->SetString( "english_name", "Must be at least jumping" );
  868. pKVJumpState = pKVJumpingKeys->CreateNewKey();
  869. pKVJumpState->SetName( "2" );
  870. pKVJumpState->SetString( "english_name", "Must be at least double-jumping" );
  871. pKVJumpState = pKVJumpingKeys->CreateNewKey();
  872. pKVJumpState->SetName( "3" );
  873. pKVJumpState->SetString( "english_name", "Must be at least triple-jumping" );
  874. pRequiredKeys->AddSubKey( pKVJumpingKeys );
  875. }
  876. }
  877. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  878. {
  879. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  880. pOutputKeys->SetInt( "jumping_state", m_eJumpingState );
  881. }
  882. protected:
  883. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  884. {
  885. #ifdef GAME_DLL
  886. CTFPlayer* pNonConstPlayer = const_cast< CTFPlayer* >( pPlayer );
  887. int nNumJumps = pNonConstPlayer->GetGroundEntity() == NULL ? 1 : 0;
  888. nNumJumps += pPlayer->m_Shared.GetAirDash();
  889. nNumJumps += pPlayer->m_bScattergunJump;
  890. if ( m_eJumpingState == JUMPING_STATE_IS_NOT_JUMPING )
  891. {
  892. return nNumJumps == 0;
  893. }
  894. else if ( m_eJumpingState == JUMPING_STATE_IS_JUMPING )
  895. {
  896. return nNumJumps >= 1;
  897. }
  898. else if ( m_eJumpingState == JUMPING_STATE_IS_DOUBLE_JUMPING )
  899. {
  900. return nNumJumps >= 2;
  901. }
  902. else if ( m_eJumpingState == JUMPING_STATE_IS_TRIPLE_JUMPING )
  903. {
  904. return nNumJumps >= 3;
  905. }
  906. else
  907. {
  908. AssertMsg1( false, "Unhandled EJumpingState_t case %d!", m_eJumpingState );
  909. }
  910. #endif
  911. return false;
  912. }
  913. EJumpingState_t m_eJumpingState;
  914. };
  915. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerJumpingRestriction, player_jumping, FIELD_PLAYER );
  916. //-----------------------------------------------------------------------------
  917. // Purpose: quest player alive-state restriction
  918. //-----------------------------------------------------------------------------
  919. class CTFQuestPlayerAliveRestriction : public CTFQuestBasePlayerRestriction
  920. {
  921. public:
  922. CTFQuestPlayerAliveRestriction() {}
  923. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  924. {
  925. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  926. return false;
  927. m_bAliveState = pKVItem->GetBool( "alive_state", true );
  928. return true;
  929. }
  930. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  931. {
  932. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  933. KeyValues *pKVAliveKeys = new KeyValues( "alive_state" );
  934. pKVAliveKeys->SetString( "english_name", "Alive" );
  935. KeyValues * pKVAliveState = pKVAliveKeys->CreateNewKey();
  936. pKVAliveState->SetName( "1" );
  937. pKVAliveState->SetString( "english_name", "Must be alive" );
  938. pKVAliveState = pKVAliveKeys->CreateNewKey();
  939. pKVAliveState->SetName( "0" );
  940. pKVAliveState->SetString( "english_name", "Must be dead" );
  941. pRequiredKeys->AddSubKey( pKVAliveKeys );
  942. }
  943. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  944. {
  945. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  946. pOutputKeys->SetInt( "alive_state", m_bAliveState );
  947. }
  948. protected:
  949. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  950. {
  951. return ( pPlayer->m_iHealth > 0 ) == m_bAliveState;
  952. }
  953. bool m_bAliveState;
  954. };
  955. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerAliveRestriction, player_alive, FIELD_PLAYER );
  956. //-----------------------------------------------------------------------------
  957. // Purpose: quest player distance restriction relative to the owner
  958. //-----------------------------------------------------------------------------
  959. class CTFQuestPlayerDistanceRestriction : public CTFQuestBasePlayerRestriction
  960. {
  961. public:
  962. CTFQuestPlayerDistanceRestriction() {}
  963. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  964. {
  965. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  966. return false;
  967. m_eCheckType = (EDistanceCheck_t)pKVItem->GetInt( "distance_check_type", INVALID_CHECK_TYPE );
  968. SCHEMA_INIT_CHECK( m_eCheckType != INVALID_CHECK_TYPE, "Invalid distance_check_type %d!", m_eCheckType );
  969. m_nDistance = pKVItem->GetInt( "distance_to_check", 0 );
  970. SCHEMA_INIT_CHECK( m_eCheckType != 0, "Distance must be non-zero!" );
  971. return true;
  972. }
  973. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  974. {
  975. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  976. KeyValues *pKVDistanceCheckTypeKeys = new KeyValues( "distance_check_type" );
  977. pKVDistanceCheckTypeKeys->SetString( "english_name", "Alive" );
  978. KeyValues * pKVType = pKVDistanceCheckTypeKeys->CreateNewKey();
  979. pKVType->SetName( "1" );
  980. pKVType->SetString( "english_name", "Closer than" );
  981. pKVType = pKVDistanceCheckTypeKeys->CreateNewKey();
  982. pKVType->SetName( "2" );
  983. pKVType->SetString( "english_name", "Further than" );
  984. pRequiredKeys->AddSubKey( pKVDistanceCheckTypeKeys );
  985. KeyValues *pDistanceKey = new KeyValues( "distance_to_check" );
  986. pDistanceKey->SetString( "control_type", "text_entry" );
  987. pRequiredKeys->AddSubKey( pDistanceKey );
  988. }
  989. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  990. {
  991. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  992. pOutputKeys->SetInt( "distance_check_type", m_eCheckType );
  993. pOutputKeys->SetInt( "distance_to_check", m_nDistance );
  994. }
  995. protected:
  996. enum EDistanceCheck_t
  997. {
  998. INVALID_CHECK_TYPE = 0,
  999. CLOSER_THAN,
  1000. FURTHER_THAN
  1001. };
  1002. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1003. {
  1004. int nTestDist = m_nDistance * m_nDistance;
  1005. int nPlayerDistSq = ( pPlayer->GetAbsOrigin() - GetQuestOwner()->GetAbsOrigin() ).LengthSqr();
  1006. if ( m_eCheckType == CLOSER_THAN )
  1007. {
  1008. return nPlayerDistSq < nTestDist;
  1009. }
  1010. else
  1011. {
  1012. return nPlayerDistSq > nTestDist;
  1013. }
  1014. }
  1015. EDistanceCheck_t m_eCheckType;
  1016. float m_nDistance;
  1017. };
  1018. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerDistanceRestriction, player_distance, FIELD_PLAYER );
  1019. //-----------------------------------------------------------------------------
  1020. // Purpose: quest player restriction
  1021. //-----------------------------------------------------------------------------
  1022. class CTFQuestPlayerIsOwnerRestriction : public CTFQuestBasePlayerRestriction
  1023. {
  1024. public:
  1025. CTFQuestPlayerIsOwnerRestriction() {}
  1026. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1027. {
  1028. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1029. return false;
  1030. // should check if this player is quest owner?
  1031. m_bIsOwner = pKVItem->GetBool( "is_owner" );
  1032. return true;
  1033. }
  1034. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1035. {
  1036. CTFQuestBasePlayerRestriction::IsValidForPlayer( pOwner, invalidReasons );
  1037. return m_bIsOwner && pOwner == GetQuestOwner();
  1038. }
  1039. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1040. {
  1041. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1042. KeyValues *pIsOwnerKey = new KeyValues( "is_owner" );
  1043. pIsOwnerKey->SetString( "english_name", "is_owner" );
  1044. KeyValues *pIsOwnerKeyChoiceTrue = new KeyValues( "1" );
  1045. pIsOwnerKeyChoiceTrue->SetString( "english_name", "true" );
  1046. KeyValues *pIsOwnerKeyChoiceFalse = new KeyValues( "0" );
  1047. pIsOwnerKeyChoiceFalse->SetString( "english_name", "false" );
  1048. pIsOwnerKey->AddSubKey( pIsOwnerKeyChoiceTrue );
  1049. pIsOwnerKey->AddSubKey( pIsOwnerKeyChoiceFalse );
  1050. pRequiredKeys->AddSubKey( pIsOwnerKey );
  1051. }
  1052. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1053. {
  1054. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1055. pOutputKeys->SetBool( "is_owner", m_bIsOwner );
  1056. }
  1057. private:
  1058. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1059. {
  1060. return m_bIsOwner == ( pPlayer == GetQuestOwner() );
  1061. }
  1062. bool m_bIsOwner;
  1063. };
  1064. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerIsOwnerRestriction, player_is_owner, FIELD_PLAYER );
  1065. //-----------------------------------------------------------------------------
  1066. // Purpose: quest class restriction
  1067. //-----------------------------------------------------------------------------
  1068. class CTFQuestPlayerClassRestriction : public CTFQuestBasePlayerRestriction
  1069. {
  1070. public:
  1071. DECLARE_CLASS( CTFQuestPlayerClassRestriction, CTFQuestBasePlayerRestriction )
  1072. CTFQuestPlayerClassRestriction()
  1073. {
  1074. m_iClass = TF_CLASS_UNDEFINED;
  1075. }
  1076. virtual const char *GetValueString() const OVERRIDE
  1077. {
  1078. return GetItemSchema()->GetClassUsabilityStrings()[ m_iClass ];
  1079. }
  1080. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1081. {
  1082. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1083. return false;
  1084. const char *pszClassName = pKVItem->GetString( "value", NULL );
  1085. m_iClass = StringFieldToInt( pszClassName, GetItemSchema()->GetClassUsabilityStrings() );
  1086. SCHEMA_INIT_CHECK( IsValidTFPlayerClass( m_iClass ), "%s", CFmtStr( "Invalid owner class restriction '%s' for quest objective", pszClassName ).Get() );
  1087. return true;
  1088. }
  1089. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1090. {
  1091. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  1092. if ( !BPlayerCheck( pOwner, NULL ) )
  1093. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_WRONG_CLASS );
  1094. return false;
  1095. }
  1096. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1097. {
  1098. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1099. KeyValues *pClassesKey = new KeyValues( "value" );
  1100. for ( int i=0; i<GetItemSchema()->GetClassUsabilityStrings().Count(); ++i )
  1101. {
  1102. const char *pszClassName = GetItemSchema()->GetClassUsabilityStrings()[i];
  1103. pClassesKey->AddSubKey( new KeyValues( pszClassName ) );
  1104. }
  1105. pRequiredKeys->AddSubKey( pClassesKey );
  1106. }
  1107. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1108. {
  1109. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1110. pOutputKeys->SetString( "value", GetValueString() );
  1111. }
  1112. private:
  1113. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1114. {
  1115. // Check if the classes match
  1116. int iClass = pPlayer->GetPlayerClass()->GetClassIndex();
  1117. return m_iClass == iClass;
  1118. }
  1119. int m_iClass;
  1120. };
  1121. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerClassRestriction, player_class, FIELD_PLAYER );
  1122. //-----------------------------------------------------------------------------
  1123. // Purpose: quest player condition restriction
  1124. //-----------------------------------------------------------------------------
  1125. class CTFQuestPlayerConditionRestriction : public CTFQuestBasePlayerRestriction
  1126. {
  1127. public:
  1128. virtual const char *GetValueString() const OVERRIDE
  1129. {
  1130. return GetTFConditionName( m_eCondition );
  1131. }
  1132. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1133. {
  1134. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1135. return false;
  1136. const char *pszConditionName = pKVItem->GetString( "value", NULL );
  1137. m_eCondition = GetTFConditionFromName( pszConditionName );
  1138. SCHEMA_INIT_CHECK( m_eCondition != TF_COND_INVALID, "%s", CFmtStr( "Invalid %s restriction '%s' for quest objective", GetConditionName(), pszConditionName ).Get() );
  1139. m_bOwnerMustBeProvider = pKVItem->GetBool( "provider_must_be_owner", false );
  1140. return true;
  1141. }
  1142. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1143. {
  1144. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1145. KeyValues *pConditionsKey = new KeyValues( "value" );
  1146. for ( int i=0; i<TF_COND_LAST; ++i )
  1147. {
  1148. const char *pszConditionName = GetTFConditionName( ETFCond( i ) );
  1149. pConditionsKey->AddSubKey( new KeyValues( pszConditionName ) );
  1150. }
  1151. pRequiredKeys->AddSubKey( pConditionsKey );
  1152. KeyValues *pRequireOwnerIsProvider = new KeyValues( "provider_must_be_owner" );
  1153. KeyValues *pIsOwnerKeyChoiceTrue = new KeyValues( "1" );
  1154. pIsOwnerKeyChoiceTrue->SetString( "english_name", "true" );
  1155. pRequireOwnerIsProvider->AddSubKey( pIsOwnerKeyChoiceTrue );
  1156. KeyValues *pIsOwnerKeyChoiceFalse = new KeyValues( "0" );
  1157. pIsOwnerKeyChoiceFalse->SetString( "english_name", "false" );
  1158. pRequireOwnerIsProvider->AddSubKey( pIsOwnerKeyChoiceFalse );
  1159. pRequiredKeys->AddSubKey( pRequireOwnerIsProvider );
  1160. }
  1161. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1162. {
  1163. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1164. pOutputKeys->SetString( "value", GetValueString() );
  1165. pOutputKeys->SetBool( "provider_must_be_owner", m_bOwnerMustBeProvider );
  1166. }
  1167. private:
  1168. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1169. {
  1170. // Must be in the condition
  1171. if ( !pPlayer->m_Shared.InCond( m_eCondition ) )
  1172. return false;
  1173. // Might require the owner is the provider
  1174. if ( m_bOwnerMustBeProvider && pPlayer->m_Shared.GetConditionProvider( m_eCondition ) != GetQuestOwner() )
  1175. return false;
  1176. return true;
  1177. }
  1178. ETFCond m_eCondition;
  1179. bool m_bOwnerMustBeProvider;
  1180. };
  1181. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerConditionRestriction, player_condition, FIELD_PLAYER );
  1182. //-----------------------------------------------------------------------------
  1183. // Purpose: quest player condition restriction
  1184. //-----------------------------------------------------------------------------
  1185. class CTFQuestPlayerObjectRestriction : public CTFQuestBasePlayerRestriction
  1186. {
  1187. public:
  1188. DECLARE_CLASS( CTFQuestPlayerObjectRestriction, CTFQuestBasePlayerRestriction )
  1189. CTFQuestPlayerObjectRestriction()
  1190. : m_pszObjectKey( NULL ),
  1191. m_eObjectType( OBJ_DISPENSER )
  1192. {}
  1193. virtual const char *GetValueString() const OVERRIDE
  1194. {
  1195. return GetObjectInfo( m_eObjectType )->m_pObjectName;
  1196. }
  1197. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1198. {
  1199. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1200. return false;
  1201. m_pszObjectKey = pKVItem->GetString( "object_key", NULL );
  1202. SCHEMA_INIT_CHECK( m_pszObjectKey != NULL, "Missing object_key" );
  1203. const char *pszObjectTypeName = pKVItem->GetString( "value", NULL );
  1204. m_eObjectType = (ObjectType_t)GetBuildableId( pszObjectTypeName );
  1205. SCHEMA_INIT_CHECK( m_eObjectType != OBJ_LAST, "%s", CFmtStr( "Invalid %s restriction '%s' for quest objective", GetConditionName(), pszObjectTypeName ).Get() );
  1206. return true;
  1207. }
  1208. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1209. {
  1210. CTFQuestBasePlayerRestriction::IsValidForPlayer( pOwner, invalidReasons );
  1211. if ( !pOwner->IsPlayerClass( TF_CLASS_ENGINEER ) )
  1212. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_WRONG_CLASS );
  1213. return false;
  1214. }
  1215. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1216. {
  1217. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1218. GetValidParamsKeyFromEvent( "object_key", CTFQuestPlayerObjectRestriction::GetConditionName(), m_pszEventName, pRequiredKeys );
  1219. KeyValues *pObjectKey = new KeyValues( "value" );
  1220. for ( int i=0; i<OBJ_LAST; ++i )
  1221. {
  1222. const char *pszObjectName = GetObjectInfo( ObjectType_t(i) )->m_pObjectName;
  1223. pObjectKey->AddSubKey( new KeyValues( pszObjectName ) );
  1224. }
  1225. pRequiredKeys->AddSubKey( pObjectKey );
  1226. }
  1227. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1228. {
  1229. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1230. pOutputKeys->SetString( "object_key", m_pszObjectKey );
  1231. pOutputKeys->SetString( "value", GetValueString() );
  1232. }
  1233. private:
  1234. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1235. {
  1236. int nEntIndex = pEvent->GetInt( m_pszObjectKey );
  1237. #ifdef GAME_DLL
  1238. CBaseEntity *pObj = UTIL_EntityByIndex( nEntIndex );
  1239. #else
  1240. CBaseEntity *pObj = ClientEntityList().GetEnt( nEntIndex );
  1241. #endif
  1242. CBaseObject *pPlayerObj = pPlayer->GetObjectOfType( m_eObjectType );
  1243. return pObj && pPlayerObj && pObj == pPlayerObj;
  1244. }
  1245. const char *m_pszObjectKey;
  1246. ObjectType_t m_eObjectType;
  1247. };
  1248. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestPlayerObjectRestriction, object_type, FIELD_PLAYER | FIELD_OBJECT );
  1249. //-----------------------------------------------------------------------------
  1250. // Purpose: quest player condition restriction
  1251. //-----------------------------------------------------------------------------
  1252. class CTFQuestScorerRestriction : public CTFQuestBasePlayerRestriction
  1253. {
  1254. public:
  1255. CTFQuestScorerRestriction()
  1256. : m_pszScorerKey( NULL )
  1257. {}
  1258. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1259. {
  1260. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1261. return false;
  1262. m_pszScorerKey = pKVItem->GetString( "scorer_key", NULL );
  1263. SCHEMA_INIT_CHECK( m_pszScorerKey != NULL, "Missing scorer key" );
  1264. return true;
  1265. }
  1266. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1267. {
  1268. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  1269. if ( !pOwner->IsPlayerClass( TF_CLASS_ENGINEER ) )
  1270. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_WRONG_CLASS );
  1271. return false;
  1272. }
  1273. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1274. {
  1275. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1276. GetValidParamsKeyFromEvent( "scorer_key", GetConditionName(), m_pszEventName, pRequiredKeys );
  1277. }
  1278. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1279. {
  1280. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1281. pOutputKeys->SetString( "scorer_key", m_pszScorerKey );
  1282. }
  1283. private:
  1284. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1285. {
  1286. #ifdef GAME_DLL
  1287. int nEntIndex = pEvent->GetInt( m_pszScorerKey );
  1288. CBaseEntity *pEnt = UTIL_EntityByIndex( nEntIndex );
  1289. IScorer* pScorer = dynamic_cast< IScorer* >( pEnt );
  1290. if ( !pScorer )
  1291. return false;
  1292. return pScorer->GetScorer() == pPlayer;
  1293. #else
  1294. return true;
  1295. #endif
  1296. }
  1297. const char *m_pszScorerKey;
  1298. };
  1299. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestScorerRestriction, scorer, FIELD_PLAYER | FIELD_SCORER );
  1300. //-----------------------------------------------------------------------------
  1301. // Purpose: quest weapon restriction
  1302. //-----------------------------------------------------------------------------
  1303. class CTFQuestWeaponTypeRestriction : public CTFGenericStringRestriction
  1304. {
  1305. public:
  1306. virtual const char *GetValueString() const OVERRIDE
  1307. {
  1308. return WeaponIdToAlias( m_eWeaponType );
  1309. }
  1310. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1311. {
  1312. if ( !CTFGenericStringRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1313. return false;
  1314. m_eWeaponType = (ETFWeaponType)atoi( m_pszValue );
  1315. SCHEMA_INIT_CHECK( m_eWeaponType != TF_WEAPON_NONE, "%s", CFmtStr( "Invalid weapon restriction '%s' for quest objective", m_pszValue ).Get() );
  1316. return true;
  1317. }
  1318. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1319. {
  1320. ETFWeaponType weaponID = (ETFWeaponType)pEvent->GetInt( m_pszKeyName );
  1321. return m_eWeaponType == weaponID;
  1322. }
  1323. private:
  1324. ETFWeaponType m_eWeaponType;
  1325. };
  1326. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestWeaponTypeRestriction, weapon_type, FIELD_WEAPON_TYPE );
  1327. //-----------------------------------------------------------------------------
  1328. // Purpose: quest custom damage restriction
  1329. //-----------------------------------------------------------------------------
  1330. class CTFQuestCustomDamageRestriction : public CTFQuestRestriction
  1331. {
  1332. public:
  1333. virtual const char *GetValueString() const OVERRIDE
  1334. {
  1335. return GetCustomDamageName( m_eCustomDamageType );
  1336. }
  1337. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1338. {
  1339. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1340. return false;
  1341. const char *pszCustomDamageName = pKVItem->GetString( "value", NULL );
  1342. m_eCustomDamageType = GetCustomDamageFromName( pszCustomDamageName );
  1343. SCHEMA_INIT_CHECK( m_eCustomDamageType != TF_DMG_CUSTOM_NONE, "%s", CFmtStr( "Invalid weapon restriction '%s' for quest objective", pszCustomDamageName ).Get() );
  1344. m_pszCustomDamageKey = pKVItem->GetString( "custom_damage_key", NULL );
  1345. SCHEMA_INIT_CHECK( m_pszCustomDamageKey != NULL, "Invalid custom_damage_key!" );
  1346. return true;
  1347. }
  1348. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1349. {
  1350. ETFDmgCustom customDamageType = (ETFDmgCustom)pEvent->GetInt( m_pszCustomDamageKey );
  1351. return m_eCustomDamageType == customDamageType;
  1352. }
  1353. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1354. {
  1355. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  1356. GetValidParamsKeyFromEvent( "custom_damage_key", GetConditionName(), m_pszEventName, pRequiredKeys );
  1357. KeyValues *pDamageKey = new KeyValues( "value" );
  1358. for ( int i=0; i<TF_DMG_CUSTOM_END; ++i )
  1359. {
  1360. const char *pszCustomDamageName = GetCustomDamageName( ETFDmgCustom( i ) );
  1361. pDamageKey->AddSubKey( new KeyValues( pszCustomDamageName ) );
  1362. }
  1363. pRequiredKeys->AddSubKey( pDamageKey );
  1364. }
  1365. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1366. {
  1367. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  1368. pOutputKeys->SetString( "value", GetValueString() );
  1369. }
  1370. private:
  1371. ETFDmgCustom m_eCustomDamageType;
  1372. const char *m_pszCustomDamageKey;
  1373. };
  1374. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestCustomDamageRestriction, custom_damage, FIELD_CUSTOM_DAMAGE );
  1375. //-----------------------------------------------------------------------------
  1376. // Purpose: quest flag event restriction
  1377. //-----------------------------------------------------------------------------
  1378. class CTFFlagEventTypeRestriction : public CTFQuestRestriction
  1379. {
  1380. public:
  1381. CTFFlagEventTypeRestriction()
  1382. : m_eEventType( TF_FLAGEVENT_CAPTURE )
  1383. , m_pszKeyName( NULL )
  1384. {}
  1385. virtual const char *GetValueString() const OVERRIDE
  1386. {
  1387. return GetCTFEventName( m_eEventType );
  1388. }
  1389. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1390. {
  1391. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1392. return false;
  1393. const char *pszEventType = pKVItem->GetString( "value", NULL );
  1394. m_eEventType = GetCTFEventTypeFromName( pszEventType );
  1395. SCHEMA_INIT_CHECK( m_eEventType != TF_NUM_FLAG_EVENTS, "%s", CFmtStr( "Invalid CTF Event Type '%s' for quest objective", pszEventType ).Get() );
  1396. m_pszKeyName = pKVItem->GetString( "event_key", "eventtype" );
  1397. SCHEMA_INIT_CHECK( m_pszKeyName != NULL, "Missing \"event_key\" for flag_event_type" );
  1398. return true;
  1399. }
  1400. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1401. {
  1402. ETFFlagEventTypes eEventType = (ETFFlagEventTypes)pEvent->GetInt( m_pszKeyName );
  1403. return m_eEventType == eEventType;
  1404. }
  1405. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1406. {
  1407. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  1408. GetValidParamsKeyFromEvent( "event_key", "flag_event", m_pszEventName, pRequiredKeys );
  1409. KeyValues *pEventKey = new KeyValues( "value" );
  1410. for ( int i=1; i<TF_NUM_FLAG_EVENTS; ++i )
  1411. {
  1412. const char *pszEventType = GetCTFEventName( ETFFlagEventTypes( i ) );
  1413. pEventKey->AddSubKey( new KeyValues( pszEventType ) );
  1414. }
  1415. pRequiredKeys->AddSubKey( pEventKey );
  1416. }
  1417. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1418. {
  1419. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  1420. pOutputKeys->SetString( "value", GetValueString() );
  1421. pOutputKeys->SetString( "event_key", m_pszKeyName );
  1422. }
  1423. private:
  1424. ETFFlagEventTypes m_eEventType;
  1425. const char* m_pszKeyName;
  1426. };
  1427. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFFlagEventTypeRestriction, flag_event_type, FIELD_FLAG_EVENT );
  1428. static const char *s_pszTeamRestrictionNames[] =
  1429. {
  1430. "TEAM_ANY",
  1431. "TEAM_IS_OWNERS",
  1432. "TEAM_IS_NOT_OWNERS",
  1433. };
  1434. //-----------------------------------------------------------------------------
  1435. // Purpose: quest custom damage restriction
  1436. //-----------------------------------------------------------------------------
  1437. class CTFQuestTeamRestriction : public CTFQuestRestriction
  1438. {
  1439. public:
  1440. enum ETeamRestriction
  1441. {
  1442. TEAM_RESTRICTION_ANY = 0,
  1443. TEAM_RESTRICTION_IS_OWNERS,
  1444. TEAM_RESTRICTION_IS_NOT_OWNERS,
  1445. TEAM_RESTRICTION_MAX
  1446. };
  1447. CTFQuestTeamRestriction()
  1448. : m_eTeamRestriction( TEAM_RESTRICTION_ANY )
  1449. , m_pszTeamKey( NULL )
  1450. {}
  1451. virtual const char *GetValueString() const OVERRIDE
  1452. {
  1453. return s_pszTeamRestrictionNames[ m_eTeamRestriction ];
  1454. }
  1455. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1456. {
  1457. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1458. return false;
  1459. m_eTeamRestriction = (ETeamRestriction)pKVItem->GetInt( "team_requirement", TEAM_RESTRICTION_ANY );
  1460. m_pszTeamKey = pKVItem->GetString( "team_key", NULL );
  1461. SCHEMA_INIT_CHECK( m_pszTeamKey != NULL, "Missing \"m_pszTeamKey\" in team_restriction" );
  1462. return true;
  1463. }
  1464. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1465. {
  1466. int nTeam = pEvent->GetInt( m_pszTeamKey, TEAM_INVALID );
  1467. if ( nTeam == TEAM_INVALID )
  1468. {
  1469. AssertMsg( 0, "This event doesn't specify a team." );
  1470. return false;
  1471. }
  1472. const CTFPlayer *pOwner = GetQuestOwner();
  1473. bool bTeamIsOwners = nTeam == pOwner->GetTeamNumber();
  1474. if ( ( m_eTeamRestriction == TEAM_RESTRICTION_IS_OWNERS && !bTeamIsOwners ) ||
  1475. ( m_eTeamRestriction == TEAM_RESTRICTION_IS_NOT_OWNERS && bTeamIsOwners ) )
  1476. {
  1477. return false;
  1478. }
  1479. return true;
  1480. }
  1481. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1482. {
  1483. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  1484. GetValidParamsKeyFromEvent( "team_key", GetConditionName(), m_pszEventName, pRequiredKeys );
  1485. KeyValues *pTeamReq = new KeyValues( "team_requirement" );
  1486. for( int i=0; i<TEAM_RESTRICTION_MAX; ++i )
  1487. {
  1488. KeyValues *pTeam = new KeyValues( CFmtStr( "%d", i ) );
  1489. pTeam->SetString( "english_name", s_pszTeamRestrictionNames[ i ] );
  1490. pTeamReq->AddSubKey( pTeam );
  1491. }
  1492. pRequiredKeys->AddSubKey( pTeamReq );
  1493. }
  1494. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1495. {
  1496. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  1497. pOutputKeys->SetInt( "team_requirement", m_eTeamRestriction );
  1498. pOutputKeys->SetString( "team_key", m_pszTeamKey );
  1499. }
  1500. private:
  1501. ETeamRestriction m_eTeamRestriction;
  1502. const char* m_pszTeamKey;
  1503. };
  1504. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestTeamRestriction, team_restriction, FIELD_TEAM );
  1505. //-----------------------------------------------------------------------------
  1506. // Purpose: quest map restriction
  1507. //-----------------------------------------------------------------------------
  1508. class CTFQuestMapRestriction : public CTFQuestRestriction
  1509. {
  1510. public:
  1511. DECLARE_CLASS( CTFQuestMapRestriction, CTFQuestRestriction )
  1512. CTFQuestMapRestriction()
  1513. : m_pszMapName( NULL )
  1514. {
  1515. }
  1516. virtual const char *GetValueString() const OVERRIDE
  1517. {
  1518. return m_pszMapName;
  1519. }
  1520. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1521. {
  1522. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1523. return false;
  1524. m_pszMapName = pKVItem->GetString( "value", NULL );
  1525. SCHEMA_INIT_CHECK( m_pszMapName != NULL, "Missing map name." );
  1526. // TODO: validate map name against some white list here
  1527. return true;
  1528. }
  1529. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1530. {
  1531. return IsValidMap();
  1532. }
  1533. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1534. {
  1535. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  1536. if ( !IsValidMap() )
  1537. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_WRONG_MAP );
  1538. return true;
  1539. }
  1540. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1541. {
  1542. //const CUtlVector<SchemaMap_t>& maps = GetItemSchema()->GetMaps();
  1543. KeyValues *pMapKey = new KeyValues( "value" );
  1544. pMapKey->SetString( "control_type", "text_entry" );
  1545. /*for ( int i=0; i<maps.Count(); ++i )
  1546. {
  1547. const char *pszMapName = maps[i].pszMapName;
  1548. pMapKey->AddSubKey( new KeyValues( pszMapName ) );
  1549. }*/
  1550. pRequiredKeys->AddSubKey( pMapKey );
  1551. }
  1552. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1553. {
  1554. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  1555. pOutputKeys->SetString( "value", GetValueString() );
  1556. }
  1557. private:
  1558. bool IsValidMap() const
  1559. {
  1560. #ifdef CLIENT_DLL
  1561. const char *pszMapName = TFGameRules()->MapName();
  1562. #else
  1563. const char *pszMapName = gpGlobals->mapname.ToCStr();
  1564. #endif
  1565. return !V_stricmp( m_pszMapName, pszMapName );
  1566. }
  1567. const char *m_pszMapName;
  1568. };
  1569. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestMapRestriction, map, FIELD_NONE );
  1570. //-----------------------------------------------------------------------------
  1571. // Purpose: quest game type restriction
  1572. //-----------------------------------------------------------------------------
  1573. class CTFQuestGameTypeRestriction : public CTFQuestRestriction
  1574. {
  1575. public:
  1576. DECLARE_CLASS( CTFQuestGameTypeRestriction, CTFQuestRestriction )
  1577. CTFQuestGameTypeRestriction()
  1578. : m_eGameType( (ETFGameType)0 )
  1579. {}
  1580. virtual const char *GetValueString() const OVERRIDE
  1581. {
  1582. return GetEnumGameTypeName( m_eGameType );
  1583. }
  1584. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1585. {
  1586. if ( !CTFQuestRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1587. return false;
  1588. const char *pszVal = pKVItem->GetString( "value", NULL );
  1589. SCHEMA_INIT_CHECK( pszVal != NULL, "Missing game_type name." );
  1590. m_eGameType = GetGameTypeFromName( pszVal );
  1591. SCHEMA_INIT_CHECK( m_eGameType != TF_GAMETYPE_UNDEFINED, "Invalid game_type name." );
  1592. return true;
  1593. }
  1594. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1595. {
  1596. return TFGameRules()->GetGameType() == m_eGameType;
  1597. }
  1598. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1599. {
  1600. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  1601. if ( TFGameRules()->GetGameType() != m_eGameType )
  1602. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_WRONG_GAME_MODE );
  1603. return false;
  1604. }
  1605. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1606. {
  1607. CTFQuestRestriction::GetRequiredParamKeys( pRequiredKeys );
  1608. KeyValues *pGameType = new KeyValues( "value" );
  1609. for ( int i=0; i<TF_GAMETYPE_COUNT; ++i )
  1610. {
  1611. const char *pszGameType = GetEnumGameTypeName( ETFGameType( i ) );
  1612. pGameType->AddSubKey( new KeyValues( pszGameType ) );
  1613. }
  1614. pRequiredKeys->AddSubKey( pGameType );
  1615. }
  1616. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1617. {
  1618. CTFQuestRestriction::GetOutputKeyValues( pOutputKeys );
  1619. pOutputKeys->SetString( "value", GetValueString() );
  1620. }
  1621. private:
  1622. ETFGameType m_eGameType;
  1623. };
  1624. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestGameTypeRestriction, game_type, FIELD_NONE );
  1625. static const char *s_loadout_position_names[] =
  1626. {
  1627. // Weapons & Equipment
  1628. "LOADOUT_POSITION_PRIMARY",
  1629. "LOADOUT_POSITION_SECONDARY",
  1630. "LOADOUT_POSITION_MELEE",
  1631. "LOADOUT_POSITION_UTILITY",
  1632. "LOADOUT_POSITION_BUILDING",
  1633. "LOADOUT_POSITION_PDA",
  1634. "LOADOUT_POSITION_PDA2",
  1635. // Wearables. If you add new wearable slots, make sure you add them to IsWearableSlot() below this.
  1636. "LOADOUT_POSITION_HEAD",
  1637. "LOADOUT_POSITION_MISC",
  1638. // other
  1639. "LOADOUT_POSITION_ACTION",
  1640. // More wearables, yay!
  1641. "LOADOUT_POSITION_MISC2",
  1642. // taunts
  1643. "LOADOUT_POSITION_TAUNT",
  1644. "LOADOUT_POSITION_TAUNT2",
  1645. "LOADOUT_POSITION_TAUNT3",
  1646. "LOADOUT_POSITION_TAUNT4",
  1647. "LOADOUT_POSITION_TAUNT5",
  1648. "LOADOUT_POSITION_TAUNT6",
  1649. "LOADOUT_POSITION_TAUNT7",
  1650. "LOADOUT_POSITION_TAUNT8",
  1651. #ifdef STAGING_ONLY
  1652. // Extra PDA mod slots
  1653. "LOADOUT_POSITION_PDA_ADDON1",
  1654. "LOADOUT_POSITION_PDA_ADDON2",
  1655. "LOADOUT_POSITION_PDA3",
  1656. //LOADOUT_POSITION_MISC3,
  1657. //LOADOUT_POSITION_MISC4,
  1658. //LOADOUT_POSITION_MISC5,
  1659. //LOADOUT_POSITION_MISC6,
  1660. //LOADOUT_POSITION_MISC7,
  1661. //LOADOUT_POSITION_MISC8,
  1662. //LOADOUT_POSITION_MISC9,
  1663. //LOADOUT_POSITION_MISC10,
  1664. "LOADOUT_POSITION_BUILDING2",
  1665. #endif // STAGING_ONLY
  1666. };
  1667. COMPILE_TIME_ASSERT( ARRAYSIZE( s_loadout_position_names ) == CLASS_LOADOUT_POSITION_COUNT );
  1668. //-----------------------------------------------------------------------------
  1669. // Purpose: quest loadout position restriction
  1670. //-----------------------------------------------------------------------------
  1671. class CTFQuestLoadoutPositionRestriction : public CTFQuestBasePlayerRestriction
  1672. {
  1673. public:
  1674. DECLARE_CLASS( CTFQuestLoadoutPositionRestriction, CTFQuestRestriction )
  1675. CTFQuestLoadoutPositionRestriction()
  1676. : m_eLoadoutPosition( LOADOUT_POSITION_INVALID )
  1677. , m_pszLoadoutKey( NULL )
  1678. {}
  1679. virtual const char *GetValueString() const OVERRIDE
  1680. {
  1681. if ( m_eLoadoutPosition == LOADOUT_POSITION_INVALID )
  1682. {
  1683. return "LOADOUT_POSITION_INVALID";
  1684. }
  1685. return s_loadout_position_names[ m_eLoadoutPosition ];
  1686. }
  1687. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1688. {
  1689. if ( !CTFQuestBasePlayerRestriction::BInitFromKV( pKVItem, pVecErrors ) )
  1690. return false;
  1691. const char *pszVal = pKVItem->GetString( "value", NULL );
  1692. SCHEMA_INIT_CHECK( pszVal != NULL, "Missing loadout_position name." );
  1693. m_eLoadoutPosition = GetLoadoutPositionByName( pszVal );
  1694. SCHEMA_INIT_CHECK( m_eLoadoutPosition != LOADOUT_POSITION_INVALID, "Invalid loadout_position name." );
  1695. m_pszPlayerKey = pKVItem->GetString( "player_key", NULL );
  1696. SCHEMA_INIT_CHECK( m_pszPlayerKey != NULL, "Missing \"player_key\" in loadout_position" );
  1697. m_pszLoadoutKey = pKVItem->GetString( "loadout_key", NULL );
  1698. SCHEMA_INIT_CHECK( m_pszLoadoutKey != NULL, "Missing \"loadout_key\" in loadout_position" );
  1699. return true;
  1700. }
  1701. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1702. {
  1703. CTFQuestBasePlayerRestriction::GetRequiredParamKeys( pRequiredKeys );
  1704. GetValidParamsKeyFromEvent( "loadout_key", GetConditionName(), m_pszEventName, pRequiredKeys );
  1705. KeyValues *pLoadoutPositions = new KeyValues( "value" );
  1706. int iLoadoutPositionCount = ARRAYSIZE( s_loadout_position_names );
  1707. for ( int i=0; i<iLoadoutPositionCount; ++i )
  1708. {
  1709. const char *pszLoadoutPosition = s_loadout_position_names[i];
  1710. pLoadoutPositions->AddSubKey( new KeyValues( pszLoadoutPosition ) );
  1711. }
  1712. pRequiredKeys->AddSubKey( pLoadoutPositions );
  1713. }
  1714. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1715. {
  1716. CTFQuestBasePlayerRestriction::GetOutputKeyValues( pOutputKeys );
  1717. pOutputKeys->SetString( "value", GetValueString() );
  1718. pOutputKeys->SetString( "loadout_key", m_pszLoadoutKey );
  1719. }
  1720. private:
  1721. loadout_positions_t GetLoadoutPositionByName( const char *pszLoadoutPositionName )
  1722. {
  1723. int iLoadoutPositionCount = ARRAYSIZE( s_loadout_position_names );
  1724. for ( int i=0; i<iLoadoutPositionCount; ++i )
  1725. {
  1726. if ( FStrEq( pszLoadoutPositionName, s_loadout_position_names[i] ) )
  1727. {
  1728. return loadout_positions_t(i);
  1729. }
  1730. }
  1731. return LOADOUT_POSITION_INVALID;
  1732. }
  1733. virtual bool BPlayerCheck( const CTFPlayer* pPlayer, IGameEvent *pEvent ) const OVERRIDE
  1734. {
  1735. int iClass = pPlayer->GetPlayerClass()->GetClassIndex();
  1736. item_definition_index_t iItemDef = pEvent->GetInt( m_pszLoadoutKey, INVALID_ITEM_DEF_INDEX );
  1737. if ( iItemDef != INVALID_ITEM_DEF_INDEX )
  1738. {
  1739. GameItemDefinition_t *pDef = ItemSystem()->GetStaticDataForItemByDefIndex( iItemDef );
  1740. Assert( pDef );
  1741. if ( pDef )
  1742. {
  1743. return pDef->GetLoadoutSlot( iClass ) == m_eLoadoutPosition;
  1744. }
  1745. }
  1746. return false;
  1747. }
  1748. loadout_positions_t m_eLoadoutPosition;
  1749. const char* m_pszLoadoutKey;
  1750. };
  1751. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFQuestLoadoutPositionRestriction, loadout_position, FIELD_PLAYER | FIELD_LOADOUT_POSITION );
  1752. //-----------------------------------------------------------------------------
  1753. // Purpose: quest player condition restriction
  1754. //-----------------------------------------------------------------------------
  1755. class CTFConditionQuestCondition : public CTFQuestRestriction
  1756. {
  1757. public:
  1758. CTFConditionQuestCondition()
  1759. : m_pszKeyName( NULL )
  1760. {}
  1761. virtual const char *GetValueString() const OVERRIDE
  1762. {
  1763. return GetTFConditionName( m_eCondition );
  1764. }
  1765. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1766. {
  1767. const char *pszKeyName = pKVItem->GetString( "condition_key", NULL );
  1768. SCHEMA_INIT_CHECK( pszKeyName != NULL, "Missing key_to_lookup in condition" );
  1769. const char *pszConditionName = pKVItem->GetString( "value" );
  1770. m_eCondition = GetTFConditionFromName( pszConditionName );
  1771. SCHEMA_INIT_CHECK( m_eCondition != TF_COND_INVALID, "%s", CFmtStr( "Invalid %s restriction '%s' for quest objective", GetConditionName(), pszConditionName ).Get() );
  1772. return true;
  1773. }
  1774. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1775. {
  1776. KeyValues *pConditionsKey = new KeyValues( "value" );
  1777. for ( int i=0; i<TF_COND_LAST; ++i )
  1778. {
  1779. const char *pszConditionName = GetTFConditionName( ETFCond( i ) );
  1780. pConditionsKey->AddSubKey( new KeyValues( pszConditionName ) );
  1781. }
  1782. GetValidParamsKeyFromEvent( "condition_key", GetConditionName(), m_pszEventName, pRequiredKeys );
  1783. pRequiredKeys->AddSubKey( pConditionsKey );
  1784. }
  1785. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1786. {
  1787. pOutputKeys->SetString( "value", GetValueString() );
  1788. pOutputKeys->SetString( "condition_key", m_pszKeyName );
  1789. }
  1790. private:
  1791. virtual bool PassesRestrictions( IGameEvent *pEvent ) const OVERRIDE
  1792. {
  1793. return pEvent->GetInt( m_pszKeyName ) == m_eCondition;
  1794. }
  1795. ETFCond m_eCondition;
  1796. const char *m_pszKeyName;
  1797. };
  1798. REGISTER_QUEST_CONDITION_SUB_CLASS( CTFConditionQuestCondition, condition, FIELD_CONDITION );
  1799. CTFQuestRestriction *CreateRestrictionByName( const char *pszName, CTFQuestCondition* pParent )
  1800. {
  1801. CTFQuestRestriction *pNewRestriction = NULL;
  1802. auto idx = k_mapConditions.Find( pszName );
  1803. if ( idx != k_mapConditions.InvalidIndex() )
  1804. {
  1805. pNewRestriction = static_cast<CTFQuestRestriction*>( k_mapConditions[ idx ]->m_pfnQuestCreate() );
  1806. pNewRestriction->SetFieldName( k_mapConditions[ idx ]->m_pszFieldName );
  1807. pNewRestriction->SetTypeName( k_mapConditions.Key( idx ) );
  1808. }
  1809. if ( pNewRestriction )
  1810. {
  1811. pNewRestriction->SetParent( pParent );
  1812. const char *pszEventName = pParent->GetEventName();
  1813. // in the case that parent has no event name (new node from editor)
  1814. // default the event name to the first valid event from the global event list
  1815. if ( !pszEventName )
  1816. {
  1817. KeyValues *pQuestEvents = GetQuestEventsKeyValues();
  1818. if ( pQuestEvents )
  1819. {
  1820. const KeyValues *pFirstKey = pQuestEvents->GetFirstTrueSubKey();
  1821. if ( pFirstKey )
  1822. {
  1823. pszEventName = pFirstKey->GetName();
  1824. }
  1825. }
  1826. }
  1827. pNewRestriction->SetEventName( pszEventName );
  1828. }
  1829. AssertMsg( pNewRestriction, "Invalid quest restriction type '%s'", pszName );
  1830. return pNewRestriction;
  1831. }
  1832. //-----------------------------------------------------------------------------
  1833. // Purpose: quest event
  1834. //-----------------------------------------------------------------------------
  1835. class CTFQuestEventListener : public CTFQuestEvaluator, public CGameEventListener
  1836. {
  1837. public:
  1838. DECLARE_CLASS( CTFQuestEventListener, CTFQuestEvaluator )
  1839. CTFQuestEventListener()
  1840. {
  1841. m_pRestrictions = NULL;
  1842. m_pszEventName = NULL;
  1843. m_pszOverrideScoreKeyName = NULL;
  1844. }
  1845. virtual ~CTFQuestEventListener()
  1846. {
  1847. if ( m_pRestrictions )
  1848. {
  1849. delete m_pRestrictions;
  1850. }
  1851. }
  1852. virtual const char *GetConditionName() const OVERRIDE { return "event_listener"; }
  1853. virtual const char *GetValueString() const OVERRIDE { return m_pszEventName; }
  1854. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  1855. {
  1856. if ( !CTFQuestEvaluator::BInitFromKV( pKVItem, pVecErrors ) )
  1857. return false;
  1858. m_pszEventName = pKVItem->GetString( "event_name", NULL );
  1859. SCHEMA_INIT_CHECK( m_pszEventName != NULL, "%s", CFmtStr( "Invalid %s condition. Missing 'event_name'", GetConditionName() ).Get() );
  1860. #ifdef GAME_DLL // Only the server needs to listen for events
  1861. ListenForGameEvent( m_pszEventName );
  1862. #endif
  1863. m_pszOverrideScoreKeyName = pKVItem->GetString( "score_key_name", "none" );
  1864. SCHEMA_INIT_CHECK( m_pszOverrideScoreKeyName != NULL, "Missing score_key_name" );
  1865. FOR_EACH_TRUE_SUBKEY( pKVItem, pSubKey )
  1866. {
  1867. SCHEMA_INIT_CHECK( !m_pRestrictions, "%s", CFmtStr( "Too many input for operator '%s'.", GetConditionName() ).Get() );
  1868. const char *pszType = pSubKey->GetString( "type" );
  1869. m_pRestrictions = CreateRestrictionByName( pszType, this );
  1870. SCHEMA_INIT_CHECK( m_pRestrictions != NULL, "%s", CFmtStr( "Failed to create quest restriction name '%s' for '%s'", pszType, GetConditionName() ).Get() );
  1871. SCHEMA_INIT_CHECK( m_pRestrictions->BInitFromKV( pSubKey, pVecErrors ), "Failed to init from KeyValues" );
  1872. }
  1873. return true;
  1874. }
  1875. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  1876. {
  1877. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  1878. int nNumFound = 0;
  1879. for ( int i = 1; i <= gpGlobals->maxClients && nNumFound < s_nMinConnectedPlayersForQuestProgress; ++i )
  1880. {
  1881. #ifdef CLIENT_DLL
  1882. IGameResources *gr = GameResources();
  1883. if ( !gr || !gr->IsConnected( i ) )
  1884. continue;
  1885. #else
  1886. CBasePlayer* pPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );
  1887. if ( !pPlayer )
  1888. continue;
  1889. #endif
  1890. ++nNumFound;
  1891. }
  1892. if ( nNumFound < s_nMinConnectedPlayersForQuestProgress )
  1893. invalidReasons.m_bits.Set( INVALID_QUEST_REASON_NOT_ENOUGH_PLAYERS );
  1894. if ( m_pRestrictions )
  1895. {
  1896. m_pRestrictions->IsValidForPlayer( pOwner, invalidReasons );
  1897. }
  1898. return true;
  1899. }
  1900. virtual void FireGameEvent( IGameEvent *pEvent ) OVERRIDE
  1901. {
  1902. // This can happen when the player's SteamID isn't setup yet after a
  1903. // disconnect -> reconnect
  1904. if ( GetQuestOwner() == NULL )
  1905. return;
  1906. InvalidReasonsContainer_t invalidReasons;
  1907. IsValidForPlayer( GetQuestOwner(), invalidReasons );
  1908. if ( !invalidReasons.m_bits.IsAllClear() )
  1909. return;
  1910. const char *pszEventName = pEvent->GetName();
  1911. if ( FStrEq( m_pszEventName, pszEventName ) )
  1912. {
  1913. if ( !m_pRestrictions || m_pRestrictions->PassesRestrictions( pEvent ) )
  1914. {
  1915. int nScoreOverride = m_pszOverrideScoreKeyName ? pEvent->GetInt( m_pszOverrideScoreKeyName, 1 ) : 1;
  1916. EvaluateCondition( this, nScoreOverride );
  1917. }
  1918. }
  1919. }
  1920. virtual void EvaluateCondition( CTFQuestEvaluator *pSender, int nScore ) OVERRIDE
  1921. {
  1922. Assert( GetParent() && GetParent()->IsEvaluator() );
  1923. assert_cast< CTFQuestEvaluator* >( GetParent() )->EvaluateCondition( pSender, nScore ) ;
  1924. }
  1925. virtual void ResetCondition() OVERRIDE
  1926. {
  1927. // DO NOTHING
  1928. }
  1929. CTFQuestCondition* AddChildByName( const char *pszChildName ) OVERRIDE
  1930. {
  1931. if ( m_pRestrictions )
  1932. {
  1933. Assert( m_pRestrictions == NULL );
  1934. return NULL;
  1935. }
  1936. m_pRestrictions = CreateRestrictionByName( pszChildName, this );
  1937. Assert( m_pRestrictions );
  1938. return m_pRestrictions;
  1939. }
  1940. virtual int GetChildren( CUtlVector< CTFQuestCondition* >& vecChildren ) OVERRIDE
  1941. {
  1942. if ( m_pRestrictions )
  1943. {
  1944. vecChildren.AddToTail( m_pRestrictions );
  1945. return vecChildren.Count();
  1946. }
  1947. return 0;
  1948. }
  1949. bool RemoveAndDeleteChild( CTFQuestCondition *pChild ) OVERRIDE
  1950. {
  1951. bool bRemoved = m_pRestrictions == pChild;
  1952. Assert( bRemoved );
  1953. if ( bRemoved )
  1954. {
  1955. delete m_pRestrictions;
  1956. m_pRestrictions = NULL;
  1957. }
  1958. return bRemoved;
  1959. }
  1960. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  1961. {
  1962. CTFQuestEvaluator::GetRequiredParamKeys( pRequiredKeys );
  1963. KeyValues *pQuestEvents = GetQuestEventsKeyValues();
  1964. if ( pQuestEvents )
  1965. {
  1966. KeyValues *pScoreKeys = new KeyValues( "score_key_name" );
  1967. KeyValues *pEventsKey = new KeyValues( "event_name" );
  1968. FOR_EACH_TRUE_SUBKEY( pQuestEvents, pSubKey )
  1969. {
  1970. const char *pszEventName = pSubKey->GetName();
  1971. pEventsKey->AddSubKey( new KeyValues( pszEventName ) );
  1972. if ( m_pszEventName && FStrEq( pszEventName, m_pszEventName ) )
  1973. {
  1974. KeyValues* pScoreSubKeys = pSubKey->FindKey( "score_keys" );
  1975. if ( pScoreSubKeys )
  1976. {
  1977. FOR_EACH_TRUE_SUBKEY( pScoreSubKeys, pScore )
  1978. {
  1979. pScoreKeys->AddSubKey( new KeyValues( pScore->GetName() ) );
  1980. }
  1981. }
  1982. }
  1983. }
  1984. pRequiredKeys->AddSubKey( pEventsKey );
  1985. if ( pScoreKeys->GetFirstTrueSubKey() )
  1986. {
  1987. pScoreKeys->AddSubKey( new KeyValues( "none" ) );
  1988. pRequiredKeys->AddSubKey( pScoreKeys );
  1989. }
  1990. }
  1991. }
  1992. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  1993. {
  1994. CTFQuestEvaluator::GetOutputKeyValues( pOutputKeys );
  1995. pOutputKeys->SetString( "event_name", GetValueString() );
  1996. pOutputKeys->SetString( "score_key_name", m_pszOverrideScoreKeyName );
  1997. }
  1998. virtual const char* GetEventName() const OVERRIDE
  1999. {
  2000. return m_pszEventName;
  2001. }
  2002. virtual void SetEventName( const char *pszEventName ) OVERRIDE
  2003. {
  2004. m_pszEventName = pszEventName;
  2005. }
  2006. virtual int GetMaxInputCount() const { return 1; }
  2007. protected:
  2008. const char *m_pszEventName;
  2009. const char *m_pszOverrideScoreKeyName;
  2010. CTFQuestRestriction *m_pRestrictions;
  2011. };
  2012. //-----------------------------------------------------------------------------
  2013. // Purpose: count evaluator
  2014. //-----------------------------------------------------------------------------
  2015. class CTFQuestCountEvaluator : public CTFQuestEvaluator
  2016. {
  2017. public:
  2018. DECLARE_CLASS( CTFQuestCountEvaluator, CTFQuestEvaluator )
  2019. virtual ~CTFQuestCountEvaluator()
  2020. {
  2021. m_vecChildren.PurgeAndDeleteElements();
  2022. }
  2023. virtual const char *GetConditionName() const OVERRIDE { return "counter"; }
  2024. virtual bool BInitFromKV( KeyValues *pKVItem, CUtlVector<CUtlString> *pVecErrors /* = NULL */ ) OVERRIDE
  2025. {
  2026. if ( !CTFQuestEvaluator::BInitFromKV( pKVItem, pVecErrors ) )
  2027. return false;
  2028. m_nStart = m_nCount = pKVItem->GetInt( "start" );
  2029. m_nEnd = pKVItem->GetInt( "end" );
  2030. FOR_EACH_TRUE_SUBKEY( pKVItem, pSubKey )
  2031. {
  2032. const char *pszType = pSubKey->GetString( "type" );
  2033. CTFQuestEvaluator *pNewCond = assert_cast< CTFQuestEvaluator* >( CreateEvaluatorByName( pszType, this ) );
  2034. SCHEMA_INIT_CHECK( pNewCond && pNewCond->BInitFromKV( pSubKey, pVecErrors ), "Failed to init from KeyValues" );
  2035. const char *pszAction = pSubKey->GetString( "action", NULL );
  2036. SCHEMA_INIT_CHECK( pszAction != NULL, "Missing action key" );
  2037. pNewCond->SetAction( pszAction );
  2038. m_vecChildren.AddToTail( pNewCond );
  2039. }
  2040. return true;
  2041. }
  2042. virtual bool IsValidForPlayer( const CTFPlayer *pOwner, InvalidReasonsContainer_t& invalidReasons ) const
  2043. {
  2044. BaseClass::IsValidForPlayer( pOwner, invalidReasons );
  2045. bool bIsForLocalPlayer = false;
  2046. FOR_EACH_VEC( m_vecChildren, i )
  2047. {
  2048. bIsForLocalPlayer |= m_vecChildren[i]->IsValidForPlayer( pOwner, invalidReasons );
  2049. }
  2050. return bIsForLocalPlayer;
  2051. }
  2052. virtual void EvaluateCondition( CTFQuestEvaluator *pSender, int nScore ) OVERRIDE
  2053. {
  2054. const char *pszAction = pSender->GetAction();
  2055. if ( FStrEq( pszAction, "increment" ) )
  2056. {
  2057. m_nCount += nScore;
  2058. }
  2059. else if ( FStrEq( pszAction, "decrement" ) )
  2060. {
  2061. m_nCount -= nScore;
  2062. // Don't dip below 0!
  2063. m_nCount = Max( 0, m_nCount );
  2064. }
  2065. else if ( FStrEq( pszAction, "reset" ) )
  2066. {
  2067. m_nCount = 0;
  2068. }
  2069. else
  2070. {
  2071. AssertMsg( 0, "Invalid evaluation condition '%s' for '%s'", pSender->GetConditionName(), GetConditionName() );
  2072. }
  2073. // Check how many time over we've scored
  2074. int nNumScored = m_nCount / m_nEnd;
  2075. // Store the remainded
  2076. m_nCount -= ( nNumScored * m_nEnd );
  2077. if ( nNumScored > 0 )
  2078. {
  2079. Assert( GetParent() && GetParent()->IsEvaluator() );
  2080. assert_cast< CTFQuestEvaluator* >( GetParent() )->EvaluateCondition( this, nNumScored ) ;
  2081. }
  2082. }
  2083. virtual void ResetCondition() OVERRIDE
  2084. {
  2085. m_nCount = 0;
  2086. FOR_EACH_VEC( m_vecChildren, i )
  2087. {
  2088. m_vecChildren[i]->ResetCondition();
  2089. }
  2090. }
  2091. enum ECounterSubType
  2092. {
  2093. COUNTER_INCREMENT = 0,
  2094. COUNTER_DECREMENT,
  2095. COUNTER_RESET,
  2096. COUNTER_TYPE_COUNT
  2097. };
  2098. virtual int GetChildrenSubTypeCount() const { return COUNTER_TYPE_COUNT; }
  2099. virtual int GetChildren( CUtlVector< CTFQuestCondition* >& vecChildren ) OVERRIDE
  2100. {
  2101. for ( int i=0; i<m_vecChildren.Count(); ++i )
  2102. {
  2103. vecChildren.AddToTail( m_vecChildren[i] );
  2104. }
  2105. return vecChildren.Count();
  2106. }
  2107. bool RemoveAndDeleteChild( CTFQuestCondition *pChild ) OVERRIDE
  2108. {
  2109. CTFQuestEvaluator *pEvaluatorChild = assert_cast< CTFQuestEvaluator* >( pChild );
  2110. bool bRemoved = m_vecChildren.FindAndFastRemove( pEvaluatorChild );
  2111. Assert( bRemoved );
  2112. if ( bRemoved )
  2113. {
  2114. delete pChild;
  2115. }
  2116. return bRemoved;
  2117. }
  2118. CTFQuestCondition* AddChildByName( const char *pszChildName ) OVERRIDE
  2119. {
  2120. CTFQuestEvaluator *pNewEvaluator = CreateEvaluatorByName( pszChildName, this );
  2121. if ( pNewEvaluator )
  2122. {
  2123. m_vecChildren.AddToTail( pNewEvaluator );
  2124. }
  2125. return pNewEvaluator;
  2126. }
  2127. virtual int GetMaxInputCount() const { return s_nMaxInputCount; }
  2128. virtual void GetRequiredParamKeys( KeyValues *pRequiredKeys ) OVERRIDE
  2129. {
  2130. CTFQuestEvaluator::GetRequiredParamKeys( pRequiredKeys );
  2131. KeyValues* pKVCounts = pRequiredKeys->CreateNewKey();
  2132. pKVCounts->SetName( "end" );
  2133. pKVCounts->SetString( "control_type", "text_entry" );
  2134. }
  2135. virtual void GetOutputKeyValues( KeyValues *pOutputKeys ) OVERRIDE
  2136. {
  2137. CTFQuestEvaluator::GetOutputKeyValues( pOutputKeys );
  2138. pOutputKeys->SetInt( "end", m_nEnd );
  2139. }
  2140. virtual void GetValidChildren( CUtlVector< const char* >& vecOutValidChildren ) const OVERRIDE
  2141. {
  2142. vecOutValidChildren.AddToTail( "event_listener" );
  2143. vecOutValidChildren.AddToTail( "counter" );
  2144. }
  2145. private:
  2146. CUtlVector< CTFQuestEvaluator* > m_vecChildren;
  2147. int m_nCount;
  2148. int m_nStart;
  2149. int m_nEnd;
  2150. };
  2151. void CTFQuestEvaluator::GetRequiredParamKeys( KeyValues *pRequiredKeys )
  2152. {
  2153. if ( GetParent() && dynamic_cast< CTFQuestCountEvaluator* >( GetParent() ) )
  2154. {
  2155. KeyValues *pActionsKey = new KeyValues( "action" );
  2156. pActionsKey->AddSubKey( new KeyValues( "increment" ) );
  2157. pActionsKey->AddSubKey( new KeyValues( "decrement" ) );
  2158. pActionsKey->AddSubKey( new KeyValues( "reset" ) );
  2159. pRequiredKeys->AddSubKey( pActionsKey );
  2160. }
  2161. }
  2162. CTFQuestEvaluator *CreateEvaluatorByName( const char *pszName, CTFQuestCondition* pParent )
  2163. {
  2164. CTFQuestEvaluator *pNewEvaluator = NULL;
  2165. if ( FStrEq( pszName, "event_listener" ) )
  2166. {
  2167. pNewEvaluator = new CTFQuestEventListener;
  2168. }
  2169. else if ( FStrEq( pszName, "counter" ) )
  2170. {
  2171. pNewEvaluator = new CTFQuestCountEvaluator;
  2172. }
  2173. if ( pNewEvaluator )
  2174. {
  2175. pNewEvaluator->SetParent( pParent );
  2176. }
  2177. AssertMsg( pNewEvaluator, "Invalid quest evaluator type '%s'", pszName );
  2178. return pNewEvaluator;
  2179. }