Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4272 lines
143 KiB

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