Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

544 lines
17 KiB

  1. //====== Copyright �, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose: CItemSelectionCriteria, which serves as a criteria for selection
  4. // of a econ item
  5. //
  6. //=============================================================================
  7. #include "cbase.h"
  8. #include "item_selection_criteria.h"
  9. #include "game_item_schema.h" // TODO: Fix circular dependency
  10. #if defined(TF_CLIENT_DLL) || defined(TF_DLL)
  11. #include "tf_gcmessages.h"
  12. #endif
  13. // memdbgon must be the last include file in a .cpp file!!!
  14. #include "tier0/memdbgon.h"
  15. // copied from \common\econ_item_view.h
  16. #define AE_USE_SCRIPT_VALUE 9999 // Can't be -1, due to unsigned ints used on the backend
  17. using namespace GCSDK;
  18. //-----------------------------------------------------------------------------
  19. // Purpose: Copy Constructor
  20. //-----------------------------------------------------------------------------
  21. CItemSelectionCriteria::CItemSelectionCriteria( const CItemSelectionCriteria &that )
  22. {
  23. (*this) = that;
  24. }
  25. struct EmptyStruct_t
  26. {
  27. };
  28. //-----------------------------------------------------------------------------
  29. // Purpose: Operator=
  30. //-----------------------------------------------------------------------------
  31. CItemSelectionCriteria &CItemSelectionCriteria::operator=( const CItemSelectionCriteria &rhs )
  32. {
  33. // Leverage the serialization code we already have for the copy
  34. CSOItemCriteria msgTemp;
  35. rhs.BSerializeToMsg( msgTemp );
  36. BDeserializeFromMsg( msgTemp );
  37. return *this;
  38. }
  39. //-----------------------------------------------------------------------------
  40. // Purpose: Destructor
  41. //-----------------------------------------------------------------------------
  42. CItemSelectionCriteria::~CItemSelectionCriteria( void )
  43. {
  44. m_vecConditions.PurgeAndDeleteElements();
  45. }
  46. const char *CItemSelectionCriteria::GetValueForFirstConditionOfFieldName( const char *pchName ) const
  47. {
  48. FOR_EACH_VEC( m_vecConditions, i )
  49. {
  50. if ( V_strcmp( m_vecConditions[i]->GetField(), pchName ) == 0 )
  51. return m_vecConditions[i]->GetValue();
  52. }
  53. return NULL;
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose: Initialize from a KV structure
  57. //-----------------------------------------------------------------------------
  58. bool CItemSelectionCriteria::BInitFromKV( KeyValues *pKVCriteria, const CEconItemSchema &pschema )
  59. {
  60. // Read in the base fields
  61. if ( pKVCriteria->FindKey( "level" ) )
  62. {
  63. SetItemLevel( pKVCriteria->GetInt( "level" ) );
  64. }
  65. if ( pKVCriteria->FindKey( "quality" ) )
  66. {
  67. uint8 nQuality;
  68. if ( !pschema.BGetItemQualityFromName( pKVCriteria->GetString( "quality" ), &nQuality ) )
  69. return false;
  70. SetQuality( nQuality );
  71. }
  72. if ( pKVCriteria->FindKey( "rarity" ) )
  73. {
  74. uint8 nRarity;
  75. if ( !pschema.BGetItemRarityFromName( pKVCriteria->GetString( "rarity" ), &nRarity ) )
  76. return false;
  77. SetRarity( nRarity );
  78. }
  79. if ( pKVCriteria->FindKey( "inventoryPos" ) )
  80. {
  81. SetInitialInventory( pKVCriteria->GetInt( "inventoryPos" ) );
  82. }
  83. if ( pKVCriteria->FindKey( "quantity" ) )
  84. {
  85. SetInitialQuantity( pKVCriteria->GetInt( "quantity" ) );
  86. }
  87. if ( pKVCriteria->FindKey( "ignore_enabled" ) )
  88. {
  89. SetIgnoreEnabledFlag( pKVCriteria->GetBool( "ignore_enabled" ) );
  90. }
  91. if ( pKVCriteria->FindKey( "recent_only" ) )
  92. {
  93. SetRecentOnly( pKVCriteria->GetBool( "recent_only" ) );
  94. }
  95. return true;
  96. }
  97. bool CItemSelectionCriteria::BInitFromItemAndPaint( int nItemDef, int nPaintID, const CEconItemSchema &schemaa )
  98. {
  99. /** Removed for partner depot **/
  100. return true;
  101. }
  102. //-----------------------------------------------------------------------------
  103. // Purpose: Adds a condition to the selection criteria
  104. // Input: pszField - Field to evaluate on
  105. // eOp - Operator to apply to the value of the field
  106. // flValue - The value to compare.
  107. // bRequired - When true, causes BEvauluate to fail if pszField doesn't
  108. // exist in the KV being checked.
  109. // Output: True if the condition was added, false otherwise
  110. //-----------------------------------------------------------------------------
  111. bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, float flValue, bool bRequired )
  112. {
  113. // Check for condition limit
  114. if ( UCHAR_MAX == GetConditionsCount() )
  115. {
  116. AssertMsg( false, "Too many conditions on a a CItemSelectionCriteria. Max: 255" );
  117. return false;
  118. }
  119. // Enforce maximum string lengths
  120. if ( Q_strlen( pszField ) >= k_cchCreateItemLen )
  121. return false;
  122. if ( V_strcmp( pszField, "*lootlist" ) == 0 )
  123. {
  124. m_bIsLootList = true;
  125. }
  126. // Create the appropriate condition for the operator
  127. switch ( eOp )
  128. {
  129. case k_EOperator_Float_EQ:
  130. case k_EOperator_Float_Not_EQ:
  131. case k_EOperator_Float_LT:
  132. case k_EOperator_Float_Not_LT:
  133. case k_EOperator_Float_LTE:
  134. case k_EOperator_Float_Not_LTE:
  135. case k_EOperator_Float_GT:
  136. case k_EOperator_Float_Not_GT:
  137. case k_EOperator_Float_GTE:
  138. case k_EOperator_Float_Not_GTE:
  139. m_vecConditions.AddToTail( new CFloatCondition( pszField, eOp, flValue, bRequired ) );
  140. return true;
  141. default:
  142. AssertMsg1( false, "Bad operator (%d) passed to BAddCondition. Float based operator required for this overload.", eOp );
  143. return false;
  144. }
  145. }
  146. //-----------------------------------------------------------------------------
  147. // Purpose: Adds a condition to the selection criteria
  148. // Input: pszField - Field to evaluate on
  149. // eOp - Operator to apply to the value of the field
  150. // pszValue - The value to compare.
  151. // bRequired - When true, causes BEvauluate to fail if pszField doesn't
  152. // exist in the KV being checked.
  153. // Output: True if the condition was added, false otherwise
  154. //-----------------------------------------------------------------------------
  155. bool CItemSelectionCriteria::BAddCondition( const char *pszField, EItemCriteriaOperator eOp, const char * pszValue, bool bRequired )
  156. {
  157. // Check for condition limit
  158. if ( UCHAR_MAX == GetConditionsCount() )
  159. {
  160. AssertMsg( false, "Too many conditions on a a CItemSelectionCriteria. Max: 255" );
  161. return false;
  162. }
  163. // Enforce maximum string lengths
  164. if ( V_strlen( pszField ) >= k_cchCreateItemLen || Q_strlen( pszValue ) >= k_cchCreateItemLen )
  165. return false;
  166. if ( V_strcmp( pszField, "*lootlist" ) == 0 )
  167. {
  168. m_bIsLootList = true;
  169. }
  170. // Create the appropriate condition for the operator
  171. switch ( eOp )
  172. {
  173. case k_EOperator_String_EQ:
  174. case k_EOperator_String_Not_EQ:
  175. m_vecConditions.AddToTail( new CStringCondition( pszField, eOp, pszValue, bRequired ) );
  176. return true;
  177. case k_EOperator_Subkey_Contains:
  178. case k_EOperator_Subkey_Not_Contains:
  179. m_vecConditions.AddToTail( new CSetCondition( pszField, eOp, pszValue, bRequired ) );
  180. return true;
  181. default:
  182. // Try the float operators
  183. return BAddCondition( pszField, eOp, Q_atof( pszValue ), bRequired );
  184. }
  185. }
  186. //-----------------------------------------------------------------------------
  187. // Purpose: Checks if a given item matches the item selection criteria
  188. // Input: itemDef - The item definition to evaluate against
  189. // Output: True is the item passes the filter, false otherwise
  190. //-----------------------------------------------------------------------------
  191. bool CItemSelectionCriteria::BEvaluate( const CEconItemDefinition* pItemDef, const CEconItemSchema &pschema ) const
  192. {
  193. // Disabled items never match
  194. if ( !m_bIgnoreEnabledFlag && !pItemDef->BEnabled() )
  195. return false;
  196. if ( m_bRecentOnly && !pItemDef->IsRecent() )
  197. return false;
  198. // Filter against level
  199. if ( BItemLevelSet() && (GetItemLevel() != AE_USE_SCRIPT_VALUE) &&
  200. ( GetItemLevel() < pItemDef->GetMinLevel() || GetItemLevel() > pItemDef->GetMaxLevel() ) )
  201. return false;
  202. // Filter against quality
  203. if ( BQualitySet() && (GetQuality() != AE_USE_SCRIPT_VALUE) )
  204. {
  205. if ( GetQuality() != pItemDef->GetQuality() )
  206. {
  207. // Filter out item defs that have a non-any quality if we have a non-matching & non-any quality criteria
  208. if ( k_unItemQuality_Any != GetQuality() &&
  209. k_unItemQuality_Any != pItemDef->GetQuality() )
  210. return false;
  211. // Filter out item defs that don't have our exact quality if our quality criteria requires explicit matches
  212. const CEconItemQualityDefinition *pQuality = pschema.GetQualityDefinition( GetQuality() );
  213. if ( m_bForcedQualityMatch || ( pQuality && pQuality->GetRequiresExplicitMatches() ) )
  214. return false;
  215. }
  216. }
  217. // Filter against the additional conditions
  218. FOR_EACH_VEC( m_vecConditions, i )
  219. {
  220. // Skip over dynamic fields that require special logic from an econitem to process
  221. if ( m_vecConditions[i]->GetField()[ 0 ] == '*' )
  222. continue;
  223. if ( !m_vecConditions[i]->BEvaluate( pItemDef->GetRawDefinition() ) )
  224. return false;
  225. }
  226. return true;
  227. }
  228. bool CItemSelectionCriteria::BEvaluate( const CEconItem *pItem, const CEconItemSchema &pschema ) const
  229. {
  230. const CEconItemDefinition *pItemDef = pItem->GetItemDefinition();
  231. if ( !BEvaluate( pItemDef, pschema ) )
  232. return false;
  233. // Filter against the dynamic conditions
  234. FOR_EACH_VEC( m_vecConditions, i )
  235. {
  236. // Skip over dynamic fields that require special logic from an econitem to process
  237. const char *pchCondition = m_vecConditions[i]->GetField();
  238. if ( pchCondition[ 0 ] != '*' )
  239. continue;
  240. pchCondition++;
  241. if ( V_strcmp( pchCondition, "rarity" ) == 0 )
  242. {
  243. const CEconItemRarityDefinition *pRarity = pschema.GetRarityDefinitionByName( m_vecConditions[i]->GetValue() );
  244. Assert( pRarity );
  245. if ( m_vecConditions[i]->GetEOp() == k_EOperator_Not || m_vecConditions[i]->GetEOp() == k_EOperator_String_Not_EQ )
  246. {
  247. if ( pItem->GetRarity() == pRarity->GetDBValue() )
  248. return false;
  249. }
  250. else
  251. {
  252. if ( pItem->GetRarity() != pRarity->GetDBValue() )
  253. return false;
  254. }
  255. }
  256. else if ( V_strcmp( pchCondition, "quality" ) == 0 )
  257. {
  258. const CEconItemQualityDefinition *pQuality = pschema.GetQualityDefinitionByName( m_vecConditions[i]->GetValue() );
  259. Assert( pQuality );
  260. if ( m_vecConditions[i]->GetEOp() == k_EOperator_Not || m_vecConditions[i]->GetEOp() == k_EOperator_String_Not_EQ )
  261. {
  262. if ( pItem->GetQuality() == pQuality->GetDBValue() )
  263. return false;
  264. }
  265. else
  266. {
  267. if ( pItem->GetQuality() != pQuality->GetDBValue() )
  268. return false;
  269. }
  270. }
  271. else if ( V_strcmp( pchCondition, "itemdef" ) == 0 )
  272. {
  273. if ( pItemDef->GetDefinitionIndex() != V_atoi( m_vecConditions[i]->GetValue() ) )
  274. return false;
  275. }
  276. else if ( V_strcmp( pchCondition, "paintkit" ) == 0 )
  277. {
  278. if ( pItem->GetCustomPaintKitIndex() != V_atoi( m_vecConditions[i]->GetValue() ) )
  279. return false;
  280. }
  281. else if ( V_strcmp( pchCondition, "kill_eater_score_type" ) == 0 )
  282. {
  283. static const CSchemaAttributeDefHandle pAttr_KillEaterScoreType( "kill eater score type" );
  284. attrib_value_t unKillEaterScoreType;
  285. bool bHasKillEaterScoreType = pItem->FindAttribute( pAttr_KillEaterScoreType, &unKillEaterScoreType );
  286. if ( !bHasKillEaterScoreType || unKillEaterScoreType != (uint32)V_atoi( m_vecConditions[ i ]->GetValue() ) )
  287. {
  288. return false;
  289. }
  290. }
  291. }
  292. return true;
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Determines if the item matches this condition of the criteria
  296. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  297. // Output: True is the item matches, false otherwise
  298. //-----------------------------------------------------------------------------
  299. bool CItemSelectionCriteria::CCondition::BEvaluate( KeyValues *pKVItem ) const
  300. {
  301. KeyValues *pKVField = pKVItem->FindKey( m_sField.String() );
  302. // Treat an empty string as a missing field as well.
  303. bool bIsEmptyString = false;
  304. if ( m_EOp == k_EOperator_String_EQ || m_EOp == k_EOperator_String_Not_EQ )
  305. {
  306. const char *pszItemVal = pKVField ? pKVField->GetString() : NULL;
  307. bIsEmptyString = ( pszItemVal == NULL || pszItemVal[0] == '\0' );
  308. }
  309. // Deal with missing fields
  310. if ( NULL == pKVField || bIsEmptyString )
  311. {
  312. if ( m_bRequired )
  313. return false;
  314. else
  315. return true;
  316. }
  317. // Run the operator specific check
  318. bool bRet = BInternalEvaluate( pKVItem );
  319. // If this is a "not" operator, reverse the result
  320. if ( m_EOp & k_EOperator_Not )
  321. return !bRet;
  322. else
  323. return bRet;
  324. }
  325. //-----------------------------------------------------------------------------
  326. // Purpose: Runs the operator specific check for this condition
  327. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  328. // Output: True is the item matches, false otherwise
  329. //-----------------------------------------------------------------------------
  330. bool CItemSelectionCriteria::CStringCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  331. {
  332. Assert( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp );
  333. if( !( k_EOperator_String_EQ == m_EOp || k_EOperator_String_Not_EQ == m_EOp ) )
  334. return false;
  335. const char *pszItemVal = pKVItem->GetString( m_sField.String() );
  336. return ( 0 == Q_stricmp( m_sValue.String(), pszItemVal ) );
  337. }
  338. bool CItemSelectionCriteria::CStringCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  339. {
  340. CCondition::BSerializeToMsg( msg );
  341. msg.set_string_value( m_sValue.Get() );
  342. return true;
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Runs the operator specific check for this condition
  346. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  347. // Output: True is the item matches, false otherwise
  348. //-----------------------------------------------------------------------------
  349. bool CItemSelectionCriteria::CSetCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  350. {
  351. Assert( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp );
  352. if( !( k_EOperator_Subkey_Contains == m_EOp || k_EOperator_Subkey_Not_Contains == m_EOp ) )
  353. return false;
  354. return ( NULL != pKVItem->FindKey( m_sField.String() )->FindKey( m_sValue.String() ) );
  355. }
  356. bool CItemSelectionCriteria::CSetCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  357. {
  358. CCondition::BSerializeToMsg( msg );
  359. msg.set_string_value( m_sValue.Get() );
  360. return true;
  361. }
  362. //-----------------------------------------------------------------------------
  363. // Purpose: Runs the operator specific check for this condition
  364. // Input: pKVItem - Pointer to the raw KeyValues definition of the item
  365. // Output: True is the item matches, false otherwise
  366. //-----------------------------------------------------------------------------
  367. bool CItemSelectionCriteria::CFloatCondition::BInternalEvaluate( KeyValues *pKVItem ) const
  368. {
  369. float itemValue = pKVItem->GetFloat( m_sField.String() );
  370. switch ( m_EOp )
  371. {
  372. case k_EOperator_Float_EQ:
  373. case k_EOperator_Float_Not_EQ:
  374. return ( itemValue == m_flValue );
  375. case k_EOperator_Float_LT:
  376. case k_EOperator_Float_Not_LT:
  377. return ( itemValue < m_flValue );
  378. case k_EOperator_Float_LTE:
  379. case k_EOperator_Float_Not_LTE:
  380. return ( itemValue <= m_flValue );
  381. case k_EOperator_Float_GT:
  382. case k_EOperator_Float_Not_GT:
  383. return ( itemValue > m_flValue );
  384. case k_EOperator_Float_GTE:
  385. case k_EOperator_Float_Not_GTE:
  386. return ( itemValue >= m_flValue );
  387. default:
  388. AssertMsg1( false, "Unknown operator: %d", m_EOp );
  389. return false;
  390. }
  391. }
  392. bool CItemSelectionCriteria::CFloatCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  393. {
  394. CCondition::BSerializeToMsg( msg );
  395. msg.set_float_value( m_flValue );
  396. return true;
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose: Serialize the item selection criteria to the given message
  400. // Input: msg - The message to serialize to.
  401. // Output: True if the operation was successful, false otherwise.
  402. //-----------------------------------------------------------------------------
  403. bool CItemSelectionCriteria::BSerializeToMsg( CSOItemCriteria & msg ) const
  404. {
  405. msg.set_item_level( m_unItemLevel );
  406. msg.set_item_quality( m_nItemQuality );
  407. msg.set_item_rarity( m_nItemRarity );
  408. msg.set_item_level_set( m_bItemLevelSet );
  409. msg.set_item_quality_set( m_bQualitySet );
  410. msg.set_item_rarity_set( m_bRaritySet );
  411. msg.set_initial_inventory( m_unInitialInventory );
  412. msg.set_initial_quantity( m_unInitialQuantity );
  413. msg.set_ignore_enabled_flag( m_bIgnoreEnabledFlag );
  414. msg.set_recent_only( m_bRecentOnly );
  415. FOR_EACH_VEC( m_vecConditions, i )
  416. {
  417. CSOItemCriteriaCondition *pConditionMsg = msg.add_conditions();
  418. m_vecConditions[i]->BSerializeToMsg( *pConditionMsg );
  419. }
  420. return true;
  421. }
  422. //-----------------------------------------------------------------------------
  423. // Purpose: Deserializes the item selection criteria from the given message
  424. // Input: msg - The message to deserialize from.
  425. // Output: True if the operation was successful, false otherwise.
  426. //-----------------------------------------------------------------------------
  427. bool CItemSelectionCriteria::BDeserializeFromMsg( const CSOItemCriteria & msg )
  428. {
  429. m_unItemLevel = msg.item_level();
  430. m_nItemQuality = msg.item_quality();
  431. m_nItemRarity = msg.item_rarity();
  432. m_bItemLevelSet = msg.item_level_set();
  433. m_bQualitySet = msg.item_quality_set();
  434. m_bRaritySet = msg.item_rarity_set();
  435. m_unInitialInventory = msg.initial_inventory();
  436. m_unInitialQuantity = msg.initial_quantity();
  437. m_bIgnoreEnabledFlag = msg.ignore_enabled_flag();
  438. m_bRecentOnly = msg.recent_only();
  439. uint32 unCount = msg.conditions_size();
  440. m_vecConditions.EnsureCapacity( unCount );
  441. return true;
  442. }
  443. //-----------------------------------------------------------------------------
  444. // Purpose: Serializes a condition to a message.
  445. // Input: msg - The message to serialize to.
  446. // Output: True if the operation was successful, false otherwise.
  447. //-----------------------------------------------------------------------------
  448. bool CItemSelectionCriteria::CCondition::BSerializeToMsg( CSOItemCriteriaCondition & msg ) const
  449. {
  450. msg.set_op( m_EOp );
  451. msg.set_field( m_sField.String() );
  452. msg.set_required( m_bRequired );
  453. return true;
  454. }