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.
489 lines
16 KiB
489 lines
16 KiB
5 years ago
|
//========= 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;
|
||
|
}
|