summaryrefslogtreecommitdiff
path: root/game/shared/econ/econ_item_interface.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/shared/econ/econ_item_interface.cpp')
-rw-r--r--game/shared/econ/econ_item_interface.cpp412
1 files changed, 412 insertions, 0 deletions
diff --git a/game/shared/econ/econ_item_interface.cpp b/game/shared/econ/econ_item_interface.cpp
new file mode 100644
index 0000000..f915846
--- /dev/null
+++ b/game/shared/econ/econ_item_interface.cpp
@@ -0,0 +1,412 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+
+#include "cbase.h"
+#include "econ_item_interface.h"
+#include "econ_item_tools.h" // needed for CEconTool_WrappedGift definition for IsMarketable()
+#include "rtime.h"
+
+#ifdef STAGING_ONLY
+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." );
+#endif
+
+// --------------------------------------------------------------------------
+bool IEconItemInterface::GetCustomPaintKitWear( float &flWear ) const
+{
+
+#ifdef STAGING_ONLY
+ // don't assert in staging if this ConVar is set
+ if ( tf_paint_kit_force_wear.GetInt() > 0 )
+ {
+ flWear = tf_paint_kit_force_wear.GetFloat();
+ return true;
+ }
+#endif // STAGING_ONLY
+
+ static CSchemaAttributeDefHandle pAttrDef_PaintKitWear( "set_item_texture_wear" );
+ float flPaintKitWear = 0;
+ if ( pAttrDef_PaintKitWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_PaintKitWear, &flPaintKitWear ) )
+ {
+ flWear = flPaintKitWear;
+ return true;
+ }
+
+ static CSchemaAttributeDefHandle pAttrDef_DefaultWear( "texture_wear_default" );
+ if ( pAttrDef_DefaultWear && FindAttribute_UnsafeBitwiseCast<attrib_value_t>( this, pAttrDef_DefaultWear, &flPaintKitWear ) )
+ {
+ flWear = flPaintKitWear;
+ return true;
+ }
+ // If you have no wear, you also should not have a paint kit
+ AssertMsg( !GetCustomPainkKitDefinition(), "No Wear Found on Item [%llu - %s] that has a Paintkit!", GetID(), GetItemDefinition()->GetDefinitionName() );
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsTemporaryItem() const
+{
+ // store preview items are also temporary
+ if ( GetOrigin() == kEconItemOrigin_PreviewItem )
+ return true;
+
+ RTime32 rtTime = GetExpirationDate();
+ if ( rtTime > 0 )
+ return true;
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+RTime32 IEconItemInterface::GetExpirationDate() const
+{
+ COMPILE_TIME_ASSERT( sizeof( float ) == sizeof( RTime32 ) );
+
+ // dynamic attributes, if present, will override any static expiration timer
+ static CSchemaAttributeDefHandle pAttrib_ExpirationDate( "expiration date" );
+
+ attrib_value_t unAttribExpirationTimeBits;
+ COMPILE_TIME_ASSERT( sizeof( unAttribExpirationTimeBits ) == sizeof( RTime32 ) );
+
+ if ( pAttrib_ExpirationDate && FindAttribute( pAttrib_ExpirationDate, &unAttribExpirationTimeBits ) )
+ return *(RTime32 *)&unAttribExpirationTimeBits;
+
+ // do we have a static timer set in the schema for all instances to expire?
+ return GetItemDefinition()
+ ? GetItemDefinition()->GetExpirationDate()
+ : RTime32( 0 );
+}
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+RTime32 IEconItemInterface::GetTradableAfterDateTime() const
+{
+ static CSchemaAttributeDefHandle pAttrib_TradableAfter( "tradable after date" );
+ Assert( pAttrib_TradableAfter );
+
+ if ( !pAttrib_TradableAfter )
+ return 0;
+
+ RTime32 rtTimestamp;
+ if ( !FindAttribute( pAttrib_TradableAfter, &rtTimestamp ) )
+ return 0;
+
+ return rtTimestamp;
+}
+
+// --------------------------------------------------------------------------
+// Purpose: Return true if this item can never be traded
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsPermanentlyUntradable() const
+{
+ if ( GetItemDefinition() == NULL )
+ return true;
+
+ // tagged to not be a part of the economy?
+ if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
+ return true;
+
+ // check attributes
+
+ static CSchemaAttributeDefHandle pAttrib_AlwaysTradable( "always tradable" );
+ static CSchemaAttributeDefHandle pAttrib_CannotTrade( "cannot trade" );
+ static CSchemaAttributeDefHandle pAttrib_NonEconomy( "non economy" );
+
+ Assert( pAttrib_AlwaysTradable != NULL );
+ Assert( pAttrib_CannotTrade != NULL );
+
+ if ( pAttrib_AlwaysTradable == NULL || pAttrib_CannotTrade == NULL || pAttrib_NonEconomy == NULL )
+ return true;
+
+ // Order matters, check for nonecon first. Always tradable overrides cannot trade.
+ if ( FindAttribute( pAttrib_NonEconomy ) )
+ return true;
+
+ if ( FindAttribute( pAttrib_AlwaysTradable ) ) // *sigh*
+ return false;
+
+ if ( FindAttribute( pAttrib_CannotTrade ) )
+ return true;
+
+ // items gained in this way are not tradable
+ switch ( GetOrigin() )
+ {
+ case kEconItemOrigin_Invalid:
+ case kEconItemOrigin_Achievement:
+ case kEconItemOrigin_Foreign:
+ case kEconItemOrigin_PreviewItem:
+ case kEconItemOrigin_SteamWorkshopContribution:
+ return true;
+ }
+
+ // temporary items (items that will expire for any reason) cannot be traded
+ if ( IsTemporaryItem() )
+ return true;
+
+ // certain quality levels are not tradable
+ if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
+ return true;
+
+ // explicitly marked cannot trade?
+ if ( ( kEconItemFlag_CannotTrade & GetFlags() ) != 0 )
+ return true;
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+// Purpose: Return true if this item is a commodity on the Market (can place buy orders)
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsCommodity() const
+{
+ if ( GetItemDefinition() == NULL )
+ return false;
+
+ static CSchemaAttributeDefHandle pAttrib_IsCommodity( "is commodity" );
+ if ( FindAttribute( pAttrib_IsCommodity ) )
+ return true;
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+// Purpose: Return true if temporarily untradable
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsTemporarilyUntradable() const
+{
+ // Temporary untradability does NOT take "always tradable" into account
+ if ( GetTradableAfterDateTime() >= CRTime::RTime32TimeCur() )
+ return true;
+
+ return false;
+}
+
+// --------------------------------------------------------------------------
+// Purpose: Return true if this item is untradable
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsTradable() const
+{
+ // Items that are expired are never listable, regardless of other rules.
+ //RTime32 timeExpirationDate = GetExpirationDate();
+ //if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
+ // return false;
+
+ return GetUntradabilityFlags() == 0;
+}
+
+// --------------------------------------------------------------------------
+// Purpose: Return untradability flags
+// --------------------------------------------------------------------------
+int IEconItemInterface::GetUntradabilityFlags() const
+{
+ int nFlags = 0;
+ if ( IsTemporarilyUntradable() )
+ {
+ nFlags |= k_Untradability_Temporary;
+ }
+
+ if ( IsPermanentlyUntradable() )
+ {
+ nFlags |= k_Untradability_Permanent;
+ }
+
+ return nFlags;
+}
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsUsableInCrafting() const
+{
+ if ( GetItemDefinition() == NULL )
+ return false;
+
+ // tagged to not be a part of the economy?
+ if ( ( kEconItemFlag_NonEconomy & GetFlags() ) != 0 )
+ return false;
+
+ // always craftable?
+ static CSchemaAttributeDefHandle pAttrib_AlwaysUsableInCraft( "always tradable" );
+ Assert( pAttrib_AlwaysUsableInCraft );
+
+ if ( FindAttribute( pAttrib_AlwaysUsableInCraft ) )
+ return true;
+
+ // never craftable?
+ static CSchemaAttributeDefHandle pAttrib_NeverCraftable( "never craftable" );
+ Assert( pAttrib_NeverCraftable );
+
+ if ( FindAttribute( pAttrib_NeverCraftable ) )
+ return false;
+
+ // temporary items (items that will expire for any reason) cannot be turned into
+ // permanent items
+ if ( IsTemporaryItem() )
+ return false;
+
+ // explicitly marked not usable in crafting?
+ if ( ( kEconItemFlag_CannotBeUsedInCrafting & GetFlags() ) != 0 )
+ return false;
+
+ // items gained in this way are not craftable
+ switch ( GetOrigin() )
+ {
+ case kEconItemOrigin_Invalid:
+ case kEconItemOrigin_Foreign:
+ case kEconItemOrigin_StorePromotion:
+ case kEconItemOrigin_SteamWorkshopContribution:
+ return false;
+
+ // purchased items can be used in crafting if explicitly tagged, but not by default
+ case kEconItemOrigin_Purchased:
+ // deny items the GC didn't flag at purchase time
+ if ( (GetFlags() & kEconItemFlag_PurchasedAfterStoreCraftabilityChanges2012) == 0 )
+ return false;
+
+ // deny items that can never be used
+ if ( (GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_CRAFTED_IF_PURCHASED) == 0 )
+ return false;
+
+ break;
+ }
+
+ // certain quality levels are not craftable
+ if ( GetQuality() >= AE_COMMUNITY && GetQuality() <= AE_SELFMADE )
+ return false;
+
+ return true;
+}
+
+// --------------------------------------------------------------------------
+// Purpose:
+// --------------------------------------------------------------------------
+bool IEconItemInterface::IsMarketable() const
+{
+ const CEconItemDefinition *pItemDef = GetItemDefinition();
+ if ( pItemDef == NULL )
+ return false;
+
+ // Untradeable items can never be marketed, regardless of other rules.
+ // Temporarily untradable items can be marketed, only permanent untradable items cannot be marketed
+ if ( IsPermanentlyUntradable() )
+ return false;
+
+ // Items that are expired are never listable, regardless of other rules.
+ RTime32 timeExpirationDate = GetExpirationDate();
+ if ( timeExpirationDate > 0 && timeExpirationDate < CRTime::RTime32TimeCur() )
+ return false;
+
+ // Initially, only TF2 supports listing items in the Marketplace.
+#if defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
+ {
+ // User-created wrapped gifts are untradeable for the moment. This would provide a backdoor
+ // for users to sell anything they wanted, which is interesting but not what we want in
+ // the initial launch.
+ if ( pItemDef->GetTypedEconTool<CEconTool_WrappedGift>() )
+ return false;
+
+ // All other tools are listable. This includes keys, paints, backpack expanders, strange
+ // parts, Halloween spells, wedding rings, etc. It does not includes gifts (see above),
+ // noisemakers, or crates (see below).
+ if ( pItemDef->IsTool() )
+ return true;
+
+ // All crates are listable. Anything with the "decodable" flag is considered a crate.
+ if ( (pItemDef->GetCapabilities() & ITEM_CAP_DECODABLE) != 0 )
+ return true;
+
+ // Genuine-quality items come from time-limited purchase promos and are listable. Vintage
+ // items are from one-time transitions and are all finite quality. Haunted quality items are
+ // TF-Halloween-event specific. Some of the older haunted items didn't generate revenue, but
+ // the content is all old and there seems to be little harm in letting it be listed. The
+ // haunted items from 2013 all come from crates, which means they all generated revenue.
+ // Collectors items are created from a finite set of recipes.
+ // Paintkit Weapons are from cases or operations
+ if ( GetQuality() == AE_RARITY1 || GetQuality() == AE_VINTAGE || GetQuality() == AE_HAUNTED
+ || GetQuality() == AE_COLLECTORS || GetQuality() == AE_PAINTKITWEAPON )
+ return true;
+
+ // All festive items are from time-limited holiday crates and are listable. This code seems
+ // safe. (...) (This code is in fact so safe that if we just do a substring match we'll also
+ // allow "A Rather Festive Tree".)
+ if ( !V_strncmp( pItemDef->GetDefinitionName(), "Festive", 7 ) )
+ return true;
+
+ // All botkiller items come from MvM rewards and are listable. This does a substring search
+ // to find all varieties (gold, silver, rust, etc.), etc.
+ if ( V_strstr( pItemDef->GetDefinitionName(), " Botkiller " ) )
+ return true;
+
+ // Mvm V2 Robit Parts
+ if ( V_strstr( pItemDef->GetDefinitionName(), "Robits " ) )
+ return true;
+
+ // MvM Killstreak Weapons
+ static CSchemaAttributeDefHandle pAttr_killstreak( "killstreak tier" );
+ if ( FindAttribute( pAttr_killstreak ) )
+ return true;
+
+ // Australium Items
+ static CSchemaAttributeDefHandle pAttrDef_IsAustralium( "is australium item" );
+ if ( FindAttribute( pAttrDef_IsAustralium ) )
+ return true;
+
+ // Glitch GateHat Replacement Item
+ static CSchemaItemDefHandle pItemDef_GlitchedCircuit( "Glitched Circuit Board" );
+ if ( pItemDef == pItemDef_GlitchedCircuit )
+ return true;
+
+ // Anything that says it wants to be marketable.
+ static CSchemaAttributeDefHandle pAttrDef_IsMarketable( "is marketable" );
+ if ( FindAttribute( pAttrDef_IsMarketable ) )
+ return true;
+
+ // Anything that is of limited quantity (ie limited promos)
+ static CSchemaAttributeDefHandle pAttrDef_IsLimited( "limited quantity item" );
+ if ( FindAttribute( pAttrDef_IsLimited ) )
+ return true;
+
+ // Allow the Giving items (not a wrapped_gift but a gift, ie Secret Saxton, Pile O Gifts, Pallet of Keys)
+ const CEconTool_Gift *pEconToolGift = pItemDef->GetTypedEconTool<CEconTool_Gift>();
+ if ( pEconToolGift )
+ return true;
+
+ // Unusual Cosmetics and Taunts
+ if ( GetQuality() == AE_UNUSUAL && ( GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_MISC || GetItemDefinition()->GetLoadoutSlot( 0 ) == LOADOUT_POSITION_TAUNT ) )
+ return true;
+
+ // Strange items. Dont just check for strange quality, actually check for a strange attribute.
+ // See if we've got any strange attributes.
+ for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
+ {
+ if ( FindAttribute( GetKillEaterAttr_Score( i ) ) )
+ {
+ return true;
+ }
+ }
+ }
+#endif // defined( TF_DLL ) || defined( TF_CLIENT_DLL ) || defined( TF_GC_DLL )
+
+ // By default, items aren't listable.
+ return false;
+}
+
+// --------------------------------------------------------------------------
+const char *IEconItemInterface::GetDefinitionString( const char *pszKeyName, const char *pszDefaultValue ) const
+{
+ const GameItemDefinition_t *pDef = GetItemDefinition();
+ if ( pDef )
+ return pDef->GetDefinitionString( pszKeyName, pszDefaultValue );
+ return pszDefaultValue;
+}
+
+// --------------------------------------------------------------------------
+KeyValues *IEconItemInterface::GetDefinitionKey( const char *pszKeyName ) const
+{
+ const GameItemDefinition_t *pDef = GetItemDefinition();
+ if ( pDef )
+ return pDef->GetDefinitionKey( pszKeyName );
+ return NULL;
+}