summaryrefslogtreecommitdiff
path: root/game/client/econ/backpack_panel.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/econ/backpack_panel.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/econ/backpack_panel.cpp')
-rw-r--r--game/client/econ/backpack_panel.cpp4272
1 files changed, 4272 insertions, 0 deletions
diff --git a/game/client/econ/backpack_panel.cpp b/game/client/econ/backpack_panel.cpp
new file mode 100644
index 0000000..eb90d6b
--- /dev/null
+++ b/game/client/econ/backpack_panel.cpp
@@ -0,0 +1,4272 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include "backpack_panel.h"
+#include "item_confirm_delete_dialog.h"
+#include "vgui/ISurface.h"
+#include "gamestringpool.h"
+#include "iclientmode.h"
+#include "econ_item_inventory.h"
+#include "ienginevgui.h"
+#include <vgui/ILocalize.h>
+#include "vgui_controls/TextImage.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/ScalableImagePanel.h"
+#include "vgui/IInput.h"
+#include "econ/tool_items/tool_items.h"
+#include "econ_gcmessages.h"
+#include "item_style_select_dialog.h"
+#include "econ_item_system.h"
+#include "econ_item_tools.h"
+#include "econ_ui.h"
+#include "gc_clientsystem.h"
+#include "econ_store.h"
+#include "rtime.h"
+#include "econ_item_description.h"
+#include "dynamic_recipe_subpanel.h"
+#include "item_slot_panel.h"
+#include "crate_detail_panels.h"
+#include "tf_warinfopanel.h"
+#include "character_info_panel.h"
+#include "trading_start_dialog.h"
+#include "vgui_controls/MenuItem.h"
+#include "tf_duckleaderboard.h"
+#include "tf_item_inventory.h"
+#include "store/store_panel.h"
+#include "strange_count_transfer_panel.h"
+#include "collection_crafting_panel.h"
+#include "halloween_offering_panel.h"
+#include "store/v2/tf_store_preview_item2.h"
+#include "item_ad_panel.h"
+#include "client_community_market.h"
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+#ifdef STAGING_ONLY
+extern ConVar tf_use_card_tooltips;
+extern ConVar tf_weapon_force_allow_inspect;
+#endif // STAGING_ONLY
+
+ConVar tf_trade_up_use_count( "tf_trade_up_use_count", "3", FCVAR_ARCHIVE | FCVAR_HIDDEN );
+
+
+void UseConsumableItem( CEconItemView *pItem, vgui::Panel* pParent );
+
+const ItemSortTypeData_t g_BackpackSortTypes[] =
+{
+ { "#Backpack_SortBy_Header", kGCItemSort_NoSort },
+ { "#Backpack_SortBy_Rarity", kGCItemSort_SortByRarity },
+ { "#Backpack_SortBy_Type", kGCItemSort_SortByType },
+ { "#Backpack_SortBy_Class", kTFGCItemSort_SortByClass },
+ { "#Backpack_SortBy_Slot", kTFGCItemSort_SortBySlot },
+ { "#Backpack_SortBy_Date", kGCItemSort_SortByDate },
+};
+
+// Array of borders for rarities. Three borders for each rarity: Base, Mouseover, and Selected
+const char *g_szItemBorders[][5] =
+{
+ { "BackpackItemBorder", "BackpackItemMouseOverBorder", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder", "BackpackItemGreyedOutSelectedBorder" }, // AE_NORMAL = 0
+ { "BackpackItemBorder_1", "BackpackItemMouseOverBorder_1", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_1", "BackpackItemGreyedOutSelectedBorder_1" }, // AE_RARITY1 = 1
+ { "BackpackItemBorder_2", "BackpackItemMouseOverBorder_2", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_2", "BackpackItemGreyedOutSelectedBorder_2" }, // AE_RARITY2 = 2
+ { "BackpackItemBorder_Vintage", "BackpackItemMouseOverBorder_Vintage", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Vintage", "BackpackItemGreyedOutSelectedBorder_Vintage" }, // AE_VINTAGE = 3
+ { "BackpackItemBorder_3", "BackpackItemMouseOverBorder_3", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_3", "BackpackItemGreyedOutSelectedBorder_3" }, // AE_RARITY3
+ { "BackpackItemBorder_4", "BackpackItemMouseOverBorder_4", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_4", "BackpackItemGreyedOutSelectedBorder_4" }, // AE_RARITY4
+ { "BackpackItemBorder_Unique", "BackpackItemMouseOverBorder_Unique", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Unique", "BackpackItemGreyedOutSelectedBorder_Unique" }, // AE_UNIQUE
+ { "BackpackItemBorder_Community", "BackpackItemMouseOverBorder_Community", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Community", "BackpackItemGreyedOutSelectedBorder_Community" }, // AE_COMMUNITY
+ { "BackpackItemBorder_Developer", "BackpackItemMouseOverBorder_Developer", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Developer", "BackpackItemGreyedOutSelectedBorder_Developer" }, // AE_DEVELOPER
+ { "BackpackItemBorder_SelfMade", "BackpackItemMouseOverBorder_SelfMade", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_SelfMade", "BackpackItemGreyedOutSelectedBorder_SelfMade" }, // AE_SELFMADE
+ { "BackpackItemBorder_Customized", "BackpackItemMouseOverBorder_Customized", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Customized", "BackpackItemGreyedOutSelectedBorder_Customized" }, // AE_CUSTOMIZED
+ { "BackpackItemBorder_Strange", "BackpackItemMouseOverBorder_Strange", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Strange", "BackpackItemGreyedOutSelectedBorder_Strange" }, // AE_STRANGE
+ { "BackpackItemBorder_Completed", "BackpackItemMouseOverBorder_Completed", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Completed", "BackpackItemGreyedOutSelectedBorder_Completed" }, // AE_COMPLETED
+ { "BackpackItemBorder_Haunted", "BackpackItemMouseOverBorder_Haunted", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Haunted", "BackpackItemGreyedOutSelectedBorder_Haunted" }, // AE_HAUNTED
+ { "BackpackItemBorder_Collectors", "BackpackItemMouseOverBorder_Collectors", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_Collectors", "BackpackItemGreyedOutSelectedBorder_Collectors" }, // AE_COLLECTORS
+
+ { "BackpackItemBorder_PaintkitWeapon", "BackpackItemMouseOverBorder_PaintkitWeapon", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_PaintkitWeapon", "BackpackItemGreyedOutSelectedBorder_PaintkitWeapon" }, // AE_Paintkit
+ { "BackpackItemBorder_RarityDefault", "BackpackItemMouseOverBorder_RarityDefault", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityDefault", "BackpackItemGreyedOutSelectedBorder_RarityDefault" }, // AE_RARITY_DEFAULT,
+ { "BackpackItemBorder_RarityCommon", "BackpackItemMouseOverBorder_RarityCommon", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityCommon", "BackpackItemGreyedOutSelectedBorder_RarityCommon" }, // AE_RARITY_COMMON,
+ { "BackpackItemBorder_RarityUncommon", "BackpackItemMouseOverBorder_RarityUncommon", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityUncommon", "BackpackItemGreyedOutSelectedBorder_RarityUncommon" }, // AE_RARITY_UNCOMMON,
+ { "BackpackItemBorder_RarityRare", "BackpackItemMouseOverBorder_RarityRare", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityRare", "BackpackItemGreyedOutSelectedBorder_RarityRare" }, // AE_RARITY_RARE,
+ { "BackpackItemBorder_RarityMythical", "BackpackItemMouseOverBorder_RarityMythical", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityMythical", "BackpackItemGreyedOutSelectedBorder_RarityMythical" }, // AE_RARITY_MYTHICAL,
+ { "BackpackItemBorder_RarityLegendary", "BackpackItemMouseOverBorder_RarityLegendary", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityLegendary", "BackpackItemGreyedOutSelectedBorder_RarityLegendary" }, // AE_RARITY_LEGENDARY,
+ { "BackpackItemBorder_RarityAncient", "BackpackItemMouseOverBorder_RarityAncient", "BackpackItemSelectedBorder", "BackpackItemGreyedOutBorder_RarityAncient", "BackpackItemGreyedOutSelectedBorder_RarityAncient" }, // AE_RARITY_ANCIENT,
+};
+
+COMPILE_TIME_ASSERT( ARRAYSIZE(g_szItemBorders) == AE_MAX_TYPES );
+
+enum { kNoUserData = -1 };
+
+static bool HasPaint ( const CEconItemView *pEconItemView, const char *, int )
+{
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB2( "set item tint RGB 2" );
+
+ return pEconItemView->FindAttribute( pAttrDef_PaintRGB )
+ || pEconItemView->FindAttribute( pAttrDef_PaintRGB2 );
+}
+
+static bool HasCustomAttribute ( const CEconItemView *pEconItemView, const char *szAttrName, int )
+{
+ const CEconItemAttributeDefinition *pAttrDef = GetItemSchema()->GetAttributeDefinitionByName( szAttrName );
+
+ return pAttrDef
+ ? pEconItemView->FindAttribute( pAttrDef )
+ : NULL;
+}
+
+static bool HasCustomUserAttribute ( const CEconItemView *pEconItemView, const char *, int iUserData )
+{
+ Assert( iUserData != kNoUserData );
+
+ CCountUserGeneratedAttributeIterator countIterator;
+ pEconItemView->IterateAttributes( &countIterator );
+
+ return countIterator.GetCount() > iUserData;
+}
+
+static bool HasRemovableCustomName ( const CEconItemView *pEconItemView, const char *, int )
+{
+ if ( !pEconItemView->GetItemDefinition() )
+ return false;
+
+ if ( pEconItemView->GetQuality() == AE_UNIQUE && pEconItemView->GetItemDefinition()->GetArmoryDescString() && !V_stricmp( pEconItemView->GetItemDefinition()->GetArmoryDescString(), "stockitem" ) )
+ return false;
+
+ return pEconItemView->GetSOCData() && pEconItemView->GetSOCData()->GetCustomName();
+}
+
+static bool HasRemovableCustomDesc ( const CEconItemView *pEconItemView, const char *, int )
+{
+ if ( !pEconItemView->GetItemDefinition() )
+ return false;
+
+ if ( pEconItemView->GetQuality() == AE_UNIQUE && pEconItemView->GetItemDefinition()->GetArmoryDescString() && !V_stricmp( pEconItemView->GetItemDefinition()->GetArmoryDescString(), "stockitem" ) )
+ return false;
+
+ return pEconItemView->GetSOCData() && pEconItemView->GetSOCData()->GetCustomDesc();
+}
+
+enum EItemCustomizationRemoveType
+{
+ kCustomizationRemove_Paint,
+ kCustomizationRemove_Name,
+ kCustomizationRemove_Desc,
+ kCustomizationRemove_CustomTexture,
+ kCustomizationRemove_MakersMark,
+ kCustomizationRemove_UniqueCraftIndex,
+ kCustomizationRemove_StrangePart,
+ kCustomizationRemove_StrangeScores,
+ kCustomizationRemove_UpgradeCard,
+ kCustomizationRemove_KillStreak,
+ kCustomizationRemove_GiftedBy,
+ kCustomizationRemove_Festivizer,
+};
+
+typedef bool (* HasRefurbishablePropertyFunc_t)( const CEconItemView *pEconItemView, const char *pArg, int iUserData );
+
+void GetCustomDialogToken_PaintName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
+{
+ extern const CEconItemDefinition *GetPaintItemDefinitionForPaintedItem( const IEconItemInterface *pEconItem );
+
+ Assert( iUserData == kNoUserData );
+
+ const CEconItemDefinition *pPaintItemDef = GetPaintItemDefinitionForPaintedItem( pEconItemView );
+ if ( !pPaintItemDef )
+ {
+ out_String = L"";
+ return;
+ }
+
+ out_String = GLocalizationProvider()->Find( pPaintItemDef->GetItemBaseName() );
+}
+
+void GetCustomDialogToken_StrangePartName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
+{
+ extern uint32 GetScoreTypeForKillEaterAttr( const IEconItemInterface *pEconItem, const CEconItemAttributeDefinition *pAttribDef );
+ extern const wchar_t *GetLocalizedStringForKillEaterTypeAttr( const CLocalizationProvider *pLocalizationProvider, uint32 unKillEaterEventType ); // return type changed from locchar_t * because the backpack panel only exists on the client
+
+ uint32 unKillEaterBaseType = GetScoreTypeForKillEaterAttr( pEconItemView, GetKillEaterAttr_Type( iUserData ) );
+
+ out_String = GetLocalizedStringForKillEaterTypeAttr( GLocalizationProvider(), unKillEaterBaseType );
+}
+
+void GetCustomDialogToken_UserAttributeName( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String )
+{
+ Assert( pEconItemView );
+
+ const CEconItemAttributeDefinition *pAttrDef = GetCardUpgradeForIndex( pEconItemView, iUserData );
+ if ( !pAttrDef )
+ {
+ out_String = L"unknown";
+ return;
+ }
+
+ attrib_value_t attrVal;
+ Verify( pEconItemView->FindAttribute( pAttrDef, &attrVal ) );
+ CEconAttributeDescription attrDesc( GLocalizationProvider(), pAttrDef, attrVal );
+ out_String = attrDesc.GetShortDescription();
+}
+
+typedef void (* GetCustomDialogLocalizationTokenFunc_t)( const CEconItemView *pEconItemView, int iUserData, CUtlConstWideString& out_String );
+
+struct RefurbishableProperty
+{
+ HasRefurbishablePropertyFunc_t m_pFunc;
+ GetCustomDialogLocalizationTokenFunc_t m_pGetCustomDialogLocalizationTokenFunc;
+ const char *m_szArg;
+ const char *m_pszSelectionUILocalizationToken;
+ const char *m_szDialogTitle;
+ const char *m_szDialogDesc;
+ EItemCustomizationRemoveType m_eRemovalType;
+ int m_iUserData;
+};
+
+// TODO: Add Gifted by Tag here
+static RefurbishableProperty g_RemoveableAttributes[] =
+{
+ { &HasRemovableCustomName, NULL, NULL, "#RefurbishItem_RemoveNameCombo", "#RefurbishItem_RemoveNameTitle", "#RefurbishItem_RemoveName", kCustomizationRemove_Name, kNoUserData }, // does this item have a custom name?
+ { &HasRemovableCustomDesc, NULL, NULL, "#RefurbishItem_RemoveDescCombo", "#RefurbishItem_RemoveDescTitle", "#RefurbishItem_RemoveDesc", kCustomizationRemove_Desc, kNoUserData }, // does this item have a custom description?
+ { &HasPaint, &GetCustomDialogToken_PaintName, "set item tint rgb", "#RefurbishItem_RemovePaintCombo", "#RefurbishItem_RemovePaintTitle", "#RefurbishItem_RemovePaint", kCustomizationRemove_Paint, kNoUserData }, // is this item painted?
+ { &HasCustomAttribute, NULL, "custom texture hi", "#RefurbishItem_RemoveCustomTextureCombo", "#RefurbishItem_RemoveCustomTextureTitle", "#RefurbishItem_RemoveCustomTexture", kCustomizationRemove_CustomTexture, kNoUserData }, // does this have a custom texture applied?
+ { &HasCustomAttribute, NULL, "makers mark id", "#RefurbishItem_RemoveMakersMarkCombo", "#RefurbishItem_RemoveMakersMarkTitle", "#RefurbishItem_RemoveMakersMark", kCustomizationRemove_MakersMark, kNoUserData }, // was this item crafted by a specific dude?
+ { &HasCustomAttribute, NULL, "killstreak tier", "#RefurbishItem_RemoveKillStreakCombo", "#RefurbishItem_RemoveKillStreakTitle", "#RefurbishItem_RemoveKillStreak", kCustomizationRemove_KillStreak, kNoUserData }, // Killstreak Effect
+ { &HasCustomAttribute, NULL, "gifter account id", "#RefurbishItem_RemoveGifterCombo", "#RefurbishItem_RemoveGifterTitle", "#RefurbishItem_RemoveGifter", kCustomizationRemove_GiftedBy, kNoUserData }, // Gifted by
+ { &HasCustomAttribute, NULL, "is_festivized", "#RefurbishItem_RemoveFestivizerCombo", "#RefurbishItem_RemoveFestivizerTitle", "#RefurbishItem_RemoveFestivizer", kCustomizationRemove_Festivizer, kNoUserData }, // Festivizer
+
+ //"gifter account id", // who gifted us this item? (will also remove "event date")
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Look over this weapon to see if it has any strange stat counters to reset optionally.
+//-----------------------------------------------------------------------------
+static bool HasResettableScoreAttributes ( const CEconItemView *pEconItemView, const char *, int )
+{
+ if ( !pEconItemView )
+ return false;
+
+ for ( int i = 0; i < GetKillEaterAttrCount(); i++ )
+ {
+ uint32 unScore;
+ if ( pEconItemView->FindAttribute( GetKillEaterAttr_Score( i ), &unScore ) && unScore > 0 )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int GetRemovableAttributesCount()
+{
+ return ARRAYSIZE( g_RemoveableAttributes )
+ + GetKillEaterAttrCount()
+ + GetMaxCardUpgradesPerItem() // remove card upgrades
+ + 1; // strange quality item score reset
+}
+
+RefurbishableProperty RemovableAttributes_GetAttributeDetails( int i )
+{
+ Assert( i >= 0 );
+ Assert( i < GetRemovableAttributesCount() );
+
+ if ( i < ARRAYSIZE( g_RemoveableAttributes ) )
+ return g_RemoveableAttributes[i];
+
+ // Which attribute in particular are we looking for?
+ int iStrangePartIndex = i - ARRAYSIZE( g_RemoveableAttributes );
+ if ( iStrangePartIndex < GetKillEaterAttrCount() )
+ {
+ int iKillEaterAttrIndex = (GetKillEaterAttrCount() - GetKillEaterAttrCount()) + iStrangePartIndex;
+
+ // if we're looking at strange attributes...
+ if ( GetKillEaterAttr_IsUserCustomizable( iKillEaterAttrIndex ) )
+ {
+ // Common properties for all strange part attributes.
+ static RefurbishableProperty sStrangePartProperty = { &HasCustomAttribute, &GetCustomDialogToken_StrangePartName, NULL, "#RefurbishItem_RemoveStrangePartCombo", "#RefurbishItem_RemoveStrangePartTitle", "#RefurbishItem_RemoveStrangePart", kCustomizationRemove_StrangePart, kNoUserData };
+
+ RefurbishableProperty partReturnProp = sStrangePartProperty;
+ partReturnProp.m_szArg = GetKillEaterAttr_Score( iKillEaterAttrIndex )->GetDefinitionName(); // ...then we check for the presence of a score attribute if this slot is a strange part...
+ partReturnProp.m_iUserData = iKillEaterAttrIndex;
+
+ return partReturnProp;
+ }
+
+ // ...or the presence of a restriction attribute if this slot is a base slot that might have a filter
+ static RefurbishableProperty sStrangeFilterProperty = { &HasCustomAttribute, &GetCustomDialogToken_StrangePartName, NULL, "#RefurbishItem_RemoveStrangeFilterCombo", "#RefurbishItem_RemoveStrangeFilterTitle", "#RefurbishItem_RemoveStrangeFilter", kCustomizationRemove_StrangePart, kNoUserData };
+
+ RefurbishableProperty filterReturnProp = sStrangeFilterProperty;
+ filterReturnProp.m_szArg = GetKillEaterAttr_Restriction( iKillEaterAttrIndex )->GetDefinitionName();
+ filterReturnProp.m_iUserData = iKillEaterAttrIndex;
+
+ return filterReturnProp;
+ }
+
+ // Look for any properties that were user-assigned. We allow users to remove them.
+ int iCardUpgradeIndex = iStrangePartIndex - GetKillEaterAttrCount();
+ if ( iCardUpgradeIndex < GetMaxCardUpgradesPerItem() )
+ {
+ // Common properties for all card upgrade attributes.
+ static RefurbishableProperty sCardUpgradeProperty = { &HasCustomUserAttribute, &GetCustomDialogToken_UserAttributeName, NULL, "#RefurbishItem_RemoveSpellCombo", "#RefurbishItem_RemoveSpellTitle", "#RefurbishItem_RemoveSpellUpgrade", kCustomizationRemove_UpgradeCard, kNoUserData };
+
+ RefurbishableProperty returnProp = sCardUpgradeProperty;
+ // FIX THIS FOR CARDS / SPELLS?
+ // returnProp.m_szArg = GetCustomDialogToken_UserAttributeName ?
+ returnProp.m_iUserData = iCardUpgradeIndex;
+
+ return returnProp;
+ }
+
+ // We might also be trying to reset the strange score counters.
+ Assert( iStrangePartIndex == GetKillEaterAttrCount() + GetMaxCardUpgradesPerItem() );
+ Assert( i == GetRemovableAttributesCount() - 1 );
+
+ static RefurbishableProperty sStrangeScoreReset = { &HasResettableScoreAttributes, NULL, NULL, "#RefurbishItem_RemoveStrangeScoresCombo", "#RefurbishItem_RemoveStrangeScoresTitle", "#RefurbishItem_RemoveStrangeScores", kCustomizationRemove_StrangeScores, kNoUserData };
+ return sStrangeScoreReset;
+}
+
+bool RemovableAttributes_DoesAttributeApply( int i, const CEconItemView *pEconItemView )
+{
+ static CSchemaAttributeDefHandle pAttr_CannotRestore( "cannot restore" );
+ if ( pEconItemView->FindAttribute( pAttr_CannotRestore ) )
+ return false;
+
+ RefurbishableProperty attr = RemovableAttributes_GetAttributeDetails( i );
+
+ return attr.m_pFunc( pEconItemView, attr.m_szArg, attr.m_iUserData );
+}
+
+bool RemovableAttributes_DoAnyAttributesApply( const CEconItemView *pEconItemView )
+{
+ static CSchemaAttributeDefHandle pAttr_CannotRestore( "cannot restore" );
+ if ( pEconItemView->FindAttribute( pAttr_CannotRestore ) )
+ return false;
+
+ for ( int i = 0; i < GetRemovableAttributesCount(); i++ )
+ {
+ if ( RemovableAttributes_DoesAttributeApply( i, pEconItemView ) )
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ConVar cl_showbackpackrarities( "cl_showbackpackrarities", "0", FCVAR_ARCHIVE, "0 = Show no backpack icon border colors. 1 = Show item rarities within the backpack. 2 = Show item rarities only for Market-listable items." );
+ConVar cl_show_market_data_on_items( "cl_show_market_data_on_items", "1", FCVAR_ARCHIVE, "0 = Never. 1 = Only when showing borders for Market-listable items. 2 = Always." );
+
+ConVar tf_explanations_backpackpanel( "tf_explanations_backpackpanel", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." );
+
+ConVar tf_backpack_page_button_delay( "tf_backpack_page_button_delay", "0.5", FCVAR_ARCHIVE, "Amount of time the mouse cursor needs to hover over the page button to select the page." );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CBackpackPanel::CBackpackPanel( vgui::Panel *parent, const char *panelName ) : CBaseLoadoutPanel( parent, panelName )
+{
+ m_nQuickOpenTxn = 0;
+ m_pContextMenu = NULL;
+ m_pPageButtonKVs = NULL;
+ m_mapSeenItems.SetLessFunc( DefLessFunc( itemid_t ) );
+ m_bInitializedSeenItems = false;
+ m_pNameFilterTextEntry = NULL;
+ m_flFilterItemTime = 0.f;
+ m_mapFilteringItems.SetLessFunc( DefLessFunc(int) );
+
+ m_pNextPageButton = NULL;
+ m_pPrevPageButton = NULL;
+ m_pShowExplanationsButton = NULL;
+ m_pCurPageLabel = NULL;
+ m_pSortByComboBox = NULL;
+ m_pShowRarityComboBox = NULL;
+ m_pShowBaseItemsCheckbox = NULL;
+ m_pDragToNextPageButton = NULL;
+ m_pDragToPrevPageButton = NULL;
+ m_flPreventDragPageSwitchUntil = 0;
+ m_flStartExplanationsAt = 0;
+
+ m_flMouseDownTime = 0;
+ m_pItemDraggedFromPanel = NULL;
+ m_iDraggedFromPage = 0;
+ m_bMouseDownOnItemPanel = false;
+ m_bDragging = false;
+ m_iMouseDownX = m_iMouseDownY = 0;
+
+ m_pMouseDragItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mousedragitempanel" ) );
+ m_pCancelToolButton = NULL;
+ m_pCraftButton = NULL;
+ m_bShowBaseItems = false;
+ m_pConfirmDeleteDialog = NULL;
+ m_pToolIcon = NULL;
+ m_eSelectionMode = StandardSelection;
+ m_nLastToolPage = 0;
+ m_pDynamicRecipePanel = NULL;
+ m_pItemSlotPanel = NULL;
+ m_pStrangeToolPanel = NULL;
+
+ m_nNumActivePages = 0;
+
+ m_pInspectPanel = new CTFItemInspectionPanel( this, "InspectionPanel" );
+ m_pInspectCosmeticPanel = new CTFStorePreviewItemPanel2( this, "Resource/UI/econ/InspectionPanel_Cosmetic.res", "storepreviewitem", NULL );
+ m_pCollectionCraftPanel = NULL;
+ m_pHalloweenOfferingPanel = NULL;
+ m_pMannCoTradePanel = NULL;
+
+ CancelToolSelection();
+
+ ListenForGameEvent( "gc_connected" );
+}
+
+CBackpackPanel::~CBackpackPanel()
+{
+ if ( m_pPageButtonKVs )
+ {
+ m_pPageButtonKVs->deleteThis();
+ m_pPageButtonKVs = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ if ( !m_pSortByComboBox && UsesRarityControls() )
+ {
+ m_pSortByComboBox = new vgui::ComboBox( this, "SortByComboBox", 5, false );
+ m_pSortByComboBox->AddActionSignalTarget( this );
+ }
+
+ LoadControlSettings( GetResFile() );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pNameFilterTextEntry = FindControl<vgui::TextEntry>( "NameFilterTextEntry" );
+ if ( m_pNameFilterTextEntry )
+ {
+ m_pNameFilterTextEntry->AddActionSignalTarget( this );
+ }
+
+ m_pCancelToolButton = dynamic_cast<CExButton*>( FindChildByName("CancelApplyToolButton") );
+ m_pCraftButton = dynamic_cast<CExButton*>( FindChildByName("CraftButton") );
+ m_pToolIcon = dynamic_cast<vgui::ScalableImagePanel*>( FindChildByName("tool_icon") );
+
+ m_pNextPageButton = dynamic_cast<CExButton*>( FindChildByName("NextPageButton") );
+ m_pPrevPageButton = dynamic_cast<CExButton*>( FindChildByName("PrevPageButton") );
+ m_pShowExplanationsButton = dynamic_cast<CExButton*>( FindChildByName("ShowExplanationsButton") );
+ m_pDragToNextPageButton = dynamic_cast<CExButton*>( FindChildByName("DragToNextPageButton") );
+ m_pDragToPrevPageButton = dynamic_cast<CExButton*>( FindChildByName("DragToPrevPageButton") );
+ m_pCurPageLabel = dynamic_cast<vgui::Label*>( FindChildByName("CurPageLabel") );
+ m_pShowRarityComboBox = dynamic_cast<vgui::ComboBox*>( FindChildByName( "ShowRarityComboBox" ) );
+ if ( m_pShowRarityComboBox )
+ {
+ m_pShowRarityComboBox->AddActionSignalTarget( this );
+
+ m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowNoBorders", NULL );
+ m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowQualityBorders", NULL );
+ m_pShowRarityComboBox->AddItem( "#TF_Backpack_ShowMarketableBorders", NULL );
+
+ m_pShowRarityComboBox->ActivateItemByRow( cl_showbackpackrarities.GetInt() );
+ }
+ m_pShowBaseItemsCheckbox = dynamic_cast<vgui::CheckButton*>( FindChildByName( "ShowBaseItemsCheckbox" ) );
+ if ( m_pShowBaseItemsCheckbox )
+ {
+ m_pShowBaseItemsCheckbox->AddActionSignalTarget( this );
+ m_pShowBaseItemsCheckbox->SetSelected( m_bShowBaseItems );
+ }
+
+ m_pMouseDragItemPanel->SetBorder( pScheme->GetBorder("BackpackItemMouseOverBorder") );
+
+ // Setup our combo box
+ if ( m_pSortByComboBox )
+ {
+ m_pSortByComboBox->RemoveAll();
+ vgui::HFont hFont = pScheme->GetFont( "HudFontSmallestBold", true );
+ m_pSortByComboBox->SetFont( hFont );
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ for ( int i = 0; i < ARRAYSIZE(g_BackpackSortTypes); i++ )
+ {
+ pKeyValues->SetInt( "sortby", i );
+ m_pSortByComboBox->AddItem( g_BackpackSortTypes[i].szSortDesc, pKeyValues );
+ }
+ pKeyValues->deleteThis();
+ m_pSortByComboBox->ActivateItemByRow( 0 );
+ m_pSortByComboBox->GetMenu()->SetNumberOfVisibleItems( ARRAYSIZE(g_BackpackSortTypes) );
+ }
+
+ // Create page buttons
+ const int nNumMaxPages = GetNumMaxPages();
+ for ( int i=m_Pages.Count(); i<nNumMaxPages; ++i )
+ {
+ EditablePanel *pPage = vgui::SETUP_PANEL( new EditablePanel( this, CFmtStr( "page_%d", i ) ) );
+ m_Pages.AddToTail( pPage );
+ }
+
+ if ( m_pInspectCosmeticPanel )
+ {
+ // Force it to load it's scheme now, because it needs to be done before we set it's visibility below
+ m_pInspectCosmeticPanel->InvalidateLayout( false, true );
+ m_pInspectCosmeticPanel->SetVisible( false );
+ }
+}
+
+void CBackpackPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ KeyValues *pItemKV = inResourceData->FindKey( "pagebuttons_kv" );
+ if ( pItemKV )
+ {
+ if ( m_pPageButtonKVs )
+ {
+ m_pPageButtonKVs->deleteThis();
+ }
+ m_pPageButtonKVs = new KeyValues("pagebuttons_kv");
+ pItemKV->CopySubkeys( m_pPageButtonKVs );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AddNewItemPanel( int iPanelIndex )
+{
+ BaseClass::AddNewItemPanel( iPanelIndex );
+
+ // Store a position for our new panel
+ m_ItemModelPanelPos.AddToTail();
+ m_ItemModelPanelPos[iPanelIndex].x = m_ItemModelPanelPos[iPanelIndex].y = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CItemModelPanel *CBackpackPanel::GetItemPanelAtPos( int x, int y )
+{
+ if ( !m_pItemModelPanels.Count() )
+ return NULL;
+
+ int iW = m_pItemModelPanels[0]->GetWide();
+ int iH = m_pItemModelPanels[0]->GetTall();
+ for ( int i = 0; i < m_ItemModelPanelPos.Count(); i++ )
+ {
+ if ( (x < m_ItemModelPanelPos[i].x) || (x > (m_ItemModelPanelPos[i].x + iW)) )
+ continue;
+ if ( (y < m_ItemModelPanelPos[i].y) || (y > (m_ItemModelPanelPos[i].y + iH)) )
+ continue;
+ return m_pItemModelPanels[i];
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBackpackPanel::GetPageButtonIndexAtPos( int x, int y )
+{
+ if ( !m_Pages.Count() )
+ return -1;
+
+ int iW = m_Pages[0]->GetWide();
+ int iH = m_Pages[0]->GetTall();
+ for ( int i = 0; i < m_PageButtonPos.Count(); i++ )
+ {
+ if ( (x < m_PageButtonPos[i].x) || (x > (m_PageButtonPos[i].x + iW)) )
+ continue;
+ if ( (y < m_PageButtonPos[i].y) || (y > (m_PageButtonPos[i].y + iH)) )
+ continue;
+ return m_Pages[i]->IsVisible() ? i : -1;
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Change the text color on the page buttons based on the context of the
+// page they represent.
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetPageButtonTextColorBasedOnContents()
+{
+ vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
+
+ if ( m_Pages.Count() == 0 )
+ return;
+
+ if ( !pScheme )
+ return;
+
+ const Color& colorEmpty = pScheme->GetColor( "TanDarker", Color( 235, 226, 202, 255 ) );
+ const Color& colorPartial = Color( 170, 161, 137, 255 );
+ const Color& colorFull = pScheme->GetColor( "TanLight", Color( 235, 226, 202, 255 ) );
+ const Color& colorSelected = pScheme->GetColor( "TFOrange", Color( 145, 73, 59, 255 ) );
+
+ CUtlVector<int> vecPageCount;
+ CUtlVector<int> vecNewPageCount;
+ vecPageCount.EnsureCount( m_Pages.Count() );
+ vecNewPageCount.EnsureCount( m_Pages.Count() );
+ // Initialize to 0
+ FOR_EACH_VEC( vecPageCount, i )
+ {
+ vecPageCount[i] = 0;
+ vecNewPageCount[i] = 0;
+ }
+
+ CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
+ Assert( pInv );
+ // Tally up how many items are on each page
+ if ( pInv )
+ {
+ for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
+ {
+ CEconItemView *pItem = pInv->GetItem( i );
+ const int nSlot = InventoryManager()->GetBackpackPositionFromBackend( pItem->GetInventoryPosition() ) - 1;
+ const int nPage = nSlot / GetNumSlotsPerPage();
+ if ( nPage >= 0 && nPage < m_Pages.Count() )
+ {
+ vecPageCount[ nPage ] = vecPageCount[ nPage ] + 1;
+
+ // Unackknowledged items technically are on the 1st page, so dont count them
+ if ( m_mapSeenItems.Find( pItem->GetItemID() ) == m_mapSeenItems.InvalidIndex()
+ && IsUnacknowledged( pItem->GetInventoryPosition() ) == false && !m_bShowBaseItems && !HasNameFilter() )
+ {
+ vecNewPageCount[ nPage ] = vecNewPageCount[ nPage ] + 1;
+ }
+ }
+ }
+ }
+
+ // Set the color for each page button
+ FOR_EACH_VEC( m_Pages, i )
+ {
+ const int nNewCount = vecNewPageCount[i];
+ const int nCount = vecPageCount[i];
+ CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[i]->FindChildByName( "Button" ) );
+ if ( pButton )
+ {
+ Color setColor = colorEmpty;
+ const Color& bgColor = GetCurrentPage() == i ? colorSelected : pButton->GetButtonDefaultBgColor();
+
+ if ( nCount == GetNumSlotsPerPage() )
+ setColor = colorFull;
+ else if ( nCount > 0 )
+ setColor = colorPartial;
+
+ pButton->SetSelectedColor( setColor, pButton->GetButtonSelectedBgColor() );
+ pButton->SetDefaultColor( setColor, bgColor );
+ pButton->SetArmedColor( setColor, pButton->GetButtonArmedBgColor() );
+ pButton->SetDepressedColor( setColor, pButton->GetButtonDepressedBgColor() );
+ }
+
+ // Show our "NEW!" label if there's any unseen items on that page
+ CExLabel* pNew = dynamic_cast<CExLabel*>( m_Pages[i]->FindChildByName( "New" ) );
+ if ( pNew )
+ {
+ pNew->SetVisible( nNewCount > 0 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::MarkItemIDDirty( itemid_t itemID )
+{
+ if ( m_vecDirtyItems.Find( itemID ) == m_vecDirtyItems.InvalidIndex() )
+ {
+ m_vecDirtyItems.AddToTail( itemID );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::PositionItemPanel( CItemModelPanel *pPanel, int iIndex )
+{
+ int iCenter = GetWide() * 0.5;
+ int iButtonX = (iIndex % GetNumColumns());
+ int iButtonY = (iIndex / GetNumColumns());
+ int iXPos = (iCenter + m_iItemBackpackOffcenterX) + (iButtonX * m_pItemModelPanels[iIndex]->GetWide()) + (m_iItemBackpackXDelta * iButtonX);
+ int iYPos = m_iItemYPos + (iButtonY * m_pItemModelPanels[iIndex]->GetTall() ) + (m_iItemBackpackYDelta * iButtonY);
+
+ m_pItemModelPanels[iIndex]->SetPos( iXPos, iYPos );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ // Viewing the backpack. Layout all the buttons and hide the class image.
+ m_pItemModelPanels[i]->SetVisible( true );
+ m_pItemModelPanels[i]->SetNoItemText( "#SelectNoItemSlot" );
+
+ PositionItemPanel( m_pItemModelPanels[i], i );
+
+ // Cache off where we put the panel
+ m_pItemModelPanels[i]->GetPos( m_ItemModelPanelPos[i].x, m_ItemModelPanelPos[i].y );
+
+ // Take into account parent's position
+ Panel* pParent = m_pItemModelPanels[i]->GetParent();
+ if( pParent )
+ {
+ int x = 0,y = 0;
+ pParent->GetPos( x, y );
+ m_ItemModelPanelPos[i].x += x;
+ m_ItemModelPanelPos[i].y += y;
+ }
+ }
+
+ // adjust page buttons
+ {
+ m_nNumActivePages = GetNumPages();
+
+ int iCenter = GetWide() * 0.5;
+
+ int iPageBarWidth = 2 * abs( m_iItemBackpackOffcenterX );
+ int iPageButtonWidth = ( iPageBarWidth - ( m_iPageButtonPerRow - 1 ) * m_iPageButtonXDelta ) / m_iPageButtonPerRow;
+ int iPageButtonWidthPlusDelta = iPageButtonWidth + m_iPageButtonXDelta;
+ int iPageButtonHeightPlusDelta = m_iPageButtonHeight + m_iPageButtonYDelta;
+ int iStart = iCenter + m_iItemBackpackOffcenterX;
+
+ m_PageButtonPos.EnsureCount( m_Pages.Count() );
+ for ( int i=0; i<m_Pages.Count(); ++i )
+ {
+ EditablePanel *pPage = m_Pages[i];
+ if ( pPage )
+ {
+ // Apply control settings here
+ if ( m_pPageButtonKVs )
+ pPage->ApplySettings( m_pPageButtonKVs );
+ CExButton* pButton = dynamic_cast<CExButton*>( pPage->FindChildByName( "Button" ) );
+ pPage->InvalidateLayout( true, true );
+ // Make the button have the right command and send it's signals to us
+ if ( pButton )
+ {
+ pButton->SetSelected( false );
+ pButton->SetCommand( CFmtStr( "goto_page_%d", i ) );
+ pButton->AddActionSignalTarget( this );
+ }
+ pPage->SetDialogVariable( "page", i+1 );
+
+ bool bVisible = i < m_nNumActivePages;
+ if ( bVisible )
+ {
+ int iRow = i /m_iPageButtonPerRow;
+ int iColumn = i % m_iPageButtonPerRow;
+ pPage->SetBounds( iStart + iColumn * iPageButtonWidthPlusDelta, m_iPageButtonYPos + iRow * iPageButtonHeightPlusDelta, iPageButtonWidth, m_iPageButtonHeight );
+ pPage->GetPos( m_PageButtonPos[i].x , m_PageButtonPos[i].y );
+ }
+ pPage->SetVisible( bVisible );
+ }
+ }
+
+ // Update colors and the "NEW!" labels
+ SetPageButtonTextColorBasedOnContents();
+ }
+
+ if ( m_pNextPageButton )
+ {
+ m_pNextPageButton->SetVisible( true );
+ }
+ if ( m_pPrevPageButton )
+ {
+ m_pPrevPageButton->SetVisible( true );
+ }
+ if ( m_pCurPageLabel )
+ {
+ m_pCurPageLabel->SetVisible( true );
+ }
+
+ if ( m_pSortByComboBox )
+ {
+ m_pSortByComboBox->SetVisible( !InToolSelectionMode() );
+ }
+ if ( m_pShowRarityComboBox )
+ {
+ m_pShowRarityComboBox->SetVisible( true );
+ }
+
+ if ( m_pNextPageButton )
+ {
+ m_pNextPageButton->SetEnabled( GetNumPages() > 1 );
+ }
+ if ( m_pPrevPageButton )
+ {
+ m_pPrevPageButton->SetEnabled( GetNumPages() > 1 );
+ }
+
+ if ( !m_bDragging )
+ {
+ if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
+ {
+ m_pDragToNextPageButton->SetVisible( false );
+ m_pDragToPrevPageButton->SetVisible( false );
+ }
+ }
+
+ bool bShowActions = (!m_bItemsOnly && !InToolSelectionMode());
+ if ( m_pCraftButton )
+ {
+ m_pCraftButton->SetVisible( bShowActions );
+ }
+ if ( m_pCancelToolButton )
+ {
+ m_pCancelToolButton->SetVisible( InToolSelectionMode() );
+ }
+
+ if ( m_pShowExplanationsButton )
+ {
+ m_pShowExplanationsButton->SetVisible( !m_bItemsOnly );
+ }
+ if ( m_pShowBaseItemsCheckbox )
+ {
+ m_pShowBaseItemsCheckbox->SetVisible( !m_bItemsOnly );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::FireGameEvent( IGameEvent *event )
+{
+ static CSchemaItemDefHandle pItemDef_BasePaintCan( "Paint Can" );
+ const char *type = event->GetName();
+ if ( Q_strcmp( "gc_connected", type ) == 0 )
+ {
+ if ( !m_bInitializedSeenItems )
+ {
+ CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
+ if ( pInventory )
+ {
+ for ( int i = 0; i < pInventory->GetItemCount(); i++ )
+ {
+ CEconItemView *pItem = pInventory->GetItem(i);
+ m_mapSeenItems.Insert( pItem->GetItemID() );
+ }
+ }
+
+ m_bInitializedSeenItems = true;
+ }
+
+ m_vecPaintCans.Purge();
+ m_vecStrangeParts.Purge();
+ const CEconItemSchema::ToolsItemDefinitionMap_t &toolDefs = GetItemSchema()->GetToolsItemDefinitionMap();
+
+ // Store all of the active paint can item defs
+ FOR_EACH_MAP_FAST( toolDefs, i )
+ {
+ const CEconItemDefinition *pItemDef = toolDefs[i];
+ const IEconTool *pEconTool = pItemDef->GetEconTool();
+ if ( !pEconTool )
+ continue;
+
+ // Paint can list
+ // Ignore the stock paintcan thats only for armory purposes
+ if ( !V_strcmp( pEconTool->GetTypeName(), "paint_can" ) && pItemDef_BasePaintCan != pItemDef )
+ {
+ // Paint Can
+ m_vecPaintCans.AddToTail( pItemDef->GetDefinitionIndex() );
+ }
+ // Strange Parts List
+ else if ( !V_strcmp( pEconTool->GetTypeName(), "strange_part" ) )
+ {
+ m_vecStrangeParts.AddToTail( pItemDef->GetDefinitionIndex() );
+ }
+ }
+ }
+
+ BaseClass::FireGameEvent( event );
+}
+
+void CBackpackPanel::CheckForQuickOpenKey()
+{
+ if ( !m_hQuickOpenCrate )
+ return;
+
+ // We only want to continue if it's the transaction we're listening for
+ if ( EconUI()->GetStorePanel()->GetMostRecentSuccessfulTransactionID() != m_nQuickOpenTxn )
+ {
+ return;
+ }
+
+ CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
+ if ( pInventory )
+ {
+ for ( int i = 0; i < pInventory->GetItemCount(); i++ )
+ {
+ CEconItemView *pInvItem = pInventory->GetItem( i );
+
+ uint32 iPosition = pInvItem->GetInventoryPosition();
+ if ( IsUnacknowledged( iPosition ) == false )
+ continue;
+
+ if ( InventoryManager()->GetBackpackPositionFromBackend( iPosition ) != 0 )
+ continue;
+
+ // Now make sure we haven't got a clientside saved ack for this item.
+ if ( InventoryManager()->HasBeenAckedByClient( pInvItem ) )
+ continue;
+
+ // If item is not a drop we want to show the notification otherwise they'll get the notification on death
+ int iFoundMethod = GetUnacknowledgedReason( iPosition );
+ if ( iFoundMethod != UNACK_ITEM_PURCHASED )
+ continue;
+
+ if ( !pInvItem->GetStaticData()->IsTool() )
+ continue;
+
+ if( !CEconSharedToolSupport::ToolCanApplyTo( pInvItem, m_hQuickOpenCrate ) )
+ continue;
+
+ if ( !pInvItem->GetStaticData()->GetEconTool() )
+ continue;
+
+ if ( !Q_strcmp( pInvItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) == 0 )
+ continue;
+
+ ApplyTool( this, pInvItem, m_hQuickOpenCrate );
+ CloseStoreStatusDialog();
+
+ m_hQuickOpenCrate = NULL;
+ m_nQuickOpenTxn = 0;
+ return;
+ }
+ }
+
+ m_hQuickOpenCrate = NULL;
+ m_nQuickOpenTxn = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: When the store get's a new transaction ID, it comes here as well
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetCurrentTransactionID( uint64 nTxnID )
+{
+ // If we've got a quick open crate st, and no quick open transaction ID,
+ // then we want to capture the incoming transaction ID so that we can
+ // compare future incoming successful transactions to see if they have
+ // the key we're expecting
+ if ( m_hQuickOpenCrate && m_nQuickOpenTxn == 0 )
+ {
+ m_nQuickOpenTxn = nTxnID;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnShowPanel( bool bVisible, bool bReturningFromArmory )
+{
+ if ( bVisible )
+ {
+ m_pMouseDragItemPanel->SetVisible( false );
+
+ if( m_pDynamicRecipePanel )
+ {
+ m_pDynamicRecipePanel->SetVisible( false );
+ }
+
+ if ( m_pItemSlotPanel )
+ {
+ m_pItemSlotPanel->SetVisible( false );
+ }
+
+ m_bShowBaseItems = false;
+ if ( m_pShowBaseItemsCheckbox )
+ {
+ m_pShowBaseItemsCheckbox->SetSelected( m_bShowBaseItems );
+ }
+
+ if ( !bReturningFromArmory )
+ {
+ SetCurrentPage( 0 );
+ CancelToolSelection();
+ }
+
+ m_nNumActivePages = 0;
+
+#ifdef STAGING_ONLY
+ // Reset pinned-state of the card
+ m_pMouseOverCardPanel->PinCard( false );
+#endif
+ }
+ else
+ {
+ if ( m_bDragging )
+ {
+ StopDrag( false );
+ }
+ }
+
+ if ( m_pInspectPanel )
+ {
+ m_pInspectPanel->SetVisible( false );
+ }
+
+ if ( m_pInspectCosmeticPanel )
+ {
+ m_pInspectCosmeticPanel->SetVisible( false );
+ }
+
+ if ( m_pCollectionCraftPanel )
+ {
+ m_pCollectionCraftPanel->SetVisible( false );
+ }
+
+ if ( m_pHalloweenOfferingPanel )
+ {
+ m_pHalloweenOfferingPanel->SetVisible( false );
+ }
+
+ if ( m_pMannCoTradePanel )
+ {
+ m_pMannCoTradePanel->SetVisible( false );
+ }
+
+ if ( m_pStrangeToolPanel )
+ {
+ m_pStrangeToolPanel->MarkForDeletion();
+ m_pStrangeToolPanel = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::PostShowPanel( bool bVisible )
+{
+ if ( bVisible )
+ {
+ DeSelectAllBackpackItemPanels();
+
+ RequestFocus();
+
+ // Clear out text field
+ ClearNameFilter( true );
+ }
+
+ // If this is the first time we've opened the loadout, start the loadout explanations
+ ConVar *pConVar = GetExplanationConVar();
+ if ( bVisible && pConVar && !pConVar->GetBool() && ShouldShowExplanations() )
+ {
+ m_flStartExplanationsAt = Plat_FloatTime() + 0.5;
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBackpackPanel::GetNumPages( void )
+{
+ int iMaxItems = InventoryManager()->GetLocalInventory()->GetMaxItemCount();
+ return (int)(ceil((float)iMaxItems / (float)BACKPACK_SLOTS_PER_PAGE));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AssignItemToPanel( CItemModelPanel *pPanel, int iIndex )
+{
+ tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
+
+ static int iItemBackpackPos = 0;
+ if ( iIndex == 0 )
+ {
+ iItemBackpackPos = 0;
+ }
+ int iPanelBackpackPos = GetBackpackPosForPanelIndex(iIndex);
+
+ static int iLastMapItem = -1;
+
+ pPanel->SetShowQuantity( true );
+
+ const wchar_t* wszFilter = GetNameFilter();
+ bool bInToolSelection = InToolSelectionMode() && m_ToolSelectionItem.IsValid();
+
+ CEconItemView *pItemData = NULL;
+ CEconItemView tempItem;
+ if ( m_bShowBaseItems )
+ {
+ const CEconItemDefinition* pItemDef = NULL;
+
+ const CEconItemSchema::BaseItemDefinitionMap_t& mapItems = GetItemSchema()->GetBaseItemDefinitionMap();
+ int iStart = iIndex == 0 ? mapItems.FirstInorder() : mapItems.NextInorder( iLastMapItem );
+ for ( int it = iStart; it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
+ {
+ iLastMapItem = it;
+
+ if ( mapItems[it]->IsBaseItem() && !mapItems[it]->IsHidden() )
+ {
+ // Instead of linking to this base item definition, link to the definition of what it will become
+ // when we customize it.
+ CFmtStr fmtStrCustomizedDefName( "Upgradeable %s", mapItems[it]->GetDefinitionName() );
+ pItemDef = GetItemSchema()->GetItemDefinitionByName( fmtStrCustomizedDefName.Access() );
+
+ // If we don't have an upgradeable version, we assume that we can't upgrade it and link to the base
+ // definition instead. We expect this to only happen if the item won't actually be useable for whatever
+ // purpose (name tags, etc.). We sanity-check this on the GC.
+ if ( !pItemDef )
+ {
+ pItemDef = mapItems[it];
+ }
+
+ tempItem.Init( pItemDef->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+
+ // skip this item if the tool cannot be applied to it
+ if ( bInToolSelection && !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, &tempItem ) )
+ {
+ pItemDef = NULL;
+ continue;
+ }
+
+ if ( DoesItemPassSearchFilter( tempItem.GetDescription(), wszFilter ) )
+ {
+ break;
+ }
+ }
+
+ pItemDef = NULL;
+ }
+
+ if ( pItemDef )
+ {
+ pItemData = &tempItem;
+
+ ++iItemBackpackPos;
+ }
+ }
+ else if ( HasNameFilter() )
+ {
+ int iStart = iIndex == 0 ? m_mapFilteringItems.FirstInorder() : m_mapFilteringItems.NextInorder( iLastMapItem );
+ for ( int it = iStart; it != m_mapFilteringItems.InvalidIndex(); it = m_mapFilteringItems.NextInorder( it ) )
+ {
+ iLastMapItem = it;
+
+ CEconItemView *pItem = m_mapFilteringItems[it];
+
+ // skip this item if the tool cannot be applied to it
+ if ( bInToolSelection && !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
+ {
+ continue;
+ }
+
+ if ( !DoesItemPassSearchFilter( pItem->GetDescription(), wszFilter ) )
+ {
+ continue;
+ }
+
+ if ( ++iItemBackpackPos != iPanelBackpackPos )
+ {
+ continue;
+ }
+
+ pItemData = pItem;
+ break;
+ }
+ }
+ else if ( bInToolSelection )
+ {
+ CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
+ if ( pInventory )
+ {
+ // Backpack positions start from 1
+ Assert( iPanelBackpackPos > 0 && iPanelBackpackPos <= pInventory->GetMaxItemCount() );
+ int iStart = iIndex == 0 ? 0 : iLastMapItem + 1;
+ for ( int i = iStart; i < pInventory->GetItemCount(); i++ )
+ {
+ iLastMapItem = i;
+
+ CEconItemView *pItem = pInventory->GetItem(i);
+
+ if ( m_ToolSelectionItem.GetStaticData()->IsTool() )
+ {
+ if ( !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
+ {
+ continue;
+ }
+ }
+ else
+ {
+ if ( !pItem->GetStaticData()->IsTool() )
+ {
+ continue;
+ }
+
+ if ( !CEconSharedToolSupport::ToolCanApplyTo( pItem, &m_ToolSelectionItem ) )
+ {
+ continue;
+ }
+
+ if ( ( m_ToolSelectionItem.GetStaticData()->GetCapabilities() & ITEM_CAP_DECODABLE ) && pItem->GetStaticData()->GetEconTool() && ( Q_strcmp( pItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) != 0 ) )
+ {
+ continue;
+ }
+ }
+
+ if ( ++iItemBackpackPos != iPanelBackpackPos )
+ {
+ continue;
+ }
+
+ pItemData = pItem;
+ break;
+ }
+ }
+ }
+ else
+ {
+ pItemData = InventoryManager()->GetItemByBackpackPosition( iPanelBackpackPos );
+ iItemBackpackPos = iPanelBackpackPos;
+
+ if ( pItemData == NULL && pPanel->GetItem() == NULL )
+ {
+ return;
+ }
+
+ int nDirtyIndex = pItemData ? m_vecDirtyItems.Find( pItemData->GetItemID() ) : m_vecDirtyItems.InvalidIndex();
+
+ if ( pItemData // Want to put in an item
+ && pPanel->GetItem() // Panel has an item
+ && pItemData->GetItemID() == pPanel->GetItem()->GetItemID() // That panel has the same item that we want to put in
+ && nDirtyIndex == m_vecDirtyItems.InvalidIndex() ) // And that item is not dirtied.
+ {
+ // We dont do anything
+ return;
+ }
+
+ if ( nDirtyIndex != m_vecDirtyItems.InvalidIndex() )
+ {
+ m_vecDirtyItems.Remove( nDirtyIndex );
+ }
+ }
+
+ if ( iItemBackpackPos != iPanelBackpackPos )
+ {
+ pItemData = NULL;
+ }
+
+ pPanel->SetItem( pItemData );
+
+ bool bSeen = true;
+ // Have we not seen this item before?
+ if ( !m_bShowBaseItems && pItemData && m_mapSeenItems.Find( pItemData->GetItemID() ) == m_mapSeenItems.InvalidIndex() )
+ {
+ bSeen = false;
+ }
+
+ // Show our "NEW!" label if this item hasnt been seen
+ CExLabel *pNewPanel = dynamic_cast< CExLabel* >( pPanel->FindChildByName( "New" ) );
+ if ( pNewPanel )
+ {
+ pNewPanel->SetVisible( !bSeen );
+ }
+
+ pPanel->DirtyDescription();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::ClearNameFilter( bool bUpdateModelPanels )
+{
+ if ( m_wNameFilter.Count() == 0 )
+ return;
+
+ m_wNameFilter.RemoveAll();
+ if( m_pNameFilterTextEntry )
+ {
+ m_pNameFilterTextEntry->SetText( "" );
+ }
+
+ if ( bUpdateModelPanels )
+ {
+ m_flFilterItemTime = gpGlobals->curtime + 0.1f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::UpdateFilteringItems()
+{
+ m_mapFilteringItems.RemoveAll();
+
+ if ( !HasNameFilter() )
+ return;
+
+ CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
+ if ( !pInventory )
+ return;
+
+ for ( int i = 0; i < pInventory->GetItemCount(); i++ )
+ {
+ CEconItemView *pItem = pInventory->GetItem(i);
+
+ if ( pItem->GetItemDefinition()->IsHidden() )
+ continue;
+
+ int iBackpackPosition = InventoryManager()->GetBackpackPositionFromBackend( pItem->GetInventoryPosition() );
+ m_mapFilteringItems.Insert( iBackpackPosition, pItem );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::UpdateModelPanels( void )
+{
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ UpdateFilteringItems();
+
+ // We're showing the backpack. Show all the items in our inventory
+ FOR_EACH_VEC( m_pItemModelPanels, i )
+ {
+ m_pItemModelPanels[i]->SetShowEquipped( true );
+ m_pItemModelPanels[i]->SetShowGreyedOutTooltip( true );
+ AssignItemToPanel( m_pItemModelPanels[i], i );
+
+ if ( !m_pItemModelPanels[i]->HasItem() && m_pItemModelPanels[i]->IsSelected() )
+ {
+ m_pItemModelPanels[i]->SetSelected( false );
+ }
+
+ SetBorderForItem( m_pItemModelPanels[i], false );
+ }
+
+ // Clean out. We just did all the heavy lifting.
+ m_vecDirtyItems.Purge();
+
+ if ( InToolSelectionMode() && m_ToolSelectionItem.IsValid() )
+ {
+ wchar_t wTemp[256];
+ g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find( "BackpackApplyTool" ), 1, m_ToolSelectionItem.GetItemName() );
+ SetDialogVariable( "loadoutclass", wTemp );
+ }
+ else
+ {
+ SetDialogVariable( "loadoutclass", g_pVGuiLocalize->Find( "BackpackTitle" ) );
+ }
+
+ char szTmp[16];
+ V_sprintf_safe( szTmp, "%d/%d", GetCurrentPage()+1, GetNumPages() );
+ SetDialogVariable( "backpackpage", szTmp );
+
+ // Now layout again to position our item buttons
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Mark visited item model panels as seen
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemPanelEntered( vgui::Panel *panel )
+{
+ if ( m_pContextMenu && m_pContextMenu->IsVisible() )
+ return;
+
+ CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
+ if ( pItemPanel )
+ {
+ // Hide the "NEW!" label
+ CExLabel *pNewPanel = dynamic_cast< CExLabel* >( pItemPanel->FindChildByName( "New" ) );
+ if ( pNewPanel )
+ {
+ pNewPanel->SetVisible( false );
+ }
+
+ // Mark this item as "seen"
+ CEconItemView *pItem = pItemPanel->GetItem();
+ if ( pItem )
+ {
+ if ( m_mapSeenItems.Find( pItem->GetItemID() ) == m_mapSeenItems.InvalidIndex() )
+ {
+ m_mapSeenItems.Insert( pItem->GetItemID() );
+ SetPageButtonTextColorBasedOnContents();
+ }
+ }
+ }
+
+ BaseClass::OnItemPanelEntered( panel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemPanelMousePressed( vgui::Panel *panel )
+{
+ CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
+
+ if ( pItemPanel && IsVisible() && pItemPanel->IsGreyedOut() == false && AllowDragging( pItemPanel ) )
+ {
+ m_flMouseDownTime = gpGlobals->curtime;
+ m_iMouseDownX = m_iMouseDownY = 0;
+ m_pItemDraggedFromPanel = pItemPanel;
+ m_iDraggedFromPage = GetCurrentPage();
+ m_bDragging = false;
+ m_bMouseDownOnItemPanel = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle the escape key since it doesn't show up in OnKeyCodePressed
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnKeyCodeTyped(vgui::KeyCode code)
+{
+ if ( code == KEY_ESCAPE && InToolSelectionMode() )
+ {
+ CancelToolSelection();
+ }
+ else if ( code == KEY_ENTER )
+ {
+ // Do nothing. This gets hit frequently when people type in the filter
+ // text entry and then hit 'Enter', expecting it to execute the filter.
+ // We automatically apply it, so let's just eat 'Enter', which was causing
+ // us to activate some button on the main menu.
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles key press events in the backpack
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // Ignore key events while the confirm delete dialog is up
+ if( m_pConfirmDeleteDialog )
+ return;
+
+ // let our parent class handle all the arrow key/dpad stuff
+ if( HandleItemSelectionKeyPressed( code ) )
+ {
+ return;
+ }
+
+ // Handle close here, CBasePanel parent doesn't support "DialogClosing" command
+ ButtonCode_t nButtonCode = GetBaseButtonCode( code );
+
+ if ( (nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B) && InToolSelectionMode() )
+ {
+ CancelToolSelection();
+ }
+ else if( code == KEY_PAGEDOWN )
+ {
+ OnCommand( "nextpage" );
+ }
+ else if( code == KEY_PAGEUP )
+ {
+ OnCommand( "prevpage" );
+ }
+ else if ( ( nButtonCode == KEY_XBUTTON_A || code == KEY_ENTER || nButtonCode == STEAMCONTROLLER_A ) )
+ {
+ if( InToolSelectionMode() )
+ {
+ HandleToolItemSelection( GetFirstSelectedItem() );
+ }
+ else
+ {
+ OpenContextMenu();
+ }
+ }
+ else if ( nButtonCode == KEY_XBUTTON_X || nButtonCode == STEAMCONTROLLER_X )
+ {
+ if( !InToolSelectionMode() )
+ {
+ OnCommand( "deleteitem" );
+ }
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles key press events in the backpack
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnKeyCodeReleased( vgui::KeyCode code )
+{
+ if( ! HandleItemSelectionKeyReleased( code ) )
+ BaseClass::OnKeyCodeReleased( code );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnMouseCaptureLost( void )
+{
+ if ( m_bDragging )
+ {
+ StopDrag( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnMouseReleased(vgui::MouseCode code)
+{
+ if ( code == MOUSE_LEFT )
+ {
+ if ( m_bDragging )
+ {
+ // When we're dragging, we have mouse capture, so the item panels aren't getting mouse input.
+ // We need to find out what item panel we're over, and let it know.
+ if ( m_pPrevDragOverItemPanel )
+ {
+ OnItemPanelMouseReleased( m_pPrevDragOverItemPanel );
+ }
+ else
+ {
+ StopDrag( false );
+ }
+ }
+ }
+
+ BaseClass::OnMouseReleased( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnConfirmDelete( KeyValues *data )
+{
+ // Delete all the selected item
+ if ( data )
+ {
+ int iConfirmed = data->GetInt( "confirmed", 0 );
+ if ( iConfirmed )
+ {
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_DELETED, m_pItemModelPanels[i]->GetItem() );
+ InventoryManager()->DropItem( m_pItemModelPanels[i]->GetItem()->GetItemID() );
+ }
+ }
+ DeSelectAllBackpackItemPanels();
+ }
+ }
+
+ m_pConfirmDeleteDialog = NULL;
+
+ // If we're embedded in the discard item panel, it needs to know we made room. Send a message to our parent that it can catch.
+ PostMessage( GetParent(), new KeyValues("ConfirmDlgResult", "confirmed", 2 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemPanelMouseReleased( vgui::Panel *panel )
+{
+ CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
+
+ if ( pItemPanel && IsVisible() )
+ {
+ if ( InToolSelectionMode() )
+ {
+ // They're selecting the item they'd like to apply a tool to
+ HandleToolItemSelection( pItemPanel->GetItem() );
+ }
+ else if ( !m_bDragging )
+ {
+ // If they're not holding down ctrl, deselect all existing selections
+ if ( !vgui::input()->IsKeyDown(KEY_LCONTROL) && !vgui::input()->IsKeyDown(KEY_RCONTROL) )
+ {
+ DeSelectAllBackpackItemPanels();
+ }
+
+ // Quick clicks just select the item
+ ToggleSelectBackpackItemPanel( pItemPanel );
+
+ if ( pItemPanel->IsSelected() )
+ {
+ OpenContextMenu();
+ }
+ }
+ else
+ {
+ int iPanelIndex = GetBackpackPositionForPanel( pItemPanel );
+ if ( !CanDragTo(pItemPanel, iPanelIndex) )
+ {
+ StopDrag(false);
+ }
+ else
+ {
+ StopDrag( true );
+ if ( (pItemPanel != m_pItemDraggedFromPanel || m_iDraggedFromPage != GetCurrentPage() ) && m_pMouseDragItemPanel->HasItem() )
+ {
+ HandleDragTo( pItemPanel, iPanelIndex );
+ }
+ else if ( m_iDraggedFromPage == GetCurrentPage() )
+ {
+ m_pItemDraggedFromPanel->SetItem( m_pMouseDragItemPanel->GetItem() );
+ }
+ }
+ }
+
+ m_pItemDraggedFromPanel = NULL;
+ }
+}
+
+
+bool GetDecodedByItemDefIndex( const CEconItemView *pItem, uint32 *pDecodedBy = NULL )
+{
+ static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );
+
+ if ( pDecodedBy )
+ {
+ return pItem->FindAttribute( pAttrDef_DecodedBy, pDecodedBy );
+ }
+ else
+ {
+ return pItem->FindAttribute( pAttrDef_DecodedBy );
+ }
+}
+
+CEconItemView* GetFirstCompatibleKeyForCrate( const CEconItemView *pItem )
+{
+ // Check if we have any decoder rings that can be applied onto this
+ CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
+ Assert( pInv );
+ if ( pInv )
+ {
+ for ( int i = 0; i < pInv->GetItemCount(); ++i )
+ {
+ CEconItemView *pInvItem = pInv->GetItem( i );
+
+ if ( pInvItem->GetQuality() == AE_SELFMADE )
+ continue;
+
+ if ( pInvItem->GetStaticData()->IsTool() && CEconSharedToolSupport::ToolCanApplyTo( pInvItem, pItem ) && pInvItem->GetStaticData()->GetEconTool() && ( Q_strcmp( pInvItem->GetStaticData()->GetEconTool()->GetTypeName(), "decoder_ring" ) == 0 ) )
+ {
+ return pInvItem;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+bool CanInventoryItemsApplyTo( const CEconItemView *pItem )
+{
+ // Check if we have any tools that can be applied onto this
+ CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
+ Assert( pInv );
+ if ( pInv )
+ {
+ for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
+ {
+ CEconItemView *pInvItem = pInv->GetItem( i );
+ if ( pInvItem->GetStaticData()->IsTool() && CEconSharedToolSupport::ToolCanApplyTo( pInvItem, pItem ) )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+//-----------------------------------------------------------------------------
+bool CreateMarketPriceString( item_definition_index_t iDefIndex, wchar_t *pszString, int iBufferSize )
+{
+ // Get Market Price
+ steam_market_gc_identifier_t ident;
+ ident.m_unDefIndex = iDefIndex;
+ ident.m_unQuality = AE_UNIQUE; // Get this from default item def?
+
+ const client_market_data_t *pClientMarketData = GetClientMarketData( ident );
+ if ( !pClientMarketData )
+ return false;
+
+ const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();
+
+ // Set that price into the button
+ wchar_t pszCurrencyString[kLocalizedPriceSizeInChararacters];
+ MakeMoneyString( pszCurrencyString, ARRAYSIZE( pszCurrencyString ), pClientMarketData->m_unLowestPrice, eCurrency );
+
+ wchar_t pszConstructed[kLocalizedPriceSizeInChararacters];
+ g_pVGuiLocalize->ConstructString_safe( pszConstructed, g_pVGuiLocalize->Find( "#TF_MarketPrice" ), 1, pszCurrencyString );
+
+ // copy result;
+ V_wcsncpy( pszString, pszConstructed, iBufferSize );
+ return true;
+}
+//-----------------------------------------------------------------------------
+bool CreateStorePriceString( item_definition_index_t iDefIndex, wchar_t *pszString, int iBufferSize )
+{
+ // Get Market Price
+ steam_market_gc_identifier_t ident;
+ ident.m_unDefIndex = iDefIndex;
+ ident.m_unQuality = AE_UNIQUE; // Get this from default item def?
+
+ // Get the price of the item
+ const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( iDefIndex );
+ if ( !pEntry )
+ return false;
+
+ const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency();
+
+ // Set that price into the button
+ wchar_t pszCurrencyString[kLocalizedPriceSizeInChararacters];
+ MakeMoneyString( pszCurrencyString, ARRAYSIZE( pszCurrencyString ), pEntry->GetCurrentPrice( eCurrency ), eCurrency );
+
+ wchar_t pszConstructed[kLocalizedPriceSizeInChararacters];
+ g_pVGuiLocalize->ConstructString_safe( pszConstructed, g_pVGuiLocalize->Find( "#TF_StorePrice" ), 1, pszCurrencyString );
+
+ // copy result;
+ V_wcsncpy( pszString, pszConstructed, iBufferSize );
+ return true;
+}
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AddCommerceSubmenus( Menu *pSubMenu, item_definition_index_t iItemDef, const char* pszActionFmt )
+{
+ wchar_t wPriceListing[256];
+ // Store
+ if ( CreateStorePriceString( iItemDef, wPriceListing, sizeof( wPriceListing ) ) )
+ {
+ int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "store_", pszActionFmt, iItemDef ) ), this );
+ vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( wPriceListing );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+
+ // Market
+ if ( CreateMarketPriceString( iItemDef, wPriceListing, sizeof( wPriceListing ) ) )
+ {
+ int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "market_", pszActionFmt, iItemDef ) ), this );
+ vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( wPriceListing );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+ else
+ {
+ int nIndex = pSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%s%d", "market_", pszActionFmt, iItemDef ) ), this );
+ vgui::MenuItem *pMenuItem = pSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_MarketUnavailable" ) );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+
+}
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AddPaintToContextMenu( Menu *pPaintSubMenu, item_definition_index_t iPaintDef, bool bAddCommerce )
+{
+ GameItemDefinition_t * pPaintCanDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( iPaintDef ) );
+ if ( !pPaintCanDef )
+ return;
+
+ wchar_t wBuff[256];
+ char cBuff[256];
+ V_swprintf_safe( wBuff, L" %ls", g_pVGuiLocalize->Find( pPaintCanDef->GetItemBaseName() ) );
+
+ char szItemName[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pPaintCanDef->GetItemBaseName() ), szItemName, sizeof( szItemName ) );
+ V_sprintf_safe( cBuff, " %s", szItemName );
+
+ uint32 unPaintRGB0 = 0;
+ uint32 unPaintRGB1 = 0;
+
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB( "set item tint RGB" );
+ static CSchemaAttributeDefHandle pAttrDef_PaintRGB2( "set item tint RGB 2" );
+
+ float fRGB = 0.0f;
+
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB, &fRGB ) && fRGB != 0.0f )
+ {
+ unPaintRGB0 = fRGB;
+
+ // We may or may not have a secondary paint color as well. If we don't, we just use the primary
+ // paint color to fill both slots.
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pPaintCanDef, pAttrDef_PaintRGB2, &fRGB ) )
+ {
+ unPaintRGB1 = fRGB;
+ }
+ else
+ {
+ unPaintRGB1 = unPaintRGB0;
+ }
+ }
+
+ if ( !bAddCommerce )
+ {
+ int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "paint%d", iPaintDef ) ), this );
+ vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( wBuff );
+ pMenuItem->InvalidateLayout( true, false );
+
+ CItemMaterialCustomizationIconPanel *pCustomPanel = new CItemMaterialCustomizationIconPanel( pMenuItem, "paint" );
+ pCustomPanel->SetZPos( -100 );
+ pCustomPanel->SetTall( 30 );
+ pCustomPanel->SetWide( 30 );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB0 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF ), 0, 255 ), 255 ) );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB1 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF ), 0, 255 ), 255 ) );
+ }
+ else
+ {
+ //
+ const char *pszContextMenuBorder = "NotificationDefault";
+ const char *pszContextMenuFont = "HudFontMediumSecondary";
+
+ Menu *pSubMenu = new Menu( this, "PaintSubMenu" );
+ pSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ int iPos = pPaintSubMenu->AddCascadingMenuItem( cBuff, this, pSubMenu );
+
+ CItemMaterialCustomizationIconPanel *pCustomPanel = new CItemMaterialCustomizationIconPanel( pPaintSubMenu, "paint" );
+ pCustomPanel->SetZPos( 100 );
+ pCustomPanel->SetPos( 0, iPos * pPaintSubMenu->GetMenuItemHeight() );
+ pCustomPanel->SetTall( 30 );
+ pCustomPanel->SetWide( 30 );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB0 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB0 & 0xFF ), 0, 255 ), 255 ) );
+ pCustomPanel->m_colPaintColors.AddToTail( Color( clamp( ( unPaintRGB1 & 0xFF0000 ) >> 16, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF00 ) >> 8, 0, 255 ), clamp( ( unPaintRGB1 & 0xFF ), 0, 255 ), 255 ) );
+
+ AddCommerceSubmenus( pSubMenu, iPaintDef, "paint" );
+ }
+}
+//
+// Add commerce context options for an item. Adds 'Store' and 'Market' options if appropriate (and Pricing) other wise just click to use
+//
+void CBackpackPanel::AddCommerceToContextMenu( Menu *pMenu, const char* pszActionFmt, item_definition_index_t iItemDefIndex, bool bAddMarket, bool bAddStore )
+{
+ GameItemDefinition_t * pItemDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( iItemDefIndex ) );
+ if ( !pItemDef )
+ return;
+
+ //
+ if ( !bAddMarket && !bAddStore )
+ {
+ int nIndex = pMenu->AddMenuItem( "", new KeyValues( "Command", "command", CFmtStr( "%s%d", pszActionFmt, iItemDefIndex ) ), this );
+ vgui::MenuItem *pMenuItem = pMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( pItemDef->GetItemBaseName() ) );
+ pMenuItem->InvalidateLayout( true, false );
+ }
+ else
+ {
+ //
+ const char *pszContextMenuBorder = "NotificationDefault";
+ const char *pszContextMenuFont = "HudFontMediumSecondary";
+
+ Menu *pSubMenu = new Menu( this, "CommerceSubMenu" );
+ pSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ pMenu->AddCascadingMenuItem( pItemDef->GetItemBaseName(), this, pSubMenu );
+
+ AddCommerceSubmenus( pSubMenu, iItemDefIndex, pszActionFmt );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens a context menu with actions relevant for the passed in item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OpenContextMenu()
+{
+ CUtlVector<CEconItemView*> vecSelectedItems;
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->GetItem() )
+ {
+ vecSelectedItems.AddToTail( m_pItemModelPanels[i]->GetItem() );
+ }
+ }
+
+ if ( m_pContextMenu )
+ delete m_pContextMenu;
+
+ m_pContextMenu = new Menu( this, "ContextMenu" );
+ MenuBuilder contextMenuBuilder( m_pContextMenu, this );
+ const char *pszContextMenuBorder = "NotificationDefault";
+ const char *pszContextMenuFont = "HudFontMediumSecondary";
+ m_pContextMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ m_pContextMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+
+ if ( vecSelectedItems.Count() == 1 )
+ {
+ const CEconItemView *pItem = vecSelectedItems.Head();
+ const CTFItemDefinition *pItemDef = pItem->GetStaticData();
+ static CSchemaItemDefHandle DuckBadgeItemDef( "Duck Badge" );
+ static CSchemaItemDefHandle StrangeCountTransferItemDef( "Strange Count Transfer Tool" );
+
+ // Tools of any kind can't be used if they are in escrow.
+ static CSchemaAttributeDefHandle pAttrib_ToolEscrowUntil( "tool escrow until date" );
+ uint32 unEscrowTime;
+ const bool bToolIsInEscrow = pItem->FindAttribute( pAttrib_ToolEscrowUntil, &unEscrowTime )
+ && unEscrowTime > CRTime::RTime32TimeCur();
+
+ const IEconTool *pEconTool = pItem->GetItemDefinition()->GetEconTool();
+
+ const bool bIsTool = pItem->GetStaticData()->IsTool() && (pEconTool != NULL);
+ const bool bIsGCConsumable = ( ( pItem->GetStaticData()->GetCapabilities() & ITEM_CAP_USABLE_GC ) != 0 );
+ bool bSkipAddTrade = false; // Hack: We should really ask the tool if the command supplants trade.
+
+ // Tool usage goes first. The cursor starts on this element, so double-clicks will work like how they used to.
+ // Strange Count Transfer
+ if ( StrangeCountTransferItemDef == pItem->GetItemDefinition() )
+ {
+ contextMenuBuilder.AddMenuItem( "#ApplyOnItem", new KeyValues( "Context_OpenStrangeCountTransfer" ), "primaryaction" );
+ }
+ else if ( pItem->GetStaticData()->IsTool() && pEconTool == NULL )
+ {
+ // do nothing. not a real tool (basic balloons with color that we don't want to 'remove' the paint)
+ }
+ else if ( (bIsTool || bIsGCConsumable) && !bToolIsInEscrow && pEconTool->CanBeUsedNow( pItem ) )
+ {
+ Assert( pEconTool );
+
+ const int nTokens = pEconTool->GetUseCommandCount( pItem );
+ for ( int i = 0; i < nTokens; ++i )
+ {
+ const char *pszToolUsageString = pEconTool->GetUseCommandLocalizationToken( pItem, i );
+
+ // If we didn't have a custom usage string, fall back to a sane default based on whether or
+ // not we're a consumable or not.
+ if ( !pszToolUsageString )
+ {
+ pszToolUsageString = bIsGCConsumable ? "#ConsumeItem" : "#ApplyOnItem";
+ }
+
+ const char *pszContext = pEconTool->GetUseCommand( pItem, i );
+ contextMenuBuilder.AddMenuItem( pszToolUsageString, new KeyValues( pszContext ), "primaryaction" );
+ }
+
+ // Hack: We should really ask the tool if the command supplants trade. For now, if we have two
+ // things, then one of them is trade, so skip it.
+ bSkipAddTrade = nTokens > 1;
+ }
+ else if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_DECODABLE )
+ {
+
+ static CSchemaAttributeDefHandle pAttrDef_CanShuffleCrateContents( "can shuffle crate contents" );
+
+ if ( pItem->FindAttribute( pAttrDef_CanShuffleCrateContents ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#ShuffleContents", new KeyValues( "Context_Shuffle" ), "primaryaction" );
+ }
+
+ if ( GetFirstCompatibleKeyForCrate( pItem ) != NULL )
+ {
+ contextMenuBuilder.AddMenuItem( "#UseKey", new KeyValues( "Context_OpenCrateWithKey" ), "primaryaction" );
+ }
+
+ if ( GetDecodedByItemDefIndex( pItem ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#GetKey", new KeyValues( "Context_GetItemFromStore" ), "primaryaction" );
+ contextMenuBuilder.AddMenuItem( "#BuyAndUseKey", new KeyValues( "Context_BuyKeyAndOpenCrate" ), "primaryaction" );
+ }
+ }
+ else if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_HAS_SLOTS )
+ {
+ // check if we have at least 1 slot criteria
+ static CSchemaAttributeDefHandle pAttrDef_Slot( "item slot criteria 1" );
+ if ( pItem->FindAttribute( pAttrDef_Slot ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#EditSlots", new KeyValues( "Context_EditSlot" ), "primaryaction" );
+ }
+ }
+ else if ( DuckBadgeItemDef == pItem->GetItemDefinition() )
+ {
+ contextMenuBuilder.AddMenuItem( "#Duck_ViewLeaderboards", new KeyValues( "Context_OpenDuckLeaderboards" ), "primaryaction" );
+
+ if ( CanInventoryItemsApplyTo( pItem ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#UseDuckToken", new KeyValues( "Context_ApplyByItem" ), "primaryaction" );
+ }
+
+ if ( GetDecodedByItemDefIndex( pItem ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#GetDuckToken", new KeyValues( "Context_GetItemFromStore" ), "primaryaction" );
+ }
+ }
+
+ // 3D Inspect
+ float flInspect = 0;
+ static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
+ static CSchemaAttributeDefHandle pAttrib_CosmeticAllowInspect( "cosmetic_allow_inspect" );
+ if ( pItem && pItem->IsValid() &&
+ ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_WeaponAllowInspect, &flInspect ) || FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_CosmeticAllowInspect, &flInspect )
+#ifdef STAGING_ONLY
+ || tf_weapon_force_allow_inspect.GetBool()
+#endif
+ ) )
+ {
+ if ( flInspect != 0
+#ifdef STAGING_ONLY
+ || tf_weapon_force_allow_inspect.GetBool()
+#endif
+ )
+ {
+ contextMenuBuilder.AddMenuItem( "#Context_InspectModel", new KeyValues( "Context_InspectModel" ), "primaryaction" );
+ }
+ }
+
+ // Add equip sub menu
+ {
+ Menu *pEquipSubMenu = NULL;
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; iClass++ )
+ {
+ if ( !pItemDef->CanBeUsedByClass( iClass ) )
+ continue;
+
+ if ( pEquipSubMenu == NULL )
+ {
+ pEquipSubMenu = new Menu( this, "EquipMenu" );
+ pEquipSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pEquipSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_Equip", pEquipSubMenu, "primaryaction" );
+ }
+
+ const char *pszClassName = NULL;
+ switch ( iClass )
+ {
+ case TF_CLASS_SCOUT: pszClassName = "#TF_Class_Name_Scout"; break;
+ case TF_CLASS_SNIPER: pszClassName = "#TF_Class_Name_Sniper"; break;
+ case TF_CLASS_SOLDIER: pszClassName = "#TF_Class_Name_Soldier"; break;
+ case TF_CLASS_DEMOMAN: pszClassName = "#TF_Class_Name_Demoman"; break;
+ case TF_CLASS_MEDIC: pszClassName = "#TF_Class_Name_Medic"; break;
+ case TF_CLASS_HEAVYWEAPONS: pszClassName = "#TF_Class_Name_HWGuy"; break;
+ case TF_CLASS_PYRO: pszClassName = "#TF_Class_Name_Pyro"; break;
+ case TF_CLASS_SPY: pszClassName = "#TF_Class_Name_Spy"; break;
+ case TF_CLASS_ENGINEER: pszClassName = "#TF_Class_Name_Engineer"; break;
+ }
+
+ pEquipSubMenu->AddMenuItem( pszClassName, new KeyValues( "Command", "command", CFmtStr( "equipclass%d", iClass ) ), this );
+ }
+ }
+
+ // For customizable items only
+ if ( !pItem->IsTemporaryItem() )
+ {
+ bool bCanCraftUp = GetCollectionCraftingInvalidReason(pItem, NULL) == NULL;
+ bool bCanStatClockTrade = GetCraftCommonStatClockInvalidReason(pItem, NULL) == NULL;
+ Menu *pMannCoTradeSubMenu = NULL;
+
+ if ( bCanCraftUp || bCanStatClockTrade )
+ {
+ pMannCoTradeSubMenu = new Menu(this, "MannCoTradeSubMenu");
+ pMannCoTradeSubMenu->SetBorder(scheme()->GetIScheme(GetScheme())->GetBorder(pszContextMenuBorder));
+ pMannCoTradeSubMenu->SetFont(scheme()->GetIScheme(GetScheme())->GetFont(pszContextMenuFont));
+ contextMenuBuilder.AddCascadingMenuItem("#Context_MannCoTrade", pMannCoTradeSubMenu, "customization");
+
+ if ( bCanCraftUp )
+ {
+ int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftUpCollection"), this);
+ vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
+ pMenuItem->SetText("#Context_TradeUp");
+ pMenuItem->InvalidateLayout(true, false);
+ }
+
+ if ( bCanStatClockTrade )
+ {
+ int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
+ vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
+ pMenuItem->SetText("#Context_CommonStatClock");
+ pMenuItem->InvalidateLayout(true, false);
+ }
+ }
+
+
+
+ // Campaign coin access trades
+ static CSchemaAttributeDefHandle pAttrDef_IsOperationPass( "is_operation_pass" );
+ if ( pItem->FindAttribute( pAttrDef_IsOperationPass ) )
+ {
+ Menu *pMannCoCoinTradeSubMenu = new Menu( this, "MannCoTradeSubMenu" );
+ pMannCoCoinTradeSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pMannCoCoinTradeSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_MannCoTrade", pMannCoCoinTradeSubMenu, "customization" );
+
+ int nIndex = pMannCoCoinTradeSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "Context_CraftUpCollection" ), this );
+ vgui::MenuItem *pMenuItem = pMannCoCoinTradeSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( "#Context_TradeUp" );
+ pMenuItem->InvalidateLayout( true, false );
+
+ nIndex = pMannCoCoinTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
+ pMenuItem = pMannCoCoinTradeSubMenu->GetMenuItem(nIndex);
+ pMenuItem->SetText("#Context_CommonStatClock");
+ pMenuItem->InvalidateLayout(true, false);
+ }
+
+ // Halloween trade up offering.
+ // Needs two attrs
+ static CSchemaAttributeDefHandle pAttrDef_HalloweenOffering( "allow_halloween_offering" );
+ static CSchemaAttributeDefHandle pAttrDef_DeactiveDate( "deactive date" );
+
+ // Check the date
+ uint32 unDeactiveDate = 0;
+ uint32 unCurrentDate = CRTime::RTime32TimeCur();
+ if ( pAttrDef_HalloweenOffering && pItem->FindAttribute( pAttrDef_HalloweenOffering ) && pItem->FindAttribute( pAttrDef_DeactiveDate, &unDeactiveDate ) && unDeactiveDate > unCurrentDate )
+ {
+ vgui::MenuItem *pMenuItem = contextMenuBuilder.AddMenuItem( "#Context_HalloweenOffering", new KeyValues( "Context_HalloweenOffering" ), "customization" );
+
+ ImagePanel *pNewImage = new ImagePanel( pMenuItem, "new" );
+ pNewImage->SetZPos( 100 );
+ pNewImage->SetWide( 40 );
+ pNewImage->SetTall( 40 );
+ pNewImage->SetPos( 220, -5 );
+ pNewImage->SetMouseInputEnabled( false );
+ pNewImage->SetShouldScaleImage( true );
+ pNewImage->SetImage( "new" );
+ }
+
+ // Change name
+ GameItemDefinition_t * pNameTagDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinitionByName( "Name Tag" ) );
+ if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pNameTagDef ), pItemDef ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#Context_Rename", new KeyValues( "DoRename" ), "customization" );
+ }
+
+ // Change description
+ GameItemDefinition_t * pDescTagDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinitionByName( "Description Tag" ) );
+ if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pDescTagDef ), pItemDef ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#Context_Description", new KeyValues( "DoDescription" ), "customization" );
+ }
+
+ // Add paint options sub menu
+ if ( m_vecPaintCans.Count() > 0 )
+ {
+ GameItemDefinition_t * pPaintCanDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( m_vecPaintCans[0] ) );
+ if ( pPaintCanDef && CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast<const GameItemDefinition_t *>( pPaintCanDef ), pItemDef ) )
+ {
+ Menu *pPaintSubMenu = NULL;
+ pPaintSubMenu = new Menu( this, "PaintSubMenu" );
+ pPaintSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pPaintSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_Paint", pPaintSubMenu, "customization" );
+
+ CUtlVector<item_definition_index_t> vecOwnedPaints;
+ CUtlVector<item_definition_index_t> vecStorePaints;
+
+ // Find out if the user owns this item or not and place in the proper bucket
+ CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();
+
+ FOR_EACH_VEC( m_vecPaintCans, i )
+ {
+ if ( pLocalInv && pLocalInv->FindFirstItembyItemDef( m_vecPaintCans[i] ) )
+ {
+ vecOwnedPaints.AddToTail( m_vecPaintCans[i] );
+ }
+ else
+ {
+ vecStorePaints.AddToTail( m_vecPaintCans[i] );
+ }
+ }
+
+ if ( vecOwnedPaints.Count() > 0 )
+ {
+ // Add Header and loop
+ int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
+ vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Owned" ) );
+ pMenuItem->InvalidateLayout( true, false );
+
+ FOR_EACH_VEC( vecOwnedPaints, i )
+ {
+ AddPaintToContextMenu( pPaintSubMenu, vecOwnedPaints[i], false );
+ }
+ }
+
+ pPaintSubMenu->AddSeparator();
+ if ( vecStorePaints.Count() > 0 )
+ {
+ // Add Header and loop
+ int nIndex = pPaintSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
+ vgui::MenuItem *pMenuItem = pPaintSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Commerce" ) );
+ pMenuItem->InvalidateLayout( true, false );
+
+ FOR_EACH_VEC( vecStorePaints, i )
+ {
+ AddPaintToContextMenu( pPaintSubMenu, vecStorePaints[i], true );
+ }
+ }
+ }
+ }
+
+ // Strange Parts
+ if ( BIsItemStrange( pItem ) )
+ {
+ Menu *pStrangePartsSubMenu = NULL;
+ CUtlVector<item_definition_index_t> vecOwnedParts;
+ CUtlVector<item_definition_index_t> vecStoreParts;
+
+ // Find out if the user owns this item or not and place in the proper bucket
+ CPlayerInventory *pLocalInv = TFInventoryManager()->GetLocalInventory();
+ FOR_EACH_VEC( m_vecStrangeParts, i )
+ {
+ // Determine if this can be applied
+ //GameItemDefinition_t *pStrangePartDef = dynamic_cast<GameItemDefinition_t*>( GEconItemSchema().GetItemDefinition( m_vecStrangeParts[i] ) );
+ CEconItemView partItemView;
+ partItemView.Init( m_vecStrangeParts[i], AE_USE_SCRIPT_VALUE, 1 );
+ if ( CEconSharedToolSupport::ToolCanApplyTo( &partItemView, pItem ) )
+ {
+ // Create menu
+ if ( !pStrangePartsSubMenu )
+ {
+ pStrangePartsSubMenu = new Menu( this, "StrangePartsSubMenu" );
+ pStrangePartsSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) );
+ pStrangePartsSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) );
+ contextMenuBuilder.AddCascadingMenuItem( "#Context_StrangeParts", pStrangePartsSubMenu, "customization" );
+ }
+
+ if ( pLocalInv && pLocalInv->FindFirstItembyItemDef( m_vecStrangeParts[i] ) )
+ {
+ vecOwnedParts.AddToTail( m_vecStrangeParts[i] );
+ }
+ else
+ {
+ vecStoreParts.AddToTail( m_vecStrangeParts[i] );
+ }
+ }
+ }
+
+ if ( pStrangePartsSubMenu )
+ {
+ if ( vecOwnedParts.Count() > 0 )
+ {
+ // Add Header and loop
+ int nIndex = pStrangePartsSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
+ vgui::MenuItem *pMenuItem = pStrangePartsSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Owned" ) );
+ pMenuItem->InvalidateLayout( true, false );
+
+ FOR_EACH_VEC( vecOwnedParts, i )
+ {
+ AddCommerceToContextMenu( pStrangePartsSubMenu, "strangepart_", vecOwnedParts[i], false, false );
+ }
+ }
+
+ pStrangePartsSubMenu->AddSeparator();
+ if ( vecStoreParts.Count() > 0 )
+ {
+ // Add Header and loop
+ int nIndex = pStrangePartsSubMenu->AddMenuItem( "", new KeyValues( "Command", "command", "" ), this );
+ vgui::MenuItem *pMenuItem = pStrangePartsSubMenu->GetMenuItem( nIndex );
+ pMenuItem->SetText( g_pVGuiLocalize->Find( "#TF_Market" ) );
+ pMenuItem->InvalidateLayout( true, false );
+
+ FOR_EACH_VEC( vecStoreParts, i )
+ {
+ AddCommerceToContextMenu( pStrangePartsSubMenu, "strangepart_", vecStoreParts[i], true, false );
+ }
+ }
+ }
+ }
+
+ if ( pItem->IsMarketable() )
+ {
+ contextMenuBuilder.AddMenuItem( "#Context_MarketPlaceSell", new KeyValues( "DoSellMarketplace" ), "economy" );
+ }
+
+ // Trade to another player
+ if ( pItem->IsTradable() && !bSkipAddTrade )
+ {
+ contextMenuBuilder.AddMenuItem( "#Context_Trade", new KeyValues( "DoTradeToPlayer" ), "economy" );
+ }
+
+ if ( pItem->GetItemDefinition()->GetCapabilities() & ITEM_CAP_CAN_BE_RESTORED )
+ {
+ if ( RemovableAttributes_DoAnyAttributesApply( pItem ) )
+ {
+ contextMenuBuilder.AddMenuItem( "#RefurbishItem", new KeyValues( "Context_RefurbishItem" ), "destructive" );
+ }
+ }
+ }
+ }
+ else
+ {
+ // Check if ALL selected items can be crafted together
+ bool bCanCraftUp = true;
+ for( int i=0; i < COLLECTION_CRAFTING_ITEM_COUNT && i < vecSelectedItems.Count(); ++i )
+ {
+ CEconItemView* pPrevItem = ( i - 1 ) < 0 ? NULL : vecSelectedItems[ i - 1 ];
+ bCanCraftUp &= GetCollectionCraftingInvalidReason( vecSelectedItems[ i ], pPrevItem ) == NULL;
+ }
+
+ bool bCanStatClockTrade = true;
+ for (int i = 0; i < COLLECTION_CRAFTING_ITEM_COUNT && i < vecSelectedItems.Count(); ++i)
+ {
+ CEconItemView* pPrevItem = (i - 1) < 0 ? NULL : vecSelectedItems[i - 1];
+ bCanStatClockTrade &= GetCraftCommonStatClockInvalidReason(vecSelectedItems[i], pPrevItem) == NULL;
+ }
+
+ Menu *pMannCoTradeSubMenu = NULL;
+
+ if ( bCanCraftUp || bCanStatClockTrade )
+ {
+ pMannCoTradeSubMenu = new Menu(this, "MannCoTradeSubMenu");
+ pMannCoTradeSubMenu->SetBorder(scheme()->GetIScheme(GetScheme())->GetBorder(pszContextMenuBorder));
+ pMannCoTradeSubMenu->SetFont(scheme()->GetIScheme(GetScheme())->GetFont(pszContextMenuFont));
+ contextMenuBuilder.AddCascadingMenuItem("#Context_MannCoTrade", pMannCoTradeSubMenu, "customization");
+
+ if (bCanCraftUp)
+ {
+ int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftUpCollection"), this);
+ vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
+ pMenuItem->SetText("#Context_TradeUp");
+ pMenuItem->InvalidateLayout(true, false);
+ }
+
+ if (bCanStatClockTrade)
+ {
+ int nIndex = pMannCoTradeSubMenu->AddMenuItem("", new KeyValues("Command", "command", "Context_CraftCommonStatClock"), this);
+ vgui::MenuItem *pMenuItem = pMannCoTradeSubMenu->GetMenuItem(nIndex);
+ pMenuItem->SetText("#Context_CommonStatClock");
+ pMenuItem->InvalidateLayout(true, false);
+ }
+ }
+ }
+
+ if ( !m_bShowBaseItems )
+ {
+ bool bDeleteAvailable = true;
+ // Check that all of the selected items are deletable
+ for( int i=0; i < vecSelectedItems.Count() && bDeleteAvailable; ++i )
+ {
+ static CSchemaAttributeDefHandle pAttrDef_NoDelete( "cannot delete" );
+ bDeleteAvailable &= !vecSelectedItems[i]->FindAttribute( pAttrDef_NoDelete );
+ }
+
+ // Only show the delete button if every slected item is deletable
+ if ( bDeleteAvailable )
+ {
+ contextMenuBuilder.AddMenuItem( "#TF_SteamWorkshop_Delete", new KeyValues( "DoDelete" ), "destructive" );
+ }
+ }
+
+ // Position to the cursor's position
+ int nX, nY;
+ g_pVGuiInput->GetCursorPosition( nX, nY );
+ m_pContextMenu->SetPos( nX - 1, nY - 1 );
+
+ m_pContextMenu->SetVisible(true);
+ m_pContextMenu->AddActionSignalTarget(this);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemPanelMouseRightRelease( vgui::Panel *panel )
+{
+#ifdef STAGING_ONLY
+ if ( tf_use_card_tooltips.GetBool() )
+ {
+ m_pMouseOverCardPanel->PinCard( true );
+ }
+ else
+#endif
+ {
+ CItemModelPanel *pItemPanel = dynamic_cast < CItemModelPanel * > ( panel );
+ if ( pItemPanel && pItemPanel->IsVisible() )
+ {
+ // If they're not holding down ctrl, deselect all existing selections
+ if ( !vgui::input()->IsKeyDown(KEY_LCONTROL) && !vgui::input()->IsKeyDown(KEY_RCONTROL) )
+ {
+ DeSelectAllBackpackItemPanels();
+ ToggleSelectBackpackItemPanel( pItemPanel );
+ }
+ else if ( AllowSelection() && !pItemPanel->IsGreyedOut() )
+ {
+ if ( !pItemPanel->IsSelected() && pItemPanel->HasItem() )
+ {
+ pItemPanel->SetSelected( true );
+ }
+ SetBorderForItem( pItemPanel, false );
+ }
+
+ OpenContextMenu();
+ }
+ }
+}
+
+void CBackpackPanel::OnMouseMismatchedRelease( MouseCode code, Panel* pPressedPanel )
+{
+ if ( pPressedPanel )
+ {
+ OnMouseReleased( code );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::StartDrag( int x, int y )
+{
+ // don't allow item drag if there's a filter
+ if ( HasNameFilter() )
+ return;
+
+ m_bDragging = true;
+ HideMouseOverPanel();
+
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+
+ m_pMouseDragItemPanel->SetItem( m_pItemDraggedFromPanel->GetItem() );
+ m_pMouseDragItemPanel->InvalidateLayout( true );
+
+ m_pItemDraggedFromPanel->Dragged( true );
+
+ // Calculate the mouse offset from the top left of the panel we're going to drag
+ m_iDragOffsetX = m_pMouseDragItemPanel->GetWide() * 0.5f;
+ m_iDragOffsetY = m_pMouseDragItemPanel->GetTall() * 0.5f;
+ m_flPreventDragPageSwitchUntil = 0;
+
+ m_pMouseDragItemPanel->SetVisible( true );
+
+ m_pItemDraggedFromPanel->SetItem( NULL );
+ SetBorderForItem( m_pItemDraggedFromPanel, false );
+ m_pPrevDragOverItemPanel = NULL;
+
+ vgui::input()->SetMouseCapture( GetVPanel() );
+
+ if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
+ {
+ m_pDragToNextPageButton->SetVisible( GetNumPages() > 1 );
+ m_pDragToPrevPageButton->SetVisible( GetNumPages() > 1 );
+ }
+
+ // play pickup sound
+ CEconItemView *item = m_pMouseDragItemPanel->GetItem();
+ if ( item )
+ {
+ const char *soundFilename = item->GetDefinitionString( "pickup_sound", "" );
+ if ( soundFilename[0] )
+ {
+ vgui::surface()->PlaySound( soundFilename );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::StopDrag( bool bSucceeded )
+{
+ if ( !m_pItemDraggedFromPanel )
+ return;
+
+ if ( !bSucceeded )
+ {
+ if ( m_iDraggedFromPage == GetCurrentPage() )
+ {
+ m_pItemDraggedFromPanel->SetItem( m_pMouseDragItemPanel->GetItem() );
+ }
+ m_pItemDraggedFromPanel = NULL;
+ }
+
+ m_pMouseDragItemPanel->SetVisible( false );
+ m_bDragging = false;
+
+ vgui::input()->SetMouseCapture( NULL );
+
+ if ( m_pDragToNextPageButton && m_pDragToPrevPageButton )
+ {
+ m_pDragToNextPageButton->SetVisible( false );
+ m_pDragToPrevPageButton->SetVisible( false );
+ }
+
+ // play drop sound
+ CEconItemView *item = m_pMouseDragItemPanel->GetItem();
+ if ( item )
+ {
+ const char *soundFilename = item->GetDefinitionString( "drop_sound", "ui/item_default_drop.wav" );
+ vgui::surface()->PlaySound( soundFilename );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBackpackPanel::GetBackpackPositionForPanel( CItemModelPanel *pItemPanel )
+{
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i] == pItemPanel )
+ return i;
+ }
+ return -1;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::HandleDragTo( CItemModelPanel *pItemPanel, int iPanelIndex )
+{
+ // Find the position based on the panel we're dragging to
+ if ( iPanelIndex != -1 )
+ {
+ // If the current panel is selected, unselect it
+ if ( m_pItemModelPanels[iPanelIndex]->IsSelected() )
+ {
+ ToggleSelectBackpackItemPanel( m_pItemModelPanels[iPanelIndex] );
+ }
+ if ( m_pItemDraggedFromPanel->IsSelected() )
+ {
+ ToggleSelectBackpackItemPanel( m_pItemDraggedFromPanel );
+ }
+
+ // We "move" the items in the backpack immediately, because when the messages come back
+ // from steam they'll fix the positions if the move fails for some reason.
+ CEconItemView *pItem = NULL;
+ if ( m_pItemModelPanels[iPanelIndex]->HasItem() )
+ {
+ // We need to copy it because it's about to get stomped by the other item
+ pItem = new CEconItemView( *m_pItemModelPanels[iPanelIndex]->GetItem() );
+ }
+ m_pItemModelPanels[iPanelIndex]->SetItem( m_pMouseDragItemPanel->GetItem() );
+
+ if ( m_iDraggedFromPage == GetCurrentPage() )
+ {
+ m_pItemDraggedFromPanel->SetItem( pItem );
+ }
+
+ if ( pItem )
+ {
+ delete pItem;
+ }
+
+ // Tell the inventory to move the item
+ // Translate it to the right page
+ int iBackpackPosition = GetBackpackPosForPanelIndex( iPanelIndex );
+ InventoryManager()->MoveItemToBackpackPosition( m_pMouseDragItemPanel->GetItem(), iBackpackPosition );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnTick( void )
+{
+ BaseClass::OnTick();
+
+ bool bNeedsTick = false;
+ if ( m_flStartExplanationsAt && m_flStartExplanationsAt < Plat_FloatTime() )
+ {
+ m_flStartExplanationsAt = 0;
+
+ if ( ShouldShowExplanations() )
+ {
+ ConVar *pConVar = GetExplanationConVar();
+ if ( pConVar )
+ {
+ pConVar->SetValue( 1 );
+ }
+
+ CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") );
+ if ( pPopup )
+ {
+ pPopup->Popup();
+ }
+ }
+ }
+ else
+ {
+ bNeedsTick = true;
+ }
+
+ // To handle page movement while holding the mouse still over the page buttons,
+ // we need to keep calling OnCursorMoved() whenever we're dragging.
+ if ( m_bDragging && m_pMouseDragItemPanel && m_pItemDraggedFromPanel && IsVisible() )
+ {
+ int mx,my;
+ vgui::input()->GetCursorPos( mx, my );
+ ScreenToLocal( mx, my );
+ OnCursorMoved( mx,my );
+
+ bNeedsTick = true;
+ }
+
+ if ( !bNeedsTick && !NeedsDerivedTickSignal() )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnThink( void )
+{
+ BaseClass::OnThink();
+
+ if ( m_flFilterItemTime > 0 && gpGlobals->curtime >= m_flFilterItemTime )
+ {
+ SetCurrentPage( 0 );
+ DeSelectAllBackpackItemPanels();
+ UpdateModelPanels();
+
+ m_flFilterItemTime = 0.0f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnCursorMoved( int x, int y )
+{
+ if ( !m_pItemDraggedFromPanel )
+ return;
+
+ if ( m_bDragging && m_pMouseDragItemPanel )
+ {
+ m_pMouseDragItemPanel->SetPos( x - m_iDragOffsetX, y - m_iDragOffsetY );
+
+ // When we're dragging, we have mouse capture, so the item panels aren't getting mouse input.
+ // We need to find out what item panel we're over, and let it know.
+
+ if ( m_flPreventDragPageSwitchUntil < Plat_FloatTime() )
+ {
+ // First, are we over the page turning areas?
+ bool bDragNext = false;
+ if ( m_pDragToNextPageButton && m_pDragToNextPageButton->IsVisible() )
+ {
+ int iDragX, iDragY;
+ m_pDragToNextPageButton->GetPos( iDragX, iDragY );
+ bDragNext = ( x >= iDragX && x <= (iDragX + m_pDragToNextPageButton->GetWide() ) );
+ }
+ if ( !bDragNext && m_pNextPageButton && m_pNextPageButton->IsEnabled() )
+ {
+ int iDragX, iDragY;
+ m_pNextPageButton->GetPos( iDragX, iDragY );
+ bDragNext = ( x >= iDragX && x <= (iDragX + m_pNextPageButton->GetWide()) && y >= iDragY && y <= (iDragY + m_pNextPageButton->GetTall()) );
+ }
+ if ( bDragNext )
+ {
+ OnCommand( "nextpage" );
+ m_flPreventDragPageSwitchUntil = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
+ return;
+ }
+
+ bool bDragPrev = false;
+ if ( m_pDragToPrevPageButton && m_pDragToPrevPageButton->IsVisible() )
+ {
+ int iDragX, iDragY;
+ m_pDragToPrevPageButton->GetPos( iDragX, iDragY );
+ bDragPrev = ( x >= iDragX && x <= (iDragX + m_pDragToPrevPageButton->GetWide() ) );
+ }
+ if ( !bDragPrev && m_pPrevPageButton && m_pPrevPageButton->IsEnabled() )
+ {
+ int iDragX, iDragY;
+ m_pPrevPageButton->GetPos( iDragX, iDragY );
+ bDragPrev = ( x >= iDragX && x <= (iDragX + m_pPrevPageButton->GetWide()) && y >= iDragY && y <= (iDragY + m_pPrevPageButton->GetTall()) );
+ }
+ if ( bDragPrev )
+ {
+ OnCommand( "prevpage" );
+ m_flPreventDragPageSwitchUntil = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
+ return;
+ }
+ }
+
+ // check if we're hovering page button
+ static int iPrevHoveringPage = -1;
+ static float flLastPageButtonEnterTime = 0.f;
+ int iHoveringPage = GetPageButtonIndexAtPos( x, y );
+ if ( iHoveringPage != -1 )
+ {
+ if ( iHoveringPage == GetCurrentPage() )
+ {
+ iPrevHoveringPage = -1;
+ flLastPageButtonEnterTime = 0.f;
+ }
+ else if ( iPrevHoveringPage != iHoveringPage )
+ {
+ iPrevHoveringPage = iHoveringPage;
+ flLastPageButtonEnterTime = Plat_FloatTime() + tf_backpack_page_button_delay.GetFloat();
+ }
+ else if ( flLastPageButtonEnterTime > 0 && flLastPageButtonEnterTime < Plat_FloatTime() )
+ {
+ flLastPageButtonEnterTime = 0.f;
+ SetCurrentPage( iHoveringPage );
+ UpdateModelPanels();
+ }
+ return;
+ }
+ else
+ {
+ // reset hovering page buttons data
+ iPrevHoveringPage = -1;
+ flLastPageButtonEnterTime = 0.f;
+ }
+
+ CItemModelPanel *pOverPanel = GetItemPanelAtPos( x, y );
+ if ( m_pPrevDragOverItemPanel != pOverPanel )
+ {
+ if ( m_pPrevDragOverItemPanel )
+ {
+ OnItemPanelExited( m_pPrevDragOverItemPanel );
+ }
+
+ m_pPrevDragOverItemPanel = pOverPanel;
+
+ if ( m_pPrevDragOverItemPanel )
+ {
+ OnItemPanelEntered( m_pPrevDragOverItemPanel );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemPanelCursorMoved( int x, int y )
+{
+ if ( !m_pItemDraggedFromPanel )
+ return;
+
+ if ( !m_bDragging && m_pItemDraggedFromPanel->HasItem() && !InToolSelectionMode() )
+ {
+ // Don't drag instantly, so it's easy to select
+ if ( (gpGlobals->curtime - m_flMouseDownTime) > 0.3 )
+ {
+ StartDrag( x,y );
+ }
+ else
+ {
+ if ( !m_iMouseDownX )
+ {
+ m_iMouseDownX = x;
+ m_iMouseDownY = y;
+ }
+ else if ( abs(m_iMouseDownX - x) > XRES(10) || abs(m_iMouseDownY - y) > YRES(10) )
+ {
+ StartDrag( x,y );
+ }
+ }
+ }
+
+ OnCursorMoved( x, y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::ToggleSelectBackpackItemPanel( CItemModelPanel *pPanel )
+{
+ if ( !AllowSelection() || pPanel->IsGreyedOut() )
+ return;
+
+ if ( pPanel->IsSelected() || !pPanel->HasItem() )
+ {
+ pPanel->SetSelected( false );
+ }
+ else
+ {
+ pPanel->SetSelected( true );
+ }
+ SetBorderForItem( pPanel, false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DeSelectAllBackpackItemPanels( void )
+{
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() )
+ {
+ m_pItemModelPanels[i]->SetSelected( false );
+ SetBorderForItem( m_pItemModelPanels[i], false );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever the selection changes in the item loadout panel
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnItemContentsChanged( CEconItemView *pEconItemView )
+{
+ Assert( pEconItemView );
+
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ CEconItemView *pInternalItem = m_pItemModelPanels[i] && m_pItemModelPanels[i]->HasItem()
+ ? m_pItemModelPanels[i]->GetItem()
+ : NULL;
+
+ if ( *pInternalItem == *pEconItemView )
+ {
+ m_pItemModelPanels[i]->DirtyDescription();
+ OnItemSelectionChanged();
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when text changes in combo box
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnTextChanged( KeyValues *data )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( data->GetPtr("panel") );
+
+ vgui::TextEntry *pTextEntry = dynamic_cast<vgui::TextEntry *>( pPanel );
+ if ( pTextEntry )
+ {
+ if ( pTextEntry == m_pNameFilterTextEntry )
+ {
+ m_wNameFilter.RemoveAll();
+ if ( m_pNameFilterTextEntry->GetTextLength() )
+ {
+ m_wNameFilter.EnsureCount( m_pNameFilterTextEntry->GetTextLength() + 1 );
+ m_pNameFilterTextEntry->GetText( m_wNameFilter.Base(), m_wNameFilter.Count() * sizeof(wchar_t) );
+ V_wcslower( m_wNameFilter.Base() );
+ }
+ m_flFilterItemTime = gpGlobals->curtime + 0.5f;
+ return;
+ }
+ }
+
+ vgui::ComboBox *pComboBox = dynamic_cast<vgui::ComboBox *>( pPanel );
+ if ( pComboBox )
+ {
+ if ( pComboBox == m_pSortByComboBox )
+ {
+ // the class selection combo box changed, update class details
+ KeyValues *pUserData = m_pSortByComboBox->GetActiveItemUserData();
+ if ( !pUserData )
+ return;
+
+ enum { kSortType_Dummy = -1 };
+ int iSortTypeSelectionIndex = pUserData->GetInt( "sortby", kSortType_Dummy );
+ if ( iSortTypeSelectionIndex != kSortType_Dummy )
+ {
+ uint32 iSortType = g_BackpackSortTypes[iSortTypeSelectionIndex].iSortType;
+ if ( iSortType != kGCItemSort_NoSort )
+ {
+ InventoryManager()->SortBackpackBy( iSortType );
+
+ // Now go back to the "Sort by" header, and move the focus to the close button.
+ m_pSortByComboBox->ActivateItemByRow( 0 );
+ }
+ }
+ }
+ else if ( pComboBox == m_pShowRarityComboBox )
+ {
+ cl_showbackpackrarities.SetValue( m_pShowRarityComboBox->GetActiveItem() );
+
+ // Refresh all item borders
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ SetBorderForItem( m_pItemModelPanels[i], false );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnButtonChecked( KeyValues *pData )
+{
+ Panel *pPanel = reinterpret_cast<vgui::Panel *>( pData->GetPtr("panel") );
+
+ if ( m_bShowBaseItems != m_pShowBaseItemsCheckbox->IsSelected() && m_pShowBaseItemsCheckbox == pPanel && IsVisible() )
+ {
+ SetShowBaseItems( m_pShowBaseItemsCheckbox->IsSelected() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnCancelSelection( void )
+{
+ if ( m_pConfirmDeleteDialog )
+ {
+ m_pConfirmDeleteDialog->MarkForDeletion();
+ m_pConfirmDeleteDialog = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CBackpackPanel::GetGreyOutItemPanelReason( CItemModelPanel *pItemPanel )
+{
+ if ( InToolSelectionMode() )
+ {
+ bool bIsSelectedTool = (m_ToolSelectionItem.IsValid() && pItemPanel->HasItem()) ? (m_ToolSelectionItem == *pItemPanel->GetItem()) : false;
+ if ( !bIsSelectedTool )
+ {
+ if ( m_ToolSelectionItem.GetStaticData()->IsTool() )
+ {
+ if ( !CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItemPanel->GetItem() ) )
+ {
+ return "#Econ_GreyOutReason_ToolCannotApply";
+ }
+ }
+ else if ( pItemPanel->GetItem() && pItemPanel->GetItem()->GetStaticData()->IsTool() )
+ {
+ if ( !CEconSharedToolSupport::ToolCanApplyTo( pItemPanel->GetItem(), &m_ToolSelectionItem ) )
+ {
+ return "#Econ_GreyOutReason_ToolCannotApply";
+ }
+ }
+ }
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetBorderForItem( CItemModelPanel *pItemPanel, bool bMouseOver )
+{
+ tmZone( TELEMETRY_LEVEL1, TMZF_NONE, "%s", __FUNCTION__ );
+
+ if ( !pItemPanel )
+ return;
+
+ const char *pszBorder = NULL;
+
+ bool bIsSelectedTool = (m_ToolSelectionItem.IsValid() && pItemPanel->HasItem()) ? (m_ToolSelectionItem == *pItemPanel->GetItem()) : false;
+
+ // Handle grey out
+ const char *pszGreyOutReason = GetGreyOutItemPanelReason( pItemPanel );
+ const bool bGreyOut = pszGreyOutReason != NULL;
+
+ pItemPanel->SetGreyedOut( pszGreyOutReason );
+
+ int iRarity = GetItemQualityForBorder( pItemPanel );
+
+ if ( InToolSelectionMode() && bIsSelectedTool )
+ {
+ // We're in tool application mode, and this panel is the tool being used
+ pszBorder = "BackpackItemBorder_SelfMade";
+
+ if ( m_pToolIcon )
+ {
+ int iX, iY;
+ pItemPanel->GetPos( iX, iY );
+ m_pToolIcon->SetPos( iX, iY );
+ m_pToolIcon->SetVisible( true );
+ }
+ }
+ else if ( bGreyOut )
+ {
+ if( pItemPanel->IsSelected() )
+ {
+ pszBorder = g_szItemBorders[iRarity][4];
+ }
+ else
+ {
+ pszBorder = g_szItemBorders[iRarity][3];
+ }
+ }
+ else
+ {
+
+ if ( pItemPanel->IsSelected() )
+ {
+ pszBorder = g_szItemBorders[iRarity][2];
+ }
+ else if ( bMouseOver )
+ {
+ pszBorder = g_szItemBorders[iRarity][1];
+ }
+ else
+ {
+ pszBorder = g_szItemBorders[iRarity][0];
+ }
+ }
+
+ vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
+ pItemPanel->SetBorder( pScheme->GetBorder( pszBorder ) );
+}
+
+//-----------------------------------------------------------------------------
+class CTFRemoveItemCustomizationConfirmDialog : public CTFGenericConfirmDialog
+{
+ DECLARE_CLASS_SIMPLE( CTFRemoveItemCustomizationConfirmDialog, CTFGenericConfirmDialog );
+public:
+ CTFRemoveItemCustomizationConfirmDialog( const RefurbishableProperty& prop, CEconItemView *pItem )
+ : CTFGenericConfirmDialog( prop.m_szDialogTitle, // dialog title
+ prop.m_szDialogDesc, // dialog text
+ "#RefurbishItem_Yes", // confirm button text
+ "#RefurbishItem_No", // cancel button text
+ NULL, // callback
+ NULL ) // parent
+ , m_prop( prop )
+ , m_Item( *pItem ) // copy in case our UI changes behind us
+ {
+ GetCustomDialogLocalizationTokenFunc_t m_pDialogCustomTokenFunc = m_prop.m_pGetCustomDialogLocalizationTokenFunc;
+ if ( m_pDialogCustomTokenFunc )
+ {
+ CUtlConstWideString wsDialogCustomToken;
+ (*m_pDialogCustomTokenFunc)( &m_Item, m_prop.m_iUserData, wsDialogCustomToken );
+ if ( !wsDialogCustomToken.IsEmpty() )
+ {
+ AddStringToken( "confirm_dialog_token", wsDialogCustomToken.Get() );
+ }
+ }
+ }
+
+ virtual ~CTFRemoveItemCustomizationConfirmDialog() { }
+
+ virtual void OnCommand( const char *command );
+
+private:
+ RefurbishableProperty m_prop;
+ CEconItemView m_Item;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void SendGCSimpleAttributeRemovalMessage( CEconItemView *pEconItemView, const char *szDesc, EGCItemMsg eItemMsg )
+{
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, pEconItemView, szDesc );
+ GCSDK::CProtoBufMsg<CMsgGCRemoveCustomizationAttributeSimple> msg( eItemMsg );
+ msg.Body().set_item_id( pEconItemView->GetItemID() );
+ GCClientSystem()->BSendMessage( msg );
+}
+
+void CTFRemoveItemCustomizationConfirmDialog::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+
+ // Did the user say "yes, remove this particular attribute"? If so, notify the GC. We can't
+ // remove multiple attributes at a time because each removal will cause a new item to be created,
+ // invalidating the item reference we've got in this dialog.
+ if ( !Q_strnicmp( command, "confirm", 7 ) )
+ {
+ // remove the attribute
+ switch( m_prop.m_eRemovalType )
+ {
+ case kCustomizationRemove_Paint:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "paint", k_EMsgGCRemoveItemPaint );
+ break;
+
+ case kCustomizationRemove_Name:
+ {
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "name" );
+ GCSDK::CGCMsg< MsgGCRemoveItemName_t > msg( k_EMsgGCRemoveItemName );
+ msg.Body().m_unItemID = m_Item.GetItemID();
+ msg.Body().m_bDescription = false;
+ GCClientSystem()->BSendMessage( msg );
+ }
+ break;
+
+ case kCustomizationRemove_Desc:
+ {
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "description" );
+ GCSDK::CGCMsg< MsgGCRemoveItemName_t > msg( k_EMsgGCRemoveItemName );
+ msg.Body().m_unItemID = m_Item.GetItemID();
+ msg.Body().m_bDescription = true;
+ GCClientSystem()->BSendMessage( msg );
+ }
+ break;
+
+ case kCustomizationRemove_CustomTexture:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "custom_texture", k_EMsgGCRemoveCustomTexture );
+ break;
+
+ case kCustomizationRemove_MakersMark:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "makers_mark", k_EMsgGCRemoveMakersMark );
+ break;
+
+ case kCustomizationRemove_StrangePart:
+ {
+ Assert( m_prop.m_iUserData != kNoUserData );
+ int iKillEaterAttrIndex = m_prop.m_iUserData;
+
+ // What attribute did we select?
+ const CEconItemAttributeDefinition *pAttrDef = GetKillEaterAttr_Type( iKillEaterAttrIndex );
+ Assert( pAttrDef );
+
+ // Make sure this item has this attribute.
+ float fScoreType = kKillEaterEvent_PlayerKill;
+ Verify( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( &m_Item, pAttrDef, &fScoreType ) || iKillEaterAttrIndex == 0 );
+
+ // Dispatch message.
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "strange_part" );
+ GCSDK::CProtoBufMsg<CMsgGCRemoveStrangePart> msg( k_EMsgGCRemoveStrangePart );
+
+ msg.Body().set_item_id( m_Item.GetItemID() );
+ msg.Body().set_strange_part_score_type( (int)fScoreType );
+ GCClientSystem()->BSendMessage( msg );
+ }
+ break;
+
+ case kCustomizationRemove_StrangeScores:
+ {
+ Assert( m_prop.m_iUserData == kNoUserData );
+
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_RESET_STRANGE_COUNTERS, &m_Item );
+ GCSDK::CProtoBufMsg<CMsgGCResetStrangeScores> msg( k_EMsgGCResetStrangeScores );
+ msg.Body().set_item_id( m_Item.GetItemID() );
+ GCClientSystem()->BSendMessage( msg );
+ }
+ break;
+
+ case kCustomizationRemove_UpgradeCard:
+ {
+ Assert( m_prop.m_iUserData != kNoUserData );
+
+ // Make sure we selected a valid attribute that this item has.
+ const CEconItemAttributeDefinition *pAttrDef = GetCardUpgradeForIndex( &m_Item, m_prop.m_iUserData );
+ Assert( pAttrDef );
+ Verify( m_Item.FindAttribute( pAttrDef ) );
+
+ // Dispatch message.
+ EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "upgrade_card" );
+ GCSDK::CProtoBufMsg<CMsgGCRemoveUpgradeCard> msg( k_EMsgGCRemoveUpgradeCard );
+
+ msg.Body().set_item_id( m_Item.GetItemID() );
+ msg.Body().set_attribute_index( pAttrDef->GetDefinitionIndex() );
+ GCClientSystem()->BSendMessage( msg );
+ }
+ break;
+
+ case kCustomizationRemove_KillStreak:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "killstreak", k_EMsgGCRemoveKillStreak );
+ break;
+ case kCustomizationRemove_GiftedBy:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "giftedby", k_EMsgGCRemoveGiftedBy );
+ break;
+ case kCustomizationRemove_Festivizer:
+ SendGCSimpleAttributeRemovalMessage( &m_Item, "festivizer", k_EMsgGCRemoveFestivizer );
+ break;
+ default:
+ AssertMsg( false, "Unknown item customization removal type!" );
+ break;
+ }
+ }
+
+ SetVisible( false );
+ MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CRefurbishItemDialog : public CComboBoxBackpackOverlayDialogBase
+{
+public:
+ DECLARE_CLASS_SIMPLE( CRefurbishItemDialog, CComboBoxBackpackOverlayDialogBase );
+
+public:
+ CRefurbishItemDialog( vgui::Panel *pParent, CEconItemView *m_pItem ) : CComboBoxBackpackOverlayDialogBase( pParent, m_pItem ) { }
+
+private:
+ virtual void PopulateComboBoxOptions()
+ {
+ Assert( m_pItem );
+
+ KeyValues *pKeyValues = new KeyValues( "data" );
+ for ( int i = 0; i < GetRemovableAttributesCount(); i++ )
+ {
+ if ( RemovableAttributes_DoesAttributeApply( i, m_pItem ) )
+ {
+ pKeyValues->SetInt( "data", i );
+
+ RefurbishableProperty prop = RemovableAttributes_GetAttributeDetails( i );
+
+ CUtlConstWideString wsDialogCustomToken;
+ if ( prop.m_pGetCustomDialogLocalizationTokenFunc )
+ {
+ (*prop.m_pGetCustomDialogLocalizationTokenFunc)( m_pItem, prop.m_iUserData, wsDialogCustomToken );
+ }
+ CConstructLocalizedString localizedUI( GLocalizationProvider()->Find( prop.m_pszSelectionUILocalizationToken ), wsDialogCustomToken.IsEmpty() ? L"" : wsDialogCustomToken.Get() );
+ GetComboBox()->AddItem( localizedUI, pKeyValues );
+ }
+ }
+ pKeyValues->deleteThis();
+
+ Assert( GetComboBox()->GetItemCount() > 0 );
+
+ GetComboBox()->ActivateItemByRow( 0 );
+ }
+
+ virtual void OnComboBoxApplication()
+ {
+ if ( !m_pItem )
+ return;
+
+ KeyValues *pKVActiveUserData = GetComboBox()->GetActiveItemUserData();
+ int iIndex = pKVActiveUserData ? pKVActiveUserData->GetInt( "data", -1 ) : -1;
+ if ( iIndex < 0 )
+ return;
+
+ const RefurbishableProperty RefurbProp = RemovableAttributes_GetAttributeDetails( iIndex );
+
+ CTFRemoveItemCustomizationConfirmDialog *pDialog = new CTFRemoveItemCustomizationConfirmDialog( RefurbProp, m_pItem );
+ if ( pDialog )
+ {
+ pDialog->Show();
+ }
+ }
+
+ virtual const char *GetTitleLabelLocalizationToken() const { return "#TF_Item_RefurbishItemHeader"; }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles item selection while in tool selection mode
+//-----------------------------------------------------------------------------
+void CBackpackPanel::HandleToolItemSelection( CEconItemView *pItem )
+{
+ if ( !InToolSelectionMode() )
+ {
+ // must be in tool selection mode
+ Assert( InToolSelectionMode() );
+ return;
+ }
+
+ if ( pItem )
+ {
+ // Check if we should bring up the shuffle dialog instead of directly using the tool
+ static CSchemaAttributeDefHandle pAttrDef_CanShuffleCrateContents( "can shuffle crate contents" );
+ if ( pItem->FindAttribute( pAttrDef_CanShuffleCrateContents ) )
+ {
+ CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, pItem, &m_ToolSelectionItem ) );
+ if ( pDialog )
+ {
+ pDialog->Show();
+ CancelToolSelection();
+ }
+ }
+ else if ( m_ToolSelectionItem.FindAttribute( pAttrDef_CanShuffleCrateContents ) )
+ {
+ CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, &m_ToolSelectionItem, pItem ) );
+ if ( pDialog )
+ {
+ pDialog->Show();
+ CancelToolSelection();
+ }
+ }
+ // is a tool being applied onto this item
+ else if ( m_ToolSelectionItem.GetStaticData()->IsTool() && ApplyTool( this, &m_ToolSelectionItem, pItem ) )
+ {
+ CancelToolSelection();
+ UpdateModelPanels();
+ }
+ // is this item a tool that can be applied on a selected item
+ else if ( pItem->GetStaticData()->IsTool() && ApplyTool( this, pItem, &m_ToolSelectionItem ) )
+ {
+ CancelToolSelection();
+ UpdateModelPanels();
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tries to use the item. This might switch the panel to a tool item
+// selection mode, or launch the recipe crafting panel.
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetupToolSelectionItem()
+{
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ m_ToolSelectionItem = *m_pItemModelPanels[i]->GetItem();
+ break;
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Open up the trade dialog
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoTradeToPlayer()
+{
+ OpenTradingStartDialog( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use the trade dialog to send a gift to a player.
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoGiftToPlayer()
+{
+ OpenTradingStartDialog( this, &m_ToolSelectionItem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open up the overlay to sell the selected item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoSellMarketplace()
+{
+ CUtlVector< CItemModelPanel* > m_vecSelected;
+ GetSelectedPanels( SELECT_FIRST, m_vecSelected );
+ Assert( m_vecSelected.Count() );
+ if( !m_vecSelected.Count() )
+ return;
+
+ if ( m_vecSelected.Count() && steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
+ {
+ CEconItemView *pItem = m_vecSelected.Head()->GetItem();
+ const char *pszPrefix = "";
+ if ( GetUniverse() == k_EUniverseBeta )
+ {
+ pszPrefix = "beta.";
+ }
+ uint32 nAssetContext = 2; // k_EEconContextBackpack
+ char szURL[512];
+ V_snprintf( szURL, sizeof(szURL), "http://%ssteamcommunity.com/my/inventory/?sellOnLoad=1#%d_%d_%llu", pszPrefix, engine->GetAppID(), nAssetContext, pItem->GetItemID() );
+ steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use a description tag, or offer to buy one
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoDescription()
+{
+ static CSchemaItemDefHandle pItemDef_DescTag( "Description Tag" );
+ if ( !AttemptToUseItem( pItemDef_DescTag->GetDefinitionIndex() ) )
+ {
+ AttemptToShowItemInStore( pItemDef_DescTag->GetDefinitionIndex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use a name tag, or offer to buy one
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoRename()
+{
+ static CSchemaItemDefHandle pItemDef_NameTag( "Name Tag" );
+ if ( !AttemptToUseItem( pItemDef_NameTag->GetDefinitionIndex() ) )
+ {
+ AttemptToShowItemInStore( pItemDef_NameTag->GetDefinitionIndex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Delete the selected items
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoDelete()
+{
+ // Hide the mouseover panel
+ HideMouseOverPanel();
+
+ int iItemsToDelete = 0;
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ iItemsToDelete++;
+ }
+ }
+
+ // Bring up confirm dialog
+ CConfirmDeleteItemDialog *pConfirm = vgui::SETUP_PANEL( new CConfirmDeleteItemDialog( this, ( iItemsToDelete > 1 ) ) );
+ if ( pConfirm )
+ {
+ pConfirm->Show();
+
+ m_pConfirmDeleteDialog = pConfirm;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use the selected tool
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoApplyOnItem()
+{
+ SetupToolSelectionItem();
+
+ if ( m_ToolSelectionItem.IsValid() )
+ {
+ const IEconTool *pEconTool = m_ToolSelectionItem.GetItemDefinition()->GetEconTool();
+
+ // Gather all quest objective attributes
+ CRecipeComponentMatchingIterator recipeIterator( NULL, NULL );
+ if ( m_ToolSelectionItem.GetSOCData() )
+ {
+ m_ToolSelectionItem.GetSOCData()->IterateAttributes( &recipeIterator );
+ }
+
+ if( pEconTool && recipeIterator.GetMatchingComponentInputs().Count() > 0 )
+ {
+ // Launch new crafting window if we need to
+ if( m_pDynamicRecipePanel == NULL )
+ {
+ m_pDynamicRecipePanel = vgui::SETUP_PANEL( new CDynamicRecipePanel( this, "dynamic_recipe_panel", &m_ToolSelectionItem ) );
+ }
+
+ // Set recipe item into panel
+ if ( m_pDynamicRecipePanel )
+ {
+ m_pDynamicRecipePanel->SetVisible( true );
+ m_pDynamicRecipePanel->SetNewRecipe( &m_ToolSelectionItem );
+ }
+ return;
+ }
+
+ // Check if we actually have any items we can use this tool on
+ bool bHasValidTargetItem = false;
+ CPlayerInventory *pInv = InventoryManager()->GetLocalInventory();
+ Assert( pInv );
+ if ( pInv )
+ {
+ for ( int i = 0 ; i < pInv->GetItemCount() ; ++i )
+ {
+ CEconItemView *pItem = pInv->GetItem( i );
+ if ( CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, pItem ) )
+ {
+ bHasValidTargetItem = true;
+ break;
+ }
+ }
+
+ // If no applicable items, try stock items
+ if ( !bHasValidTargetItem )
+ {
+ // this is really inefficient, maybe have a list of baseitems somewhere
+ CEconItemView tempItem;
+ const CEconItemDefinition* pItemDef = NULL;
+
+ const CEconItemSchema::SortedItemDefinitionMap_t& mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
+ for ( int it = mapItems.FirstInorder(); it != mapItems.InvalidIndex(); it = mapItems.NextInorder( it ) )
+ {
+ if ( mapItems[it]->IsBaseItem() && !mapItems[it]->IsHidden() )
+ {
+ CFmtStr fmtStrCustomizedDefName( "Upgradeable %s", mapItems[it]->GetDefinitionName() );
+ pItemDef = GetItemSchema()->GetItemDefinitionByName( fmtStrCustomizedDefName.Access() );
+ if ( pItemDef )
+ {
+ tempItem.Init( pItemDef->GetDefinitionIndex(), AE_UNIQUE, AE_USE_SCRIPT_VALUE, true );
+ if ( CEconSharedToolSupport::ToolCanApplyTo( &m_ToolSelectionItem, &tempItem ) )
+ {
+ bHasValidTargetItem = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( bHasValidTargetItem )
+ {
+ // automatically switch to stock items
+ OnCommand( "showbaseitems" );
+ }
+ }
+ }
+
+ if ( !bHasValidTargetItem )
+ {
+ ShowMessageBox( NULL, "#ToolNoTargetItems", "#GameUI_OK" );
+ return;
+ }
+
+ m_eSelectionMode = ToolSelection;
+ m_nLastToolPage = GetCurrentPage();
+
+ if ( m_pMouseOverTooltip )
+ {
+ m_pMouseOverTooltip->HideTooltip();
+ }
+
+ ClearNameFilter( true );
+ SetCurrentPage( 0 );
+ UpdateModelPanels();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: use a consumable item directly from the backpack
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoUseConsumableItem()
+{
+ SetupToolSelectionItem();
+
+#ifdef TF_CLIENT_DLL
+ UseConsumableItem( &m_ToolSelectionItem, this );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use the tool to unwrap an item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoUnwrapItem()
+{
+ DoUseConsumableItem();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Use the tool to deliver an item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoDeliverItem()
+{
+ SetupToolSelectionItem();
+
+#ifdef TF_CLIENT_DLL
+ const CEconTool_WrappedGift *pWrappedGiftTool = m_ToolSelectionItem.GetItemDefinition()
+ ? m_ToolSelectionItem.GetItemDefinition()->GetTypedEconTool<CEconTool_WrappedGift>()
+ : NULL;
+
+ if ( pWrappedGiftTool && pWrappedGiftTool->BIsDirectGift() )
+ {
+ DoUseConsumableItem();
+ return;
+ }
+ else if ( pWrappedGiftTool && pWrappedGiftTool->BIsGlobalGift() )
+ {
+ // If this is a global gift, we don't let the user pick a target so we're done as of now.
+ extern void UseUntargetedGiftConfirm( bool bConfirmed, void *pContext );
+ CTFGenericConfirmDialog *pDialog = ShowConfirmDialog( "#TF_DeliverGiftDialog_Title", "#TF_DeliverGiftDialog_Random_Text",
+ "#TF_DeliverGiftDialog_Confirm", "#TF_DeliverGiftDialog_Cancel",
+ &UseUntargetedGiftConfirm );
+
+ pDialog->SetContext( &m_ToolSelectionItem );
+ return;
+ }
+
+ DoGiftToPlayer();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Show
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoApplyByItem()
+{
+ SetupToolSelectionItem();
+
+ m_eSelectionMode = ToolSelection;
+ m_nLastToolPage = GetCurrentPage();
+
+ if ( m_pMouseOverTooltip )
+ {
+ m_pMouseOverTooltip->HideTooltip();
+ }
+
+ ClearNameFilter( true );
+ SetCurrentPage( 0 );
+ UpdateModelPanels();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: open shuffle items dialog
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoShuffle()
+{
+ SetupToolSelectionItem();
+
+ CInputStringForItemBackpackOverlayDialog *pDialog = vgui::SETUP_PANEL( new CInputStringForItemBackpackOverlayDialog( this, &m_ToolSelectionItem ) );
+ if ( pDialog )
+ {
+ pDialog->Show();
+ }
+}
+
+void CBackpackPanel::DoEditSlot()
+{
+ SetupToolSelectionItem();
+
+ // Launch new slot window if we need to
+ if( m_pItemSlotPanel == NULL )
+ {
+ m_pItemSlotPanel = vgui::SETUP_PANEL( new CItemSlotPanel( this ) );
+ }
+
+ // Set item into panel
+ if ( m_pItemSlotPanel )
+ {
+ m_pItemSlotPanel->SetVisible( true );
+ m_pItemSlotPanel->SetItem( m_ToolSelectionItem.GetSOCData() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Refurbish item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoRefurbishItem()
+{
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ m_ComboBoxOverlaySelectionItem = *m_pItemModelPanels[i]->GetItem();
+ break;
+ }
+ }
+
+ CRefurbishItemDialog *pRefurbishDialog = vgui::SETUP_PANEL( new CRefurbishItemDialog( this, &m_ComboBoxOverlaySelectionItem ) );
+ if ( pRefurbishDialog )
+ {
+ pRefurbishDialog->Show();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deode by item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoGetItemFromStore()
+{
+ SetupToolSelectionItem();
+
+ uint32 iDecoableItemDef = 0;
+ if ( GetDecodedByItemDefIndex( &m_ToolSelectionItem, &iDecoableItemDef ) )
+ {
+ // casting to the proper type since our econ system is dumb
+ const float& value_as_float = (float&)iDecoableItemDef;
+ CEconItemDefinition * pDefIndex = GetItemSchema()->GetItemDefinition( (int)value_as_float );
+
+ EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( pDefIndex->GetDefinitionIndex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open End of the Line duck leaderboards
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoOpenDuckLeaderboards()
+{
+ CCharacterInfoPanel* pCharInfo = dynamic_cast< CCharacterInfoPanel* >( EconUI() );
+ CDucksLeaderboardManager *pDuckLeaderboards = vgui::SETUP_PANEL( new CDucksLeaderboardManager( pCharInfo, "DucksLeaderboardPanel" ) );
+ pDuckLeaderboards->SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+// Strange Count Transfer Dialog
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoStrangeCountTransfer()
+{
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels( SELECT_FIRST, vecSelected );
+
+ Assert( vecSelected.Count() );
+ if ( vecSelected.IsEmpty() )
+ return;
+
+ m_pStrangeToolPanel = vgui::SETUP_PANEL( new CStrangeCountTransferPanel( this, vecSelected[0]->GetItem() ) );
+}
+
+//-----------------------------------------------------------------------------
+// Collection crafting
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoCraftUpCollection()
+{
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels( SELECT_ALL, vecSelected );
+
+ //Assert( vecSelected.Count() );
+ //if ( vecSelected.IsEmpty() )
+ // return;
+
+ // Get all the items that were selected
+ CUtlVector< const CEconItemView* > vecSelectedItems;
+ FOR_EACH_VEC( vecSelected, i )
+ {
+ if ( vecSelected[ i ]->GetItem() && GetCollectionCraftingInvalidReason( vecSelected[ i ]->GetItem(), NULL ) == NULL )
+ {
+ vecSelectedItems.AddToTail( vecSelected[ i ]->GetItem() );
+ }
+ }
+
+ // For tracking how many times they've opened this menu
+ tf_trade_up_use_count.SetValue( tf_trade_up_use_count.GetInt() - 1 );
+
+ // Open it up!
+ GetCollectionCraftPanel()->Show( vecSelectedItems );
+}
+
+//-----------------------------------------------------------------------------
+// Collection crafting
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoHalloweenOffering()
+{
+ // Open it up!
+ if ( !m_pHalloweenOfferingPanel )
+ {
+ m_pHalloweenOfferingPanel = vgui::SETUP_PANEL( new CHalloweenOfferingPanel( this, m_pMouseOverTooltip ) );
+ m_pHalloweenOfferingPanel->InvalidateLayout( true, true );
+ }
+ // empty
+ CUtlVector< const CEconItemView* > vecSelectedItems;
+ m_pHalloweenOfferingPanel->Show( vecSelectedItems );
+}
+
+//-----------------------------------------------------------------------------
+// Craft Common StatClock
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoCraftCommonStatClock()
+{
+ // Open it up!
+ if ( !m_pMannCoTradePanel )
+ {
+ m_pMannCoTradePanel = vgui::SETUP_PANEL( new CCraftCommonStatClockPanel( this, m_pMouseOverTooltip ) ); // make this more generic
+ m_pMannCoTradePanel->InvalidateLayout( true, true );
+ }
+
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels(SELECT_ALL, vecSelected);
+
+ CUtlVector< const CEconItemView* > vecSelectedItems;
+ FOR_EACH_VEC(vecSelected, i)
+ {
+ if (vecSelected[i]->GetItem() && GetCraftCommonStatClockInvalidReason(vecSelected[i]->GetItem(), NULL) == NULL)
+ {
+ vecSelectedItems.AddToTail(vecSelected[i]->GetItem());
+ }
+ }
+
+ m_pMannCoTradePanel->Show( vecSelectedItems );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Bring up the 3D inspect panel for the selected item
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoInspectModel()
+{
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels( SELECT_FIRST, vecSelected );
+
+ if ( vecSelected.IsEmpty() )
+ return;
+
+ CEconItemView *pItem = vecSelected[0]->GetItem();
+ if ( pItem )
+ {
+ float flInspect = 0;
+ static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
+ if ( ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItem, pAttrib_WeaponAllowInspect, &flInspect ) && flInspect != 0.f )
+#ifdef STAGING_ONLY
+ || tf_weapon_force_allow_inspect.GetBool()
+#endif
+ )
+ {
+ m_pInspectPanel->SetVisible( true );
+ m_pInspectPanel->SetItemCopy( vecSelected[0]->GetItem() );
+ }
+ else
+ {
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; ++iClass )
+ {
+ if ( pItem->GetStaticData()->CanBeUsedByClass( iClass ) )
+ {
+ m_pInspectCosmeticPanel->PreviewItem( iClass, pItem );
+ break;
+ }
+ }
+ m_pInspectCosmeticPanel->SetVisible( true );
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OpenInspectModelPanelAndCopyItem( CEconItemView *pItemView )
+{
+ if ( !pItemView )
+ return;
+
+ EconUI()->OpenEconUI( ECONUI_BACKPACK );
+
+ // Figure out which preview to show
+ float flInspect = 0;
+ static CSchemaAttributeDefHandle pAttrib_WeaponAllowInspect( "weapon_allow_inspect" );
+ if ( FindAttribute_UnsafeBitwiseCast<attrib_value_t>( pItemView, pAttrib_WeaponAllowInspect, &flInspect ) && flInspect != 0.f )
+ {
+ m_pInspectPanel->SetVisible( true );
+ m_pInspectPanel->SetItemCopy( pItemView );
+ }
+ else
+ {
+ for ( int iClass = TF_FIRST_NORMAL_CLASS; iClass < TF_LAST_NORMAL_CLASS; ++iClass )
+ {
+ if ( pItemView->GetStaticData()->CanBeUsedByClass( iClass ) )
+ {
+ m_pInspectCosmeticPanel->PreviewItemCopy( iClass, pItemView );
+ m_pInspectCosmeticPanel->SetVisible( true );
+ break;
+ }
+ }
+ }
+}
+
+CCollectionCraftingPanel* CBackpackPanel::GetCollectionCraftPanel()
+{
+ if ( !m_pCollectionCraftPanel )
+ {
+ m_pCollectionCraftPanel = vgui::SETUP_PANEL( new CCollectionCraftingPanel( this, m_pMouseOverTooltip ) );
+ m_pCollectionCraftPanel->InvalidateLayout( true, true );
+ }
+
+ return m_pCollectionCraftPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Buy a key, and then immediately use it on the selected crate once
+// tbe store transaction completes
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoBuyKeyAndOpenCrate()
+{
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels( SELECT_FIRST, vecSelected );
+
+ if ( vecSelected.IsEmpty() )
+ return;
+
+ m_hQuickOpenCrate.SetItem( vecSelected.Head()->GetItem() );
+
+ uint32 iDecoableItemDef = 0;
+ if ( GetDecodedByItemDefIndex( m_hQuickOpenCrate, &iDecoableItemDef ) )
+ {
+ // casting to the proper type since our econ system is dumb
+ const float& value_as_float = (float&)iDecoableItemDef;
+ CEconItemDefinition * pDefIndex = GetItemSchema()->GetItemDefinition( (int)value_as_float );
+
+ EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( pDefIndex->GetDefinitionIndex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Find the first compatible key in our inventory, and use it on the
+// selected crate
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoOpenCrateWithKey()
+{
+ CUtlVector< CItemModelPanel* > vecSelected;
+ GetSelectedPanels( SELECT_FIRST, vecSelected );
+
+ if ( vecSelected.IsEmpty() )
+ return;
+
+ CEconItemView *pCrate = vecSelected.Head()->GetItem();
+
+ CEconItemView *pKey = GetFirstCompatibleKeyForCrate( pCrate );
+ if ( !pKey )
+ return;
+
+ ApplyTool( this, pKey, pCrate );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Open up the loadout for a class
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoEquipForClass( int nClass )
+{
+ // Negative because reasons
+ EconUI()->OpenEconUI( -nClass );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Given a paint can index, offer to use one or buy one
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoPaint( int nPaintItemIndex, bool bUseStore, bool bUseMarket )
+{
+ if ( !bUseStore && !bUseMarket )
+ {
+ AttemptToUseItem( nPaintItemIndex );
+ }
+
+ if ( bUseStore )
+ {
+ AttemptToShowItemInStore( nPaintItemIndex );
+ }
+ else if ( bUseMarket )
+ {
+ AttemptToShowItemInMarket( nPaintItemIndex );
+ }
+}
+//-----------------------------------------------------------------------------
+// Purpose: Given a strange part index, offer to use one or buy one (Market)
+//-----------------------------------------------------------------------------
+void CBackpackPanel::DoStrangePart( int nStrangePartIndex, bool bUseMarket )
+{
+ if ( !bUseMarket )
+ {
+ AttemptToUseItem( nStrangePartIndex );
+ }
+
+ if ( bUseMarket )
+ {
+ AttemptToShowItemInMarket( nStrangePartIndex );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Try to find the first item with the passed-in item name in our inventory
+// and try to use it on the selected panel's item. If we dont have an item
+// matching the name passed in, go to the store and prompt the user to buy one.
+//-----------------------------------------------------------------------------
+bool CBackpackPanel::AttemptToUseItem( item_definition_index_t iItemDefIndex )
+{
+ CUtlVector< CItemModelPanel* > m_vecSelected;
+ GetSelectedPanels( SELECT_FIRST, m_vecSelected );
+ Assert( m_vecSelected.Count() );
+ if ( !m_vecSelected.Count() )
+ return false;
+
+ CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
+ Assert( pSelectedItem );
+ if ( !pSelectedItem )
+ return false;
+
+ CEconItemView *pNameTag = CTFPlayerInventory::GetFirstItemOfItemDef( iItemDefIndex );
+ if ( pNameTag )
+ {
+ if ( ApplyTool( this, pNameTag, pSelectedItem ) )
+ {
+ CancelToolSelection();
+ UpdateModelPanels();
+ }
+ return true;
+ }
+ return false;
+}
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AttemptToShowItemInStore( item_definition_index_t iItemDefIndex )
+{
+ CUtlVector< CItemModelPanel* > m_vecSelected;
+ GetSelectedPanels( SELECT_FIRST, m_vecSelected );
+ Assert( m_vecSelected.Count() );
+ if( !m_vecSelected.Count() )
+ return;
+
+ CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
+ Assert( pSelectedItem );
+ if ( !pSelectedItem )
+ return;
+
+ EconUI()->OpenStorePanel( iItemDefIndex, false );
+}
+//-----------------------------------------------------------------------------
+void CBackpackPanel::AttemptToShowItemInMarket( item_definition_index_t iItemDefIndex )
+{
+ CUtlVector< CItemModelPanel* > m_vecSelected;
+ GetSelectedPanels( SELECT_FIRST, m_vecSelected );
+ Assert( m_vecSelected.Count() );
+ if ( !m_vecSelected.Count() )
+ return;
+
+ CEconItemView *pSelectedItem = m_vecSelected.Head()->GetItem();
+ Assert( pSelectedItem );
+ if ( !pSelectedItem )
+ return;
+
+ CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( iItemDefIndex );
+ Assert( pItemDef );
+ if ( !pItemDef )
+ return;
+
+ if ( !CBaseAdPanel::CheckForRequiredSteamComponents( "#StoreUpdate_SteamRequired", "#MMenu_OverlayRequired" ) )
+ return;
+
+ if ( pItemDef && steamapicontext && steamapicontext->SteamFriends() )
+ {
+ const char *pszPrefix = "";
+ if ( GetUniverse() == k_EUniverseBeta )
+ {
+ pszPrefix = "beta.";
+ }
+
+ static char pszItemName[256];
+ g_pVGuiLocalize->ConvertUnicodeToANSI( g_pVGuiLocalize->Find( pItemDef->GetItemBaseName() ), pszItemName, sizeof( pszItemName ) );
+
+ char szURL[512];
+ V_snprintf( szURL, sizeof( szURL ), "http://%ssteamcommunity.com/market/listings/%d/%s", pszPrefix, engine->GetAppID(), pszItemName );
+ steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( szURL );
+ }
+}
+//-----------------------------------------------------------------------------
+// Purpose: Get the first, or all selected item model panels
+//-----------------------------------------------------------------------------
+void CBackpackPanel::GetSelectedPanels( ESelection eSelection, CUtlVector< CItemModelPanel* >& m_vecSelected ) const
+{
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ m_vecSelected.AddToTail( m_pItemModelPanels[i] );
+
+ if ( eSelection == SELECT_FIRST )
+ {
+ return;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OnCommand( const char *command )
+{
+ if ( V_strncasecmp( command, "goto_page_", V_strlen( "goto_page_" ) ) == 0 )
+ {
+ int iPage = V_atoi( &command[ V_strlen( "goto_page_" ) ] );
+ SetCurrentPage( iPage );
+ UpdateModelPanels();
+ return;
+ }
+ else if ( !Q_strnicmp( command, "nextpage", 8 ) )
+ {
+ if ( !m_bDragging )
+ {
+ DeSelectAllBackpackItemPanels();
+ }
+
+ SetCurrentPage( GetCurrentPage() + 1 );
+ UpdateModelPanels();
+ return;
+ }
+ else if ( !Q_strnicmp( command, "prevpage", 8 ) )
+ {
+ if ( !m_bDragging )
+ {
+ DeSelectAllBackpackItemPanels();
+ }
+
+ SetCurrentPage( GetCurrentPage() - 1 );
+ UpdateModelPanels();
+ return;
+ }
+ else if ( !Q_strnicmp( command, "useitem", 7 ) )
+ {
+ AssertMsg( 0, "Everything should be going through the context menu. Fix the calling code." );
+ return;
+ }
+ else if ( !Q_strnicmp( command, "showbackpackitems", 17 ) )
+ {
+ SetShowBaseItems( false );
+ if ( m_pShowBaseItemsCheckbox )
+ {
+ m_pShowBaseItemsCheckbox->SetSelected( false );
+ }
+ return;
+ }
+ else if ( !Q_strnicmp( command, "showbaseitems", 13 ) )
+ {
+ SetShowBaseItems( true );
+ if ( m_pShowBaseItemsCheckbox )
+ {
+ m_pShowBaseItemsCheckbox->SetSelected( true );
+ }
+ return;
+ }
+ else if ( !Q_strnicmp( command, "canceltool", 10 ) )
+ {
+ CancelToolSelection();
+ UpdateModelPanels();
+ return;
+ }
+ else if ( !Q_stricmp( command, "show_explanations" ) )
+ {
+ if ( !m_flStartExplanationsAt )
+ {
+ m_flStartExplanationsAt = Plat_FloatTime();
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+ }
+ RequestFocus();
+ }
+ else if ( !Q_stricmp( command, "showdetails" ) )
+ {
+ for ( int i = 0; i < m_pItemModelPanels.Count(); i++ )
+ {
+ if ( m_pItemModelPanels[i]->IsSelected() && m_pItemModelPanels[i]->HasItem() )
+ {
+ OpenArmory( m_pItemModelPanels[i]->GetItem() );
+ break;
+ }
+ }
+ UpdateModelPanels();
+ return;
+ }
+ else if ( !V_strnicmp( command, "equipclass", 10 ) )
+ {
+ int nClass = atoi( command + 10 );
+ DoEquipForClass( nClass );
+ }
+ else if ( !V_strnicmp( command, "paint", 5 ) )
+ {
+ int nIndex = atoi( command + 5 );
+ DoPaint( nIndex, false, false );
+ }
+ else if ( !V_strnicmp( command, "market_paint", 12 ) )
+ {
+ int nIndex = atoi( command + 12 );
+ DoPaint( nIndex, false, true );
+ }
+ else if ( !V_strnicmp( command, "store_paint", 11 ) )
+ {
+ int nIndex = atoi( command + 11 );
+ DoPaint( nIndex, true, false );
+ }
+ else if ( !V_strnicmp( command, "strangepart_", 12 ) )
+ {
+ int nIndex = atoi( command + 12 );
+ DoStrangePart( nIndex, false );
+ }
+ else if ( !V_strnicmp( command, "market_strangepart_", 19 ) )
+ {
+ int nIndex = atoi( command + 19 );
+ DoStrangePart( nIndex, true );
+ }
+ else if ( !V_strnicmp( command, "Context_CraftUpCollection", 25 ) )
+ {
+ DoCraftUpCollection();
+ }
+ else if ( !V_strnicmp( command, "Context_CraftCommonStatClock", 25 ) )
+ {
+ DoCraftCommonStatClock();
+ }
+#ifdef STAGING_ONLY
+ else if ( !V_strnicmp( command, "unpin", 5 ) )
+ {
+ m_pMouseOverCardPanel->PinCard( false );
+ }
+#endif
+
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::OpenArmory( CEconItemView* item )
+{
+ PostMessage( GetParent()->GetParent()->GetParent(), new KeyValues("OpenArmoryDirect", "itemdef", item->GetItemDefIndex() ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::CancelToolSelection( void )
+{
+ if ( m_eSelectionMode == StandardSelection )
+ return;
+
+ m_eSelectionMode = StandardSelection;
+
+ ClearNameFilter( false );
+
+ OnCommand( "showbackpackitems" );
+
+ SetCurrentPage( m_nLastToolPage );
+ m_nLastToolPage = 0;
+
+ m_ToolSelectionItem.Invalidate();
+ if ( m_pToolIcon )
+ {
+ m_pToolIcon->SetVisible( false );
+ }
+ DeSelectAllBackpackItemPanels();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetShowBaseItems( bool bShow )
+{
+ bool bGoToFirstPage = m_bShowBaseItems != bShow;
+ m_bShowBaseItems = bShow;
+ if( bGoToFirstPage )
+ {
+ SetCurrentPage( 0 );
+ }
+
+ DeSelectAllBackpackItemPanels();
+ if ( m_pToolIcon )
+ {
+ m_pToolIcon->SetVisible( false );
+ }
+ UpdateModelPanels();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ConVar *CBackpackPanel::GetExplanationConVar( void )
+{
+ return &tf_explanations_backpackpanel;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackpackPanel::SetCurrentPage( int nNewPage )
+{
+ if( m_pToolIcon )
+ {
+ m_pToolIcon->SetVisible( false );
+ }
+
+ if ( nNewPage < 0 )
+ {
+ nNewPage = GetNumPages() - 1;
+ }
+ else if ( nNewPage >= GetNumPages() )
+ {
+ nNewPage = 0;
+ }
+
+ // deselect old page button
+ if ( m_Pages.Count() > GetCurrentPage() && m_Pages[GetCurrentPage()] )
+ {
+ CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[GetCurrentPage()]->FindChildByName( "Button" ) );
+ if ( pButton )
+ {
+ pButton->SetSelected( false );
+ }
+ }
+
+ BaseClass::SetCurrentPage( nNewPage );
+
+ // mark new page button as selected
+ if ( m_Pages.Count() > GetCurrentPage() && m_Pages[GetCurrentPage()] )
+ {
+ CExButton* pButton = dynamic_cast<CExButton*>( m_Pages[GetCurrentPage()]->FindChildByName( "Button" ) );
+ if ( pButton )
+ {
+ pButton->SetSelected( true );
+ }
+ }
+}
+
+
+int CBackpackPanel::GetItemQualityForBorder( CItemModelPanel* pItemPanel ) const
+{
+ if ( pItemPanel->HasItem() && ( cl_showbackpackrarities.GetInt() > 0 || m_bForceShowBackpackRarities )
+ && ( cl_showbackpackrarities.GetInt() < 2 || pItemPanel->GetItem()->IsMarketable() ) )
+ {
+ uint8 nRarity = pItemPanel->GetItem()->GetItemDefinition()->GetRarity();
+ if ( ( nRarity != k_unItemRarity_Any ) && ( pItemPanel->GetItem()->GetItemQuality() != AE_SELFMADE ) )
+ {
+ // translate this quality to rarity
+ return nRarity + AE_RARITY_DEFAULT;
+ }
+
+ return pItemPanel->GetItem()->GetItemQuality();
+ }
+
+ return 0;
+}