Modified source engine (2017) developed by valve and leaked in 2020. Not for commercial purporses
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

826 lines
27 KiB

//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "tf_party.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/ScrollableEditablePanel.h"
#include "tf_lobbypanel_comp.h"
#include "tf_lobby_container_frame_comp.h"
#include "vgui/ISystem.h"
#include "tf_streams.h"
#include "tf_badge_panel.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
ConVar tf_mm_ladder_ui_last_rating_change( "tf_mm_ladder_ui_last_rating_change", "0", FCVAR_HIDDEN | FCVAR_ARCHIVE, "Track last match skillrating change for UI." );
ConVar tf_mm_ladder_ui_last_rating_time( "tf_mm_ladder_ui_last_rating_time", "-1", FCVAR_HIDDEN | FCVAR_ARCHIVE, "Track last match skillrating change time for UI." );
class CLobbyPanel_Comp;
#include "iclientmode.h"
#include <vgui_controls/AnimationController.h>
class CMatchHistoryEntryPanel : public CExpandablePanel
{
public:
DECLARE_CLASS_SIMPLE( CMatchHistoryEntryPanel, CExpandablePanel );
CMatchHistoryEntryPanel( Panel* pParent, const char *pszPanelname )
: BaseClass( pParent, pszPanelname )
{}
virtual void ApplySchemeSettings( IScheme *pScheme ) OVERRIDE
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "resource/ui/MatchHistoryEntryPanel.res" );
}
void SetMatchData( const CSOTFMatchResultPlayerStats& stats )
{
EditablePanel* pContainer = FindControl< EditablePanel >( "Container" );
if ( !pContainer )
return;
// Match date
CRTime matchdate( stats.endtime() );
char rtime_buf[k_RTimeRenderBufferSize];
matchdate.Render( rtime_buf );
pContainer->SetDialogVariable( "match_date", rtime_buf );
// Map name
const MapDef_t* pMapDef = GetItemSchema()->GetMasterMapDefByIndex( stats.map_index() );
const char* pszMapToken = "#TF_Map_Unknown";
if ( pMapDef )
{
pszMapToken = pMapDef->pszMapNameLocKey;
}
pContainer->SetDialogVariable( "map_name", g_pVGuiLocalize->Find( pszMapToken ) );
// KD ratio
float flKDRatio = stats.kills();
if ( stats.deaths() > 0 )
{
flKDRatio /= (float)stats.deaths();
}
pContainer->SetDialogVariable( "kd_ratio", CFmtStr( "%.1f", flKDRatio ) );
pContainer->SetControlVisible( "WinLabel", stats.display_rating_change() > 0 );
pContainer->SetControlVisible( "LossLabel", stats.display_rating_change() < 0 );
EditablePanel* pStatsContainer = FindControl< EditablePanel >( "SlidingStatsContainer", true );
if ( pStatsContainer )
{
pStatsContainer->SetDialogVariable( "stat_kills", LocalizeNumberWithToken( "TF_Competitive_Kills", stats.kills() ) );
pStatsContainer->SetDialogVariable( "stat_deaths", LocalizeNumberWithToken( "TF_Competitive_Deaths", stats.deaths() ) );
pStatsContainer->SetDialogVariable( "stat_damage", LocalizeNumberWithToken( "TF_Competitive_Damage", stats.damage() ) );
pStatsContainer->SetDialogVariable( "stat_healing", LocalizeNumberWithToken( "TF_Competitive_Healing", stats.healing() ) );
pStatsContainer->SetDialogVariable( "stat_support", LocalizeNumberWithToken( "TF_Competitive_Support", stats.support() ) );
pStatsContainer->SetDialogVariable( "stat_score", LocalizeNumberWithToken( "TF_Competitive_Score", stats.score() ) );
ScalableImagePanel* pMapImage = pStatsContainer->FindControl< ScalableImagePanel >( "BGImage", true );
if ( pMapImage && pMapDef )
{
char imagename[ 512 ];
Q_snprintf( imagename, sizeof( imagename ), "..\\vgui\\maps\\menu_thumb_%s", pMapDef->pszMapName );
pMapImage->SetImage( imagename );
}
// Lambdas, wherefore art thou...
SetupClassIcon( pStatsContainer, "scout", TF_CLASS_SCOUT, stats );
SetupClassIcon( pStatsContainer, "soldier", TF_CLASS_SOLDIER, stats );
SetupClassIcon( pStatsContainer, "pyro", TF_CLASS_PYRO, stats );
SetupClassIcon( pStatsContainer, "demo", TF_CLASS_DEMOMAN, stats );
SetupClassIcon( pStatsContainer, "heavy", TF_CLASS_HEAVYWEAPONS, stats );
SetupClassIcon( pStatsContainer, "engineer", TF_CLASS_ENGINEER, stats );
SetupClassIcon( pStatsContainer, "medic", TF_CLASS_MEDIC, stats );
SetupClassIcon( pStatsContainer, "sniper", TF_CLASS_SNIPER, stats );
SetupClassIcon( pStatsContainer, "spy", TF_CLASS_SPY, stats );
SetupMedalForStat( pStatsContainer, stats.kills_medal(), "kills" );
SetupMedalForStat( pStatsContainer, stats.damage_medal(), "damage" );
SetupMedalForStat( pStatsContainer, stats.healing_medal(), "healing" );
SetupMedalForStat( pStatsContainer, stats.support_medal(), "support" );
SetupMedalForStat( pStatsContainer, stats.score_medal(), "score" );
}
}
private:
void SetupMedalForStat( EditablePanel* pParent, int nStat, const char* pszStatName )
{
ScalableImagePanel* pMedalImage = pParent->FindControl< ScalableImagePanel >( CFmtStr( "%sMedal", pszStatName ) );
if ( pMedalImage )
{
if ( nStat != StatMedal_None )
{
pMedalImage->SetImage( g_pszCompetitiveMedalImages[ nStat ] );
}
pMedalImage->SetVisible( nStat != StatMedal_None );
}
}
void SetupClassIcon( EditablePanel* pParent, const char* pszClassName, int nBit, const CSOTFMatchResultPlayerStats& stats )
{
ScalableImagePanel* pClassIcon = pParent->FindControl< ScalableImagePanel >( CFmtStr( "%sIcon", pszClassName ), true );
if( pClassIcon )
{
pClassIcon->SetImage( stats.classes_played() & (1<<nBit) ? CFmtStr( "class_icons/filter_%s_on", pszClassName ) : CFmtStr( "class_icons/filter_%s", pszClassName ) );
}
}
};
DECLARE_BUILD_FACTORY( CMatchHistoryEntryPanel );
extern Color s_colorChallengeHeader;
DECLARE_BUILD_FACTORY( CLadderLobbyLeaderboard );
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CLadderLobbyLeaderboard::CLadderLobbyLeaderboard( Panel *pParent, const char *pszPanelName )
: CTFLeaderboardPanel( pParent, pszPanelName )
{
m_pScoreList = new vgui::EditablePanel( this, "ScoreList" );
m_pScoreListScroller = new vgui::ScrollableEditablePanel( this, m_pScoreList, "ScoreListScroller" );
m_pScoreListScroller->AddActionSignalTarget( this );
m_pszLeaderboardName = "tf2_ladder_6v6";
for ( int i = 0; i < 100; ++i )
{
vgui::EditablePanel *pEntryUI = new vgui::EditablePanel( m_pScoreList, "LeaderboardEntry" );
m_vecLeaderboardEntries.AddToTail( pEntryUI );
}
m_pToolTip = new CTFTextToolTip( this );
m_pToolTipEmbeddedPanel = new vgui::EditablePanel( this, "TooltipPanel" );
m_pToolTipEmbeddedPanel->SetKeyBoardInputEnabled( false );
m_pToolTipEmbeddedPanel->SetMouseInputEnabled( false );
m_pToolTip->SetEmbeddedPanel( m_pToolTipEmbeddedPanel );
m_pToolTip->SetTooltipDelay( 0 );
m_bIsDataValid = false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLadderLobbyLeaderboard::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( "Resource/UI/econ/LobbyLeaderboard.res" );
FOR_EACH_VEC( m_vecLeaderboardEntries, i )
{
m_vecLeaderboardEntries[i]->ApplySchemeSettings( pScheme );
m_vecLeaderboardEntries[i]->LoadControlSettings( "Resource/UI/LeaderboardEntryRank.res" );
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLadderLobbyLeaderboard::PerformLayout()
{
BaseClass::PerformLayout();
UpdateLeaderboards();
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLadderLobbyLeaderboard::OnCommand( const char *command )
{
if ( Q_strnicmp( command, "stream", 6 ) == 0 )
{
vgui::system()->ShellExecute( "open", command + 7 );
return;
}
else if ( FStrEq( "global", command ) )
{
if ( m_bGlobal != true )
{
m_bGlobal = true;
UpdateLeaderboards();
}
return;
}
else if ( FStrEq( "local", command ) )
{
if ( m_bGlobal == true )
{
m_bGlobal = false;
UpdateLeaderboards();
}
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CLadderLobbyLeaderboard::GetLeaderboardData( CUtlVector< LeaderboardEntry_t* >& scores )
{
CUtlVector< LeaderboardEntry_t* > vecLadderScores;
if ( Leaderboards_GetLadderLeaderboard( vecLadderScores, m_pszLeaderboardName, m_bGlobal ) )
{
scores.AddVectorToTail( vecLadderScores );
return true;
}
return false;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CLadderLobbyLeaderboard::UpdateLeaderboards()
{
CUtlVector< LeaderboardEntry_t* > scores;
m_bIsDataValid = GetLeaderboardData( scores );
if ( !m_bIsDataValid )
return false;
int nScoreListHeight = scores.Count() * m_yEntryStep;
int nScrollerWidth, nScrollerHeight;
m_pScoreListScroller->GetSize( nScrollerWidth, nScrollerHeight );
m_pScoreList->SetSize( nScrollerWidth, Max( nScoreListHeight, nScrollerHeight ) );
m_pScoreList->InvalidateLayout( true );
m_pScoreListScroller->InvalidateLayout( true );
m_pScoreListScroller->GetScrollbar()->InvalidateLayout( true );
static int nScrollWidth = m_pScoreListScroller->GetScrollbar()->GetWide();
m_pScoreListScroller->GetScrollbar()->SetWide( nScrollWidth>>1 );
if ( m_pScoreListScroller->GetScrollbar()->GetButton( 0 ) &&
m_pScoreListScroller->GetScrollbar()->GetButton( 1 ) )
{
m_pScoreListScroller->GetScrollbar()->GetButton( 0 )->SetVisible( false );
m_pScoreListScroller->GetScrollbar()->GetButton( 1 )->SetVisible( false );
}
FOR_EACH_VEC( m_vecLeaderboardEntries, i )
{
EditablePanel *pContainer = dynamic_cast< EditablePanel* >( m_vecLeaderboardEntries[i] );
if ( !pContainer )
continue;
Color colorToUse = i % 2 == 1 ? m_OddTextColor : m_EvenTextColor;
bool bIsEntryVisible = i < scores.Count();
pContainer->SetVisible( bIsEntryVisible );
pContainer->SetPos( 0, i * m_yEntryStep );
if ( bIsEntryVisible )
{
const LeaderboardEntry_t *pLeaderboardEntry = scores[i];
const CSteamID &steamID = pLeaderboardEntry->m_steamIDUser;
#ifdef TWITCH_LEADERBOARD
TwitchTvAccountInfo_t *pTwitchInfo = StreamManager()->GetTwitchTvAccountInfo( steamID.ConvertToUint64() );
ETwitchTvState_t twitchState = pTwitchInfo ? pTwitchInfo->m_eTwitchTvState : k_ETwitchTvState_Error;
// still waiting for twitch info to load
if ( twitchState <= k_ETwitchTvState_Loading )
return false;
#endif // TWITCH_LEADERBOARD
bool bIsLocalPlayer = steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUser()->GetSteamID() == steamID;
pContainer->SetDialogVariable( "position", m_bGlobal ? CFmtStr( "%d.", pLeaderboardEntry->m_nGlobalRank ) : "" );
pContainer->SetDialogVariable( "username", InventoryManager()->PersonaName_Get( steamID.GetAccountID() ) );
CExLabel *pNameText = dynamic_cast< CExLabel* >( pContainer->FindChildByName( "UserName" ) );
if ( pNameText )
{
pNameText->SetColorStr( bIsLocalPlayer ? m_LocalPlayerTextColor : colorToUse );
}
CAvatarImagePanel *pAvatar = dynamic_cast< CAvatarImagePanel* >( pContainer->FindChildByName( "AvatarImage" ) );
if ( pAvatar )
{
pAvatar->SetShouldDrawFriendIcon( false );
pAvatar->SetPlayer( steamID, k_EAvatarSize32x32 );
}
CTFBadgePanel *pRankImage = dynamic_cast< CTFBadgePanel* >( pContainer->FindChildByName( "RankImage" ) );
if ( pRankImage )
{
const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( k_nMatchGroup_Ladder_6v6 );
const LevelInfo_t& levelInfo = pMatchDesc->m_pProgressionDesc->GetLevelForExperience( pLeaderboardEntry->m_nScore );
pRankImage->SetupBadge( pMatchDesc->m_pProgressionDesc, levelInfo );
wchar_t wszOutString[ 128 ];
char szLocalized[512];
wchar_t wszCount[ 16 ];
_snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", levelInfo.m_nLevelNum );
const wchar_t *wpszFormat = g_pVGuiLocalize->Find( pMatchDesc->m_pProgressionDesc->m_pszLevelToken );
g_pVGuiLocalize->ConstructString_safe( wszOutString, wpszFormat, 2, wszCount, g_pVGuiLocalize->Find( levelInfo.m_pszLevelTitle ) );
g_pVGuiLocalize->ConvertUnicodeToANSI( wszOutString, szLocalized, sizeof( szLocalized ) );
pRankImage->SetMouseInputEnabled( true );
pRankImage->SetVisible( true );
pRankImage->SetTooltip( m_pToolTip, szLocalized );
}
CExImageButton *pStreamImage = dynamic_cast< CExImageButton* >( pContainer->FindChildByName( "StreamImageButton" ) );
if ( pStreamImage )
{
#ifdef TWITCH_LEADERBOARD
if ( twitchState == k_ETwitchTvState_Linked )
{
pStreamImage->SetVisible( true );
pStreamImage->SetCommand( CFmtStr( "stream %s", pTwitchInfo->m_sTwitchTvChannel.String() ) );
}
else
#endif // TWITCH_LEADERBOARD
{
pStreamImage->SetVisible( false );
pStreamImage->SetCommand( "" );
}
}
}
}
return true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLadderLobbyLeaderboard::SetLeaderboard( const char *pszLeaderboardName, bool bGlobal )
{
m_pszLeaderboardName = pszLeaderboardName;
m_bGlobal = bGlobal;
UpdateLeaderboards();
}
static void GetPlayerNameForSteamID( wchar_t *wCharPlayerName, int nBufSizeBytes, const CSteamID &steamID )
{
const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( steamID );
V_UTF8ToUnicode( pszName, wCharPlayerName, nBufSizeBytes );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CLobbyPanel_Comp::CLobbyPanel_Comp( vgui::Panel *pParent, CBaseLobbyContainerFrame* pLobbyContainer )
: CBaseLobbyPanel( pParent, pLobbyContainer )
, m_pCompetitiveModeLeaderboard( NULL )
, m_pMatchHistoryScroller( NULL )
, m_eMatchSortMethod( SORT_BY_DATE )
, m_bDescendingMatchHistorySort( true )
{
// Comp
m_fontMedalsCount = 0;
m_flCompetitiveRankProgress = -1.f;
m_flCompetitiveRankPrevProgress = -1.f;
m_flRefreshPlayerListTime = -1.f;
m_bCompetitiveRankChangePlayedSound = false;
m_bMatchHistoryLoaded = false;
m_bMatchDataForLocalPlayerDirty = true;
ListenForGameEvent( "gc_new_session" );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CLobbyPanel_Comp::~CLobbyPanel_Comp()
{
delete m_pImageList;
m_pImageList = NULL;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::OnCommand( const char *command )
{
if ( FStrEq( command, "medals_help" ) )
{
CExplanationPopup *pPopup = dynamic_cast< CExplanationPopup* >( GetParent()->FindChildByName( "MedalsHelp" ) );
if ( pPopup )
{
pPopup->Popup();
}
return;
}
else if ( FStrEq( command, "show_leaderboards" ) )
{
if ( m_pCompetitiveModeLeaderboard )
{
m_pCompetitiveModeLeaderboard->SetVisible( true );
}
SetControlVisible( "MatchHistoryCategories", false, true );
SetControlVisible( "MatchHistoryContainer", false, true );
return;
}
else if ( FStrEq( command, "show_match_history" ) )
{
m_bMatchDataForLocalPlayerDirty = true;
if ( m_pCompetitiveModeLeaderboard )
{
m_pCompetitiveModeLeaderboard->SetVisible( false );
}
SetControlVisible( "MatchHistoryCategories", true, true );
SetControlVisible( "MatchHistoryContainer", true, true );
return;
}
else if ( !Q_strncmp( "sort", command, 4 ) )
{
EMatchHistorySortMethods_t eNewMethod = (EMatchHistorySortMethods_t)atoi( command + 4 );
if ( eNewMethod == m_eMatchSortMethod )
{
m_bDescendingMatchHistorySort = !m_bDescendingMatchHistorySort;
}
else
{
m_eMatchSortMethod = eNewMethod;
m_bDescendingMatchHistorySort = true;
}
m_bMatchDataForLocalPlayerDirty = true;
return;
}
BaseClass::OnCommand( command );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CLobbyPanel_Comp::ShouldShowLateJoin() const
{
return false; // For now
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::ApplyChatUserSettings( const CBaseLobbyPanel::LobbyPlayerInfo &player, KeyValues *pKV ) const
{
pKV->SetInt( "has_ticket", 0 );
pKV->SetInt( "squad_surplus", 0 );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::WriteGameSettingsControls()
{
BaseClass::WriteGameSettingsControls();
// Make sure we want to be in matchmaking. (If we don't, the frame should hide us pretty quickly.)
// We might get an event or something right at the transition point occasionally when the UI should
// not be visible
if ( GTFGCClientSystem()->GetMatchmakingUIState() == eMatchmakingUIState_Inactive )
{
return;
}
++m_iWritingPanel;
m_pContainer->SetNextButtonEnabled( true );
SetControlVisible( "ScrollableContainer", GTFGCClientSystem()->GetWizardStep()== TF_Matchmaking_WizardStep_LADDER );
--m_iWritingPanel;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
int CLobbyPanel_Comp::GetMedalCountForStat( EMatchGroup unLadderType, RankStatType_t nStatType, int nMedalLevel )
{
CSOTFLadderData *pData = GetLocalPlayerLadderData( unLadderType );
if ( !pData )
return 0;
switch ( nStatType )
{
case RankStat_Score:
if ( nMedalLevel == StatMedal_Bronze )
{
return pData->Obj().score_bronze();
}
else if ( nMedalLevel == StatMedal_Silver )
{
return pData->Obj().score_silver();
}
else if ( nMedalLevel == StatMedal_Gold )
{
return pData->Obj().score_gold();
}
break;
case RankStat_Kills:
if ( nMedalLevel == StatMedal_Bronze )
{
return pData->Obj().kills_bronze();
}
else if ( nMedalLevel == StatMedal_Silver )
{
return pData->Obj().kills_silver();
}
else if ( nMedalLevel == StatMedal_Gold )
{
return pData->Obj().kills_gold();
}
break;
case RankStat_Damage:
if ( nMedalLevel == StatMedal_Bronze )
{
return pData->Obj().damage_bronze();
}
else if ( nMedalLevel == StatMedal_Silver )
{
return pData->Obj().damage_silver();
}
else if ( nMedalLevel == StatMedal_Gold )
{
return pData->Obj().damage_gold();
}
break;
case RankStat_Healing:
if ( nMedalLevel == StatMedal_Bronze )
{
return pData->Obj().healing_bronze();
}
else if ( nMedalLevel == StatMedal_Silver )
{
return pData->Obj().healing_silver();
}
else if ( nMedalLevel == StatMedal_Gold )
{
return pData->Obj().healing_gold();
}
break;
case RankStat_Support:
if ( nMedalLevel == StatMedal_Bronze )
{
return pData->Obj().support_bronze();
}
else if ( nMedalLevel == StatMedal_Silver )
{
return pData->Obj().support_silver();
}
else if ( nMedalLevel == StatMedal_Gold )
{
return pData->Obj().support_gold();
}
break;
case RankStat_Deaths:
// Not supported
break;
default:
Assert( 0 );
}
return 0;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::OnThink()
{
BaseClass::OnThink();
if ( m_bMatchDataForLocalPlayerDirty )
{
UpdateMatchDataForLocalPlayer();
}
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::FireGameEvent( IGameEvent *event )
{
const char *pszEventname = event->GetName();
if ( !Q_stricmp( pszEventname, "gc_new_session" ) )
{
// This is loaded on demand by the GC - if we have a new session, we need to re-request
if ( m_bMatchHistoryLoaded )
{
m_bMatchHistoryLoaded = false;
m_bMatchDataForLocalPlayerDirty = true;
}
}
BaseClass::FireGameEvent( event );
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
EMatchGroup CLobbyPanel_Comp::GetMatchGroup( void ) const
{
return k_nMatchGroup_Ladder_6v6;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::SOCreated( const CSteamID & steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent )
{
if ( pObject->GetTypeID() != CSOTFMatchResultPlayerInfo::k_nTypeID )
return;
m_bMatchDataForLocalPlayerDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::SOUpdated( const CSteamID & steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent )
{
if ( pObject->GetTypeID() != CSOTFMatchResultPlayerInfo::k_nTypeID )
return;
m_bMatchDataForLocalPlayerDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::PerformLayout()
{
BaseClass::PerformLayout();
m_bMatchDataForLocalPlayerDirty = true;
}
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CLobbyPanel_Comp::ApplySchemeSettings( vgui::IScheme *pScheme )
{
BaseClass::ApplySchemeSettings( pScheme );
EditablePanel* pPlaylistBGPanel = FindControl< EditablePanel >( "PlaylistBGPanel", true );
m_pCompetitiveModeLeaderboard = pPlaylistBGPanel->FindControl< CLadderLobbyLeaderboard >( "Leaderboard", true );
m_pMatchHistoryScroller = pPlaylistBGPanel->FindControl< CScrollableList >( "MatchHistoryContainer" );
int nAvatarWidth = ( ( m_iAvatarWidth * 5 / 4 ) + 1 );
int nExtraWidth = ( m_pChatPlayerList->GetWide() - ( 2 * nAvatarWidth ) - m_iPlayerNameWidth - m_iBannedWidth - m_iHasPassWidth );
m_pChatPlayerList->AddColumnToSection( 0, "avatar", "#TF_Players", vgui::SectionedListPanel::COLUMN_IMAGE, nAvatarWidth );
m_pChatPlayerList->AddColumnToSection( 0, "name", "", 0, m_iPlayerNameWidth + nExtraWidth );
m_pChatPlayerList->AddColumnToSection( 0, "is_banned", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, m_iBannedWidth );
m_pChatPlayerList->AddColumnToSection( 0, "has_competitive_access", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, m_iHasPassWidth );
m_pChatPlayerList->AddColumnToSection( 0, "rank", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, nAvatarWidth );
m_pChatPlayerList->SetDrawHeaders( false );
m_fontMedalsCount = pScheme->GetFont( "HudFontSmallestBold", true );
}
static int SortResult( const CSOTFMatchResultPlayerStats * a, const CSOTFMatchResultPlayerStats * b )
{
return a->display_rating_change() < b->display_rating_change();
}
static int SortDate( const CSOTFMatchResultPlayerStats * a, const CSOTFMatchResultPlayerStats * b )
{
return a->endtime() < b->endtime();
}
static int SortMap( const CSOTFMatchResultPlayerStats * a, const CSOTFMatchResultPlayerStats * b )
{
const MapDef_t* pMapDef = GetItemSchema()->GetMasterMapDefByIndex( a->map_index() );
const wchar_t* pszAMapName = g_pVGuiLocalize->Find( pMapDef ? pMapDef->pszMapNameLocKey : "#TF_Map_Unknown" );
pMapDef = GetItemSchema()->GetMasterMapDefByIndex( b->map_index() );
const wchar_t* pszBMapName = g_pVGuiLocalize->Find( pMapDef ? pMapDef->pszMapNameLocKey : "#TF_Map_Unknown" );
return wcscoll( pszAMapName, pszBMapName );
}
static int SortKDR( const CSOTFMatchResultPlayerStats * a, const CSOTFMatchResultPlayerStats * b )
{
float flAKDRatio = a->kills();
if ( a->deaths() > 0 )
{
flAKDRatio /= (float)a->deaths();
}
float flBKDRatio = b->kills();
if ( b->deaths() > 0 )
{
flBKDRatio /= (float)b->deaths();
}
return ( flBKDRatio - flAKDRatio ) * 1000.f;
}
void CLobbyPanel_Comp::UpdateMatchDataForLocalPlayer()
{
m_bMatchDataForLocalPlayerDirty = false;
CUtlVector < CSOTFMatchResultPlayerStats > vecMatches;
GetLocalPlayerMatchHistory( GetMatchGroup(), vecMatches );
if ( !m_bMatchHistoryLoaded )
{
GCSDK::CProtoBufMsg< CMsgGCMatchHistoryLoad > msg( k_EMsgGCMatchHistoryLoad );
GCClientSystem()->BSendMessage( msg );
m_bMatchHistoryLoaded = true;
}
if ( m_pMatchHistoryScroller )
{
m_pMatchHistoryScroller->ClearAutoLayoutPanels();
typedef int (*MatchSortFunc)( const CSOTFMatchResultPlayerStats * a, const CSOTFMatchResultPlayerStats * b );
struct SortMethodData_t
{
MatchSortFunc m_pfnSort;
CExButton* m_pSortButton;
};
EditablePanel* pPlaylistBGPanel = FindControl< EditablePanel >( "PlaylistBGPanel", true );
Assert( pPlaylistBGPanel );
if ( !pPlaylistBGPanel )
return;
SortMethodData_t sortMethods[ NUM_SORT_METHODS ] = { { &SortResult, pPlaylistBGPanel->FindControl< CExButton >( "ResultButton", true ) }
, { &SortDate, pPlaylistBGPanel->FindControl< CExButton >( "DateButton", true ) }
, { &SortMap, pPlaylistBGPanel->FindControl< CExButton >( "MapButton", true ) }
, { &SortKDR, pPlaylistBGPanel->FindControl< CExButton >( "KDRButton", true ) } };
// Sort
vecMatches.Sort( sortMethods[ m_eMatchSortMethod ].m_pfnSort );
Label* pSortArrow = pPlaylistBGPanel->FindControl< Label >( "SortArrow", true );
Assert( pSortArrow );
if ( !pSortArrow )
return;
// Update controls
for( int i=0; i<ARRAYSIZE( sortMethods ); ++i )
{
if( sortMethods[ i ].m_pSortButton )
{
bool bSelected = i == m_eMatchSortMethod;
sortMethods[ i ].m_pSortButton->SetSelected( bSelected );
if ( bSelected )
{
int nDummy, nX;
sortMethods[ i ].m_pSortButton->GetContentSize( nX, nDummy );
// Move the sort arrow to the right edge of the selected panel
pSortArrow->SetPos( sortMethods[ i ].m_pSortButton->GetXPos() + nX , pSortArrow->GetYPos() );
// Fixup the label to be an up or down arrow
pSortArrow->SetText( m_bDescendingMatchHistorySort ? L"6" : L"5" );
}
}
}
// Potentially go backwards
if ( m_bDescendingMatchHistorySort )
{
FOR_EACH_VEC( vecMatches, i )
{
CMatchHistoryEntryPanel* pMatchEntryPanel = new CMatchHistoryEntryPanel( m_pMatchHistoryScroller, "MatchEntry" );
pMatchEntryPanel->MakeReadyForUse();
pMatchEntryPanel->SetMatchData( vecMatches[ i ] );
m_pMatchHistoryScroller->AddPanel( pMatchEntryPanel, 5 );
}
}
else
{
FOR_EACH_VEC_BACK( vecMatches, i )
{
CMatchHistoryEntryPanel* pMatchEntryPanel = new CMatchHistoryEntryPanel( m_pMatchHistoryScroller, "MatchEntry" );
pMatchEntryPanel->MakeReadyForUse();
pMatchEntryPanel->SetMatchData( vecMatches[ i ] );
m_pMatchHistoryScroller->AddPanel( pMatchEntryPanel, 5 );
}
}
m_pMatchHistoryScroller->MakeReadyForUse();
}
}