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.

412 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. #include "cbase.h"
  3. #include "econ_item_interface.h"
  4. #include "econ_item_tools.h" // needed for CEconTool_WrappedGift definition for IsMarketable()
  5. #include "rtime.h"
  6. #ifdef STAGING_ONLY
  7. ConVar tf_paint_kit_force_wear( "tf_paint_kit_force_wear", "0", FCVAR_REPLICATED, "Set to force the wear level of paink kit weapons and ignore the GC dynamic attribute value." );
  8. #endif
  9. // --------------------------------------------------------------------------
  10. bool IEconItemInterface::GetCustomPaintKitWear( float &flWear ) const
  11. {
  12. #ifdef STAGING_ONLY
  13. // don't assert in staging if this ConVar is set
  14. if ( tf_paint_kit_force_wear.GetInt() > 0 )
  15. {
  16. flWear = tf_paint_kit_force_wear.GetFloat();
  17. return true;
  18. }
  19. #endif // STAGING_ONLY
  20. static CSchemaAttributeDefHandle pAttrDef_PaintKitWear( "set_item_texture_wear" );
  21. float flPaintKitWear = 0;
  22. if ( pAttrDef_PaintKitWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_PaintKitWear, &flPaintKitWear ) )
  23. {
  24. flWear = flPaintKitWear;
  25. return true;
  26. }
  27. static CSchemaAttributeDefHandle pAttrDef_DefaultWear( "texture_wear_default" );
  28. if ( pAttrDef_DefaultWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_DefaultWear, &flPaintKitWear ) )
  29. {
  30. flWear = flPaintKitWear;
  31. return true;
  32. }
  33. // If you have no wear, you also should not have a paint kit
  34. AssertMsg( !GetCustomPainkKitDefinition(), "No Wear Found on Item [%llu - %s] that has a Paintkit!", GetID(), GetItemDefinition()->GetDefinitionName() );
  35. return false;
  36. }
  37. // --------------------------------------------------------------------------
  38. // Purpose:
  39. // --------------------------------------------------------------------------
  40. bool IEconItemInterface::IsTemporaryItem() const
  41. {
  42. // store preview items are also temporary
  43. if ( GetOrigin() == kEconItemOrigin_PreviewItem )
  44. return true;
  45. RTime32 rtTime = GetExpirationDate();
  46. if ( rtTime > 0 )
  47. return true;
  48. return false;
  49. }
  50. // --------------------------------------------------------------------------
  51. RTime32 IEconItemInterface::GetExpirationDate() const
  52. {
  53. COMPILE_TIME_ASSERT( sizeof( float ) == sizeof( RTime32 ) );
  54. // dynamic attributes, if present, will override any static expiration timer
  55. static CSchemaAttributeDefHandle pAttrib_ExpirationDate( "expiration date" );
  56. attrib_value_t unAttribExpirationTimeBits;
  57. COMPILE_TIME_ASSERT( sizeof( unAttribExpirationTimeBits ) == sizeof( RTime32 ) );
  58. if ( pAttrib_ExpirationDate && FindAttribute( pAttrib_ExpirationDate, &unAttribExpirationTimeBits ) )
  59. return *(RTime32 *)&unAttribExpirationTimeBits;
  60. // do we have a static timer set in the schema for all instances to expire?
  61. return GetItemDefinition()
  62. ? GetItemDefinition()->GetExpirationDate()
  63. : RTime32( 0 );
  64. }
  65. // --------------------------------------------------------------------------
  66. // Purpose:
  67. // --------------------------------------------------------------------------
  68. RTime32 IEconItemInterface::GetTradableAfterDateTime() const
  69. {
  70. static CSchemaAttributeDefHandle pAttrib_TradableAfter( "tradable after date" );
  71. Assert( pAttrib_TradableAfter );
  72. if ( !pAttrib_TradableAfter )
  73. return 0;
  74. RTime32 rtTimestamp;
  75. if ( !FindAttribute( pAttrib_TradableAfter, &rtTimestamp ) )
  76. return 0;
  77. return rtTimestamp;
  78. }
  79. // --------------------------------------------------------------------------
  80. // Purpose: Return true if this item can never be traded
  81. // --------------------------------------------------------------------------
  82. bool IEconItemInterface::IsPermanentlyUntradable() const
  83. {
  84. if ( GetItemDefinition() == NULL )
  85. return true;
  86. // tagged to not be a part of the economy?
  87. if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
  88. return true;
  89. // check attributes
  90. static CSchemaAttributeDefHandle pAttrib_AlwaysTradable( "always tradable" );
  91. static CSchemaAttributeDefHandle pAttrib_CannotTrade( "cannot trade" );
  92. static CSchemaAttributeDefHandle pAttrib_NonEconomy( "non economy" );
  93. Assert( pAttrib_AlwaysTradable != NULL );
  94. Assert( pAttrib_CannotTrade != NULL );
  95. if ( pAttrib_AlwaysTradable == NULL || pAttrib_CannotTrade == NULL || pAttrib_NonEconomy == NULL )
  96. return true;
  97. // Order matters, check for nonecon first. Always tradable overrides cannot trade.
  98. if ( FindAttribute( pAttrib_NonEconomy ) )
  99. return true;
  100. if ( FindAttribute( pAttrib_AlwaysTradable ) ) // *sigh*
  101. return false;
  102. if ( FindAttribute( pAttrib_CannotTrade ) )
  103. return true;
  104. // items gained in this way are not tradable
  105. switch ( GetOrigin() )
  106. {
  107. case kEconItemOrigin_Invalid:
  108. case kEconItemOrigin_Achievement:
  109. case kEconItemOrigin_Foreign:
  110. case kEconItemOrigin_PreviewItem:
  111. case kEconItemOrigin_SteamWorkshopContribution:
  112. return true;
  113. }
  114. // temporary items (items that will expire for any reason) cannot be traded
  115. if ( IsTemporaryItem() )
  116. return true;
  117. // certain quality levels are not tradable
  118. if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
  119. return true;
  120. // explicitly marked cannot trade?
  121. if ( ( kEconItemFlag_CannotTrade & GetFlags() ) != 0 )
  122. return true;
  123. return false;
  124. }
  125. // --------------------------------------------------------------------------
  126. // Purpose: Return true if this item is a commodity on the Market (can place buy orders)
  127. // --------------------------------------------------------------------------
  128. bool IEconItemInterface::IsCommodity() const
  129. {
  130. if ( GetItemDefinition() == NULL )
  131. return false;
  132. static CSchemaAttributeDefHandle pAttrib_IsCommodity( "is commodity" );
  133. if ( FindAttribute( pAttrib_IsCommodity ) )
  134. return true;
  135. return false;
  136. }
  137. // --------------------------------------------------------------------------
  138. // Purpose: Return true if temporarily untradable
  139. // --------------------------------------------------------------------------
  140. bool IEconItemInterface::IsTemporarilyUntradable() const
  141. {
  142. // Temporary untradability does NOT take "always tradable" into account
  143. if ( GetTradableAfterDateTime() >= CRTime::RTime32TimeCur() )
  144. return true;
  145. return false;
  146. }
  147. // --------------------------------------------------------------------------
  148. // Purpose: Return true if this item is untradable
  149. // --------------------------------------------------------------------------
  150. bool IEconItemInterface::IsTradable() const
  151. {
  152. // Items that are expired are never listable, regardless of other rules.
  153. //RTime32 timeExpirationDate = GetExpirationDate();
  154. //if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
  155. // return false;
  156. return GetUntradabilityFlags() == 0;
  157. }
  158. // --------------------------------------------------------------------------
  159. // Purpose: Return untradability flags
  160. // --------------------------------------------------------------------------
  161. int IEconItemInterface::GetUntradabilityFlags() const
  162. {
  163. int nFlags = 0;
  164. if ( IsTemporarilyUntradable() )
  165. {
  166. nFlags |= k_Untradability_Temporary;
  167. }
  168. if ( IsPermanentlyUntradable() )
  169. {
  170. nFlags |= k_Untradability_Permanent;
  171. }
  172. return nFlags;
  173. }
  174. // --------------------------------------------------------------------------
  175. // Purpose:
  176. // --------------------------------------------------------------------------
  177. bool IEconItemInterface::IsUsableInCrafting() const
  178. {
  179. if ( GetItemDefinition() == NULL )
  180. return false;
  181. // tagged to not be a part of the economy?
  182. if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
  183. return false;
  184. // always craftable?
  185. static CSchemaAttributeDefHandle pAttrib_AlwaysUsableInCraft( "always tradable" );
  186. Assert( pAttrib_AlwaysUsableInCraft );
  187. if ( FindAttribute( pAttrib_AlwaysUsableInCraft ) )
  188. return true;
  189. // never craftable?
  190. static CSchemaAttributeDefHandle pAttrib_NeverCraftable( "never craftable" );
  191. Assert( pAttrib_NeverCraftable );
  192. if ( FindAttribute( pAttrib_NeverCraftable ) )
  193. return false;
  194. // temporary items (items that will expire for any reason) cannot be turned into
  195. // permanent items
  196. if ( IsTemporaryItem() )
  197. return false;
  198. // explicitly marked not usable in crafting?
  199. if ( ( kEconItemFlag_CannotBeUsedInCrafting & GetFlags() ) != 0 )
  200. return false;
  201. // items gained in this way are not craftable
  202. switch ( GetOrigin() )
  203. {
  204. case kEconItemOrigin_Invalid:
  205. case kEconItemOrigin_Foreign:
  206. case kEconItemOrigin_StorePromotion:
  207. case kEconItemOrigin_SteamWorkshopContribution:
  208. return false;
  209. // purchased items can be used in crafting if explicitly tagged, but not by default
  210. case kEconItemOrigin_Purchased:
  211. // deny items the GC didn't flag at purchase time
  212. if ( (GetFlags() & kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012) == 0 )
  213. return false;
  214. // deny items that can never be used
  215. if ( (GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED) == 0 )
  216. return false;
  217. break;
  218. }
  219. // certain quality levels are not craftable
  220. if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
  221. return false;
  222. return true;
  223. }
  224. // --------------------------------------------------------------------------
  225. // Purpose:
  226. // --------------------------------------------------------------------------
  227. bool IEconItemInterface::IsMarketable() const
  228. {
  229. const CEconItemDefinition *pItemDef = GetItemDefinition();
  230. if ( pItemDef == NULL )
  231. return false;
  232. // Untradeable items can never be marketed, regardless of other rules.
  233. // Temporarily untradable items can be marketed, only permanent untradable items cannot be marketed
  234. if ( IsPermanentlyUntradable() )
  235. return false;
  236. // Items that are expired are never listable, regardless of other rules.
  237. RTime32 timeExpirationDate = GetExpirationDate();
  238. if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
  239. return false;
  240. // Initially, only TF2 supports listing items in the Marketplace.
  241. #if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
  242. {
  243. // User-created wrapped gifts are untradeable for the moment. This would provide a backdoor
  244. // for users to sell anything they wanted, which is interesting but not what we want in
  245. // the initial launch.
  246. if ( pItemDef->GetTypedEconTool<CEconTool_WrappedGift>() )
  247. return false;
  248. // All other tools are listable. This includes keys, paints, backpack expanders, strange
  249. // parts, Halloween spells, wedding rings, etc. It does not includes gifts (see above),
  250. // noisemakers, or crates (see below).
  251. if ( pItemDef->IsTool() )
  252. return true;
  253. // All crates are listable. Anything with the "decodable" flag is considered a crate.
  254. if ( (pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE) != 0 )
  255. return true;
  256. // Genuine-quality items come from time-limited purchase promos and are listable. Vintage
  257. // items are from one-time transitions and are all finite quality. Haunted quality items are
  258. // TF-Halloween-event specific. Some of the older haunted items didn't generate revenue, but
  259. // the content is all old and there seems to be little harm in letting it be listed. The
  260. // haunted items from 2013 all come from crates, which means they all generated revenue.
  261. // Collectors items are created from a finite set of recipes.
  262. // Paintkit Weapons are from cases or operations
  263. if ( GetQuality() == AE_RARITY1 || GetQuality() == AE_VINTAGE || GetQuality() == AE_HAUNTED
  264. || GetQuality() == AE_COLLECTORS || GetQuality() == AE_PAINTKITWEAPON )
  265. return true;
  266. // All festive items are from time-limited holiday crates and are listable. This code seems
  267. // safe. (...) (This code is in fact so safe that if we just do a substring match we'll also
  268. // allow "A Rather Festive Tree".)
  269. if ( !V_strncmp( pItemDef->GetDefinitionName(), "Festive", 7 ) )
  270. return true;
  271. // All botkiller items come from MvM rewards and are listable. This does a substring search
  272. // to find all varieties (gold, silver, rust, etc.), etc.
  273. if ( V_strstr( pItemDef->GetDefinitionName(), " Botkiller " ) )
  274. return true;
  275. // Mvm V2 Robit Parts
  276. if ( V_strstr( pItemDef->GetDefinitionName(), "Robits " ) )
  277. return true;
  278. // MvM Killstreak Weapons
  279. static CSchemaAttributeDefHandle pAttr_killstreak( "killstreak tier" );
  280. if ( FindAttribute( pAttr_killstreak ) )
  281. return true;
  282. // Australium Items
  283. static CSchemaAttributeDefHandle pAttrDef_IsAustralium( "is australium item" );
  284. if ( FindAttribute( pAttrDef_IsAustralium ) )
  285. return true;
  286. // Glitch GateHat Replacement Item
  287. static CSchemaItemDefHandle pItemDef_GlitchedCircuit( "Glitched Circuit Board" );
  288. if ( pItemDef == pItemDef_GlitchedCircuit )
  289. return true;
  290. // Anything that says it wants to be marketable.
  291. static CSchemaAttributeDefHandle pAttrDef_IsMarketable( "is marketable" );
  292. if ( FindAttribute( pAttrDef_IsMarketable ) )
  293. return true;
  294. // Anything that is of limited quantity (ie limited promos)
  295. static CSchemaAttributeDefHandle pAttrDef_IsLimited( "limited quantity item" );
  296. if ( FindAttribute( pAttrDef_IsLimited ) )
  297. return true;
  298. // Allow the Giving items (not a wrapped_gift but a gift, ie Secret Saxton, Pile O Gifts, Pallet of Keys)
  299. const CEconTool_Gift *pEconToolGift = pItemDef->GetTypedEconTool<CEconTool_Gift>();
  300. if ( pEconToolGift )
  301. return true;
  302. // Unusual Cosmetics and Taunts
  303. if ( GetQuality() == AE_UNUSUAL && ( GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT ) )
  304. return true;
  305. // Strange items. Dont just check for strange quality, actually check for a strange attribute.
  306. // See if we've got any strange attributes.
  307. for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
  308. {
  309. if ( FindAttribute( GetKillEaterAttr_Score( i ) ) )
  310. {
  311. return true;
  312. }
  313. }
  314. }
  315. #endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
  316. // By default, items aren't listable.
  317. return false;
  318. }
  319. // --------------------------------------------------------------------------
  320. const char *IEconItemInterface::GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue ) const
  321. {
  322. const GameItemDefinition_t *pDef = GetItemDefinition();
  323. if ( pDef )
  324. return pDef->GetDefinitionString( pszKeyName, pszDefaultValue );
  325. return pszDefaultValue;
  326. }
  327. // --------------------------------------------------------------------------
  328. KeyValues *IEconItemInterface::GetDefinitionKey( const char *pszKeyName ) const
  329. {
  330. const GameItemDefinition_t *pDef = GetItemDefinition();
  331. if ( pDef )
  332. return pDef->GetDefinitionKey( pszKeyName );
  333. return NULL;
  334. }