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
412 lines
14 KiB
//========= 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; |
|
}
|
|
|