summaryrefslogtreecommitdiff
path: root/game/client/tf/vgui/tf_mapinfomenu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/vgui/tf_mapinfomenu.cpp')
-rw-r--r--game/client/tf/vgui/tf_mapinfomenu.cpp648
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();
+}
+