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

//========= 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;
}