|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "tf_party.h"
#include "tf_item_inventory.h"
#include "vgui_controls/PropertySheet.h"
#include "vgui_controls/SectionedListPanel.h"
#include "vgui/IInput.h"
#include <vgui_controls/ImageList.h>
#include "vgui_avatarimage.h"
#include "tf_ladder_data.h"
#include "vgui_controls/Menu.h"
#include "tf_match_description.h"
#include "tf_badge_panel.h"
#include "tf_controls.h"
#include "tf_lobbypanel.h"
#include "tf_lobby_container_frame.h"
// memdbgon must be the last include file in a .cpp file!!!
#include <tier0/memdbgon.h>
ConVar tf_matchmaking_join_in_progress( "tf_matchmaking_join_in_progress", "0", FCVAR_DONTRECORD | FCVAR_ARCHIVE, "Saved preference for if the player wants to join games in progress." );
const int k_iPopIndex_Any = -1000; const int k_iPopIndex_OnlyNotYetCompleted = -1001; const int k_iPopIndex_AnyNormal = -1002; const int k_iPopIndex_AnyIntermediate = -1003; const int k_iPopIndex_AnyAdvanced = -1004; const int k_iPopIndex_AnyExpert = -1005; const int k_iPopIndex_AnyHaunted = -1006;
static void GetMvmChallengeSet( int idxChallenge, CMvMMissionSet &result ) { result.Clear();
if ( idxChallenge >= 0 ) { result.SetMissionBySchemaIndex( idxChallenge, true ); return; }
bool bMannUP = GTFGCClientSystem()->GetSearchPlayForBraggingRights(); #ifdef USE_MVM_TOUR
int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex(); Assert( bMannUP || idxTour < 0 ); #endif // USE_MVM_TOUR
#ifdef USE_MVM_TOUR
uint32 nNotCompletedChallenges = ~0U; CTFParty *pParty = GTFGCClientSystem()->GetParty(); if ( pParty ) { for ( int i = 0 ; i < pParty->GetNumMembers() ; ++i ) { nNotCompletedChallenges &= ~pParty->Obj().members( i ).completed_missions(); } } else { if ( idxTour >= 0 ) { uint32 nTours = 0, nCompletedChallenge = 0; GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &nTours, &nCompletedChallenge );
nNotCompletedChallenges = ~nCompletedChallenge; } } #endif // USE_MVM_TOUR
for ( int i = 0 ; i < GetItemSchema()->GetMvmMissions().Count() ; ++i ) { const MvMMission_t &chal = GetItemSchema()->GetMvmMissions()[ i ];
// Cannot select non-MannUp missions in mann up mode
#ifdef USE_MVM_TOUR
int iBadgeSlot = (idxTour < 0) ? -1 : GetItemSchema()->GetMvmMissionBadgeSlotForTour( idxTour, i ); if ( bMannUP && iBadgeSlot < 0 ) continue; #else // new mm
bool bIsChallengeInMannUp = chal.m_unMannUpPoints > 0; if ( bMannUP && !bIsChallengeInMannUp ) continue; #endif // USE_MVM_TOUR
// Does this challenge fit the search criteria?
bool bSelect = false; switch ( idxChallenge ) { case k_iPopIndex_Any: bSelect = true; break; case k_iPopIndex_OnlyNotYetCompleted: #ifdef USE_MVM_TOUR
if ( iBadgeSlot >= 0 ) { int iChallengeBit = ( 1 << iBadgeSlot ); if ( nNotCompletedChallenges & iChallengeBit ) { bSelect = true; } } #endif // USE_MVM_TOUR
break;
case k_iPopIndex_AnyNormal: bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Normal ); break;
case k_iPopIndex_AnyIntermediate: bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Intermediate ); break;
case k_iPopIndex_AnyAdvanced: bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Advanced ); break;
case k_iPopIndex_AnyExpert: bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Expert ); break;
case k_iPopIndex_AnyHaunted: bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Haunted ); break;
default: Assert( false ); } result.SetMissionBySchemaIndex( i, bSelect ); } }
#ifdef ENABLE_GC_MATCHMAKING
Color s_colorBannedPlayerListItem( 250, 50, 45, 255 ); Color s_colorPlayerListItem( 255, 255, 255, 255 ); Color s_colorChatRemovedFromQueue( 200, 10, 10, 255 ); Color s_colorChatAddedToQueue( 10, 200, 10, 255 ); Color s_colorChatPlayerJoinedParty( 255, 255, 255, 255 ); Color s_colorChatPlayerJoinedPartyName( 200, 200, 10, 255 ); Color s_colorChatPlayerLeftParty( 255, 255, 255, 255 ); Color s_colorChatPlayerLeftPartyName( 200, 200, 10, 255 ); Color s_colorChatPlayerChatName( 200, 200, 10, 255 ); Color s_colorChatPlayerChatText( 180, 180, 180, 255 ); Color s_colorChatDefault( 180, 180, 180, 255 ); Color s_colorChallengeForegroundEnabled( 255, 255, 255, 255 ); Color s_colorChallengeForegroundHaunted( 135, 79, 173, 255 ); Color s_colorChallengeForegroundDisabled( 100, 100, 100, 128 ); Color s_colorChallengeHeader( 250, 114, 45, 255 );
static void GetPlayerNameForSteamID( wchar_t *wCharPlayerName, int nBufSizeBytes, const CSteamID &steamID ) { const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( steamID ); V_UTF8ToUnicode( pszName, wCharPlayerName, nBufSizeBytes ); }
CBaseLobbyPanel::CBaseLobbyPanel( vgui::Panel *pParent, CBaseLobbyContainerFrame* pContainer ) : vgui::PropertySheet( pParent, "LobbyPanel" ), m_sPersonaStateChangedCallback( this, &CBaseLobbyPanel::OnPersonaStateChanged ) , m_pContainer( pContainer ) { //ListenForGameEvent( "lobby_updated" );
ListenForGameEvent( "party_updated" ); ListenForGameEvent( "mm_lobby_chat" ); ListenForGameEvent( "mm_lobby_member_join" ); ListenForGameEvent( "mm_lobby_member_leave" );
m_iWritingPanel = 0;
m_pSearchActiveGroupBox = NULL; m_pSearchActiveTitleLabel = NULL; m_pSearchActivePenaltyLabel = NULL; m_pPartyHasLowPriority = NULL;
m_pJoinLateCheckButton = NULL; m_pJoinLateValueLabel = NULL;
m_pInviteButton = NULL; m_pChatLog = NULL; //m_nFirstMapShown = -1;
m_pImageList = NULL;
m_iImageIsBanned = -1; m_iImageRadioButtonYes = -1; m_iImageRadioButtonNo = -1; m_iImageCheckBoxDisabled = -1; m_iImageCheckBoxYes = -1; m_iImageCheckBoxNo = -1; m_iImageCheckBoxMixed = -1; m_iImageNew = -1; m_iImageNo = -1;
m_fontPlayerListItem = 0;
// Party
m_pPartyActiveGroupBox = new vgui::EditablePanel( this, "PartyActiveGroupBox" ); vgui::EditablePanel *pPartyGroupPanel = new vgui::EditablePanel( m_pPartyActiveGroupBox, "PartyGroupBox" ); m_pChatPlayerList = new vgui::SectionedListPanel( pPartyGroupPanel, "PartyPlayerList" ); m_pChatTextEntry = new ChatTextEntry( m_pPartyActiveGroupBox, "ChatTextEntry" ); Assert( m_pChatTextEntry ); m_pChatLog = new ChatLog( m_pPartyActiveGroupBox, "ChatLog" ); Assert( m_pChatLog );
m_mapAvatarsToImageList.SetLessFunc( DefLessFunc(int) );
m_eCurrentPartyState = CSOTFParty_State_UI;
m_flRefreshPlayerListTime = -1.f;
m_pToolTip = new CMainMenuToolTip( this ); vgui::EditablePanel* pToolTipEmbeddedPanel = new vgui::EditablePanel( this, "TooltipPanel" ); pToolTipEmbeddedPanel->SetKeyBoardInputEnabled( false ); pToolTipEmbeddedPanel->SetMouseInputEnabled( false ); m_pToolTip->SetEmbeddedPanel( pToolTipEmbeddedPanel ); m_pToolTip->SetTooltipDelay( 0 ); }
CBaseLobbyPanel::~CBaseLobbyPanel() { delete m_pImageList; m_pImageList = NULL; }
void CBaseLobbyPanel::OnClickedOnPlayer() { int iSelected = m_pChatPlayerList->GetSelectedItem(); //m_pChatPlayerList->ClearSelection();
if ( iSelected < 0 ) return; CSteamID steamID = SteamIDFromDecimalString( m_pChatPlayerList->GetItemData( iSelected )->GetString( "steamid", "" ) ); if ( !steamID.IsValid() ) return;
vgui::Menu *menu = new vgui::Menu(this, "ContextMenu");
int x, y; vgui::input()->GetCursorPos(x, y); menu->SetPos(x, y);
wchar_t wszLocalized[512]; char szLocalized[512]; g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Context_Trade" ), 0 ); g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof( szLocalized ) );
menu->AddMenuItem( szLocalized, new KeyValues( "TradeWithUser", "steamid", CFmtStr( "%llu", steamID.ConvertToUint64() ).Access() ), this );
menu->SetVisible(true); }
void CBaseLobbyPanel::SetMatchmakingModeBackground() { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
// Get the background panel.
vgui::ImagePanel* pModeBackgroundImage = FindControl< vgui::ImagePanel >( "ModeBackgroundImage", true ); if ( !pModeBackgroundImage ) return;
const char* pszImageName = NULL; const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( GetMatchGroup() ); if ( pMatchDesc && pMatchDesc->m_pProgressionDesc ) { // Get the level of the local player, and pull the background image out of the level
const LevelInfo_t& level = pMatchDesc->m_pProgressionDesc->YieldingGetLevelForSteamID( steamapicontext->SteamUser()->GetSteamID() ); pszImageName = level.m_pszLobbyBackgroundImage; }
// Set the image name, if we got one, into the panel
if ( pszImageName ) { pModeBackgroundImage->SetImage( pszImageName ); }
// Only show if we got one (MvM doesn't have any)
pModeBackgroundImage->SetVisible( pszImageName != NULL ); }
//-----------------------------------------------------------------------------
void CBaseLobbyPanel::FireGameEvent( IGameEvent *event ) { if ( !IsVisible() || !m_pContainer->IsVisible() ) return;
const char *pszEventName = event->GetName(); if ( !Q_stricmp( pszEventName, "party_updated" ) ) {
CTFParty *pParty = GTFGCClientSystem()->GetParty(); if ( pParty ) { if ( m_eCurrentPartyState != pParty->GetState() ) { wchar_t wszLocalized[512];
switch ( pParty->GetState() ) { case CSOTFParty_State_UI: m_pChatLog->InsertColorChange( s_colorChatRemovedFromQueue ); g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_RemovedFromQueue" ), 0 ); m_pChatLog->InsertString( wszLocalized ); break;
case CSOTFParty_State_FINDING_MATCH: m_pChatLog->InsertColorChange( s_colorChatAddedToQueue ); g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_AddedToQueue" ), 0 ); m_pChatLog->InsertString( wszLocalized ); break;
default: Assert( false ); case CSOTFParty_State_IN_MATCH: break; } m_eCurrentPartyState = pParty->GetState(); } } else { m_eCurrentPartyState = CSOTFParty_State_UI; }
UpdatePlayerList(); WriteGameSettingsControls(); return; }
if ( !Q_stricmp( pszEventName, "mm_lobby_chat" ) ) { CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) );
const char *pszText = event->GetString( "text", "" ); int l = V_strlen( pszText ); if ( l > 0 ) { int nBufSize = l * sizeof(wchar_t) + 4; wchar_t *wText = (wchar_t *)stackalloc( nBufSize ); V_UTF8ToUnicode( pszText, wText, nBufSize ); switch ( event->GetInt( "type", CTFGCClientSystem::k_eLobbyMsg_UserChat ) ) { default: Assert( !"Unknown chat message type" ); case CTFGCClientSystem::k_eLobbyMsg_SystemMsgFromLeader: m_pChatLog->InsertColorChange( s_colorChatDefault ); m_pChatLog->InsertString( wText ); m_pChatLog->InsertString("\n"); break;
case CTFGCClientSystem::k_eLobbyMsg_UserChat: {
wchar_t wCharPlayerName[ 128 ]; GetPlayerNameForSteamID( wCharPlayerName, sizeof(wCharPlayerName), steamID ); m_pChatLog->InsertColorChange( s_colorChatPlayerChatName ); m_pChatLog->InsertString( wCharPlayerName ); m_pChatLog->InsertString( ": " ); m_pChatLog->InsertColorChange( s_colorChatPlayerChatText ); m_pChatLog->InsertString( wText ); m_pChatLog->InsertString("\n"); } break; } }
return; }
if ( !Q_stricmp( pszEventName, "mm_lobby_member_join" ) ) { CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) );
bool bSolo = false; if ( steamID == steamapicontext->SteamUser()->GetSteamID() ) { m_pChatLog->SetText(""); bSolo = ( event->GetInt( "solo", 0 ) != 0 ); }
wchar_t wszLocalized[512];
// An empty lobby by ourselves?
if ( bSolo ) { m_pChatLog->InsertColorChange( s_colorChatDefault );
g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_StartSearchChat" ), 0 ); m_pChatLog->InsertString( wszLocalized );
g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_InviteFriendsChat" ), 0 ); m_pChatLog->InsertString( wszLocalized ); } else { wchar_t wCharPlayerName[128]; m_pChatLog->InsertColorChange( s_colorChatPlayerJoinedPartyName ); GetPlayerNameForSteamID( wCharPlayerName, sizeof( wCharPlayerName ), steamID ); m_pChatLog->InsertColorChange( s_colorChatPlayerJoinedParty );
g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_PlayerJoinedPartyChat" ), 1, wCharPlayerName ); m_pChatLog->InsertString( wszLocalized ); }
UpdatePlayerList();
return; }
if ( !Q_stricmp( pszEventName, "mm_lobby_member_leave" ) ) { CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) ); wchar_t wCharPlayerName[ 128 ]; GetPlayerNameForSteamID( wCharPlayerName, sizeof(wCharPlayerName), steamID ); m_pChatLog->InsertColorChange( s_colorChatPlayerLeftParty );
wchar_t wszLocalized[512]; g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_PlayerLeftPartyChat" ), 1, wCharPlayerName ); m_pChatLog->InsertString( wszLocalized );
UpdatePlayerList(); WriteGameSettingsControls();
return; }
Assert( false ); }
void CBaseLobbyPanel::OnCommand( const char *command ) { if ( FStrEq( command, "invite" ) ) { GTFGCClientSystem()->RequestActivateInvite(); } else if ( FStrEq( command, "open_charinfo" ) ) { engine->ClientCmd_Unrestricted( "open_econui_backpack" ); } else { // What other commands are there?
Assert( false ); } }
bool CBaseLobbyPanel::IsAnyoneBanned( RTime32 &rtimeExpire ) const { bool bBanned = false; RTime32 rtimeHighest = 0;
// This only matters if we're searching for a mannup or ladder game
CTFParty *pParty = GTFGCClientSystem()->GetParty(); if ( pParty && ( !pParty->GetSearchPlayForBraggingRights() && !IsLadderGroup( pParty->GetMatchGroup() ) ) ) { return false; }
for( int i=0; i<m_vecPlayers.Count(); ++i ) { if ( m_vecPlayers[i].m_bIsBanned ) { bBanned = true;
if ( m_vecPlayers[i].m_rtimeBanExpire > rtimeHighest ) { rtimeHighest = m_vecPlayers[i].m_rtimeBanExpire; } } }
rtimeExpire = rtimeHighest; return bBanned; }
const CBaseLobbyPanel::LobbyPlayerInfo* CBaseLobbyPanel::GetLobbyPlayerInfo( CSteamID &steamID ) const { for ( int i = 0; i < m_vecPlayers.Count(); ++i ) { if ( m_vecPlayers[i].m_steamID == steamID ) { return &m_vecPlayers[i]; } }
Assert( false ); return NULL; }
bool CBaseLobbyPanel::IsAnyoneLowPriority( RTime32 &rtimeExpire ) const { bool bLowPriority = false; RTime32 rtimeHighest = 0;
CTFParty *pParty = GTFGCClientSystem()->GetParty(); if ( pParty && !pParty->GetSearchPlayForBraggingRights() && !IsLadderGroup( pParty->GetMatchGroup() ) ) return false;
for ( int i = 0; i < m_vecPlayers.Count(); ++i ) { if ( m_vecPlayers[i].m_bIsLowPriority ) { bLowPriority = true;
if ( m_vecPlayers[i].m_rtimeLowPriorityExpire > rtimeHighest ) { rtimeHighest = m_vecPlayers[i].m_rtimeLowPriorityExpire; } } }
rtimeExpire = rtimeHighest; return bLowPriority; }
void CBaseLobbyPanel::UpdateControls() { WriteGameSettingsControls(); WriteStatusControls(); UpdatePlayerList(); }
void CBaseLobbyPanel::OnCheckButtonChecked( vgui::Panel *panel ) { if ( m_iWritingPanel > 0 ) return; if ( panel == m_pJoinLateCheckButton ) { if ( BIsPartyLeader() && GCClientSystem()->BConnectedtoGC() ) { tf_matchmaking_join_in_progress.SetValue( m_pJoinLateCheckButton->IsSelected() ? 1 : 0 ); GTFGCClientSystem()->SetSearchJoinLate( m_pJoinLateCheckButton->IsSelected() ); } else { WriteGameSettingsControls(); } } }
void CBaseLobbyPanel::OnTradeWithUser( KeyValues* params ) { CSteamID steamID = SteamIDFromDecimalString( params->GetString( "steamid", "" ) ); if ( !steamID.IsValid() ) return; steamapicontext->SteamFriends()->ActivateGameOverlayToUser( "jointrade", steamID ); }
void CBaseLobbyPanel::OnItemLeftClick( vgui::Panel* panel ) { if ( m_iWritingPanel > 0 ) return; m_pChatTextEntry->RequestFocus(); if ( panel == m_pChatPlayerList ) { OnClickedOnPlayer(); } }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CBaseLobbyPanel::WriteStatusControls() { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
enum EDisabledState { DISABLED_NONE, DISABLED_NO_GC, DISABLED_MATCH_IN_PROGRESS };
EDisabledState eDisabled = DISABLED_NONE;
if ( GTFGCClientSystem()->BHaveLiveMatch() ) { eDisabled = DISABLED_MATCH_IN_PROGRESS; }
if ( !GCClientSystem()->BConnectedtoGC() || ( GTFGCClientSystem()->GetParty() && GTFGCClientSystem()->GetParty()->BOffline() ) ) { eDisabled = DISABLED_NO_GC; }
SetControlVisible( "NoGCGroupBox", eDisabled == DISABLED_NO_GC, true ); SetControlVisible( "MatchInProgressGroupBox", eDisabled == DISABLED_MATCH_IN_PROGRESS, true );
if ( GTFGCClientSystem()->GetWizardStep() == TF_Matchmaking_WizardStep_SEARCHING ) { m_pSearchActiveGroupBox->SetVisible( true );
const CMsgMatchmakingProgress &progress = GTFGCClientSystem()->m_msgMatchmakingProgress; wchar_t wszCount[32]; CUtlVector<vgui::Label *> vecNearbyFields; vgui::Label *pNearbyColumnHead = dynamic_cast<vgui::Label *>( FindChildByName( "NearbyColumnHead", true ) ); Assert( pNearbyColumnHead ); vecNearbyFields.AddToTail( pNearbyColumnHead );
#define DO_FIELD( protobufname, labelname, bNearby ) \
vgui::Label *p##labelname = dynamic_cast<vgui::Label *>( FindChildByName( #labelname, true ) ); \ Assert( p##labelname ); \ if ( p##labelname ) \ { \ if ( progress.has_##protobufname() ) \ { \ _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", progress.protobufname() ); \ p##labelname->SetText( wszCount ); \ if ( bNearby ) bHasAnyNearbyData = true; \ } \ else \ { \ p##labelname->SetText( "#TF_Matchmaking_NoData" ); \ } \ if ( bNearby ) vecNearbyFields.AddToTail( p##labelname ); \ }
bool bHasAnyNearbyData = false; DO_FIELD( matching_worldwide_searching_players, PlayersSearchingMatchingWorldwideValue, false ) DO_FIELD( matching_near_you_searching_players, PlayersSearchingMatchingNearbyValue, true ) DO_FIELD( matching_worldwide_active_players, PlayersInGameMatchingWorldwideValue, false ) DO_FIELD( matching_near_you_active_players, PlayersInGameMatchingNearbyValue, true ) DO_FIELD( matching_worldwide_empty_gameservers, EmptyGameserversMatchingWorldwideValue, false ) DO_FIELD( matching_near_you_empty_gameservers, EmptyGameserversMatchingNearbyValue, true ) DO_FIELD( total_worldwide_searching_players, PlayersSearchingTotalWorldwideValue, false ) DO_FIELD( total_near_you_searching_players, PlayersSearchingTotalNearbyValue, true ) DO_FIELD( total_worldwide_active_players, PlayersInGameTotalWorldwideValue, false ) DO_FIELD( total_near_you_active_players, PlayersInGameTotalNearbyValue, true )
FOR_EACH_VEC( vecNearbyFields, i ) { vecNearbyFields[i]->SetVisible( bHasAnyNearbyData ); }
// Show the low priority message? This only really applies to ladder games for now.
RTime32 rtimeExpire = 0; bool bShowTimer = IsAnyoneLowPriority( rtimeExpire ); if ( bShowTimer ) { CRTime timeExpire( rtimeExpire ); timeExpire.SetToGMT( false ); char time_buf[k_RTimeRenderBufferSize]; if ( m_pPartyHasLowPriority ) { m_pPartyHasLowPriority->SetDialogVariable( "penaltytimer", CFmtStr( "Expires: %s", ( ( rtimeExpire > 0 ) ? timeExpire.Render( time_buf ) : "" ) ) ); } if ( m_pSearchActivePenaltyLabel ) { m_pSearchActivePenaltyLabel->SetText( "#TF_Matchmaking_PartyLowPriority" ); } } if ( m_pPartyHasLowPriority ) { m_pPartyHasLowPriority->SetVisible( bShowTimer ); } if ( m_pSearchActivePenaltyLabel ) { m_pSearchActivePenaltyLabel->SetVisible( bShowTimer ); }
// HOLY CHEESEBALL BUSY INDICATOR
const wchar_t *pwszEllipses = &L"....."[ 4 - ( (unsigned)Plat_FloatTime() % 5U ) ]; wchar_t wszLocalized[512]; g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_Searching" ), 1, pwszEllipses ); if ( m_pSearchActiveTitleLabel ) { m_pSearchActiveTitleLabel->SetText( wszLocalized ); } } else { m_pSearchActiveGroupBox->SetVisible( false ); } }
void CBaseLobbyPanel::WriteGameSettingsControls() { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
// 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; }
SetMatchmakingModeBackground();
bool bLeader = BIsPartyLeader(); bool bInUIState = BIsPartyInUIState();
m_pJoinLateCheckButton->ToggleButton::SetSelected( GTFGCClientSystem()->GetSearchJoinLate() ); // !KLUDGE! call base to avoid firing the signal
bool bShowLateJoin = ShouldShowLateJoin(); m_pJoinLateCheckButton->SetVisible( bShowLateJoin && bLeader ); m_pJoinLateValueLabel->SetText( GTFGCClientSystem()->GetSearchJoinLate() ? "#TF_Matchmaking_SearchForAll" : "#TF_Matchmaking_SearchForNew" ); m_pJoinLateValueLabel->SetVisible( bShowLateJoin && !bLeader ); //m_pJoinLateValueLabel->SetEnabled( bInUIState );
m_pInviteButton->SetVisible( bInUIState && ( m_vecPlayers.Count() < k_nTFPartyMaxSize ) );
m_pChatTextEntry->RequestFocus(); }
//-----------------------------------------------------------------------------
// Purpose: Updates the player list
//-----------------------------------------------------------------------------
void CBaseLobbyPanel::UpdatePlayerList() { tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
if ( !IsVisible() || !m_pContainer->IsVisible() ) return;
m_pChatPlayerList->ClearSelection(); m_pChatPlayerList->RemoveAll(); m_vecPlayers.RemoveAll();
bool bLadderGame = GTFGCClientSystem()->GetSearchMode() == TF_Matchmaking_LADDER && IsLadderGroup( (EMatchGroup)GTFGCClientSystem()->GetLadderType() ); const IMatchGroupDescription *pMatchDesc = GetMatchGroupDescription( GetMatchGroup() ); EMMPenaltyPool ePenaltyPool = pMatchDesc ? pMatchDesc->m_params.m_ePenaltyPool : eMMPenaltyPool_Invalid;
if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL ) return;
// Locate party, if we have one.
CTFParty *pParty = GTFGCClientSystem()->GetParty();
if ( pParty == NULL ) { LobbyPlayerInfo p; p.m_steamID = steamapicontext->SteamUser()->GetSteamID(); p.m_sName = steamapicontext->SteamFriends()->GetPersonaName(); p.m_bHasTicket = GTFGCClientSystem()->BLocalPlayerInventoryHasMvmTicket(); p.m_bSquadSurplus = GTFGCClientSystem()->GetLocalPlayerSquadSurplus(); #ifdef USE_MVM_TOUR
int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex(); if ( idxTour < 0 || !GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &p.m_nBadgeLevel, &p.m_nCompletedChallenges ) ) { p.m_nBadgeLevel = 0; p.m_nCompletedChallenges = 0; } #endif // USE_MVM_TOUR
p.m_pAvatarImage = NULL; p.m_bHasCompetitiveAccess = GTFGCClientSystem()->BHasCompetitiveAccess(); CSOTFLadderData *pData = GetLocalPlayerLadderData( (EMatchGroup)GTFGCClientSystem()->GetLadderType() ); p.m_unLadderRank = ( pData ? pData->Obj().rank() : 1u );
uint32 unExperienceLevel = 1u; const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL; if ( pData && pProgressionDesc && pMatchDesc->m_params.m_eMatchType == MATCH_TYPE_CASUAL ) { LevelInfo_t levelInfo = pProgressionDesc->GetLevelForExperience( pData->Obj().experience() ); unExperienceLevel = levelInfo.m_nLevelNum; } p.m_unExperienceLevel = unExperienceLevel;
CEconGameAccountClient *pGameAccountClient = NULL; if ( InventoryManager() && TFInventoryManager()->GetLocalTFInventory() && TFInventoryManager()->GetLocalTFInventory()->GetSOC() ) { pGameAccountClient = TFInventoryManager()->GetLocalTFInventory()->GetSOC()->GetSingleton<CEconGameAccountClient>(); }
p.m_bIsBanned = false; p.m_rtimeBanExpire = 0; p.m_rtimeLowPriorityExpire = 0; p.m_bIsLowPriority = false; if ( pGameAccountClient && ePenaltyPool != eMMPenaltyPool_Invalid ) { switch ( ePenaltyPool ) { case eMMPenaltyPool_Casual: p.m_rtimeBanExpire = pGameAccountClient->Obj().matchmaking_casual_ban_expiration(); p.m_rtimeLowPriorityExpire = pGameAccountClient->Obj().matchmaking_casual_low_priority_expiration(); p.m_bIsBanned = p.m_rtimeBanExpire > CRTime::RTime32TimeCur(); p.m_bIsLowPriority = p.m_rtimeLowPriorityExpire > CRTime::RTime32TimeCur(); break; case eMMPenaltyPool_Ranked: p.m_rtimeBanExpire = pGameAccountClient->Obj().matchmaking_ranked_ban_expiration(); p.m_rtimeLowPriorityExpire = pGameAccountClient->Obj().matchmaking_ranked_low_priority_expiration(); p.m_bIsBanned = p.m_rtimeBanExpire > CRTime::RTime32TimeCur(); p.m_bIsLowPriority = p.m_rtimeLowPriorityExpire > CRTime::RTime32TimeCur(); break; default: Assert( false ); } }
// !TEST!
//p.m_bIsBanned = true;
//for (int i = 0 ; i < 6 ; ++i) // !TEST!
m_vecPlayers.AddToTail( p ); } else { for ( int i = 0 ; i < pParty->GetNumMembers() ; ++i ) { LobbyPlayerInfo p; p.m_steamID = pParty->GetMember( i ); p.m_sName = steamapicontext->SteamFriends()->GetFriendPersonaName( p.m_steamID ); if ( p.m_sName.IsEmpty() ) continue; p.m_bHasTicket = pParty->Obj().members( i ).owns_ticket(); p.m_nBadgeLevel = pParty->Obj().members( i ).badge_level(); p.m_nCompletedChallenges = pParty->Obj().members( i ).completed_missions(); p.m_bSquadSurplus = pParty->Obj().members( i ).squad_surplus(); p.m_pAvatarImage = NULL; p.m_bIsBanned = pParty->Obj().members( i ).is_banned(); p.m_bHasCompetitiveAccess = pParty->Obj().members( i ).competitive_access(); p.m_unLadderRank = pParty->Obj().members( i ).ladder_rank(); p.m_rtimeBanExpire = pParty->Obj().matchmaking_ban_time(); p.m_rtimeLowPriorityExpire = pParty->Obj().matchmaking_low_priority_time(); p.m_bIsLowPriority = pParty->Obj().members( i ).is_low_priority();
uint32 unExperienceLevel = 1u; const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL; if ( pProgressionDesc && pMatchDesc->m_params.m_eMatchType == MATCH_TYPE_CASUAL ) { LevelInfo_t levelInfo = pProgressionDesc->GetLevelForExperience( pParty->Obj().members( i ).experience() ); unExperienceLevel = levelInfo.m_nLevelNum; } p.m_unExperienceLevel = unExperienceLevel;
if ( p.m_steamID == pParty->GetLeader() ) { m_vecPlayers.AddToHead( p ); } else { m_vecPlayers.AddToTail( p ); } } }
for( int i = 0; i < m_vecPlayers.Count(); ++i ) { KeyValues *pKeyValues = new KeyValues( "data" ); CUtlString sName; if ( i == 0 && m_vecPlayers.Count() > 1 ) { sName.Format( "%s (leader)", m_vecPlayers[i].m_sName.String() ); // !FIXME! Localize
} else { sName = m_vecPlayers[i].m_sName; } pKeyValues->SetString( "name", sName );
pKeyValues->SetString( "steamid", CFmtStr( "%llu", m_vecPlayers[i].m_steamID.ConvertToUint64() ).Access() ); pKeyValues->SetInt( "badge_level", Max( 1U, m_vecPlayers[i].m_nBadgeLevel ) );
ApplyChatUserSettings( m_vecPlayers[ i ], pKeyValues );
pKeyValues->SetInt( "is_banned", ( m_vecPlayers[i].m_bIsBanned || m_vecPlayers[i].m_bIsLowPriority ) ? m_iImageIsBanned : 0 );
// See if the avatar's changed
int iAvatar = steamapicontext->SteamFriends()->GetSmallFriendAvatar( m_vecPlayers[i].m_steamID ); int iIndex = m_mapAvatarsToImageList.Find( iAvatar ); if ( iIndex == m_mapAvatarsToImageList.InvalidIndex() ) { CAvatarImage *pImage = new CAvatarImage(); pImage->SetAvatarSteamID( m_vecPlayers[i].m_steamID ); pImage->SetDrawFriend( false ); // you can only invite friends, this isn't that useful
pImage->SetAvatarSize( m_iAvatarWidth, m_iAvatarWidth ); int iImageIndex = m_pImageList->AddImage( pImage );
iIndex = m_mapAvatarsToImageList.Insert( iAvatar, iImageIndex ); } pKeyValues->SetInt( "avatar", m_mapAvatarsToImageList[iIndex] ); CAvatarImage *pAvIm = (CAvatarImage *)m_pImageList->GetImage( m_mapAvatarsToImageList[iIndex] ); pAvIm->UpdateFriendStatus(); m_vecPlayers[i].m_pAvatarImage = pAvIm; if ( bLadderGame ) { if ( !m_vecPlayers[i].m_bHasCompetitiveAccess ) { pKeyValues->SetInt( "has_competitive_access", m_iImageNo ); } }
pKeyValues->SetInt( "ladder_rank", m_vecPlayers[i].m_unLadderRank ); pKeyValues->SetInt( "experience_level", m_vecPlayers[i].m_unExperienceLevel );
int itemID = m_pChatPlayerList->AddItem( 0, pKeyValues ); m_pChatPlayerList->SetItemFont( itemID, m_fontPlayerListItem ); m_pChatPlayerList->SetItemFgColor( itemID, ( m_vecPlayers[i].m_bIsBanned || m_vecPlayers[i].m_bIsLowPriority ) ? s_colorBannedPlayerListItem : s_colorPlayerListItem );
pKeyValues->deleteThis(); }
// force the list to PerformLayout() now so we can update our medal images
m_pChatPlayerList->InvalidateLayout( true );
int iPanelCount = 0; // This only works in 6v6 Comp and 12v12 Casual for now
if ( ( GetMatchGroup() == k_nMatchGroup_Ladder_6v6 ) || ( GetMatchGroup() == k_nMatchGroup_Casual_12v12 ) ) { int nColumn = m_pChatPlayerList->GetColumnIndexByName( 0, "rank" );
for ( int nRow = 0; nRow < m_pChatPlayerList->GetItemCount(); nRow++ ) { KeyValues *pKeyValues = m_pChatPlayerList->GetItemData( nRow ); if ( !pKeyValues ) continue;
CSteamID steamID = SteamIDFromDecimalString( pKeyValues->GetString( "steamid", "0" ) ); if ( !steamID.IsValid() ) continue;
uint32 unLevel = pKeyValues->GetInt( "ladder_rank" ); if ( GetMatchGroup() == k_nMatchGroup_Casual_12v12 ) { unLevel = pKeyValues->GetInt( "experience_level" ); }
// Create a panel if we need one
if ( iPanelCount >= m_vecChatBadges.Count() ) { m_vecChatBadges.AddToTail(); m_vecChatBadges[iPanelCount].m_pBadgeModel = vgui::SETUP_PANEL( new CTFBadgePanel( m_pChatPlayerList, "Model" ) ); m_vecChatBadges[iPanelCount].m_pBadgeModel->SetZPos( 9999 ); m_vecChatBadges[iPanelCount].m_nShownLevel = 0u; }
// Move it into place and resize. This is terrible, but VGUI has forced my hand
int nX, nY, nWide, nTall; m_pChatPlayerList->GetMaxCellBounds( nRow, nColumn, nX, nY, nWide, nTall ); int nSideLength = Max( nWide, nTall ); nX = ( nX + ( nWide / 2 ) ) - ( nSideLength / 2 ); nY = ( nY + ( nTall / 2 ) ) - ( nSideLength / 2 );
m_vecChatBadges[iPanelCount].m_pBadgeModel->SetBounds( nX, nY, nSideLength, nSideLength );
// Different dude in the slot or their level is different? Update the medal model
if ( m_vecChatBadges[iPanelCount].m_steamIDOwner != steamID || m_vecChatBadges[iPanelCount].m_nShownLevel != unLevel ) { m_vecChatBadges[iPanelCount].m_steamIDOwner = steamID;
const LevelInfo_t& level = pMatchDesc->m_pProgressionDesc->GetLevelByNumber( unLevel ); m_vecChatBadges[iPanelCount].m_pBadgeModel->SetupBadge( pMatchDesc->m_pProgressionDesc, level );
wchar_t wszOutString[128]; char szLocalized[512]; wchar_t wszCount[16]; _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", level.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( level.m_pszLevelTitle ) ); g_pVGuiLocalize->ConvertUnicodeToANSI( wszOutString, szLocalized, sizeof( szLocalized ) );
m_vecChatBadges[iPanelCount].m_pBadgeModel->SetTooltip( m_pToolTip, szLocalized ); m_vecChatBadges[iPanelCount].m_nShownLevel = level.m_nLevelNum; m_vecChatBadges[iPanelCount].m_pBadgeModel->InvalidateLayout( true, true ); m_vecChatBadges[iPanelCount].m_pBadgeModel->SetVisible( true ); }
iPanelCount++; } }
for ( ; iPanelCount < m_vecChatBadges.Count(); ++iPanelCount ) { m_vecChatBadges[iPanelCount].m_pBadgeModel->SetVisible( false ); m_vecChatBadges[iPanelCount].m_nShownLevel = 0u; // Will cause the badge to refresh when it gets a player
} }
//-----------------------------------------------------------------------------
void CBaseLobbyPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme );
LoadControlSettings( GetResFile() );
m_pSearchActiveGroupBox = dynamic_cast<vgui::EditablePanel *>(FindChildByName( "SearchActiveGroupBox", true )); Assert( m_pSearchActiveGroupBox ); m_pSearchActiveTitleLabel = dynamic_cast<vgui::Label *>(FindChildByName( "SearchActiveTitle", true )); Assert( m_pSearchActiveTitleLabel ); m_pSearchActivePenaltyLabel = dynamic_cast<vgui::Label *>( FindChildByName( "PartyHasLowPriorityLabel", true ) ); Assert( m_pSearchActivePenaltyLabel );
m_pPartyHasLowPriority = dynamic_cast<vgui::EditablePanel *>( FindChildByName( "PartyHasLowPriorityGroupBox", true ) ); Assert( m_pPartyHasLowPriority );
m_pJoinLateCheckButton = dynamic_cast<vgui::CheckButton *>(FindChildByName( "JoinLateCheckButton", true )); Assert( m_pJoinLateCheckButton ); m_pJoinLateValueLabel = dynamic_cast<vgui::Label *>(FindChildByName( "JoinLateValueLabel", true )); Assert( m_pJoinLateValueLabel );
m_pInviteButton = dynamic_cast<vgui::Button *>(FindChildByName( "InviteButton", true )); Assert( m_pInviteButton );
delete m_pImageList; m_pImageList = new vgui::ImageList( false );
m_iImageIsBanned = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_timeout_active", true ) ); m_pImageList->GetImage( m_iImageIsBanned )->SetSize( m_iBannedWidth, m_iBannedWidth ); m_iImageCheckBoxDisabled = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_disabled", true ) ); m_pImageList->GetImage( m_iImageCheckBoxDisabled )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageCheckBoxYes = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_yes", true ) ); m_pImageList->GetImage( m_iImageCheckBoxYes )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageCheckBoxNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_no", true ) ); m_pImageList->GetImage( m_iImageCheckBoxNo )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageCheckBoxMixed = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_mixed", true ) ); m_pImageList->GetImage( m_iImageCheckBoxMixed )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageRadioButtonYes = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_radio_button_yes", true ) ); m_pImageList->GetImage( m_iImageRadioButtonYes )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageRadioButtonNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_radio_button_no", true ) ); m_pImageList->GetImage( m_iImageRadioButtonNo )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) ); m_iImageNew = m_pImageList->AddImage( vgui::scheme()->GetImage( "new", true ) ); m_pImageList->GetImage( m_iImageNew )->SetSize( m_iNewWidth, m_iNewWidth * ( 3.75f / 4.0f ) );
m_iImageNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "hud/vote_no", true ) );
m_mapAvatarsToImageList.RemoveAll(); m_pChatPlayerList->SetImageList( m_pImageList, false ); m_pChatPlayerList->SetVisible( true );
//
// Populate the challenge list
//
m_pJoinLateCheckButton->AddActionSignalTarget( this ); m_pInviteButton->AddActionSignalTarget( this ); m_pChatPlayerList->AddActionSignalTarget( this );
m_fontPlayerListItem = pScheme->GetFont( "DefaultSmall", true );
//
// Populate the player list
//
m_pChatPlayerList->SetVerticalScrollbar( false ); m_pChatPlayerList->RemoveAll(); m_pChatPlayerList->RemoveAllSections(); m_pChatPlayerList->AddSection( 0, "Players" ); m_pChatPlayerList->SetSectionAlwaysVisible( 0, true ); m_pChatPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) ); m_pChatPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) ); m_pChatPlayerList->SetBorder( NULL ); m_pChatPlayerList->SetClickable( false ); //m_pChatPlayerList->SetClickable( true ); // enable context menu to trade / kick?
bool bPartyLeader = BIsPartyLeader() && GCClientSystem()->BConnectedtoGC();
if ( bPartyLeader ) { extern bool TF_IsHolidayActive( int eHoliday ); bool bHalloween = TF_IsHolidayActive( kHoliday_Halloween ); static bool bForcedOnce = false; if ( bHalloween && !bForcedOnce ) { GTFGCClientSystem()->SetQuickplayGameType( kGameCategory_Event247 ); bForcedOnce = true; } }
if ( bPartyLeader ) { GTFGCClientSystem()->SetSearchJoinLate( tf_matchmaking_join_in_progress.GetBool() ); } }
void CBaseLobbyPanel::PerformLayout() { BaseClass::PerformLayout();
WriteGameSettingsControls(); UpdatePlayerList(); }
void CBaseLobbyPanel::OnItemContextMenu( vgui::Panel* panel ) { if ( m_iWritingPanel > 0 ) return; m_pChatTextEntry->RequestFocus(); if ( panel == m_pChatPlayerList ) { OnClickedOnPlayer(); return; } }
//-----------------------------------------------------------------------------
// Command to launch the lobby UI, connecting to a particular lobby
//-----------------------------------------------------------------------------
static void CL_ConnectLobby( const CCommand &args ) { if ( args.ArgC() < 2 ) { Warning( "connect_lobby missing LobbyID argument\n" ); return; } uint64 ulSteamID = 0; sscanf( args.Arg( 1 ), "%lld", &ulSteamID ); CSteamID steamIDLobby( ulSteamID ); if ( !steamIDLobby.IsValid() || !steamIDLobby.IsLobby() ) { Warning( "connect_lobby passed invalid LobbyID '%s'\n", args.Arg( 1 ) ); return; }
GTFGCClientSystem()->AcceptFriendInviteToJoinLobby( steamIDLobby ); }
void OnSteamGameLobbyJoinRequested( GameLobbyJoinRequested_t *pInfo );
static ConCommand connect_lobby_command( "connect_lobby", &CL_ConnectLobby, "<64-bit lobby ID> Accept friend invite, connecting to specified Steam lobby and joining the corresponding search party" );
#endif // #ifdef ENABLE_GC_MATCHMAKING
|