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.

1114 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "tf_gc_client.h"
  8. #include "tf_party.h"
  9. #include "vgui_controls/PropertySheet.h"
  10. #include "vgui_controls/SectionedListPanel.h"
  11. #include "vgui_bitmapimage.h"
  12. #include "vgui_avatarimage.h"
  13. #include "store/store_panel.h"
  14. #include <VGuiMatSurface/IMatSystemSurface.h>
  15. #include <vgui_controls/ImageList.h>
  16. #include "tf_lobbypanel_mvm.h"
  17. #include "tf_lobby_container_frame_mvm.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include <tier0/memdbgon.h>
  20. extern ConVar tf_matchmaking_join_in_progress;
  21. ConVar tf_matchmaking_ticket_help( "tf_matchmaking_ticket_help", "0", FCVAR_CLIENTDLL | FCVAR_DONTRECORD | FCVAR_ARCHIVE | FCVAR_HIDDEN, "Saved if the player has see the ticket help screen." );
  22. const int k_iPopIndex_Any = -1000;
  23. const int k_iPopIndex_OnlyNotYetCompleted = -1001;
  24. const int k_iPopIndex_AnyNormal = -1002;
  25. const int k_iPopIndex_AnyIntermediate = -1003;
  26. const int k_iPopIndex_AnyAdvanced = -1004;
  27. const int k_iPopIndex_AnyExpert = -1005;
  28. const int k_iPopIndex_AnyHaunted = -1006;
  29. static void GetMvmChallengeSet( int idxChallenge, CMvMMissionSet &result )
  30. {
  31. result.Clear();
  32. if ( idxChallenge >= 0 )
  33. {
  34. result.SetMissionBySchemaIndex( idxChallenge, true );
  35. return;
  36. }
  37. bool bMannUP = GTFGCClientSystem()->GetSearchPlayForBraggingRights();
  38. #ifdef USE_MVM_TOUR
  39. int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  40. Assert( bMannUP || idxTour < 0 );
  41. #endif // USE_MVM_TOUR
  42. #ifdef USE_MVM_TOUR
  43. uint32 nNotCompletedChallenges = ~0U;
  44. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  45. if ( pParty )
  46. {
  47. for ( int i = 0 ; i < pParty->GetNumMembers() ; ++i )
  48. {
  49. nNotCompletedChallenges &= ~pParty->Obj().members( i ).completed_missions();
  50. }
  51. }
  52. else
  53. {
  54. if ( idxTour >= 0 )
  55. {
  56. uint32 nTours = 0, nCompletedChallenge = 0;
  57. GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &nTours, &nCompletedChallenge );
  58. nNotCompletedChallenges = ~nCompletedChallenge;
  59. }
  60. }
  61. #endif // USE_MVM_TOUR
  62. for ( int i = 0 ; i < GetItemSchema()->GetMvmMissions().Count() ; ++i )
  63. {
  64. const MvMMission_t &chal = GetItemSchema()->GetMvmMissions()[ i ];
  65. // Cannot select non-MannUp missions in mann up mode
  66. #ifdef USE_MVM_TOUR
  67. int iBadgeSlot = (idxTour < 0) ? -1 : GetItemSchema()->GetMvmMissionBadgeSlotForTour( idxTour, i );
  68. if ( bMannUP && iBadgeSlot < 0 )
  69. continue;
  70. #else // new mm
  71. bool bIsChallengeInMannUp = chal.m_unMannUpPoints > 0;
  72. if ( bMannUP && !bIsChallengeInMannUp )
  73. continue;
  74. #endif // USE_MVM_TOUR
  75. // Does this challenge fit the search criteria?
  76. bool bSelect = false;
  77. switch ( idxChallenge )
  78. {
  79. case k_iPopIndex_Any:
  80. bSelect = true;
  81. break;
  82. case k_iPopIndex_OnlyNotYetCompleted:
  83. #ifdef USE_MVM_TOUR
  84. if ( iBadgeSlot >= 0 )
  85. {
  86. int iChallengeBit = ( 1 << iBadgeSlot );
  87. if ( nNotCompletedChallenges & iChallengeBit )
  88. {
  89. bSelect = true;
  90. }
  91. }
  92. #endif // USE_MVM_TOUR
  93. break;
  94. case k_iPopIndex_AnyNormal:
  95. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Normal );
  96. break;
  97. case k_iPopIndex_AnyIntermediate:
  98. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Intermediate );
  99. break;
  100. case k_iPopIndex_AnyAdvanced:
  101. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Advanced );
  102. break;
  103. case k_iPopIndex_AnyExpert:
  104. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Expert );
  105. break;
  106. case k_iPopIndex_AnyHaunted:
  107. bSelect = ( chal.m_eDifficulty == k_EMvMChallengeDifficulty_Haunted );
  108. break;
  109. default:
  110. Assert( false );
  111. }
  112. result.SetMissionBySchemaIndex( i, bSelect );
  113. }
  114. }
  115. extern Color s_colorBannedPlayerListItem;
  116. extern Color s_colorPlayerListItem;
  117. extern Color s_colorChatRemovedFromQueue;
  118. extern Color s_colorChatAddedToQueue;
  119. extern Color s_colorChatPlayerJoinedParty;
  120. extern Color s_colorChatPlayerJoinedPartyName;
  121. extern Color s_colorChatPlayerLeftParty;
  122. extern Color s_colorChatPlayerLeftPartyName;
  123. extern Color s_colorChatPlayerChatName;
  124. extern Color s_colorChatPlayerChatText;
  125. extern Color s_colorChatDefault;
  126. extern Color s_colorChallengeForegroundEnabled;
  127. extern Color s_colorChallengeForegroundHaunted;
  128. extern Color s_colorChallengeForegroundDisabled;
  129. extern Color s_colorChallengeHeader;
  130. static void GetPlayerNameForSteamID( wchar_t *wCharPlayerName, int nBufSizeBytes, const CSteamID &steamID )
  131. {
  132. const char *pszName = steamapicontext->SteamFriends()->GetFriendPersonaName( steamID );
  133. V_UTF8ToUnicode( pszName, wCharPlayerName, nBufSizeBytes );
  134. }
  135. CLobbyPanel_MvM::CLobbyPanel_MvM( vgui::Panel *pParent, CBaseLobbyContainerFrame* pLobbyContainer )
  136. : CBaseLobbyPanel( pParent, pLobbyContainer )
  137. {
  138. m_pMvMMannVsMachineGroupPanel = NULL;
  139. m_pMvMMannUpGroupPanel = NULL;
  140. m_pMvMPracticeGroupPanel = NULL;
  141. m_pMvMTourOfDutyGroupPanel = NULL;
  142. m_pMvMTourOfDutyListGroupBox = NULL;
  143. m_pTourList = NULL;
  144. m_MvMEconItemsGroupBox = NULL;
  145. m_pSquadSurplusCheckButton = NULL;
  146. m_pOpenStoreButton = NULL;
  147. m_pOpenStoreButton2 = NULL;
  148. m_pOpenHelpButton = NULL;
  149. m_pMannUpNowButton = NULL;
  150. m_pMannUpTourLootDescriptionBox = NULL;
  151. m_pMannUpTourLootImage = NULL;
  152. //m_pMannUpTourLootDetailLabel = NULL;
  153. m_pTourDifficultyWarning = NULL;
  154. m_MvMPracticeGroupPanel = NULL;
  155. m_pMvMSelectChallengeGroupPanel = NULL;
  156. m_pMVMChallengeListGroupBox = NULL;
  157. // MvM
  158. m_pMvMMannVsMachineGroupPanel = new vgui::EditablePanel( this, "MannVsMachineGroupBox" );
  159. m_pMvMMannUpGroupPanel = new vgui::EditablePanel( this, "MannUpGroupBox" );
  160. m_pMvMPracticeGroupPanel = new vgui::EditablePanel( this, "PracticeGroupBox" );
  161. m_pMvMTourOfDutyGroupPanel = new vgui::EditablePanel( this, "MvMTourOfDutyGroupBox" );
  162. m_MvMEconItemsGroupBox = new vgui::EditablePanel( this, "MvMEconItemsGroupBox" );
  163. m_pMannUpTicketImage = new vgui::ImagePanel( m_MvMEconItemsGroupBox, "MannUpTicketImage" );
  164. m_pSquadSurplusImage = new vgui::ImagePanel( m_MvMEconItemsGroupBox, "SquadSurplusImage" );
  165. m_pMannUpTourLootDescriptionBox = new vgui::EditablePanel( this, "MannUpTourLootDescriptionBox" );
  166. m_pMannUpTourLootImage = new vgui::ImagePanel( m_pMannUpTourLootDescriptionBox, "TourLootImage" );
  167. //m_pMannUpTourLootDetailLabel = new vgui::Label( m_pMannUpTourLootDescriptionBox, "TourLootDetailLabel", " );
  168. m_MvMPracticeGroupPanel = new vgui::EditablePanel( this, "MvMPracticeGroupBox" );
  169. m_pMvMSelectChallengeGroupPanel = new vgui::EditablePanel( this, "MvMSelectChallengeGroupBox" );
  170. m_pMVMChallengeListGroupBox = new vgui::EditablePanel( m_pMvMSelectChallengeGroupPanel, "ChallengeListGroupBox" );
  171. m_pChallengeList = new ChallengeList( this, m_pMVMChallengeListGroupBox, "ChallengeList" );
  172. m_pMvMTourOfDutyListGroupBox = new vgui::EditablePanel( m_pMvMTourOfDutyGroupPanel, "TourlistGroupBox" );
  173. m_pTourList = new vgui::SectionedListPanel( m_pMvMTourOfDutyListGroupBox, "TourList" );
  174. m_pTourDifficultyWarning = new vgui::Label( m_pMvMTourOfDutyGroupPanel, "TourDifficultyWarning", "" );
  175. m_fontChallengeListHeader = 0;
  176. m_fontChallengeListItem = 0;
  177. }
  178. CLobbyPanel_MvM::~CLobbyPanel_MvM()
  179. {}
  180. //-----------------------------------------------------------------------------
  181. void CLobbyPanel_MvM::FireGameEvent( IGameEvent *event )
  182. {
  183. BaseClass::FireGameEvent( event );
  184. const char *pszEventName = event->GetName();
  185. if ( !Q_stricmp( pszEventName, "mm_lobby_member_join" ) )
  186. {
  187. #ifdef USE_MVM_TOUR
  188. WriteTourList();
  189. #endif // USE_MVM_TOUR
  190. WriteChallengeList();
  191. return;
  192. }
  193. else if ( !Q_stricmp( pszEventName, "mm_lobby_member_leave" ) )
  194. {
  195. #ifdef USE_MVM_TOUR
  196. WriteTourList();
  197. #endif // USE_MVM_TOUR
  198. WriteChallengeList();
  199. return;
  200. }
  201. }
  202. void CLobbyPanel_MvM::OnCommand( const char *command )
  203. {
  204. if ( FStrEq( command, "open_store_ticket" ) )
  205. {
  206. // Open the store, and show the upgrade advice
  207. EconUI()->CloseEconUI();
  208. CSchemaItemDefHandle hItemDef( CTFItemSchema::k_rchMvMTicketItemDefName );
  209. EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( hItemDef->GetDefinitionIndex() );
  210. return;
  211. }
  212. else if ( FStrEq( command, "open_store_voucher" ) )
  213. {
  214. // Open the store, and show the upgrade advice
  215. EconUI()->CloseEconUI();
  216. CSchemaItemDefHandle hItemDef( CTFItemSchema::k_rchMvMSquadSurplusVoucherItemDefName );
  217. EconUI()->GetStorePanel()->AddToCartAndCheckoutImmediately( hItemDef->GetDefinitionIndex() );
  218. return;
  219. }
  220. else if ( FStrEq( command, "open_help" ) )
  221. {
  222. CExplanationPopup *pPopup = dynamic_cast< CExplanationPopup* >( GetParent()->FindChildByName("StartExplanation") );
  223. if ( pPopup )
  224. {
  225. pPopup->Popup();
  226. }
  227. return;
  228. }
  229. else if ( FStrEq( command, "mann_up_now" ) )
  230. {
  231. GTFGCClientSystem()->SetSearchChallenges( CMvMMissionSet() );
  232. m_pContainer->OnCommand( "back" );
  233. m_pContainer->OnCommand( "mannup" );
  234. return;
  235. }
  236. BaseClass::OnCommand( command );
  237. }
  238. void CLobbyPanel_MvM::SetMannUpTicketCount( int nCount )
  239. {
  240. m_pMannUpTicketImage->SetImage( nCount > 0 ? "pve/mvm_ticket_active" : "pve/mvm_ticket_inactive" );
  241. char szCount[ 5 ];
  242. V_snprintf( szCount, sizeof( szCount ), "%i", nCount );
  243. m_MvMEconItemsGroupBox->SetDialogVariable( "ticket_count", szCount );
  244. }
  245. void CLobbyPanel_MvM::SetSquadSurplusCount( int nCount )
  246. {
  247. char szCount[ 5 ];
  248. V_snprintf( szCount, sizeof( szCount ), "%i", nCount );
  249. m_MvMEconItemsGroupBox->SetDialogVariable( "voucher_count", szCount );
  250. }
  251. EMatchGroup CLobbyPanel_MvM::GetMatchGroup( void ) const
  252. {
  253. return GTFGCClientSystem()->GetSearchPlayForBraggingRights() ? k_nMatchGroup_MvM_MannUp : k_nMatchGroup_MvM_Practice;
  254. }
  255. void CLobbyPanel_MvM::OnCheckButtonChecked( vgui::Panel *panel )
  256. {
  257. if ( m_iWritingPanel > 0 )
  258. return;
  259. if ( panel == m_pSquadSurplusCheckButton )
  260. {
  261. if ( BIsPartyInUIState() && GTFGCClientSystem()->GetSearchPlayForBraggingRights() )
  262. {
  263. if ( m_pSquadSurplusCheckButton->IsSelected() )
  264. {
  265. if ( GTFGCClientSystem()->BLocalPlayerInventoryHasSquadSurplusVoucher() )
  266. {
  267. GTFGCClientSystem()->SetLocalPlayerSquadSurplus( true );
  268. m_pSquadSurplusImage->SetImage( "pve/mvm_voucher_active" );
  269. }
  270. else
  271. {
  272. m_pSquadSurplusCheckButton->SetSilentMode( true );
  273. m_pSquadSurplusCheckButton->SetSelected( false );
  274. m_pSquadSurplusCheckButton->SetSilentMode( false );
  275. ShowEconRequirementDialog( "#TF_MvM_RequiresSquadSurplusVoucher_Title", "#TF_MvM_RequiresSquadSurplusVoucher", CTFItemSchema::k_rchMvMSquadSurplusVoucherItemDefName );
  276. }
  277. }
  278. else
  279. {
  280. GTFGCClientSystem()->SetLocalPlayerSquadSurplus( false );
  281. m_pSquadSurplusImage->SetImage( "pve/mvm_voucher_inactive" );
  282. }
  283. }
  284. else
  285. {
  286. WriteGameSettingsControls();
  287. }
  288. return;
  289. }
  290. BaseClass::OnCheckButtonChecked( panel );
  291. }
  292. void CLobbyPanel_MvM::OnItemLeftClick( vgui::Panel* panel )
  293. {
  294. if ( m_iWritingPanel > 0 )
  295. return;
  296. #ifdef USE_MVM_TOUR
  297. if ( panel == m_pTourList )
  298. {
  299. OnClickedOnTour();
  300. }
  301. #endif // USE_MVM_TOUR
  302. else if ( panel == m_pChallengeList )
  303. {
  304. OnClickedOnChallenge();
  305. }
  306. BaseClass::OnItemLeftClick( panel );
  307. }
  308. void CLobbyPanel_MvM::ApplyChatUserSettings( const LobbyPlayerInfo& player, KeyValues* pSettings ) const
  309. {
  310. if ( GTFGCClientSystem()->GetSearchPlayForBraggingRights() )
  311. {
  312. pSettings->SetInt( "has_ticket", player.m_bHasTicket ? m_iImageHasTicket : m_iImageNoTicket );
  313. pSettings->SetInt( "squad_surplus", player.m_bSquadSurplus ? m_iImageSquadSurplus : m_iImageNoSquadSurplus );
  314. }
  315. }
  316. #ifdef USE_MVM_TOUR
  317. void CLobbyPanel_MvM::OnClickedOnTour()
  318. {
  319. int iSelected = m_pTourList->GetSelectedItem();
  320. m_pTourList->SetSelectedItem( -1 );
  321. if ( iSelected < 0 )
  322. return;
  323. if ( BIsPartyLeader() && BIsPartyInUIState() )
  324. {
  325. int iTourIndex = m_pTourList->GetItemData( iSelected )->GetInt( "tour_index", -1 );
  326. Assert( iTourIndex >= 0 );
  327. GTFGCClientSystem()->SetSearchMannUpTourIndex( iTourIndex );
  328. }
  329. else
  330. {
  331. WriteChallengeList();
  332. }
  333. }
  334. #endif // USE_MVM_TOUR
  335. void CLobbyPanel_MvM::WriteGameSettingsControls()
  336. {
  337. BaseClass::WriteGameSettingsControls();
  338. // Make sure we want to be in matchmaking. (If we don't, the frame should hide us pretty quickly.)
  339. // We might get an event or something right at the transition point occasionally when the UI should
  340. // not be visible
  341. if ( GTFGCClientSystem()->GetMatchmakingUIState() == eMatchmakingUIState_Inactive )
  342. {
  343. return;
  344. }
  345. ++m_iWritingPanel;
  346. bool bLeader = BIsPartyLeader();
  347. bool bInUIState = BIsPartyInUIState();
  348. TF_Matchmaking_WizardStep eWizardStep = GTFGCClientSystem()->GetWizardStep();
  349. // MVM
  350. m_pMvMMannVsMachineGroupPanel->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_PLAY_FOR_BRAGGING_RIGHTS );
  351. m_pMvMMannUpGroupPanel->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_PLAY_FOR_BRAGGING_RIGHTS );
  352. m_pMvMPracticeGroupPanel->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_PLAY_FOR_BRAGGING_RIGHTS );
  353. m_pMannUpTourLootDescriptionBox->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_TOUR_OF_DUTY );
  354. m_pMvMTourOfDutyGroupPanel->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_TOUR_OF_DUTY );
  355. m_pMvMSelectChallengeGroupPanel->SetVisible( eWizardStep == TF_Matchmaking_WizardStep_MVM_CHALLENGE );
  356. bool bShowBottomPanel = ( eWizardStep == TF_Matchmaking_WizardStep_MVM_CHALLENGE );
  357. if ( !tf_matchmaking_ticket_help.GetBool() && bShowBottomPanel && GTFGCClientSystem()->GetSearchPlayForBraggingRights() )
  358. {
  359. OnCommand( "open_help" );
  360. tf_matchmaking_ticket_help.SetValue( 1 );
  361. }
  362. m_MvMEconItemsGroupBox->SetVisible( bShowBottomPanel && GTFGCClientSystem()->GetSearchPlayForBraggingRights() );
  363. m_MvMPracticeGroupPanel->SetVisible( bShowBottomPanel && !GTFGCClientSystem()->GetSearchPlayForBraggingRights() );
  364. if ( m_pMvMTourOfDutyGroupPanel->IsVisible() )
  365. {
  366. SetNavToRelay( m_pMvMTourOfDutyGroupPanel->GetName() );
  367. }
  368. else if ( m_pMvMSelectChallengeGroupPanel->IsVisible() )
  369. if ( m_pMvMSelectChallengeGroupPanel->IsVisible() )
  370. {
  371. SetNavToRelay( m_pMvMSelectChallengeGroupPanel->GetName() );
  372. }
  373. if ( m_MvMPracticeGroupPanel->IsVisible() )
  374. {
  375. SetNavToRelay( m_MvMPracticeGroupPanel->GetName() );
  376. }
  377. else if ( m_MvMEconItemsGroupBox->IsVisible() )
  378. {
  379. SetNavToRelay( m_MvMEconItemsGroupBox->GetName() );
  380. }
  381. m_pContainer->SetNextButtonEnabled( true );
  382. #ifdef USE_MVM_TOUR
  383. WriteTourList();
  384. #endif // USE_MVM_TOUR
  385. WriteChallengeList();
  386. FOR_EACH_VEC( m_vecSearchCriteriaLabels, i )
  387. {
  388. m_vecSearchCriteriaLabels[i]->SetEnabled( bInUIState );
  389. }
  390. m_pMVMChallengeListGroupBox->SetControlVisible( "GreyOutPanel", !( bLeader && bInUIState ) );
  391. #ifdef USE_MVM_TOUR
  392. m_pMvMTourOfDutyListGroupBox->SetControlVisible( "GreyOutPanel", !( bLeader && bInUIState ) );
  393. #endif // USE_MVM_TOUR
  394. bool bPlayForBraggingRights = GTFGCClientSystem()->GetSearchPlayForBraggingRights();
  395. m_pSquadSurplusCheckButton->SetEnabled( bInUIState && bPlayForBraggingRights );
  396. m_pSquadSurplusCheckButton->SetSilentMode( true );
  397. m_pSquadSurplusCheckButton->SetSelected( GTFGCClientSystem()->GetLocalPlayerSquadSurplus() );
  398. m_pSquadSurplusCheckButton->SetSilentMode( false );
  399. m_pSquadSurplusImage->SetImage( GTFGCClientSystem()->GetLocalPlayerSquadSurplus() ? "pve/mvm_voucher_active" : "pve/mvm_voucher_inactive" );
  400. --m_iWritingPanel;
  401. }
  402. bool CLobbyPanel_MvM::ShouldShowLateJoin() const
  403. {
  404. TF_Matchmaking_WizardStep eWizardStep = GTFGCClientSystem()->GetWizardStep();
  405. return
  406. #ifdef USE_MVM_TOUR
  407. ( eWizardStep == TF_Matchmaking_WizardStep_MVM_TOUR_OF_DUTY ) ||
  408. #endif // USE_MVM_TOUR
  409. ( eWizardStep == TF_Matchmaking_WizardStep_MVM_CHALLENGE ) ||
  410. ( ( eWizardStep == TF_Matchmaking_WizardStep_SEARCHING ) && ( GTFGCClientSystem()->GetSearchMode() == TF_Matchmaking_MVM ) );
  411. }
  412. #ifdef USE_MVM_TOUR
  413. void CLobbyPanel_MvM::WriteTourList()
  414. {
  415. if ( !GTFGCClientSystem()->GetSearchPlayForBraggingRights() )
  416. return;
  417. ++m_iWritingPanel;
  418. bool bLeader = BIsPartyLeader();
  419. bool bInUIState = BIsPartyInUIState();
  420. int idxSelectedTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  421. m_pTourList->RemoveAll();
  422. m_pTourList->RemoveAllSections();
  423. m_pTourList->SetClickable( bLeader && bInUIState );
  424. m_pTourList->AddSection( 0, "Tour name" );
  425. m_pTourList->SetSectionAlwaysVisible( 0, false );
  426. m_pTourList->SetSectionFgColor( 0, s_colorChallengeHeader );
  427. m_pTourList->SetSectionDividerColor( 0, Color(0,0,0,0) );
  428. m_pTourList->AddColumnToSection( 0, "new","", vgui::SectionedListPanel::COLUMN_IMAGE, m_iNewWidth );
  429. m_pTourList->AddColumnToSection( 0, "check_box", "", vgui::SectionedListPanel::COLUMN_IMAGE, m_iChallengeCheckBoxWidth );
  430. m_pTourList->AddColumnToSection( 0, "spacer", "", 0, m_iChallengeSpacer );
  431. m_pTourList->AddColumnToSection( 0, "display_name", "Tour", 0, m_iTourNameWidth );
  432. m_pTourList->AddColumnToSection( 0, "skill", "Difficulty", 0, m_iTourSkillWidth );
  433. m_pTourList->AddColumnToSection( 0, "progress", "Progress", 0, m_iTourProgressWidth );
  434. m_pTourList->AddColumnToSection( 0, "badge_level", "Tours Completed", 0, m_iTourNumberWidth );
  435. m_pTourList->SetFontSection( 0, m_fontChallengeListHeader );
  436. bool bCompletedOneAdvancedTour = false;
  437. uint32 unBadgeLevel = 0, unCompletedChallengeMask = 0;
  438. const char *pszWarningString = "#TF_MVM_Tour_ExpertDifficulty_Warning";
  439. // Local player has completed at least one Advanced tour?
  440. FOR_EACH_VEC( GetItemSchema()->GetMvmTours(), idxTour )
  441. {
  442. GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &unBadgeLevel, &unCompletedChallengeMask );
  443. const MvMTour_t &tourInfo = GetItemSchema()->GetMvmTours()[idxTour];
  444. if ( tourInfo.m_eDifficulty >= k_EMvMChallengeDifficulty_Advanced && unBadgeLevel > 0 )
  445. {
  446. bCompletedOneAdvancedTour = true;
  447. break;
  448. }
  449. }
  450. // Add a row for each tour
  451. FOR_EACH_VEC( GetItemSchema()->GetMvmTours(), idxTour )
  452. {
  453. const MvMTour_t &tour = GetItemSchema()->GetMvmTours()[ idxTour ];
  454. KeyValues *kvItem = new KeyValues("item");
  455. GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &unBadgeLevel, &unCompletedChallengeMask );
  456. int nCompletedChallengeCount = 0;
  457. for ( int i = 0 ; i < tour.m_vecMissions.Count() ; ++i )
  458. {
  459. if ( unCompletedChallengeMask & ( 1 << tour.m_vecMissions[i].m_iBadgeSlot ) )
  460. {
  461. ++nCompletedChallengeCount;
  462. }
  463. }
  464. char cchTemp[256];
  465. V_sprintf_safe( cchTemp, "%d / %d", nCompletedChallengeCount, tour.m_vecMissions.Count() );
  466. kvItem->SetString( "progress", cchTemp );
  467. uint32 iTourNumber = Max( 1U, unBadgeLevel );
  468. V_sprintf_safe( cchTemp, "%d", iTourNumber );
  469. kvItem->SetString( "badge_level", cchTemp );
  470. if ( tour.m_bIsNew )
  471. {
  472. kvItem->SetInt( "new", m_iImageNew );
  473. }
  474. kvItem->SetInt( "check_box", idxSelectedTour == idxTour ? m_iImageRadioButtonYes : m_iImageRadioButtonNo );
  475. kvItem->SetString( "display_name", tour.m_sTourNameLocalizationToken.Get() );
  476. kvItem->SetString( "skill", GetMvMChallengeDifficultyLocName( tour.m_eDifficulty ) );
  477. kvItem->SetInt( "tour_index", idxTour );
  478. int itemID = m_pTourList->AddItem( 0, kvItem );
  479. m_pTourList->SetItemFont( itemID, m_fontChallengeListItem );
  480. if ( tour.m_eDifficulty >= k_EMvMChallengeDifficulty_Expert && !bCompletedOneAdvancedTour )
  481. {
  482. m_pTourList->SetItemFgColor( itemID, s_colorBannedPlayerListItem );
  483. pszWarningString = "#TF_MVM_Tour_ExpertDifficulty_Denied";
  484. }
  485. else
  486. {
  487. m_pTourList->SetItemFgColor( itemID, s_colorChallengeForegroundEnabled );
  488. }
  489. }
  490. m_pTourList->SetSelectedItem( idxSelectedTour );
  491. const char *pszSelectedTourLocToken = "TF_MvM_Tour_NoSelection";
  492. const char *pszLootImage = "pve/mvm_loot_image";
  493. bool bShowDifficultyWarning = false;
  494. if ( idxSelectedTour >= 0 )
  495. {
  496. const MvMTour_t &tour = GetItemSchema()->GetMvmTours()[ idxSelectedTour ];
  497. pszLootImage = tour.m_sLootImageName.Get();
  498. pszSelectedTourLocToken = tour.m_sTourNameLocalizationToken.Get();
  499. // Check if we should show the difficulty warning
  500. if ( tour.m_eDifficulty >= k_EMvMChallengeDifficulty_Expert )
  501. {
  502. // Deny expert mode if they haven't completed at least one Advanced tour
  503. if ( !bCompletedOneAdvancedTour )
  504. {
  505. m_pContainer->SetNextButtonEnabled( false );
  506. }
  507. // Local player hasn't completed one mission?
  508. if ( !GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxSelectedTour, &unBadgeLevel, &unCompletedChallengeMask )
  509. || unBadgeLevel == 0 )
  510. {
  511. bShowDifficultyWarning = true;
  512. }
  513. // Anybody in the party hasn't completed a mission?
  514. CTFParty *pParty = GTFGCClientSystem()->GetParty();
  515. if ( pParty != NULL )
  516. {
  517. for ( int i = 0 ; !bShowDifficultyWarning && i < pParty->GetNumMembers() ; ++i )
  518. {
  519. if ( pParty->Obj().members( i ).badge_level() == 0 )
  520. {
  521. bShowDifficultyWarning = true;
  522. }
  523. }
  524. }
  525. }
  526. }
  527. char archTemp[ 256 ];
  528. V_sprintf_safe( archTemp, "%s_LootDescription", pszSelectedTourLocToken );
  529. m_pMannUpTourLootDescriptionBox->SetDialogVariable( "tour_loot_detail", g_pVGuiLocalize->Find( archTemp ) );
  530. m_pMannUpTourLootImage->SetImage( pszLootImage );
  531. wchar_t wszLocalized[512];
  532. g_pVGuiLocalize->ConstructString_safe( wszLocalized, g_pVGuiLocalize->Find( pszWarningString ), 0 );
  533. m_pTourDifficultyWarning->SetText( wszLocalized );
  534. m_pTourDifficultyWarning->SetVisible( bShowDifficultyWarning );
  535. --m_iWritingPanel;
  536. }
  537. #endif // USE_MVM_TOUR
  538. void CLobbyPanel_MvM::WriteChallengeList()
  539. {
  540. ++m_iWritingPanel;
  541. bool bLeader = BIsPartyLeader();
  542. bool bInUIState = BIsPartyInUIState();
  543. bool bForBraggingRights = GTFGCClientSystem()->GetSearchPlayForBraggingRights();
  544. #ifdef USE_MVM_TOUR
  545. int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  546. char szTours[ 8 ] = "";
  547. if ( idxTour >= 0 )
  548. {
  549. uint32 nTours, nCompletedChallenge;
  550. GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &nTours, &nCompletedChallenge );
  551. if ( nTours < 1 ) // if we don't have a badge, show "1"
  552. nTours = 1;
  553. V_snprintf( szTours, sizeof( szTours ), "%u", nTours );
  554. }
  555. m_pChallengeList->SetClickable( bLeader && bInUIState );
  556. if ( idxTour < 0 )
  557. {
  558. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "tour_name", g_pVGuiLocalize->Find( "#TF_MvM_Missions" ) );
  559. }
  560. else
  561. {
  562. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "tour_name", g_pVGuiLocalize->Find( GetItemSchema()->GetMvmTours()[ idxTour ].m_sTourNameLocalizationToken.Get() ) );
  563. }
  564. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "complete_heading", g_pVGuiLocalize->Find( bForBraggingRights ? "#TF_MvM_Complete" : "#TF_MvM_Difficulty" ) );
  565. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "tour_level", szTours );
  566. m_pMvMSelectChallengeGroupPanel->SetControlVisible( "TourLevelImage", idxTour >= 0 );
  567. #else // new mm
  568. char szTours[ 8 ] = "";
  569. m_pChallengeList->SetClickable( bLeader && bInUIState );
  570. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "tour_name", g_pVGuiLocalize->Find( "#TF_MvM_Missions" ) );
  571. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "complete_heading", g_pVGuiLocalize->Find( "#TF_MvM_Difficulty" ) );
  572. m_pMvMSelectChallengeGroupPanel->SetDialogVariable( "tour_level", szTours );
  573. m_pMvMSelectChallengeGroupPanel->SetControlVisible( "TourLevelImage", false );
  574. #endif // USE_MVM_TOUR
  575. CMvMMissionSet searchChallenges;
  576. GTFGCClientSystem()->GetSearchChallenges( searchChallenges );
  577. m_pChallengeList->RemoveAll();
  578. m_pChallengeList->RemoveAllSections();
  579. // int iSelectChallengeItem = -1;
  580. int nCurrentSection = -1;
  581. KeyValues *kvItem = NULL;
  582. int itemID = 0;
  583. //
  584. // Top section is for special multi-select checkboxes
  585. //
  586. ++nCurrentSection;
  587. m_pChallengeList->AddSection( nCurrentSection, "dummy_any_section" );
  588. m_pChallengeList->SetSectionAlwaysVisible( nCurrentSection, true );
  589. m_pChallengeList->SetSectionDividerColor( nCurrentSection, Color(0,0,0,0) );
  590. //m_pChallengeList->SetSectionFgColor( nCurrentSection, Color( 255, 255, 255, 255 ) );
  591. m_pChallengeList->AddColumnToSection( nCurrentSection, "check_box", "", vgui::SectionedListPanel::COLUMN_IMAGE, m_iChallengeCheckBoxWidth );
  592. m_pChallengeList->AddColumnToSection( nCurrentSection, "spacer", "", 0, m_iChallengeSpacer );
  593. m_pChallengeList->AddColumnToSection( nCurrentSection, "display_name", "", 0, m_iChallengeNameWidth );
  594. //m_pChallengeList->AddColumnToSection( nCurrentSection, "completed", "", 0, m_iChallengeCompletedWidth );
  595. //m_pChallengeList->SetFontSection( nCurrentSection, m_fontChallengeListHeader );
  596. //m_pChallengeList->SetSectionMinimumContentHeight( nCurrentSection, m_iMapImageHeight );
  597. m_pChallengeList->m_vecMapImages.Purge();
  598. // List of special multi-select options
  599. struct MissionMultiSelect_t
  600. {
  601. int m_idxChallenge;
  602. const char *m_pszDisplayName;
  603. bool m_bMannUp;
  604. bool m_bBootCamp;
  605. };
  606. static const MissionMultiSelect_t arMultiSelect[] =
  607. {
  608. #ifdef USE_MVM_TOUR
  609. { k_iPopIndex_Any, "#TF_MvM_AnyChallenge", true, false },
  610. // { k_iPopIndex_AnyHaunted, "#TF_MvM_AnyHauntedChallenge", false, true },
  611. { k_iPopIndex_AnyNormal, "#TF_MvM_AnyNormalChallenge", false, true },
  612. { k_iPopIndex_AnyIntermediate, "#TF_MvM_AnyIntermediateChallenge", false, true },
  613. { k_iPopIndex_AnyAdvanced, "#TF_MvM_AnyAdvancedChallenge", false, true },
  614. { k_iPopIndex_AnyExpert, "#TF_MvM_AnyExpertChallenge", false, true },
  615. { k_iPopIndex_OnlyNotYetCompleted, "#TF_MvM_OnlyChallengeNotYetCompleted", true, false }
  616. #else // new mm
  617. { k_iPopIndex_Any, "#TF_MvM_AnyChallenge", true, true },
  618. // { k_iPopIndex_AnyHaunted, "#TF_MvM_AnyHauntedChallenge", false, true },
  619. { k_iPopIndex_AnyNormal, "#TF_MvM_AnyNormalChallenge", true, true },
  620. { k_iPopIndex_AnyIntermediate, "#TF_MvM_AnyIntermediateChallenge", true, true },
  621. { k_iPopIndex_AnyAdvanced, "#TF_MvM_AnyAdvancedChallenge", true, true },
  622. { k_iPopIndex_AnyExpert, "#TF_MvM_AnyExpertChallenge", true, true },
  623. { k_iPopIndex_OnlyNotYetCompleted, "#TF_MvM_OnlyChallengeNotYetCompleted", false, false }
  624. #endif // USE_MVM_TOUR
  625. };
  626. // Scan each potential multi-select option
  627. for ( int i = 0 ; i < Q_ARRAYSIZE( arMultiSelect ) ; ++i )
  628. {
  629. const MissionMultiSelect_t &ms = arMultiSelect[i];
  630. // Check if entry is applicable for this mode
  631. if ( bForBraggingRights ? !ms.m_bMannUp : !ms.m_bBootCamp )
  632. continue;
  633. // Gather list of all missions that fit this mode
  634. CMvMMissionSet msChallenges;
  635. GetMvmChallengeSet( ms.m_idxChallenge, msChallenges );
  636. // Any missions actually met the criteria for this multi-select?
  637. // (e.g. we might not have any intermediate missions active right now).
  638. int iCheckImage;
  639. if ( msChallenges.IsEmpty() )
  640. {
  641. if ( ms.m_idxChallenge != k_iPopIndex_OnlyNotYetCompleted )
  642. continue;
  643. iCheckImage = m_iImageCheckBoxDisabled;
  644. }
  645. else
  646. {
  647. // Determine checkbox status. "Only not yet completed" is special
  648. if ( ms.m_idxChallenge == k_iPopIndex_OnlyNotYetCompleted )
  649. {
  650. if ( searchChallenges == msChallenges )
  651. iCheckImage = m_iImageCheckBoxYes; // all items currently selected
  652. else
  653. iCheckImage = m_iImageCheckBoxNo; // does not exactly match, show as a "no"
  654. }
  655. else
  656. {
  657. // Get set of checked challenges that fall under this category
  658. CMvMMissionSet checked( searchChallenges );
  659. checked.Intersect( msChallenges );
  660. if ( checked == msChallenges )
  661. iCheckImage = m_iImageCheckBoxYes; // all items currently selected
  662. //else if ( !checked.IsEmpty() ) // Nope, don't ever show "mixed" state
  663. // iCheckImage = m_iImageCheckBoxMixed; // some items currently selected
  664. else
  665. iCheckImage = m_iImageCheckBoxNo; // no items currently selected
  666. }
  667. }
  668. kvItem = new KeyValues("item");
  669. kvItem->SetInt( "check_box", iCheckImage );
  670. kvItem->SetString( "display_name", ms.m_pszDisplayName );
  671. kvItem->SetInt( "pop_index", ms.m_idxChallenge );
  672. itemID = m_pChallengeList->AddItem( nCurrentSection, kvItem );
  673. m_pChallengeList->SetItemFont( itemID, m_fontChallengeListItem );
  674. Color color = s_colorChallengeForegroundEnabled;
  675. if ( ms.m_idxChallenge == k_iPopIndex_AnyHaunted )
  676. color = s_colorChallengeForegroundHaunted;
  677. if ( iCheckImage == m_iImageCheckBoxDisabled )
  678. color = s_colorChallengeForegroundDisabled;
  679. m_pChallengeList->SetItemFgColor( itemID, color );
  680. }
  681. //
  682. // Now add a section for each map
  683. //
  684. int nCurrentMap = -1;
  685. FOR_EACH_VEC( GetItemSchema()->GetMvmMissions(), iMissionIndex )
  686. {
  687. const MvMMission_t &mission = GetItemSchema()->GetMvmMissions()[ iMissionIndex ];
  688. #ifdef USE_MVM_TOUR
  689. if ( bForBraggingRights && GetItemSchema()->FindMvmMissionInTour( idxTour, iMissionIndex) < 0 ) // !KLUDGE! This is sort of crappy, we probably should iterate the tour's mission list rather than iterating the larger list with filtering
  690. #else // new mm
  691. if ( bForBraggingRights && !searchChallenges.GetMissionBySchemaIndex( iMissionIndex ) )
  692. #endif // USE_MVM_TOUR
  693. continue;
  694. kvItem = new KeyValues("item");
  695. const MvMMap_t &map = GetItemSchema()->GetMvmMaps()[ mission.m_iDisplayMapIndex ];
  696. if ( mission.m_iDisplayMapIndex != nCurrentMap )
  697. {
  698. ++nCurrentSection;
  699. m_pChallengeList->AddSection( nCurrentSection, map.m_sDisplayName.Get() );
  700. m_pChallengeList->SetSectionAlwaysVisible( nCurrentSection, true );
  701. m_pChallengeList->SetSectionFgColor( nCurrentSection, s_colorChallengeHeader );
  702. m_pChallengeList->SetSectionDividerColor( nCurrentSection, Color(0,0,0,0) );
  703. #ifdef USE_MVM_TOUR
  704. m_pChallengeList->AddColumnToSection( nCurrentSection, "check_box", "", vgui::SectionedListPanel::COLUMN_IMAGE, m_iChallengeCheckBoxWidth );
  705. #else // new mm
  706. // for mannup, don't show check box
  707. if ( bForBraggingRights )
  708. {
  709. m_pChallengeList->AddColumnToSection( nCurrentSection, "spacer", "", 0, m_iChallengeCheckBoxWidth );
  710. }
  711. else
  712. {
  713. m_pChallengeList->AddColumnToSection( nCurrentSection, "check_box", "", vgui::SectionedListPanel::COLUMN_IMAGE, m_iChallengeCheckBoxWidth );
  714. }
  715. #endif // USE_MVM_TOUR
  716. m_pChallengeList->AddColumnToSection( nCurrentSection, "spacer", "", 0, m_iChallengeSpacer );
  717. m_pChallengeList->AddColumnToSection( nCurrentSection, "display_name", map.m_sDisplayName.Get(), 0, m_iChallengeNameWidth );
  718. m_pChallengeList->AddColumnToSection( nCurrentSection, "skill", "", 0, m_iChallengeSkillWidth );
  719. m_pChallengeList->SetFontSection( nCurrentSection, m_fontChallengeListHeader );
  720. m_pChallengeList->SetSectionMinimumHeight( nCurrentSection, m_iMapImageHeight );
  721. BitmapImage &img = m_pChallengeList->m_vecMapImages[ m_pChallengeList->m_vecMapImages.AddToTail() ];
  722. CFmtStr sImageName("vgui/maps/menu_thumb_%s", map.m_sMap.Get() );
  723. img.SetImageFile( sImageName );
  724. nCurrentMap = mission.m_iDisplayMapIndex;
  725. }
  726. //wchar_t wszChallengeName[ 256 ];
  727. //g_pVGuiLocalize->ConstructString_safe( wszChallengeName, L"%s1 (%s2)", 2,
  728. // g_pVGuiLocalize->Find( mission.m_sDisplayName.Get() ), g_pVGuiLocalize->Find( mission.m_sMode.Get() ) );
  729. //kvItem->SetWString( "display_name", wszChallengeName );
  730. kvItem->SetString( "display_name", mission.m_sDisplayName.Get() );
  731. bool bSelected = searchChallenges.GetMissionBySchemaIndex( iMissionIndex );
  732. kvItem->SetInt( "check_box", bSelected ? m_iImageCheckBoxYes : m_iImageCheckBoxNo );
  733. const char *pszDifficulty = "";
  734. #ifdef USE_MVM_TOUR
  735. if ( !bForBraggingRights )
  736. #endif // USE_MVM_TOUR
  737. {
  738. pszDifficulty = GetMvMChallengeDifficultyLocName( mission.m_eDifficulty );
  739. }
  740. kvItem->SetString( "skill", pszDifficulty );
  741. kvItem->SetInt( "pop_index", iMissionIndex );
  742. itemID = m_pChallengeList->AddItem( nCurrentSection, kvItem );
  743. m_pChallengeList->SetItemFont( itemID, m_fontChallengeListItem );
  744. Color color = s_colorChallengeForegroundEnabled;
  745. if ( mission.m_eDifficulty == k_EMvMChallengeDifficulty_Haunted )
  746. color = s_colorChallengeForegroundHaunted;
  747. m_pChallengeList->SetItemFgColor( itemID, color );
  748. kvItem->deleteThis();
  749. }
  750. --m_iWritingPanel;
  751. }
  752. //-----------------------------------------------------------------------------
  753. void CLobbyPanel_MvM::ApplySchemeSettings( vgui::IScheme *pScheme )
  754. {
  755. BaseClass::ApplySchemeSettings( pScheme );
  756. m_pOpenStoreButton = dynamic_cast<vgui::Button *>(FindChildByName( "OpenStoreButton", true )); Assert( m_pOpenStoreButton );
  757. m_pOpenStoreButton2 = dynamic_cast<vgui::Button *>(FindChildByName( "OpenStoreButton2", true )); Assert( m_pOpenStoreButton2 );
  758. m_pOpenHelpButton = dynamic_cast<vgui::Button *>(FindChildByName( "OpenHelpButton", true )); Assert( m_pOpenHelpButton );
  759. m_pSquadSurplusCheckButton = dynamic_cast<vgui::CheckButton *>(FindChildByName( "SquadSurplusCheckButton", true )); Assert( m_pSquadSurplusCheckButton );
  760. m_pMannUpNowButton = dynamic_cast<vgui::Button *>(FindChildByName( "MannUpNowButton", true )); Assert( m_pMannUpNowButton );
  761. m_iImageHasTicket = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_ticket_small", true ) );
  762. m_pImageList->GetImage( m_iImageHasTicket )->SetSize( m_iHasTicketWidth, m_iHasTicketWidth );
  763. m_iImageNoTicket = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_no_ticket_small", true ) );
  764. m_pImageList->GetImage( m_iImageNoTicket )->SetSize( m_iHasTicketWidth, m_iHasTicketWidth );
  765. m_iImageSquadSurplus = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_squad_surplus_small", true ) );
  766. m_pImageList->GetImage( m_iImageSquadSurplus )->SetSize( m_iSquadSurplusWidth, m_iSquadSurplusWidth );
  767. m_iImageNoSquadSurplus = m_pImageList->AddImage( vgui::scheme()->GetImage( "pve/mvm_no_squad_surplus_small", true ) );
  768. m_pImageList->GetImage( m_iImageNoSquadSurplus )->SetSize( m_iSquadSurplusWidth, m_iSquadSurplusWidth );
  769. m_pChatPlayerList->SetImageList( m_pImageList, false );
  770. m_pChatPlayerList->SetVisible( true );
  771. m_pChallengeList->SetImageList( m_pImageList, false );
  772. #ifdef USE_MVM_TOUR
  773. m_pTourList->SetImageList( m_pImageList, false );
  774. #endif // USE_MVM_TOUR
  775. //
  776. // Populate the challenge list
  777. //
  778. m_pChallengeList->AddActionSignalTarget( this );
  779. #ifdef USE_MVM_TOUR
  780. m_pTourList->AddActionSignalTarget( this );
  781. #endif // USE_MVM_TOUR
  782. m_pSquadSurplusCheckButton->AddActionSignalTarget( this );
  783. m_pChatPlayerList->AddActionSignalTarget( this );
  784. m_pOpenStoreButton->AddActionSignalTarget( this );
  785. m_pOpenStoreButton2->AddActionSignalTarget( this );
  786. m_pOpenHelpButton->AddActionSignalTarget( this );
  787. m_pMannUpNowButton->AddActionSignalTarget( this );
  788. m_pChallengeList->SetVerticalScrollbar( true );
  789. m_pChallengeList->RemoveAll();
  790. m_pChallengeList->RemoveAllSections();
  791. m_pChallengeList->SetDrawHeaders( true );
  792. m_pChallengeList->SetClickable( true );
  793. m_pChallengeList->SetBgColor( Color( 0, 0, 0, 0 ) );
  794. m_pChallengeList->SetBorder( NULL );
  795. #ifdef USE_MVM_TOUR
  796. m_pTourList->SetDrawHeaders( false );
  797. #endif // USE_MVM_TOUR
  798. m_fontChallengeListHeader = pScheme->GetFont( "HudFontSmallestBold", true );
  799. m_fontChallengeListItem = pScheme->GetFont( "HudFontSmallest", true );
  800. //
  801. // Populate the player list
  802. //
  803. int nAvatarWidth = ( ( m_iAvatarWidth * 5 / 4 ) + 1 );
  804. int nExtraWidth = m_pChatPlayerList->GetWide() - nAvatarWidth - m_iPlayerNameWidth - m_iBannedWidth - m_iHasTicketWidth - m_iSquadSurplusWidth - m_iBadgeLevelWidth;
  805. m_pChatPlayerList->AddColumnToSection( 0, "avatar", "#TF_Players", vgui::SectionedListPanel::COLUMN_IMAGE, nAvatarWidth );
  806. m_pChatPlayerList->AddColumnToSection( 0, "name", "", 0, m_iPlayerNameWidth + nExtraWidth );
  807. m_pChatPlayerList->AddColumnToSection( 0, "is_banned", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, m_iBannedWidth );
  808. m_pChatPlayerList->AddColumnToSection( 0, "has_ticket", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, m_iHasTicketWidth );
  809. m_pChatPlayerList->AddColumnToSection( 0, "squad_surplus", "", vgui::SectionedListPanel::COLUMN_IMAGE | vgui::SectionedListPanel::COLUMN_CENTER, m_iSquadSurplusWidth );
  810. m_pChatPlayerList->AddColumnToSection( 0, "badge_level", "#TF_MvM_Tours", vgui::SectionedListPanel::COLUMN_CENTER, m_iBadgeLevelWidth );
  811. }
  812. void CLobbyPanel_MvM::PerformLayout()
  813. {
  814. #ifdef USE_MVM_TOUR
  815. WriteTourList();
  816. #endif // USE_MVM_TOUR
  817. WriteChallengeList();
  818. BaseClass::PerformLayout();
  819. }
  820. void CLobbyPanel_MvM::OnClickedOnChallenge()
  821. {
  822. int iSelected = m_pChallengeList->GetSelectedItem();
  823. m_pChallengeList->SetSelectedItem( -1 );
  824. if ( iSelected < 0 )
  825. return;
  826. if ( BIsPartyLeader() && BIsPartyInUIState() )
  827. {
  828. int iChallengeIndex = m_pChallengeList->GetItemData( iSelected )->GetInt( "pop_index", -1 );
  829. #ifndef USE_MVM_TOUR
  830. // disallow player to select individual challenge in mannup
  831. if ( iChallengeIndex >= 0 && GTFGCClientSystem()->GetSearchPlayForBraggingRights() )
  832. return;
  833. #endif // !USE_MVM_TOUR
  834. CMvMMissionSet searchChallenges;
  835. // Fetch current selection. Except when clicking the "only uncompleted" checkbox, which is special
  836. if ( iChallengeIndex != k_iPopIndex_OnlyNotYetCompleted )
  837. GTFGCClientSystem()->GetSearchChallenges( searchChallenges );
  838. CMvMMissionSet setChallenges;
  839. GetMvmChallengeSet( iChallengeIndex, setChallenges );
  840. bool bSelect = ( m_pChallengeList->GetItemData( iSelected )->GetInt( "check_box" ) != m_iImageCheckBoxYes );
  841. for ( int i = 0 ; i < GetItemSchema()->GetMvmMissions().Count() ; ++i )
  842. {
  843. if ( setChallenges.GetMissionBySchemaIndex( i ) )
  844. {
  845. searchChallenges.SetMissionBySchemaIndex( i, bSelect );
  846. }
  847. }
  848. GTFGCClientSystem()->SetSearchChallenges( searchChallenges );
  849. }
  850. else
  851. {
  852. WriteChallengeList();
  853. }
  854. }
  855. void CLobbyPanel_MvM::ChallengeList::Paint()
  856. {
  857. vgui::SectionedListPanel::Paint();
  858. FOR_EACH_VEC( m_vecMapImages, i )
  859. {
  860. int x, y, w, h;
  861. if ( !GetSectionHeaderBounds( i + 1, x, y, w, h ) )
  862. {
  863. Assert( "MvM map mismatch" );
  864. continue;
  865. }
  866. // Dear god. Why is VGUI such a piece of crap?
  867. // And why is it such excruciating pain to do
  868. // anything at all?
  869. // Select subrectangle within image to draw
  870. w = m_pLobbyPanel->m_iMapImageWidth;
  871. h = m_pLobbyPanel->m_iMapImageHeight;
  872. m_vecMapImages[i].SetViewport( true, 0.0, 0.0, 1.0, (float)h / (float)w );
  873. // Compute horiziontal position of icon
  874. int gutter = vgui::scheme()->GetProportionalScaledValue( 5 );
  875. x -= gutter + m_pLobbyPanel->m_iMapImageWidth;
  876. // Save clipping rectangle. We want to be able to draw off to the left,
  877. // outside of our bounding box, but we need to keep the vertical clipping
  878. int left, top, right, bottom;
  879. bool bDisabled;
  880. g_pMatSystemSurface->GetClippingRect( left, top, right, bottom, bDisabled );
  881. // Adjust clipping rectangle
  882. int sx = x;
  883. int sy = y;
  884. LocalToScreen(sx, sy);
  885. g_pMatSystemSurface->SetClippingRect( sx, top, right, bottom );
  886. m_vecMapImages[i].DoPaint( x, y, w, h );
  887. // Restore clipping rectangle
  888. g_pMatSystemSurface->SetClippingRect( left, top, right, bottom );
  889. g_pMatSystemSurface->DisableClipping( bDisabled );
  890. }
  891. #ifdef USE_MVM_TOUR
  892. // We can only do checkmarks if we know what tour they are working towards
  893. int idxTour = GTFGCClientSystem()->GetSearchMannUpTourIndex();
  894. if ( idxTour >= 0 )
  895. {
  896. int nCheckSize = m_pLobbyPanel->m_iChallengeCompletedSize;
  897. int nCompletedX0 = m_pLobbyPanel->m_iChallengeCheckBoxWidth + m_pLobbyPanel->m_iChallengeNameWidth + m_pLobbyPanel->m_iChallengeSkillWidth / 4;
  898. uint32 nTours, nCompletedChallenge;
  899. bool bFoundPlayerCompletedChallenges = GTFGCClientSystem()->BGetLocalPlayerBadgeInfoForTour( idxTour, &nTours, &nCompletedChallenge );
  900. for ( int i = 0 ; i < GetItemCount() ; ++i )
  901. {
  902. // Get The Pop File Name for this item
  903. KeyValues *pkv = GetItemData( GetItemIDFromRow( i ) );
  904. int iMissionIndexInSchema = pkv->GetInt( "pop_index", -1 );
  905. if ( iMissionIndexInSchema < 0 ) // special multi-select entry
  906. continue;
  907. int iBadgeSlot = GetItemSchema()->GetMvmMissionBadgeSlotForTour( idxTour, iMissionIndexInSchema );
  908. if ( iBadgeSlot < 0 )
  909. continue;
  910. int x, y, w, h;
  911. GetItemBounds( i, x, y, w, h );
  912. if ( bFoundPlayerCompletedChallenges )
  913. {
  914. if ( nCompletedChallenge & (1 << iBadgeSlot) )
  915. {
  916. m_imageChallengeCompleted.SetColor( Color(255,255,255,255) );
  917. }
  918. else if ( GetSelectedItem() == i )
  919. {
  920. m_imageChallengeCompleted.SetColor( Color(0,0,0,255) );
  921. }
  922. else
  923. {
  924. m_imageChallengeCompleted.SetColor( Color(0,0,0,70) );
  925. }
  926. int checkX0 = nCompletedX0;
  927. int checkY0 = y + ( h - nCheckSize ) / 2;
  928. m_imageChallengeCompleted.DoPaint( checkX0, checkY0, nCheckSize, nCheckSize );
  929. }
  930. }
  931. }
  932. #endif // USE_MVM_TOUR
  933. }