Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

388 lines
12 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "crate_detail_panels.h"
  8. #include "vgui_controls/TextImage.h"
  9. #include "econ_gcmessages.h"
  10. #include "gc_clientsystem.h"
  11. #include "econ_ui.h"
  12. #include <vgui/ISurface.h>
  13. #include "econ_item_inventory.h"
  14. #include "econ/tool_items/tool_items.h"
  15. #define SHUFFLE_TIME 5.f
  16. float CInputStringForItemBackpackOverlayDialog::m_sflNextShuffleTime = 0.f;
  17. //-----------------------------------------------------------------------------
  18. // Purpose:
  19. //-----------------------------------------------------------------------------
  20. CInputStringForItemBackpackOverlayDialog::CInputStringForItemBackpackOverlayDialog( vgui::Panel *pParent, CEconItemView *pItem, CEconItemView *pChosenKey )
  21. : vgui::EditablePanel( pParent, "InputStringForItemBackpackOverlayDialog" )
  22. , m_Item( *pItem )
  23. , m_pPreviewModelPanel( NULL )
  24. , m_pTextEntry( NULL )
  25. , m_pItemModelPanelKVs( NULL )
  26. , m_bUpdateRecieved( false )
  27. {
  28. if ( pChosenKey )
  29. {
  30. m_UseableKey = *pChosenKey;
  31. }
  32. m_pPreviewModelPanel = new CItemModelPanel( this, "preview_model" );
  33. m_pTextEntry = new vgui::TextEntry( this, "TextEntryControl" );
  34. m_pShuffleButton = new CExButton( this, "ShuffleButton", "Shuffle" );
  35. m_pRareLootLabel = new CExLabel( this, "RareLootLabel", "#Econ_Revolving_Loot_List_Rare_Item" );
  36. m_pProgressBar = new vgui::ProgressBar( this, "ShuffleProgress" );
  37. m_pGetKeyButton = new CExButton( this, "GetKeyButton", "getkey" );
  38. m_pUseKeyButton = new CExButton( this, "UseKeyButton", "usekey" );
  39. m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) );
  40. m_pMouseOverTooltip = new CItemModelPanelToolTip( this );
  41. m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel );
  42. ListenForGameEvent( "inventory_updated" );
  43. }
  44. CInputStringForItemBackpackOverlayDialog::~CInputStringForItemBackpackOverlayDialog()
  45. {
  46. if ( m_pItemModelPanelKVs )
  47. {
  48. m_pItemModelPanelKVs->deleteThis();
  49. m_pItemModelPanelKVs = NULL;
  50. }
  51. m_vecContentsPanels.PurgeAndDeleteElements();
  52. }
  53. void CInputStringForItemBackpackOverlayDialog::FireGameEvent( IGameEvent *event )
  54. {
  55. // If we're not visible, ignore all events
  56. if ( !IsVisible() )
  57. return;
  58. // Something caused our inventory to update. Assuming it was from our shuffle
  59. // then we need to update ourselves.
  60. const char *type = event->GetName();
  61. if ( Q_strcmp( "inventory_updated", type ) == 0 )
  62. {
  63. m_bUpdateRecieved = true;
  64. }
  65. }
  66. void CInputStringForItemBackpackOverlayDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  67. {
  68. BaseClass::ApplySchemeSettings( pScheme );
  69. LoadControlSettings( "Resource/UI/econ/InputStringForItemBackpackOverlayDialog.res" );
  70. CCrateLootListWrapper itemWrapper( &m_Item );
  71. const IEconLootList *pLootList = itemWrapper.GetEconLootList();
  72. // Set the crate footer text. The crate itself specifies what to use.
  73. if ( pLootList->GetLootListFooterLocalizationKey() )
  74. {
  75. m_pRareLootLabel->SetText( pLootList->GetLootListFooterLocalizationKey() );
  76. }
  77. else
  78. {
  79. const char *pszRareLootListFooterLocalizationKey = m_Item.GetItemDefinition()->GetDefinitionString( "loot_list_rare_item_footer", "#Econ_Revolving_Loot_List_Rare_Item" );
  80. m_pRareLootLabel->SetText( pszRareLootListFooterLocalizationKey );
  81. }
  82. // Use the gradient border for the tooltip
  83. m_pMouseOverItemPanel->SetBorder( pScheme->GetBorder("LoadoutItemPopupBorder") );
  84. m_pPreviewModelPanel->SetItem( &m_Item );
  85. m_pPreviewModelPanel->SetActAsButton( false, false ); // Dont mess around with the mouse
  86. m_pTextEntry->RequestFocus();
  87. }
  88. void CInputStringForItemBackpackOverlayDialog::ApplySettings( KeyValues *inResourceData )
  89. {
  90. BaseClass::ApplySettings( inResourceData );
  91. // Pull out the model panel KVs for this panel
  92. KeyValues *pItemKV = inResourceData->FindKey( "modelpanels_kv" );
  93. if ( pItemKV )
  94. {
  95. if ( m_pItemModelPanelKVs )
  96. {
  97. m_pItemModelPanelKVs->deleteThis();
  98. }
  99. m_pItemModelPanelKVs = new KeyValues( "modelpanels_kv" );
  100. pItemKV->CopySubkeys( m_pItemModelPanelKVs );
  101. }
  102. CreateItemPanels();
  103. }
  104. void CInputStringForItemBackpackOverlayDialog::CreateItemPanels()
  105. {
  106. CCrateLootListWrapper itemWrapper( &m_Item );
  107. const IEconLootList *pLootList = itemWrapper.GetEconLootList();
  108. class CItemDefLootListIterator : public IEconLootList::IEconLootListIterator
  109. {
  110. public:
  111. CItemDefLootListIterator( CUtlVector< item_definition_index_t > *pVecItemDefs )
  112. : m_pVecItemDefs( pVecItemDefs )
  113. {}
  114. virtual void OnIterate( item_definition_index_t unItemDefIndex ) OVERRIDE
  115. {
  116. const CEconItemDefinition *pItemDef = GetItemSchema()->GetItemDefinition( unItemDefIndex );
  117. if ( pItemDef && pItemDef->BValidForShuffle() )
  118. {
  119. m_pVecItemDefs->AddToTail( unItemDefIndex );
  120. }
  121. }
  122. private:
  123. CUtlVector< item_definition_index_t > * const m_pVecItemDefs;
  124. };
  125. // Get the drops from the item
  126. CUtlVector< item_definition_index_t > vecItemDefs;
  127. CItemDefLootListIterator it( &vecItemDefs );
  128. pLootList->EnumerateUserFacingPotentialDrops( &it );
  129. if ( !m_pItemModelPanelKVs )
  130. return;
  131. if ( m_vecContentsPanels.Count() != vecItemDefs.Count() )
  132. {
  133. m_vecContentsPanels.PurgeAndDeleteElements();
  134. FOR_EACH_VEC( vecItemDefs, i )
  135. {
  136. // Create new panel
  137. CItemModelPanel* pItemPanel = m_vecContentsPanels[ m_vecContentsPanels.AddToTail( new CItemModelPanel( this, CFmtStr( "item_preview_%d", i ) ) ) ];
  138. pItemPanel->ApplySettings( m_pItemModelPanelKVs );
  139. pItemPanel->InvalidateLayout( true );
  140. pItemPanel->SetActAsButton( false, true ); // Lets us get mouse enter/exit evens for tooltips
  141. pItemPanel->SetTooltip( m_pMouseOverTooltip, "" ); // Tooltip panel to use
  142. }
  143. }
  144. // Create the panels and set the items into them
  145. FOR_EACH_VEC( vecItemDefs, i )
  146. {
  147. const item_definition_index_t &itemDef = vecItemDefs[i];
  148. CItemModelPanel* pItemPanel = m_vecContentsPanels[i];
  149. CEconItemView item;
  150. item.SetItemDefIndex( itemDef );
  151. item.SetItemQuality( AE_UNIQUE ); // Unique by default
  152. item.SetItemLevel( 0 ); // Hide this?
  153. item.SetInitialized( true );
  154. item.SetItemOriginOverride( kEconItemOrigin_Invalid );
  155. pItemPanel->SetItem( &item );
  156. }
  157. }
  158. void CInputStringForItemBackpackOverlayDialog::PerformLayout( void )
  159. {
  160. BaseClass::PerformLayout();
  161. // Find out how wide these panels will be side by side
  162. const int nBuffer = 5;
  163. int nTotalWide = 0;
  164. const int nCount = m_vecContentsPanels.Count();
  165. if ( nCount )
  166. {
  167. const int nWide = m_vecContentsPanels.Head()->GetWide();
  168. nTotalWide = (nCount * nWide) + ( (nCount - 1) * nBuffer );
  169. }
  170. // Find out how much space the panels take up within the parent
  171. int nParentWide = GetWide();
  172. int nDiff = nParentWide - nTotalWide;
  173. // How far we need to offset from the left edge
  174. int nStartOffset = nDiff / 2;
  175. // Place all the panels side by side
  176. FOR_EACH_VEC( m_vecContentsPanels, i )
  177. {
  178. CItemModelPanel* pItemPanel = m_vecContentsPanels[ i ];
  179. const int nWide = pItemPanel->GetWide();
  180. pItemPanel->SetPos( nStartOffset + i * (nWide + nBuffer), YRES(150) );
  181. pItemPanel->SetVisible( true );
  182. }
  183. // Which button to show
  184. m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() );
  185. m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() );
  186. }
  187. void CInputStringForItemBackpackOverlayDialog::OnCommand( const char *command )
  188. {
  189. if ( !Q_strnicmp( command, "cancel", 6 ) )
  190. {
  191. TFModalStack()->PopModal( this );
  192. SetVisible( false );
  193. MarkForDeletion();
  194. }
  195. else if ( !Q_strnicmp( command, "shuffle", 7 ) )
  196. {
  197. // let the GC know
  198. if ( m_pTextEntry && Plat_FloatTime() >= m_sflNextShuffleTime )
  199. {
  200. // Set the next time they can send a request to shuffle
  201. m_sflNextShuffleTime = Plat_FloatTime() + SHUFFLE_TIME;
  202. enum { kMaxCodeStringSize = 32 };
  203. char szText[ kMaxCodeStringSize ] = { 0 };
  204. m_pTextEntry->GetText( &szText[0], sizeof( szText ) );
  205. GCSDK::CProtoBufMsg<CMsgGCShuffleCrateContents> msg( k_EMsgGCShuffleCrateContents );
  206. msg.Body().set_crate_item_id( m_Item.GetID() );
  207. msg.Body().set_user_code_string( szText );
  208. GCClientSystem()->BSendMessage( msg );
  209. m_pProgressBar->SetProgress( 0.f );
  210. m_pProgressBar->SetVisible( true );
  211. m_pTextEntry->SetVisible( false );
  212. vgui::surface()->PlaySound( "ui/itemcrate_shuffle.wav" );
  213. }
  214. }
  215. else if ( !Q_strnicmp( command, "getkey", 6 ) )
  216. {
  217. static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );
  218. uint32 iDecodableItemDef = 0;
  219. if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) )
  220. {
  221. // casting to the proper type since our econ system is dumb
  222. const float& value_as_float = (float&)iDecodableItemDef;
  223. EconUI()->CloseEconUI();
  224. EconUI()->OpenStorePanel( (int)value_as_float, false );
  225. // close ourselves
  226. TFModalStack()->PopModal( this );
  227. SetVisible( false );
  228. MarkForDeletion();
  229. }
  230. }
  231. else if ( !Q_strnicmp( command, "usekey", 6 ) )
  232. {
  233. if ( m_UseableKey.IsValid() )
  234. {
  235. // Use the key
  236. ApplyTool( GetParent(), &m_UseableKey, &m_Item );
  237. // close ourselves
  238. TFModalStack()->PopModal( this );
  239. SetVisible( false );
  240. MarkForDeletion();
  241. }
  242. }
  243. }
  244. void CInputStringForItemBackpackOverlayDialog::FindUsableKey()
  245. {
  246. static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "decoded by itemdefindex" );
  247. uint32 iDecodableItemDef = 0;
  248. if ( m_Item.FindAttribute( pAttrDef_DecodedBy, &iDecodableItemDef ) )
  249. {
  250. const float& value_as_float = (float&)iDecodableItemDef;
  251. iDecodableItemDef = (float)value_as_float;
  252. CPlayerInventory *pInventory = InventoryManager()->GetLocalInventory();
  253. if ( !pInventory )
  254. return;
  255. for ( int i = 0; i < pInventory->GetItemCount(); i++ )
  256. {
  257. CEconItemView *pItem = pInventory->GetItem(i);
  258. if ( pItem->GetItemDefIndex() == iDecodableItemDef )
  259. {
  260. m_UseableKey = *pItem;
  261. }
  262. }
  263. }
  264. }
  265. void CInputStringForItemBackpackOverlayDialog::OnThink()
  266. {
  267. float flDelta = m_sflNextShuffleTime - Plat_FloatTime();
  268. // If we're ready, show "Shuffle"
  269. if ( flDelta < 0 )
  270. {
  271. // Show the text entry, show the progress bar
  272. m_pProgressBar->SetVisible( false );
  273. m_pTextEntry->SetVisible( true );
  274. // Re-enable the shuffle/use buttons
  275. m_pShuffleButton->SetEnabled( m_pTextEntry->GetTextLength() != 0 );
  276. m_pUseKeyButton->SetEnabled( true );
  277. // Say "Shuffle"
  278. m_pShuffleButton->SetText( "#ShuffleContents" );
  279. // We got a inventory update message, update
  280. if ( m_bUpdateRecieved )
  281. {
  282. CreateItemPanels();
  283. m_bUpdateRecieved = false;
  284. }
  285. }
  286. else
  287. {
  288. // Show the progress bar, hide the text field
  289. m_pProgressBar->SetVisible( true );
  290. m_pTextEntry->SetVisible( false );
  291. // Dont allow clicking the shuffle or use key button
  292. m_pShuffleButton->SetEnabled( false );
  293. m_pUseKeyButton->SetEnabled( false );
  294. // Say "Shuffling..."
  295. m_pShuffleButton->SetText( "#ShufflingContents" );
  296. // Set progress
  297. float flProgress = ( SHUFFLE_TIME - flDelta ) / SHUFFLE_TIME;
  298. m_pProgressBar->SetProgress( flProgress );
  299. }
  300. }
  301. void CInputStringForItemBackpackOverlayDialog::Show()
  302. {
  303. SetVisible( true );
  304. MakePopup();
  305. MoveToFront();
  306. SetKeyBoardInputEnabled( true );
  307. SetMouseInputEnabled( true );
  308. TFModalStack()->PushModal( this );
  309. // If a key wasnt passed in, find the first one in the
  310. // player's inventory
  311. if ( !m_UseableKey.IsValid() )
  312. {
  313. FindUsableKey();
  314. }
  315. // Which button to show
  316. m_pUseKeyButton->SetVisible( m_UseableKey.IsValid() );
  317. m_pGetKeyButton->SetVisible( !m_UseableKey.IsValid() );
  318. // Put the current gen code of the crate into the text field
  319. static CSchemaAttributeDefHandle pAttrDef_DecodedBy( "crate generation code" );
  320. const char *pszAttrGenCode;
  321. if ( FindAttribute_UnsafeBitwiseCast<CAttribute_String>( &m_Item, pAttrDef_DecodedBy, &pszAttrGenCode ) )
  322. {
  323. m_pTextEntry->SetText( pszAttrGenCode );
  324. }
  325. }