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.

970 lines
31 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Holds constants for the econ item system
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. // memdbgon must be the last include file in a .cpp file!!!
  8. #include "tier0/memdbgon.h"
  9. //-----------------------------------------------------------------------------
  10. // Purpose:
  11. //-----------------------------------------------------------------------------
  12. const char *g_szQualityStrings[] =
  13. {
  14. "Normal",
  15. "rarity1", // Genuine
  16. "rarity2", // Customized
  17. "vintage", // Vintage has to stay at 3 for backwards compatibility
  18. "rarity3", // Well-Designed
  19. "rarity4", // Unusual
  20. "Unique",
  21. "community",
  22. "developer",
  23. "selfmade",
  24. "customized",
  25. "strange",
  26. "completed",
  27. "haunted",
  28. "collectors",
  29. "paintkitWeapon",
  30. "default", // AE_RARITY_DEFAULT,
  31. "common", // AE_RARITY_COMMON,
  32. "uncommon", // AE_RARITY_UNCOMMON,
  33. "rare", // AE_RARITY_RARE,
  34. "mythical", // AE_RARITY_MYTHICAL,
  35. "legendary", // AE_RARITY_LEGENDARY,
  36. "ancient", // AE_RARITY_ANCIENT,
  37. };
  38. COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityStrings ) == AE_MAX_TYPES );
  39. const char *EconQuality_GetQualityString( EEconItemQuality eQuality )
  40. {
  41. // This is a runtime check and not an assert because we could theoretically bounce the GC with new
  42. // qualities while the client is running.
  43. if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
  44. return g_szQualityStrings[ eQuality ];
  45. return NULL;
  46. }
  47. EEconItemQuality EconQuality_GetQualityFromString( const char* pszQuality )
  48. {
  49. // Convert to lowercase
  50. CUtlString strLoweredInput( pszQuality );
  51. strLoweredInput.ToLower();
  52. // Guaranteed with the compile time assert above that AE_MAX_TYPES is
  53. // the size of the string qualities
  54. for( int i = 0; i < AE_MAX_TYPES; ++i )
  55. {
  56. // Convert to lowercase
  57. CUtlString strLoweredQuality( g_szQualityStrings[i] );
  58. strLoweredQuality.ToLower();
  59. if( !Q_stricmp( strLoweredInput.Get(), strLoweredQuality.Get() ) )
  60. return EEconItemQuality(i);
  61. }
  62. return AE_UNDEFINED;
  63. }
  64. //-----------------------------------------------------------------------------
  65. // Purpose:
  66. //-----------------------------------------------------------------------------
  67. const char *g_szQualityColorStrings[] =
  68. {
  69. "QualityColorNormal",
  70. "QualityColorrarity1",
  71. "QualityColorrarity2",
  72. "QualityColorVintage",
  73. "QualityColorrarity3",
  74. "QualityColorrarity4", // AE_UNUSUAL
  75. "QualityColorUnique",
  76. "QualityColorCommunity",
  77. "QualityColorDeveloper",
  78. "QualityColorSelfMade",
  79. "QualityColorSelfMadeCustomized",
  80. "QualityColorStrange",
  81. "QualityColorCompleted",
  82. "QualityColorHaunted", // AE_HAUNTED
  83. "QualityColorCollectors", // AE_COLLECTORS
  84. "QualityColorPaintkitWeapon", // AE_PAINTKITWEAPON
  85. "ItemRarityDefault" , // AE_RARITY_DEFAULT,
  86. "ItemRarityCommon" , // AE_RARITY_COMMON,
  87. "ItemRarityUncommon" , // AE_RARITY_UNCOMMON,
  88. "ItemRarityRare" , // AE_RARITY_RARE,
  89. "ItemRarityMythical" , // AE_RARITY_MYTHICAL,
  90. "ItemRarityLegendary" , // AE_RARITY_LEGENDARY,
  91. "ItemRarityAncient" , // AE_RARITY_ANCIENT,
  92. };
  93. COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityColorStrings ) == AE_MAX_TYPES );
  94. const char *EconQuality_GetColorString( EEconItemQuality eQuality )
  95. {
  96. if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
  97. return g_szQualityColorStrings[ eQuality ];
  98. return NULL;
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. const char *g_szQualityLocalizationStrings[] =
  104. {
  105. "#Normal",
  106. "#rarity1", // Genuine
  107. "#rarity2",
  108. "#vintage",
  109. "#rarity3", // Artisan
  110. "#rarity4", // Unusual
  111. "#unique",
  112. "#community",
  113. "#developer",
  114. "#selfmade",
  115. "#customized",
  116. "#strange",
  117. "#completed",
  118. "#haunted",
  119. "#collectors",
  120. "#paintkitWeapon",
  121. "#Rarity_Default",
  122. "#Rarity_Common",
  123. "#Rarity_Uncommon",
  124. "#Rarity_Rare",
  125. "#Rarity_Mythical",
  126. "#Rarity_Legendary",
  127. "#Rarity_Ancient"
  128. };
  129. COMPILE_TIME_ASSERT( ARRAYSIZE( g_szQualityLocalizationStrings ) == AE_MAX_TYPES );
  130. const char *EconQuality_GetLocalizationString( EEconItemQuality eQuality )
  131. {
  132. if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
  133. return g_szQualityLocalizationStrings[ eQuality ];
  134. return NULL;
  135. }
  136. //-----------------------------------------------------------------------------
  137. // Purpose: Sort order for rarities
  138. // Small Numbers sort to front
  139. //-----------------------------------------------------------------------------
  140. int g_nRarityScores[] =
  141. {
  142. 15, // AE_NORMAL,
  143. 10, // AE_RARITY1, // Geniune
  144. 102, // AE_RARITY2, // Customized (unused)
  145. 11, // AE_VINTAGE,
  146. 101, // AE_RARITY3, // Artisan (unused)
  147. 0, // AE_UNUSUAL,
  148. 14, // AE_UNIQUE,
  149. -1, // AE_COMMUNITY,
  150. -3, // AE_DEVELOPER,
  151. -2, // AE_SELFMADE,
  152. 100, // AE_CUSTOMIZED, // Unused
  153. 9, // AE_STRANGE,
  154. 103, // AE_COMPLETED, // Unused
  155. 13, // AE_HAUNTED
  156. 12, // AE_COLLECTORS
  157. 8, // AE_PAINTKITWEAPON
  158. 7, // AE_RARITY_DEFAULT,
  159. 6, // AE_RARITY_COMMON,
  160. 5, // AE_RARITY_UNCOMMON,
  161. 4, // AE_RARITY_RARE,
  162. 3, // AE_RARITY_MYTHICAL,
  163. 2, // AE_RARITY_LEGENDARY,
  164. 1, // AE_RARITY_ANCIENT,
  165. };
  166. COMPILE_TIME_ASSERT( ARRAYSIZE( g_nRarityScores ) == AE_MAX_TYPES );
  167. //-----------------------------------------------------------------------------
  168. int EconQuality_GetRarityScore( EEconItemQuality eQuality )
  169. {
  170. if ( eQuality >= 0 && eQuality < AE_MAX_TYPES )
  171. return g_nRarityScores[ eQuality ];
  172. return 0;
  173. }
  174. //-----------------------------------------------------------------------------
  175. const char *g_pchWearAmountStrings[] =
  176. {
  177. "#TFUI_InvTooltip_None",
  178. "#TFUI_InvTooltip_FactoryNew",
  179. "#TFUI_InvTooltip_MinimalWear",
  180. "#TFUI_InvTooltip_FieldTested",
  181. "#TFUI_InvTooltip_WellWorn",
  182. "#TFUI_InvTooltip_BattleScared"
  183. };
  184. //-----------------------------------------------------------------------------
  185. int EconWear_ToIntCategory( float flWear )
  186. {
  187. if ( flWear <= 0.2f )
  188. {
  189. return 1;
  190. }
  191. else if ( flWear <= 0.4f )
  192. {
  193. return 2;
  194. }
  195. else if ( flWear <= 0.6f )
  196. {
  197. return 3;
  198. }
  199. else if ( flWear <= 0.8f )
  200. {
  201. return 4;
  202. }
  203. else if ( flWear <= 1.0f )
  204. {
  205. return 5;
  206. }
  207. return 3; // default wear
  208. }
  209. // -------------------------------------------------------------------------
  210. // Shim to return a value for buckets. For strange we bucket all of them in to 1 non-instance data group
  211. int EconStrange_ToStrangeBucket( float value )
  212. {
  213. return 0;
  214. }
  215. float EconStrange_FromStrangeBucket( int value )
  216. {
  217. return 0;
  218. }
  219. //-----------------------------------------------------------------------------
  220. const char *GetWearLocalizationString( float flWear )
  221. {
  222. int nIndex = EconWear_ToIntCategory( flWear );
  223. return g_pchWearAmountStrings[ nIndex ];
  224. }
  225. //-----------------------------------------------------------------------------
  226. bool EconWear_IsValidValue( int nWear )
  227. {
  228. return nWear > 0 && nWear <= 5;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose:
  232. //-----------------------------------------------------------------------------
  233. CSchemaColorDefHandle g_AttribColorDefs[] =
  234. {
  235. CSchemaColorDefHandle( "desc_level" ), // ATTRIB_COL_LEVEL
  236. CSchemaColorDefHandle( "desc_attrib_neutral" ), // ATTRIB_COL_NEUTRAL
  237. CSchemaColorDefHandle( "desc_attrib_positive" ), // ATTRIB_COL_POSITIVE
  238. CSchemaColorDefHandle( "desc_attrib_negative" ), // ATTRIB_COL_NEGATIVE
  239. CSchemaColorDefHandle( "desc_itemset_name" ), // ATTRIB_COL_ITEMSET_NAME
  240. CSchemaColorDefHandle( "desc_itemset_equipped" ), // ATTRIB_COL_ITEMSET_EQUIPPED
  241. CSchemaColorDefHandle( "desc_itemset_missing" ), // ATTRIB_COL_ITEMSET_MISSING
  242. CSchemaColorDefHandle( "desc_bundle" ), // ATTRIB_COL_BUNDLE_ITEM
  243. CSchemaColorDefHandle( "desc_limited_use" ), // ATTRIB_COL_LIMITED_USE
  244. CSchemaColorDefHandle( "desc_flags" ), // ATTRIB_COL_component_flags
  245. CSchemaColorDefHandle( "desc_limited_quantity" ), // ATTRIB_COL_LIMITED_QUANTITY
  246. CSchemaColorDefHandle( "desc_default" ), // ATTRIB_COL_RARITY_DEFAULT
  247. CSchemaColorDefHandle( "desc_common" ), // ATTRIB_COL_RARITY_COMMON
  248. CSchemaColorDefHandle( "desc_uncommon" ), // ATTRIB_COL_RARITY_UNCOMMON
  249. CSchemaColorDefHandle( "desc_rare" ), // ATTRIB_COL_RARITY_RARE
  250. CSchemaColorDefHandle( "desc_mythical" ), // ATTRIB_COL_RARITY_MYTHICAL
  251. CSchemaColorDefHandle( "desc_legendary" ), // ATTRIB_COL_RARITY_LEGENDARY
  252. CSchemaColorDefHandle( "desc_ancient" ), // ATTRIB_COL_RARITY_ANCIENT
  253. CSchemaColorDefHandle( "desc_immortal" ), // ATTRIB_COL_RARITY_IMMORTAL
  254. CSchemaColorDefHandle( "desc_arcana" ), // ATTRIB_COL_RARITY_ARCANA
  255. CSchemaColorDefHandle( "desc_strange" ), // ATTRIB_COL_STRANGE
  256. CSchemaColorDefHandle( "desc_unusual" ), // ATTRIB_COL_UNUSUAL
  257. };
  258. COMPILE_TIME_ASSERT( ARRAYSIZE( g_AttribColorDefs ) == NUM_ATTRIB_COLORS );
  259. attrib_colors_t GetAttribColorIndexForName( const char* pszName )
  260. {
  261. for ( int i = 0; i < NUM_ATTRIB_COLORS; ++i )
  262. {
  263. if ( !Q_strcmp( g_AttribColorDefs[i].GetName(), pszName ) )
  264. return (attrib_colors_t)i;
  265. }
  266. return (attrib_colors_t)0;
  267. }
  268. const char *GetColorNameForAttribColor( attrib_colors_t unAttribColor )
  269. {
  270. Assert( unAttribColor >= 0 );
  271. Assert( unAttribColor < NUM_ATTRIB_COLORS );
  272. return g_AttribColorDefs[unAttribColor]
  273. ? g_AttribColorDefs[unAttribColor]->GetColorName()
  274. : "ItemAttribNeutral";
  275. }
  276. const char *GetHexColorForAttribColor( attrib_colors_t unAttribColor )
  277. {
  278. Assert( unAttribColor >= 0 );
  279. Assert( unAttribColor < NUM_ATTRIB_COLORS );
  280. return g_AttribColorDefs[unAttribColor]
  281. ? g_AttribColorDefs[unAttribColor]->GetHexColor()
  282. : "#ebe2ca";
  283. }
  284. entityquality_t GetItemQualityFromString( const char *sQuality )
  285. {
  286. for ( int i = 0; i < AE_MAX_TYPES; i++ )
  287. {
  288. if ( !Q_strnicmp( sQuality, g_szQualityStrings[i], 16 ) )
  289. return (entityquality_t)i;
  290. }
  291. return AE_NORMAL;
  292. }
  293. const char *g_szRecipeCategoryStrings[] =
  294. {
  295. "crafting", // RECIPE_CATEGORY_CRAFTINGITEMS = 0,
  296. "commonitem", // RECIPE_CATEGORY_COMMONITEMS,
  297. "rareitem", // RECIPE_CATEGORY_RAREITEMS,
  298. "special", // RECIPE_CATEGORY_SPECIAL,
  299. };
  300. COMPILE_TIME_ASSERT( ARRAYSIZE( g_szRecipeCategoryStrings ) == NUM_RECIPE_CATEGORIES );
  301. //-----------------------------------------------------------------------------
  302. // Item acquisition.
  303. //-----------------------------------------------------------------------------
  304. // Strings shown to the local player in the pickup dialog
  305. const char *g_pszItemPickupMethodStrings[] =
  306. {
  307. "#NewItemMethod_Dropped", // UNACK_ITEM_DROPPED = 1,
  308. "#NewItemMethod_Crafted", // UNACK_ITEM_CRAFTED,
  309. "#NewItemMethod_Traded", // UNACK_ITEM_TRADED,
  310. "#NewItemMethod_Purchased", // UNACK_ITEM_PURCHASED,
  311. "#NewItemMethod_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
  312. "#NewItemMethod_Gifted", // UNACK_ITEM_GIFTED,
  313. "#NewItemMethod_Support", // UNACK_ITEM_SUPPORT,
  314. "#NewItemMethod_Promotion", // UNACK_ITEM_PROMOTION,
  315. "#NewItemMethod_Earned", // UNACK_ITEM_EARNED,
  316. "#NewItemMethod_Refunded", // UNACK_ITEM_REFUNDED,
  317. "#NewItemMethod_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED,
  318. "#NewItemMethod_Foreign", // UNACK_ITEM_FOREIGN,
  319. "#NewItemMethod_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
  320. "#NewItemMethod_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
  321. "#NewItemMethod_PreviewItemPurchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
  322. "#NewItemMethod_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
  323. "#NewItemMethod_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
  324. "#NewItemMethod_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
  325. "#NewItemMethod_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
  326. "#NewItemMethod_CommunityMarketPurchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
  327. "#NewItemMethod_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
  328. NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
  329. "#NewItemMethod_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
  330. "#NewItemMethod_QuestLoaner", // UNACK_ITEM_QUEST_LOANER
  331. "#NewItemMethod_TradeUp", // UNACK_ITEM_TRADE_UP
  332. "#NewItemMethod_QuestMerasmissionOutput", //UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
  333. "#NewItemMethod_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
  334. #ifdef ENABLE_STORE_RENTAL_BACKEND
  335. "#NewItemMethod_RentalPurchase", // UNACK_ITEM_RENTAL_PURCHASE
  336. #endif
  337. };
  338. COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStrings ) == (UNACK_NUM_METHODS - 1) ); // -1 because UNACK_ITEM_DROPPED is index 1, not 0
  339. const char *g_pszItemPickupMethodStringsUnloc[] =
  340. {
  341. "dropped", // UNACK_ITEM_DROPPED = 1,
  342. "crafted", // UNACK_ITEM_CRAFTED,
  343. "traded", // UNACK_ITEM_TRADED,
  344. "purchased", // UNACK_ITEM_PURCHASED,
  345. "found_in_crate", // UNACK_ITEM_FOUND_IN_CRATE,
  346. "gifted", // UNACK_ITEM_GIFTED,
  347. "support", // UNACK_ITEM_SUPPORT,
  348. "promotion", // UNACK_ITEM_PROMOTION,
  349. "earned", // UNACK_ITEM_EARNED,
  350. "refunded", // UNACK_ITEM_REFUNDED,
  351. "gift_wrapped", // UNACK_ITEM_GIFT_WRAPPED
  352. "foreign", // UNACK_ITEM_FOREIGN
  353. "collection_reward",// UNACK_ITEM_COLLECTION_REWARD
  354. "preview_item", // UNACK_ITEM_PREVIEW_ITEM
  355. "preview_item_purchased", // UNACK_ITEM_PREVIEW_ITEM_PURCHASED
  356. "periodic_score_reward", // UNACK_ITEM_PERIODIC_SCORE_REWARD
  357. "mvm_badge_completion_reward", // UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
  358. "mvm_squad_surplus_reward", // UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
  359. "holiday_gift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
  360. "market_purchase", // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
  361. "recipe_output", // UNACK_ITEM_RECIPE_OUTPUT
  362. "hidden_quest", // UNACK_ITEM_HIDDEN_QUEST_ITEM
  363. "quest_output", // UNACK_ITEM_QUEST_OUTPUT
  364. "trade_up", // UNACK_ITEM_TRADE_UP
  365. "quest_output", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
  366. "viral_competitive_beta_pass", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
  367. #ifdef ENABLE_STORE_RENTAL_BACKEND
  368. "rental_purchase", // UNACK_ITEM_RENTAL_PURCHASE
  369. #endif
  370. };
  371. COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemPickupMethodStringsUnloc ) == (UNACK_NUM_METHODS - 1) );
  372. // Strings shown to other players in the chat dialog
  373. const char *g_pszItemFoundMethodStrings[] =
  374. {
  375. "#Item_Found", // UNACK_ITEM_DROPPED = 1,
  376. "#Item_Crafted", // UNACK_ITEM_CRAFTED,
  377. "#Item_Traded", // UNACK_ITEM_TRADED,
  378. NULL, // UNACK_ITEM_PURCHASED,
  379. "#Item_FoundInCrate", // UNACK_ITEM_FOUND_IN_CRATE,
  380. "#Item_Gifted", // UNACK_ITEM_GIFTED,
  381. NULL, // UNACK_ITEM_SUPPORT,
  382. NULL, // UNACK_ITEM_PROMOTION
  383. "#Item_Earned", // UNACK_ITEM_EARNED
  384. "#Item_Refunded", // UNACK_ITEM_REFUNDED
  385. "#Item_GiftWrapped", // UNACK_ITEM_GIFT_WRAPPED
  386. "#Item_Foreign", // UNACK_ITEM_FOREIGN
  387. "#Item_CollectionReward", // UNACK_ITEM_COLLECTION_REWARD
  388. "#Item_PreviewItem", // UNACK_ITEM_PREVIEW_ITEM
  389. "#Item_PreviewItemPurchased",// UNACK_ITEM_PREVIEW_ITEM_PURCHASED
  390. "#Item_PeriodicScoreReward",// UNACK_ITEM_PERIODIC_SCORE_REWARD
  391. "#Item_MvMBadgeCompletionReward",// UNACK_ITEM_MVM_MISSION_COMPLETION_REWARD
  392. "#Item_MvMSquadSurplusReward",// UNACK_ITEM_MVM_SQUAD_SURPLUS_REWARD
  393. "#Item_HolidayGift", // UNACK_ITEM_FOUND_HOLIDAY_GIFT
  394. NULL, // UNACK_ITEM_COMMUNITY_MARKET_PURCHASE
  395. "#Item_RecipeOutput", // UNACK_ITEM_RECIPE_OUTPUT
  396. NULL, // UNACK_ITEM_HIDDEN_QUEST_ITEM
  397. "#Item_QuestOutput", // UNACK_ITEM_QUEST_OUTPUT
  398. NULL, // UNACK_ITEM_QUEST_LOANER
  399. "#Item_TradeUp", // UNACK_ITEM_TRADE_UP
  400. "#Item_QuestMerasmissionOutput", // UNACK_ITEM_QUEST_MERASMISSION_OUTPUT
  401. "#Item_ViralCompetitiveBetaPassSpread", //UNACK_ITEM_VIRAL_COMPETITIVE_BETA_PASS_SPREAD
  402. #ifdef ENABLE_STORE_RENTAL_BACKEND
  403. NULL, // UNACK_ITEM_RENTAL_PURCHASE
  404. #endif
  405. };
  406. COMPILE_TIME_ASSERT( ARRAYSIZE( g_pszItemFoundMethodStrings ) == (UNACK_NUM_METHODS - 1) );
  407. //-----------------------------------------------------------------------------
  408. // Purpose:
  409. //-----------------------------------------------------------------------------
  410. struct strange_attr_set_t
  411. {
  412. strange_attr_set_t( const char *pScoreAttrName, const char *pTypeAttrName, const char *pRestrictionAttrName, const char *pRestrictionValueAttrName, bool bIsUserCustomizable )
  413. : m_attrScore( pScoreAttrName )
  414. , m_attrType( pTypeAttrName )
  415. , m_attrRestriction( pRestrictionAttrName )
  416. , m_attrRestrictionValue( pRestrictionValueAttrName )
  417. , m_bIsUserCustomizable( bIsUserCustomizable )
  418. {
  419. //
  420. }
  421. CSchemaAttributeDefHandle m_attrScore;
  422. CSchemaAttributeDefHandle m_attrType;
  423. CSchemaAttributeDefHandle m_attrRestriction;
  424. CSchemaAttributeDefHandle m_attrRestrictionValue;
  425. bool m_bIsUserCustomizable;
  426. };
  427. strange_attr_set_t g_KillEaterAttr[] =
  428. {
  429. strange_attr_set_t( "kill eater", "kill eater score type", "strange restriction type 1", "strange restriction value 1", false ),
  430. strange_attr_set_t( "kill eater 2", "kill eater score type 2", "strange restriction type 2", "strange restriction value 2", false ),
  431. strange_attr_set_t( "kill eater 3", "kill eater score type 3", "strange restriction type 3", "strange restriction value 3", false ),
  432. // assumption: all of the user-customizable attributes will follow all of the schema-specified attributes
  433. strange_attr_set_t( "kill eater user 1", "kill eater user score type 1", "strange restriction user type 1", "strange restriction user value 1", true ),
  434. strange_attr_set_t( "kill eater user 2", "kill eater user score type 2", "strange restriction user type 2", "strange restriction user value 2", true ),
  435. strange_attr_set_t( "kill eater user 3", "kill eater user score type 3", "strange restriction user type 3", "strange restriction user value 3", true ),
  436. };
  437. int GetKillEaterAttrCount()
  438. {
  439. #ifdef DBGFLAG_ASSERT
  440. // Verify our commented assumption that all of the non-user-customizable attributes will be followed by
  441. // all of the user-customizable attributes.
  442. bool bInUserCustomizableBlock = false;
  443. for ( int i = 0; i < ARRAYSIZE( g_KillEaterAttr ); i++ )
  444. {
  445. if ( bInUserCustomizableBlock )
  446. {
  447. AssertMsg( g_KillEaterAttr[i].m_bIsUserCustomizable, "Ordering assumption for g_KillEaterAttr violated! User-customizable attributes should all be at the end of the list!" );
  448. }
  449. bInUserCustomizableBlock |= g_KillEaterAttr[i].m_bIsUserCustomizable;
  450. }
  451. #endif
  452. return ARRAYSIZE( g_KillEaterAttr );
  453. }
  454. int GetKillEaterAttrCount_UserCustomizable()
  455. {
  456. int iCount = 0;
  457. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  458. {
  459. if ( GetKillEaterAttr_IsUserCustomizable( i ) )
  460. {
  461. iCount++;
  462. }
  463. }
  464. return iCount;
  465. }
  466. const CEconItemAttributeDefinition *GetKillEaterAttr_Score( int i )
  467. {
  468. Assert( i >= 0 );
  469. Assert( i < GetKillEaterAttrCount() );
  470. const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrScore;
  471. AssertMsg1( pAttrRes, "Missing Killeater attr score %s", g_KillEaterAttr[ i ].m_attrScore.GetName() );
  472. return pAttrRes;
  473. }
  474. const CEconItemAttributeDefinition *GetKillEaterAttr_Type( int i )
  475. {
  476. Assert( i >= 0 );
  477. Assert( i < GetKillEaterAttrCount() );
  478. const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrType;
  479. AssertMsg1( pAttrRes, "Missing Killeater attr type %s", g_KillEaterAttr[ i ].m_attrType.GetName() );
  480. return pAttrRes;
  481. }
  482. const CEconItemAttributeDefinition *GetKillEaterAttr_Restriction( int i )
  483. {
  484. Assert( i >= 0 );
  485. Assert( i < GetKillEaterAttrCount() );
  486. const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestriction;
  487. AssertMsg1( pAttrRes, "Missing Killeater attr restriction %s", g_KillEaterAttr[ i ].m_attrRestriction.GetName() );
  488. return pAttrRes;
  489. }
  490. const CEconItemAttributeDefinition *GetKillEaterAttr_RestrictionValue( int i )
  491. {
  492. Assert( i >= 0 );
  493. Assert( i < GetKillEaterAttrCount() );
  494. const CEconItemAttributeDefinition *pAttrRes = g_KillEaterAttr[i].m_attrRestrictionValue;
  495. AssertMsg1( pAttrRes, "Missing Killeater attr restriction value %s", g_KillEaterAttr[ i ].m_attrRestrictionValue.GetName() );
  496. return pAttrRes;
  497. }
  498. bool GetKillEaterAttr_IsUserCustomizable( int i )
  499. {
  500. Assert( i >= 0 );
  501. Assert( i < GetKillEaterAttrCount() );
  502. return g_KillEaterAttr[i].m_bIsUserCustomizable;
  503. }
  504. bool GetKilleaterValueByEvent( const IEconItemInterface* pItem, const kill_eater_event_t& EEventType, uint32& value )
  505. {
  506. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  507. {
  508. const CEconItemAttributeDefinition *pAttribKillEater = GetKillEaterAttr_Score( i );
  509. const CEconItemAttributeDefinition *pAttribKillEaterScoreType = GetKillEaterAttr_Type( i );
  510. Assert( pAttribKillEater && pAttribKillEaterScoreType );
  511. if ( !pAttribKillEater || !pAttribKillEaterScoreType )
  512. return false;
  513. // make sure this item even has a kill count attribute we're looking for
  514. uint32 unKillEaterAttrValue;
  515. if ( !pItem->FindAttribute( pAttribKillEater, &unKillEaterAttrValue ) )
  516. continue;
  517. uint32 unKillEaterScoreTypeAttrValue = kKillEaterEvent_PlayerKill;
  518. float fKillEaterScoreTypeAttrValue;
  519. if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttribKillEaterScoreType, &fKillEaterScoreTypeAttrValue ) )
  520. {
  521. unKillEaterScoreTypeAttrValue = (uint32)fKillEaterScoreTypeAttrValue;
  522. }
  523. // this isn't the attribute we're trying to find
  524. if ( EEventType != (kill_eater_event_t)unKillEaterScoreTypeAttrValue )
  525. continue;
  526. value = unKillEaterAttrValue;
  527. return true;
  528. }
  529. return false;
  530. }
  531. // Does this thing have kill eater
  532. bool BIsItemStrange( const IEconItemInterface *pItem )
  533. {
  534. // Go over the attributes of the item, if it has any strange attributes the item is strange and don't apply
  535. uint32 unKillEaterAttr;
  536. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  537. {
  538. if ( pItem->FindAttribute( GetKillEaterAttr_Score( i ), &unKillEaterAttr ) )
  539. {
  540. return true;
  541. }
  542. }
  543. return false;
  544. }
  545. //-----------------------------------------------------------------------------
  546. // Purpose: Get a localization token that describes why an item is not usable
  547. // in the trade-up crafting. Returns NULL if no reason. Can pass in
  548. // another item to compare against, which causes extra consistency checks
  549. //-----------------------------------------------------------------------------
  550. const char* GetCollectionCraftingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
  551. {
  552. if ( !pTestItem )
  553. {
  554. return "#TF_CollectionCrafting_NoItem";
  555. }
  556. // Needs to have a collection
  557. const CEconItemCollectionDefinition* pTestCollection = pTestItem->GetItemDefinition()->GetItemCollectionDefinition();
  558. if ( !pTestCollection )
  559. {
  560. return "#TF_CollectionCrafting_NoCollection";
  561. }
  562. // Make sure this item is a part of the collection it claims to be in
  563. {
  564. item_definition_index_t nThisDefIndex = pTestItem->GetItemDefIndex();
  565. bool bFound = false;
  566. for( int i=0; i < pTestCollection->m_iItemDefs.Count() && !bFound; ++i )
  567. {
  568. bFound |= pTestCollection->m_iItemDefs[i] == nThisDefIndex;
  569. }
  570. if ( !bFound )
  571. {
  572. return "#TF_CollectionCrafting_NoCollection";
  573. }
  574. }
  575. // Needs rarity
  576. uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
  577. if( nRarity == k_unItemRarity_Any )
  578. {
  579. return "#TF_CollectionCrafting_NoRarity";
  580. }
  581. // Can't use items with rarity at the "top" of a collection (what would they craft into?)
  582. if ( nRarity == pTestCollection->GetMaxRarity() )
  583. {
  584. return "#TF_CollectionCrafting_MaxRarity";
  585. }
  586. // No self mades or community items
  587. uint32 eQuality = pTestItem->GetQuality();
  588. if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
  589. {
  590. return "#TF_CollectionCrafting_NoUnusual";
  591. }
  592. // This is how we test for unusuals. Don't let unusuals be crafted
  593. static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
  594. if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
  595. {
  596. return "#TF_CollectionCrafting_NoUnusual";
  597. }
  598. static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
  599. if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
  600. {
  601. return "#TF_CollectionCrafting_NoUnusual";
  602. }
  603. // Not allowed to be crafted?
  604. if ( !pTestItem->IsUsableInCrafting() )
  605. {
  606. return "#TF_CollectionCrafting_NotCraftable";
  607. }
  608. // If another item was passed in, we have a few consistency checks to make
  609. if ( pSourceItem )
  610. {
  611. // Need to have the same rarity
  612. if ( nRarity != pSourceItem->GetItemDefinition()->GetRarity() )
  613. {
  614. return "#TF_CollectionCrafting_MismatchRarity";
  615. }
  616. // Need to have the same strangeness
  617. if ( BIsItemStrange( pSourceItem ) != BIsItemStrange( pTestItem ) )
  618. {
  619. return "#TF_CollectionCrafting_MismatchStrange";
  620. }
  621. }
  622. return NULL;
  623. }
  624. //-----------------------------------------------------------------------------
  625. // Purpose: Get a localization token that describes why an item is not usable
  626. // in the Halloween Offering. Returns NULL if no reason. Can pass in
  627. // another item to compare against, which causes extra consistency checks
  628. //-----------------------------------------------------------------------------
  629. const char* GetHalloweenOfferingInvalidReason( const IEconItemInterface *pTestItem, const IEconItemInterface *pSourceItem )
  630. {
  631. // Must either be a Cosmetic
  632. // Taunt
  633. // Allowable Tool (Strange part, Paint, name tag, killstreak). Not crates, keys
  634. // Marketable Weapon ie Strange, Genuine, Vintage, paintkit
  635. // Cannot be Unusual
  636. if ( !pTestItem )
  637. {
  638. return "#TF_CollectionCrafting_NoItem";
  639. }
  640. // No self mades or community items
  641. uint32 eQuality = pTestItem->GetQuality();
  642. if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
  643. {
  644. return "#TF_CollectionCrafting_NoUnusual";
  645. }
  646. // This is how we test for unusuals. Don't let unusuals be crafted
  647. static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
  648. if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
  649. {
  650. return "#TF_CollectionCrafting_NoUnusual";
  651. }
  652. static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
  653. if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
  654. {
  655. return "#TF_CollectionCrafting_NoUnusual";
  656. }
  657. // Invalid Items
  658. static CSchemaAttributeDefHandle pAttrDef_CannotTransmute( "cannot_transmute" );
  659. if ( pTestItem->FindAttribute( pAttrDef_CannotTransmute ) )
  660. {
  661. return "#TF_HalloweenOffering_Invalid";
  662. }
  663. static CSchemaAttributeDefHandle pAttrDef_CannotDelete( "cannot delete" );
  664. if ( pTestItem->FindAttribute( pAttrDef_CannotDelete ) )
  665. {
  666. return "#TF_HalloweenOffering_Invalid";
  667. }
  668. const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
  669. if ( pItemDef == NULL )
  670. {
  671. return "#TF_CollectionCrafting_NoItem";
  672. }
  673. if ( pTestItem->IsTemporaryItem() )
  674. {
  675. return "#TF_CollectionCrafting_NoItem";
  676. }
  677. // If you are a taunt or a cosmetic you are allowed
  678. if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT )
  679. {
  680. // do not 'medal' equip region items
  681. if ( pTestItem->GetItemDefinition()->GetEquipRegionMask() & GetItemSchema()->GetEquipRegionBitMaskByName( "medal" ) )
  682. {
  683. return "#TF_HalloweenOffering_Invalid";
  684. }
  685. return NULL;
  686. }
  687. // Do not allow Crates
  688. if ( ( pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE ) != 0 )
  689. {
  690. return "#TF_HalloweenOffering_Invalid";
  691. }
  692. // Cause of weird legacy items lets be explicit about what we allow
  693. if ( pItemDef->IsTool() )
  694. {
  695. // ignore everything that is not a paint can tool
  696. const IEconTool *pEconTool = pItemDef->GetEconTool();
  697. if ( !pEconTool )
  698. return "#TF_HalloweenOffering_Invalid";
  699. const char *pToolType = pEconTool->GetTypeName();
  700. if ( !V_strcmp( pToolType, "paint_can" ) )
  701. return NULL;
  702. else if ( !V_strcmp( pToolType, "strange_part" ) )
  703. return NULL;
  704. else if ( !V_strcmp( pToolType, "name" ) )
  705. return NULL;
  706. else if ( !V_strcmp( pToolType, "desc" ) )
  707. return NULL;
  708. else if ( !V_strcmp( pToolType, "killstreakifier" ) )
  709. return NULL;
  710. else if ( !V_strcmp( pToolType, "strangifier" ) )
  711. return NULL;
  712. // Not a tool we are allowing
  713. return "#TF_HalloweenOffering_Invalid";
  714. }
  715. // Otherwise you must be a weapon or we won't allow
  716. if ( pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PRIMARY
  717. || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_SECONDARY
  718. || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MELEE
  719. || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_BUILDING
  720. || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA
  721. || pTestItem->GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_PDA2
  722. ) {
  723. // Must be strange, genuine, vintage, haunted or paintkit (ie a marketable weapon)
  724. eQuality = pTestItem->GetQuality();
  725. if ( eQuality == AE_RARITY1
  726. || eQuality == AE_VINTAGE
  727. || eQuality == AE_HAUNTED
  728. || eQuality == AE_COLLECTORS
  729. || eQuality == AE_PAINTKITWEAPON
  730. ) {
  731. return NULL;
  732. }
  733. // Weapons with rarity are allowed
  734. uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
  735. if ( nRarity != k_unItemRarity_Any )
  736. {
  737. return NULL;
  738. }
  739. // Strange items. Dont just check for strange quality, actually check for a strange attribute.
  740. // See if we've got any strange attributes.
  741. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  742. {
  743. if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
  744. {
  745. return NULL;
  746. }
  747. }
  748. }
  749. return "#TF_HalloweenOffering_Invalid";
  750. }
  751. const char* GetCraftCommonStatClockInvalidReason( const class IEconItemInterface *pTestItem, const class IEconItemInterface *pSourceItem )
  752. {
  753. if ( !pTestItem )
  754. {
  755. return "#TF_CollectionCrafting_NoItem";
  756. }
  757. // Not allowed to be crafted?
  758. if ( !pTestItem->IsUsableInCrafting() )
  759. {
  760. return "#TF_CollectionCrafting_NotCraftable";
  761. }
  762. // No self mades or community items
  763. uint32 eQuality = pTestItem->GetQuality();
  764. if ( eQuality == AE_SELFMADE || eQuality == AE_COMMUNITY )
  765. return "#TF_CollectionCrafting_NoUnusual";
  766. // This is how we test for unusuals. Don't let unusuals be crafted
  767. static CSchemaAttributeDefHandle pAttrDef_ParticleEffect( "attach particle effect" );
  768. if ( pTestItem->FindAttribute( pAttrDef_ParticleEffect ) )
  769. return "#TF_CollectionCrafting_NoUnusual";
  770. static CSchemaAttributeDefHandle pAttrDef_TauntUnusualAttr( "on taunt attach particle index" );
  771. if ( pTestItem->FindAttribute( pAttrDef_TauntUnusualAttr ) )
  772. return "#TF_CollectionCrafting_NoUnusual";
  773. const CEconItemDefinition *pItemDef = pTestItem->GetItemDefinition();
  774. if ( pItemDef == NULL )
  775. return "#TF_CollectionCrafting_NoItem";
  776. if ( pTestItem->IsTemporaryItem() )
  777. return "#TF_CollectionCrafting_NoItem";
  778. // Strange items. Dont just check for strange quality, actually check for a strange attribute.
  779. // See if we've got any strange attributes.
  780. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  781. {
  782. if ( pTestItem->FindAttribute( GetKillEaterAttr_Score( i ) ) )
  783. {
  784. return NULL;
  785. }
  786. }
  787. // Needs Rarity
  788. uint8 nRarity = pTestItem->GetItemDefinition()->GetRarity();
  789. if ( nRarity != k_unItemRarity_Any && nRarity > 1 ) // do not allow default nor common rarity
  790. {
  791. return NULL;
  792. }
  793. return "#TF_MannCoTrade_ItemInvalid";
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Purpose:
  797. //-----------------------------------------------------------------------------
  798. enum { kMaxCardUpgradesPerItem = 2 };
  799. int GetMaxCardUpgradesPerItem()
  800. {
  801. return kMaxCardUpgradesPerItem;
  802. }
  803. const CEconItemAttributeDefinition *GetCardUpgradeForIndex( const IEconItemInterface *pItem, int i )
  804. {
  805. Assert( pItem );
  806. Assert( i >= 0 );
  807. Assert( i < kMaxCardUpgradesPerItem );
  808. class CGetNthUserGeneratedAttributeIterator : public IEconItemUntypedAttributeIterator
  809. {
  810. public:
  811. CGetNthUserGeneratedAttributeIterator( int iTargetIndex )
  812. : m_iCount( iTargetIndex )
  813. , m_pAttrDef( NULL )
  814. {
  815. }
  816. virtual bool OnIterateAttributeValueUntyped( const CEconItemAttributeDefinition *pAttrDef ) OVERRIDE
  817. {
  818. if ( pAttrDef->GetUserGenerationType() != 0 && m_iCount-- == 0 )
  819. {
  820. m_pAttrDef = pAttrDef;
  821. return false;
  822. }
  823. return true;
  824. }
  825. const CEconItemAttributeDefinition *GetAttrDef() const { return m_pAttrDef; }
  826. private:
  827. int m_iCount;
  828. const CEconItemAttributeDefinition *m_pAttrDef;
  829. };
  830. CGetNthUserGeneratedAttributeIterator findNthAttrIterator( i );
  831. pItem->IterateAttributes( &findNthAttrIterator );
  832. return findNthAttrIterator.GetAttrDef();
  833. }