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.
1703 lines
50 KiB
1703 lines
50 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "tf_classmenu.h" |
|
#include "IGameUIFuncs.h" // for key bindings |
|
#include "tf_hud_notification_panel.h" |
|
#include "character_info_panel.h" |
|
#include "playerspawncache.h" |
|
#include "iclientmode.h" |
|
#include "econ_gcmessages.h" |
|
#include "gc_clientsystem.h" |
|
#include "vgui/IInput.h" |
|
#include <vgui_controls/PanelListPanel.h> |
|
#include <vgui_controls/ScrollBarSlider.h> |
|
#include "tf_gamerules.h" |
|
#include "engine/IEngineSound.h" |
|
#include "inputsystem/iinputsystem.h" |
|
|
|
#if defined( REPLAY_ENABLED ) |
|
#include "replay/iclientreplaycontext.h" |
|
#include "replay/ireplaysystem.h" |
|
#include "replay/ienginereplay.h" |
|
#include "replay/shared_defs.h" |
|
#endif |
|
|
|
extern IGameUIFuncs *gameuifuncs; // for key binding details |
|
|
|
using namespace vgui; |
|
|
|
ConVar _cl_classmenuopen( "_cl_classmenuopen", "0", 0, "internal cvar used to tell server when class menu is open" ); |
|
|
|
#if defined( REPLAY_ENABLED ) |
|
ConVar replay_replaywelcomedlgcount( "replay_replaywelcomedlgcount", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD | FCVAR_ARCHIVE | FCVAR_HIDDEN, "The number of times the replay help dialog has displayed." ); |
|
#endif |
|
|
|
ConVar tf_mvm_classupgradehelpcount( "tf_mvm_classupgradehelpcount", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD | FCVAR_ARCHIVE | FCVAR_HIDDEN, "The number of times the player upgrade help dialog has displayed." ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFClassTipsItemPanel::CTFClassTipsItemPanel( Panel *parent, const char *name, int iListItemID ) : BaseClass( parent, name ) |
|
{ |
|
m_pTipIcon = new vgui::ImagePanel( this, "TipIcon" ); |
|
m_pTipLabel = new CExLabel( this, "TipLabel", "" ); |
|
|
|
// m_pTipIcon = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "TipIcon" ) ); |
|
// m_pTipLabel = dynamic_cast<CExLabel*>( FindChildByName( "TipLabel" ) ); |
|
} |
|
|
|
CTFClassTipsItemPanel::~CTFClassTipsItemPanel() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassTipsItemPanel::SetClassTip( const wchar_t *pwszText, const char *pszIcon ) |
|
{ |
|
// Set tf_english string and .res icon path |
|
if ( m_pTipLabel && m_pTipIcon ) |
|
{ |
|
if ( pszIcon ) |
|
{ |
|
m_pTipIcon->SetImage( pszIcon ); |
|
} |
|
else |
|
{ |
|
m_pTipIcon->SetVisible( false ); |
|
// int iX, iY = 0; |
|
// m_pTipLabel->GetPos( iX, iY ); |
|
// int nIconWidth = m_pTipIcon->GetWide(); |
|
// m_pTipLabel->SetPos( ( iX - nIconWidth ), iY ); |
|
} |
|
m_pTipLabel->SetText( pwszText ); |
|
} |
|
|
|
InvalidateLayout( true, true ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassTipsItemPanel::ApplySchemeSettings( IScheme* pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/UI/ClassTipsItem.res" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class CTFClassTipsListPanel : public PanelListPanel |
|
{ |
|
private: |
|
DECLARE_CLASS_SIMPLE( CTFClassTipsListPanel, PanelListPanel ); |
|
|
|
public: |
|
CTFClassTipsListPanel( Panel *parent, const char *panelName ) |
|
: PanelListPanel( parent, panelName ) |
|
{ |
|
m_pScrollBar = GetScrollbar(); |
|
|
|
m_pUpArrow = new CExImageButton( this, "UpArrow", "" ); |
|
if ( m_pUpArrow ) |
|
{ |
|
m_pUpArrow->AddActionSignalTarget( m_pScrollBar ); |
|
m_pUpArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 0)); |
|
m_pUpArrow->GetImage()->SetShouldScaleImage( true ); |
|
m_pUpArrow->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
m_pUpArrow->SetAlpha( 255 ); |
|
m_pUpArrow->SetPaintBackgroundEnabled( false ); |
|
m_pUpArrow->SetVisible( false ); |
|
m_pUpArrow->PassMouseTicksTo( m_pScrollBar ); |
|
m_pUpArrow->SetImageDefault( "chalkboard_scroll_up" ); |
|
} |
|
|
|
m_pDownArrow = new CExImageButton( this, "DownArrow", "" ); |
|
if ( m_pDownArrow ) |
|
{ |
|
m_pDownArrow->AddActionSignalTarget( m_pScrollBar ); |
|
m_pDownArrow->SetCommand(new KeyValues("ScrollButtonPressed", "index", 1)); |
|
m_pDownArrow->GetImage()->SetShouldScaleImage( true ); |
|
m_pDownArrow->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
m_pDownArrow->SetAlpha( 255 ); |
|
m_pDownArrow->SetPaintBackgroundEnabled( false ); |
|
m_pDownArrow->SetVisible( false ); |
|
m_pDownArrow->PassMouseTicksTo( m_pScrollBar ); |
|
m_pDownArrow->SetImageDefault( "chalkboard_scroll_down" ); |
|
} |
|
|
|
if ( m_pScrollBar ) |
|
{ |
|
m_pScrollBar->SetOverriddenButtons( m_pUpArrow, m_pDownArrow ); |
|
m_pScrollBar->SetVisible( false ); |
|
} |
|
|
|
m_pLine = new vgui::ImagePanel( this, "Line" ); |
|
m_pBox = new vgui::ImagePanel( this, "Box" ); |
|
if ( m_pLine ) |
|
{ |
|
m_pLine->SetImage( "chalkboard_scroll_line" ); |
|
m_pLine->SetShouldScaleImage( true ); |
|
} |
|
|
|
if ( m_pBox ) |
|
{ |
|
m_pBox->SetImage( "chalkboard_scroll_box" ); |
|
m_pBox->SetShouldScaleImage( true ); |
|
} |
|
|
|
SetScrollBarImagesVisible( false ); |
|
|
|
vgui::ivgui()->AddTickSignal( GetVPanel() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
~CTFClassTipsListPanel() |
|
{ |
|
ivgui()->RemoveTickSignal( GetVPanel() ); |
|
} |
|
|
|
private: |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int GetListHeight( void ) |
|
{ |
|
int nHeight = 0; |
|
|
|
for ( int i = FirstItem(); i < GetItemCount(); i++ ) |
|
{ |
|
vgui::Panel *pClassTipsItemPanel = GetItemPanel( i ); |
|
if ( pClassTipsItemPanel ) |
|
{ |
|
nHeight += pClassTipsItemPanel->GetTall(); |
|
} |
|
} |
|
|
|
return nHeight; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void SetScrollBarImagesVisible( bool visible ) |
|
{ |
|
if ( m_pDownArrow && m_pDownArrow->IsVisible() != visible ) |
|
{ |
|
m_pDownArrow->SetVisible( visible ); |
|
m_pDownArrow->SetEnabled( visible ); |
|
} |
|
|
|
if ( m_pUpArrow && m_pUpArrow->IsVisible() != visible ) |
|
{ |
|
m_pUpArrow->SetVisible( visible ); |
|
m_pUpArrow->SetEnabled( visible ); |
|
} |
|
|
|
if ( m_pLine && m_pLine->IsVisible() != visible ) |
|
{ |
|
m_pLine->SetVisible( visible ); |
|
} |
|
|
|
if ( m_pBox && m_pBox->IsVisible() != visible ) |
|
{ |
|
m_pBox->SetVisible( visible ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void OnTick() |
|
{ |
|
if ( !IsVisible() ) |
|
return; |
|
|
|
if ( m_pDownArrow && m_pUpArrow && m_pLine && m_pBox ) |
|
{ |
|
if ( m_pScrollBar && m_pScrollBar->IsVisible() && GetListHeight() > GetTall() ) |
|
{ |
|
SetScrollBarImagesVisible ( true ); |
|
|
|
// set the alpha on the up arrow |
|
int nMin, nMax; |
|
m_pScrollBar->GetRange( nMin, nMax ); |
|
int nScrollPos = m_pScrollBar->GetValue(); |
|
int nRangeWindow = m_pScrollBar->GetRangeWindow(); |
|
int nBottom = nMax - nRangeWindow; |
|
if ( nBottom < 0 ) |
|
{ |
|
nBottom = 0; |
|
} |
|
|
|
int nAlpha = ( nScrollPos - nMin <= 0 ) ? 90 : 255; |
|
m_pUpArrow->SetAlpha( nAlpha ); |
|
|
|
// set the alpha on the down arrow |
|
nAlpha = ( nScrollPos >= nBottom ) ? 90 : 255; |
|
m_pDownArrow->SetAlpha( nAlpha ); |
|
|
|
ScrollBarSlider *pSlider = m_pScrollBar->GetSlider(); |
|
if ( pSlider && pSlider->GetRangeWindow() > 0 ) |
|
{ |
|
int x, y, w, t, min, max; |
|
m_pLine->GetBounds( x, y, w, t ); |
|
pSlider->GetNobPos( min, max ); |
|
m_pBox->SetBounds( x, y + min, w, ( max - min ) ); |
|
} |
|
} |
|
else |
|
{ |
|
// turn off our images |
|
SetScrollBarImagesVisible ( false ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
if ( m_pScrollBar ) |
|
{ |
|
m_pScrollBar->SetZPos( 500 ); |
|
m_pUpArrow->SetZPos( 501 ); |
|
m_pDownArrow->SetZPos( 501 ); |
|
|
|
// turn off painting the vertical scrollbar |
|
m_pScrollBar->SetPaintBackgroundEnabled( false ); |
|
m_pScrollBar->SetPaintBorderEnabled( false ); |
|
m_pScrollBar->SetPaintEnabled( false ); |
|
m_pScrollBar->SetScrollbarButtonsVisible( false ); |
|
m_pScrollBar->GetButton(0)->SetMouseInputEnabled( false ); |
|
m_pScrollBar->GetButton(1)->SetMouseInputEnabled( false ); |
|
|
|
if ( m_pScrollBar->IsVisible() ) |
|
{ |
|
int nMin, nMax; |
|
m_pScrollBar->GetRange( nMin, nMax ); |
|
m_pScrollBar->SetValue( nMin ); |
|
|
|
int nScrollbarWide = m_pScrollBar->GetWide(); |
|
|
|
int wide, tall; |
|
GetSize( wide, tall ); |
|
|
|
if ( m_pUpArrow ) |
|
{ |
|
m_pUpArrow->SetBounds( wide - nScrollbarWide, 0, nScrollbarWide, nScrollbarWide ); |
|
m_pUpArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide ); |
|
} |
|
|
|
if ( m_pLine ) |
|
{ |
|
m_pLine->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, tall - ( 2 * nScrollbarWide ) ); |
|
} |
|
|
|
if ( m_pBox ) |
|
{ |
|
m_pBox->SetBounds( wide - nScrollbarWide, nScrollbarWide, nScrollbarWide, nScrollbarWide ); |
|
} |
|
|
|
if ( m_pDownArrow ) |
|
{ |
|
m_pDownArrow->SetBounds( wide - nScrollbarWide, tall - nScrollbarWide, nScrollbarWide, nScrollbarWide ); |
|
m_pDownArrow->GetImage()->SetSize( nScrollbarWide, nScrollbarWide ); |
|
} |
|
|
|
SetScrollBarImagesVisible( false ); |
|
} |
|
} |
|
} |
|
|
|
vgui::ScrollBar *m_pScrollBar; |
|
CExImageButton *m_pUpArrow; |
|
CExImageButton *m_pDownArrow; |
|
vgui::ImagePanel *m_pLine; |
|
vgui::ImagePanel *m_pBox; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class CTFClassTipsPanel : public EditablePanel |
|
{ |
|
private: |
|
DECLARE_CLASS_SIMPLE( CTFClassTipsPanel, EditablePanel ); |
|
|
|
public: |
|
CTFClassTipsPanel( Panel *parent, const char *panelName ) |
|
: EditablePanel( parent, panelName ) |
|
{ |
|
m_pClassTipsListPanel = new CTFClassTipsListPanel( this, "ClassTipsListPanel" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
~CTFClassTipsPanel() |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void SetClass( int iClass ) |
|
{ |
|
const char *pPathID = IsX360() ? "MOD" : "GAME"; |
|
m_fmtResFilename.sprintf( "classes/%s.res", g_aRawPlayerClassNames[ iClass ] ); |
|
if ( !g_pFullFileSystem->FileExists( m_fmtResFilename.Access(), pPathID ) && |
|
g_pFullFileSystem->FileExists( "classes/default.res", pPathID ) ) |
|
{ |
|
m_fmtResFilename.sprintf( "classes/default.res" ); |
|
} |
|
|
|
if ( m_pClassTipsListPanel ) |
|
{ |
|
m_pClassTipsListPanel->DeleteAllItems(); |
|
|
|
int nScrollToItem = 0; |
|
|
|
// Get tip count |
|
const wchar_t *wzTipCount = g_pVGuiLocalize->Find( CFmtStr( "ClassTips_%d_Count", iClass ) ); |
|
int nTipCount = wzTipCount ? _wtoi( wzTipCount ) : 0; |
|
for ( int iTip = 1; iTip < nTipCount+1; ++iTip ) |
|
{ |
|
const wchar_t *pwszText = g_pVGuiLocalize->Find( CFmtStr( "#ClassTips_%d_%d", iClass, iTip ) ); |
|
const wchar_t *pwszTextMvM = g_pVGuiLocalize->Find( CFmtStr( "#ClassTips_%d_%d_MvM", iClass, iTip ) ); |
|
wchar_t *pwszIcon = g_pVGuiLocalize->Find( CFmtStr( "ClassTips_%d_%d_Icon", iClass, iTip ) ); |
|
char szIcon[MAX_PATH]; |
|
|
|
szIcon[0] = 0; |
|
if ( pwszIcon ) |
|
{ |
|
g_pVGuiLocalize->ConvertUnicodeToANSI( pwszIcon, szIcon, sizeof( szIcon ) ); |
|
} |
|
|
|
// Don't load MvM tips outside the mode |
|
if ( pwszTextMvM ) |
|
{ |
|
if ( !TFGameRules()->IsMannVsMachineMode() ) |
|
continue; |
|
|
|
// If we're MvM mode, remember first MvM tip |
|
if ( !nScrollToItem ) |
|
nScrollToItem = iTip; |
|
} |
|
|
|
// Create a TipsItemPanel for each tip |
|
if ( pwszText || pwszTextMvM ) |
|
{ |
|
CTFClassTipsItemPanel *pClassTipsItemPanel = new CTFClassTipsItemPanel( this, "ClassTipsItemPanel", iTip ); |
|
if ( pwszText ) |
|
{ |
|
pClassTipsItemPanel->SetClassTip( pwszText, szIcon ); |
|
} |
|
else if ( pwszTextMvM ) |
|
{ |
|
pClassTipsItemPanel->SetClassTip( pwszTextMvM, szIcon ); |
|
} |
|
|
|
m_pClassTipsListPanel->AddItem( NULL, pClassTipsItemPanel ); |
|
} |
|
} |
|
|
|
if ( m_pClassTipsListPanel->GetItemCount() > 0 ) |
|
{ |
|
m_pClassTipsListPanel->SetFirstColumnWidth( 0 ); |
|
m_pClassTipsListPanel->ScrollToItem( nScrollToItem ); |
|
} |
|
} |
|
|
|
InvalidateLayout( true, true ); |
|
} |
|
|
|
private: |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
virtual void ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
LoadControlSettings( "Resource/UI/ClassTipsList.res" ); |
|
} |
|
|
|
CTFClassTipsListPanel *m_pClassTipsListPanel; |
|
|
|
CFmtStr m_fmtResFilename; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CTFClassMenu::CTFClassMenu( IViewPort *pViewPort ) |
|
: CClassMenu( pViewPort ) |
|
{ |
|
MakePopup(); |
|
|
|
m_mouseoverButtons.RemoveAll(); |
|
|
|
m_iClassMenuKey = BUTTON_CODE_INVALID; |
|
m_iCurrentClassIndex = TF_CLASS_HEAVYWEAPONS; |
|
|
|
#ifdef _X360 |
|
m_pFooter = new CTFFooter( this, "Footer" ); |
|
#endif |
|
|
|
m_pTFPlayerModelPanel = NULL; |
|
m_pSelectAClassLabel = NULL; |
|
|
|
m_pClassTipsPanel = new CTFClassTipsPanel( this, "ClassTipsPanel" ); |
|
|
|
Q_memset( m_pClassButtons, 0, sizeof( m_pClassButtons ) ); |
|
|
|
#ifndef _X360 |
|
char tempName[MAX_PATH]; |
|
for ( int i = 0 ; i < CLASS_COUNT_IMAGES ; ++i ) |
|
{ |
|
Q_snprintf( tempName, sizeof( tempName ), "countImage%d", i ); |
|
m_ClassCountImages[i] = new CTFImagePanel( this, tempName ); |
|
} |
|
|
|
m_pCountLabel = NULL; |
|
|
|
m_pLocalPlayerImage = new CTFImagePanel( this, "localPlayerImage" ); |
|
m_pLocalPlayerBG = new CTFImagePanel( this, "localPlayerBG" ); |
|
m_iLocalPlayerClass = TEAM_UNASSIGNED; |
|
|
|
m_pClassButtons[TF_CLASS_SCOUT] = new CExImageButton( this, "scout", "", this ); |
|
m_pClassButtons[TF_CLASS_SOLDIER] = new CExImageButton( this, "soldier", "", this ); |
|
m_pClassButtons[TF_CLASS_PYRO] = new CExImageButton( this, "pyro", "", this ); |
|
m_pClassButtons[TF_CLASS_DEMOMAN] = new CExImageButton( this, "demoman", "", this ); |
|
m_pClassButtons[TF_CLASS_MEDIC] = new CExImageButton( this, "medic", "", this ); |
|
m_pClassButtons[TF_CLASS_HEAVYWEAPONS] = new CExImageButton( this, "heavyweapons", "", this ); |
|
m_pClassButtons[TF_CLASS_SNIPER] = new CExImageButton( this, "sniper", "", this ); |
|
m_pClassButtons[TF_CLASS_ENGINEER] = new CExImageButton( this, "engineer", "", this ); |
|
m_pClassButtons[TF_CLASS_SPY] = new CExImageButton( this, "spy", "", this ); |
|
m_pClassButtons[TF_CLASS_RANDOM] = new CExImageButton( this, "random", "", this ); |
|
#endif |
|
|
|
m_pEditLoadoutButton = NULL; |
|
m_nBaseMusicGuid = -1; |
|
|
|
ListenForGameEvent( "localplayer_changeteam" ); |
|
ListenForGameEvent( "show_match_summary" ); |
|
|
|
Q_memset( m_pMvmUpgradeImages, 0, sizeof( m_pMvmUpgradeImages ) ); |
|
m_pMvmUpgradeImages[TF_CLASS_SCOUT] = new vgui::ImagePanel( this, "MvMUpgradeImageScout" ); |
|
m_pMvmUpgradeImages[TF_CLASS_SOLDIER] = new vgui::ImagePanel( this, "MvMUpgradeImageSolider" ); |
|
m_pMvmUpgradeImages[TF_CLASS_PYRO] = new vgui::ImagePanel( this, "MvMUpgradeImagePyro" ); |
|
m_pMvmUpgradeImages[TF_CLASS_DEMOMAN] = new vgui::ImagePanel( this, "MvMUpgradeImageDemoman" ); |
|
m_pMvmUpgradeImages[TF_CLASS_MEDIC] = new vgui::ImagePanel( this, "MvMUpgradeImageMedic" ); |
|
m_pMvmUpgradeImages[TF_CLASS_HEAVYWEAPONS] = new vgui::ImagePanel( this, "MvMUpgradeImageHeavy" ); |
|
m_pMvmUpgradeImages[TF_CLASS_SNIPER] = new vgui::ImagePanel( this, "MvMUpgradeImageSniper" ); |
|
m_pMvmUpgradeImages[TF_CLASS_ENGINEER] = new vgui::ImagePanel( this, "MvMUpgradeImageEngineer" ); |
|
m_pMvmUpgradeImages[TF_CLASS_SPY] = new vgui::ImagePanel( this, "MvMUpgradeImageSpy" ); |
|
|
|
vgui::ivgui()->AddTickSignal( GetVPanel() ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
for ( int i = 0; i < TF_CLASS_MENU_BUTTONS; i++ ) |
|
{ |
|
m_pClassHintIcons[i] = nullptr; |
|
} |
|
|
|
// Load the .res file |
|
if ( ::input->IsSteamControllerActive() ) |
|
{ |
|
LoadControlSettings( "Resource/UI/ClassSelection_SC.res" ); |
|
m_pCancelHintIcon = dynamic_cast< CSCHintIcon* >( FindChildByName( "CancelHintIcon" ) ); |
|
m_pEditLoadoutHintIcon = dynamic_cast< CSCHintIcon* >( FindChildByName( "EditLoadoutHintIcon" ) ); |
|
|
|
m_pClassHintIcons[TF_CLASS_SCOUT] = dynamic_cast< CSCHintIcon* >( FindChildByName( "ScoutHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_SOLDIER] = dynamic_cast< CSCHintIcon* >( FindChildByName( "SoldierHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_PYRO] = dynamic_cast< CSCHintIcon* >( FindChildByName( "PyroHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_DEMOMAN] = dynamic_cast< CSCHintIcon* >( FindChildByName( "DemomanHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_HEAVYWEAPONS] = dynamic_cast< CSCHintIcon* >( FindChildByName( "HeavyHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_MEDIC] = dynamic_cast< CSCHintIcon* >( FindChildByName( "MedicHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_SPY] = dynamic_cast< CSCHintIcon* >( FindChildByName( "SpyHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_ENGINEER] = dynamic_cast< CSCHintIcon* >( FindChildByName( "EngineerHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_SNIPER] = dynamic_cast< CSCHintIcon* >( FindChildByName( "SniperHintIcon" ) ); |
|
m_pClassHintIcons[TF_CLASS_RANDOM] = dynamic_cast< CSCHintIcon* >( FindChildByName( "RandomHintIcon" ) ); |
|
|
|
for ( int i = 0; i < TF_CLASS_MENU_BUTTONS; i++ ) |
|
{ |
|
if ( m_pClassHintIcons[i] ) |
|
{ |
|
m_pClassHintIcons[i]->SetVisible( false ); |
|
} |
|
} |
|
|
|
SetMouseInputEnabled( false ); |
|
} |
|
else |
|
{ |
|
LoadControlSettings( "Resource/UI/ClassSelection.res" ); |
|
m_pCancelHintIcon = m_pEditLoadoutHintIcon = nullptr; |
|
SetMouseInputEnabled( true ); |
|
} |
|
|
|
m_pTFPlayerModelPanel = dynamic_cast<CTFPlayerModelPanel*>( FindChildByName("TFPlayerModel") ); |
|
m_pSelectAClassLabel = dynamic_cast<CExLabel*>( FindChildByName( "ClassMenuSelect" ) ); |
|
m_pEditLoadoutButton = dynamic_cast<CExButton*>( FindChildByName( "EditLoadoutButton" ) ); |
|
|
|
const char *pTeamExtension = GetTeamNumber() == TF_TEAM_BLUE ? "blu" : "red"; |
|
for ( int i = 0; i < ARRAYSIZE( m_pClassButtons ); ++i ) |
|
{ |
|
if ( !m_pClassButtons[i] ) |
|
continue; |
|
|
|
if ( !IsValidTFPlayerClass( i ) && i != TF_CLASS_RANDOM ) |
|
continue; |
|
|
|
m_pClassButtons[i]->SetImageSelected( CFmtStr( "class_sel_sm_%s_%s", g_aRawPlayerClassNamesShort[i], pTeamExtension ).Access() ); |
|
if( i != TF_CLASS_RANDOM ) |
|
{ |
|
m_pClassButtons[i]->SetArmedSound("misc/null.wav"); |
|
} |
|
} |
|
} |
|
|
|
void CTFClassMenu::PerformLayout() |
|
{ |
|
BaseClass::PerformLayout(); |
|
|
|
#ifndef _X360 |
|
m_pCountLabel = dynamic_cast< CExLabel * >( FindChildByName( "CountLabel" ) ); |
|
|
|
if ( m_pCountLabel ) |
|
{ |
|
m_pCountLabel->SizeToContents(); |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
int CTFClassMenu::GetCurrentPlayerClass() |
|
{ |
|
int iClass = TF_CLASS_HEAVYWEAPONS; |
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
if ( pLocalPlayer && pLocalPlayer->m_Shared.GetDesiredPlayerClassIndex() != TF_CLASS_UNDEFINED ) |
|
{ |
|
iClass = pLocalPlayer->m_Shared.GetDesiredPlayerClassIndex(); |
|
} |
|
|
|
return iClass; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CExImageButton *CTFClassMenu::GetCurrentClassButton() |
|
{ |
|
const int iClass = GetCurrentPlayerClass(); |
|
m_iCurrentClassIndex = iRemapIndexToClass[ iClass ]; |
|
return m_pClassButtons[iClass]; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::ShowPanel( bool bShow ) |
|
{ |
|
if ( bShow ) |
|
{ |
|
// Hide the other class menu |
|
if ( gViewPortInterface ) |
|
{ |
|
gViewPortInterface->ShowPanel( GetTeamNumber() == TF_TEAM_BLUE ? PANEL_CLASS_RED : PANEL_CLASS_BLUE, false ); |
|
} |
|
|
|
// can't change class if you're on the losing team during the "bonus time" after a team has won the round |
|
if ( ( TFGameRules()->State_Get() == GR_STATE_TEAM_WIN && |
|
C_TFPlayer::GetLocalTFPlayer() && |
|
C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber() != TFGameRules()->GetWinningTeam() |
|
&& C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber() != TEAM_SPECTATOR |
|
&& C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber() != TEAM_UNASSIGNED |
|
&& GetSpectatorMode() == OBS_MODE_NONE ) || |
|
TFGameRules()->State_Get() == GR_STATE_GAME_OVER || |
|
( TFGameRules()->IsInTraining() && C_TFPlayer::GetLocalTFPlayer() && |
|
( C_TFPlayer::GetLocalTFPlayer()->GetPlayerClass() == NULL || C_TFPlayer::GetLocalTFPlayer()->GetPlayerClass()->GetClassIndex() != TF_CLASS_UNDEFINED ) ) ) |
|
{ |
|
SetVisible( false ); |
|
|
|
CHudNotificationPanel *pNotifyPanel = GET_HUDELEMENT( CHudNotificationPanel ); |
|
if ( pNotifyPanel ) |
|
{ |
|
if ( C_TFPlayer::GetLocalTFPlayer() ) |
|
{ |
|
pNotifyPanel->SetupNotifyCustom( "#TF_CantChangeClassNow", "ico_notify_flag_moving", C_TFPlayer::GetLocalTFPlayer()->GetTeamNumber() ); |
|
} |
|
} |
|
|
|
return; |
|
} |
|
|
|
engine->CheckPoint( "ClassMenu" ); |
|
|
|
// Force us to reload our scheme, in case Steam Controller stuff has changed. |
|
InvalidateLayout( true, true ); |
|
|
|
Activate(); |
|
|
|
m_iClassMenuKey = gameuifuncs->GetButtonCodeForBind( "changeclass" ); |
|
m_iScoreBoardKey = gameuifuncs->GetButtonCodeForBind( "showscores" ); |
|
|
|
SelectClass( GetCurrentPlayerClass() ); |
|
} |
|
else |
|
{ |
|
SetVisible( false ); |
|
if ( m_pTFPlayerModelPanel ) |
|
{ |
|
m_pTFPlayerModelPanel->ClearCarriedItems(); |
|
} |
|
} |
|
} |
|
|
|
const char *g_pszLegacyClassSelectVCDWeapons[TF_LAST_NORMAL_CLASS] = |
|
{ |
|
"", // TF_CLASS_UNDEFINED = 0, |
|
"", // TF_CLASS_SCOUT, // weapons handled individually |
|
"", // TF_CLASS_SNIPER, // weapons handled individually |
|
"", // TF_CLASS_SOLDIER, // weapons handled individually |
|
"tf_weapon_grenadelauncher", // TF_CLASS_DEMOMAN, |
|
"tf_weapon_medigun", // TF_CLASS_MEDIC, |
|
"tf_weapon_minigun", // TF_CLASS_HEAVYWEAPONS, |
|
"tf_weapon_flamethrower", // TF_CLASS_PYRO, |
|
"", // TF_CLASS_SPY, // weapons handled individually |
|
"tf_weapon_wrench", // TF_CLASS_ENGINEER, |
|
}; |
|
|
|
int g_iLegacyClassSelectWeaponSlots[TF_LAST_NORMAL_CLASS] = |
|
{ |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_UNDEFINED = 0, |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_SCOUT, // TF_FIRST_NORMAL_CLASS |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_SNIPER, |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_SOLDIER, |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_DEMOMAN, |
|
LOADOUT_POSITION_SECONDARY, // TF_CLASS_MEDIC, |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_HEAVYWEAPONS, |
|
LOADOUT_POSITION_PRIMARY, // TF_CLASS_PYRO, |
|
LOADOUT_POSITION_MELEE, // TF_CLASS_SPY, |
|
LOADOUT_POSITION_MELEE, // TF_CLASS_ENGINEER, |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::UpdateButtonSelectionStates( int iClass ) |
|
{ |
|
// Set the correct button as selected, all other buttons as not selected |
|
for ( int i = 0; i < ARRAYSIZE( m_pClassButtons ); ++i ) |
|
{ |
|
if ( !m_pClassButtons[ i ] ) |
|
continue; |
|
|
|
m_pClassButtons[ i ]->SetSelected( i == iClass ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::SelectClass( int iClass ) |
|
{ |
|
if ( !engine->IsInGame() ) |
|
return; |
|
|
|
if ( !m_pTFPlayerModelPanel ) |
|
return; |
|
|
|
if ( !m_pClassTipsPanel ) |
|
return; |
|
|
|
if ( !m_pEditLoadoutButton ) |
|
return; |
|
|
|
// Update select hint icon for Steam Controller |
|
for ( int i = 0; i < TF_CLASS_MENU_BUTTONS; i++ ) |
|
{ |
|
if ( m_pClassHintIcons[i] ) |
|
{ |
|
m_pClassHintIcons[i]->SetVisible( i == iClass ); |
|
} |
|
} |
|
|
|
// Were we random? If so, we'll force our class to refresh later to prevent the |
|
// model panel thinking the class hasn't changed. |
|
const bool bClassWasRandom = m_iCurrentClassIndex == TF_CLASS_RANDOM; |
|
|
|
// Cache current player class |
|
m_iCurrentClassIndex = iClass; |
|
|
|
UpdateButtonSelectionStates( iClass ); |
|
|
|
bool bRandomClass = iClass == TF_CLASS_RANDOM; |
|
if ( !IsValidTFPlayerClass( iClass ) && !bRandomClass ) |
|
{ |
|
m_pTFPlayerModelPanel->SetVisible( false ); |
|
m_pTFPlayerModelPanel->ClearCarriedItems(); |
|
return; |
|
} |
|
|
|
m_pTFPlayerModelPanel->SetVisible( true ); |
|
m_pTFPlayerModelPanel->ClearCarriedItems(); |
|
|
|
if ( bRandomClass ) |
|
{ |
|
m_pEditLoadoutButton->SetVisible( false ); |
|
if ( m_pEditLoadoutHintIcon ) |
|
{ |
|
m_pEditLoadoutHintIcon->SetVisible( false ); |
|
} |
|
|
|
MDLHandle_t hModel = mdlcache->FindMDL( "models/class_menu/random_class_icon.mdl" ); |
|
m_pTFPlayerModelPanel->SetMDL( hModel ); |
|
m_pTFPlayerModelPanel->SetSequence( ACT_IDLE ); |
|
m_pTFPlayerModelPanel->InvalidateLayout( true, true ); // Updates position |
|
m_pTFPlayerModelPanel->SetSkin( GetTeamNumber() == TF_TEAM_RED ? 0 : 1 ); |
|
mdlcache->Release( hModel ); // counterbalance addref from within FindMDL |
|
} |
|
else |
|
{ |
|
bool bIsRobot = false; |
|
// Check for Robot |
|
static CSchemaAttributeDefHandle pAttrDef_PlayerRobot( "appear as mvm robot" ); |
|
for ( int i = 0; i < CLASS_LOADOUT_POSITION_COUNT; i++ ) |
|
{ |
|
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( iClass, i ); |
|
if ( !pItemData ) |
|
continue; |
|
if ( FindAttribute( pItemData, pAttrDef_PlayerRobot ) ) |
|
{ |
|
bIsRobot = true; |
|
break; |
|
} |
|
} |
|
|
|
/*if ( pLocalPlayer ) |
|
{ |
|
int iRobot = 0; |
|
CALL_ATTRIB_HOOK_INT_ON_OTHER( pLocalPlayer, iRobot, appear_as_mvm_robot ); |
|
bIsRobot = iRobot ? true : false; |
|
}*/ |
|
m_pTFPlayerModelPanel->SetToPlayerClass( iClass, bIsRobot, bClassWasRandom ); |
|
|
|
m_pEditLoadoutButton->SetVisible( true ); |
|
if ( m_pEditLoadoutHintIcon ) |
|
{ |
|
m_pEditLoadoutHintIcon->SetVisible( true ); |
|
} |
|
|
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( pLocalPlayer ) |
|
{ |
|
int iTeam = GetTeamNumber(); |
|
m_pTFPlayerModelPanel->SetTeam( iTeam ); |
|
} |
|
|
|
LoadItems(); |
|
} |
|
|
|
m_pClassTipsPanel->SetClass( iClass ); |
|
|
|
enginesound->StopSoundByGuid( m_nBaseMusicGuid ); |
|
CBroadcastRecipientFilter filter; |
|
char nClassMusicStr[64]; |
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
sprintf( nClassMusicStr, "music.mvm_class_menu_0%i", iClass ); |
|
} |
|
else |
|
{ |
|
sprintf( nClassMusicStr, "music.class_menu_0%i", iClass ); |
|
} |
|
CBaseEntity::EmitSound( filter, SOUND_FROM_UI_PANEL, nClassMusicStr ); |
|
m_nBaseMusicGuid = enginesound->GetGuidForLastSoundEmitted(); |
|
|
|
|
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::LoadItems() |
|
{ |
|
const int iClass = m_pTFPlayerModelPanel->GetPlayerClass(); |
|
|
|
m_pTFPlayerModelPanel->ClearCarriedItems(); |
|
|
|
static CSchemaAttributeDefHandle pAttrDef_DisableFancyLoadoutAnim( "disable fancy class select anim" ); |
|
bool bCanUseFancyClassSelectAnimation = true; |
|
|
|
static CSchemaAttributeDefHandle pAttrDef_ClassSelectOverrideVCD( "class select override vcd" ); |
|
CAttribute_String attrClassSelectOverrideVCD; |
|
|
|
const char *pszVCD = "class_select"; |
|
|
|
for ( int i = 0; i < CLASS_LOADOUT_POSITION_COUNT; i++ ) |
|
{ |
|
CEconItemView *pItemData = TFInventoryManager()->GetItemInLoadoutForClass( iClass, i ); |
|
if ( pItemData && pItemData->IsValid() ) |
|
{ |
|
m_pTFPlayerModelPanel->AddCarriedItem( pItemData ); |
|
|
|
// Certain items have different shapes and would interfere with our class select animations. |
|
bCanUseFancyClassSelectAnimation = bCanUseFancyClassSelectAnimation |
|
&& !pItemData->FindAttribute( pAttrDef_DisableFancyLoadoutAnim ); |
|
|
|
// Some items want to override the class select VCD |
|
if ( pItemData->FindAttribute( pAttrDef_ClassSelectOverrideVCD, &attrClassSelectOverrideVCD ) ) |
|
{ |
|
const char *pszClassSelectOverrideVCD = attrClassSelectOverrideVCD.value().c_str(); |
|
if ( pszClassSelectOverrideVCD && *pszClassSelectOverrideVCD ) |
|
{ |
|
pszVCD = pszClassSelectOverrideVCD; |
|
} |
|
} |
|
} |
|
} |
|
|
|
m_pTFPlayerModelPanel->PlayVCD( bCanUseFancyClassSelectAnimation ? pszVCD : NULL, g_pszLegacyClassSelectVCDWeapons[iClass] ); |
|
m_pTFPlayerModelPanel->HoldItemInSlot( g_iLegacyClassSelectWeaponSlots[iClass] ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnKeyCodePressed( KeyCode code ) |
|
{ |
|
m_KeyRepeat.KeyDown( code ); |
|
|
|
if ( code > KEY_0 && code <= KEY_9 ) |
|
{ |
|
const int iButton = code - KEY_0; |
|
const int iClass = iRemapIndexToClass[ iButton ]; |
|
SelectClass( iClass ); |
|
Go(); |
|
} |
|
else if ( code > KEY_PAD_0 && code <= KEY_PAD_9 ) |
|
{ |
|
const int iButton = code - KEY_PAD_0; |
|
const int iClass = iRemapIndexToClass[ iButton ]; |
|
SelectClass( iClass ); |
|
Go(); |
|
} |
|
else if( code == KEY_ENTER || code == KEY_SPACE || code == KEY_XBUTTON_A || code == KEY_XBUTTON_RTRIGGER || code == STEAMCONTROLLER_A ) |
|
{ |
|
Go(); |
|
} |
|
else if ( ( m_iClassMenuKey != BUTTON_CODE_INVALID && m_iClassMenuKey == code ) || |
|
code == KEY_XBUTTON_BACK || |
|
code == KEY_XBUTTON_B || |
|
code == STEAMCONTROLLER_B || |
|
code == KEY_0 || |
|
code == KEY_PAD_0 ) |
|
{ |
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
if ( pLocalPlayer && ( pLocalPlayer->GetPlayerClass()->GetClassIndex() != TF_CLASS_UNDEFINED ) ) |
|
{ |
|
ShowPanel( false ); |
|
} |
|
} |
|
else if( code == KEY_XBUTTON_RIGHT || code == KEY_XSTICK1_RIGHT || code == STEAMCONTROLLER_DPAD_RIGHT ) |
|
{ |
|
int loopCheck = 0; |
|
int nCurrentClass = GetRemappedMenuIndexForClass( m_iCurrentClassIndex ); |
|
|
|
do |
|
{ |
|
loopCheck++; |
|
nCurrentClass++; |
|
nCurrentClass = ( nCurrentClass % TF_CLASS_MENU_BUTTONS ); |
|
} while( ( m_pClassButtons[ iRemapIndexToClass[nCurrentClass] ] == NULL ) && ( loopCheck < TF_CLASS_MENU_BUTTONS ) ); |
|
|
|
SelectClass( iRemapIndexToClass[ nCurrentClass ] ); |
|
} |
|
else if ( code == STEAMCONTROLLER_Y ) |
|
{ |
|
OnCommand( "openloadout" ); |
|
} |
|
else if( code == KEY_XBUTTON_LEFT || code == KEY_XSTICK1_LEFT || code == STEAMCONTROLLER_DPAD_LEFT ) |
|
{ |
|
int loopCheck = 0; |
|
int nCurrentClass = GetRemappedMenuIndexForClass( m_iCurrentClassIndex ); |
|
|
|
do |
|
{ |
|
loopCheck++; |
|
nCurrentClass--; |
|
if( nCurrentClass <= 0 ) |
|
{ |
|
nCurrentClass = GetRemappedMenuIndexForClass( TF_CLASS_RANDOM ); |
|
} |
|
} while( ( m_pClassButtons[ iRemapIndexToClass[nCurrentClass] ] == NULL ) && ( loopCheck < TF_CLASS_MENU_BUTTONS ) ); |
|
|
|
SelectClass( iRemapIndexToClass[ nCurrentClass ] ); |
|
} |
|
else if( code == KEY_XBUTTON_UP || code == KEY_XSTICK1_UP || code == STEAMCONTROLLER_DPAD_UP ) |
|
{ |
|
// Scroll class info text up |
|
if ( g_lastPanel ) |
|
{ |
|
CExRichText *pRichText = dynamic_cast< CExRichText * >( g_lastPanel->FindChildByName( "classInfo" ) ); |
|
|
|
if ( pRichText ) |
|
{ |
|
PostMessage( pRichText, new KeyValues("MoveScrollBarDirect", "delta", 1) ); |
|
} |
|
} |
|
} |
|
else if( code == KEY_XBUTTON_DOWN || code == KEY_XSTICK1_DOWN || code == STEAMCONTROLLER_DPAD_DOWN ) |
|
{ |
|
// Scroll class info text up |
|
if ( g_lastPanel ) |
|
{ |
|
CExRichText *pRichText = dynamic_cast< CExRichText * >( g_lastPanel->FindChildByName( "classInfo" ) ); |
|
|
|
if ( pRichText ) |
|
{ |
|
PostMessage( pRichText, new KeyValues("MoveScrollBarDirect", "delta", -1) ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnKeyCodeReleased( vgui::KeyCode code ) |
|
{ |
|
m_KeyRepeat.KeyUp( code ); |
|
|
|
BaseClass::OnKeyCodeReleased( code ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnThink() |
|
{ |
|
vgui::KeyCode code = m_KeyRepeat.KeyRepeated(); |
|
if ( code ) |
|
{ |
|
OnKeyCodePressed( code ); |
|
} |
|
|
|
// Get mouse cursor position |
|
int aCursorPos[2]; |
|
vgui::input()->GetCursorPos( aCursorPos[0], aCursorPos[1] ); |
|
|
|
// Go through all buttons - if the mouse is within one, select that class |
|
for ( int i = 0; i < ARRAYSIZE( m_pClassButtons ); ++i ) |
|
{ |
|
if ( !m_pClassButtons[ i ] ) |
|
continue; |
|
|
|
if ( m_iCurrentClassIndex != i && m_pClassButtons[ i ]->IsWithin( aCursorPos[0], aCursorPos[1] ) ) |
|
{ |
|
SelectClass( i ); |
|
} |
|
} |
|
|
|
//Always hide the health... this needs to be done every frame because a message from the server keeps resetting this. |
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( pLocalPlayer ) |
|
{ |
|
pLocalPlayer->m_Local.m_iHideHUD |= HIDEHUD_HEALTH; |
|
} |
|
|
|
BaseClass::OnThink(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::SetCancelButtonVisible( bool bVisible ) |
|
{ |
|
SetVisibleButton( "CancelButton", bVisible ); |
|
if ( m_pCancelHintIcon ) |
|
{ |
|
m_pCancelHintIcon->SetVisible( bVisible ); |
|
} |
|
|
|
if ( m_pSelectAClassLabel ) |
|
{ |
|
m_pSelectAClassLabel->SetVisible( !bVisible ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::Update() |
|
{ |
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
// Force them to pick a class if they haven't picked one yet. |
|
if ( ( pLocalPlayer && pLocalPlayer->m_Shared.GetDesiredPlayerClassIndex() != TF_CLASS_UNDEFINED ) ) |
|
{ |
|
#ifdef _X360 |
|
if ( m_pFooter ) |
|
{ |
|
m_pFooter->ShowButtonLabel( "cancel", true ); |
|
} |
|
#else |
|
SetCancelButtonVisible( true ); |
|
|
|
if ( TFGameRules() && TFGameRules()->IsInHighlanderMode() ) |
|
{ |
|
SetVisibleButton( "ResetButton", true ); |
|
} |
|
else |
|
{ |
|
SetVisibleButton( "ResetButton", false ); |
|
} |
|
#endif |
|
} |
|
else |
|
{ |
|
#ifdef _X360 |
|
if ( m_pFooter ) |
|
{ |
|
m_pFooter->ShowButtonLabel( "cancel", false ); |
|
} |
|
#else |
|
SetCancelButtonVisible( false ); |
|
SetVisibleButton( "ResetButton", false ); |
|
#endif |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
Panel *CTFClassMenu::CreateControlByName( const char *controlName ) |
|
{ |
|
if ( !Q_stricmp( "CIconPanel", controlName ) ) |
|
{ |
|
return new CIconPanel( this, "icon_panel" ); |
|
} |
|
else |
|
{ |
|
return BaseClass::CreateControlByName( controlName ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Catch the mouseover event and set the active class |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnShowPage( vgui::Panel *panel, const char *pagename ) |
|
{ |
|
for ( int i = 0; i < TF_CLASS_MENU_BUTTONS; i++ ) |
|
{ |
|
if (m_pClassButtons[i] == panel ) |
|
{ |
|
// SelectClass( i ); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Draw nothing |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::PaintBackground( void ) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Do things that should be done often, eg number of players in the |
|
// selected class |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnTick( void ) |
|
{ |
|
//When a player changes teams, their class and team values don't get here |
|
//necessarily before the command to update the class menu. This leads to the cancel button |
|
//being visible and people cancelling before they have a class. check for class == TF_CLASS_UNDEFINED and if so |
|
//hide the cancel button |
|
|
|
if ( !IsVisible() ) |
|
return; |
|
|
|
#ifndef _X360 |
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
// Force them to pick a class if they haven't picked one yet. |
|
if ( pLocalPlayer && pLocalPlayer->m_Shared.GetDesiredPlayerClassIndex() == TF_CLASS_UNDEFINED ) |
|
{ |
|
SetCancelButtonVisible( false ); |
|
SetVisibleButton( "ResetButton", false ); |
|
} |
|
|
|
UpdateClassCounts(); |
|
|
|
#endif |
|
|
|
BaseClass::OnTick(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnClose() |
|
{ |
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( pLocalPlayer ) |
|
{ |
|
// Clear the HIDEHUD_HEALTH bit we hackily added. Turns out prediction |
|
// was restoring these bits every frame. Unfortunately, prediction |
|
// is off for karts which means the spell hud item would disappear if you |
|
// brought up this menu and returned. |
|
pLocalPlayer->m_Local.m_iHideHUD &= ~HIDEHUD_HEALTH; |
|
} |
|
|
|
ShowPanel( false ); |
|
|
|
BaseClass::OnClose(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::SetVisible( bool state ) |
|
{ |
|
BaseClass::SetVisible( state ); |
|
|
|
m_KeyRepeat.Reset(); |
|
|
|
if ( state ) |
|
{ |
|
engine->ServerCmd( "menuopen" ); // to the server |
|
engine->ClientCmd( "_cl_classmenuopen 1" ); // for other panels |
|
CBroadcastRecipientFilter filter; |
|
|
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
CBaseEntity::EmitSound( filter, SOUND_FROM_UI_PANEL, "music.mvm_class_menu" ); |
|
} |
|
else |
|
{ |
|
CBaseEntity::EmitSound( filter, SOUND_FROM_UI_PANEL, "music.class_menu" ); |
|
} |
|
|
|
CheckMvMUpgrades(); |
|
} |
|
else |
|
{ |
|
engine->ServerCmd( "menuclosed" ); |
|
engine->ClientCmd( "_cl_classmenuopen 0" ); |
|
|
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
CBaseEntity::StopSound( SOUND_FROM_UI_PANEL, "music.mvm_class_menu" ); |
|
} |
|
else |
|
{ |
|
CBaseEntity::StopSound( SOUND_FROM_UI_PANEL, "music.class_menu" ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::Go() |
|
{ |
|
const int iClass = m_iCurrentClassIndex; |
|
if ( iClass == TF_CLASS_UNDEFINED ) |
|
return; |
|
|
|
// Check class limits |
|
if ( TFGameRules() && !TFGameRules()->CanPlayerChooseClass( C_TFPlayer::GetLocalTFPlayer(), iClass ) ) |
|
return; |
|
|
|
#if defined( REPLAY_ENABLED ) |
|
// Display replay recording message if appropriate |
|
int &nDisplayedConnectedRecording = CPlayerSpawnCache::Instance().m_Data.m_nDisplayedConnectedRecording; |
|
if ( g_pReplay->IsReplayEnabled() && |
|
!g_pEngineClientReplay->IsPlayingReplayDemo() && // FIXME: We shouldn't need this here but for some reason the engine thinks a replay is recording during demo playback, even though replay_recording has a FCVAR_DONTRECORD flag |
|
!nDisplayedConnectedRecording && |
|
replay_replaywelcomedlgcount.GetInt() <= MAX_TIMES_TO_SHOW_REPLAY_WELCOME_DLG ) |
|
{ |
|
wchar_t wText[256]; |
|
wchar wKeyBind[80]; |
|
char szText[256]; |
|
|
|
const char *pSaveReplayKey = engine->Key_LookupBinding( "save_replay" ); |
|
if ( !pSaveReplayKey ) |
|
{ |
|
pSaveReplayKey = "< not bound >"; |
|
} |
|
g_pVGuiLocalize->ConvertANSIToUnicode( pSaveReplayKey, wKeyBind, sizeof( wKeyBind ) ); |
|
g_pVGuiLocalize->ConstructString_safe( wText, g_pVGuiLocalize->Find( "#Replay_ConnectRecording" ), 1, wKeyBind ); |
|
g_pVGuiLocalize->ConvertUnicodeToANSI( wText, szText, sizeof( szText ) ); |
|
|
|
extern ConVar replay_msgduration_connectrecording; |
|
g_pClientMode->DisplayReplayMessage( szText, replay_msgduration_connectrecording.GetFloat(), false, NULL, true ); |
|
|
|
// Don't execute this clause next time the player spawns, unless the cache has been cleared |
|
++nDisplayedConnectedRecording; |
|
|
|
// Increment (archives) |
|
replay_replaywelcomedlgcount.SetValue( replay_replaywelcomedlgcount.GetInt() + 1 ); |
|
} |
|
#endif |
|
|
|
// This will complete any pending replay, commit if necessary, and clear - this way when the player respawns |
|
// we will start with a fresh replay for the new life. |
|
g_pClientReplayContext->OnPlayerClassChanged(); |
|
|
|
// Change class |
|
BaseClass::OnCommand( CFmtStr( "joinclass %s", g_aRawPlayerClassNames[ iClass ] ).Access() ); |
|
|
|
CBroadcastRecipientFilter filter; |
|
|
|
if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) |
|
{ |
|
CBaseEntity::EmitSound( filter, SOUND_FROM_UI_PANEL, "music.mvm_class_select" ); |
|
} |
|
else |
|
{ |
|
|
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnCommand( const char *command ) |
|
{ |
|
if ( !V_strnicmp( command, "select", 6 ) ) |
|
{ |
|
const char *pClass = command + 6; |
|
const int iClass = atoi( pClass ); |
|
|
|
// Avoid restarting the animation if the user selected on the same class |
|
if ( iClass != m_iCurrentClassIndex ) |
|
{ |
|
SelectClass( iClass ); |
|
} |
|
else |
|
{ |
|
// Ensure selection states, in case the user clicks a button and drags away |
|
UpdateButtonSelectionStates( iClass ); |
|
} |
|
|
|
Go(); |
|
} |
|
else if ( !V_strnicmp( command, "resetclass", 10 ) ) |
|
{ |
|
if ( TFGameRules() && !TFGameRules()->IsInHighlanderMode() ) |
|
return; |
|
|
|
engine->ClientCmd( const_cast<char *>( command ) ); |
|
} |
|
else if ( !V_strnicmp( command, "openloadout", 11 ) ) |
|
{ |
|
// Let this panel know when you've closed, so we can reload items |
|
EconUI()->AddPanelCloseListener( this ); |
|
|
|
// Make the back button close, rather than go back to the econ root panel |
|
EconUI()->SetClosePanel( -m_iCurrentClassIndex ); |
|
|
|
// Set team number, so the model's color will match |
|
EconUI()->SetDefaultTeam( GetTeamNumber() ); |
|
|
|
// Go directly to the loadout for the selected class |
|
EconUI()->OpenEconUI( -m_iCurrentClassIndex ); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Console command to select a class |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::Join_Class( const CCommand &args ) |
|
{ |
|
if ( args.ArgC() > 1 ) |
|
{ |
|
char cmd[256]; |
|
Q_snprintf( cmd, sizeof( cmd ), "joinclass %s", args.Arg( 1 ) ); |
|
OnCommand( cmd ); |
|
ShowPanel( false ); |
|
} |
|
} |
|
|
|
static const char *g_sDialogVariables[] = { |
|
"", |
|
"numScout", |
|
"numSoldier", |
|
"numPyro", |
|
|
|
"numDemoman", |
|
"numHeavy", |
|
"numEngineer", |
|
|
|
"numMedic", |
|
"numSniper", |
|
"numSpy", |
|
"", |
|
}; |
|
|
|
static const char *g_sClassImagesBlue[] = { |
|
"", |
|
"class_sel_sm_scout_blu", |
|
"class_sel_sm_soldier_blu", |
|
"class_sel_sm_pyro_blu", |
|
|
|
"class_sel_sm_demo_blu", |
|
"class_sel_sm_heavy_blu", |
|
"class_sel_sm_engineer_blu", |
|
|
|
"class_sel_sm_medic_blu", |
|
"class_sel_sm_sniper_blu", |
|
"class_sel_sm_spy_blu", |
|
|
|
"class_sel_sm_scout_blu", |
|
}; |
|
|
|
static const char *g_sClassImagesRed[] = { |
|
"", |
|
"class_sel_sm_scout_red", |
|
"class_sel_sm_soldier_red", |
|
"class_sel_sm_pyro_red", |
|
|
|
"class_sel_sm_demo_red", |
|
"class_sel_sm_heavy_red", |
|
"class_sel_sm_engineer_red", |
|
|
|
"class_sel_sm_medic_red", |
|
"class_sel_sm_sniper_red", |
|
"class_sel_sm_spy_red", |
|
|
|
"class_sel_sm_scout_red", |
|
}; |
|
|
|
int g_ClassDefinesRemap[] = { |
|
0, |
|
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, |
|
TF_CLASS_CIVILIAN, |
|
}; |
|
|
|
void CTFClassMenu::UpdateNumClassLabels( int iTeam ) |
|
{ |
|
#ifndef _X360 |
|
int nTotalCount = 0; |
|
|
|
// count how many of each class there are |
|
if ( !g_TF_PR ) |
|
return; |
|
|
|
if ( iTeam < FIRST_GAME_TEAM || iTeam >= TF_TEAM_COUNT ) // invalid team number |
|
return; |
|
|
|
C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); |
|
|
|
bool bSpectator = pLocalPlayer && pLocalPlayer->GetTeamNumber() == TEAM_SPECTATOR; |
|
|
|
int iLocalPlayerClass = TF_CLASS_UNDEFINED; |
|
if ( pLocalPlayer ) |
|
{ |
|
iLocalPlayerClass = pLocalPlayer->m_Shared.GetDesiredPlayerClassIndex(); |
|
} |
|
|
|
if ( iLocalPlayerClass == TF_CLASS_UNDEFINED ) |
|
{ |
|
m_iLocalPlayerClass = iLocalPlayerClass; |
|
|
|
if ( m_pLocalPlayerImage && m_pLocalPlayerImage->IsVisible() ) |
|
{ |
|
m_pLocalPlayerImage->SetVisible( false ); |
|
} |
|
|
|
if ( m_pLocalPlayerBG && m_pLocalPlayerBG->IsVisible() ) |
|
{ |
|
m_pLocalPlayerBG->SetVisible( false ); |
|
} |
|
} |
|
|
|
for( int i = TF_FIRST_NORMAL_CLASS ; i <= TF_LAST_NORMAL_CLASS ; i++ ) |
|
{ |
|
if ( bSpectator == true ) |
|
{ |
|
SetDialogVariable( g_sDialogVariables[i], "" ); |
|
continue; |
|
} |
|
|
|
int classCount = g_TF_PR->GetCountForPlayerClass( iTeam, g_ClassDefinesRemap[i], false ); |
|
int iClassLimit = TFGameRules()->GetClassLimit( g_ClassDefinesRemap[i] ); |
|
|
|
if ( iClassLimit != NO_CLASS_LIMIT ) |
|
{ |
|
if ( classCount >= iClassLimit ) |
|
{ |
|
if ( classCount > 0 ) |
|
{ |
|
wchar_t wTemp[32]; |
|
wchar_t wzCount[10]; |
|
_snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", classCount ); |
|
g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("TF_ClassLimitHit"), 1, wzCount ); |
|
SetDialogVariable( g_sDialogVariables[i], wTemp ); |
|
} |
|
else |
|
{ |
|
SetDialogVariable( g_sDialogVariables[i], g_pVGuiLocalize->Find("TF_ClassLimitHit_None") ); |
|
} |
|
} |
|
else |
|
{ |
|
wchar_t wTemp[32]; |
|
wchar_t wzCount[10]; |
|
_snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", classCount ); |
|
wchar_t wzMax[10]; |
|
_snwprintf( wzMax, ARRAYSIZE( wzMax ), L"%d", iClassLimit ); |
|
g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("TF_ClassLimitUnder"), 2, wzCount, wzMax ); |
|
SetDialogVariable( g_sDialogVariables[i], wTemp ); |
|
} |
|
} |
|
else if ( classCount > 0 ) |
|
{ |
|
SetDialogVariable( g_sDialogVariables[i], classCount ); |
|
} |
|
else |
|
{ |
|
SetDialogVariable( g_sDialogVariables[i], "" ); |
|
} |
|
|
|
if ( g_ClassDefinesRemap[i] == iLocalPlayerClass ) |
|
{ |
|
// take 1 off the count for the images since the local player has their own image already |
|
if ( classCount > 0 ) |
|
{ |
|
classCount--; |
|
} |
|
|
|
if ( m_pLocalPlayerImage ) |
|
{ |
|
if ( !m_pLocalPlayerImage->IsVisible() ) |
|
{ |
|
m_pLocalPlayerImage->SetVisible( true ); |
|
} |
|
|
|
if ( m_iLocalPlayerClass != iLocalPlayerClass ) |
|
{ |
|
m_iLocalPlayerClass = iLocalPlayerClass; |
|
m_pLocalPlayerImage->SetImage( iTeam == TF_TEAM_BLUE ? g_sClassImagesBlue[i] : g_sClassImagesRed[i] ); |
|
} |
|
} |
|
|
|
if ( m_pLocalPlayerBG && !m_pLocalPlayerBG->IsVisible() ) |
|
{ |
|
m_pLocalPlayerBG->SetVisible( true ); |
|
} |
|
} |
|
|
|
if ( nTotalCount < CLASS_COUNT_IMAGES ) |
|
{ |
|
for ( int j = 0 ; j < classCount ; ++j ) |
|
{ |
|
CTFImagePanel *pImage = m_ClassCountImages[nTotalCount]; |
|
if ( pImage ) |
|
{ |
|
pImage->SetVisible( true ); |
|
pImage->SetImage( iTeam == TF_TEAM_BLUE ? g_sClassImagesBlue[i] : g_sClassImagesRed[i] ); |
|
} |
|
|
|
nTotalCount++; |
|
if ( nTotalCount >= CLASS_COUNT_IMAGES ) |
|
{ |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( nTotalCount == 0 ) |
|
{ |
|
// no classes for our team yet |
|
if ( m_pCountLabel && m_pCountLabel->IsVisible() ) |
|
{ |
|
m_pCountLabel->SetVisible( false ); |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_pCountLabel && !m_pCountLabel->IsVisible() ) |
|
{ |
|
m_pCountLabel->SetVisible( true ); |
|
} |
|
} |
|
|
|
// turn off any unused images |
|
while ( nTotalCount < CLASS_COUNT_IMAGES ) |
|
{ |
|
CTFImagePanel *pImage = m_ClassCountImages[nTotalCount]; |
|
if ( pImage ) |
|
{ |
|
pImage->SetVisible( false ); |
|
} |
|
|
|
nTotalCount++; |
|
} |
|
#endif |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::FireGameEvent( IGameEvent *event ) |
|
{ |
|
const char *pszEventName = event->GetName(); |
|
|
|
// when we are changing levels |
|
if ( FStrEq( pszEventName, "localplayer_changeteam" ) ) |
|
{ |
|
if ( IsVisible() ) |
|
{ |
|
C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); |
|
if ( pLocalPlayer ) |
|
{ |
|
int iTeam = pLocalPlayer->GetTeamNumber(); |
|
if ( iTeam != GetTeamNumber() ) |
|
{ |
|
ShowPanel( false ); |
|
|
|
if ( iTeam == TF_TEAM_BLUE ) |
|
{ |
|
gViewPortInterface->ShowPanel( PANEL_CLASS_BLUE, true ); |
|
} |
|
else |
|
{ |
|
gViewPortInterface->ShowPanel( PANEL_CLASS_RED, true ); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
else if ( FStrEq( pszEventName, "show_match_summary" ) ) |
|
{ |
|
if ( IsVisible() ) |
|
{ |
|
ShowPanel( false ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::OnEconUIClosed() |
|
{ |
|
// Reload items on model panel, in case anything's changed |
|
LoadItems(); |
|
} |
|
|
|
int g_nNumUpgradeIconsForLastHint = 0; |
|
|
|
//----------------------------------------------------------------------------- |
|
void CTFClassMenu::CheckMvMUpgrades() |
|
{ |
|
// Set MvM Icons invisible |
|
for ( int icons = 0; icons < ARRAYSIZE( m_pMvmUpgradeImages ); ++icons ) |
|
{ |
|
if ( m_pMvmUpgradeImages[icons] == NULL ) |
|
continue; |
|
m_pMvmUpgradeImages[icons]->SetVisible( false ); |
|
} |
|
|
|
if ( !TFGameRules() || !TFGameRules()->IsMannVsMachineMode() ) |
|
return; |
|
|
|
CMannVsMachineStats *pStats = MannVsMachineStats_GetInstance(); |
|
if ( !pStats ) |
|
return; |
|
|
|
CUtlVector< CUpgradeInfo > *upgrades = pStats->GetLocalPlayerUpgrades(); |
|
|
|
int nShowUpgradingHint = -1; |
|
int nNumUpgradeIconsForHint = 0; |
|
|
|
for ( int i = 0; i < upgrades->Count(); ++i ) |
|
{ |
|
vgui::Panel *pUpgradeImage = m_pMvmUpgradeImages[upgrades->Element(i).m_iPlayerClass]; |
|
|
|
if ( !pUpgradeImage ) |
|
continue; |
|
|
|
if ( !pUpgradeImage->IsVisible() ) |
|
{ |
|
pUpgradeImage->SetVisible( true ); |
|
nNumUpgradeIconsForHint++; |
|
|
|
// Only show the hint if we've shown it 3 or less times ever |
|
if ( nShowUpgradingHint == -1 && tf_mvm_classupgradehelpcount.GetInt() < 3 ) |
|
{ |
|
int nY; |
|
pUpgradeImage->GetPos( nShowUpgradingHint, nY ); |
|
nShowUpgradingHint += pUpgradeImage->GetWide() / 2; |
|
} |
|
} |
|
} |
|
|
|
// Only show the hint if there are more upgrade icon than the last time we openned the menu |
|
if ( nShowUpgradingHint != -1 && g_nNumUpgradeIconsForLastHint < nNumUpgradeIconsForHint ) |
|
{ |
|
CExplanationPopup *pPopup = dynamic_cast< CExplanationPopup* >( FindChildByName("StartExplanation") ); |
|
if ( pPopup ) |
|
{ |
|
pPopup->SetCalloutInParentsX( nShowUpgradingHint ); |
|
pPopup->Popup(); |
|
|
|
g_nNumUpgradeIconsForLastHint = nNumUpgradeIconsForHint; |
|
tf_mvm_classupgradehelpcount.SetValue( tf_mvm_classupgradehelpcount.GetInt() + 1 ); |
|
} |
|
} |
|
} |
|
|
|
|
|
|