Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
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.

1244 lines
36 KiB

5 years ago
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "charinfo_loadout_subpanel.h"
#include "vgui/ISurface.h"
#include "vgui/IInput.h"
#include "vgui/ILocalize.h"
#include "c_tf_freeaccount.h"
#include "c_tf_player.h"
#include "confirm_dialog.h"
#include "gamestringpool.h"
#include "c_tf_objective_resource.h"
#include "tf_gamerules.h"
#include "tf_item_inventory.h"
#include "trading_start_dialog.h"
#include "gc_clientsystem.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
DECLARE_BUILD_FACTORY( CImageButton );
ConVar tf_explanations_charinfopanel( "tf_explanations_charinfopanel", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CImageButton::CImageButton( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName, "" )
{
m_pszActiveImageName = NULL;
m_pszInactiveImageName = NULL;
m_pActiveImage = NULL;
m_pInactiveImage = NULL;
m_ActiveDrawColor = Color(255,255,255,255);
m_InactiveDrawColor = Color(255,255,255,255);
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::ApplySettings( KeyValues *inResourceData )
{
m_bScaleImage = inResourceData->GetInt( "scaleImage", 0 );
// Active Image
delete [] m_pszActiveImageName;
m_pszActiveImageName = NULL;
const char *activeImageName = inResourceData->GetString( "activeimage", "" );
if ( *activeImageName )
{
SetActiveImage( activeImageName );
}
// Inactive Image
delete [] m_pszInactiveImageName;
m_pszInactiveImageName = NULL;
const char *inactiveImageName = inResourceData->GetString( "inactiveimage", "" );
if ( *inactiveImageName )
{
SetInactiveImage( inactiveImageName );
}
const char *pszDrawColor = inResourceData->GetString("activedrawcolor", "");
if (*pszDrawColor)
{
int r = 0, g = 0, b = 0, a = 255;
if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
{
m_ActiveDrawColor = Color(r, g, b, a);
}
else
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
m_ActiveDrawColor = pScheme->GetColor(pszDrawColor, Color(0, 0, 0, 0));
}
}
pszDrawColor = inResourceData->GetString("inactivedrawcolor", "");
if (*pszDrawColor)
{
int r = 0, g = 0, b = 0, a = 255;
if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
{
m_InactiveDrawColor = Color(r, g, b, a);
}
else
{
vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
m_InactiveDrawColor = pScheme->GetColor(pszDrawColor, Color(0, 0, 0, 0));
}
}
BaseClass::ApplySettings( inResourceData );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
if ( m_pszActiveImageName && strlen( m_pszActiveImageName ) > 0 )
{
SetActiveImage(vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) );
}
if ( m_pszInactiveImageName && strlen( m_pszInactiveImageName ) > 0 )
{
SetInactiveImage(vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) );
}
vgui::IBorder *pBorder = pScheme->GetBorder( "NoBorder" );
SetDefaultBorder( pBorder);
SetDepressedBorder( pBorder );
SetKeyFocusBorder( pBorder );
Color defaultFgColor = GetSchemeColor( "Button.TextColor", Color(255, 255, 255, 255), pScheme );
Color armedFgColor = GetSchemeColor( "Button.ArmedTextColor", Color(255, 255, 255, 255), pScheme );
Color depressedFgColor = GetSchemeColor( "Button.DepressedTextColor", Color(255, 255, 255, 255), pScheme );
Color blank(0,0,0,0);
SetDefaultColor( defaultFgColor, blank );
SetArmedColor( armedFgColor, blank );
SetDepressedColor( depressedFgColor, blank );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::SetActiveImage( const char *imagename )
{
int len = Q_strlen( imagename ) + 1;
m_pszActiveImageName = new char[ len ];
Q_strncpy( m_pszActiveImageName, imagename, len );
SetActiveImage(vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::SetInactiveImage( const char *imagename )
{
int len = Q_strlen( imagename ) + 1;
m_pszInactiveImageName = new char[ len ];
Q_strncpy( m_pszInactiveImageName, imagename, len );
SetInactiveImage(vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::SetActiveImage( vgui::IImage *image )
{
m_pActiveImage = image;
if ( m_pActiveImage )
{
int wide, tall;
if ( m_bScaleImage )
{
// scaling, force the image size to be our size
GetSize( wide, tall );
m_pActiveImage->SetSize( wide, tall );
}
else
{
// not scaling, so set our size to the image size
m_pActiveImage->GetSize( wide, tall );
SetSize( wide, tall );
}
}
Repaint();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::SetInactiveImage( vgui::IImage *image )
{
m_pInactiveImage = image;
if ( m_pInactiveImage )
{
int wide, tall;
if ( m_bScaleImage)
{
// scaling, force the image size to be our size
GetSize( wide, tall );
m_pInactiveImage->SetSize( wide, tall );
}
else
{
// not scaling, so set our size to the image size
m_pInactiveImage->GetSize( wide, tall );
SetSize( wide, tall );
}
}
Repaint();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::OnSizeChanged( int newWide, int newTall )
{
if ( m_bScaleImage )
{
// scaling, force the image size to be our size
if ( m_pActiveImage )
m_pActiveImage->SetSize( newWide, newTall );
if ( m_pInactiveImage )
m_pInactiveImage->SetSize( newWide, newTall );
}
BaseClass::OnSizeChanged( newWide, newTall );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CImageButton::Paint()
{
if ( IsArmed() || _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) )
{
// draw the active image
if ( m_pActiveImage )
{
m_pActiveImage->SetColor( m_ActiveDrawColor );
m_pActiveImage->SetPos( 0, 0 );
m_pActiveImage->Paint();
}
}
else
{
// draw the inactive image
if ( m_pInactiveImage )
{
m_pActiveImage->SetColor( m_InactiveDrawColor );
m_pInactiveImage->SetPos( 0, 0 );
m_pInactiveImage->Paint();
}
}
BaseClass::Paint();
}
const char *g_pszSubButtonNames[CHSB_NUM_BUTTONS] =
{
"ShowBackpackButton", // CHSB_BACKPACK,
"ShowCraftingButton", // CHSB_CRAFTING,
"ShowArmoryButton", // CHSB_ARMORY,
"ShowTradeButton", // CHSB_TRADING,
};
const char *g_pszSubButtonLabelNames[CHSB_NUM_BUTTONS] =
{
"ShowBackpackLabel", // CHSB_BACKPACK,
"ShowCraftingLabel", // CHSB_CRAFTING,
"ShowArmoryLabel", // CHSB_ARMORY,
"ShowTradeLabel", // CHSB_TRADING,
};
int g_nLoadoutClassOrder[] =
{
TF_CLASS_SCOUT,
TF_CLASS_SOLDIER,
TF_CLASS_PYRO,
TF_CLASS_DEMOMAN,
TF_CLASS_HEAVYWEAPONS,
TF_CLASS_ENGINEER,
TF_CLASS_MEDIC,
TF_CLASS_SNIPER,
TF_CLASS_SPY
};
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCharInfoLoadoutSubPanel::CCharInfoLoadoutSubPanel(Panel *parent) : vgui::PropertyPage(parent, "CharInfoLoadoutSubPanel")
{
m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
m_iCurrentTeamIndex = TF_TEAM_RED;
m_iShowingPanel = CHAP_LOADOUT;
m_iPrevShowingPanel = CHAP_LOADOUT;
memset( m_pClassButtons, 0, sizeof( m_pClassButtons ) );
m_pClassButtons[ TF_CLASS_SCOUT ] = new CImageButton( this, "scout" );
m_pClassButtons[ TF_CLASS_SOLDIER ] = new CImageButton( this, "soldier" );
m_pClassButtons[ TF_CLASS_PYRO ] = new CImageButton( this, "pyro" );
m_pClassButtons[ TF_CLASS_DEMOMAN ] = new CImageButton( this, "demoman" );
m_pClassButtons[ TF_CLASS_HEAVYWEAPONS ] = new CImageButton( this, "heavyweapons" );
m_pClassButtons[ TF_CLASS_ENGINEER ] = new CImageButton( this, "engineer" );
m_pClassButtons[ TF_CLASS_MEDIC ] = new CImageButton( this, "medic" );
m_pClassButtons[ TF_CLASS_SNIPER ] = new CImageButton( this, "sniper" );
m_pClassButtons[ TF_CLASS_SPY ] = new CImageButton( this, "spy" );
for( int i = 0; i < Q_ARRAYSIZE( m_pClassButtons ); i++ )
{
if( m_pClassButtons[ i ] )
m_pClassButtons[ i ]->SetParentNeedsCursorMoveEvents( true );
}
for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
{
m_pSubButtons[i] = new CImageButton( this, g_pszSubButtonNames[i] );
m_pButtonLabels[i] = new CExLabel( this, g_pszSubButtonLabelNames[i], "" );
}
m_iOverSubButton = -1;
m_pClassLoadoutPanel = new CClassLoadoutPanel( this );
m_pBackpackPanel = new CBackpackPanel( this, "backpack_panel" );
m_pCraftingPanel = new CCraftingPanel( this, "crafting_panel" );
m_pArmoryPanel = new CArmoryPanel( this, "armory_panel" );
m_pArmoryPanel->AllowGotoStore();
m_pSelectLabel = NULL;
m_pLoadoutChangesLabel = NULL;
m_pNoSteamLabel = NULL;
m_pNoGCLabel = NULL;
m_pClassLabel = NULL;
m_pItemsLabel = NULL;
m_bSnapClassLayout = false;
m_bClassLayoutDirty = false;
m_bRequestingInventoryRefresh = false;
m_flStartExplanationsAt = 0;
vgui::ivgui()->AddTickSignal( GetVPanel() );
REGISTER_COLOR_AS_OVERRIDABLE( m_ItemColorNone, "itemcountcolor_noitems" );
REGISTER_COLOR_AS_OVERRIDABLE( m_ItemColor, "itemcountcolor" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CCharInfoLoadoutSubPanel::~CCharInfoLoadoutSubPanel()
{
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "Resource/UI/CharInfoLoadoutSubPanel.res" );
m_pSelectLabel = dynamic_cast<vgui::Label*>( FindChildByName("SelectLabel") );
m_pLoadoutChangesLabel = dynamic_cast<vgui::Label*>( FindChildByName("LoadoutChangesLabel") );
m_pNoSteamLabel = dynamic_cast<vgui::Label*>( FindChildByName("NoSteamLabel") );
m_pNoGCLabel = dynamic_cast<vgui::Label*>( FindChildByName("NoGCLabel") );
m_pClassLabel = dynamic_cast<vgui::Label*>( FindChildByName("ClassLabel") );
int ignored;
if ( m_pClassLabel )
{
m_pClassLabel->GetPos( ignored, m_iClassLabelYPos );
}
m_pItemsLabel = dynamic_cast<CExLabel*>( FindChildByName("ItemsLabel") );
if ( m_pItemsLabel )
{
m_pItemsLabel->GetPos( ignored, m_iItemLabelYPos );
}
// Start classes sized as if the mouse is in the middle of the screen
m_iMouseXPos = -1;
m_bSnapClassLayout = true;
RecalculateTargetClassLayout();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnPageShow( void )
{
SetVisible( true );
BaseClass::OnPageShow();
if( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
m_pClassButtons[ m_iCurrentClassIndex ]->GetPos( m_iMouseXPos, m_iMouseYPos );
m_bClassLayoutDirty = true;
InvalidateLayout();
}
// If this is the first time we've opened the loadout, start the loadout explanations
if ( !tf_explanations_charinfopanel.GetBool() && ShouldShowExplanations() )
{
m_flStartExplanationsAt = engine->Time() + 0.5;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnSelectionStarted( void )
{
PostActionSignal( new KeyValues("SelectionUpdate", "open", 1 ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnSelectionEnded( void )
{
PostActionSignal( new KeyValues("SelectionUpdate", "open", 0 ) );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnCancelSelection( void )
{
PostMessage( m_pClassLoadoutPanel, new KeyValues("CancelSelection") );
PostMessage( m_pBackpackPanel, new KeyValues("CancelSelection") );
PostMessage( m_pCraftingPanel, new KeyValues("CancelSelection") );
PostMessage( m_pArmoryPanel, new KeyValues("CancelSelection") );
RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnCharInfoClosing( void )
{
switch ( m_iShowingPanel )
{
case CHAP_CRAFTING:
PostMessage( m_pCraftingPanel, new KeyValues("Closing") );
break;
case CHAP_BACKPACK:
break;
case CHAP_ARMORY:
PostMessage( m_pArmoryPanel, new KeyValues("Closing") );
break;
case CHAP_LOADOUT:
PostMessage( m_pClassLoadoutPanel, new KeyValues("Closing") );
break;
default: // Class loadout.
break;
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnOpenCrafting( void )
{
OpenToCrafting();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnCraftingClosed( void )
{
PostMessage( m_pCraftingPanel, new KeyValues("Closing") );
m_iShowingPanel = CHAP_LOADOUT;
m_iPrevShowingPanel = CHAP_CRAFTING;
m_flStartExplanationsAt = 0;
m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
UpdateModelPanels();
RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnArmoryClosed( void )
{
// Return to whatever we were on before opening the armory
PostMessage( m_pArmoryPanel, new KeyValues("Closing") );
m_iShowingPanel = m_iPrevShowingPanel;
m_iPrevShowingPanel = CHAP_ARMORY;
m_flStartExplanationsAt = 0;
m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
UpdateModelPanels();
RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnCommand( const char *command )
{
if ( !Q_strnicmp( command, "loadout ", 8 ) )
{
// Ignore selection while we don't have a steam connection
if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
return;
m_flStartExplanationsAt = 0;
const char *pszClass = command+8;
if ( pszClass[0] != '\0' )
{
int nClassIndex = GetClassIndexFromString( pszClass, NUM_CLASSES_IN_LOADOUT_PANEL );
if ( nClassIndex != TF_CLASS_UNDEFINED && m_iCurrentClassIndex != nClassIndex )
{
SetClassIndex( nClassIndex, true );
return;
}
}
}
else if ( !Q_strnicmp( command, "backpack", 8 ) )
{
OpenToBackpack();
}
else if ( !Q_strnicmp( command, "crafting", 8 ) )
{
OpenToCrafting();
}
else if ( !Q_strnicmp( command, "armory", 6 ) )
{
OpenToArmory();
}
else if ( !Q_strnicmp( command, "trading", 7 ) )
{
OpenTradingStartDialog( this );
}
else if ( !Q_stricmp( command, "show_explanations" ) )
{
if ( !m_flStartExplanationsAt )
{
m_flStartExplanationsAt = engine->Time();
}
RequestFocus();
}
else
{
engine->ClientCmd( const_cast<char *>( command ) );
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::RequestInventoryRefresh()
{
m_bRequestingInventoryRefresh = false;
// Don't respond to the mouse if we don't have items
if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
{
ShowWaitingDialog( new CGenericWaitingDialog(this), "#NoSteamNoItems_Refresh", true, true, 30.0f );
if ( !m_bRequestingInventoryRefresh )
{
// make sure the local inventory is added as a listener
TFInventoryManager()->UpdateLocalInventory();
m_bRequestingInventoryRefresh = true;
// ask GC for refresh
GCSDK::CProtoBufMsg< CMsgRequestInventoryRefresh > msg( k_EMsgGCRequestInventoryRefresh );
GCClientSystem()->BSendMessage( msg );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::SetClassIndex( int iClassIndex, bool bOpenClassLoadout )
{
Assert(iClassIndex >= TF_CLASS_UNDEFINED && iClassIndex <= NUM_CLASSES_IN_LOADOUT_PANEL);
m_iCurrentClassIndex = iClassIndex;
m_iShowingPanel = CHAP_LOADOUT;
UpdateModelPanels( bOpenClassLoadout );
RequestInventoryRefresh();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::SetTeamIndex( int iTeam )
{
Assert( IsValidTFTeam( iTeam ) );
m_iCurrentTeamIndex = iTeam;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OpenSubPanel( charinfo_activepanels_t iPanel )
{
m_flStartExplanationsAt = 0;
m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
m_iPrevShowingPanel = m_iShowingPanel;
m_iShowingPanel = iPanel;
UpdateModelPanels();
RequestInventoryRefresh();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::UpdateModelPanels( bool bOpenClassLoadout )
{
int iLabelClassToSet = -1;
int iClassIndexToSet = 0;
if ( m_iShowingPanel == CHAP_CRAFTING )
{
m_pClassLoadoutPanel->SetVisible( false );
m_pBackpackPanel->SetVisible( false );
m_pArmoryPanel->SetVisible( false );
m_pCraftingPanel->ShowPanel( m_iCurrentClassIndex, true, (m_iPrevShowingPanel == CHAP_ARMORY) );
}
else if ( m_iShowingPanel == CHAP_BACKPACK )
{
m_pClassLoadoutPanel->SetVisible( false );
m_pCraftingPanel->SetVisible( false );
m_pArmoryPanel->SetVisible( false );
m_pBackpackPanel->ShowPanel( m_iCurrentClassIndex, true, (m_iPrevShowingPanel == CHAP_ARMORY) );
}
else if ( m_iShowingPanel == CHAP_ARMORY )
{
m_pClassLoadoutPanel->SetVisible( false );
m_pCraftingPanel->SetVisible( false );
m_pBackpackPanel->SetVisible( false );
m_pArmoryPanel->ShowPanel( m_iArmoryItemDef );
}
else
{
iClassIndexToSet = bOpenClassLoadout ? m_iCurrentClassIndex : TF_CLASS_UNDEFINED;
m_pArmoryPanel->SetVisible( false );
m_pBackpackPanel->SetVisible( false );
m_pCraftingPanel->SetVisible( false );
m_pClassLoadoutPanel->SetTeam( m_iCurrentTeamIndex );
m_pClassLoadoutPanel->SetClass( iClassIndexToSet );
m_pClassLoadoutPanel->ShowPanel( iClassIndexToSet, false, (m_iPrevShowingPanel == CHAP_ARMORY) );
iLabelClassToSet = m_iCurrentClassIndex;
}
m_iCurrentClassIndex = iClassIndexToSet;
if( bOpenClassLoadout )
{
PostActionSignal( new KeyValues("ClassSelected", "class", m_iCurrentClassIndex ) );
}
else
{
m_iLabelSetToClass = iLabelClassToSet;
m_bClassLayoutDirty = true;
InvalidateLayout();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::PerformLayout( void )
{
BaseClass::PerformLayout();
// Show our changes label if we're alive, and hence won't get the changes immediately
bool bChangesLabel = false;
if ( engine->IsInGame() )
{
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
if ( pLocalPlayer && pLocalPlayer->IsAlive() && pLocalPlayer->GetObserverMode() == OBS_MODE_NONE )
{
bChangesLabel = true;
}
}
if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
{
bool bLoggedIntoSteam = steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUser()->BLoggedOn();
if ( m_pItemsLabel )
m_pNoGCLabel->SetVisible( bLoggedIntoSteam );
if ( m_pNoSteamLabel )
m_pNoSteamLabel->SetVisible( !bLoggedIntoSteam );
if ( m_pSelectLabel )
m_pSelectLabel->SetVisible( false );
if ( m_pLoadoutChangesLabel)
m_pLoadoutChangesLabel->SetVisible( false );
for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
{
m_pSubButtons[i]->SetVisible( false );
m_pButtonLabels[i]->SetVisible( false );
}
}
else
{
if ( m_pNoSteamLabel )
m_pNoSteamLabel->SetVisible( false );
if ( m_pNoGCLabel )
m_pNoGCLabel->SetVisible( false );
if ( m_pSelectLabel )
m_pSelectLabel->SetVisible( true );
for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
{
m_pSubButtons[i]->SetVisible( true );
m_pButtonLabels[i]->SetVisible( true );
}
if ( !bChangesLabel )
{
if ( m_pSelectLabel )
m_pSelectLabel->SetPos( 0, m_iSelectLabelY );
if ( m_pLoadoutChangesLabel )
m_pLoadoutChangesLabel->SetVisible( false );
}
else
{
if ( m_pSelectLabel )
m_pSelectLabel->SetPos( 0, m_iSelectLabelOnChangesY );
if ( m_pLoadoutChangesLabel )
m_pLoadoutChangesLabel->SetVisible( true );
}
}
m_iOverSubButton = -1;
if ( m_pSelectLabel )
m_pClassLabel->SetVisible( false );
if ( m_pItemsLabel )
m_pItemsLabel->SetVisible( false );
m_bClassLayoutDirty = false;
// Now Layout the class images.
for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
{
int i = g_nLoadoutClassOrder[iPanel];
int iX = m_iClassLayout[i][0];
int iY = m_iClassLayout[i][1];
int iWide = m_iClassLayout[i][2];
int iTall = m_iClassLayout[i][3];
if ( m_bSnapClassLayout )
{
m_pClassButtons[i]->SetBounds( iX, iY, iWide, iTall );
}
else
{
// Lerp towards the target
int iCurX, iCurY, iCurWide, iCurTall;
m_pClassButtons[i]->GetBounds( iCurX, iCurY, iCurWide, iCurTall );
int iNewX = Lerp( 0.2, iCurX, iX );
int iNewY = Lerp( 0.2, iCurY, iY );
int iNewWide = Lerp( 0.2, iCurWide, iWide );
int iNewTall = Lerp( 0.2, iCurTall, iTall );
m_pClassButtons[i]->SetBounds( iNewX, iNewY, iNewWide, iNewTall );
if ( abs(iNewX-iX) > 5 || abs(iNewY-iY) > 5 || abs(iNewWide-iWide) > 5 || abs(iNewTall-iTall) > 5 )
{
m_bClassLayoutDirty = true;
}
}
}
// We need to do our own management of cursor arming in the buttons, because the curserentered/exited code can't
// deal with the way we resize the buttons without the cursor moving.
int iBestButton = -1;
int iBestZ = 0;
int x = m_iMouseXPos, y = m_iMouseYPos;
// only get the actual cursor pos if we don't have a cached cursor pos. THe
// cached pos might have come from the keyboard.
if( x < 0 )
vgui::input()->GetCursorPos(x, y);
for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
{
int i = g_nLoadoutClassOrder[iPanel];
m_pClassButtons[i]->SetArmed( false );
m_pClassButtons[i]->SetEnabled( TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() );
if ( m_pClassButtons[i]->IsWithin( x,y ) && iBestZ < m_pClassButtons[i]->GetZPos() )
{
iBestButton = i;
iBestZ = m_pClassButtons[i]->GetZPos();
}
}
if ( iBestButton >= 0 && iBestButton < ARRAYSIZE( m_pClassButtons ) )
{
m_pClassButtons[iBestButton]->SetArmed( true );
if ( m_iLabelSetToClass != iBestButton )
{
m_iLabelSetToClass = iBestButton;
}
UpdateLabelFromClass( m_iLabelSetToClass );
}
m_bSnapClassLayout = false;
}
void CCharInfoLoadoutSubPanel::UpdateLabelFromClass( int nClass )
{
if ( nClass < 0 )
return;
const wchar_t *wszClassName = g_pVGuiLocalize->Find( g_aPlayerClassNames[nClass] );
if ( m_pClassLabel )
{
m_pClassLabel->SetText( wszClassName );
m_pClassLabel->SetVisible( true );
}
if ( m_pItemsLabel )
{
m_pItemsLabel->SetVisible( true );
}
CUtlVector<CEconItemView*> pList;
int iNumItems = TFInventoryManager()->GetAllUsableItemsForSlot( nClass, -1, &pList );
if ( !iNumItems )
{
const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#NoItemsFoundShort" );
m_pItemsLabel->SetText( wszItemsName );
m_pItemsLabel->SetColorStr( m_ItemColorNone );
}
else if ( iNumItems == 1 )
{
const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#ItemsFoundShortOne" );
m_pItemsLabel->SetText( wszItemsName );
m_pItemsLabel->SetColorStr( m_ItemColor );
}
else
{
wchar_t wzCount[10];
_snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iNumItems );
wchar_t wTemp[32];
g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("ItemsFoundShort"), 1, wzCount );
m_pItemsLabel->SetText( wTemp );
m_pItemsLabel->SetColorStr( m_ItemColor );
}
int iPos = 0;
for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
{
if ( iRemapIndexToClass[i] == nClass )
{
iPos = i;
break;
}
}
Assert(iPos != 0 );
int iXLeft = (GetWide() - ((m_iClassWideMin * NUM_CLASSES_IN_LOADOUT_PANEL) + (m_iClassXDelta * (NUM_CLASSES_IN_LOADOUT_PANEL-1)))) * 0.5;
int iBaseX = iXLeft + ((m_iClassWideMin + m_iClassXDelta) * (iPos-1));
int iCenterX = iBaseX + (m_iClassWideMin * 0.5);
m_pClassLabel->SetVisible( true );
m_pClassLabel->SetPos( iCenterX - (m_pClassLabel->GetWide() * 0.5), m_iClassLabelYPos );
m_pItemsLabel->SetVisible( true );
m_pItemsLabel->SetPos( iCenterX - (m_pItemsLabel->GetWide() * 0.5), m_iItemLabelYPos );
}
void CCharInfoLoadoutSubPanel::UpdateLabelFromSubButton( int nButton )
{
if( nButton < 0 )
nButton = CHSB_NUM_BUTTONS - 1;
else if( nButton >= CHSB_NUM_BUTTONS )
nButton = 0;
if ( m_iOverSubButton == nButton )
return;
m_iOverSubButton = nButton;
switch ( nButton )
{
default:
case CHSB_BACKPACK:
{
int iNumItems = TFInventoryManager()->GetLocalTFInventory()->GetItemCount();
if ( iNumItems == 1 )
{
const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#Loadout_OpenBackpackDesc1" );
m_pItemsLabel->SetText( wszItemsName );
}
else
{
wchar_t wzCount[10];
_snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iNumItems );
wchar_t wTemp[32];
g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("Loadout_OpenBackpackDesc"), 1, wzCount );
m_pItemsLabel->SetText( wTemp );
}
}
break;
case CHSB_CRAFTING:
m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenCraftingDesc" ) );
break;
case CHSB_ARMORY:
m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenArmoryDesc" ) );
break;
case CHSB_TRADING:
m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenTradingDesc" ) );
break;
}
int iX, iY;
m_pSubButtons[nButton]->GetPos( iX, iY );
iX += (m_pSubButtons[nButton]->GetWide() * 0.5);
iY += m_pSubButtons[nButton]->GetTall() + YRES(5);
m_pItemsLabel->SetVisible( true );
m_pItemsLabel->SetPos( iX - (m_pItemsLabel->GetWide() * 0.5), iY + (m_iItemLabelYPos - m_iClassLabelYPos) );
m_pItemsLabel->SetColorStr( m_ItemColor );
for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
{
m_pSubButtons[i]->SetArmed( false );
}
m_pSubButtons[nButton]->SetArmed( true );
m_pSubButtons[nButton]->RequestFocus();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnTick( void )
{
if ( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
return;
if ( !IsVisible() )
return;
if ( m_bRequestingInventoryRefresh && TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
{
m_bRequestingInventoryRefresh = false;
CloseWaitingDialog();
return;
}
// if the class layout is dirty, invalidate our layout so that
// we'll animate the class buttons.
if ( m_bClassLayoutDirty )
{
InvalidateLayout();
}
if ( !HasFocus() )
return;
// Don't respond to the mouse if we don't have items
if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
return;
if ( m_flStartExplanationsAt && m_flStartExplanationsAt < engine->Time() )
{
m_flStartExplanationsAt = 0;
if ( ShouldShowExplanations() )
{
tf_explanations_charinfopanel.SetValue( 1 );
CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") );
if ( pPopup )
{
pPopup->Popup();
}
}
}
}
//-----------------------------------------------------------------------------
// Purpose: Handles mousing over classes
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::OnCursorMoved( int x, int y )
{
RecalculateTargetClassLayoutAtPos( x, y );
}
//-----------------------------------------------------------------------------
// Purpose: Handles setting the highlighted class for both mouse and keyboard
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::RecalculateTargetClassLayoutAtPos( int x, int y )
{
// Ignore mouse movement outside the buttons
bool bWithin = false;
for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
{
if ( m_pClassButtons[i]->IsWithin(x,y) )
{
bWithin = true;
break;
}
}
if ( bWithin )
{
m_iMouseXPos = x;
m_iMouseYPos = y;
RecalculateTargetClassLayout();
m_bClassLayoutDirty = true;
}
else
{
// See if we're over a sub button
bool bOverSubButton = false;
for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
{
if ( m_pSubButtons[i]->IsWithin(x,y) )
{
bOverSubButton = true;
UpdateLabelFromSubButton( i );
}
}
if ( !bOverSubButton && m_pClassLabel->IsVisible() )
{
// Hide the class label
if ( m_iMouseXPos != -1 )
{
m_iMouseXPos = -1;
RecalculateTargetClassLayout();
m_bClassLayoutDirty = true;
}
m_iOverSubButton = -1;
m_iLabelSetToClass = -1;
m_pClassLabel->SetVisible( false );
m_pItemsLabel->SetVisible( false );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CCharInfoLoadoutSubPanel::RecalculateTargetClassLayout( void )
{
// Now Layout the class images.
for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
{
int iIndex = GetRemappedMenuIndexForClass(i);
// Figure out where we'd be unscaled
int iXLeft = (GetWide() - ((m_iClassWideMin * NUM_CLASSES_IN_LOADOUT_PANEL) + (m_iClassXDelta * (NUM_CLASSES_IN_LOADOUT_PANEL-1)))) * 0.5;
int iBaseX = iXLeft + ((m_iClassWideMin + m_iClassXDelta) * (iIndex-1));
// Scale based on distance from the mouse cursor.
int iCenterX = iBaseX + (m_iClassWideMin * 0.5);
float flScale = 0.0;
if ( m_iMouseXPos >= 0 )
{
flScale = RemapValClamped( abs(m_iMouseXPos - iCenterX), m_iClassDistanceMin, m_iClassDistanceMax, 1.0, 0.0 );
}
float iWide = RemapValClamped( flScale, 0.0, 1.0, m_iClassWideMin, m_iClassWideMax );
float iTall = RemapValClamped( flScale, 0.0, 1.0, m_iClassTallMin, m_iClassTallMax );
int iY = m_iClassYPos - ((iTall - m_iClassTallMin) * 0.5);
int iX = iBaseX - ((iWide - m_iClassWideMin) * 0.5);
m_pClassButtons[i]->SetZPos( flScale * 100 );
// Cache off the target bounds for this class button
m_iClassLayout[i][0] = iX;
m_iClassLayout[i][1] = iY;
m_iClassLayout[i][2] = iWide;
m_iClassLayout[i][3] = iTall;
}
}
void CCharInfoLoadoutSubPanel::MoveCharacterSelection( int nDirection )
{
int nCurrent = 0;
if ( m_iLabelSetToClass != -1 )
{
for ( int i = 0; i < ARRAYSIZE( g_nLoadoutClassOrder ); i++ )
{
if ( m_iLabelSetToClass == g_nLoadoutClassOrder[ i ] )
{
nCurrent = i;
break;
}
}
nCurrent += nDirection;
if ( nCurrent < 0 )
{
nCurrent = ARRAYSIZE( g_nLoadoutClassOrder ) - 1;
}
else if ( nCurrent >= ARRAYSIZE( g_nLoadoutClassOrder ) )
{
nCurrent = 0;
}
}
for ( int i = 0; i < ARRAYSIZE( g_nLoadoutClassOrder ); i++ )
{
m_pClassButtons[ g_nLoadoutClassOrder[ i ] ]->SetArmed( false );
}
// animate the class buttons
CImageButton *pButton = m_pClassButtons[ g_nLoadoutClassOrder[ nCurrent ] ];
int x, y, wide, tall;
pButton->GetBounds( x, y, wide, tall );
RecalculateTargetClassLayoutAtPos( x + wide/2, y + tall/2 );
pButton->RequestFocus();
}
void CCharInfoLoadoutSubPanel::OnKeyCodeTyped(vgui::KeyCode code)
{
// turn off key handling in this panel when we're showing a loadout
// for one class
if ( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
// let escape and B (aka "go back") through so we
// can actually get out of the loadout screen
if ( code == KEY_ESCAPE )
{
BaseClass::OnKeyCodePressed( code );
}
return;
}
BaseClass::OnKeyCodeTyped( code );
}
void CCharInfoLoadoutSubPanel::OnKeyCodePressed(vgui::KeyCode code)
{
ButtonCode_t nButtonCode = GetBaseButtonCode( code );
// turn off key handling in this panel when we're showing a loadout
// for one class
if( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
{
// let escape and B (aka "go back") through so we
// can actually get out of the loadout screen
if ( nButtonCode == KEY_XBUTTON_B )
{
BaseClass::OnKeyCodePressed( code );
}
return;
}
if ( nButtonCode == KEY_XBUTTON_LEFT ||
nButtonCode == KEY_XSTICK1_LEFT ||
nButtonCode == KEY_XSTICK2_LEFT ||
nButtonCode == STEAMCONTROLLER_DPAD_LEFT ||
code == KEY_LEFT )
{
if ( m_iLabelSetToClass != -1 )
{
MoveCharacterSelection( -1 );
}
else
{
UpdateLabelFromSubButton( m_iOverSubButton - 1 );
}
return;
}
else if ( nButtonCode == KEY_XBUTTON_RIGHT ||
nButtonCode == KEY_XSTICK1_RIGHT ||
nButtonCode == KEY_XSTICK2_RIGHT ||
nButtonCode == STEAMCONTROLLER_DPAD_RIGHT ||
code == KEY_RIGHT )
{
if ( m_iLabelSetToClass != -1 )
{
MoveCharacterSelection( 1 );
}
else
{
UpdateLabelFromSubButton( m_iOverSubButton + 1 );
}
return;
}
else if ( nButtonCode == KEY_XBUTTON_UP ||
nButtonCode == KEY_XSTICK1_UP ||
nButtonCode == KEY_XSTICK2_UP ||
nButtonCode == STEAMCONTROLLER_DPAD_UP ||
code == KEY_UP )
{
if ( m_iLabelSetToClass == -1 )
{
m_iLabelSetToClass = g_nLoadoutClassOrder[ 0 ];
CImageButton *pButton = m_pClassButtons[ m_iLabelSetToClass ];
UpdateLabelFromClass( m_iLabelSetToClass );
int x, y, wide, tall;
pButton->GetBounds( x, y, wide, tall );
RecalculateTargetClassLayoutAtPos( x + wide/2, y + tall/2 );
pButton->RequestFocus();
}
return;
}
else if ( nButtonCode == KEY_XBUTTON_DOWN ||
nButtonCode == KEY_XSTICK1_DOWN ||
nButtonCode == KEY_XSTICK2_DOWN ||
nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
code == KEY_DOWN )
{
if ( m_iLabelSetToClass != -1 )
{
m_iLabelSetToClass = -1;
m_pClassLabel->SetVisible( false );
m_pItemsLabel->SetVisible( false );
for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
{
int i = g_nLoadoutClassOrder[iPanel];
m_pClassButtons[i]->SetArmed( false );
}
UpdateLabelFromSubButton( 0 );
}
return;
}
BaseClass::OnKeyCodePressed( code );
}