//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Present a list of sessions from which the player can choose a game to join. // //=============================================================================// #include "sessionbrowserdialog.h" #include "engine/imatchmaking.h" #include "EngineInterface.h" #include "vgui_controls/ImagePanel.h" #include "vgui_controls/Label.h" #include "KeyValues.h" #include "vgui/ISurface.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" CSessionBrowserDialog *g_pBrowserDialog; //-------------------------------- // CSessionBrowserDialog //-------------------------------- CSessionBrowserDialog::CSessionBrowserDialog( vgui::Panel *pParent, KeyValues *pDialogKeys ) : BaseClass( pParent, "" ) { g_pBrowserDialog = this; m_pDialogKeys = pDialogKeys; SetDeleteSelfOnClose( true ); } CSessionBrowserDialog::~CSessionBrowserDialog() { m_pScenarioInfos.PurgeAndDeleteElements(); } //--------------------------------------------------------------------- // Purpose: Center the dialog on the screen //--------------------------------------------------------------------- void CSessionBrowserDialog::PerformLayout() { BaseClass::PerformLayout(); MoveToCenterOfScreen(); UpdateScenarioDisplay(); } //--------------------------------------------------------------------- // Purpose: Parse session properties and contexts from the resource file //--------------------------------------------------------------------- void CSessionBrowserDialog::ApplySettings( KeyValues *pResourceData ) { BaseClass::ApplySettings( pResourceData ); KeyValues *pScenarios = pResourceData->FindKey( "ScenarioInfoPanels" ); if ( pScenarios ) { for ( KeyValues *pScenario = pScenarios->GetFirstSubKey(); pScenario != NULL; pScenario = pScenario->GetNextKey() ) { CScenarioInfoPanel *pScenarioInfo = new CScenarioInfoPanel( this, "ScenarioInfoPanel" ); SETUP_PANEL( pScenarioInfo ); pScenarioInfo->m_pTitle->SetText( pScenario->GetString( "title" ) ); pScenarioInfo->m_pSubtitle->SetText( pScenario->GetString( "subtitle" ) ); pScenarioInfo->m_pMapImage->SetImage( pScenario->GetString( "image" ) ); int nTall = pScenario->GetInt( "tall", -1 ); if ( nTall > 0 ) { pScenarioInfo->SetTall( nTall ); } int nXPos = pScenario->GetInt( "xpos", -1 ); if ( nXPos >= 0 ) { int x, y; pScenarioInfo->GetPos( x, y ); pScenarioInfo->SetPos( nXPos, y ); } int nDescOneYpos = pScenario->GetInt( "descOneY", -1 ); if ( nDescOneYpos > 0 ) { int x, y; pScenarioInfo->m_pDescOne->GetPos( x, y ); pScenarioInfo->m_pDescOne->SetPos( x, nDescOneYpos ); } int nDescTwoYpos = pScenario->GetInt( "descTwoY", -1 ); if ( nDescTwoYpos > 0 ) { int x, y; pScenarioInfo->m_pDescTwo->GetPos( x, y ); pScenarioInfo->m_pDescTwo->SetPos( x, nDescTwoYpos ); } m_pScenarioInfos.AddToTail( pScenarioInfo ); } } } //--------------------------------------------------------------------- // Purpose: Set up colors and other such stuff //--------------------------------------------------------------------- void CSessionBrowserDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) { BaseClass::ApplySchemeSettings( pScheme ); for ( int i = 0; i < m_pScenarioInfos.Count(); ++i ) { m_pScenarioInfos[i]->SetBgColor( pScheme->GetColor( "TanDark", Color( 0, 0, 0, 255 ) ) ); } } //--------------------------------------------------------------------- // Purpose: Info about a session, sent from matchmaking //--------------------------------------------------------------------- void CSessionBrowserDialog::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping ) { char *pPing; switch ( ping ) { case 0: pPing = "#TF_Icon_Ping_Green"; break; case 1: pPing = "#TF_Icon_Ping_Yellow"; break; case 2: default: pPing = "#TF_Icon_Ping_Red"; break; } int nScenarioId = 0; uint nContextId = m_pDialogKeys->GetInt( "scenario", -1 ); for ( uint i = 0; i < pResult->cContexts; ++i ) { if ( pResult->pContexts[i].dwContextId == nContextId ) { nScenarioId = pResult->pContexts[i].dwValue; break; } } hostData_s *pData = (hostData_s*)pHostData; int filledSlots = pResult->dwFilledPublicSlots + pResult->dwFilledPrivateSlots; int totalSlots = filledSlots + pResult->dwOpenPublicSlots + pResult->dwOpenPrivateSlots; m_GameStates.AddToTail( pData->gameState ); m_GameTimes.AddToTail( pData->gameTime ); m_XUIDs.AddToTail( pData->xuid ); char szSlots[16] = {0}; Q_snprintf( szSlots, sizeof( szSlots ), "%d/%d", filledSlots, totalSlots ); int ct = 0; const char *ppStrings[4]; ppStrings[ct++] = pData->hostName; ppStrings[ct++] = szSlots; ppStrings[ct++] = pData->scenario; if ( ping != -1 ) { ppStrings[ct++] = pPing; } m_Menu.AddSectionedItem( ppStrings, ct ); m_ScenarioIndices.AddToTail( nScenarioId ); m_SearchIndices.AddToTail( searchIdx ); if ( m_Menu.GetItemCount() == 1 ) { m_Menu.SetFocus( 0 ); } UpdateScenarioDisplay(); } //----------------------------------------------------------------- // Purpose: Show the correct scenario image and text //----------------------------------------------------------------- void CSessionBrowserDialog::UpdateScenarioDisplay( void ) { if ( !m_ScenarioIndices.Count() ) return; // Check if the selected map has changed (first menu item) int idx = m_Menu.GetActiveItemIndex(); for ( int i = 0; i < m_pScenarioInfos.Count(); ++i ) { m_pScenarioInfos[i]->SetVisible( i == m_ScenarioIndices[idx] ); } // Get the screen size int wide, tall; vgui::surface()->GetScreenSize(wide, tall); bool bLodef = ( tall <= 480 ); const char *pState = ""; switch( m_GameStates[idx] ) { case 0: if ( bLodef ) { pState = "#TF_GameState_InLobby_lodef"; } else { pState = "#TF_GameState_InLobby"; } break; case 1: if ( bLodef ) { pState = "#TF_GameState_GameInProgress_lodef"; } else { pState = "#TF_GameState_GameInProgress"; } break; } char szTime[32] = {0}; if ( m_GameTimes[idx] >= NO_TIME_LIMIT ) { Q_strncpy( szTime, "#TF_NoTimeLimit", sizeof( szTime) ); } else { Q_snprintf( szTime, sizeof( szTime), "%d:00", m_GameTimes[idx] ); } if ( !m_pScenarioInfos.IsValidIndex( m_ScenarioIndices[idx] ) ) return; CScenarioInfoPanel *pPanel = m_pScenarioInfos[ m_ScenarioIndices[idx] ]; pPanel->m_pDescOne->SetText( pState ); pPanel->m_pDescTwo->SetText( szTime ); } //----------------------------------------------------------------- // helper to swap two ints in a utlvector //----------------------------------------------------------------- static void Swap( CUtlVector< int > &vec, int iOne, int iTwo ) { int temp = vec[iOne]; vec[iOne] = vec[iTwo]; vec[iTwo] = temp; } //----------------------------------------------------------------- // Purpose: Swap the order of two menu items //----------------------------------------------------------------- void CSessionBrowserDialog::SwapMenuItems( int iOne, int iTwo ) { Swap( m_ScenarioIndices, iOne, iTwo ); Swap( m_SearchIndices, iOne, iTwo ); Swap( m_GameStates, iOne, iTwo ); Swap( m_GameTimes, iOne, iTwo ); // swap the XUIDs, too XUID temp = m_XUIDs[iOne]; m_XUIDs[iOne] = m_XUIDs[iTwo]; m_XUIDs[iTwo] = temp; } //----------------------------------------------------------------- // Purpose: Handle commands from the dialog menu //----------------------------------------------------------------- void CSessionBrowserDialog::OnCommand( const char *pCommand ) { if ( !Q_stricmp( pCommand, "SelectSession" ) ) { int idx = m_SearchIndices[ m_Menu.GetActiveItemIndex() ]; matchmaking->SelectSession( idx ); } m_pParent->OnCommand( pCommand ); } //----------------------------------------------------------------- // Purpose: Send key presses to the dialog's menu //----------------------------------------------------------------- void CSessionBrowserDialog::OnKeyCodePressed( vgui::KeyCode code ) { switch( code ) { case KEY_XBUTTON_B: matchmaking->KickPlayerFromSession( 0 ); break; case KEY_XBUTTON_X: #ifdef _X360 int idx = m_Menu.GetActiveItemIndex(); if ( m_XUIDs.IsValidIndex( idx ) ) { XShowGamerCardUI( XBX_GetPrimaryUserId(), m_XUIDs[idx] ); } #endif break; } BaseClass::OnKeyCodePressed( code ); // Selected session may have been updated UpdateScenarioDisplay(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CSessionBrowserDialog::OnThink() { vgui::KeyCode code = m_KeyRepeat.KeyRepeated(); if ( code ) { m_Menu.HandleKeyCode( code ); UpdateScenarioDisplay(); } BaseClass::OnThink(); }