diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/tf/vgui/tf_clientscoreboard.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/tf/vgui/tf_clientscoreboard.cpp')
| -rw-r--r-- | game/client/tf/vgui/tf_clientscoreboard.cpp | 2424 |
1 files changed, 2424 insertions, 0 deletions
diff --git a/game/client/tf/vgui/tf_clientscoreboard.cpp b/game/client/tf/vgui/tf_clientscoreboard.cpp new file mode 100644 index 0000000..2cbdfe0 --- /dev/null +++ b/game/client/tf/vgui/tf_clientscoreboard.cpp @@ -0,0 +1,2424 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include <tier1/fmtstr.h> +#include <vgui_controls/Label.h> +#include <vgui_controls/Button.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui_controls/RichText.h> +#include <vgui_controls/Frame.h> +#include <vgui/IScheme.h> +#include <vgui/ILocalize.h> +#include <vgui/ISurface.h> +#include <vgui/IVGui.h> +#include <vgui_controls/SectionedListPanel.h> +#include <vgui_controls/ImageList.h> +#include <game/client/iviewport.h> +#include <KeyValues.h> +#include <filesystem.h> +#include "IGameUIFuncs.h" // for key bindings +#include "VGuiMatSurface/IMatSystemSurface.h" + +#include "tf_controls.h" +#include "tf_shareddefs.h" +#include "tf_playermodelpanel.h" +#include "tf_clientscoreboard.h" +#include "c_playerresource.h" +#include "c_tf_playerresource.h" +#include "c_tf_team.h" +#include "c_tf_player.h" +#include "vgui_avatarimage.h" +#include "tf_gamerules.h" +#include "econ_item_description.h" +#include "vgui_controls/MenuItem.h" +#include "vgui/IInput.h" +#include "voice_status.h" +#include "vgui_controls/ScrollBarSlider.h" +#include "econ/econ_trading.h" +#include "in_buttons.h" +#include "tf_mapinfo.h" + +#if defined ( _X360 ) +#include "engine/imatchmaking.h" +#endif + +#if defined( REPLAY_ENABLED ) +#include "replay/ireplaysystem.h" +#include "replay/ienginereplay.h" +#endif + +#include "econ_item_system.h" +#include "tf_mann_vs_machine_stats.h" +#include "player_vs_environment/c_tf_upgrades.h" +#include "tf_badge_panel.h" +#include "report_player_dialog.h" + +using namespace vgui; + +#define SCOREBOARD_MAX_LIST_ENTRIES 12 + +ConVar tf_scoreboard_mouse_mode( "tf_scoreboard_mouse_mode", "0", FCVAR_ARCHIVE ); + + +void cc_scoreboard_convar_changed( IConVar *pConVar, const char *pOldString, float flOldValue ) +{ + CTFClientScoreBoardDialog *pScoreboard = dynamic_cast< CTFClientScoreBoardDialog *>( gViewPortInterface->FindPanelByName( PANEL_SCOREBOARD ) ); + if ( pScoreboard ) + { + pScoreboard->Reset(); + } +} +ConVar tf_scoreboard_ping_as_text( "tf_scoreboard_ping_as_text", "0", FCVAR_ARCHIVE, "Show ping values as text in the scoreboard.", cc_scoreboard_convar_changed ); +ConVar tf_scoreboard_alt_class_icons( "tf_scoreboard_alt_class_icons", "0", FCVAR_ARCHIVE, "Show alternate class icons in the scoreboard." ); + +extern bool IsInCommentaryMode( void ); +extern bool DuelMiniGame_GetStats( C_TFPlayer **ppPlayer, uint32 &unMyScore, uint32 &unOpponentScore ); +extern void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); + +extern ConVar cl_hud_playerclass_use_playermodel; +extern ConVar mp_tournament; + +//...................................................... +enum +{ + PING_LOW, + PING_MED, + PING_HIGH, + PING_VERY_HIGH, + PING_BOT_RED, + PING_BOT_BLUE, + + PING_MAX_TYPES +}; +static const char *pszPingIcons[SCOREBOARD_PING_ICONS] = { + "../hud/scoreboard_ping_low", + "../hud/scoreboard_ping_med", + "../hud/scoreboard_ping_high", + "../hud/scoreboard_ping_very_high", + "../hud/scoreboard_ping_bot_red", + "../hud/scoreboard_ping_bot_blue", +}; +static const char *pszPingIconsDead[SCOREBOARD_PING_ICONS] = { + "../hud/scoreboard_ping_low_d", + "../hud/scoreboard_ping_med_d", + "../hud/scoreboard_ping_high_d", + "../hud/scoreboard_ping_very_high_d", + "../hud/scoreboard_ping_bot_red_d", + "../hud/scoreboard_ping_bot_blue_d", +}; +COMPILE_TIME_ASSERT( SCOREBOARD_PING_ICONS == PING_MAX_TYPES ); +//...................................................... + +static const char *pszDominationIcons[SCOREBOARD_DOMINATION_ICONS] = { + "", + "../hud/leaderboard_dom1", + "../hud/leaderboard_dom2", + "../hud/leaderboard_dom3", + "../hud/leaderboard_dom4", + "../hud/leaderboard_dom5", + "../hud/leaderboard_dom6", + "../hud/leaderboard_dom7", + "../hud/leaderboard_dom8", + "../hud/leaderboard_dom9", + "../hud/leaderboard_dom10", + "../hud/leaderboard_dom11", + "../hud/leaderboard_dom12", + "../hud/leaderboard_dom13", + "../hud/leaderboard_dom14", + "../hud/leaderboard_dom15", + "../hud/leaderboard_dom16", +}; + +static const char *pszDominationIconsDead[SCOREBOARD_DOMINATION_ICONS] = { + "", + "../hud/leaderboard_dom1_d", + "../hud/leaderboard_dom2_d", + "../hud/leaderboard_dom3_d", + "../hud/leaderboard_dom4_d", + "../hud/leaderboard_dom5_d", + "../hud/leaderboard_dom6_d", + "../hud/leaderboard_dom7_d", + "../hud/leaderboard_dom8_d", + "../hud/leaderboard_dom9_d", + "../hud/leaderboard_dom10_d", + "../hud/leaderboard_dom11_d", + "../hud/leaderboard_dom12_d", + "../hud/leaderboard_dom13_d", + "../hud/leaderboard_dom14_d", + "../hud/leaderboard_dom15_d", + "../hud/leaderboard_dom16_d", +}; + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CTFClientScoreBoardDialog::CTFClientScoreBoardDialog( IViewPort *pViewPort ) : CClientScoreBoardDialog( pViewPort ) +{ + SetProportional( true ); + SetKeyBoardInputEnabled( false ); + SetScheme( "ClientScheme" ); + + m_pPlayerListBlue = new SectionedListPanel( this, "BluePlayerList" ); + m_pPlayerListRed = new SectionedListPanel( this, "RedPlayerList" ); + m_pLabelPlayerName = new CExLabel( this, "PlayerNameLabel", "" ); + m_pImagePanelHorizLine = new ImagePanel( this, "HorizontalLine" ); + m_pClassImage = new CTFClassImage( this, "ClassImage" ); + m_pPlayerModelPanel = new CTFPlayerModelPanel( this, "classmodelpanel" ); + m_pLocalPlayerStatsPanel = new vgui::EditablePanel( this, "LocalPlayerStatsPanel" ); + m_pLocalPlayerDuelStatsPanel = new vgui::EditablePanel( this, "LocalPlayerDuelStatsPanel" ); + m_duelPanelLocalPlayer.m_pPanel = new vgui::EditablePanel( m_pLocalPlayerDuelStatsPanel, "LocalPlayerData" ); + m_duelPanelOpponent.m_pPanel = new vgui::EditablePanel( m_pLocalPlayerDuelStatsPanel, "OpponentData" ); + m_pRedTeamName = new CExLabel( this, "RedTeamLabel", "" ); + m_pBlueTeamName = new CExLabel( this, "BlueTeamLabel", "" ); + m_pRedLeaderAvatarImage = new CAvatarImagePanel( this, "RedLeaderAvatar" ); + m_pRedLeaderAvatarBG = new EditablePanel( this, "RedLeaderAvatarBG" ); + m_pRedTeamImage = new ImagePanel( this, "RedTeamImage" ); + m_pBlueLeaderAvatarImage = new CAvatarImagePanel( this, "BlueLeaderAvatar" ); + m_pBlueLeaderAvatarBG = new EditablePanel( this, "BlueLeaderAvatarBG" ); + m_pBlueTeamImage = new ImagePanel( this, "BlueTeamImage" ); + + m_pServerTimeLeftValue = NULL; + m_pFontTimeLeftNumbers = vgui::INVALID_FONT; + m_pFontTimeLeftString = vgui::INVALID_FONT; + + m_pMvMScoreboard = new CTFHudMannVsMachineScoreboard( this, "MvMScoreboard" ); + m_pRightClickMenu = NULL; + + m_iImageDominated = 0; + m_iImageDominatedDead = 0; + m_iImageNemesis = 0; + m_iImageNemesisDead = 0; + m_iImageStreak = 0; + m_iImageStreakDead = 0; + m_iTextureCamera = -1; + + m_bIsPVEMode = false; +// m_bDisplayLevel = false; + m_bMouseActivated = true; + + Q_memset( m_iImageClass, NULL, sizeof( m_iImageClass ) ); + Q_memset( m_iImageClassAlt, NULL, sizeof( m_iImageClassAlt ) ); + Q_memset( m_iImageDom, NULL, sizeof( m_iImageDom ) ); + Q_memset( m_iImageDomDead, NULL, sizeof( m_iImageDomDead ) ); + + ListenForGameEvent( "server_spawn" ); +#ifdef STAGING_ONLY +// ListenForGameEvent( "bountymode_toggled" ); +#endif + + SetDialogVariable( "server", "" ); + SetVisible( false ); + + m_nPlayerModelPanelIndex = -1; + m_bRedScrollBarVisible = false; + m_bBlueScrollBarVisible = false; + m_nExtraSpace = 0; + m_hSelectedPlayer = NULL; + m_bUsePlayerModel = false; +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CTFClientScoreBoardDialog::~CTFClientScoreBoardDialog() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::PerformLayout() +{ + BaseClass::PerformLayout(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdatePlayerModel() +{ + if ( !m_pPlayerModelPanel->IsVisible() ) + return; + + if ( m_nPlayerModelPanelIndex == -1 ) + { + m_nPlayerModelPanelIndex = GetLocalPlayerIndex(); + } + + C_TFPlayer *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( m_nPlayerModelPanelIndex ) ); + if ( !pPlayer ) + return; + + int nClass = pPlayer->GetPlayerClass()->GetClassIndex(); + int nTeam = pPlayer->GetTeamNumber(); + int nItemSlot = ( pPlayer->IsAlive() && pPlayer->GetActiveTFWeapon() ) ? pPlayer->GetActiveTFWeapon()->GetAttributeContainer()->GetItem()->GetStaticData()->GetLoadoutSlot( nClass ) : LOADOUT_POSITION_PRIMARY;; + CEconItemView *pWeapon = NULL; + + CTFWeaponBase *pEnt = dynamic_cast<CTFWeaponBase*>( pPlayer->GetEntityForLoadoutSlot( nItemSlot ) ); + if ( pEnt ) + { + pWeapon = pEnt->GetAttributeContainer()->GetItem(); + } + + bool bIsRobot = false; + int iRobot = 0; + CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iRobot, appear_as_mvm_robot ); + bIsRobot = iRobot ? true : false; + + m_pPlayerModelPanel->ClearCarriedItems(); + m_pPlayerModelPanel->SetToPlayerClass( nClass, bIsRobot ); + m_pPlayerModelPanel->SetTeam( nTeam ); + + if ( pWeapon ) + { + m_pPlayerModelPanel->AddCarriedItem( pWeapon ); + } + + for ( int wbl = pPlayer->GetNumWearables() - 1; wbl >= 0; wbl-- ) + { + C_TFWearable *pItem = dynamic_cast<C_TFWearable*>( pPlayer->GetWearable( wbl ) ); + if ( !pItem ) + continue; + + if ( pItem->IsViewModelWearable() ) + continue; + + if ( pItem->IsDisguiseWearable() ) + continue; + + CAttributeContainer *pCont = pItem->GetAttributeContainer(); + CEconItemView *pEconItemView = pCont ? pCont->GetItem() : NULL; + + if ( pEconItemView && pEconItemView->IsValid() ) + { + m_pPlayerModelPanel->AddCarriedItem( pEconItemView ); + } + } + + m_pPlayerModelPanel->HoldItemInSlot( nItemSlot ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + + if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) + { + pConditions = new KeyValues( "conditions" ); + AddSubKeyNamed( pConditions, "if_mvm" ); + } + + LoadControlSettings( "Resource/UI/Scoreboard.res", NULL, NULL, pConditions ); + m_hScoreFontDefault = pScheme->GetFont( "Default", true ); + m_hScoreFontSmallest = pScheme->GetFont( "ScoreboardSmallest", true ); + + if ( pConditions ) + { + pConditions->deleteThis(); + } + + if ( m_pImageList ) + { + m_iImageDominated = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dominated", true ) ); + m_iImageDominatedDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_dominated_d", true ) ); + m_iImageNemesis = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_nemesis", true ) ); + m_iImageNemesisDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/leaderboard_nemesis_d", true ) ); + m_iImageStreak = m_pImageList->AddImage( scheme()->GetImage( "../hud/scoreboard_streak", true ) ); + m_iImageStreakDead = m_pImageList->AddImage( scheme()->GetImage( "../hud/scoreboard_streak_d", true ) ); + + for(int i = 1 ; i < SCOREBOARD_DOMINATION_ICONS ; i++) + { + m_iImageDom[i] = m_pImageList->AddImage( scheme()->GetImage( pszDominationIcons[i], true ) ); + m_iImageDomDead[i] = m_pImageList->AddImage( scheme()->GetImage( pszDominationIconsDead[i], true ) ); + } + for( int i = 1 ; i < SCOREBOARD_CLASS_ICONS ; i++ ) + { + m_iImageClass[i] = m_pImageList->AddImage( scheme()->GetImage( g_pszClassIcons[i], true ) ); + m_iImageClassAlt[i] = m_pImageList->AddImage( scheme()->GetImage( g_pszClassIconsAlt[i], true ) ); + } + for ( int i = 0; i < SCOREBOARD_PING_ICONS; i++ ) + { + m_iImagePing[i] = m_pImageList->AddImage( scheme()->GetImage( pszPingIcons[i], true ) ); + m_iImagePingDead[i] = m_pImageList->AddImage( scheme()->GetImage( pszPingIconsDead[i], true ) ); + } + + // resize the images to our resolution + for (int i = 1 ; i < m_pImageList->GetImageCount(); i++ ) + { + int wide = 13, tall = 13; + m_pImageList->GetImage(i)->SetSize(scheme()->GetProportionalScaledValueEx( GetScheme(), wide ), scheme()->GetProportionalScaledValueEx( GetScheme(),tall ) ); + } + } + + SetPlayerListImages( m_pPlayerListBlue ); + SetPlayerListImages( m_pPlayerListRed ); + + SetBgColor( Color( 0, 0, 0, 0) ); + SetBorder( NULL ); + SetVisible( false ); + + m_duelPanelLocalPlayer.m_pAvatar = dynamic_cast< CAvatarImagePanel *>( m_duelPanelLocalPlayer.m_pPanel->FindChildByName("AvatarImage") ); + m_duelPanelLocalPlayer.m_pPlayerNameLabel = dynamic_cast< CExLabel *>( m_duelPanelLocalPlayer.m_pPanel->FindChildByName("AvatarTextLabel") ); + m_duelPanelOpponent.m_pAvatar = dynamic_cast< CAvatarImagePanel *>( m_duelPanelOpponent.m_pPanel->FindChildByName("AvatarImage") ); + m_duelPanelOpponent.m_pPlayerNameLabel = dynamic_cast< CExLabel *>( m_duelPanelOpponent.m_pPanel->FindChildByName("AvatarTextLabel") ); + + if ( m_pLocalPlayerStatsPanel ) + { + m_pKillsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Kills" ) ); + m_pDeathsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Deaths" ) ); + m_pAssistLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Assists" ) ); + m_pDestructionLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Destruction" ) ); + m_pCapturesLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Captures" ) ); + m_pDefensesLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Defenses" ) ); + m_pDominationsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Domination" ) ); + m_pRevengeLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Revenge" ) ); + m_pHealingLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Healing" ) ); + m_pInvulnsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Invuln" ) ); + m_pTeleportsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Teleports" ) ); + m_pHeadshotsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Headshots" ) ); + m_pBackstabsLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Backstabs" ) ); + m_pBonusLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Bonus" ) ); + m_pSupportLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Support" ) ); + m_pDamageLabel = dynamic_cast< CExLabel* >( m_pLocalPlayerStatsPanel->FindChildByName( "Damage" ) ); + } + + m_pServerTimeLeftValue = dynamic_cast< CExLabel* >( FindChildByName( "ServerTimeLeftValue" ) ); + m_pFontTimeLeftNumbers = pScheme->GetFont( "ScoreboardMediumSmall", true ); + m_pFontTimeLeftString = pScheme->GetFont( "ScoreboardVerySmall", true ); + + Reset(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::ShowPanel( bool bShow ) +{ + if ( bShow ) + { + if ( TFGameRules() && TFGameRules()->ShowMatchSummary() ) + return; + } + + // Catch the case where we call ShowPanel before ApplySchemeSettings, eg when + // going from windowed <-> fullscreen + if ( m_pImageList == NULL ) + { + InvalidateLayout( true, true ); + } + + bool bIsPVEMode = TFGameRules() && TFGameRules()->IsPVEModeActive(); + if ( m_bIsPVEMode != bIsPVEMode ) + { + m_bIsPVEMode = bIsPVEMode; + InvalidateLayout( true, true ); + } + + // Don't show in commentary mode + if ( IsInCommentaryMode() ) + { + bShow = false; + } + + if ( IsVisible() == bShow ) + { + return; + } + + int iRenderGroup = gHUD.LookupRenderGroupIndexByName( "global" ); + + if ( bShow ) + { + SetVisible( true ); + MoveToFront(); + InitializeInputScheme(); + + gHUD.LockRenderGroup( iRenderGroup ); + + // Clear the selected item, this forces the default to the local player + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + pList->ClearSelection(); + } + + if ( tf_scoreboard_mouse_mode.GetInt() == 2 ) + m_bMouseActivated = false; + + UpdateServerTimeLeft(); + + m_nPlayerModelPanelIndex = -1; + m_hSelectedPlayer = NULL; + UpdatePlayerModel(); + } + else + { + SetVisible( false ); + + if ( m_pRightClickMenu ) + { + delete m_pRightClickMenu; + m_pRightClickMenu = NULL; + } + + gHUD.UnlockRenderGroup( iRenderGroup ); + m_bMouseActivated = false; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::OnCommand( const char *command ) +{ + if ( V_stristr( command, "report_player" ) ) + { + engine->ClientCmd( command ); + } + else if ( !V_strcmp( command, "muteplayer" ) ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + if ( playerIndex > 0 && playerIndex <= MAX_PLAYERS && GetClientVoiceMgr() ) + { + // Toggle + GetClientVoiceMgr()->SetPlayerBlockedState( playerIndex, ( GetClientVoiceMgr()->IsPlayerBlocked( playerIndex ) ? false : true ) ); + } + } + } + } + else if ( !V_strcmp( command, "specplayer" ) ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + if ( playerIndex > 0 && playerIndex <= MAX_PLAYERS ) + { + engine->ClientCmd_Unrestricted( VarArgs( "spec_player %d\n", playerIndex ) ); + } + } + } + } + else if ( !V_strcmp( command, "friendadd" ) ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + CBasePlayer *pTarget = UTIL_PlayerByIndex( playerIndex ); + if ( pTarget && !( pTarget->IsBot() || pTarget->IsHLTV() ) ) + { + CSteamID steamID; + if ( pTarget->GetSteamID( &steamID ) && steamapicontext && steamapicontext->SteamFriends() ) + { + steamapicontext->SteamFriends()->ActivateGameOverlayToUser( "friendadd", steamID ); + } + } + } + } + } + else if ( !V_strcmp( command, "jointrade" ) ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + CBasePlayer *pTarget = UTIL_PlayerByIndex( playerIndex ); + if ( pTarget && !( pTarget->IsBot() || pTarget->IsHLTV() ) ) + { + // Prevent large UI popup during a match + if ( pTarget->GetTeamNumber() >= FIRST_GAME_TEAM ) + { + if ( TFGameRules() && TFGameRules()->UsePlayerReadyStatusMode() && TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ) + return; + } + + Trading_RequestTrade( playerIndex ); + } + } + } + } + else if ( !V_strcmp( command, "profile" ) ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + CBasePlayer *pTarget = UTIL_PlayerByIndex( playerIndex ); + if ( pTarget && !( pTarget->IsBot() || pTarget->IsHLTV() ) ) + { + CSteamID steamID; + if ( pTarget->GetSteamID( &steamID ) && steamapicontext && steamapicontext->SteamFriends() ) + { + steamapicontext->SteamFriends()->ActivateGameOverlayToUser( "steamid", steamID ); + } + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::OnItemSelected( vgui::Panel *panel ) +{ + if ( panel == m_pPlayerListBlue || panel == m_pPlayerListRed ) + { + // There can be only one... selection + if ( panel == m_pPlayerListBlue && m_pPlayerListBlue->GetSelectedItem() >= 0 && m_pPlayerListRed->GetSelectedItem() >= 0 ) + { + m_pPlayerListRed->ClearSelection(); + } + else if ( panel == m_pPlayerListRed && m_pPlayerListRed->GetSelectedItem() >= 0 && m_pPlayerListBlue->GetSelectedItem() >= 0 ) + { + m_pPlayerListBlue->ClearSelection(); + } + + if ( vgui::input()->IsMouseDown( MOUSE_RIGHT ) ) + { + OnScoreBoardMouseRightRelease(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::OnItemContextMenu( vgui::Panel *panel ) +{ + if ( panel == m_pPlayerListBlue || panel == m_pPlayerListRed ) + { + if ( vgui::input()->IsMouseDown( MOUSE_RIGHT ) ) + { + OnScoreBoardMouseRightRelease(); + } + } +} + +void CTFClientScoreBoardDialog::OnReportPlayer( KeyValues *pData ) +{ + int playerIndex = pData->GetInt( "playerIndex" ); + int nReason = pData->GetInt( "reason" ); + CSteamID steamID = GetSteamIDForPlayerIndex( playerIndex ); + ReportPlayerAccount( steamID, nReason ); +} + +//----------------------------------------------------------------------------- +// Purpose: Figure out where to put the camera view +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::GetCameraUnderlayBounds( int *pX, int *pY, int *pWide, int *pTall ) +{ + GetBounds( *pX, *pY, *pWide, *pTall ); + + // inset these b*pY a bit + *pX += 15; + *pY += 25; + *pWide -= 30; + *pTall -= 40; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::OnScoreBoardMouseRightRelease( void ) +{ + if ( !IsVisible() ) + return; + + C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalTFPlayer ) + return; + + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( !pList ) + return; + + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem < 0 ) + return; + + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( !pIssueKeyValues ) + return; + + int playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + if ( GetLocalPlayerIndex() == playerIndex ) + return; + + if ( m_pRightClickMenu ) + delete m_pRightClickMenu; + + const char *pszContextMenuBorder = "DarkComboBoxBorder"; + const char *pszContextMenuFont = "HudFontMediumSecondary"; + m_pRightClickMenu = new Menu( pList, "RightClickMenu" ); + m_pRightClickMenu->SetKeyBoardInputEnabled( false ); + m_pRightClickMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) ); + m_pRightClickMenu->SetFgColor( Color( 0, 0, 255, 255 ) ); + m_pRightClickMenu->SetPaintBackgroundEnabled( true ); + m_pRightClickMenu->SetPaintBackgroundType( 0 ); + m_pRightClickMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) ); + + bool bFakeClient = ( g_TF_PR->IsFakePlayer( playerIndex ) ); + bool bTournamentGame = ( g_TF_PR->GetTeam( playerIndex ) >= FIRST_GAME_TEAM && TFGameRules() && TFGameRules()->UsePlayerReadyStatusMode() && TFGameRules()->State_Get() == GR_STATE_RND_RUNNING ); + + MenuBuilder contextMenuBuilder( m_pRightClickMenu, this ); + + // Report + if ( !bFakeClient && engine->GetLocalPlayer() != playerIndex ) + { + Menu *pReportSubMenu = new Menu( this, "ReportSubMenu" ); + pReportSubMenu->SetBorder( scheme()->GetIScheme( GetScheme() )->GetBorder( pszContextMenuBorder ) ); + pReportSubMenu->SetFont( scheme()->GetIScheme( GetScheme() )->GetFont( pszContextMenuFont ) ); + contextMenuBuilder.AddCascadingMenuItem( "#TF_ScoreBoard_Context_Report", pReportSubMenu, "report" ); + for ( int iReason=CMsgGC_ReportPlayer_EReason_kReason_INVALID+1; iReason<CMsgGC_ReportPlayer_EReason_kReason_COUNT; ++iReason ) + { + CFmtStr name( "#TF_ScoreBoard_Context_Report_Reason%d", iReason ); + KeyValues *pReport = new KeyValues( "ReportPlayer" ); + pReport->SetInt( "playerIndex", playerIndex ); + pReport->SetInt( "reason", iReason ); + pReportSubMenu->AddMenuItem( name, pReport, this ); + } + } + + // Mute + if ( !bFakeClient && GetClientVoiceMgr() ) + { + const char *pszString = GetClientVoiceMgr()->IsPlayerBlocked( playerIndex ) ? "#TF_ScoreBoard_Context_UnMute" : "#TF_ScoreBoard_Context_Mute"; + contextMenuBuilder.AddMenuItem( pszString, "muteplayer", "mute" ); + } + + // Spectate + if ( g_TF_PR->IsAlive( playerIndex ) && ( !pLocalTFPlayer->IsAlive() || pLocalTFPlayer->GetTeamNumber() == TEAM_SPECTATOR ) ) + { + contextMenuBuilder.AddMenuItem( "#TF_ScoreBoard_Context_Spec", "specplayer", "spectate" ); + } + + // Add Friend + if ( !bFakeClient ) + { + CSteamID steamID; + C_TFPlayer *pTFTarget = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) ); + if ( pTFTarget && pTFTarget->GetSteamID( &steamID ) ) + { + if ( steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamFriends()->GetFriendRelationship( steamID ) == k_EFriendRelationshipNone ) + { + contextMenuBuilder.AddMenuItem( "#TF_ScoreBoard_Context_Friend", "friendadd", "friend" ); + } + } + } + + // Trade + if ( !bFakeClient && !bTournamentGame ) + { + contextMenuBuilder.AddMenuItem( "#TF_ScoreBoard_Context_Trade", "jointrade", "trade" ); + } + + // Profile + if ( !bFakeClient ) + { + contextMenuBuilder.AddMenuItem( "#TF_ScoreBoard_Context_Profile", "profile", "profile" ); + } + + int x, y; + vgui::input()->GetCursorPosition( x, y ); + m_pRightClickMenu->SetPos( x, y ); + m_pRightClickMenu->SetVisible( true ); + m_pRightClickMenu->AddActionSignalTarget( this ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFClientScoreBoardDialog::UseMouseMode( void ) +{ + return tf_scoreboard_mouse_mode.GetInt() == 1 || ( tf_scoreboard_mouse_mode.GetInt() == 2 && m_bMouseActivated ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::InitializeInputScheme( void ) +{ + if ( !IsVisible() ) + return; + + if ( !m_pPlayerListBlue || !m_pPlayerListRed ) + return; + + MakePopup( false, UseMouseMode() ); + SetKeyBoardInputEnabled( false ); + SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListBlue->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListBlue->AddActionSignalTarget( this ); + m_pPlayerListBlue->SetClickable( UseMouseMode() ); + m_pPlayerListRed->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListRed->AddActionSignalTarget( this ); + m_pPlayerListRed->SetClickable( UseMouseMode() ); + + if ( m_pPlayerListBlue->GetScrollBar() && + m_pPlayerListBlue->GetScrollBar()->GetButton( 0 ) && + m_pPlayerListBlue->GetScrollBar()->GetButton( 1 ) && + m_pPlayerListBlue->GetScrollBar()->GetSlider() ) + { + m_pPlayerListBlue->SetVerticalScrollbar( UseMouseMode() ); + m_pPlayerListBlue->GetScrollBar()->GetButton( 0 )->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListBlue->GetScrollBar()->GetButton( 1 )->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListBlue->GetScrollBar()->GetSlider()->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListBlue->GetScrollBar()->SetMouseInputEnabled( UseMouseMode() ); + } + + if ( m_pPlayerListRed->GetScrollBar() && + m_pPlayerListRed->GetScrollBar()->GetButton( 0 ) && + m_pPlayerListRed->GetScrollBar()->GetButton( 1 ) && + m_pPlayerListRed->GetScrollBar()->GetSlider() ) + { + m_pPlayerListRed->SetVerticalScrollbar( UseMouseMode() ); + m_pPlayerListRed->GetScrollBar()->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListRed->GetScrollBar()->GetButton( 0 )->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListRed->GetScrollBar()->GetButton( 1 )->SetMouseInputEnabled( UseMouseMode() ); + m_pPlayerListRed->GetScrollBar()->GetSlider()->SetMouseInputEnabled( UseMouseMode() ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Resets the scoreboard panel +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::Reset() +{ + if ( !m_bIsPVEMode ) + { + InitPlayerList( m_pPlayerListBlue ); + InitPlayerList( m_pPlayerListRed ); + } + + m_pPlayerListBlue->SetVisible( !m_bIsPVEMode ); + m_pPlayerListRed->SetVisible( !m_bIsPVEMode ); +} + +//----------------------------------------------------------------------------- +// Purpose: Inits the player list in a list panel +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::InitPlayerList( SectionedListPanel *pPlayerList ) +{ + pPlayerList->SetVerticalScrollbar( UseMouseMode() ); + pPlayerList->RemoveAll(); + pPlayerList->RemoveAllSections(); + pPlayerList->AddSection( 0, "Players", TFPlayerSortFunc ); + pPlayerList->SetSectionAlwaysVisible( 0, true ); + pPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) ); + pPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) ); + pPlayerList->SetBorder( NULL ); + + pPlayerList->AddColumnToSection( 0, "medal", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iMedalWidth ); + + // Avatars are always displayed at 32x32 regardless of resolution + if ( ShowAvatars() ) + { + pPlayerList->AddColumnToSection( 0, "avatar", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iAvatarWidth ); + pPlayerList->AddColumnToSection( 0, "spacer", "", 0, m_iSpacerWidth ); + } + + // the player avatar is always a fixed size, so as we change resolutions we need to vary the size of the name column to adjust the total width of all the columns + m_nExtraSpace = pPlayerList->GetWide() - m_iMedalWidth - m_iAvatarWidth - m_iSpacerWidth - m_iNameWidth - m_iKillstreakWidth - m_iKillstreakImageWidth - m_iNemesisWidth - m_iNemesisWidth - m_iScoreWidth - m_iClassWidth - m_iPingWidth - m_iSpacerWidth - ( 2 * SectionedListPanel::COLUMN_DATA_INDENT ); // the SectionedListPanel will indent the columns on either end by SectionedListPanel::COLUMN_DATA_INDENT + + pPlayerList->AddColumnToSection( 0, "name", "#TF_Scoreboard_Name", 0, m_iNameWidth + m_nExtraSpace ); + pPlayerList->AddColumnToSection( 0, "killstreak", "", SectionedListPanel::COLUMN_RIGHT, m_iKillstreakWidth ); + pPlayerList->AddColumnToSection( 0, "killstreak_image", "", SectionedListPanel::COLUMN_IMAGE, m_iKillstreakImageWidth ); + pPlayerList->AddColumnToSection( 0, "dominating", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iNemesisWidth ); + pPlayerList->AddColumnToSection( 0, "nemesis", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_CENTER, m_iNemesisWidth ); + pPlayerList->AddColumnToSection( 0, "score", "#TF_Scoreboard_Score", SectionedListPanel::COLUMN_RIGHT, m_iScoreWidth ); + pPlayerList->AddColumnToSection( 0, "class", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iClassWidth ); + + if ( tf_scoreboard_ping_as_text.GetBool() ) + { + pPlayerList->AddColumnToSection( 0, "ping", "#TF_Scoreboard_Ping", SectionedListPanel::COLUMN_RIGHT, m_iPingWidth ); + } + else + { + pPlayerList->AddColumnToSection( 0, "ping", "", SectionedListPanel::COLUMN_IMAGE | SectionedListPanel::COLUMN_RIGHT, m_iPingWidth ); + } +#ifdef STAGING_ONLY +// if ( m_bDisplayLevel ) +// { +// pPlayerList->AddColumnToSection( 0, "level", "#TF_ScoreBoard_LevelLabel", SectionedListPanel::COLUMN_RIGHT, m_iPingWidth ); +// } +#endif // STAGING_ONLY +} + +//----------------------------------------------------------------------------- +// Purpose: Builds the image list to use in the player list +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::SetPlayerListImages( vgui::SectionedListPanel *pPlayerList ) +{ + pPlayerList->SetImageList( m_pImageList, false ); + pPlayerList->SetVisible( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the dialog +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::Update() +{ + // MvM + if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) + { + m_pMvMScoreboard->OnTick(); + } + + UpdateTeamInfo(); + UpdatePlayerList(); + UpdateSpectatorList(); + UpdateArenaWaitingToPlayList(); + UpdatePlayerDetails(); + MoveToCenterOfScreen(); + UpdateServerTimeLeft(); + AdjustForVisibleScrollbar(); + UpdateBadgePanels( m_pRedBadgePanels, m_pPlayerListRed ); + UpdateBadgePanels( m_pBlueBadgePanels, m_pPlayerListBlue ); + + float flNextUpdate = 1.0f; + if ( UseMouseMode() ) + { + if ( ( m_pPlayerListRed && m_pPlayerListRed->GetScrollBar() && m_pPlayerListRed->GetScrollBar()->IsVisible() ) || + ( m_pPlayerListBlue && m_pPlayerListBlue->GetScrollBar() && m_pPlayerListBlue->GetScrollBar()->IsVisible() ) ) + { + // we need a much faster update rate for MouseMode() so the MedalList can update when the scrollbar is quickly moved + // we're listening for the ScrollBarSliderMoved message but it still doesn't keep up with dragging the mouse around + flNextUpdate = 0.02f; + } + else + { + flNextUpdate = 0.15f; + } + } + + m_fNextUpdateTime = gpGlobals->curtime + flNextUpdate; +} + +//----------------------------------------------------------------------------- +// Purpose: Updates information about teams +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdateTeamInfo() +{ + // update the team sections in the scoreboard + for ( int teamIndex = TF_TEAM_RED; teamIndex <= TF_TEAM_BLUE; teamIndex++ ) + { + C_TFTeam *team = GetGlobalTFTeam( teamIndex ); + if ( team ) + { + // choose dialog variables to set depending on team + const char *pDialogVarTeamScore = ""; + const char *pDialogVarTeamPlayerCount = ""; + const char *pDialogVarTeamName = ""; + + switch ( teamIndex ) + { + case TF_TEAM_RED: + pDialogVarTeamScore = "redteamscore"; + pDialogVarTeamPlayerCount = "redteamplayercount"; + pDialogVarTeamName = "redteamname"; + break; + case TF_TEAM_BLUE: + pDialogVarTeamScore = "blueteamscore"; + pDialogVarTeamPlayerCount = "blueteamplayercount"; + pDialogVarTeamName = "blueteamname"; + break; + default: + Assert( false ); + break; + } + + // update # of players on each team + wchar_t string1[1024]; + wchar_t wNumPlayers[6]; + _snwprintf( wNumPlayers, ARRAYSIZE( wNumPlayers ), L"%i", team->Get_Number_Players() ); + if ( team->Get_Number_Players() == 1 ) + { + g_pVGuiLocalize->ConstructString_safe( string1, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Player" ), 1, wNumPlayers ); + } + else + { + g_pVGuiLocalize->ConstructString_safe( string1, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Players" ), 1, wNumPlayers ); + } + + // set # of players for team in dialog + SetDialogVariable( pDialogVarTeamPlayerCount, string1 ); + + // set team score in dialog + SetDialogVariable( pDialogVarTeamScore, team->Get_Score() ); + + // set the team name + SetDialogVariable( pDialogVarTeamName, team->Get_Localized_Name() ); + } + } + + bool bMvM = TFGameRules() && TFGameRules()->IsMannVsMachineMode(); + bool bTournament = mp_tournament.GetBool() && !bMvM; + if ( m_pRedTeamName->IsVisible() != bTournament ) + { + m_pRedTeamName->SetVisible( bTournament ); + } + + if ( m_pBlueTeamName->IsVisible() != bTournament ) + { + m_pBlueTeamName->SetVisible( bTournament ); + } + + bool bShowAvatars = g_TF_PR && g_TF_PR->HasPremadeParties(); + if ( bShowAvatars ) + { + m_pRedLeaderAvatarImage->SetPlayer( GetSteamIDForPlayerIndex( g_TF_PR->GetPartyLeaderRedTeamIndex() ), k_EAvatarSize64x64 ); + m_pRedLeaderAvatarImage->SetShouldDrawFriendIcon( false ); + m_pBlueLeaderAvatarImage->SetPlayer( GetSteamIDForPlayerIndex( g_TF_PR->GetPartyLeaderBlueTeamIndex() ), k_EAvatarSize64x64 ); + m_pBlueLeaderAvatarImage->SetShouldDrawFriendIcon( false ); + } + + m_pRedLeaderAvatarImage->SetVisible( bShowAvatars ); + m_pRedLeaderAvatarBG->SetVisible( bShowAvatars ); + m_pRedTeamImage->SetVisible( !bShowAvatars && !bMvM ); + + m_pBlueLeaderAvatarImage->SetVisible( bShowAvatars ); + m_pBlueLeaderAvatarBG->SetVisible( bShowAvatars ); + m_pBlueTeamImage->SetVisible( !bShowAvatars && !bMvM ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool AreEnemyTeams( int iTeam1, int iTeam2 ) +{ + if ( iTeam1 == TF_TEAM_RED && iTeam2 == TF_TEAM_BLUE ) + return true; + + if ( iTeam1 == TF_TEAM_BLUE && iTeam2 == TF_TEAM_RED ) + return true; + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::AdjustForVisibleScrollbar( void ) +{ + if ( m_pPlayerListRed && m_pPlayerListRed->GetScrollBar() && ( m_bRedScrollBarVisible != m_pPlayerListRed->GetScrollBar()->IsVisible() ) ) + { + m_bRedScrollBarVisible = m_pPlayerListRed->GetScrollBar()->IsVisible(); + int iScrollBarWidth = m_bRedScrollBarVisible ? m_pPlayerListRed->GetScrollBar()->GetWide() : 0; + m_pPlayerListRed->SetColumnWidthBySection( 0, "name", m_iNameWidth + m_nExtraSpace - iScrollBarWidth ); + } + + if ( m_pPlayerListBlue && m_pPlayerListBlue->GetScrollBar() && ( m_bBlueScrollBarVisible != m_pPlayerListBlue->GetScrollBar()->IsVisible() ) ) + { + m_bBlueScrollBarVisible = m_pPlayerListBlue->GetScrollBar()->IsVisible(); + int iScrollBarWidth = m_bBlueScrollBarVisible ? m_pPlayerListBlue->GetScrollBar()->GetWide() : 0; + m_pPlayerListBlue->SetColumnWidthBySection( 0, "name", m_iNameWidth + m_nExtraSpace - iScrollBarWidth ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdateBadgePanels( CUtlVector<CTFBadgePanel*> &pBadgePanels, vgui::SectionedListPanel *pPlayerList ) +{ + int iNumPanels = 0; + + const IMatchGroupDescription *pMatchDesc = TFGameRules() ? GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() ) : NULL; + const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL; + if ( pProgressionDesc && pPlayerList ) + { + if ( TFGameRules()->IsMatchTypeCasual() ) + { + int parentTall = pPlayerList->GetTall(); + CTFBadgePanel *pPanel = NULL; + + for ( int i = 0; i < pPlayerList->GetItemCount(); i++ ) + { + KeyValues *pKeyValues = pPlayerList->GetItemData( i ); + if ( !pKeyValues ) + continue; + + int iPlayerIndex = pKeyValues->GetInt( "playerIndex" ); + const CSteamID steamID = GetSteamIDForPlayerIndex( iPlayerIndex ); + if ( steamID.IsValid() ) + { + if ( iNumPanels >= pBadgePanels.Count() ) + { + pPanel = new CTFBadgePanel( this, "BadgePanel" ); + pPanel->MakeReadyForUse(); + pPanel->SetVisible( true ); + pPanel->SetZPos( 9999 ); + pBadgePanels.AddToTail( pPanel ); + } + else + { + pPanel = pBadgePanels[iNumPanels]; + } + + int x, y, wide, tall; + pPlayerList->GetMaxCellBounds( i, 0, x, y, wide, tall ); + + if ( y + tall > parentTall ) + continue; + + if ( !pPanel->IsVisible() ) + { + pPanel->SetVisible( true ); + } + + int xParent, yParent; + pPlayerList->GetPos( xParent, yParent ); + + int nPanelXPos, nPanelYPos, nPanelWide, nPanelTall; + pPanel->GetBounds( nPanelXPos, nPanelYPos, nPanelWide, nPanelTall ); + + if ( ( nPanelXPos != xParent + x ) + || ( nPanelYPos != yParent + y ) + || ( nPanelWide != wide ) + || ( nPanelTall != tall ) ) + { + pPanel->SetBounds( xParent + x, yParent + y, wide, tall ); + pPanel->InvalidateLayout( true, true ); + } + + pPanel->SetupBadge( pProgressionDesc, steamID ); + iNumPanels++; + } + } + } + } + + // hide any unused images + for ( int i = iNumPanels; i < pBadgePanels.Count(); i++ ) + { + if ( pBadgePanels[i]->IsVisible() ) + { + pBadgePanels[i]->SetVisible( false ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the player list +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdatePlayerList() +{ + int iSelectedPlayerIndex = GetLocalPlayerIndex(); + + // Save off which player we had selected + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int itemID = pList->GetSelectedItem(); + + if ( itemID >= 0 ) + { + KeyValues *pInfo = pList->GetItemData( itemID ); + if ( pInfo ) + { + iSelectedPlayerIndex = pInfo->GetInt( "playerIndex" ); + } + } + } + + m_pPlayerListRed->ClearSelection(); + m_pPlayerListBlue->ClearSelection(); + m_pPlayerListRed->RemoveAll(); + m_pPlayerListBlue->RemoveAll(); + + if ( !g_TF_PR ) + return; + + C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalTFPlayer ) + return; + + int localteam = pLocalTFPlayer->GetTeamNumber(); + if ( pLocalTFPlayer->m_bIsCoaching && pLocalTFPlayer->m_hStudent ) + { + localteam = pLocalTFPlayer->m_hStudent->GetTeamNumber(); + } + + bool bMadeSelection = false; + + for ( int playerIndex = 1; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( g_PR->IsConnected( playerIndex ) || g_PR->IsValid( playerIndex ) ) + { + SectionedListPanel *pPlayerList = NULL; + int nTeam = g_PR->GetTeam( playerIndex ); + switch ( nTeam ) + { + case TF_TEAM_BLUE: + pPlayerList = m_pPlayerListBlue; + break; + case TF_TEAM_RED: + pPlayerList = m_pPlayerListRed; + break; + } + if ( !pPlayerList ) + continue; + + MM_PlayerConnectionState_t eConnectionState = g_TF_PR->GetPlayerConnectionState( playerIndex ); + const wchar_t *pwszFormat = NULL; + if ( eConnectionState == MM_DISCONNECTED ) + { + pwszFormat = g_pVGuiLocalize->Find( "#TF_MM_PlayerLostConnection" ); + } + else if ( ( eConnectionState == MM_CONNECTING ) || ( eConnectionState == MM_LOADING ) ) + { + pwszFormat = g_pVGuiLocalize->Find( "#TF_MM_PlayerConnecting" ); + } + + if ( pwszFormat ) + { + KeyValues *pKV = new KeyValues( "data" ); + pKV->SetInt( "playerIndex", playerIndex ); + pKV->SetInt( "connected", 1 ); + + // HOLY CHEESEBALL BUSY INDICATOR + const wchar_t *pwszEllipses = &L"....."[4 - ( (unsigned)Plat_FloatTime() % 5U )]; + wchar_t wszLocalized[512]; + g_pVGuiLocalize->ConstructString_safe( wszLocalized, pwszFormat, 1, pwszEllipses ); + pKV->SetWString( "name", wszLocalized ); + + int itemID = pPlayerList->AddItem( 0, pKV ); + pPlayerList->SetItemFgColor( itemID, ( eConnectionState == MM_DISCONNECTED ) ? Color( 208, 147, 7, 255 ) : Color( 76, 107, 34, 255 ) ); + pPlayerList->SetItemBgColor( itemID, Color( 0, 0, 0, 80 ) ); + pPlayerList->SetItemFont( itemID, m_hScoreFontSmallest ); + + pKV->deleteThis(); + + continue; + } + + int iActiveDominations = g_TF_PR->GetActiveDominations( playerIndex ); + + // Debug getting some bogus counts here. + if ( iActiveDominations < 0 ) + { + Assert( iActiveDominations >= 0 ); + iActiveDominations = 0; + } + else if ( iActiveDominations >= MAX_PLAYERS ) + { + Assert( iActiveDominations < MAX_PLAYERS ); + iActiveDominations = MAX_PLAYERS - 1; + } + + // Now limit based on the number of images we have + if ( iActiveDominations >= SCOREBOARD_DOMINATION_ICONS ) + { + iActiveDominations = SCOREBOARD_DOMINATION_ICONS - 1; + } + + bool bDominating; + if ( iActiveDominations > 0 ) + { + bDominating = true; + } + else + { + bDominating = false; + } + + bool bAlive = g_TF_PR->IsAlive( playerIndex ); + + int iDominationIndex = ( bDominating ? ( m_iImageDom[iActiveDominations] ) : 0 ); + if ( !bAlive ) + { + iDominationIndex = ( bDominating ? ( m_iImageDomDead[iActiveDominations] ) : 0 ); + } + + KeyValues *pKeyValues = new KeyValues( "data" ); + pKeyValues->SetInt( "playerIndex", playerIndex ); + pKeyValues->SetString( "name", g_TF_PR->GetPlayerName( playerIndex ) ); + pKeyValues->SetInt( "dominating", iDominationIndex ); + pKeyValues->SetInt( "score", g_TF_PR->GetTotalScore( playerIndex ) ); + pKeyValues->SetInt( "connected", 2 ); + + C_TFPlayer *pTFPlayer = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) ); + + if ( pTFPlayer && pTFPlayer->GetActiveTFWeapon() ) + { + int nCount = g_TF_PR->GetStreak( playerIndex, CTFPlayerShared::kTFStreak_Kills ); + if ( nCount ) + { + pKeyValues->SetInt( "killstreak_image", bAlive ? m_iImageStreak : m_iImageStreakDead ); + pKeyValues->SetInt( "killstreak", nCount ); + } + else + { + pKeyValues->SetInt( "killstreak_image", 0 ); + pKeyValues->SetString( "killstreak", "" ); + } + } + + // check for bots first, so malicious server operators can't fake a ping and stuff their server with bots that look like players + if ( g_PR->IsFakePlayer( playerIndex ) ) + { + if ( tf_scoreboard_ping_as_text.GetBool() ) + { + pKeyValues->SetString( "ping", "#TF_Scoreboard_Bot" ); + } + else + { + int iIndex = ( nTeam == TF_TEAM_RED ) ? PING_BOT_RED : PING_BOT_BLUE; + pKeyValues->SetInt( "ping", bAlive ? m_iImagePing[iIndex] : m_iImagePingDead[iIndex] ); + } + } + else + { + int nPing = g_PR->GetPing( playerIndex ); + + if ( nPing < 1 ) + { + if ( tf_scoreboard_ping_as_text.GetBool() ) + { + pKeyValues->SetString( "ping", "" ); + } + else + { + pKeyValues->SetInt( "ping", 0 ); + } + } + else + { + if ( tf_scoreboard_ping_as_text.GetBool() ) + { + pKeyValues->SetInt( "ping", nPing ); + } + else + { + int iIndex = PING_VERY_HIGH; + + if ( nPing < 125 ) + { + iIndex = PING_LOW; + } + else if ( nPing < 200 ) + { + iIndex = PING_MED; + } + else if ( nPing < 275 ) + { + iIndex = PING_HIGH; + } + + pKeyValues->SetInt( "ping", bAlive ? m_iImagePing[iIndex] : m_iImagePingDead[iIndex] ); + } + } + } + + if ( TFGameRules() && TFGameRules()->IsHolidayActive( kHoliday_Halloween ) && TFGameRules()->ArePlayersInHell() ) + { + bAlive &= pTFPlayer && !pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ); + } + + // are they a Spy that's feigning death? mark them as dead in the scoreboard... + if ( g_TF_PR->GetPlayerClass( playerIndex ) == TF_CLASS_SPY ) + { + if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_FEIGN_DEATH ) ) + { + bAlive = false; + } + } + + // can only see class information if we're on the same team + if ( !AreEnemyTeams( g_PR->GetTeam( playerIndex ), localteam ) && !( localteam == TEAM_UNASSIGNED ) ) + { + // class name + if ( g_PR->IsConnected( playerIndex ) ) + { + int iClass = g_TF_PR->GetPlayerClass( playerIndex ); + if ( GetLocalPlayerIndex() == playerIndex && !bAlive ) + { + // If this is local player and he is dead, show desired class (which he will spawn as) rather than current class. + int iDesiredClass = pLocalTFPlayer->m_Shared.GetDesiredPlayerClassIndex(); + // use desired class unless it's random -- if random, his future class is not decided until moment of spawn + if ( TF_CLASS_RANDOM != iDesiredClass ) + { + iClass = iDesiredClass; + } + } + else + { + // for non-local players, show the current class + iClass = g_TF_PR->GetPlayerClass( playerIndex ); + } + + if ( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= TF_LAST_NORMAL_CLASS ) + { + if ( bAlive ) + { + pKeyValues->SetInt( "class", tf_scoreboard_alt_class_icons.GetBool() ? m_iImageClassAlt[iClass] : m_iImageClass[iClass] ); + } + else + { + pKeyValues->SetInt( "class", tf_scoreboard_alt_class_icons.GetBool() ? m_iImageClassAlt[iClass + 9] : m_iImageClass[iClass + 9] ); // +9 is to jump ahead to the darker dead icons + } + } + else + { + pKeyValues->SetInt( "class", 0 ); + } + } + } + else + { + if ( pTFPlayer && pTFPlayer->m_Shared.IsPlayerDominated( pLocalTFPlayer->entindex() ) ) + { + // if local player is dominated by this player, show a nemesis icon + pKeyValues->SetInt( "nemesis", bAlive ? m_iImageNemesis : m_iImageNemesisDead ); + } + else if ( pLocalTFPlayer->m_Shared.IsPlayerDominated( playerIndex ) ) + { + // if this player is dominated by the local player, show the domination icon + pKeyValues->SetInt( "nemesis", bAlive ? m_iImageDominated : m_iImageDominatedDead ); + } + } + +#ifdef STAGING_ONLY +// if ( m_bDisplayLevel ) +// { +// pKeyValues->SetInt( "level", g_TF_PR->GetPlayerLevel( playerIndex ) ); +// } +#endif // STAGING_ONLY + + UpdatePlayerAvatar( playerIndex, pKeyValues ); + + // the medal column is just a place holder for the images that are displayed later + pKeyValues->SetInt( "medal", 0 ); + + int itemID = pPlayerList->AddItem( 0, pKeyValues ); + Color clr = g_PR->GetTeamColor( nTeam ); + + // change color based off alive or dead status. Also slightly different if its local player since the name is highlighted. + if ( !bAlive ) + { + if ( nTeam == TF_TEAM_RED ) + { + if ( GetLocalPlayerIndex() != playerIndex ) + { + clr = Color( 135, 83, 83, 255 ); + } + else + { + clr = Color( 182, 75, 75, 255 ); + } + } + else + { + if ( GetLocalPlayerIndex() != playerIndex ) + { + clr = Color( 81, 97, 129, 255 ); + } + else + { + clr = Color( 123, 153, 187, 255 ); + } + } + } + + pPlayerList->SetItemFgColor( itemID, clr ); + pPlayerList->SetItemBgColor( itemID, Color( 0, 0, 0, 80 ) ); + pPlayerList->SetItemFont( itemID, m_hScoreFontDefault ); + + if ( iSelectedPlayerIndex == playerIndex ) + { + bMadeSelection = true; + pPlayerList->SetSelectedItem( itemID ); + } + + pKeyValues->deleteThis(); + } + else + { + MM_PlayerConnectionState_t eConnectionState = g_TF_PR->GetPlayerConnectionState( playerIndex ); + if ( eConnectionState == MM_WAITING_FOR_PLAYER ) + { + SectionedListPanel *pPlayerList = NULL; + int nTeam = g_PR->GetTeam( playerIndex ); + switch ( nTeam ) + { + case TF_TEAM_BLUE: + pPlayerList = m_pPlayerListBlue; + break; + case TF_TEAM_RED: + pPlayerList = m_pPlayerListRed; + break; + } + if ( pPlayerList ) + { + const wchar_t *pwszFormat = g_pVGuiLocalize->Find( "#TF_MM_LookingForPlayer" ); + if ( pwszFormat ) + { + KeyValues *pKV = new KeyValues( "data" ); + pKV->SetInt( "playerIndex", playerIndex ); + pKV->SetInt( "connected", 0 ); + + // HOLY CHEESEBALL BUSY INDICATOR + const wchar_t *pwszEllipses = &L"....."[4 - ( (unsigned)Plat_FloatTime() % 5U )]; + wchar_t wszLocalized[512]; + g_pVGuiLocalize->ConstructString_safe( wszLocalized, pwszFormat, 1, pwszEllipses ); + pKV->SetWString( "name", wszLocalized ); + + int itemID = pPlayerList->AddItem( 0, pKV ); + pPlayerList->SetItemFgColor( itemID, Color( 120, 120, 120, 255 ) ); + pPlayerList->SetItemBgColor( itemID, Color( 0, 0, 0, 80 ) ); + pPlayerList->SetItemFont( itemID, m_hScoreFontSmallest ); + + pKV->deleteThis(); + } + } + } + } + } + + // If we're on spectator, find a default selection +#ifdef _X360 + if ( !bMadeSelection ) + { + if ( m_pPlayerListBlue->GetItemCount() > 0 ) + { + m_pPlayerListBlue->SetSelectedItem( 0 ); + } + else if ( m_pPlayerListRed->GetItemCount() > 0 ) + { + m_pPlayerListRed->SetSelectedItem( 0 ); + } + } +#endif + + // force the lists to PerformLayout() now so we can update our medal images after we return + m_pPlayerListRed->InvalidateLayout( true ); + m_pPlayerListBlue->InvalidateLayout( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the spectator list +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdateSpectatorList() +{ + char szCoachList[512] = "" ; + int nCoaches = 0; + char szSpectatorList[512] = "" ; + int nSpectators = 0; + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( ShouldShowAsSpectator( playerIndex ) ) + { + C_TFPlayer *pPlayer = (C_TFPlayer*)UTIL_PlayerByIndex( playerIndex ); + if ( pPlayer && pPlayer->m_bIsCoaching && pPlayer->m_hStudent ) + { + if ( nCoaches > 0 ) + { + Q_strncat( szCoachList, ", ", ARRAYSIZE( szCoachList ) ); + } + + Q_strncat( szCoachList, g_PR->GetPlayerName( playerIndex ), ARRAYSIZE( szCoachList ) ); + nCoaches++; + } + else + { + if ( nSpectators > 0 ) + { + Q_strncat( szSpectatorList, ", ", ARRAYSIZE( szSpectatorList ) ); + } + + Q_strncat( szSpectatorList, g_PR->GetPlayerName( playerIndex ), ARRAYSIZE( szSpectatorList ) ); + nSpectators++; + } + } + } + + wchar_t wzText[512] = L""; + if ( nCoaches > 0 ) + { + const char *pchFormat = ( 1 == nCoaches ? "#ScoreBoard_Coach" : "#ScoreBoard_Coaches" ); + + wchar_t wzCount[16]; + wchar_t wzList[1024]; + _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%i", nCoaches ); + g_pVGuiLocalize->ConvertANSIToUnicode( szCoachList, wzList, sizeof( wzList ) ); + g_pVGuiLocalize->ConstructString_safe( wzText, g_pVGuiLocalize->Find( pchFormat), 2, wzCount, wzList ); + } + if ( nSpectators > 0 ) + { + const char *pchFormat = ( 1 == nSpectators ? "#ScoreBoard_Spectator" : "#ScoreBoard_Spectators" ); + + wchar_t wzSpectatorText[512] = L""; + wchar_t wzSpectatorCount[16]; + wchar_t wzSpectatorList[1024]; + _snwprintf( wzSpectatorCount, ARRAYSIZE( wzSpectatorCount ), L"%i", nSpectators ); + g_pVGuiLocalize->ConvertANSIToUnicode( szSpectatorList, wzSpectatorList, sizeof( wzSpectatorList ) ); + g_pVGuiLocalize->ConstructString_safe( wzSpectatorText, g_pVGuiLocalize->Find( pchFormat), 2, wzSpectatorCount, wzSpectatorList ); + if ( nCoaches > 0 ) + { + V_wcscat_safe( wzText, L". " ); + } + V_wcscat_safe( wzText, wzSpectatorText ); + } + + SetDialogVariable( "spectators", wzText ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether the specified player index is an arena spectator +//----------------------------------------------------------------------------- +bool CTFClientScoreBoardDialog::ShouldShowAsArenaWaitingToPlay( int iPlayerIndex ) +{ + if ( !g_TF_PR ) + return false; + + // see if player is connected + if ( g_TF_PR->IsConnected( iPlayerIndex ) ) + { + if ( g_TF_PR->IsArenaSpectator( iPlayerIndex ) == true ) + return false; + + if ( g_TF_PR->GetPlayerClass( iPlayerIndex ) == TF_CLASS_UNDEFINED ) + return false; + + if ( g_TF_PR->GetTeam( iPlayerIndex ) > LAST_SHARED_TEAM ) + return false; + + return true; + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Updates the spectator list +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdateArenaWaitingToPlayList() +{ + char szSpectatorList[512] = "" ; + wchar_t wzSpectators[512] = L""; + + if ( TFGameRules() && TFGameRules()->IsInArenaMode() == true ) + { + int nSpectators = 0; + for( int playerIndex = 1 ; playerIndex <= MAX_PLAYERS; playerIndex++ ) + { + if ( ShouldShowAsArenaWaitingToPlay( playerIndex ) ) + { + if ( nSpectators > 0 ) + { + Q_strncat( szSpectatorList, ", ", ARRAYSIZE( szSpectatorList ) ); + } + + Q_strncat( szSpectatorList, g_PR->GetPlayerName( playerIndex ), ARRAYSIZE( szSpectatorList ) ); + nSpectators++; + } + } + + if ( nSpectators > 0 ) + { + const char *pchFormat = ( 1 == nSpectators ? "#TF_Arena_ScoreBoard_Spectator" : "#TF_Arena_ScoreBoard_Spectators" ); + + wchar_t wzSpectatorCount[16]; + wchar_t wzSpectatorList[1024]; + _snwprintf( wzSpectatorCount, ARRAYSIZE( wzSpectatorCount ), L"%i", nSpectators ); + g_pVGuiLocalize->ConvertANSIToUnicode( szSpectatorList, wzSpectatorList, sizeof( wzSpectatorList ) ); + g_pVGuiLocalize->ConstructString_safe( wzSpectators, g_pVGuiLocalize->Find( pchFormat), 2, wzSpectatorCount, wzSpectatorList ); + } + } + + SetDialogVariable( "waitingtoplay", wzSpectators ); +} + +static void PopulateDuelPanel( CTFClientScoreBoardDialog::duel_panel_t &duelPanel, C_TFPlayer *pPlayer, int unScore ) +{ + CSteamID steamID; + if ( duelPanel.m_pAvatar && pPlayer->GetSteamID( &steamID ) ) + { + duelPanel.m_pAvatar->SetVisible( true ); + duelPanel.m_pAvatar->SetShouldDrawFriendIcon( false ); + duelPanel.m_pAvatar->SetPlayer( steamID, k_EAvatarSize64x64 ); + } + + if ( duelPanel.m_pPlayerNameLabel && g_TF_PR != NULL ) + { + duelPanel.m_pPanel->SetDialogVariable( "playername", g_TF_PR->GetPlayerName( pPlayer->entindex() ) ); + Color clr = g_PR->GetTeamColor( g_PR->GetTeam( pPlayer->entindex() ) ); + duelPanel.m_pPlayerNameLabel->SetFgColor( clr ); + } + duelPanel.m_pPanel->SetDialogVariable( "score", unScore ); +} + +//----------------------------------------------------------------------------- +// Purpose: Updates details about a player +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdatePlayerDetails() +{ + ClearPlayerDetails(); + + // by default, hide these, especially for source tv + m_pLocalPlayerStatsPanel->SetVisible( false ); + m_pLocalPlayerDuelStatsPanel->SetVisible( false ); + + if ( !g_TF_PR ) + return; + + // Default is local player + C_TFPlayer *pSelectedPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pSelectedPlayer ) + return; + + int playerIndex = pSelectedPlayer->entindex(); + + // Change to selected player when using mouse mode + if ( UseMouseMode() ) + { + SectionedListPanel *pList = GetSelectedPlayerList(); + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + if ( iSelectedItem >= 0 ) + { + KeyValues *pIssueKeyValues = pList->GetItemData( iSelectedItem ); + if ( pIssueKeyValues ) + { + playerIndex = pIssueKeyValues->GetInt( "playerIndex", 0 ); + pSelectedPlayer = ToTFPlayer( UTIL_PlayerByIndex( playerIndex ) ); + if ( !pSelectedPlayer || !playerIndex ) + return; + } + } + } + } + + // Make sure the selected player is still connected. + if ( !g_TF_PR->IsConnected( playerIndex ) ) + return; + +#if defined( REPLAY_ENABLED ) + if ( engine->IsHLTV() || g_pEngineClientReplay->IsPlayingReplayDemo() ) +#else + if ( engine->IsHLTV() ) +#endif + { + SetDialogVariable( "playername", g_TF_PR->GetPlayerName( playerIndex ) ); + return; + } + + uint32 unMyScore, unOpponentScore; + C_TFPlayer *pDuelingPartner = NULL; + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pSelectedPlayer == pLocalPlayer && DuelMiniGame_GetStats( &pDuelingPartner, unMyScore, unOpponentScore ) ) + { + PopulateDuelPanel( m_duelPanelLocalPlayer, pLocalPlayer, unMyScore ); + PopulateDuelPanel( m_duelPanelOpponent, pDuelingPartner, unOpponentScore ); + + if ( m_pLocalPlayerStatsPanel->IsVisible() == true ) + { + m_pLocalPlayerStatsPanel->SetVisible( false ); + } + if ( m_pLocalPlayerDuelStatsPanel->IsVisible() == false ) + { + m_pLocalPlayerDuelStatsPanel->SetVisible( true ); + } + } + else + { + if ( m_pLocalPlayerStatsPanel->IsVisible() == false ) + { + m_pLocalPlayerStatsPanel->SetVisible( true ); + } + if ( m_pLocalPlayerDuelStatsPanel->IsVisible() == true ) + { + m_pLocalPlayerDuelStatsPanel->SetVisible( false ); + } + + Color cGreen = Color( 0, 255, 0, 255 ); + Color cWhite = Color( 255, 255, 255, 255 ); + + m_pLocalPlayerStatsPanel->SetDialogVariable( "kills", g_TF_PR->GetPlayerScore( playerIndex ) ); + if ( m_pKillsLabel ) + { + m_pKillsLabel->SetFgColor( g_TF_PR->GetPlayerScore( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "deaths", g_TF_PR->GetDeaths( playerIndex ) ); + if ( m_pDeathsLabel ) + { + m_pDeathsLabel->SetFgColor( g_TF_PR->GetDeaths( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "assists", pSelectedPlayer->m_Shared.GetKillAssists( playerIndex ) ); + if ( m_pAssistLabel ) + { + m_pAssistLabel->SetFgColor( pSelectedPlayer->m_Shared.GetKillAssists( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "destruction", pSelectedPlayer->m_Shared.GetBuildingsDestroyed( playerIndex ) ); + if ( m_pDestructionLabel ) + { + m_pDestructionLabel->SetFgColor( pSelectedPlayer->m_Shared.GetBuildingsDestroyed( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "captures", pSelectedPlayer->m_Shared.GetCaptures( playerIndex ) ); + if ( m_pCapturesLabel ) + { + m_pCapturesLabel->SetFgColor( pSelectedPlayer->m_Shared.GetCaptures( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "defenses", pSelectedPlayer->m_Shared.GetDefenses( playerIndex ) ); + if ( m_pDefensesLabel ) + { + m_pDefensesLabel->SetFgColor( pSelectedPlayer->m_Shared.GetDefenses( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "dominations", pSelectedPlayer->m_Shared.GetDominations( playerIndex ) ); + if ( m_pDominationsLabel ) + { + m_pDominationsLabel->SetFgColor( pSelectedPlayer->m_Shared.GetDominations( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "revenge", pSelectedPlayer->m_Shared.GetRevenge( playerIndex ) ); + if ( m_pRevengeLabel ) + { + m_pRevengeLabel->SetFgColor( pSelectedPlayer->m_Shared.GetRevenge( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "healing", pSelectedPlayer->m_Shared.GetHealPoints( playerIndex ) ); + if ( m_pHealingLabel ) + { + m_pHealingLabel->SetFgColor( pSelectedPlayer->m_Shared.GetHealPoints( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "invulns", pSelectedPlayer->m_Shared.GetInvulns( playerIndex ) ); + if ( m_pInvulnsLabel ) + { + m_pInvulnsLabel->SetFgColor( pSelectedPlayer->m_Shared.GetInvulns( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "teleports", pSelectedPlayer->m_Shared.GetTeleports( playerIndex ) ); + if ( m_pTeleportsLabel ) + { + m_pTeleportsLabel->SetFgColor( pSelectedPlayer->m_Shared.GetTeleports( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "headshots", pSelectedPlayer->m_Shared.GetHeadshots( playerIndex ) ); + if ( m_pHeadshotsLabel ) + { + m_pHeadshotsLabel->SetFgColor( pSelectedPlayer->m_Shared.GetHeadshots( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "backstabs", pSelectedPlayer->m_Shared.GetBackstabs( playerIndex ) ); + if ( m_pBackstabsLabel ) + { + m_pBackstabsLabel->SetFgColor( pSelectedPlayer->m_Shared.GetBackstabs( playerIndex ) ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "bonus", pSelectedPlayer->m_Shared.GetBonusPoints( playerIndex ) ); + if ( m_pBonusLabel ) + { + m_pBonusLabel->SetFgColor( pSelectedPlayer->m_Shared.GetBonusPoints( playerIndex ) ? cGreen : cWhite ); + } + + int nSupport = TFGameRules() ? TFGameRules()->CalcPlayerSupportScore( NULL, playerIndex ) : 0; + m_pLocalPlayerStatsPanel->SetDialogVariable( "support", nSupport ); + if ( m_pSupportLabel ) + { + m_pSupportLabel->SetFgColor( nSupport ? cGreen : cWhite ); + } + m_pLocalPlayerStatsPanel->SetDialogVariable( "damage", g_TF_PR->GetDamage( playerIndex ) ); + if ( m_pDamageLabel ) + { + m_pDamageLabel->SetFgColor( g_TF_PR->GetDamage( playerIndex ) ? cGreen : cWhite ); + } + } + + SetDialogVariable( "playername", g_TF_PR->GetPlayerName( playerIndex ) ); + + Color clr = g_PR->GetTeamColor( g_PR->GetTeam( playerIndex ) ); + m_pLabelPlayerName->SetFgColor( clr ); + m_pImagePanelHorizLine->SetFillColor( clr ); + + // update our image if our selected player or mode of display has changed + if ( ( m_hSelectedPlayer != pSelectedPlayer ) || ( m_bUsePlayerModel != cl_hud_playerclass_use_playermodel.GetBool() ) ) + { + m_hSelectedPlayer = pSelectedPlayer; + m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool(); + + int iClass = pSelectedPlayer->m_Shared.GetDesiredPlayerClassIndex(); + int iTeam = pSelectedPlayer->GetTeamNumber(); + if ( ( pLocalPlayer->InSameTeam( pSelectedPlayer ) || pLocalPlayer->GetTeamNumber() < FIRST_GAME_TEAM ) && + iTeam >= FIRST_GAME_TEAM && iClass >= TF_FIRST_NORMAL_CLASS && iClass <= TF_LAST_NORMAL_CLASS ) + { + if ( cl_hud_playerclass_use_playermodel.GetBool() ) + { + if ( !m_pPlayerModelPanel->IsVisible() ) + { + m_pPlayerModelPanel->SetVisible( true ); + } + + if ( m_pClassImage->IsVisible() ) + { + m_pClassImage->SetVisible( false ); + } + + m_nPlayerModelPanelIndex = pSelectedPlayer->entindex(); + UpdatePlayerModel(); + } + else + { + if ( m_pPlayerModelPanel->IsVisible() ) + { + m_pPlayerModelPanel->SetVisible( false ); + } + + if ( !m_pClassImage->IsVisible() ) + { + m_pClassImage->SetVisible( true ); + } + + m_pClassImage->SetClass( iTeam, iClass, 0 ); + } + } + else + { + if ( m_pPlayerModelPanel->IsVisible() ) + { + m_pPlayerModelPanel->SetVisible( false ); + } + if ( m_pClassImage->IsVisible() ) + { + m_pClassImage->SetVisible( false ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Updates Server Time Left +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::UpdateServerTimeLeft() +{ + wchar_t wzServerTimeHrsLeft[128]; + wchar_t wzServerTimeMinLeft[128]; + wchar_t wzServerTimeSecLeft[128]; + wchar_t wzServerTimeLeft[128]; + + int iTimeLeft = 0; + int iHours = 0; + int iMinutes = 0; + int iSeconds = 0; + int iServerTimeLimit = mp_timelimit.GetInt() * 60; + + if ( iServerTimeLimit == 0 ) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_NoTimeLimit" ), 0 ); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_NoTimeLimitNew" ), 0 ); + SetDialogVariable( "servertime", wzServerTimeLeft ); + + if ( m_pServerTimeLeftValue && m_pServerTimeLeftValue->IsVisible() && ( m_pFontTimeLeftString != vgui::INVALID_FONT ) ) + { + m_pServerTimeLeftValue->SetFont( m_pFontTimeLeftString ); + m_pServerTimeLeftValue->InvalidateLayout(); + } + + return; + } + + iTimeLeft = TFGameRules() ? TFGameRules()->GetTimeLeft() : 0; + + if ( iTimeLeft < 0 ) + { + iTimeLeft = 0; + } + if ( iTimeLeft == 0 ) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_ChangeOnRoundEnd" ), 0 ); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_ChangeOnRoundEndNew" ), 0 ); + SetDialogVariable( "servertime", wzServerTimeLeft ); + + if ( m_pServerTimeLeftValue && m_pServerTimeLeftValue->IsVisible() && ( m_pFontTimeLeftString != vgui::INVALID_FONT ) ) + { + m_pServerTimeLeftValue->SetFont( m_pFontTimeLeftString ); + m_pServerTimeLeftValue->InvalidateLayout(); + } + + return; + } + + iHours = iTimeLeft / 3600; + iMinutes = ( iTimeLeft % 3600 ) / 60; + iSeconds = ( iTimeLeft % 60 ); + + _snwprintf( wzServerTimeHrsLeft, ARRAYSIZE( wzServerTimeHrsLeft ), L"%i", iHours ); + _snwprintf( wzServerTimeMinLeft, ARRAYSIZE( wzServerTimeMinLeft ), L"%02i", iMinutes ); + _snwprintf( wzServerTimeSecLeft, ARRAYSIZE( wzServerTimeSecLeft ), L"%02i", iSeconds ); + + if ( m_pServerTimeLeftValue && m_pServerTimeLeftValue->IsVisible() && ( m_pFontTimeLeftNumbers != vgui::INVALID_FONT ) ) + { + m_pServerTimeLeftValue->SetFont( m_pFontTimeLeftNumbers ); + m_pServerTimeLeftValue->InvalidateLayout(); + } + + if ( iHours == 0 ) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_TimeLeftNoHours" ), 2, wzServerTimeMinLeft, wzServerTimeSecLeft ); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_TimeLeftNoHoursNew" ), 2, wzServerTimeMinLeft, wzServerTimeSecLeft ); + SetDialogVariable( "servertime", wzServerTimeLeft ); + + return; + } + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_TimeLeft" ), 3, wzServerTimeHrsLeft, wzServerTimeMinLeft, wzServerTimeSecLeft ); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#Scoreboard_TimeLeftNew" ), 3, wzServerTimeHrsLeft, wzServerTimeMinLeft, wzServerTimeSecLeft ); + SetDialogVariable( "servertime", wzServerTimeLeft ); +} + +//----------------------------------------------------------------------------- +// Purpose: Clears score details +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::ClearPlayerDetails() +{ + // HLTV has no game stats +#if defined( REPLAY_ENABLED ) + bool bVisible = !engine->IsHLTV() && !g_pEngineClientReplay->IsPlayingReplayDemo(); +#else + bool bVisible = !engine->IsHLTV(); +#endif + + SetDialogVariable( "kills", "" ); + SetControlVisible( "KillsLabel", bVisible ); + + SetDialogVariable( "deaths", "" ); + SetControlVisible( "DeathsLabel", bVisible ); + + SetDialogVariable( "captures", "" ); + SetControlVisible( "CapturesLabel", bVisible ); + + SetDialogVariable( "defenses", "" ); + SetControlVisible( "DefensesLabel", bVisible ); + + SetDialogVariable( "dominations", "" ); + SetControlVisible( "DominationLabel", bVisible ); + + SetDialogVariable( "revenge", "" ); + SetControlVisible( "RevengeLabel", bVisible ); + + SetDialogVariable( "assists", "" ); + SetControlVisible( "AssistsLabel", bVisible ); + + SetDialogVariable( "destruction", "" ); + SetControlVisible( "DestructionLabel", bVisible ); + + SetDialogVariable( "healing", "" ); + SetControlVisible( "HealingLabel", bVisible ); + + SetDialogVariable( "invulns", "" ); + SetControlVisible( "InvulnLabel", bVisible ); + + SetDialogVariable( "teleports", "" ); + SetControlVisible( "TeleportsLabel", bVisible ); + + SetDialogVariable( "headshots", "" ); + SetControlVisible( "HeadshotsLabel", bVisible ); + + SetDialogVariable( "backstabs", "" ); + SetControlVisible( "BackstabsLabel", bVisible ); + + SetDialogVariable( "bonus", "" ); + SetControlVisible( "BonusLabel", bVisible ); + + SetDialogVariable( "support", "" ); + SetControlVisible( "SupportLabel", bVisible ); + + SetDialogVariable( "damage", "" ); + SetControlVisible( "DamageLabel", bVisible ); + + SetDialogVariable( "playername", "" ); + +// SetDialogVariable( "playerscore", "" ); + + +} + +//----------------------------------------------------------------------------- +// Purpose: Used for sorting players +//----------------------------------------------------------------------------- +bool CTFClientScoreBoardDialog::TFPlayerSortFunc( vgui::SectionedListPanel *list, int itemID1, int itemID2 ) +{ + KeyValues *it1 = list->GetItemData(itemID1); + KeyValues *it2 = list->GetItemData(itemID2); + Assert(it1 && it2); + + // first compare score + int v1 = it1->GetInt("score"); + int v2 = it2->GetInt("score"); + if (v1 > v2) + return true; + else if (v1 < v2) + return false; + + // sort by connected status next ( 0 is looking for player, 1 is disconnected/connecting/loading, 2 is fully connected ) + int connected1 = it1->GetInt( "connected" ); + int connected2 = it2->GetInt( "connected" ); + if ( ( connected1 != 2 ) || ( connected2 != 2 ) ) + return ( connected1 > connected2 ); + + // if score is the same, use player index to get deterministic sort + int iPlayerIndex1 = it1->GetInt( "playerIndex" ); + int iPlayerIndex2 = it2->GetInt( "playerIndex" ); + return ( iPlayerIndex1 > iPlayerIndex2 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a localized string of form "1 point", "2 points", etc for specified # of points +//----------------------------------------------------------------------------- +const wchar_t *GetPointsString( int iPoints ) +{ + wchar_t wzScoreVal[128]; + static wchar_t wzScore[128]; + _snwprintf( wzScoreVal, ARRAYSIZE( wzScoreVal ), L"%i", iPoints ); + if ( 1 == iPoints ) + { + g_pVGuiLocalize->ConstructString_safe( wzScore, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Point" ), 1, wzScoreVal ); + } + else + { + g_pVGuiLocalize->ConstructString_safe( wzScore, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Points" ), 1, wzScoreVal ); + } + return wzScore; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns whether the specified player index is a spectator +//----------------------------------------------------------------------------- +bool CTFClientScoreBoardDialog::ShouldShowAsSpectator( int iPlayerIndex ) +{ + if ( !g_TF_PR ) + return false; + + // see if player is connected + if ( g_TF_PR->IsConnected( iPlayerIndex ) ) + { + // either spectating or unassigned team should show in spectator list + int iTeam = g_TF_PR->GetTeam( iPlayerIndex ); + + if ( TFGameRules() ) + { + if ( TFGameRules()->IsInArenaMode() ) + { + if ( g_TF_PR->IsArenaSpectator( iPlayerIndex ) ) + return true; + + return false; + } + else if ( TFGameRules()->IsMannVsMachineMode() ) + { + if ( g_TF_PR->IsFakePlayer( iPlayerIndex ) ) + return false; + } + } + + if ( TEAM_SPECTATOR == iTeam || TEAM_UNASSIGNED == iTeam ) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Event handler +//----------------------------------------------------------------------------- +void CTFClientScoreBoardDialog::FireGameEvent( IGameEvent *event ) +{ + const char *type = event->GetName(); + + if ( FStrEq( type, "server_spawn" ) ) + { + // set server name in scoreboard + const char *hostname = event->GetString( "hostname" ); + wchar_t wzHostName[256]; + wchar_t wzServerLabel[256]; + g_pVGuiLocalize->ConvertANSIToUnicode( hostname, wzHostName, sizeof( wzHostName ) ); + g_pVGuiLocalize->ConstructString_safe( wzServerLabel, g_pVGuiLocalize->Find( "#Scoreboard_Server" ), 1, wzHostName ); + SetDialogVariable( "server", wzServerLabel ); + const char *pMapName = event->GetString( "mapname" ); + SetDialogVariable( "mapname", GetMapDisplayName( pMapName ) ); + // m_pLocalPlayerStatsPanel->SetDialogVariable( "gametype", g_pVGuiLocalize->Find( GetMapType( pMapName ) ) ); + } +#ifdef STAGING_ONLY +// else if ( FStrEq( type, "bountymode_toggled" ) ) +// { +// m_bDisplayLevel = event->GetBool( "active" ); +// InvalidateLayout( true, true ); +// } +#endif + + if ( IsVisible() ) + { + Update(); + } +} +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +SectionedListPanel *CTFClientScoreBoardDialog::GetSelectedPlayerList( void ) +{ + SectionedListPanel *pList = NULL; + + // navigation + if ( m_pPlayerListBlue->GetSelectedItem() >= 0 ) + { + pList = m_pPlayerListBlue; + } + else if ( m_pPlayerListRed->GetSelectedItem() >= 0 ) + { + pList = m_pPlayerListRed; + } + + return pList; +} + +//----------------------------------------------------------------------------- +// Purpose: Event handler +//----------------------------------------------------------------------------- +int CTFClientScoreBoardDialog::HudElementKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + if ( !IsVisible() ) + return 1; + + if ( !down ) + { + return 1; + } + + if ( tf_scoreboard_mouse_mode.GetInt() == 2 ) + { + if ( !m_bMouseActivated && ( keynum == MOUSE_LEFT || keynum == MOUSE_RIGHT ) ) + { + m_bMouseActivated = true; + InitializeInputScheme(); + return 0; + } + } + +#if defined ( _X360 ) + SectionedListPanel *pList = GetSelectedPlayerList(); + + switch( keynum ) + { + case KEY_XBUTTON_UP: + { + if ( pList ) + { + pList->MoveSelectionUp(); + } + } + return 0; + + case KEY_XBUTTON_DOWN: + { + if ( pList ) + { + pList->MoveSelectionDown(); + } + } + return 0; + + case KEY_XBUTTON_RIGHT: + { + if ( m_pPlayerListRed->GetItemCount() == 0 ) + return 0; + + // move to the red list + + // get the row we're in now + int iSelectedBlueItem = m_pPlayerListBlue->GetSelectedItem(); + + m_pPlayerListBlue->ClearSelection(); + + if ( iSelectedBlueItem >= 0 ) + { + int row = m_pPlayerListBlue->GetRowFromItemID( iSelectedBlueItem ); + + if ( row >= 0 ) + { + int iNewItem = m_pPlayerListRed->GetItemIDFromRow( row ); + + if ( iNewItem >= 0 ) + { + m_pPlayerListRed->SetSelectedItem( iNewItem ); + } + else + { + // we have fewer items. Select the last one + int iLastRow = m_pPlayerListRed->GetItemCount()-1; + + iNewItem = m_pPlayerListRed->GetItemIDFromRow( iLastRow ); + + if ( iNewItem >= 0 ) + { + m_pPlayerListRed->SetSelectedItem( iNewItem ); + } + } + } + } + } + return 0; + + case KEY_XBUTTON_LEFT: + { + if ( m_pPlayerListBlue->GetItemCount() == 0 ) + return 0; + + // move to the blue list + + // get the row we're in now + int iSelectedRedItem = m_pPlayerListRed->GetSelectedItem(); + + if ( iSelectedRedItem < 0 ) + iSelectedRedItem = 0; + + m_pPlayerListRed->ClearSelection(); + + if ( iSelectedRedItem >= 0 ) + { + int row = m_pPlayerListRed->GetRowFromItemID( iSelectedRedItem ); + + if ( row >= 0 ) + { + int iNewItem = m_pPlayerListBlue->GetItemIDFromRow( row ); + + if ( iNewItem >= 0 ) + { + m_pPlayerListBlue->SetSelectedItem( iNewItem ); + } + else + { + // we have fewer items. Select the last one + int iLastRow = m_pPlayerListBlue->GetItemCount()-1; + + iNewItem = m_pPlayerListBlue->GetItemIDFromRow( iLastRow ); + + if ( iNewItem >= 0 ) + { + m_pPlayerListBlue->SetSelectedItem( iNewItem ); + } + } + } + } + } + return 0; + + case KEY_XBUTTON_B: + { + ShowPanel( false ); + } + return 0; + + case KEY_XBUTTON_A: // Show GamerCard for the selected player + { + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + + if ( iSelectedItem >= 0 ) + { + KeyValues *pInfo = pList->GetItemData( iSelectedItem ); + + DevMsg( 1, "XShowGamerCardUI for player '%s'\n", pInfo->GetString( "name" ) ); + + uint64 xuid = matchmaking->PlayerIdToXuid( pInfo->GetInt( "playerIndex" ) ); + XShowGamerCardUI( XBX_GetPrimaryUserId(), xuid ); + } + } + } + return 0; + + case KEY_XBUTTON_X: // Show player review for the selected player + { + if ( pList ) + { + int iSelectedItem = pList->GetSelectedItem(); + + if ( iSelectedItem >= 0 ) + { + KeyValues *pInfo = pList->GetItemData( iSelectedItem ); + + DevMsg( 1, "XShowPlayerReviewUI for player '%s'\n", pInfo->GetString( "name" ) ); + + uint64 xuid = matchmaking->PlayerIdToXuid( pInfo->GetInt( "playerIndex" ) ); + XShowPlayerReviewUI( XBX_GetPrimaryUserId(), xuid ); + } + } + } + return 0; + + default: + break; + } +#endif //_X360 + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool ShouldScoreBoardHandleKeyInput( int down, ButtonCode_t keynum, const char *pszCurrentBinding ) +{ + // We're only looking for specific mouse input + if ( keynum == MOUSE_LEFT || keynum == MOUSE_RIGHT ) + { + CTFClientScoreBoardDialog *pScoreBoard = dynamic_cast< CTFClientScoreBoardDialog* >( gViewPortInterface->FindPanelByName( PANEL_SCOREBOARD ) ); + if ( pScoreBoard ) + { + return !pScoreBoard->HudElementKeyInput( down, keynum, pszCurrentBinding ); + } + } + + return false; +} |