|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "item_ad_panel.h"
#include "econ_item_system.h"
#include "item_model_panel.h"
#include "econ_store.h"
#include "econ_ui.h"
#include "store/store_panel.h"
#include "tf_controls.h"
#include "econ_item_description.h"
#include "vgui/IInput.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CBaseAdPanel::CBaseAdPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) {}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseAdPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData );
m_flPresentTime = inResourceData->GetFloat( "present_time", 10.f ); }
bool CBaseAdPanel::CheckForRequiredSteamComponents( const char* pszSteamRequried, const char* pszOverlayRequired ) { // Make sure we've got the appropriate connections to Steam
if ( !steamapicontext || !steamapicontext->SteamUtils() ) { OpenStoreStatusDialog( NULL, pszSteamRequried, true, false ); return false; }
if ( !steamapicontext->SteamUtils()->IsOverlayEnabled() ) { OpenStoreStatusDialog( NULL, pszOverlayRequired, true, false ); return false; }
return true; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CItemAdPanel::CItemAdPanel( Panel *parent, const char *panelName, item_definition_index_t itemDefIndex ) : BaseClass( parent, panelName ) , m_ItemDefIndex( itemDefIndex ) , m_bShowMarketButton( true ) { SetDialogVariable( "price", "..." ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAdPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( GetItemDef()->GetAdResFile() ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAdPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData );
m_bShowMarketButton = inResourceData->GetBool( "show_market", true ); // Default to showing market
if ( !m_bShowMarketButton ) { // Tick every second as we try to get our price from the store
vgui::ivgui()->AddTickSignal( GetVPanel(), 1000 ); }
const CTFItemDefinition* pItemDef = GetItemDef(); CItemModelPanel* pItemImage = FindControl< CItemModelPanel >( "ItemIcon" ); if ( pItemImage ) { CEconItemView adItem; adItem.Init( pItemDef->GetDefinitionIndex(), AE_UNIQUE, 1, 1 ); pItemImage->InvalidateLayout( true, true ); pItemImage->SetItem( &adItem );
KeyValuesAD modelpanelKV( "modelpanel_kv" ); KeyValues *itemKV = new KeyValues( "itemmodelpanel" ); itemKV->SetBool( "inventory_image_type", true ); itemKV->SetBool( "use_item_rendertarget", false ); itemKV->SetBool( "allow_rot", false );
modelpanelKV->AddSubKey( itemKV ); pItemImage->ApplySettings( modelpanelKV ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAdPanel::PerformLayout() { BaseClass::PerformLayout();
const CTFItemDefinition* pItemDef = GetItemDef();
// Get the ad text for the item. If it's not there, juse use the description text.
SetDialogVariable( "item_name", g_pVGuiLocalize->Find( pItemDef->GetItemBaseName() ) ); const char* pszAdtext = pItemDef->GetAdTextToken() ? pItemDef->GetAdTextToken() : pItemDef->GetItemDesc(); CExScrollingEditablePanel* pScrollableItemText = FindControl< CExScrollingEditablePanel >( "ScrollableItemText", true ); if ( pszAdtext && pScrollableItemText ) { pScrollableItemText->SetDialogVariable( "item_ad_text", g_pVGuiLocalize->Find( pszAdtext ) );
Label* pAdLabel = pScrollableItemText->FindControl< Label >( "ItemAdText", true ); if ( pAdLabel ) { int nWide, nTall; pAdLabel->GetContentSize( nWide, nTall ); pAdLabel->SetTall( nTall ); }
pScrollableItemText->InvalidateLayout( true ); }
CExButton* pBuyButton = FindControl< CExButton >( "BuyButton", true ); CExButton* pMarketButton = FindControl< CExButton >( "MarketButton", true ); if ( pBuyButton && pMarketButton ) { pBuyButton->SetVisible( !m_bShowMarketButton ); pMarketButton->SetVisible( m_bShowMarketButton ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAdPanel::OnTick() { const CTFItemDefinition* pItemDef = GetItemDef(); bool bStoreIsReady = EconUI()->GetStorePanel() && EconUI()->GetStorePanel()->GetPriceSheet() && EconUI()->GetStorePanel()->GetCart() && steamapicontext && steamapicontext->SteamUser() && pItemDef; if ( bStoreIsReady ) { // Get the price of the item
const ECurrency eCurrency = EconUI()->GetStorePanel()->GetCurrency(); const econ_store_entry_t *pEntry = EconUI()->GetStorePanel()->GetPriceSheet()->GetEntry( pItemDef->GetDefinitionIndex() ); if ( pEntry ) { item_price_t unPrice = pEntry->GetCurrentPrice( eCurrency ); // Set that price into the button
wchar_t wzLocalizedPrice[ kLocalizedPriceSizeInChararacters ]; MakeMoneyString( wzLocalizedPrice, ARRAYSIZE( wzLocalizedPrice ), unPrice, eCurrency ); SetDialogVariable( "price", wzLocalizedPrice );
// Don't need to tick anymore
vgui::ivgui()->RemoveTickSignal( GetVPanel() ); } } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
const CTFItemDefinition* CItemAdPanel::GetItemDef() const { return (CTFItemDefinition*)ItemSystem()->GetItemSchema()->GetItemDefinition( m_ItemDefIndex ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CItemAdPanel::OnCommand( const char *command ) { if ( FStrEq( "purchase", command ) ) { if ( !CheckForRequiredSteamComponents( "#StoreUpdate_SteamRequired", "#MMenu_OverlayRequired" ) ) return;
const CTFItemDefinition* pItemDef = GetItemDef(); if ( pItemDef ) { if ( EconUI()->GetStorePanel() && EconUI()->GetStorePanel()->GetPriceSheet() && EconUI()->GetStorePanel()->GetCart() && steamapicontext && steamapicontext->SteamUser() ) { // Add a the item to the users cart and checkout
EconUI()->GetStorePanel()->GetCart()->EmptyCart(); AddItemToCartHelper( NULL, pItemDef->GetDefinitionIndex(), kCartItem_Purchase ); EconUI()->GetStorePanel()->InitiateCheckout( true ); } } } else if ( FStrEq( "market", command ) ) { if ( !CheckForRequiredSteamComponents( "#StoreUpdate_SteamRequired", "#MMenu_OverlayRequired" ) ) return;
const CTFItemDefinition* pItemDef = GetItemDef(); 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 ); } } }
DECLARE_BUILD_FACTORY( CCyclingAdContainerPanel );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCyclingAdContainerPanel::CCyclingAdContainerPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) , m_pAdsContainer( NULL ) , m_pKVItems( NULL ) , m_nCurrentIndex( 0 ) , m_nXPos( 0 ) , m_nTargetIndex( 0 ) , m_nTransitionStartOffsetX( 0 ) , m_bTransitionRight( true ) , m_bSettingsApplied( false ) , m_bNeedsToCreatePanels( false ) { m_pAdsContainer = new EditablePanel( this, "AdsContainer" ); m_pFadePanel = new EditablePanel( this, "FadeTransition" ); m_pNextButton = new CExButton( this, "NextButton", ">", this, "next" ); m_pPrevButton = new CExButton( this, "PrevButton", "<", this, "prev" ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCyclingAdContainerPanel::~CCyclingAdContainerPanel() { if ( m_pKVItems ) { m_pKVItems->deleteThis(); m_pKVItems = NULL; } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::ApplySchemeSettings( IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "Resource/UI/econ/CyclingAdContainer.res" );
m_bSettingsApplied = true; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::ApplySettings( KeyValues *inResourceData ) { BaseClass::ApplySettings( inResourceData );
KeyValues* pKVItems = inResourceData->FindKey( "items" ); if ( pKVItems ) { SetItemKVs( pKVItems ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::CreatePanels() { if ( ItemSystem()->GetItemSchema()->GetVersion() == 0 ) return;
m_vecPossibleAds.Purge();
FOR_EACH_TRUE_SUBKEY( m_pKVItems, pKVItem ) { const char* pszItemName = pKVItem->GetString( "item" ); const CEconItemDefinition *pDef = ItemSystem()->GetItemSchema()->GetItemDefinitionByName( pszItemName ); if ( pDef ) { AdData_t& adData = m_vecPossibleAds[ m_vecPossibleAds.AddToTail() ]; adData.m_pAdPanel = new CItemAdPanel( m_pAdsContainer, "ad", pDef->GetDefinitionIndex() );
adData.m_pAdPanel->InvalidateLayout( true, true ); // Default settings
adData.m_pAdPanel->ApplySettings( pKVItem ); adData.m_pAdPanel->InvalidateLayout(); } else { AssertMsg( 0, "Invalid item def '%s'!", pszItemName ); } }
m_bNeedsToCreatePanels = false; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::PerformLayout() { BaseClass::PerformLayout();
PresentIndex( 0 ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::OnThink() { BaseClass::OnThink();
if ( m_bNeedsToCreatePanels && m_bSettingsApplied ) { CreatePanels(); PresentIndex( 0 ); }
UpdateAdPanelPositions();
// See if it's time to auto-cycle to the next ad
if ( m_ShowTimer.HasStarted() && m_ShowTimer.IsElapsed() && m_vecPossibleAds.Count() > 1 ) { m_ShowTimer.Invalidate(); PresentIndex( m_nTargetIndex + 1 ); }
int nMouseX, nMouseY; vgui::input()->GetCursorPos( nMouseX, nMouseY ); bool bControlsVisible = IsWithin( nMouseX, nMouseY ) && m_vecPossibleAds.Count() > 1; m_pPrevButton->SetVisible( bControlsVisible ); m_pNextButton->SetVisible( bControlsVisible ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::SetItemKVs( KeyValues* pKVItems ) { if ( pKVItems ) { if ( m_pKVItems ) { m_pKVItems->deleteThis(); m_pKVItems = NULL; } m_pKVItems = pKVItems->MakeCopy(); }
m_bNeedsToCreatePanels = true; }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::OnCommand( const char *command ) { if ( FStrEq( "next", command ) ) { PresentIndex( m_nTargetIndex + 1 ); } else if ( FStrEq( "prev", command ) ) { PresentIndex( m_nTargetIndex - 1 ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::PresentIndex( int nIndex ) { if ( m_vecPossibleAds.IsEmpty() ) return;
if ( m_nCurrentIndex == nIndex ) return;
// Figure out which way we want to ransition
m_bTransitionRight = nIndex > m_nCurrentIndex;
// Wrap if needed
if ( nIndex >= m_vecPossibleAds.Count() ) { nIndex = 0; } else if ( nIndex < 0 ) { nIndex = m_vecPossibleAds.Count() - 1; }
m_nTargetIndex = nIndex;
// If they click more times while transitioning out, just change the target. If we're
// into transitioning in to the next panel, then we need to start the whole thing over.
if ( !IsTransitioningOut() ) { m_nTransitionStartOffsetX = m_nXPos; float flTransitionTime = 1.f; m_TransitionTimer.Start( flTransitionTime );
m_ShowTimer.Start( flTransitionTime + m_vecPossibleAds[ m_nCurrentIndex ].m_pAdPanel->GetPresentTime() ); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCyclingAdContainerPanel::UpdateAdPanelPositions() { // Figure out how far along a transition we are
float flPercent = Clamp( m_TransitionTimer.GetElapsedTime() / m_TransitionTimer.GetCountdownDuration(), 0.f, 1.f ); flPercent = Gain( flPercent, 0.8f );
// At a certain point, we're no longer transitioning out the old -- we're transitioning in the new
const float flTransitionCutOff = m_TransitionTimer.GetCountdownDuration() / 2.f; bool bTransitionOut = flPercent < flTransitionCutOff;
int nStartX = 0; int nTargetX = 0; float flFadeAmount = 0.f;
if ( bTransitionOut ) { nStartX = m_nTransitionStartOffsetX; nTargetX = m_bTransitionRight ? -100 : 100; flFadeAmount = RemapValClamped( flPercent, 0.f, flTransitionCutOff * 0.75f, 0.f, 255.f ); } else { // Once we've passed the middle, show the target
m_nCurrentIndex = m_nTargetIndex; nStartX = m_bTransitionRight ? 100 : -100; nTargetX = 0; flFadeAmount = RemapValClamped( flPercent, flTransitionCutOff * 1.25f, 1.f, 255.f, 0.f ); }
// Alpha fades up entirely near the middle to cover the swap
m_pFadePanel->SetAlpha( flFadeAmount );
m_nXPos = RemapVal( flPercent, 0.f, 1.f, nStartX, nTargetX ); FOR_EACH_VEC( m_vecPossibleAds, i ) { m_vecPossibleAds[i].m_pAdPanel->SetPos( m_nXPos, m_vecPossibleAds[i].m_pAdPanel->GetYPos() ); m_vecPossibleAds[i].m_pAdPanel->SetVisible( i == m_nCurrentIndex ); } }
float CCyclingAdContainerPanel::GetTransitionProgress() const { float flPercent = Clamp( m_TransitionTimer.GetElapsedTime() / m_TransitionTimer.GetCountdownDuration(), 0.f, 1.f ); return Gain( flPercent, 0.8f ); }
bool CCyclingAdContainerPanel::IsTransitioningOut() const { const float flTransitionCutOff = m_TransitionTimer.GetCountdownDuration() / 2.f; return GetTransitionProgress() < flTransitionCutOff; }
|