//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "crate_detail_panels.h" #include "vgui_controls/TextImage.h" #include "econ_gcmessages.h" #include "gc_clientsystem.h" #include "econ_ui.h" #include #include "econ_item_inventory.h" #include "econ/tool_items/tool_items.h" #define SHUFFLE_TIME 5.f float CInputStringForItemBackpackOverlayDialog::m_sflNextShuffleTime = 0.f; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CInputStringForItemBackpackOverlayDialog::CInputStringForItemBackpackOverlayDialog( vgui::Panel *pParent, CEconItemView *pItem, CEconItemView *pChosenKey ) : vgui::EditablePanel( pParent, "InputStringForItemBackpackOverlayDialog" ) , m_Item( *pItem ) , m_pPreviewModelPanel( NULL ) , m_pTextEntry( NULL ) , m_pItemModelPanelKVs( NULL ) , m_bUpdateRecieved( false ) { if ( pChosenKey ) { m_UseableKey = *pChosenKey; } m_pPreviewModelPanel = new CItemModelPanel( this, "preview_model" ); m_pTextEntry = new vgui::TextEntry( this, "TextEntryControl" ); m_pShuffleButton = new CExButton( this, "ShuffleButton", "Shuffle" ); m_pRareLootLabel = new CExLabel( this, "RareLootLabel", "#Econ_Revolving_Loot_List_Rare_Item" ); m_pProgressBar = new vgui::ProgressBar( this, "ShuffleProgress" ); m_pGetKeyButton = new CExButton( this, "GetKeyButton", "getkey" ); m_pUseKeyButton = new CExButton( this, "UseKeyButton", "usekey" ); m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) ); m_pMouseOverTooltip = new CItemModelPanelToolTip( this ); m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel ); ListenForGameEvent( "inventory_updated" ); } CInputStringForItemBackpackOverlayDialog::~CInputStringForItemBackpackOverlayDialog() { if ( m_pItemModelPanelKVs ) { m_pItemModelPanelKVs->deleteThis(); m_pItemModelPanelKVs = NULL; } m_vecContentsPanels.PurgeAndDeleteElements(); } void CInputStringForItemBackpackOverlayDialog::FireGameEvent( IGameEvent *event ) { // If we're not visible, ignore all events if ( !IsVisible() ) return; // Something caused our inventory to update. Assuming it was from our shuffle // then we need to update ourselves. const char *type = event->GetName(); if ( Q_strcmp( "inventory_updated", type ) == 0 ) { m_bUpdateRecieved = true; } } void CInputStringForItemBackpackOverlayDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); LoadControlSettings( "Resource/UI/econ/InputStringForItemBackpackOverlayDialog.res" ); CCrateLootListWrapper itemWrapper( &m_Item ); const IEconLootList *pLootList = itemWrapper.GetEconLootList(); // Set the crate footer text. The crate itself specifies what to use. if ( pLootList->GetLootListFooterLocalizationKey() ) { m_pRareLootLabel->SetText( pLootList->GetLootListFooterLocalizationKey() ); } else { const char *pszRareLootListFooterLocalizationKey = m_Item.GetItemDefinition()->GetDefinitionString( "loot_list_rare_item_footer", "#Econ_Revolving_Loot_List_Rare_Item" ); m_pRareLootLabel->SetText( pszRareLootListFooterLocalizationKey ); } // Use the gradient border for the tooltip m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") ); m_pPreviewModelPanel->SetItem( &m_Item ); m_pPreviewModelPanel->SetActAsButton( false, false ); // Dont mess around with the mouse m_pTextEntry->RequestFocus(); } void CInputStringForItemBackpackOverlayDialog::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData ); // Pull out the model panel KVs for this panel KeyValues *pItemKV = inResourceData->FindKey( "modelpanels_kv" ); if ( pItemKV ) { if ( m_pItemModelPanelKVs ) { m_pItemModelPanelKVs->deleteThis(); } m_pItemModelPanelKVs = new KeyValues( "modelpanels_kv" ); pItemKV->CopySubkeys( m_pItemModelPanelKVs ); } CreateItemPanels(); } void CInputStringForItemBackpackOverlayDialog::CreateItemPanels() { CCrateLootListWrapper itemWrapper( &m_Item ); const IEconLootList *pLootList = itemWrapper.GetEconLootList(); class CItemDefLootListIterator : public IEconLootList::IEconLootListIterator { public: CItemDefLootListIterator( CUtlVector< item_definition_index_t > *pVecItemDefs ) : m_pVecItemDefs( pVecItemDefs ) {} virtual void OnIterate( item_definition_index_t unItemDefIndex ) OVERRIDE { const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( unItemDefIndex ); if ( pItemDef && pItemDef->BValidForShuffle() ) { m_pVecItemDefs->AddToTail( unItemDefIndex ); } } private: CUtlVector< item_definition_index_t > * const m_pVecItemDefs; }; // Get the drops from the item CUtlVector< item_definition_index_t > vecItemDefs; CItemDefLootListIterator it( &vecItemDefs ); pLootList->EnumerateUserFacingPotentialDrops( &it ); if ( !m_pItemModelPanelKVs ) return; if ( m_vecContentsPanels.Count() != vecItemDefs.Count() ) { m_vecContentsPanels.PurgeAndDeleteElements(); FOR_EACH_VEC( vecItemDefs, i ) { // Create new panel CItemModelPanel* pItemPanel = m_vecContentsPanels[ m_vecContentsPanels.AddToTail( new CItemModelPanel( this, CFmtStr( "item_preview_%d", i ) ) ) ]; pItemPanel->ApplySettings( m_pItemModelPanelKVs ); pItemPanel->InvalidateLayout( true ); pItemPanel->SetActAsButton( false, true ); // Lets us get mouse enter/exit evens for tooltips pItemPanel->SetTooltip( m_pMouseOverTooltip, "" ); // Tooltip panel to use } } // Create the panels and set the items into them FOR_EACH_VEC( vecItemDefs, i ) { const item_definition_index_t &itemDef = vecItemDefs[i]; CItemModelPanel* pItemPanel = m_vecContentsPanels[i]; CEconItemView item; item.SetItemDefIndex( itemDef ); item.SetItemQuality( AE_UNIQUE ); // Unique by default item.SetItemLevel( 0 ); // Hide this? item.SetInitialized( true ); item.SetItemOriginOverride( kEconItemOrigin_Invalid ); pItemPanel->SetItem( &item ); } } void CInputStringForItemBackpackOverlayDialog::PerformLayout( void ) { BaseClass::PerformLayout(); // Find out how wide these panels will be side by side const int nBuffer = 5; int nTotalWide = 0; const int nCount = m_vecContentsPanels.Count(); if ( nCount ) { const int nWide = m_vecContentsPanels.Head()->GetWide(); nTotalWide = (nCount * nWide) + ( (nCount - 1) * nBuffer ); } // Find out how much space the panels take up within the parent int nParentWide = GetWide(); int nDiff = nParentWide - nTotalWide; // How far we need to offset from the left edge int nStartOffset = nDiff / 2; // Place all the panels side by side FOR_EACH_VEC( m_vecContentsPanels, i ) { CItemModelPanel* pItemPanel = m_vecContentsPanels[ i ]; const int nWide = pItemPanel->GetWide(); pItemPanel->SetPos( nStartOffset + i * (nWide + nBuffer), YRES(150) ); pItemPanel->SetVisible( true ); } // Which button to show m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() ); m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() ); } void CInputStringForItemBackpackOverlayDialog::OnCommand( const char *command ) { if ( !Q_strnicmp( command, "cancel", 6 ) ) { TFModalStack()->PopModal( this ); SetVisible( false ); MarkForDeletion(); } else if ( !Q_strnicmp( command, "shuffle", 7 ) ) { // let the GC know if ( m_pTextEntry && Plat_FloatTime() >= m_sflNextShuffleTime ) { // Set the next time they can send a request to shuffle m_sflNextShuffleTime = Plat_FloatTime() + SHUFFLE_TIME; enum { kMaxCodeStringSize = 32 }; char szText[ kMaxCodeStringSize ] = { 0 }; m_pTextEntry->GetText( &szText[0], sizeof( szText ) ); GCSDK::CProtoBufMsg msg( k_EMsgGCShuffleCrateContents ); msg.Body().set_crate_item_id( m_Item.GetID() ); msg.Body().set_user_code_string( szText ); GCClientSystem()->BSendMessage( msg ); m_pProgressBar->SetProgress( 0.f ); m_pProgressBar->SetVisible( true ); m_pTextEntry->SetVisible( false ); vgui::surface()->PlaySound( "ui/itemcrate_shuffle.wav" ); } } else if ( !Q_strnicmp( command, "getkey", 6 ) ) { static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" ); uint32 iDecodableItemDef = 0; if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) ) { // casting to the proper type since our econ system is dumb const float& value_as_float = (float&)iDecodableItemDef; EconUI()->CloseEconUI(); EconUI()->OpenStorePanel( (int)value_as_float, false ); // close ourselves TFModalStack()->PopModal( this ); SetVisible( false ); MarkForDeletion(); } } else if ( !Q_strnicmp( command, "usekey", 6 ) ) { if ( m_UseableKey.IsValid() ) { // Use the key ApplyTool( GetParent(), &m_UseableKey, &m_Item ); // close ourselves TFModalStack()->PopModal( this ); SetVisible( false ); MarkForDeletion(); } } } void CInputStringForItemBackpackOverlayDialog::FindUsableKey() { static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" ); uint32 iDecodableItemDef = 0; if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) ) { const float& value_as_float = (float&)iDecodableItemDef; iDecodableItemDef = (float)value_as_float; CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory(); if ( !pInventory ) return; for ( int i = 0; i < pInventory->GetItemCount(); i++ ) { CEconItemView *pItem = pInventory->GetItem(i); if ( pItem->GetItemDefIndex() == iDecodableItemDef ) { m_UseableKey = *pItem; } } } } void CInputStringForItemBackpackOverlayDialog::OnThink() { float flDelta = m_sflNextShuffleTime - Plat_FloatTime(); // If we're ready, show "Shuffle" if ( flDelta < 0 ) { // Show the text entry, show the progress bar m_pProgressBar->SetVisible( false ); m_pTextEntry->SetVisible( true ); // Re-enable the shuffle/use buttons m_pShuffleButton->SetEnabled( m_pTextEntry->GetTextLength() != 0 ); m_pUseKeyButton->SetEnabled( true ); // Say "Shuffle" m_pShuffleButton->SetText( "#ShuffleContents" ); // We got a inventory update message, update if ( m_bUpdateRecieved ) { CreateItemPanels(); m_bUpdateRecieved = false; } } else { // Show the progress bar, hide the text field m_pProgressBar->SetVisible( true ); m_pTextEntry->SetVisible( false ); // Dont allow clicking the shuffle or use key button m_pShuffleButton->SetEnabled( false ); m_pUseKeyButton->SetEnabled( false ); // Say "Shuffling..." m_pShuffleButton->SetText( "#ShufflingContents" ); // Set progress float flProgress = ( SHUFFLE_TIME - flDelta ) / SHUFFLE_TIME; m_pProgressBar->SetProgress( flProgress ); } } void CInputStringForItemBackpackOverlayDialog::Show() { SetVisible( true ); MakePopup(); MoveToFront(); SetKeyBoardInputEnabled( true ); SetMouseInputEnabled( true ); TFModalStack()->PushModal( this ); // If a key wasnt passed in, find the first one in the // player's inventory if ( !m_UseableKey.IsValid() ) { FindUsableKey(); } // Which button to show m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() ); m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() ); // Put the current gen code of the crate into the text field static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "crate generation code" ); const char *pszAttrGenCode; if ( FindAttribute_UnsafeBitwiseCast( &m_Item, pAttrDef_DecodedBy, &pszAttrGenCode ) ) { m_pTextEntry->SetText( pszAttrGenCode ); } }