Team Fortress 2 Source Code as on 22/4/2020
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.

1107 lines
38 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_party.h"
  8. #include "tf_item_inventory.h"
  9. #include "vgui_controls/PropertySheet.h"
  10. #include "vgui_controls/SectionedListPanel.h"
  11. #include "vgui/IInput.h"
  12. #include <vgui_controls/ImageList.h>
  13. #include "vgui_avatarimage.h"
  14. #include "tf_ladder_data.h"
  15. #include "vgui_controls/Menu.h"
  16. #include "tf_match_description.h"
  17. #include "tf_badge_panel.h"
  18. #include "tf_controls.h"
  19. #include "tf_lobbypanel.h"
  20. #include "tf_lobby_container_frame.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include <tier0/memdbgon.h>
  23. 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." );
  24. const int k_iPopIndex_Any = -1000;
  25. const int k_iPopIndex_OnlyNotYetCompleted = -1001;
  26. const int k_iPopIndex_AnyNormal = -1002;
  27. const int k_iPopIndex_AnyIntermediate = -1003;
  28. const int k_iPopIndex_AnyAdvanced = -1004;
  29. const int k_iPopIndex_AnyExpert = -1005;
  30. const int k_iPopIndex_AnyHaunted = -1006;
  31. static void GetMvmChallengeSet( int idxChallenge, CMvMMissionSet &result )
  32. {
  33. result.Clear();
  34. if ( idxChallenge >= 0 )
  35. {
  36. result.SetMissionBySchemaIndex( idxChallenge, true );
  37. return;
  38. }
  39. bool bMannUP = GTFGCClientSystem()->GetSearchPlayForBraggingRights();
  40. #ifdef USE_MVM_TOUR
  41. int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  42. Assert( bMannUP || idxTour < 0 );
  43. #endif // USE_MVM_TOUR
  44. #ifdef USE_MVM_TOUR
  45. uint32 nNotCompletedChallenges = ~0U;
  46. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  47. if ( pParty )
  48. {
  49. for ( int i = 0 ; i < pParty->GetNumMembers() ; ++i )
  50. {
  51. nNotCompletedChallenges &= ~pParty->Obj().members( i ).completed_missions();
  52. }
  53. }
  54. else
  55. {
  56. if ( idxTour >= 0 )
  57. {
  58. uint32 nTours = 0, nCompletedChallenge = 0;
  59. GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &nTours, &nCompletedChallenge );
  60. nNotCompletedChallenges = ~nCompletedChallenge;
  61. }
  62. }
  63. #endif // USE_MVM_TOUR
  64. for ( int i = 0 ; i < GetItemSchema()->GetMvmMissions().Count() ; ++i )
  65. {
  66. const MvMMission_t &chal = GetItemSchema()->GetMvmMissions()[ i ];
  67. // Cannot select non-MannUp missions in mann up mode
  68. #ifdef USE_MVM_TOUR
  69. int iBadgeSlot = (idxTour < 0) ? -1 : GetItemSchema()->GetMvmMissionBadgeSlotForTour( idxTour, i );
  70. if ( bMannUP && iBadgeSlot < 0 )
  71. continue;
  72. #else // new mm
  73. bool bIsChallengeInMannUp = chal.m_unMannUpPoints > 0;
  74. if ( bMannUP && !bIsChallengeInMannUp )
  75. continue;
  76. #endif // USE_MVM_TOUR
  77. // Does this challenge fit the search criteria?
  78. bool bSelect = false;
  79. switch ( idxChallenge )
  80. {
  81. case k_iPopIndex_Any:
  82. bSelect = true;
  83. break;
  84. case k_iPopIndex_OnlyNotYetCompleted:
  85. #ifdef USE_MVM_TOUR
  86. if ( iBadgeSlot >= 0 )
  87. {
  88. int iChallengeBit = ( 1 << iBadgeSlot );
  89. if ( nNotCompletedChallenges & iChallengeBit )
  90. {
  91. bSelect = true;
  92. }
  93. }
  94. #endif // USE_MVM_TOUR
  95. break;
  96. case k_iPopIndex_AnyNormal:
  97. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Normal );
  98. break;
  99. case k_iPopIndex_AnyIntermediate:
  100. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Intermediate );
  101. break;
  102. case k_iPopIndex_AnyAdvanced:
  103. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Advanced );
  104. break;
  105. case k_iPopIndex_AnyExpert:
  106. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Expert );
  107. break;
  108. case k_iPopIndex_AnyHaunted:
  109. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Haunted );
  110. break;
  111. default:
  112. Assert( false );
  113. }
  114. result.SetMissionBySchemaIndex( i, bSelect );
  115. }
  116. }
  117. #ifdef ENABLE_GC_MATCHMAKING
  118. Color s_colorBannedPlayerListItem( 250, 50, 45, 255 );
  119. Color s_colorPlayerListItem( 255, 255, 255, 255 );
  120. Color s_colorChatRemovedFromQueue( 200, 10, 10, 255 );
  121. Color s_colorChatAddedToQueue( 10, 200, 10, 255 );
  122. Color s_colorChatPlayerJoinedParty( 255, 255, 255, 255 );
  123. Color s_colorChatPlayerJoinedPartyName( 200, 200, 10, 255 );
  124. Color s_colorChatPlayerLeftParty( 255, 255, 255, 255 );
  125. Color s_colorChatPlayerLeftPartyName( 200, 200, 10, 255 );
  126. Color s_colorChatPlayerChatName( 200, 200, 10, 255 );
  127. Color s_colorChatPlayerChatText( 180, 180, 180, 255 );
  128. Color s_colorChatDefault( 180, 180, 180, 255 );
  129. Color s_colorChallengeForegroundEnabled( 255, 255, 255, 255 );
  130. Color s_colorChallengeForegroundHaunted( 135, 79, 173, 255 );
  131. Color s_colorChallengeForegroundDisabled( 100, 100, 100, 128 );
  132. Color s_colorChallengeHeader( 250, 114, 45, 255 );
  133. static void GetPlayerNameForSteamID( wchar_t *wCharPlayerName, int nBufSizeBytes, const CSteamID &steamID )
  134. {
  135. const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( steamID );
  136. V_UTF8ToUnicode( pszName, wCharPlayerName, nBufSizeBytes );
  137. }
  138. CBaseLobbyPanel::CBaseLobbyPanel( vgui::Panel *pParent, CBaseLobbyContainerFrame* pContainer )
  139. : vgui::PropertySheet( pParent, "LobbyPanel" ), m_sPersonaStateChangedCallback( this, &CBaseLobbyPanel::OnPersonaStateChanged )
  140. , m_pContainer( pContainer )
  141. {
  142. //ListenForGameEvent( "lobby_updated" );
  143. ListenForGameEvent( "party_updated" );
  144. ListenForGameEvent( "mm_lobby_chat" );
  145. ListenForGameEvent( "mm_lobby_member_join" );
  146. ListenForGameEvent( "mm_lobby_member_leave" );
  147. m_iWritingPanel = 0;
  148. m_pSearchActiveGroupBox = NULL;
  149. m_pSearchActiveTitleLabel = NULL;
  150. m_pSearchActivePenaltyLabel = NULL;
  151. m_pPartyHasLowPriority = NULL;
  152. m_pJoinLateCheckButton = NULL;
  153. m_pJoinLateValueLabel = NULL;
  154. m_pInviteButton = NULL;
  155. m_pChatLog = NULL;
  156. //m_nFirstMapShown = -1;
  157. m_pImageList = NULL;
  158. m_iImageIsBanned = -1;
  159. m_iImageRadioButtonYes = -1;
  160. m_iImageRadioButtonNo = -1;
  161. m_iImageCheckBoxDisabled = -1;
  162. m_iImageCheckBoxYes = -1;
  163. m_iImageCheckBoxNo = -1;
  164. m_iImageCheckBoxMixed = -1;
  165. m_iImageNew = -1;
  166. m_iImageNo = -1;
  167. m_fontPlayerListItem = 0;
  168. // Party
  169. m_pPartyActiveGroupBox = new vgui::EditablePanel( this, "PartyActiveGroupBox" );
  170. vgui::EditablePanel *pPartyGroupPanel = new vgui::EditablePanel( m_pPartyActiveGroupBox, "PartyGroupBox" );
  171. m_pChatPlayerList = new vgui::SectionedListPanel( pPartyGroupPanel, "PartyPlayerList" );
  172. m_pChatTextEntry = new ChatTextEntry( m_pPartyActiveGroupBox, "ChatTextEntry" ); Assert( m_pChatTextEntry );
  173. m_pChatLog = new ChatLog( m_pPartyActiveGroupBox, "ChatLog" ); Assert( m_pChatLog );
  174. m_mapAvatarsToImageList.SetLessFunc( DefLessFunc(int) );
  175. m_eCurrentPartyState = CSOTFParty_State_UI;
  176. m_flRefreshPlayerListTime = -1.f;
  177. m_pToolTip = new CMainMenuToolTip( this );
  178. vgui::EditablePanel* pToolTipEmbeddedPanel = new vgui::EditablePanel( this, "TooltipPanel" );
  179. pToolTipEmbeddedPanel->SetKeyBoardInputEnabled( false );
  180. pToolTipEmbeddedPanel->SetMouseInputEnabled( false );
  181. m_pToolTip->SetEmbeddedPanel( pToolTipEmbeddedPanel );
  182. m_pToolTip->SetTooltipDelay( 0 );
  183. }
  184. CBaseLobbyPanel::~CBaseLobbyPanel()
  185. {
  186. delete m_pImageList;
  187. m_pImageList = NULL;
  188. }
  189. void CBaseLobbyPanel::OnClickedOnPlayer()
  190. {
  191. int iSelected = m_pChatPlayerList->GetSelectedItem();
  192. //m_pChatPlayerList->ClearSelection();
  193. if ( iSelected < 0 )
  194. return;
  195. CSteamID steamID = SteamIDFromDecimalString( m_pChatPlayerList->GetItemData( iSelected )->GetString( "steamid", "" ) );
  196. if ( !steamID.IsValid() )
  197. return;
  198. vgui::Menu *menu = new vgui::Menu(this, "ContextMenu");
  199. int x, y;
  200. vgui::input()->GetCursorPos(x, y);
  201. menu->SetPos(x, y);
  202. wchar_t wszLocalized[512];
  203. char szLocalized[512];
  204. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_ScoreBoard_Context_Trade" ), 0 );
  205. g_pVGuiLocalize->ConvertUnicodeToANSI( wszLocalized, szLocalized, sizeof( szLocalized ) );
  206. menu->AddMenuItem( szLocalized, new KeyValues( "TradeWithUser", "steamid", CFmtStr( "%llu", steamID.ConvertToUint64() ).Access() ), this );
  207. menu->SetVisible(true);
  208. }
  209. void CBaseLobbyPanel::SetMatchmakingModeBackground()
  210. {
  211. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  212. // Get the background panel.
  213. vgui::ImagePanel* pModeBackgroundImage = FindControl< vgui::ImagePanel >( "ModeBackgroundImage", true );
  214. if ( !pModeBackgroundImage )
  215. return;
  216. const char* pszImageName = NULL;
  217. const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( GetMatchGroup() );
  218. if ( pMatchDesc && pMatchDesc->m_pProgressionDesc )
  219. {
  220. // Get the level of the local player, and pull the background image out of the level
  221. const LevelInfo_t& level = pMatchDesc->m_pProgressionDesc->YieldingGetLevelForSteamID( steamapicontext->SteamUser()->GetSteamID() );
  222. pszImageName = level.m_pszLobbyBackgroundImage;
  223. }
  224. // Set the image name, if we got one, into the panel
  225. if ( pszImageName )
  226. {
  227. pModeBackgroundImage->SetImage( pszImageName );
  228. }
  229. // Only show if we got one (MvM doesn't have any)
  230. pModeBackgroundImage->SetVisible( pszImageName != NULL );
  231. }
  232. //-----------------------------------------------------------------------------
  233. void CBaseLobbyPanel::FireGameEvent( IGameEvent *event )
  234. {
  235. if ( !IsVisible() || !m_pContainer->IsVisible() )
  236. return;
  237. const char *pszEventName = event->GetName();
  238. if ( !Q_stricmp( pszEventName, "party_updated" ) )
  239. {
  240. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  241. if ( pParty )
  242. {
  243. if ( m_eCurrentPartyState != pParty->GetState() )
  244. {
  245. wchar_t wszLocalized[512];
  246. switch ( pParty->GetState() )
  247. {
  248. case CSOTFParty_State_UI:
  249. m_pChatLog->InsertColorChange( s_colorChatRemovedFromQueue );
  250. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_RemovedFromQueue" ), 0 );
  251. m_pChatLog->InsertString( wszLocalized );
  252. break;
  253. case CSOTFParty_State_FINDING_MATCH:
  254. m_pChatLog->InsertColorChange( s_colorChatAddedToQueue );
  255. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_AddedToQueue" ), 0 );
  256. m_pChatLog->InsertString( wszLocalized );
  257. break;
  258. default:
  259. Assert( false );
  260. case CSOTFParty_State_IN_MATCH:
  261. break;
  262. }
  263. m_eCurrentPartyState = pParty->GetState();
  264. }
  265. }
  266. else
  267. {
  268. m_eCurrentPartyState = CSOTFParty_State_UI;
  269. }
  270. UpdatePlayerList();
  271. WriteGameSettingsControls();
  272. return;
  273. }
  274. if ( !Q_stricmp( pszEventName, "mm_lobby_chat" ) )
  275. {
  276. CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) );
  277. const char *pszText = event->GetString( "text", "" );
  278. int l = V_strlen( pszText );
  279. if ( l > 0 )
  280. {
  281. int nBufSize = l * sizeof(wchar_t) + 4;
  282. wchar_t *wText = (wchar_t *)stackalloc( nBufSize );
  283. V_UTF8ToUnicode( pszText, wText, nBufSize );
  284. switch ( event->GetInt( "type", CTFGCClientSystem::k_eLobbyMsg_UserChat ) )
  285. {
  286. default:
  287. Assert( !"Unknown chat message type" );
  288. case CTFGCClientSystem::k_eLobbyMsg_SystemMsgFromLeader:
  289. m_pChatLog->InsertColorChange( s_colorChatDefault );
  290. m_pChatLog->InsertString( wText );
  291. m_pChatLog->InsertString("\n");
  292. break;
  293. case CTFGCClientSystem::k_eLobbyMsg_UserChat:
  294. {
  295. wchar_t wCharPlayerName[ 128 ];
  296. GetPlayerNameForSteamID( wCharPlayerName, sizeof(wCharPlayerName), steamID );
  297. m_pChatLog->InsertColorChange( s_colorChatPlayerChatName );
  298. m_pChatLog->InsertString( wCharPlayerName );
  299. m_pChatLog->InsertString( ": " );
  300. m_pChatLog->InsertColorChange( s_colorChatPlayerChatText );
  301. m_pChatLog->InsertString( wText );
  302. m_pChatLog->InsertString("\n");
  303. } break;
  304. }
  305. }
  306. return;
  307. }
  308. if ( !Q_stricmp( pszEventName, "mm_lobby_member_join" ) )
  309. {
  310. CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) );
  311. bool bSolo = false;
  312. if ( steamID == steamapicontext->SteamUser()->GetSteamID() )
  313. {
  314. m_pChatLog->SetText("");
  315. bSolo = ( event->GetInt( "solo", 0 ) != 0 );
  316. }
  317. wchar_t wszLocalized[512];
  318. // An empty lobby by ourselves?
  319. if ( bSolo )
  320. {
  321. m_pChatLog->InsertColorChange( s_colorChatDefault );
  322. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_StartSearchChat" ), 0 );
  323. m_pChatLog->InsertString( wszLocalized );
  324. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_InviteFriendsChat" ), 0 );
  325. m_pChatLog->InsertString( wszLocalized );
  326. }
  327. else
  328. {
  329. wchar_t wCharPlayerName[128];
  330. m_pChatLog->InsertColorChange( s_colorChatPlayerJoinedPartyName );
  331. GetPlayerNameForSteamID( wCharPlayerName, sizeof( wCharPlayerName ), steamID );
  332. m_pChatLog->InsertColorChange( s_colorChatPlayerJoinedParty );
  333. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_PlayerJoinedPartyChat" ), 1, wCharPlayerName );
  334. m_pChatLog->InsertString( wszLocalized );
  335. }
  336. UpdatePlayerList();
  337. return;
  338. }
  339. if ( !Q_stricmp( pszEventName, "mm_lobby_member_leave" ) )
  340. {
  341. CSteamID steamID = SteamIDFromDecimalString( event->GetString( "steamid", "0" ) );
  342. wchar_t wCharPlayerName[ 128 ];
  343. GetPlayerNameForSteamID( wCharPlayerName, sizeof(wCharPlayerName), steamID );
  344. m_pChatLog->InsertColorChange( s_colorChatPlayerLeftParty );
  345. wchar_t wszLocalized[512];
  346. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_PlayerLeftPartyChat" ), 1, wCharPlayerName );
  347. m_pChatLog->InsertString( wszLocalized );
  348. UpdatePlayerList();
  349. WriteGameSettingsControls();
  350. return;
  351. }
  352. Assert( false );
  353. }
  354. void CBaseLobbyPanel::OnCommand( const char *command )
  355. {
  356. if ( FStrEq( command, "invite" ) )
  357. {
  358. GTFGCClientSystem()->RequestActivateInvite();
  359. }
  360. else if ( FStrEq( command, "open_charinfo" ) )
  361. {
  362. engine->ClientCmd_Unrestricted( "open_econui_backpack" );
  363. }
  364. else
  365. {
  366. // What other commands are there?
  367. Assert( false );
  368. }
  369. }
  370. bool CBaseLobbyPanel::IsAnyoneBanned( RTime32 &rtimeExpire ) const
  371. {
  372. bool bBanned = false;
  373. RTime32 rtimeHighest = 0;
  374. // This only matters if we're searching for a mannup or ladder game
  375. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  376. if ( pParty && ( !pParty->GetSearchPlayForBraggingRights() && !IsLadderGroup( pParty->GetMatchGroup() ) ) )
  377. {
  378. return false;
  379. }
  380. for( int i=0; i<m_vecPlayers.Count(); ++i )
  381. {
  382. if ( m_vecPlayers[i].m_bIsBanned )
  383. {
  384. bBanned = true;
  385. if ( m_vecPlayers[i].m_rtimeBanExpire > rtimeHighest )
  386. {
  387. rtimeHighest = m_vecPlayers[i].m_rtimeBanExpire;
  388. }
  389. }
  390. }
  391. rtimeExpire = rtimeHighest;
  392. return bBanned;
  393. }
  394. const CBaseLobbyPanel::LobbyPlayerInfo* CBaseLobbyPanel::GetLobbyPlayerInfo( CSteamID &steamID ) const
  395. {
  396. for ( int i = 0; i < m_vecPlayers.Count(); ++i )
  397. {
  398. if ( m_vecPlayers[i].m_steamID == steamID )
  399. {
  400. return &m_vecPlayers[i];
  401. }
  402. }
  403. Assert( false );
  404. return NULL;
  405. }
  406. bool CBaseLobbyPanel::IsAnyoneLowPriority( RTime32 &rtimeExpire ) const
  407. {
  408. bool bLowPriority = false;
  409. RTime32 rtimeHighest = 0;
  410. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  411. if ( pParty && !pParty->GetSearchPlayForBraggingRights() && !IsLadderGroup( pParty->GetMatchGroup() ) )
  412. return false;
  413. for ( int i = 0; i < m_vecPlayers.Count(); ++i )
  414. {
  415. if ( m_vecPlayers[i].m_bIsLowPriority )
  416. {
  417. bLowPriority = true;
  418. if ( m_vecPlayers[i].m_rtimeLowPriorityExpire > rtimeHighest )
  419. {
  420. rtimeHighest = m_vecPlayers[i].m_rtimeLowPriorityExpire;
  421. }
  422. }
  423. }
  424. rtimeExpire = rtimeHighest;
  425. return bLowPriority;
  426. }
  427. void CBaseLobbyPanel::UpdateControls()
  428. {
  429. WriteGameSettingsControls();
  430. WriteStatusControls();
  431. UpdatePlayerList();
  432. }
  433. void CBaseLobbyPanel::OnCheckButtonChecked( vgui::Panel *panel )
  434. {
  435. if ( m_iWritingPanel > 0 )
  436. return;
  437. if ( panel == m_pJoinLateCheckButton )
  438. {
  439. if ( BIsPartyLeader() && GCClientSystem()->BConnectedtoGC() )
  440. {
  441. tf_matchmaking_join_in_progress.SetValue( m_pJoinLateCheckButton->IsSelected() ? 1 : 0 );
  442. GTFGCClientSystem()->SetSearchJoinLate( m_pJoinLateCheckButton->IsSelected() );
  443. }
  444. else
  445. {
  446. WriteGameSettingsControls();
  447. }
  448. }
  449. }
  450. void CBaseLobbyPanel::OnTradeWithUser( KeyValues* params )
  451. {
  452. CSteamID steamID = SteamIDFromDecimalString( params->GetString( "steamid", "" ) );
  453. if ( !steamID.IsValid() )
  454. return;
  455. steamapicontext->SteamFriends()->ActivateGameOverlayToUser( "jointrade", steamID );
  456. }
  457. void CBaseLobbyPanel::OnItemLeftClick( vgui::Panel* panel )
  458. {
  459. if ( m_iWritingPanel > 0 )
  460. return;
  461. m_pChatTextEntry->RequestFocus();
  462. if ( panel == m_pChatPlayerList )
  463. {
  464. OnClickedOnPlayer();
  465. }
  466. }
  467. //-----------------------------------------------------------------------------
  468. // Purpose:
  469. //-----------------------------------------------------------------------------
  470. void CBaseLobbyPanel::WriteStatusControls()
  471. {
  472. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  473. enum EDisabledState
  474. {
  475. DISABLED_NONE,
  476. DISABLED_NO_GC,
  477. DISABLED_MATCH_IN_PROGRESS
  478. };
  479. EDisabledState eDisabled = DISABLED_NONE;
  480. if ( GTFGCClientSystem()->BHaveLiveMatch() )
  481. {
  482. eDisabled = DISABLED_MATCH_IN_PROGRESS;
  483. }
  484. if ( !GCClientSystem()->BConnectedtoGC() || ( GTFGCClientSystem()->GetParty() && GTFGCClientSystem()->GetParty()->BOffline() ) )
  485. {
  486. eDisabled = DISABLED_NO_GC;
  487. }
  488. SetControlVisible( "NoGCGroupBox", eDisabled == DISABLED_NO_GC, true );
  489. SetControlVisible( "MatchInProgressGroupBox", eDisabled == DISABLED_MATCH_IN_PROGRESS, true );
  490. if ( GTFGCClientSystem()->GetWizardStep() == TF_Matchmaking_WizardStep_SEARCHING )
  491. {
  492. m_pSearchActiveGroupBox->SetVisible( true );
  493. const CMsgMatchmakingProgress &progress = GTFGCClientSystem()->m_msgMatchmakingProgress;
  494. wchar_t wszCount[32];
  495. CUtlVector<vgui::Label *> vecNearbyFields;
  496. vgui::Label *pNearbyColumnHead = dynamic_cast<vgui::Label *>( FindChildByName( "NearbyColumnHead", true ) );
  497. Assert( pNearbyColumnHead );
  498. vecNearbyFields.AddToTail( pNearbyColumnHead );
  499. #define DO_FIELD( protobufname, labelname, bNearby ) \
  500. vgui::Label *p##labelname = dynamic_cast<vgui::Label *>( FindChildByName( #labelname, true ) ); \
  501. Assert( p##labelname ); \
  502. if ( p##labelname ) \
  503. { \
  504. if ( progress.has_##protobufname() ) \
  505. { \
  506. _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", progress.protobufname() ); \
  507. p##labelname->SetText( wszCount ); \
  508. if ( bNearby ) bHasAnyNearbyData = true; \
  509. } \
  510. else \
  511. { \
  512. p##labelname->SetText( "#TF_Matchmaking_NoData" ); \
  513. } \
  514. if ( bNearby ) vecNearbyFields.AddToTail( p##labelname ); \
  515. }
  516. bool bHasAnyNearbyData = false;
  517. DO_FIELD( matching_worldwide_searching_players, PlayersSearchingMatchingWorldwideValue, false )
  518. DO_FIELD( matching_near_you_searching_players, PlayersSearchingMatchingNearbyValue, true )
  519. DO_FIELD( matching_worldwide_active_players, PlayersInGameMatchingWorldwideValue, false )
  520. DO_FIELD( matching_near_you_active_players, PlayersInGameMatchingNearbyValue, true )
  521. DO_FIELD( matching_worldwide_empty_gameservers, EmptyGameserversMatchingWorldwideValue, false )
  522. DO_FIELD( matching_near_you_empty_gameservers, EmptyGameserversMatchingNearbyValue, true )
  523. DO_FIELD( total_worldwide_searching_players, PlayersSearchingTotalWorldwideValue, false )
  524. DO_FIELD( total_near_you_searching_players, PlayersSearchingTotalNearbyValue, true )
  525. DO_FIELD( total_worldwide_active_players, PlayersInGameTotalWorldwideValue, false )
  526. DO_FIELD( total_near_you_active_players, PlayersInGameTotalNearbyValue, true )
  527. FOR_EACH_VEC( vecNearbyFields, i )
  528. {
  529. vecNearbyFields[i]->SetVisible( bHasAnyNearbyData );
  530. }
  531. // Show the low priority message? This only really applies to ladder games for now.
  532. RTime32 rtimeExpire = 0;
  533. bool bShowTimer = IsAnyoneLowPriority( rtimeExpire );
  534. if ( bShowTimer )
  535. {
  536. CRTime timeExpire( rtimeExpire );
  537. timeExpire.SetToGMT( false );
  538. char time_buf[k_RTimeRenderBufferSize];
  539. if ( m_pPartyHasLowPriority )
  540. {
  541. m_pPartyHasLowPriority->SetDialogVariable( "penaltytimer", CFmtStr( "Expires: %s", ( ( rtimeExpire > 0 ) ? timeExpire.Render( time_buf ) : "" ) ) );
  542. }
  543. if ( m_pSearchActivePenaltyLabel )
  544. {
  545. m_pSearchActivePenaltyLabel->SetText( "#TF_Matchmaking_PartyLowPriority" );
  546. }
  547. }
  548. if ( m_pPartyHasLowPriority )
  549. {
  550. m_pPartyHasLowPriority->SetVisible( bShowTimer );
  551. }
  552. if ( m_pSearchActivePenaltyLabel )
  553. {
  554. m_pSearchActivePenaltyLabel->SetVisible( bShowTimer );
  555. }
  556. // HOLY CHEESEBALL BUSY INDICATOR
  557. const wchar_t *pwszEllipses = &L"....."[ 4 - ( (unsigned)Plat_FloatTime() % 5U ) ];
  558. wchar_t wszLocalized[512];
  559. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( "#TF_Matchmaking_Searching" ), 1, pwszEllipses );
  560. if ( m_pSearchActiveTitleLabel )
  561. {
  562. m_pSearchActiveTitleLabel->SetText( wszLocalized );
  563. }
  564. }
  565. else
  566. {
  567. m_pSearchActiveGroupBox->SetVisible( false );
  568. }
  569. }
  570. void CBaseLobbyPanel::WriteGameSettingsControls()
  571. {
  572. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  573. // Make sure we want to be in matchmaking. (If we don't, the frame should hide us pretty quickly.)
  574. // We might get an event or something right at the transition point occasionally when the UI should
  575. // not be visible
  576. if ( GTFGCClientSystem()->GetMatchmakingUIState() == eMatchmakingUIState_Inactive )
  577. {
  578. return;
  579. }
  580. SetMatchmakingModeBackground();
  581. bool bLeader = BIsPartyLeader();
  582. bool bInUIState = BIsPartyInUIState();
  583. m_pJoinLateCheckButton->ToggleButton::SetSelected( GTFGCClientSystem()->GetSearchJoinLate() ); // !KLUDGE! call base to avoid firing the signal
  584. bool bShowLateJoin = ShouldShowLateJoin();
  585. m_pJoinLateCheckButton->SetVisible( bShowLateJoin && bLeader );
  586. m_pJoinLateValueLabel->SetText( GTFGCClientSystem()->GetSearchJoinLate() ? "#TF_Matchmaking_SearchForAll" : "#TF_Matchmaking_SearchForNew" );
  587. m_pJoinLateValueLabel->SetVisible( bShowLateJoin && !bLeader );
  588. //m_pJoinLateValueLabel->SetEnabled( bInUIState );
  589. m_pInviteButton->SetVisible( bInUIState && ( m_vecPlayers.Count() < k_nTFPartyMaxSize ) );
  590. m_pChatTextEntry->RequestFocus();
  591. }
  592. //-----------------------------------------------------------------------------
  593. // Purpose: Updates the player list
  594. //-----------------------------------------------------------------------------
  595. void CBaseLobbyPanel::UpdatePlayerList()
  596. {
  597. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
  598. if ( !IsVisible() || !m_pContainer->IsVisible() )
  599. return;
  600. m_pChatPlayerList->ClearSelection();
  601. m_pChatPlayerList->RemoveAll();
  602. m_vecPlayers.RemoveAll();
  603. bool bLadderGame = GTFGCClientSystem()->GetSearchMode() == TF_Matchmaking_LADDER &&
  604. IsLadderGroup( (EMatchGroup)GTFGCClientSystem()->GetLadderType() );
  605. const IMatchGroupDescription *pMatchDesc = GetMatchGroupDescription( GetMatchGroup() );
  606. EMMPenaltyPool ePenaltyPool = pMatchDesc ? pMatchDesc->m_params.m_ePenaltyPool : eMMPenaltyPool_Invalid;
  607. if ( steamapicontext == NULL || steamapicontext->SteamUser() == NULL )
  608. return;
  609. // Locate party, if we have one.
  610. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  611. if ( pParty == NULL )
  612. {
  613. LobbyPlayerInfo p;
  614. p.m_steamID = steamapicontext->SteamUser()->GetSteamID();
  615. p.m_sName = steamapicontext->SteamFriends()->GetPersonaName();
  616. p.m_bHasTicket = GTFGCClientSystem()->BLocalPlayerInventoryHasMvmTicket();
  617. p.m_bSquadSurplus = GTFGCClientSystem()->GetLocalPlayerSquadSurplus();
  618. #ifdef USE_MVM_TOUR
  619. int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  620. if ( idxTour < 0 || !GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &p.m_nBadgeLevel, &p.m_nCompletedChallenges ) )
  621. {
  622. p.m_nBadgeLevel = 0;
  623. p.m_nCompletedChallenges = 0;
  624. }
  625. #endif // USE_MVM_TOUR
  626. p.m_pAvatarImage = NULL;
  627. p.m_bHasCompetitiveAccess = GTFGCClientSystem()->BHasCompetitiveAccess();
  628. CSOTFLadderData *pData = GetLocalPlayerLadderData( (EMatchGroup)GTFGCClientSystem()->GetLadderType() );
  629. p.m_unLadderRank = ( pData ? pData->Obj().rank() : 1u );
  630. uint32 unExperienceLevel = 1u;
  631. const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL;
  632. if ( pData && pProgressionDesc && pMatchDesc->m_params.m_eMatchType == MATCH_TYPE_CASUAL )
  633. {
  634. LevelInfo_t levelInfo = pProgressionDesc->GetLevelForExperience( pData->Obj().experience() );
  635. unExperienceLevel = levelInfo.m_nLevelNum;
  636. }
  637. p.m_unExperienceLevel = unExperienceLevel;
  638. CEconGameAccountClient *pGameAccountClient = NULL;
  639. if ( InventoryManager() && TFInventoryManager()->GetLocalTFInventory() && TFInventoryManager()->GetLocalTFInventory()->GetSOC() )
  640. {
  641. pGameAccountClient = TFInventoryManager()->GetLocalTFInventory()->GetSOC()->GetSingleton<CEconGameAccountClient>();
  642. }
  643. p.m_bIsBanned = false;
  644. p.m_rtimeBanExpire = 0;
  645. p.m_rtimeLowPriorityExpire = 0;
  646. p.m_bIsLowPriority = false;
  647. if ( pGameAccountClient && ePenaltyPool != eMMPenaltyPool_Invalid )
  648. {
  649. switch ( ePenaltyPool )
  650. {
  651. case eMMPenaltyPool_Casual:
  652. p.m_rtimeBanExpire = pGameAccountClient->Obj().matchmaking_casual_ban_expiration();
  653. p.m_rtimeLowPriorityExpire = pGameAccountClient->Obj().matchmaking_casual_low_priority_expiration();
  654. p.m_bIsBanned = p.m_rtimeBanExpire > CRTime::RTime32TimeCur();
  655. p.m_bIsLowPriority = p.m_rtimeLowPriorityExpire > CRTime::RTime32TimeCur();
  656. break;
  657. case eMMPenaltyPool_Ranked:
  658. p.m_rtimeBanExpire = pGameAccountClient->Obj().matchmaking_ranked_ban_expiration();
  659. p.m_rtimeLowPriorityExpire = pGameAccountClient->Obj().matchmaking_ranked_low_priority_expiration();
  660. p.m_bIsBanned = p.m_rtimeBanExpire > CRTime::RTime32TimeCur();
  661. p.m_bIsLowPriority = p.m_rtimeLowPriorityExpire > CRTime::RTime32TimeCur();
  662. break;
  663. default: Assert( false );
  664. }
  665. }
  666. // !TEST!
  667. //p.m_bIsBanned = true;
  668. //for (int i = 0 ; i < 6 ; ++i) // !TEST!
  669. m_vecPlayers.AddToTail( p );
  670. }
  671. else
  672. {
  673. for ( int i = 0 ; i < pParty->GetNumMembers() ; ++i )
  674. {
  675. LobbyPlayerInfo p;
  676. p.m_steamID = pParty->GetMember( i );
  677. p.m_sName = steamapicontext->SteamFriends()->GetFriendPersonaName( p.m_steamID );
  678. if ( p.m_sName.IsEmpty() )
  679. continue;
  680. p.m_bHasTicket = pParty->Obj().members( i ).owns_ticket();
  681. p.m_nBadgeLevel = pParty->Obj().members( i ).badge_level();
  682. p.m_nCompletedChallenges = pParty->Obj().members( i ).completed_missions();
  683. p.m_bSquadSurplus = pParty->Obj().members( i ).squad_surplus();
  684. p.m_pAvatarImage = NULL;
  685. p.m_bIsBanned = pParty->Obj().members( i ).is_banned();
  686. p.m_bHasCompetitiveAccess = pParty->Obj().members( i ).competitive_access();
  687. p.m_unLadderRank = pParty->Obj().members( i ).ladder_rank();
  688. p.m_rtimeBanExpire = pParty->Obj().matchmaking_ban_time();
  689. p.m_rtimeLowPriorityExpire = pParty->Obj().matchmaking_low_priority_time();
  690. p.m_bIsLowPriority = pParty->Obj().members( i ).is_low_priority();
  691. uint32 unExperienceLevel = 1u;
  692. const IProgressionDesc *pProgressionDesc = pMatchDesc ? pMatchDesc->m_pProgressionDesc : NULL;
  693. if ( pProgressionDesc && pMatchDesc->m_params.m_eMatchType == MATCH_TYPE_CASUAL )
  694. {
  695. LevelInfo_t levelInfo = pProgressionDesc->GetLevelForExperience( pParty->Obj().members( i ).experience() );
  696. unExperienceLevel = levelInfo.m_nLevelNum;
  697. }
  698. p.m_unExperienceLevel = unExperienceLevel;
  699. if ( p.m_steamID == pParty->GetLeader() )
  700. {
  701. m_vecPlayers.AddToHead( p );
  702. }
  703. else
  704. {
  705. m_vecPlayers.AddToTail( p );
  706. }
  707. }
  708. }
  709. for( int i = 0; i < m_vecPlayers.Count(); ++i )
  710. {
  711. KeyValues *pKeyValues = new KeyValues( "data" );
  712. CUtlString sName;
  713. if ( i == 0 && m_vecPlayers.Count() > 1 )
  714. {
  715. sName.Format( "%s (leader)", m_vecPlayers[i].m_sName.String() ); // !FIXME! Localize
  716. }
  717. else
  718. {
  719. sName = m_vecPlayers[i].m_sName;
  720. }
  721. pKeyValues->SetString( "name", sName );
  722. pKeyValues->SetString( "steamid", CFmtStr( "%llu", m_vecPlayers[i].m_steamID.ConvertToUint64() ).Access() );
  723. pKeyValues->SetInt( "badge_level", Max( 1U, m_vecPlayers[i].m_nBadgeLevel ) );
  724. ApplyChatUserSettings( m_vecPlayers[ i ], pKeyValues );
  725. pKeyValues->SetInt( "is_banned", ( m_vecPlayers[i].m_bIsBanned || m_vecPlayers[i].m_bIsLowPriority ) ? m_iImageIsBanned : 0 );
  726. // See if the avatar's changed
  727. int iAvatar = steamapicontext->SteamFriends()->GetSmallFriendAvatar( m_vecPlayers[i].m_steamID );
  728. int iIndex = m_mapAvatarsToImageList.Find( iAvatar );
  729. if ( iIndex == m_mapAvatarsToImageList.InvalidIndex() )
  730. {
  731. CAvatarImage *pImage = new CAvatarImage();
  732. pImage->SetAvatarSteamID( m_vecPlayers[i].m_steamID );
  733. pImage->SetDrawFriend( false ); // you can only invite friends, this isn't that useful
  734. pImage->SetAvatarSize( m_iAvatarWidth, m_iAvatarWidth );
  735. int iImageIndex = m_pImageList->AddImage( pImage );
  736. iIndex = m_mapAvatarsToImageList.Insert( iAvatar, iImageIndex );
  737. }
  738. pKeyValues->SetInt( "avatar", m_mapAvatarsToImageList[iIndex] );
  739. CAvatarImage *pAvIm = (CAvatarImage *)m_pImageList->GetImage( m_mapAvatarsToImageList[iIndex] );
  740. pAvIm->UpdateFriendStatus();
  741. m_vecPlayers[i].m_pAvatarImage = pAvIm;
  742. if ( bLadderGame )
  743. {
  744. if ( !m_vecPlayers[i].m_bHasCompetitiveAccess )
  745. {
  746. pKeyValues->SetInt( "has_competitive_access", m_iImageNo );
  747. }
  748. }
  749. pKeyValues->SetInt( "ladder_rank", m_vecPlayers[i].m_unLadderRank );
  750. pKeyValues->SetInt( "experience_level", m_vecPlayers[i].m_unExperienceLevel );
  751. int itemID = m_pChatPlayerList->AddItem( 0, pKeyValues );
  752. m_pChatPlayerList->SetItemFont( itemID, m_fontPlayerListItem );
  753. m_pChatPlayerList->SetItemFgColor( itemID, ( m_vecPlayers[i].m_bIsBanned || m_vecPlayers[i].m_bIsLowPriority ) ? s_colorBannedPlayerListItem : s_colorPlayerListItem );
  754. pKeyValues->deleteThis();
  755. }
  756. // force the list to PerformLayout() now so we can update our medal images
  757. m_pChatPlayerList->InvalidateLayout( true );
  758. int iPanelCount = 0;
  759. // This only works in 6v6 Comp and 12v12 Casual for now
  760. if ( ( GetMatchGroup() == k_nMatchGroup_Ladder_6v6 ) || ( GetMatchGroup() == k_nMatchGroup_Casual_12v12 ) )
  761. {
  762. int nColumn = m_pChatPlayerList->GetColumnIndexByName( 0, "rank" );
  763. for ( int nRow = 0; nRow < m_pChatPlayerList->GetItemCount(); nRow++ )
  764. {
  765. KeyValues *pKeyValues = m_pChatPlayerList->GetItemData( nRow );
  766. if ( !pKeyValues )
  767. continue;
  768. CSteamID steamID = SteamIDFromDecimalString( pKeyValues->GetString( "steamid", "0" ) );
  769. if ( !steamID.IsValid() )
  770. continue;
  771. uint32 unLevel = pKeyValues->GetInt( "ladder_rank" );
  772. if ( GetMatchGroup() == k_nMatchGroup_Casual_12v12 )
  773. {
  774. unLevel = pKeyValues->GetInt( "experience_level" );
  775. }
  776. // Create a panel if we need one
  777. if ( iPanelCount >= m_vecChatBadges.Count() )
  778. {
  779. m_vecChatBadges.AddToTail();
  780. m_vecChatBadges[iPanelCount].m_pBadgeModel = vgui::SETUP_PANEL( new CTFBadgePanel( m_pChatPlayerList, "Model" ) );
  781. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetZPos( 9999 );
  782. m_vecChatBadges[iPanelCount].m_nShownLevel = 0u;
  783. }
  784. // Move it into place and resize. This is terrible, but VGUI has forced my hand
  785. int nX, nY, nWide, nTall;
  786. m_pChatPlayerList->GetMaxCellBounds( nRow, nColumn, nX, nY, nWide, nTall );
  787. int nSideLength = Max( nWide, nTall );
  788. nX = ( nX + ( nWide / 2 ) ) - ( nSideLength / 2 );
  789. nY = ( nY + ( nTall / 2 ) ) - ( nSideLength / 2 );
  790. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetBounds( nX, nY, nSideLength, nSideLength );
  791. // Different dude in the slot or their level is different? Update the medal model
  792. if ( m_vecChatBadges[iPanelCount].m_steamIDOwner != steamID ||
  793. m_vecChatBadges[iPanelCount].m_nShownLevel != unLevel )
  794. {
  795. m_vecChatBadges[iPanelCount].m_steamIDOwner = steamID;
  796. const LevelInfo_t& level = pMatchDesc->m_pProgressionDesc->GetLevelByNumber( unLevel );
  797. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetupBadge( pMatchDesc->m_pProgressionDesc, level );
  798. wchar_t wszOutString[128];
  799. char szLocalized[512];
  800. wchar_t wszCount[16];
  801. _snwprintf( wszCount, ARRAYSIZE( wszCount ), L"%d", level.m_nLevelNum );
  802. const wchar_t *wpszFormat = g_pVGuiLocalize->Find( pMatchDesc->m_pProgressionDesc->m_pszLevelToken );
  803. g_pVGuiLocalize->ConstructString_safe( wszOutString, wpszFormat, 2, wszCount, g_pVGuiLocalize->Find( level.m_pszLevelTitle ) );
  804. g_pVGuiLocalize->ConvertUnicodeToANSI( wszOutString, szLocalized, sizeof( szLocalized ) );
  805. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetTooltip( m_pToolTip, szLocalized );
  806. m_vecChatBadges[iPanelCount].m_nShownLevel = level.m_nLevelNum;
  807. m_vecChatBadges[iPanelCount].m_pBadgeModel->InvalidateLayout( true, true );
  808. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetVisible( true );
  809. }
  810. iPanelCount++;
  811. }
  812. }
  813. for ( ; iPanelCount < m_vecChatBadges.Count(); ++iPanelCount )
  814. {
  815. m_vecChatBadges[iPanelCount].m_pBadgeModel->SetVisible( false );
  816. m_vecChatBadges[iPanelCount].m_nShownLevel = 0u; // Will cause the badge to refresh when it gets a player
  817. }
  818. }
  819. //-----------------------------------------------------------------------------
  820. void CBaseLobbyPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  821. {
  822. BaseClass::ApplySchemeSettings( pScheme );
  823. LoadControlSettings( GetResFile() );
  824. m_pSearchActiveGroupBox = dynamic_cast<vgui::EditablePanel *>(FindChildByName( "SearchActiveGroupBox", true )); Assert( m_pSearchActiveGroupBox );
  825. m_pSearchActiveTitleLabel = dynamic_cast<vgui::Label *>(FindChildByName( "SearchActiveTitle", true )); Assert( m_pSearchActiveTitleLabel );
  826. m_pSearchActivePenaltyLabel = dynamic_cast<vgui::Label *>( FindChildByName( "PartyHasLowPriorityLabel", true ) ); Assert( m_pSearchActivePenaltyLabel );
  827. m_pPartyHasLowPriority = dynamic_cast<vgui::EditablePanel *>( FindChildByName( "PartyHasLowPriorityGroupBox", true ) ); Assert( m_pPartyHasLowPriority );
  828. m_pJoinLateCheckButton = dynamic_cast<vgui::CheckButton *>(FindChildByName( "JoinLateCheckButton", true )); Assert( m_pJoinLateCheckButton );
  829. m_pJoinLateValueLabel = dynamic_cast<vgui::Label *>(FindChildByName( "JoinLateValueLabel", true )); Assert( m_pJoinLateValueLabel );
  830. m_pInviteButton = dynamic_cast<vgui::Button *>(FindChildByName( "InviteButton", true )); Assert( m_pInviteButton );
  831. delete m_pImageList;
  832. m_pImageList = new vgui::ImageList( false );
  833. m_iImageIsBanned = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_timeout_active", true ) );
  834. m_pImageList->GetImage( m_iImageIsBanned )->SetSize( m_iBannedWidth, m_iBannedWidth );
  835. m_iImageCheckBoxDisabled = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_disabled", true ) );
  836. m_pImageList->GetImage( m_iImageCheckBoxDisabled )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  837. m_iImageCheckBoxYes = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_yes", true ) );
  838. m_pImageList->GetImage( m_iImageCheckBoxYes )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  839. m_iImageCheckBoxNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_no", true ) );
  840. m_pImageList->GetImage( m_iImageCheckBoxNo )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  841. m_iImageCheckBoxMixed = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_check_box_mixed", true ) );
  842. m_pImageList->GetImage( m_iImageCheckBoxMixed )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  843. m_iImageRadioButtonYes = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_radio_button_yes", true ) );
  844. m_pImageList->GetImage( m_iImageRadioButtonYes )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  845. m_iImageRadioButtonNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_radio_button_no", true ) );
  846. m_pImageList->GetImage( m_iImageRadioButtonNo )->SetSize( m_iChallengeCheckBoxWidth, m_iChallengeCheckBoxWidth * ( 3.75f / 4.0f ) );
  847. m_iImageNew = m_pImageList->AddImage( vgui::scheme()->GetImage( "new", true ) );
  848. m_pImageList->GetImage( m_iImageNew )->SetSize( m_iNewWidth, m_iNewWidth * ( 3.75f / 4.0f ) );
  849. m_iImageNo = m_pImageList->AddImage( vgui::scheme()->GetImage( "hud/vote_no", true ) );
  850. m_mapAvatarsToImageList.RemoveAll();
  851. m_pChatPlayerList->SetImageList( m_pImageList, false );
  852. m_pChatPlayerList->SetVisible( true );
  853. //
  854. // Populate the challenge list
  855. //
  856. m_pJoinLateCheckButton->AddActionSignalTarget( this );
  857. m_pInviteButton->AddActionSignalTarget( this );
  858. m_pChatPlayerList->AddActionSignalTarget( this );
  859. m_fontPlayerListItem = pScheme->GetFont( "DefaultSmall", true );
  860. //
  861. // Populate the player list
  862. //
  863. m_pChatPlayerList->SetVerticalScrollbar( false );
  864. m_pChatPlayerList->RemoveAll();
  865. m_pChatPlayerList->RemoveAllSections();
  866. m_pChatPlayerList->AddSection( 0, "Players" );
  867. m_pChatPlayerList->SetSectionAlwaysVisible( 0, true );
  868. m_pChatPlayerList->SetSectionFgColor( 0, Color( 255, 255, 255, 255 ) );
  869. m_pChatPlayerList->SetBgColor( Color( 0, 0, 0, 0 ) );
  870. m_pChatPlayerList->SetBorder( NULL );
  871. m_pChatPlayerList->SetClickable( false );
  872. //m_pChatPlayerList->SetClickable( true ); // enable context menu to trade / kick?
  873. bool bPartyLeader = BIsPartyLeader() && GCClientSystem()->BConnectedtoGC();
  874. if ( bPartyLeader )
  875. {
  876. extern bool TF_IsHolidayActive( int eHoliday );
  877. bool bHalloween = TF_IsHolidayActive( kHoliday_Halloween );
  878. static bool bForcedOnce = false;
  879. if ( bHalloween && !bForcedOnce )
  880. {
  881. GTFGCClientSystem()->SetQuickplayGameType( kGameCategory_Event247 );
  882. bForcedOnce = true;
  883. }
  884. }
  885. if ( bPartyLeader )
  886. {
  887. GTFGCClientSystem()->SetSearchJoinLate( tf_matchmaking_join_in_progress.GetBool() );
  888. }
  889. }
  890. void CBaseLobbyPanel::PerformLayout()
  891. {
  892. BaseClass::PerformLayout();
  893. WriteGameSettingsControls();
  894. UpdatePlayerList();
  895. }
  896. void CBaseLobbyPanel::OnItemContextMenu( vgui::Panel* panel )
  897. {
  898. if ( m_iWritingPanel > 0 )
  899. return;
  900. m_pChatTextEntry->RequestFocus();
  901. if ( panel == m_pChatPlayerList )
  902. {
  903. OnClickedOnPlayer();
  904. return;
  905. }
  906. }
  907. //-----------------------------------------------------------------------------
  908. // Command to launch the lobby UI, connecting to a particular lobby
  909. //-----------------------------------------------------------------------------
  910. static void CL_ConnectLobby( const CCommand &args )
  911. {
  912. if ( args.ArgC() < 2 )
  913. {
  914. Warning( "connect_lobby missing LobbyID argument\n" );
  915. return;
  916. }
  917. uint64 ulSteamID = 0;
  918. sscanf( args.Arg( 1 ), "%lld", &ulSteamID );
  919. CSteamID steamIDLobby( ulSteamID );
  920. if ( !steamIDLobby.IsValid() || !steamIDLobby.IsLobby() )
  921. {
  922. Warning( "connect_lobby passed invalid LobbyID '%s'\n", args.Arg( 1 ) );
  923. return;
  924. }
  925. GTFGCClientSystem()->AcceptFriendInviteToJoinLobby( steamIDLobby );
  926. }
  927. void OnSteamGameLobbyJoinRequested( GameLobbyJoinRequested_t *pInfo );
  928. 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" );
  929. #endif // #ifdef ENABLE_GC_MATCHMAKING