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
//========= 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; |
|
} |