diff options
Diffstat (limited to 'game/client/tf/vgui/tf_mapinfomenu.cpp')
| -rw-r--r-- | game/client/tf/vgui/tf_mapinfomenu.cpp | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/game/client/tf/vgui/tf_mapinfomenu.cpp b/game/client/tf/vgui/tf_mapinfomenu.cpp new file mode 100644 index 0000000..5c5956d --- /dev/null +++ b/game/client/tf/vgui/tf_mapinfomenu.cpp @@ -0,0 +1,648 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + +#include "cbase.h" + +#include <vgui_controls/ImagePanel.h> +#include <vgui_controls/RichText.h> +#include <game/client/iviewport.h> +#include <vgui/ILocalize.h> +#include <KeyValues.h> +#include <filesystem.h> +#include "IGameUIFuncs.h" // for key bindings +#include "inputsystem/iinputsystem.h" + +#include "ixboxsystem.h" +#include "tf_gamerules.h" +#include "tf_controls.h" +#include "tf_shareddefs.h" +#include "tf_mapinfomenu.h" + +#include "video/ivideoservices.h" + +using namespace vgui; + +const char *GetMapDisplayName( const char *mapName ); + +//----------------------------------------------------------------------------- +// Purpose: Constructor +//----------------------------------------------------------------------------- +CTFMapInfoMenu::CTFMapInfoMenu( IViewPort *pViewPort ) : Frame( NULL, PANEL_MAPINFO ) +{ + m_pViewPort = pViewPort; + + // load the new scheme early!! + SetScheme( "ClientScheme" ); + + SetTitleBarVisible( false ); + SetMinimizeButtonVisible( false ); + SetMaximizeButtonVisible( false ); + SetCloseButtonVisible( false ); + SetSizeable( false ); + SetMoveable( false ); + SetProportional( true ); + SetVisible( false ); + SetKeyBoardInputEnabled( true ); + + m_pTitle = new CExLabel( this, "MapInfoTitle", " " ); + +#ifdef _X360 + m_pFooter = new CTFFooter( this, "Footer" ); +#else + m_pContinue = new CExButton( this, "MapInfoContinue", "#TF_Continue" ); + m_pBack = new CExButton( this, "MapInfoBack", "#TF_Back" ); + m_pIntro = new CExButton( this, "MapInfoWatchIntro", "#TF_WatchIntro" ); +#endif + + // info window about this map + m_pMapInfo = new CExRichText( this, "MapInfoText" ); + m_pMapImage = new ImagePanel( this, "MapImage" ); + + m_szMapName[0] = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Destructor +//----------------------------------------------------------------------------- +CTFMapInfoMenu::~CTFMapInfoMenu() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + if ( ::input->IsSteamControllerActive() ) + { + LoadControlSettings( "Resource/UI/MapInfoMenu_SC.res" ); + m_pContinueHintIcon = dynamic_cast< CSCHintIcon* >( FindChildByName( "MapInfoContinueHintIcon" ) ); + m_pBackHintIcon = dynamic_cast< CSCHintIcon* >( FindChildByName( "MapInfoBackHintIcon" ) ); + m_pIntroHintIcon = dynamic_cast< CSCHintIcon* >( FindChildByName( "MapInfoIntroHintIcon" ) ); + + SetMouseInputEnabled( false ); + } + else + { + LoadControlSettings( "Resource/UI/MapInfoMenu.res" ); + m_pContinueHintIcon = m_pBackHintIcon = m_pIntroHintIcon = nullptr; + SetMouseInputEnabled( true ); + } + + CheckIntroState(); + CheckBackContinueButtons(); + + char mapname[MAX_MAP_NAME]; + + Q_FileBase( engine->GetLevelName(), mapname, sizeof(mapname) ); + + // Save off the map name so we can re-load the page in ApplySchemeSettings(). + Q_strncpy( m_szMapName, mapname, sizeof( m_szMapName ) ); + Q_strupr( m_szMapName ); + +#ifdef _X360 + char *pExt = Q_stristr( m_szMapName, ".360" ); + if ( pExt ) + { + *pExt = '\0'; + } +#endif + + LoadMapPage(); + SetMapTitle(); + +#ifndef _X360 + if ( m_pContinue ) + { + m_pContinue->RequestFocus(); + } +#endif + + SetDialogVariable( "gamemode", g_pVGuiLocalize->Find( GetMapType( m_szMapName ) ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::ShowPanel( bool bShow ) +{ + if ( IsVisible() == bShow ) + return; + + m_KeyRepeat.Reset(); + + if ( bShow ) + { + InvalidateLayout( true, true ); // Force scheme reload since the steam controller state may have changed. + Activate(); + CheckIntroState(); + } + else + { + SetVisible( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFMapInfoMenu::CheckForIntroMovie() +{ + const char *pVideoFileName = TFGameRules()->GetVideoFileForMap(); + if ( pVideoFileName == NULL ) + { + return false; + } + + VideoSystem_t playbackSystem = VideoSystem::NONE; + char resolvedFile[MAX_PATH]; + if ( g_pVideo && g_pVideo->LocatePlayableVideoFile( pVideoFileName, "GAME", &playbackSystem, resolvedFile, sizeof(resolvedFile) ) == VideoResult::SUCCESS ) + { + return true; + } + + return false; +} + +const char *COM_GetModDirectory(); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFMapInfoMenu::HasViewedMovieForMap() +{ + return ( UTIL_GetMapKeyCount( "viewed" ) > 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::CheckIntroState() +{ + if ( CheckForIntroMovie() && HasViewedMovieForMap() ) + { +#ifdef _X360 + if ( m_pFooter ) + { + m_pFooter->ShowButtonLabel( "intro", true ); + } +#else + if ( m_pIntro && !m_pIntro->IsVisible() ) + { + m_pIntro->SetVisible( true ); + if ( m_pIntroHintIcon ) + { + m_pIntroHintIcon->SetVisible( true ); + } + } +#endif + } + else + { +#ifdef _X360 + if ( m_pFooter ) + { + m_pFooter->ShowButtonLabel( "intro", false ); + } +#else + if ( m_pIntro && m_pIntro->IsVisible() ) + { + m_pIntro->SetVisible( false ); + if ( m_pIntroHintIcon ) + { + m_pIntroHintIcon->SetVisible( false ); + } + } +#endif + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::CheckBackContinueButtons() +{ +#ifndef _X360 + if ( m_pBack && m_pContinue ) + { + if ( GetLocalPlayerTeam() == TEAM_UNASSIGNED ) + { + m_pBack->SetVisible( true ); + if ( m_pBackHintIcon ) + { + m_pBackHintIcon->SetVisible( true ); + } + m_pContinue->SetText( "#TF_Continue" ); + } + else + { + m_pBack->SetVisible( false ); + if ( m_pBackHintIcon ) + { + m_pBackHintIcon->SetVisible( false ); + } + m_pContinue->SetText( "#TF_Close" ); + } + } +#endif +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::OnCommand( const char *command ) +{ + m_KeyRepeat.Reset(); + + if ( !Q_strcmp( command, "back" ) ) + { + // only want to go back to the Welcome menu if we're not already on a team + if ( !IsX360() && ( GetLocalPlayerTeam() == TEAM_UNASSIGNED ) ) + { + m_pViewPort->ShowPanel( this, false ); + m_pViewPort->ShowPanel( PANEL_INFO, true ); + } + } + else if ( !Q_strcmp( command, "continue" ) ) + { + m_pViewPort->ShowPanel( this, false ); + + if ( CheckForIntroMovie() && !HasViewedMovieForMap() ) + { + m_pViewPort->ShowPanel( PANEL_INTRO, true ); + + UTIL_IncrementMapKey( "viewed" ); + } + else + { + // On console, we may already have a team due to the lobby assigning us one. + // We tell the server we're done with the map info menu, and it decides what to do with us. + if ( IsX360() ) + { + engine->ClientCmd( "closedwelcomemenu" ); + } + else if ( GetLocalPlayerTeam() == TEAM_UNASSIGNED ) + { + if ( TFGameRules()->IsInArenaMode() == true && tf_arena_use_queue.GetBool() == true ) + { + m_pViewPort->ShowPanel( PANEL_ARENA_TEAM, true ); + } + else + { + engine->ClientCmd( "team_ui_setup" ); + } + } + + UTIL_IncrementMapKey( "viewed" ); + } + } + else if ( !Q_strcmp( command, "intro" ) ) + { + m_pViewPort->ShowPanel( this, false ); + + if ( CheckForIntroMovie() ) + { + m_pViewPort->ShowPanel( PANEL_INTRO, true ); + } + else + { + if ( TFGameRules()->IsInArenaMode() == true && tf_arena_use_queue.GetBool() == true ) + { + m_pViewPort->ShowPanel( PANEL_ARENA_TEAM, true ); + } + else + { + engine->ClientCmd( "team_ui_setup" ); + } + } + } + else + { + BaseClass::OnCommand( command ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::Update() +{ + InvalidateLayout( false, true ); +} + +//----------------------------------------------------------------------------- +// Purpose: chooses and loads the text page to display that describes mapName map +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::LoadMapPage() +{ + if ( !m_szMapName[0] ) + { + m_pMapInfo->SetText( "" ); + m_pMapImage->SetVisible( false ); + return; + } + + // load the map image (if it exists for the current map) + char szMapImage[ MAX_PATH ]; + Q_snprintf( szMapImage, sizeof( szMapImage ), "VGUI/maps/menu_photos_%s", m_szMapName ); + Q_strlower( szMapImage ); + + IMaterial *pMapMaterial = materials->FindMaterial( szMapImage, TEXTURE_GROUP_VGUI, false ); + if ( pMapMaterial && !IsErrorMaterial( pMapMaterial ) ) + { + if ( m_pMapImage ) + { + if ( !m_pMapImage->IsVisible() ) + { + m_pMapImage->SetVisible( true ); + } + + // take off the vgui/ at the beginning when we set the image + Q_snprintf( szMapImage, sizeof( szMapImage ), "maps/menu_photos_%s", m_szMapName ); + Q_strlower( szMapImage ); + + m_pMapImage->SetImage( szMapImage ); + } + } + else + { + if ( m_pMapImage && m_pMapImage->IsVisible() ) + { + m_pMapImage->SetVisible( false ); + } + } + + // try loading map descriptions from the localization files first + char mapDescriptionKey[ 64 ]; + Q_snprintf( mapDescriptionKey, sizeof( mapDescriptionKey ), "#%s_description", m_szMapName ); + Q_strlower( mapDescriptionKey ); + wchar_t* wszMapDescription = g_pVGuiLocalize->Find( mapDescriptionKey ); + if( wszMapDescription ) + { + m_pMapInfo->SetText( wszMapDescription ); + } + else + { + // try loading map descriptions from .txt files first + char mapRES[ MAX_PATH ]; + + char uilanguage[ 64 ]; + uilanguage[0] = 0; + engine->GetUILanguage( uilanguage, sizeof( uilanguage ) ); + + Q_snprintf( mapRES, sizeof( mapRES ), "maps/%s_%s.txt", m_szMapName, uilanguage ); + + // try English if the file doesn't exist for our language + if( !g_pFullFileSystem->FileExists( mapRES, "GAME" ) ) + { + Q_snprintf( mapRES, sizeof( mapRES ), "maps/%s_english.txt", m_szMapName ); + + // if the file doesn't exist for English either, try the filename without any language extension + if( !g_pFullFileSystem->FileExists( mapRES, "GAME" ) ) + { + Q_snprintf( mapRES, sizeof( mapRES ), "maps/%s.txt", m_szMapName ); + } + } + + // if no map specific description exists, load default text + if( g_pFullFileSystem->FileExists( mapRES, "GAME" ) ) + { + FileHandle_t f = g_pFullFileSystem->Open( mapRES, "rb" ); + + // read into a memory block + int fileSize = g_pFullFileSystem->Size(f); + int dataSize = fileSize + sizeof( wchar_t ); + if ( dataSize % 2 ) + ++dataSize; + wchar_t *memBlock = (wchar_t *)malloc(dataSize); + memset( memBlock, 0x0, dataSize); + int bytesRead = g_pFullFileSystem->Read(memBlock, fileSize, f); + if ( bytesRead < fileSize ) + { + // NULL-terminate based on the length read in, since Read() can transform \r\n to \n and + // return fewer bytes than we were expecting. + char *data = reinterpret_cast<char *>( memBlock ); + data[ bytesRead ] = 0; + data[ bytesRead+1 ] = 0; + } + + #ifndef WIN32 + if ( ((ucs2 *)memBlock)[0] == 0xFEFF ) + { + // convert the win32 ucs2 data to wchar_t + dataSize*=2;// need to *2 to account for ucs2 to wchar_t (4byte) growth + wchar_t *memBlockConverted = (wchar_t *)malloc(dataSize); + V_UCS2ToUnicode( (ucs2 *)memBlock, memBlockConverted, dataSize ); + free(memBlock); + memBlock = memBlockConverted; + } + #else + // null-terminate the stream (redundant, since we memset & then trimmed the transformed buffer already) + memBlock[dataSize / sizeof(wchar_t) - 1] = 0x0000; + #endif + // check the first character, make sure this a little-endian unicode file + + #if defined( _X360 ) + if ( memBlock[0] != 0xFFFE ) + #else + if ( memBlock[0] != 0xFEFF ) + #endif + { + // its a ascii char file + m_pMapInfo->SetText( reinterpret_cast<char *>( memBlock ) ); + } + else + { + // ensure little-endian unicode reads correctly on all platforms + CByteswap byteSwap; + byteSwap.SetTargetBigEndian( false ); + byteSwap.SwapBufferToTargetEndian( memBlock, memBlock, dataSize/sizeof(wchar_t) ); + + m_pMapInfo->SetText( memBlock+1 ); + } + // go back to the top of the text buffer + m_pMapInfo->GotoTextStart(); + + g_pFullFileSystem->Close( f ); + free(memBlock); + } + else + { + // try loading map descriptions from localization files next + const char *pszDescription = NULL; + char mapInfoKey[ 64 ]; + + if ( TFGameRules() && TFGameRules()->IsPowerupMode() && ( FStrEq( m_szMapName, "ctf_foundry" ) || FStrEq( m_szMapName, "ctf_gorge" ) ) ) + { + Q_snprintf( mapInfoKey, sizeof( mapInfoKey ), "#%s_beta", m_szMapName ); + } + else + { + Q_snprintf( mapInfoKey, sizeof( mapInfoKey ), "#%s", m_szMapName ); + } + + Q_strlower( mapInfoKey ); + + if( !g_pVGuiLocalize->Find( mapInfoKey ) ) + { + if ( TFGameRules() ) + { + if ( TFGameRules()->IsMannVsMachineMode() ) + { + pszDescription = "#default_mvm_description"; + } + else + { + switch ( TFGameRules()->GetGameType() ) + { + case TF_GAMETYPE_CTF: + pszDescription = "#default_ctf_description"; + break; + case TF_GAMETYPE_CP: + if ( TFGameRules()->IsInKothMode() ) + { + pszDescription = "#default_koth_description"; + } + else + { + pszDescription = "#default_cp_description"; + } + break; + case TF_GAMETYPE_ESCORT: + if ( TFGameRules()->HasMultipleTrains() ) + { + pszDescription = "#default_payload_race_description"; + } + else + { + pszDescription = "#default_payload_description"; + } + break; + case TF_GAMETYPE_ARENA: + pszDescription = "#default_arena_description"; + break; + case TF_GAMETYPE_RD: + pszDescription = "#default_rd_description"; + break; + case TF_GAMETYPE_PASSTIME: + pszDescription = "#default_passtime_description"; + break; + case TF_GAMETYPE_PD: + pszDescription = "#default_pd_description"; + break; + } + } + } + } + else + { + pszDescription = mapInfoKey; + } + + if ( pszDescription && pszDescription[0] ) + { + m_pMapInfo->SetText( pszDescription ); + } + else + { + m_pMapInfo->SetText( "" ); + } + } + } + + // we haven't loaded a valid map image for the current map + if ( m_pMapImage && !m_pMapImage->IsVisible() ) + { + if ( m_pMapInfo ) + { + m_pMapInfo->SetWide( m_pMapInfo->GetWide() + ( m_pMapImage->GetWide() * 0.75 ) ); // add in the extra space the images would have taken + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::SetMapTitle() +{ + SetDialogVariable( "mapname", GetMapDisplayName( m_szMapName ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::OnKeyCodePressed( KeyCode code ) +{ + m_KeyRepeat.KeyDown( code ); + + if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A ) + { + OnCommand( "continue" ); + } + else if ( code == STEAMCONTROLLER_B ) + { + OnCommand( "back" ); + } + else if ( code == KEY_XBUTTON_Y || code == STEAMCONTROLLER_Y ) + { + OnCommand( "intro" ); + } + else if( code == KEY_XBUTTON_UP || code == KEY_XSTICK1_UP || code == STEAMCONTROLLER_DPAD_UP ) + { + // Scroll class info text up + if ( m_pMapInfo ) + { + PostMessage( m_pMapInfo, new KeyValues("MoveScrollBarDirect", "delta", 1) ); + } + } + else if( code == KEY_XBUTTON_DOWN || code == KEY_XSTICK1_DOWN || code == STEAMCONTROLLER_DPAD_DOWN ) + { + // Scroll class info text up + if ( m_pMapInfo ) + { + PostMessage( m_pMapInfo, new KeyValues("MoveScrollBarDirect", "delta", -1) ); + } + } + else + { + BaseClass::OnKeyCodePressed( code ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::OnKeyCodeReleased( vgui::KeyCode code ) +{ + m_KeyRepeat.KeyUp( code ); + + BaseClass::OnKeyCodeReleased( code ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFMapInfoMenu::OnThink() +{ + vgui::KeyCode code = m_KeyRepeat.KeyRepeated(); + if ( code ) + { + OnKeyCodePressed( code ); + } + + //Always hide the health... this needs to be done every frame because a message from the server keeps resetting this. + C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pLocalPlayer ) + { + pLocalPlayer->m_Local.m_iHideHUD |= HIDEHUD_HEALTH; + } + + BaseClass::OnThink(); +} + |