//========= 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 #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 #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( "NameFilterTextEntry" ); if ( m_pNameFilterTextEntry ) { m_pNameFilterTextEntry->AddActionSignalTarget( this ); } m_pCancelToolButton = dynamic_cast( FindChildByName("CancelApplyToolButton") ); m_pCraftButton = dynamic_cast( FindChildByName("CraftButton") ); m_pToolIcon = dynamic_cast( FindChildByName("tool_icon") ); m_pNextPageButton = dynamic_cast( FindChildByName("NextPageButton") ); m_pPrevPageButton = dynamic_cast( FindChildByName("PrevPageButton") ); m_pShowExplanationsButton = dynamic_cast( FindChildByName("ShowExplanationsButton") ); m_pDragToNextPageButton = dynamic_cast( FindChildByName("DragToNextPageButton") ); m_pDragToPrevPageButton = dynamic_cast( FindChildByName("DragToPrevPageButton") ); m_pCurPageLabel = dynamic_cast( FindChildByName("CurPageLabel") ); m_pShowRarityComboBox = dynamic_cast( 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( 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(); iInvalidateLayout( 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 vecPageCount; CUtlVector 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( 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( 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; iApplySettings( m_pPageButtonKVs ); CExButton* pButton = dynamic_cast( 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( 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( 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( 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( 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 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( pItem, pAttrib_WeaponAllowInspect, &flInspect ) || FindAttribute_UnsafeBitwiseCast( 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( GEconItemSchema().GetItemDefinitionByName( "Name Tag" ) ); if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast( pNameTagDef ), pItemDef ) ) { contextMenuBuilder.AddMenuItem( "#Context_Rename", new KeyValues( "DoRename" ), "customization" ); } // Change description GameItemDefinition_t * pDescTagDef = dynamic_cast( GEconItemSchema().GetItemDefinitionByName( "Description Tag" ) ); if ( CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast( 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( GEconItemSchema().GetItemDefinition( m_vecPaintCans[0] ) ); if ( pPaintCanDef && CEconSharedToolSupport::ToolCanApplyToDefinition( dynamic_cast( 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 vecOwnedPaints; CUtlVector 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 vecOwnedParts; CUtlVector 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( 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( 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( data->GetPtr("panel") ); vgui::TextEntry *pTextEntry = dynamic_cast( 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( 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( 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 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( &m_Item, pAttrDef, &fScoreType ) || iKillEaterAttrIndex == 0 ); // Dispatch message. EconUI()->Gamestats_ItemTransaction( IE_ITEM_REMOVED_ATTRIB, &m_Item, "strange_part" ); GCSDK::CProtoBufMsg 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 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 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() : 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( 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( 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( 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( 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; }