summaryrefslogtreecommitdiff
path: root/gameui
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /gameui
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'gameui')
-rw-r--r--gameui/BackgroundMenuButton.cpp72
-rw-r--r--gameui/BackgroundMenuButton.h39
-rw-r--r--gameui/BasePanel.cpp4832
-rw-r--r--gameui/BasePanel.h462
-rw-r--r--gameui/BaseSaveGameDialog.cpp668
-rw-r--r--gameui/BaseSaveGameDialog.h81
-rw-r--r--gameui/BenchmarkDialog.cpp130
-rw-r--r--gameui/BenchmarkDialog.h45
-rw-r--r--gameui/BitmapImagePanel.cpp78
-rw-r--r--gameui/BitmapImagePanel.h37
-rw-r--r--gameui/BonusMapsDatabase.cpp916
-rw-r--r--gameui/BonusMapsDatabase.h167
-rw-r--r--gameui/BonusMapsDialog.cpp1006
-rw-r--r--gameui/BonusMapsDialog.h75
-rw-r--r--gameui/CDKeyEntryDialog.cpp323
-rw-r--r--gameui/CDKeyEntryDialog.h58
-rw-r--r--gameui/ChangeGameDialog.cpp161
-rw-r--r--gameui/ChangeGameDialog.h36
-rw-r--r--gameui/CommandCheckButton.cpp47
-rw-r--r--gameui/CommandCheckButton.h30
-rw-r--r--gameui/CommentaryDialog.cpp255
-rw-r--r--gameui/CommentaryDialog.h55
-rw-r--r--gameui/CommentaryExplanationDialog.cpp107
-rw-r--r--gameui/CommentaryExplanationDialog.h37
-rw-r--r--gameui/ContentControlDialog.cpp406
-rw-r--r--gameui/ContentControlDialog.h66
-rw-r--r--gameui/ControllerDialog.cpp25
-rw-r--r--gameui/ControllerDialog.h27
-rw-r--r--gameui/CreateMultiplayerGameBotPage.cpp228
-rw-r--r--gameui/CreateMultiplayerGameBotPage.h66
-rw-r--r--gameui/CreateMultiplayerGameDialog.cpp190
-rw-r--r--gameui/CreateMultiplayerGameDialog.h47
-rw-r--r--gameui/CreateMultiplayerGameGameplayPage.cpp475
-rw-r--r--gameui/CreateMultiplayerGameGameplayPage.h48
-rw-r--r--gameui/CreateMultiplayerGameServerPage.cpp313
-rw-r--r--gameui/CreateMultiplayerGameServerPage.h60
-rw-r--r--gameui/CustomTabExplanationDialog.cpp93
-rw-r--r--gameui/CustomTabExplanationDialog.h35
-rw-r--r--gameui/CvarNegateCheckButton.cpp136
-rw-r--r--gameui/CvarNegateCheckButton.h39
-rw-r--r--gameui/CvarTextEntry.cpp112
-rw-r--r--gameui/CvarTextEntry.h35
-rw-r--r--gameui/CvarToggleCheckButton.cpp159
-rw-r--r--gameui/CvarToggleCheckButton.h41
-rw-r--r--gameui/EngineInterface.h34
-rw-r--r--gameui/GameApp.cpp1
-rw-r--r--gameui/GameApp.h1
-rw-r--r--gameui/GameConsole.cpp169
-rw-r--r--gameui/GameConsole.h54
-rw-r--r--gameui/GameConsoleDialog.cpp99
-rw-r--r--gameui/GameConsoleDialog.h40
-rw-r--r--gameui/GameUI.h25
-rw-r--r--gameui/GameUI.vpc258
-rw-r--r--gameui/GameUIPanel.h22
-rw-r--r--gameui/GameUI_Interface.cpp1285
-rw-r--r--gameui/GameUI_Interface.h159
-rw-r--r--gameui/HapticControlBox.cpp191
-rw-r--r--gameui/HapticControlBox.h53
-rw-r--r--gameui/KeyToggleCheckButton.cpp118
-rw-r--r--gameui/KeyToggleCheckButton.h38
-rw-r--r--gameui/LabeledCommandComboBox.cpp131
-rw-r--r--gameui/LabeledCommandComboBox.h59
-rw-r--r--gameui/LoadCommentaryDialog.cpp411
-rw-r--r--gameui/LoadCommentaryDialog.h63
-rw-r--r--gameui/LoadGameDialog.cpp107
-rw-r--r--gameui/LoadGameDialog.h54
-rw-r--r--gameui/LoadGameDialog_Xbox.cpp219
-rw-r--r--gameui/LoadingDialog.cpp669
-rw-r--r--gameui/LoadingDialog.h77
-rw-r--r--gameui/LogoFile.cpp287
-rw-r--r--gameui/ModInfo.cpp251
-rw-r--r--gameui/ModInfo.h68
-rw-r--r--gameui/MouseMessageForwardingPanel.cpp39
-rw-r--r--gameui/MouseMessageForwardingPanel.h29
-rw-r--r--gameui/MultiplayerAdvancedDialog.cpp431
-rw-r--r--gameui/MultiplayerAdvancedDialog.h52
-rw-r--r--gameui/NewGameDialog.cpp1724
-rw-r--r--gameui/NewGameDialog.h155
-rw-r--r--gameui/OptionsDialog.cpp155
-rw-r--r--gameui/OptionsDialog.h141
-rw-r--r--gameui/OptionsDialog_Xbox.cpp1683
-rw-r--r--gameui/OptionsSubAudio.cpp432
-rw-r--r--gameui/OptionsSubAudio.h65
-rw-r--r--gameui/OptionsSubDifficulty.cpp79
-rw-r--r--gameui/OptionsSubDifficulty.h38
-rw-r--r--gameui/OptionsSubGame.cpp41
-rw-r--r--gameui/OptionsSubGame.h35
-rw-r--r--gameui/OptionsSubHaptics.cpp196
-rw-r--r--gameui/OptionsSubHaptics.h100
-rw-r--r--gameui/OptionsSubKeyboard.cpp839
-rw-r--r--gameui/OptionsSubKeyboard.h101
-rw-r--r--gameui/OptionsSubMouse.cpp261
-rw-r--r--gameui/OptionsSubMouse.h80
-rw-r--r--gameui/OptionsSubMultiplayer.cpp1890
-rw-r--r--gameui/OptionsSubMultiplayer.h113
-rw-r--r--gameui/OptionsSubPortal.cpp98
-rw-r--r--gameui/OptionsSubPortal.h59
-rw-r--r--gameui/OptionsSubVideo.cpp1763
-rw-r--r--gameui/OptionsSubVideo.h80
-rw-r--r--gameui/OptionsSubVoice.cpp334
-rw-r--r--gameui/OptionsSubVoice.h73
-rw-r--r--gameui/PanelListPanel.cpp306
-rw-r--r--gameui/PanelListPanel.h79
-rw-r--r--gameui/PlayerListDialog.cpp250
-rw-r--r--gameui/PlayerListDialog.h53
-rw-r--r--gameui/RunGameEngine.cpp205
-rw-r--r--gameui/RunGameEngine.h1
-rw-r--r--gameui/SaveGameBrowserDialog.cpp1423
-rw-r--r--gameui/SaveGameBrowserDialog.h193
-rw-r--r--gameui/SaveGameDialog.cpp163
-rw-r--r--gameui/SaveGameDialog.h66
-rw-r--r--gameui/SaveGameDialog_Xbox.cpp295
-rw-r--r--gameui/Sys_Utils.cpp180
-rw-r--r--gameui/Sys_Utils.h49
-rw-r--r--gameui/TGAImagePanel.cpp92
-rw-r--r--gameui/TGAImagePanel.h41
-rw-r--r--gameui/TextEntryBox.cpp120
-rw-r--r--gameui/TextEntryBox.h46
-rw-r--r--gameui/URLButton.cpp622
-rw-r--r--gameui/URLButton.h171
-rw-r--r--gameui/VGuiSystemModuleLoader.cpp384
-rw-r--r--gameui/VGuiSystemModuleLoader.h97
-rw-r--r--gameui/gameui_util.cpp32
-rw-r--r--gameui/gameui_util.h15
-rw-r--r--gameui/matchmaking/achievementsdialog.cpp1075
-rw-r--r--gameui/matchmaking/achievementsdialog.h182
-rw-r--r--gameui/matchmaking/basedialog.cpp295
-rw-r--r--gameui/matchmaking/basedialog.h120
-rw-r--r--gameui/matchmaking/dialogmenu.cpp1524
-rw-r--r--gameui/matchmaking/dialogmenu.h367
-rw-r--r--gameui/matchmaking/leaderboarddialog.cpp563
-rw-r--r--gameui/matchmaking/leaderboarddialog.h59
-rw-r--r--gameui/matchmaking/matchmakingbasepanel.cpp999
-rw-r--r--gameui/matchmaking/matchmakingbasepanel.h114
-rw-r--r--gameui/matchmaking/pausedialog.cpp47
-rw-r--r--gameui/matchmaking/pausedialog.h30
-rw-r--r--gameui/matchmaking/sessionbrowserdialog.cpp323
-rw-r--r--gameui/matchmaking/sessionbrowserdialog.h46
-rw-r--r--gameui/matchmaking/sessionlobbydialog.cpp739
-rw-r--r--gameui/matchmaking/sessionlobbydialog.h85
-rw-r--r--gameui/matchmaking/sessionoptionsdialog.cpp420
-rw-r--r--gameui/matchmaking/sessionoptionsdialog.h61
-rw-r--r--gameui/matchmaking/welcomedialog.cpp58
-rw-r--r--gameui/matchmaking/welcomedialog.h34
-rw-r--r--gameui/vcontrolslistpanel.cpp207
-rw-r--r--gameui/vcontrolslistpanel.h54
-rw-r--r--gameui/xbox/xbox.def3
147 files changed, 40635 insertions, 0 deletions
diff --git a/gameui/BackgroundMenuButton.cpp b/gameui/BackgroundMenuButton.cpp
new file mode 100644
index 0000000..f67f487
--- /dev/null
+++ b/gameui/BackgroundMenuButton.cpp
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BackgroundMenuButton.h"
+
+#include <KeyValues.h>
+#include <vgui/IImage.h>
+#include <vgui/IScheme.h>
+#include <vgui_controls/Menu.h>
+#include <vgui_controls/MenuItem.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBackgroundMenuButton::CBackgroundMenuButton(vgui::Panel *parent, const char *name) : BaseClass(parent, name, "")
+{
+ m_pImage = NULL;
+ m_pMouseOverImage = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBackgroundMenuButton::~CBackgroundMenuButton()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBackgroundMenuButton::OnCommand(const char *command)
+{
+ BaseClass::OnCommand(command);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes the button transparent
+//-----------------------------------------------------------------------------
+void CBackgroundMenuButton::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // hack some colors in
+ SetFgColor(Color(255, 255, 255, 255));
+ SetBgColor(Color(0, 0, 0, 0));
+ SetDefaultColor(Color(255, 255, 255, 255), Color(0, 0, 0, 0));
+ SetArmedColor(Color(255, 255, 0, 255), Color(0, 0, 0, 0));
+ SetDepressedColor(Color(255, 255, 0, 255), Color(0, 0, 0, 0));
+ SetContentAlignment(Label::a_west);
+ SetBorder(NULL);
+ SetDefaultBorder(NULL);
+ SetDepressedBorder(NULL);
+ SetKeyFocusBorder(NULL);
+ SetTextInset(0, 0);
+ SetAlpha(0);
+
+ /*
+ // sounds disabled for this button (since it's so big now)
+ SetArmedSound("UI/buttonrollover.wav");
+ SetDepressedSound("UI/buttonclick.wav");
+ SetReleasedSound("UI/buttonclickrelease.wav");
+ */
+}
diff --git a/gameui/BackgroundMenuButton.h b/gameui/BackgroundMenuButton.h
new file mode 100644
index 0000000..c4886a2
--- /dev/null
+++ b/gameui/BackgroundMenuButton.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BACKGROUNDMENUBUTTON_H
+#define BACKGROUNDMENUBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Button.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Baseclass for the left and right ingame menus that lay on the background
+//-----------------------------------------------------------------------------
+class CBackgroundMenuButton : public vgui::Button
+{
+public:
+ CBackgroundMenuButton(vgui::Panel *parent, const char *name);
+ ~CBackgroundMenuButton();
+
+ virtual void OnCommand(const char *command);
+
+protected:
+ vgui::Menu *RecursiveLoadGameMenu(KeyValues *datafile);
+ vgui::Menu *m_pMenu;
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+private:
+ vgui::IImage *m_pImage, *m_pMouseOverImage;
+ typedef vgui::Button BaseClass;
+};
+
+
+#endif // BACKGROUNDMENUBUTTON_H \ No newline at end of file
diff --git a/gameui/BasePanel.cpp b/gameui/BasePanel.cpp
new file mode 100644
index 0000000..eaabd91
--- /dev/null
+++ b/gameui/BasePanel.cpp
@@ -0,0 +1,4832 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include <stdio.h>
+
+#include "threadtools.h"
+
+#include "BasePanel.h"
+#include "EngineInterface.h"
+#include "VGuiSystemModuleLoader.h"
+
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include "vgui/IPanel.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+#include "filesystem.h"
+#include "GameConsole.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/PropertyDialog.h"
+#include "vgui_controls/PropertySheet.h"
+#include "materialsystem/materialsystem_config.h"
+#include "materialsystem/imaterialsystem.h"
+#include "sourcevr/isourcevirtualreality.h"
+
+using namespace vgui;
+
+#include "GameConsole.h"
+#include "ModInfo.h"
+
+#include "IGameUIFuncs.h"
+#include "LoadingDialog.h"
+#include "BackgroundMenuButton.h"
+#include "vgui_controls/AnimationController.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/Menu.h"
+#include "vgui_controls/MenuItem.h"
+#include "vgui_controls/PHandle.h"
+#include "vgui_controls/MessageBox.h"
+#include "vgui_controls/QueryBox.h"
+#include "vgui_controls/ControllerMap.h"
+#include "vgui_controls/KeyRepeat.h"
+#include "tier0/icommandline.h"
+#include "tier1/convar.h"
+#include "NewGameDialog.h"
+#include "BonusMapsDialog.h"
+#include "LoadGameDialog.h"
+#include "SaveGameDialog.h"
+#include "OptionsDialog.h"
+#include "CreateMultiplayerGameDialog.h"
+#include "ChangeGameDialog.h"
+#include "BackgroundMenuButton.h"
+#include "PlayerListDialog.h"
+#include "BenchmarkDialog.h"
+#include "LoadCommentaryDialog.h"
+#include "ControllerDialog.h"
+#include "BonusMapsDatabase.h"
+#include "engine/IEngineSound.h"
+#include "bitbuf.h"
+#include "tier1/fmtstr.h"
+#include "inputsystem/iinputsystem.h"
+#include "ixboxsystem.h"
+#include "matchmaking/matchmakingbasepanel.h"
+#include "matchmaking/achievementsdialog.h"
+#include "iachievementmgr.h"
+#include "UtlSortVector.h"
+
+#include "game/client/IGameClientExports.h"
+
+#include "OptionsSubAudio.h"
+#include "hl2orange.spa.h"
+#include "CustomTabExplanationDialog.h"
+#if defined( _X360 )
+#include "xbox/xbox_launch.h"
+#else
+#include "xbox/xboxstubs.h"
+#endif
+
+#include "../engine/imatchmaking.h"
+#include "tier1/utlstring.h"
+#include "steam/steam_api.h"
+
+#undef MessageBox // Windows helpfully #define's this to MessageBoxA, we're using vgui::MessageBox
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define MAIN_MENU_INDENT_X360 10
+
+ConVar vgui_message_dialog_modal( "vgui_message_dialog_modal", "1", FCVAR_ARCHIVE );
+
+extern vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
+static CBasePanel *g_pBasePanel = NULL;
+static float g_flAnimationPadding = 0.01f;
+
+extern const char *COM_GetModDirectory( void );
+
+extern ConVar x360_audio_english;
+extern bool bSteamCommunityFriendsVersion;
+
+static vgui::DHANDLE<vgui::PropertyDialog> g_hOptionsDialog;
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CBasePanel *BasePanel()
+{
+ return g_pBasePanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: hack function to give the module loader access to the main panel handle
+// only used in VguiSystemModuleLoader
+//-----------------------------------------------------------------------------
+VPANEL GetGameUIBasePanel()
+{
+ return BasePanel()->GetVPanel();
+}
+
+CGameMenuItem::CGameMenuItem(vgui::Menu *parent, const char *name) : BaseClass(parent, name, "GameMenuItem")
+{
+ m_bRightAligned = false;
+}
+
+void CGameMenuItem::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // make fully transparent
+ SetFgColor(GetSchemeColor("MainMenu.TextColor", pScheme));
+ SetBgColor(Color(0, 0, 0, 0));
+ SetDefaultColor(GetSchemeColor("MainMenu.TextColor", pScheme), Color(0, 0, 0, 0));
+ SetArmedColor(GetSchemeColor("MainMenu.ArmedTextColor", pScheme), Color(0, 0, 0, 0));
+ SetDepressedColor(GetSchemeColor("MainMenu.DepressedTextColor", pScheme), Color(0, 0, 0, 0));
+ SetContentAlignment(Label::a_west);
+ SetBorder(NULL);
+ SetDefaultBorder(NULL);
+ SetDepressedBorder(NULL);
+ SetKeyFocusBorder(NULL);
+
+ vgui::HFont hMainMenuFont = pScheme->GetFont( "MainMenuFont", IsProportional() );
+
+ if ( hMainMenuFont )
+ {
+ SetFont( hMainMenuFont );
+ }
+ else
+ {
+ SetFont( pScheme->GetFont( "MenuLarge", IsProportional() ) );
+ }
+ SetTextInset(0, 0);
+ SetArmedSound("UI/buttonrollover.wav");
+ SetDepressedSound("UI/buttonclick.wav");
+ SetReleasedSound("UI/buttonclickrelease.wav");
+ SetButtonActivationType(Button::ACTIVATE_ONPRESSED);
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ SetArmedColor(GetSchemeColor("MainMenu.ArmedTextColor", pScheme), GetSchemeColor("Button.ArmedBgColor", pScheme));
+ SetTextInset( MAIN_MENU_INDENT_X360, 0 );
+ }
+
+ if (m_bRightAligned)
+ {
+ SetContentAlignment(Label::a_east);
+ }
+}
+
+void CGameMenuItem::PaintBackground()
+{
+ if ( !GameUI().IsConsoleUI() )
+ {
+ BaseClass::PaintBackground();
+ }
+ else
+ {
+ if ( !IsArmed() || !IsVisible() || GetParent()->GetAlpha() < 32 )
+ return;
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ DrawBoxFade( 0, 0, wide, tall, GetButtonBgColor(), 1.0f, 255, 0, true );
+ DrawBoxFade( 2, 2, wide - 4, tall - 4, Color( 0, 0, 0, 96 ), 1.0f, 255, 0, true );
+ }
+}
+
+void CGameMenuItem::SetRightAlignedText(bool state)
+{
+ m_bRightAligned = state;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: General purpose 1 of N menu
+//-----------------------------------------------------------------------------
+class CGameMenu : public vgui::Menu
+{
+public:
+ DECLARE_CLASS_SIMPLE( CGameMenu, vgui::Menu );
+
+ CGameMenu(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ // shows graphic button hints
+ m_pConsoleFooter = new CFooterPanel( parent, "MainMenuFooter" );
+
+ int iFixedWidth = 245;
+
+#ifdef _X360
+ // In low def we need a smaller highlight
+ XVIDEO_MODE videoMode;
+ XGetVideoMode( &videoMode );
+ if ( !videoMode.fIsHiDef )
+ {
+ iFixedWidth = 240;
+ }
+ else
+ {
+ iFixedWidth = 350;
+ }
+#endif
+
+ SetFixedWidth( iFixedWidth );
+ }
+ else
+ {
+ m_pConsoleFooter = NULL;
+ }
+
+ m_hMainMenuOverridePanel = NULL;
+ }
+
+ virtual void ApplySchemeSettings(IScheme *pScheme)
+ {
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ // make fully transparent
+ SetMenuItemHeight(atoi(pScheme->GetResourceString("MainMenu.MenuItemHeight")));
+ SetBgColor(Color(0, 0, 0, 0));
+ SetBorder(NULL);
+ }
+
+ virtual void LayoutMenuBorder()
+ {
+ }
+
+ void SetMainMenuOverride( vgui::VPANEL panel )
+ {
+ m_hMainMenuOverridePanel = panel;
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // We've got an override panel. Nuke all our menu items.
+ DeleteAllItems();
+ }
+ }
+
+ virtual void SetVisible(bool state)
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force to be always visible
+ ipanel()->SetVisible( m_hMainMenuOverridePanel, true );
+
+ // move us to the back instead of going invisible
+ if ( !state )
+ {
+ ipanel()->MoveToBack(m_hMainMenuOverridePanel);
+ }
+ }
+
+ // force to be always visible
+ BaseClass::SetVisible(true);
+
+ // move us to the back instead of going invisible
+ if (!state)
+ {
+ ipanel()->MoveToBack(GetVPanel());
+ }
+ }
+
+ virtual int AddMenuItem(const char *itemName, const char *itemText, const char *command, Panel *target, KeyValues *userData = NULL)
+ {
+ MenuItem *item = new CGameMenuItem(this, itemName);
+ item->AddActionSignalTarget(target);
+ item->SetCommand(command);
+ item->SetText(itemText);
+ item->SetUserData(userData);
+ return BaseClass::AddMenuItem(item);
+ }
+
+ virtual int AddMenuItem(const char *itemName, const char *itemText, KeyValues *command, Panel *target, KeyValues *userData = NULL)
+ {
+ CGameMenuItem *item = new CGameMenuItem(this, itemName);
+ item->AddActionSignalTarget(target);
+ item->SetCommand(command);
+ item->SetText(itemText);
+ item->SetRightAlignedText(true);
+ item->SetUserData(userData);
+ return BaseClass::AddMenuItem(item);
+ }
+
+ virtual void SetMenuItemBlinkingState( const char *itemName, bool state )
+ {
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ MenuItem *menuItem = dynamic_cast<MenuItem *>(child);
+ if (menuItem)
+ {
+ if ( Q_strcmp( menuItem->GetCommand()->GetString("command", ""), itemName ) == 0 )
+ {
+ menuItem->SetBlink( state );
+ }
+ }
+ }
+ InvalidateLayout();
+ }
+
+ virtual void OnSetFocus()
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ Panel *pMainMenu = ipanel()->GetPanel( m_hMainMenuOverridePanel, "ClientDLL" );
+ if ( pMainMenu )
+ {
+ pMainMenu->PerformLayout();
+ }
+ }
+
+ BaseClass::OnSetFocus();
+ }
+
+ virtual void OnCommand(const char *command)
+ {
+ m_KeyRepeat.Reset();
+
+
+ if (!stricmp(command, "Open"))
+ {
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force to be always visible
+ ipanel()->MoveToFront( m_hMainMenuOverridePanel );
+ ipanel()->RequestFocus( m_hMainMenuOverridePanel );
+ }
+ else
+ {
+ MoveToFront();
+ RequestFocus();
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+ }
+
+ virtual void OnKeyCodePressed( KeyCode code )
+ {
+ if ( IsX360() )
+ {
+ if ( GetAlpha() != 255 )
+ {
+ SetEnabled( false );
+ // inhibit key activity during transitions
+ return;
+ }
+
+ SetEnabled( true );
+
+ if ( code == KEY_XBUTTON_B || code == KEY_XBUTTON_START )
+ {
+ if ( GameUI().IsInLevel() )
+ {
+ GetParent()->OnCommand( "ResumeGame" );
+ }
+ return;
+ }
+ }
+
+ m_KeyRepeat.KeyDown( code );
+
+ int nDir = 0;
+
+ switch ( code )
+ {
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case KEY_XSTICK2_UP:
+ case KEY_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ nDir = -1;
+ break;
+
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case KEY_XSTICK2_DOWN:
+ case KEY_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ nDir = 1;
+ break;
+ }
+
+ if ( nDir != 0 )
+ {
+ CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
+ VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons );
+
+ if ( VguiPanelNavigateSortedChildButtonList( (void*)&vecSortedButtons, nDir ) != -1 )
+ {
+ // Handled!
+ return;
+ }
+ }
+ else if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ CUtlSortVector< SortedPanel_t, CSortedPanelYLess > vecSortedButtons;
+ VguiPanelGetSortedChildButtonList( this, (void*)&vecSortedButtons );
+
+ for ( int i = 0; i < vecSortedButtons.Count(); i++ )
+ {
+ if ( vecSortedButtons[ i ].pButton->IsArmed() )
+ {
+ vecSortedButtons[ i ].pButton->DoClick();
+ return;
+ }
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+
+ // HACK: Allow F key bindings to operate even here
+ if ( IsPC() && code >= KEY_F1 && code <= KEY_F12 )
+ {
+ // See if there is a binding for the FKey
+ const char *binding = gameuifuncs->GetBindingForButtonCode( code );
+ if ( binding && binding[0] )
+ {
+ // submit the entry as a console commmand
+ char szCommand[256];
+ Q_strncpy( szCommand, binding, sizeof( szCommand ) );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ }
+ }
+
+ void OnKeyCodeReleased( vgui::KeyCode code )
+ {
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+ }
+
+ void OnThink()
+ {
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ OnKeyCodeTyped( code );
+ }
+
+ BaseClass::OnThink();
+ }
+
+ virtual void OnKillFocus()
+ {
+ BaseClass::OnKillFocus();
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // force us to the rear when we lose focus (so it looks like the menu is always on the background)
+ surface()->MovePopupToBack( m_hMainMenuOverridePanel );
+ }
+ else
+ {
+ // force us to the rear when we lose focus (so it looks like the menu is always on the background)
+ surface()->MovePopupToBack(GetVPanel());
+ }
+
+ m_KeyRepeat.Reset();
+ }
+
+ void ShowFooter( bool bShow )
+ {
+ if ( m_pConsoleFooter )
+ {
+ m_pConsoleFooter->SetVisible( bShow );
+ }
+ }
+
+ void UpdateMenuItemState( bool isInGame, bool isMultiplayer, bool isInReplay, bool isVREnabled, bool isVRActive )
+ {
+ bool isSteam = IsPC() && ( CommandLine()->FindParm("-steam") != 0 );
+ bool bIsConsoleUI = GameUI().IsConsoleUI();
+
+ // disabled save button if we're not in a game
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ MenuItem *menuItem = dynamic_cast<MenuItem *>(child);
+ if (menuItem)
+ {
+ bool shouldBeVisible = true;
+ // filter the visibility
+ KeyValues *kv = menuItem->GetUserData();
+ if (!kv)
+ continue;
+
+ if (!isInGame && kv->GetInt("OnlyInGame") )
+ {
+ shouldBeVisible = false;
+ }
+ if (!isInReplay && kv->GetInt("OnlyInReplay") )
+ {
+ shouldBeVisible = false;
+ }
+ else if (!isVREnabled && kv->GetInt("OnlyWhenVREnabled") )
+ {
+ shouldBeVisible = false;
+ }
+ else if ( ( !isVRActive || ShouldForceVRActive() ) && kv->GetInt( "OnlyWhenVRActive" ) )
+ {
+ shouldBeVisible = false;
+ }
+ else if (isVRActive && kv->GetInt("OnlyWhenVRInactive") )
+ {
+ shouldBeVisible = false;
+ }
+ else if (isMultiplayer && kv->GetInt("notmulti"))
+ {
+ shouldBeVisible = false;
+ }
+ else if (isInGame && !isMultiplayer && kv->GetInt("notsingle"))
+ {
+ shouldBeVisible = false;
+ }
+ else if (isSteam && kv->GetInt("notsteam"))
+ {
+ shouldBeVisible = false;
+ }
+ else if ( !bIsConsoleUI && kv->GetInt( "ConsoleOnly" ) )
+ {
+ shouldBeVisible = false;
+ }
+
+ // If we're playing back a replay, hide everything else
+ if ( isInReplay && !kv->GetInt("OnlyInReplay") )
+ {
+ shouldBeVisible = false;
+ }
+
+ menuItem->SetVisible( shouldBeVisible );
+ }
+ }
+
+ if ( !isInGame )
+ {
+ // Sort them into their original order
+ for ( int j = 0; j < GetChildCount() - 2; j++ )
+ {
+ MoveMenuItem( j, j + 1 );
+ }
+ }
+ else
+ {
+ // Sort them into their in game order
+ for ( int i = 0; i < GetChildCount(); i++ )
+ {
+ for ( int j = i; j < GetChildCount() - 2; j++ )
+ {
+ int iID1 = GetMenuID( j );
+ int iID2 = GetMenuID( j + 1 );
+
+ MenuItem *menuItem1 = GetMenuItem( iID1 );
+ MenuItem *menuItem2 = GetMenuItem( iID2 );
+
+ KeyValues *kv1 = menuItem1->GetUserData();
+ KeyValues *kv2 = menuItem2->GetUserData();
+
+ if ( kv1->GetInt("InGameOrder") > kv2->GetInt("InGameOrder") )
+ MoveMenuItem( iID2, iID1 );
+ }
+ }
+ }
+
+ InvalidateLayout();
+
+ if ( m_pConsoleFooter )
+ {
+ // update the console footer
+ const char *pHelpName;
+ if ( !isInGame )
+ pHelpName = "MainMenu";
+ else
+ pHelpName = "GameMenu";
+
+ if ( !m_pConsoleFooter->GetHelpName() || V_stricmp( pHelpName, m_pConsoleFooter->GetHelpName() ) )
+ {
+ // game menu must re-establish its own help once it becomes re-active
+ m_pConsoleFooter->SetHelpNameAndReset( pHelpName );
+ m_pConsoleFooter->AddNewButtonLabel( "#GameUI_Action", "#GameUI_Icons_A_BUTTON" );
+ if ( isInGame )
+ {
+ m_pConsoleFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ }
+ }
+ }
+ }
+
+ MESSAGE_FUNC_INT( OnCursorEnteredMenuItem, "CursorEnteredMenuItem", VPanel);
+
+private:
+ CFooterPanel *m_pConsoleFooter;
+ vgui::CKeyRepeatHandler m_KeyRepeat;
+ vgui::VPANEL m_hMainMenuOverridePanel;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Respond to cursor entering a menuItem.
+//-----------------------------------------------------------------------------
+void CGameMenu::OnCursorEnteredMenuItem(int VPanel)
+{
+ VPANEL menuItem = (VPANEL)VPanel;
+ MenuItem *item = static_cast<MenuItem *>(ipanel()->GetPanel(menuItem, GetModuleName()));
+ KeyValues *pCommand = item->GetCommand();
+ if ( !pCommand->GetFirstSubKey() )
+ return;
+ const char *pszCmd = pCommand->GetFirstSubKey()->GetString();
+ if ( !pszCmd || !pszCmd[0] )
+ return;
+
+ BaseClass::OnCursorEnteredMenuItem( VPanel );
+}
+
+static CBackgroundMenuButton* CreateMenuButton( CBasePanel *parent, const char *panelName, const wchar_t *panelText )
+{
+ CBackgroundMenuButton *pButton = new CBackgroundMenuButton( parent, panelName );
+ pButton->SetProportional(true);
+ pButton->SetCommand("OpenGameMenu");
+ pButton->SetText(panelText);
+
+ return pButton;
+}
+
+bool g_bIsCreatingNewGameMenuForPreFetching = false;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBasePanel::CBasePanel() : Panel(NULL, "BaseGameUIPanel")
+{
+ g_pBasePanel = this;
+ m_bLevelLoading = false;
+ m_eBackgroundState = BACKGROUND_INITIAL;
+ m_flTransitionStartTime = 0.0f;
+ m_flTransitionEndTime = 0.0f;
+ m_flFrameFadeInTime = 0.5f;
+ m_bRenderingBackgroundTransition = false;
+ m_bFadingInMenus = false;
+ m_bEverActivated = false;
+ m_iGameMenuInset = 24;
+ m_bPlatformMenuInitialized = false;
+ m_bHaveDarkenedBackground = false;
+ m_bHaveDarkenedTitleText = true;
+ m_bForceTitleTextUpdate = true;
+ m_BackdropColor = Color(0, 0, 0, 128);
+ m_pConsoleAnimationController = NULL;
+ m_pConsoleControlSettings = NULL;
+ m_bCopyFrameBuffer = false;
+ m_bUseRenderTargetImage = false;
+ m_ExitingFrameCount = 0;
+ m_bXUIVisible = false;
+ m_bUseMatchmaking = false;
+ m_bRestartFromInvite = false;
+ m_bRestartSameGame = false;
+ m_bUserRefusedSignIn = false;
+ m_bUserRefusedStorageDevice = false;
+ m_bWaitingForUserSignIn = false;
+ m_bWaitingForStorageDeviceHandle = false;
+ m_bNeedStorageDeviceHandle = false;
+ m_bStorageBladeShown = false;
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ m_pAsyncJob = NULL;
+ m_pStorageDeviceValidatedNotify = NULL;
+
+ m_iRenderTargetImageID = -1;
+ m_iBackgroundImageID = -1;
+ m_iProductImageID = -1;
+ m_iLoadingImageID = -1;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pConsoleAnimationController = new AnimationController( this );
+ m_pConsoleAnimationController->SetScriptFile( GetVPanel(), "scripts/GameUIAnimations.txt" );
+ m_pConsoleAnimationController->SetAutoReloadScript( IsDebug() );
+
+ m_pConsoleControlSettings = new KeyValues( "XboxDialogs.res" );
+ if ( !m_pConsoleControlSettings->LoadFromFile( g_pFullFileSystem, "resource/UI/XboxDialogs.res", "GAME" ) )
+ {
+ Error( "Failed to load UI control settings!\n" );
+ }
+ else
+ {
+ m_pConsoleControlSettings->ProcessResolutionKeys( surface()->GetResolutionKey() );
+ }
+
+#ifdef _X360
+ x360_audio_english.SetValue( XboxLaunch()->GetForceEnglish() );
+#endif
+ }
+
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "GameMenuButton", ModInfo().GetGameTitle() ) );
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "GameMenuButton2", ModInfo().GetGameTitle2() ) );
+#ifdef CS_BETA
+ if ( !ModInfo().NoCrosshair() ) // hack to not show the BETA for HL2 or HL1Port
+ {
+ m_pGameMenuButtons.AddToTail( CreateMenuButton( this, "BetaButton", L"BETA" ) );
+ }
+#endif // CS_BETA
+
+ m_pGameMenu = NULL;
+ m_pGameLogo = NULL;
+ m_hMainMenuOverridePanel = NULL;
+
+ if ( SteamClient() )
+ {
+ HSteamPipe steamPipe = SteamClient()->CreateSteamPipe();
+ ISteamUtils *pUtils = SteamClient()->GetISteamUtils( steamPipe, "SteamUtils002" );
+ if ( pUtils )
+ {
+ bSteamCommunityFriendsVersion = true;
+ }
+
+ SteamClient()->BReleaseSteamPipe( steamPipe );
+ }
+
+ CreateGameMenu();
+ CreateGameLogo();
+
+ // Bonus maps menu blinks if something has been unlocked since the player last opened the menu
+ // This is saved as persistant data, and here is where we check for that
+ CheckBonusBlinkState();
+
+ // start the menus fully transparent
+ SetMenuAlpha( 0 );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ // do any costly resource prefetching now....
+ // force the new dialog to get all of its chapter pics
+ g_bIsCreatingNewGameMenuForPreFetching = true;
+ m_hNewGameDialog = new CNewGameDialog( this, false );
+ m_hNewGameDialog->MarkForDeletion();
+ g_bIsCreatingNewGameMenuForPreFetching = false;
+
+ m_hOptionsDialog_Xbox = new COptionsDialogXbox( this );
+ m_hOptionsDialog_Xbox->MarkForDeletion();
+
+ m_hControllerDialog = new CControllerDialog( this );
+ m_hControllerDialog->MarkForDeletion();
+
+ ArmFirstMenuItem();
+ m_pConsoleAnimationController->StartAnimationSequence( "InitializeUILayout" );
+ }
+
+ // Record data used for rich presence updates
+ if ( IsX360() )
+ {
+ // Get our active mod directory name
+ const char *pGameName = CommandLine()->ParmValue( "-game", "hl2" );;
+
+ // Set the game we're playing
+ m_iGameID = CONTEXT_GAME_GAME_HALF_LIFE_2;
+ m_bSinglePlayer = true;
+ if ( Q_stristr( pGameName, "episodic" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_EPISODE_ONE;
+ }
+ else if ( Q_stristr( pGameName, "ep2" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_EPISODE_TWO;
+ }
+ else if ( Q_stristr( pGameName, "portal" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_PORTAL;
+ }
+ else if ( Q_stristr( pGameName, "tf" ) )
+ {
+ m_iGameID = CONTEXT_GAME_GAME_TEAM_FORTRESS;
+ m_bSinglePlayer = false;
+ }
+
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Xbox 360 - Get the console UI keyvalues to pass to LoadControlSettings()
+//-----------------------------------------------------------------------------
+KeyValues *CBasePanel::GetConsoleControlSettings( void )
+{
+ return m_pConsoleControlSettings;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Causes the first menu item to be armed
+//-----------------------------------------------------------------------------
+void CBasePanel::ArmFirstMenuItem( void )
+{
+ UpdateGameMenus();
+
+ // Arm the first item in the menu
+ for ( int i = 0; i < m_pGameMenu->GetItemCount(); ++i )
+ {
+ if ( m_pGameMenu->GetMenuItem( i )->IsVisible() )
+ {
+ m_pGameMenu->SetCurrentlyHighlightedItem( i );
+ break;
+ }
+ }
+}
+
+CBasePanel::~CBasePanel()
+{
+ g_pBasePanel = NULL;
+
+ if ( vgui::surface() )
+ {
+ if ( m_iRenderTargetImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iRenderTargetImageID );
+ m_iRenderTargetImageID = -1;
+ }
+
+ if ( m_iBackgroundImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iBackgroundImageID );
+ m_iBackgroundImageID = -1;
+ }
+
+ if ( m_iProductImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iProductImageID );
+ m_iProductImageID = -1;
+ }
+
+ if ( m_iLoadingImageID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iLoadingImageID );
+ m_iLoadingImageID = -1;
+ }
+ }
+}
+
+static const char *g_rgValidCommands[] =
+{
+ "OpenGameMenu",
+ "OpenPlayerListDialog",
+ "OpenNewGameDialog",
+ "OpenLoadGameDialog",
+ "OpenSaveGameDialog",
+ "OpenCustomMapsDialog",
+ "OpenOptionsDialog",
+ "OpenBenchmarkDialog",
+ "OpenServerBrowser",
+ "OpenFriendsDialog",
+ "OpenLoadDemoDialog",
+ "OpenCreateMultiplayerGameDialog",
+ "OpenChangeGameDialog",
+ "OpenLoadCommentaryDialog",
+ "Quit",
+ "QuitNoConfirm",
+ "ResumeGame",
+ "Disconnect",
+};
+
+static void CC_GameMenuCommand( const CCommand &args )
+{
+ int c = args.ArgC();
+ if ( c < 2 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ if ( !g_pBasePanel )
+ {
+ return;
+ }
+
+ vgui::ivgui()->PostMessage( g_pBasePanel->GetVPanel(), new KeyValues("Command", "command", args[1] ), NULL);
+}
+
+static int CC_GameMenuCompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
+{
+ char const *cmdname = "gamemenucommand";
+
+ char *substring = (char *)partial;
+ if ( Q_strstr( partial, cmdname ) )
+ {
+ substring = (char *)partial + strlen( cmdname ) + 1;
+ }
+
+ int checklen = Q_strlen( substring );
+
+ CUtlRBTree< CUtlString > symbols( 0, 0, UtlStringLessFunc );
+
+ int i;
+ int c = ARRAYSIZE( g_rgValidCommands );
+ for ( i = 0; i < c; ++i )
+ {
+ if ( Q_strnicmp( g_rgValidCommands[ i ], substring, checklen ) )
+ continue;
+
+ CUtlString str;
+ str = g_rgValidCommands[ i ];
+
+ symbols.Insert( str );
+
+ // Too many
+ if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
+ break;
+ }
+
+ // Now fill in the results
+ int slot = 0;
+ for ( i = symbols.FirstInorder(); i != symbols.InvalidIndex(); i = symbols.NextInorder( i ) )
+ {
+ char const *name = symbols[ i ].String();
+
+ char buf[ 512 ];
+ Q_strncpy( buf, name, sizeof( buf ) );
+ Q_strlower( buf );
+
+ Q_snprintf( commands[ slot++ ], COMMAND_COMPLETION_ITEM_LENGTH, "%s %s",
+ cmdname, buf );
+ }
+
+ return slot;
+}
+
+static ConCommand gamemenucommand( "gamemenucommand", CC_GameMenuCommand, "Issue game menu command.", 0, CC_GameMenuCompletionFunc );
+
+//-----------------------------------------------------------------------------
+// Purpose: paints the main background image
+//-----------------------------------------------------------------------------
+void CBasePanel::PaintBackground()
+{
+ if ( !GameUI().IsInLevel() || g_hLoadingDialog.Get() || m_ExitingFrameCount )
+ {
+ // not in the game or loading dialog active or exiting, draw the ui background
+ DrawBackgroundImage();
+ }
+ else if ( IsX360() )
+ {
+ // only valid during loading from level to level
+ m_bUseRenderTargetImage = false;
+ }
+
+ if ( m_flBackgroundFillAlpha )
+ {
+ int swide, stall;
+ surface()->GetScreenSize(swide, stall);
+ surface()->DrawSetColor(0, 0, 0, m_flBackgroundFillAlpha);
+ surface()->DrawFilledRect(0, 0, swide, stall);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Updates which background state we should be in.
+//
+// NOTE: These states change at funny times and overlap. They CANNOT be
+// used to demarcate exact transitions.
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateBackgroundState()
+{
+ if ( m_ExitingFrameCount )
+ {
+ // trumps all, an exiting state must own the screen image
+ // cannot be stopped
+ SetBackgroundRenderState( BACKGROUND_EXITING );
+ }
+ else if ( GameUI().IsInLevel() )
+ {
+ SetBackgroundRenderState( BACKGROUND_LEVEL );
+ }
+ else if ( GameUI().IsInBackgroundLevel() && !m_bLevelLoading )
+ {
+ // 360 guarantees a progress bar
+ // level loading is truly completed when the progress bar is gone, then transition to main menu
+ if ( IsPC() || ( IsX360() && !g_hLoadingDialog.Get() ) )
+ {
+ SetBackgroundRenderState( BACKGROUND_MAINMENU );
+ }
+ }
+ else if ( m_bLevelLoading )
+ {
+ SetBackgroundRenderState( BACKGROUND_LOADING );
+ }
+ else if ( m_bEverActivated && m_bPlatformMenuInitialized )
+ {
+ SetBackgroundRenderState( BACKGROUND_DISCONNECTED );
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !m_ExitingFrameCount && !m_bLevelLoading && !g_hLoadingDialog.Get() && GameUI().IsInLevel() )
+ {
+ // paused
+ if ( m_flBackgroundFillAlpha == 0.0f )
+ m_flBackgroundFillAlpha = 120.0f;
+ }
+ else
+ {
+ m_flBackgroundFillAlpha = 0;
+ }
+
+ // console ui has completely different menu/dialog/fill/fading behavior
+ return;
+ }
+
+ // don't evaluate the rest until we've initialized the menus
+ if ( !m_bPlatformMenuInitialized )
+ return;
+
+ // check for background fill
+ // fill over the top if we have any dialogs up
+ int i;
+ bool bHaveActiveDialogs = false;
+ bool bIsInLevel = GameUI().IsInLevel();
+ for ( i = 0; i < GetChildCount(); ++i )
+ {
+ VPANEL child = ipanel()->GetChild( GetVPanel(), i );
+ if ( child
+ && ipanel()->IsVisible( child )
+ && ipanel()->IsPopup( child )
+ && child != m_pGameMenu->GetVPanel() )
+ {
+ bHaveActiveDialogs = true;
+ }
+ }
+ // see if the base gameui panel has dialogs hanging off it (engine stuff, console, bug reporter)
+ VPANEL parent = GetVParent();
+ for ( i = 0; i < ipanel()->GetChildCount( parent ); ++i )
+ {
+ VPANEL child = ipanel()->GetChild( parent, i );
+ if ( child
+ && ipanel()->IsVisible( child )
+ && ipanel()->IsPopup( child )
+ && child != GetVPanel() )
+ {
+ bHaveActiveDialogs = true;
+ }
+ }
+
+ // check to see if we need to fade in the background fill
+ bool bNeedDarkenedBackground = (bHaveActiveDialogs || bIsInLevel);
+ if ( m_bHaveDarkenedBackground != bNeedDarkenedBackground )
+ {
+ // fade in faster than we fade out
+ float targetAlpha, duration;
+ if ( bNeedDarkenedBackground )
+ {
+ // fade in background tint
+ targetAlpha = m_BackdropColor[3];
+ duration = m_flFrameFadeInTime;
+ }
+ else
+ {
+ // fade out background tint
+ targetAlpha = 0.0f;
+ duration = 2.0f;
+ }
+
+ m_bHaveDarkenedBackground = bNeedDarkenedBackground;
+ vgui::GetAnimationController()->RunAnimationCommand( this, "m_flBackgroundFillAlpha", targetAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ // check to see if the game title should be dimmed
+ // don't transition on level change
+ if ( m_bLevelLoading )
+ return;
+
+ bool bNeedDarkenedTitleText = bHaveActiveDialogs;
+ if (m_bHaveDarkenedTitleText != bNeedDarkenedTitleText || m_bForceTitleTextUpdate)
+ {
+ float targetTitleAlpha, duration;
+ if (bHaveActiveDialogs)
+ {
+ // fade out title text
+ duration = m_flFrameFadeInTime;
+ targetTitleAlpha = 32.0f;
+ }
+ else
+ {
+ // fade in title text
+ duration = 2.0f;
+ targetTitleAlpha = 255.0f;
+ }
+
+ if ( m_pGameLogo )
+ {
+ vgui::GetAnimationController()->RunAnimationCommand( m_pGameLogo, "alpha", targetTitleAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ // Msg( "animating title (%d => %d at time %.2f)\n", m_pGameMenuButton->GetAlpha(), (int)targetTitleAlpha, engine->Time());
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ vgui::GetAnimationController()->RunAnimationCommand( m_pGameMenuButtons[i], "alpha", targetTitleAlpha, 0.0f, duration, AnimationController::INTERPOLATOR_LINEAR );
+ }
+ m_bHaveDarkenedTitleText = bNeedDarkenedTitleText;
+ m_bForceTitleTextUpdate = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets how the game background should render
+//-----------------------------------------------------------------------------
+void CBasePanel::SetBackgroundRenderState(EBackgroundState state)
+{
+ if ( state == m_eBackgroundState )
+ {
+ return;
+ }
+
+ // apply state change transition
+ float frametime = engine->Time();
+
+ if ( m_eBackgroundState == BACKGROUND_INITIAL && ( state == BACKGROUND_DISCONNECTED || state == BACKGROUND_MAINMENU ) )
+ {
+ ConVar* dev_loadtime_mainmenu = cvar->FindVar( "dev_loadtime_mainmenu" );
+ if (dev_loadtime_mainmenu) {
+ dev_loadtime_mainmenu->SetValue( frametime );
+ }
+ }
+
+
+ m_bRenderingBackgroundTransition = false;
+ m_bFadingInMenus = false;
+
+ CMatchmakingBasePanel *pPanel = GetMatchmakingBasePanel();
+
+ if ( pPanel )
+ {
+ if ( state == BACKGROUND_LOADING )
+ {
+ pPanel->SetVisible( false );
+ }
+ else
+ {
+ pPanel->SetVisible( true );
+ }
+ }
+
+ if ( state == BACKGROUND_EXITING )
+ {
+ // hide the menus
+ m_bCopyFrameBuffer = false;
+ }
+ else if ( state == BACKGROUND_DISCONNECTED || state == BACKGROUND_MAINMENU )
+ {
+ // menu fading
+ // make the menus visible
+ m_bFadingInMenus = true;
+ m_flFadeMenuStartTime = frametime;
+ m_flFadeMenuEndTime = frametime + 3.0f;
+
+ if ( state == BACKGROUND_MAINMENU )
+ {
+ // fade background into main menu
+ m_bRenderingBackgroundTransition = true;
+ m_flTransitionStartTime = frametime;
+ m_flTransitionEndTime = frametime + 3.0f;
+ }
+ }
+ else if ( state == BACKGROUND_LOADING )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ RunAnimationWithCallback( this, "InstantHideMainMenu", new KeyValues( "LoadMap" ) );
+ }
+
+ // hide the menus
+ SetMenuAlpha( 0 );
+ }
+ else if ( state == BACKGROUND_LEVEL )
+ {
+ // show the menus
+ SetMenuAlpha( 255 );
+ }
+
+ m_eBackgroundState = state;
+}
+
+void CBasePanel::StartExitingProcess()
+{
+ // must let a non trivial number of screen swaps occur to stabilize image
+ // ui runs in a constrained state, while shutdown is occurring
+ m_flTransitionStartTime = engine->Time();
+ m_flTransitionEndTime = m_flTransitionStartTime + 0.5f;
+ m_ExitingFrameCount = 30;
+ g_pInputSystem->DetachFromWindow();
+
+ CMatchmakingBasePanel *pPanel = GetMatchmakingBasePanel();
+ if ( pPanel )
+ {
+ pPanel->CloseAllDialogs( false );
+ }
+
+ engine->StartXboxExitingProcess();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Size should only change on first vgui frame after startup
+//-----------------------------------------------------------------------------
+void CBasePanel::OnSizeChanged( int newWide, int newTall )
+{
+ // Recenter message dialogs
+ m_MessageDialogHandler.PositionDialogs( newWide, newTall );
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->SetBounds( 0, 0, newWide, newTall );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: notifications
+//-----------------------------------------------------------------------------
+void CBasePanel::OnLevelLoadingStarted()
+{
+ m_bLevelLoading = true;
+
+ m_pGameMenu->ShowFooter( false );
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->OnCommand( "LevelLoadingStarted" );
+ }
+
+ if ( IsX360() && m_eBackgroundState == BACKGROUND_LEVEL )
+ {
+ // already in a level going to another level
+ // frame buffer is about to be cleared, copy it off for ui backing purposes
+ m_bCopyFrameBuffer = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: notification
+//-----------------------------------------------------------------------------
+void CBasePanel::OnLevelLoadingFinished()
+{
+ m_bLevelLoading = false;
+
+ if ( m_hMatchmakingBasePanel.Get() )
+ {
+ m_hMatchmakingBasePanel->OnCommand( "LevelLoadingFinished" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Draws the background image.
+//-----------------------------------------------------------------------------
+void CBasePanel::DrawBackgroundImage()
+{
+ if ( IsX360() && m_bCopyFrameBuffer )
+ {
+ // force the engine to do an image capture ONCE into this image's render target
+ char filename[MAX_PATH];
+ surface()->DrawGetTextureFile( m_iRenderTargetImageID, filename, sizeof( filename ) );
+ engine->CopyFrameBufferToMaterial( filename );
+ m_bCopyFrameBuffer = false;
+ m_bUseRenderTargetImage = true;
+ }
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ float frametime = engine->Time();
+
+ // a background transition has a running map underneath it, so fade image out
+ // otherwise, there is no map and the background image stays opaque
+ int alpha = 255;
+ if ( m_bRenderingBackgroundTransition )
+ {
+ // goes from [255..0]
+ alpha = (m_flTransitionEndTime - frametime) / (m_flTransitionEndTime - m_flTransitionStartTime) * 255;
+ alpha = clamp( alpha, 0, 255 );
+ }
+
+ // an exiting process needs to opaquely cover everything
+ if ( m_ExitingFrameCount )
+ {
+ // goes from [0..255]
+ alpha = (m_flTransitionEndTime - frametime) / (m_flTransitionEndTime - m_flTransitionStartTime) * 255;
+ alpha = 255 - clamp( alpha, 0, 255 );
+ }
+
+ int iImageID = m_iBackgroundImageID;
+ if ( IsX360() )
+ {
+ if ( m_ExitingFrameCount )
+ {
+ if ( !m_bRestartSameGame )
+ {
+ iImageID = m_iProductImageID;
+ }
+ }
+ else if ( m_bUseRenderTargetImage )
+ {
+ // the render target image must be opaque, the alpha channel contents are unknown
+ // it is strictly an opaque background image and never used as an overlay
+ iImageID = m_iRenderTargetImageID;
+ alpha = 255;
+ }
+ }
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( iImageID );
+ surface()->DrawTexturedRect( 0, 0, wide, tall );
+
+ if ( IsX360() && m_ExitingFrameCount )
+ {
+ // Make invisible when going back to appchooser
+ m_pGameMenu->CGameMenu::BaseClass::SetVisible( false );
+
+ IScheme *pScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "SourceScheme" ) );
+ HFont hFont = pScheme->GetFont( "ChapterTitle" );
+ wchar_t *pString = g_pVGuiLocalize->Find( "#GameUI_Loading" );
+ int textWide, textTall;
+ surface()->GetTextSize( hFont, pString, textWide, textTall );
+ surface()->DrawSetTextPos( ( wide - textWide )/2, tall * 0.50f );
+ surface()->DrawSetTextFont( hFont );
+ surface()->DrawSetTextColor( 255, 255, 255, alpha );
+ surface()->DrawPrintText( pString, wcslen( pString ) );
+ }
+
+ // 360 always use the progress bar, TCR Requirement, and never this loading plaque
+ if ( IsPC() && ( m_bRenderingBackgroundTransition || m_eBackgroundState == BACKGROUND_LOADING ) )
+ {
+ // draw the loading image over the top
+ surface()->DrawSetColor(255, 255, 255, alpha);
+ surface()->DrawSetTexture(m_iLoadingImageID);
+ int twide, ttall;
+ surface()->DrawGetTextureSize(m_iLoadingImageID, twide, ttall);
+ surface()->DrawTexturedRect(wide - twide, tall - ttall, wide, tall);
+ }
+
+ // update the menu alpha
+ if ( m_bFadingInMenus )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pConsoleAnimationController->StartAnimationSequence( "OpenMainMenu" );
+ m_bFadingInMenus = false;
+ }
+ else
+ {
+ // goes from [0..255]
+ alpha = (frametime - m_flFadeMenuStartTime) / (m_flFadeMenuEndTime - m_flFadeMenuStartTime) * 255;
+ alpha = clamp( alpha, 0, 255 );
+ m_pGameMenu->SetAlpha( alpha );
+ if ( alpha == 255 )
+ {
+ m_bFadingInMenus = false;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CreateGameMenu()
+{
+ // load settings from config file
+ KeyValues *datafile = new KeyValues("GameMenu");
+ datafile->UsesEscapeSequences( true ); // VGUI uses escape sequences
+ if (datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res" ) )
+ {
+ m_pGameMenu = RecursiveLoadGameMenu(datafile);
+ }
+
+ if ( !m_pGameMenu )
+ {
+ Error( "Could not load file Resource/GameMenu.res" );
+ }
+ else
+ {
+ // start invisible
+ SETUP_PANEL( m_pGameMenu );
+ m_pGameMenu->SetAlpha( 0 );
+ }
+
+ datafile->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CreateGameLogo()
+{
+ if ( ModInfo().UseGameLogo() )
+ {
+ m_pGameLogo = new CMainMenuGameLogo( this, "GameLogo" );
+
+ if ( m_pGameLogo )
+ {
+ SETUP_PANEL( m_pGameLogo );
+ m_pGameLogo->InvalidateLayout( true, true );
+
+ // start invisible
+ m_pGameLogo->SetAlpha( 0 );
+ }
+ }
+ else
+ {
+ m_pGameLogo = NULL;
+ }
+}
+
+void CBasePanel::CheckBonusBlinkState()
+{
+#ifdef _X360
+ // On 360 if we have a storage device at this point and try to read the bonus data it can't find the bonus file!
+ return;
+#endif
+
+ if ( BonusMapsDatabase()->GetBlink() )
+ {
+ if ( GameUI().IsConsoleUI() )
+ SetMenuItemBlinkingState( "OpenNewGameDialog", true ); // Consoles integrate bonus maps menu into the new game menu
+ else
+ SetMenuItemBlinkingState( "OpenBonusMapsDialog", true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if menu items need to be enabled/disabled
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateGameMenus()
+{
+ // check our current state
+ bool isInGame = GameUI().IsInLevel();
+ bool isMulti = isInGame && (engine->GetMaxClients() > 1);
+ bool isInReplay = GameUI().IsInReplay();
+ bool isVREnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter();
+ bool isVRActive = UseVR();
+
+ // iterate all the menu items
+ m_pGameMenu->UpdateMenuItemState( isInGame, isMulti, isInReplay, isVREnabled, isVRActive );
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ vgui::ivgui()->PostMessage( m_hMainMenuOverridePanel, new KeyValues( "UpdateMenu" ), NULL );
+ }
+
+ // position the menu
+ InvalidateLayout();
+ m_pGameMenu->SetVisible( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up the game menu from the keyvalues
+// the game menu is hierarchial, so this is recursive
+//-----------------------------------------------------------------------------
+CGameMenu *CBasePanel::RecursiveLoadGameMenu(KeyValues *datafile)
+{
+ CGameMenu *menu = new CGameMenu(this, datafile->GetName());
+
+ // loop through all the data adding items to the menu
+ for (KeyValues *dat = datafile->GetFirstSubKey(); dat != NULL; dat = dat->GetNextKey())
+ {
+ const char *label = dat->GetString("label", "<unknown>");
+ const char *cmd = dat->GetString("command", NULL);
+ const char *name = dat->GetString("name", label);
+
+ if ( cmd && !Q_stricmp( cmd, "OpenFriendsDialog" ) && bSteamCommunityFriendsVersion )
+ continue;
+
+ menu->AddMenuItem(name, label, cmd, this, dat);
+ }
+
+ return menu;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: update the taskbar a frame
+//-----------------------------------------------------------------------------
+void CBasePanel::RunFrame()
+{
+ InvalidateLayout();
+ vgui::GetAnimationController()->UpdateAnimations( engine->Time() );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ // run the console ui animations
+ m_pConsoleAnimationController->UpdateAnimations( engine->Time() );
+
+ if ( IsX360() && m_ExitingFrameCount && engine->Time() >= m_flTransitionEndTime )
+ {
+ if ( m_ExitingFrameCount > 1 )
+ {
+ m_ExitingFrameCount--;
+ if ( m_ExitingFrameCount == 1 )
+ {
+ // enough frames have transpired, send the single shot quit command
+ // If we kicked off this event from an invite, we need to properly setup the restart to account for that
+ if ( m_bRestartFromInvite )
+ {
+ engine->ClientCmd_Unrestricted( "quit_x360 invite" );
+ }
+ else if ( m_bRestartSameGame )
+ {
+ engine->ClientCmd_Unrestricted( "quit_x360 restart" );
+ }
+ else
+ {
+ // quits to appchooser
+ engine->ClientCmd_Unrestricted( "quit_x360\n" );
+ }
+ }
+ }
+ }
+ }
+
+ UpdateBackgroundState();
+
+ if ( !m_bPlatformMenuInitialized )
+ {
+ // check to see if the platform is ready to load yet
+ if ( IsX360() || g_VModuleLoader.IsPlatformReady() )
+ {
+ m_bPlatformMenuInitialized = true;
+ }
+ }
+
+ // Check to see if a pending async task has already finished
+ if ( m_pAsyncJob && !m_pAsyncJob->m_hThreadHandle )
+ {
+ m_pAsyncJob->Completed();
+ delete m_pAsyncJob;
+ m_pAsyncJob = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tells XBox Live our user is in the current game's menu
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdateRichPresenceInfo()
+{
+#if defined( _X360 )
+ // For all other users logged into this console (not primary), set to idle to satisfy cert
+ for( uint i = 0; i < XUSER_MAX_COUNT; ++i )
+ {
+ XUSER_SIGNIN_STATE State = XUserGetSigninState( i );
+
+ if( State != eXUserSigninState_NotSignedIn )
+ {
+ if ( i != XBX_GetPrimaryUserId() )
+ {
+ // Set rich presence as 'idle' for users logged in that can't participate in orange box.
+ if ( !xboxsystem->UserSetContext( i, X_CONTEXT_PRESENCE, CONTEXT_PRESENCE_IDLE, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ }
+ }
+ }
+
+ if ( !GameUI().IsInLevel() )
+ {
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), CONTEXT_GAME, m_iGameID, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), X_CONTEXT_PRESENCE, CONTEXT_PRESENCE_MENU, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ if ( m_bSinglePlayer )
+ {
+ if ( !xboxsystem->UserSetContext( XBX_GetPrimaryUserId(), X_CONTEXT_GAME_MODE, CONTEXT_GAME_MODE_SINGLEPLAYER, true ) )
+ {
+ Warning( "BasePanel: UserSetContext failed.\n" );
+ }
+ }
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Lays out the position of the taskbar
+//-----------------------------------------------------------------------------
+void CBasePanel::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Get the screen size
+ int wide, tall;
+ vgui::surface()->GetScreenSize(wide, tall);
+
+ // Get the size of the menu
+ int menuWide, menuTall;
+ m_pGameMenu->GetSize( menuWide, menuTall );
+
+ int idealMenuY = m_iGameMenuPos.y;
+ if ( idealMenuY + menuTall + m_iGameMenuInset > tall )
+ {
+ idealMenuY = tall - menuTall - m_iGameMenuInset;
+ }
+
+ int yDiff = idealMenuY - m_iGameMenuPos.y;
+
+ for ( int i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ // Get the size of the logo text
+ //int textWide, textTall;
+ m_pGameMenuButtons[i]->SizeToContents();
+ //vgui::surface()->GetTextSize( m_pGameMenuButtons[i]->GetFont(), ModInfo().GetGameTitle(), textWide, textTall );
+
+ // place menu buttons above middle of screen
+ m_pGameMenuButtons[i]->SetPos(m_iGameTitlePos[i].x, m_iGameTitlePos[i].y + yDiff);
+ //m_pGameMenuButtons[i]->SetSize(textWide + 4, textTall + 4);
+ }
+
+ if ( m_pGameLogo )
+ {
+ // move the logo to sit right on top of the menu
+ m_pGameLogo->SetPos( m_iGameMenuPos.x + m_pGameLogo->GetOffsetX(), idealMenuY - m_pGameLogo->GetTall() + m_pGameLogo->GetOffsetY() );
+ }
+
+ // position self along middle of screen
+ if ( GameUI().IsConsoleUI() )
+ {
+ int posx, posy;
+ m_pGameMenu->GetPos( posx, posy );
+ m_iGameMenuPos.x = posx;
+ }
+ m_pGameMenu->SetPos(m_iGameMenuPos.x, idealMenuY);
+
+ UpdateGameMenus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads scheme information
+//-----------------------------------------------------------------------------
+void CBasePanel::ApplySchemeSettings(IScheme *pScheme)
+{
+ int i;
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ m_iGameMenuInset = atoi(pScheme->GetResourceString("MainMenu.Inset"));
+ m_iGameMenuInset *= 2;
+
+ IScheme *pClientScheme = vgui::scheme()->GetIScheme( vgui::scheme()->GetScheme( "ClientScheme" ) );
+ CUtlVector< Color > buttonColor;
+ if ( pClientScheme )
+ {
+ m_iGameTitlePos.RemoveAll();
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetFont(pClientScheme->GetFont("ClientTitleFont", true));
+ m_iGameTitlePos.AddToTail( coord() );
+ m_iGameTitlePos[i].x = atoi(pClientScheme->GetResourceString( CFmtStr( "Main.Title%d.X", i+1 ) ) );
+ m_iGameTitlePos[i].x = scheme()->GetProportionalScaledValue( m_iGameTitlePos[i].x );
+ m_iGameTitlePos[i].y = atoi(pClientScheme->GetResourceString( CFmtStr( "Main.Title%d.Y", i+1 ) ) );
+ m_iGameTitlePos[i].y = scheme()->GetProportionalScaledValue( m_iGameTitlePos[i].y );
+
+ if ( GameUI().IsConsoleUI() )
+ m_iGameTitlePos[i].x += MAIN_MENU_INDENT_X360;
+
+ buttonColor.AddToTail( pClientScheme->GetColor( CFmtStr( "Main.Title%d.Color", i+1 ), Color(255, 255, 255, 255)) );
+ }
+#ifdef CS_BETA
+ if ( !ModInfo().NoCrosshair() ) // hack to not show the BETA for HL2 or HL1Port
+ {
+ m_pGameMenuButtons[m_pGameMenuButtons.Count()-1]->SetFont(pClientScheme->GetFont("BetaFont", true));
+ }
+#endif // CS_BETA
+
+ m_iGameMenuPos.x = atoi(pClientScheme->GetResourceString("Main.Menu.X"));
+ m_iGameMenuPos.x = scheme()->GetProportionalScaledValue( m_iGameMenuPos.x );
+ m_iGameMenuPos.y = atoi(pClientScheme->GetResourceString("Main.Menu.Y"));
+ m_iGameMenuPos.y = scheme()->GetProportionalScaledValue( m_iGameMenuPos.y );
+
+ m_iGameMenuInset = atoi(pClientScheme->GetResourceString("Main.BottomBorder"));
+ m_iGameMenuInset = scheme()->GetProportionalScaledValue( m_iGameMenuInset );
+ }
+ else
+ {
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetFont(pScheme->GetFont("TitleFont"));
+ buttonColor.AddToTail( Color( 255, 255, 255, 255 ) );
+ }
+ }
+
+ for ( i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetDefaultColor(buttonColor[i], Color(0, 0, 0, 0));
+ m_pGameMenuButtons[i]->SetArmedColor(buttonColor[i], Color(0, 0, 0, 0));
+ m_pGameMenuButtons[i]->SetDepressedColor(buttonColor[i], Color(0, 0, 0, 0));
+ }
+
+ m_flFrameFadeInTime = atof(pScheme->GetResourceString("Frame.TransitionEffectTime"));
+
+ // work out current focus - find the topmost panel
+ SetBgColor(Color(0, 0, 0, 0));
+
+ m_BackdropColor = pScheme->GetColor("mainmenu.backdrop", Color(0, 0, 0, 128));
+
+ char filename[MAX_PATH];
+ if ( IsX360() )
+ {
+ // 360 uses FullFrameFB1 RT for map to map transitioning
+ if ( m_iRenderTargetImageID == -1 )
+ {
+ m_iRenderTargetImageID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_iRenderTargetImageID, "console/rt_background", false, false );
+ }
+ }
+
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );
+ float aspectRatio = (float)screenWide/(float)screenTall;
+ bool bIsWidescreen = aspectRatio >= 1.5999f;
+
+ // work out which background image to use
+ if ( IsPC() || !IsX360() )
+ {
+ // pc uses blurry backgrounds based on the background level
+ char background[MAX_PATH];
+ engine->GetMainMenuBackgroundName( background, sizeof(background) );
+ Q_snprintf( filename, sizeof( filename ), "console/%s%s", background, ( bIsWidescreen ? "_widescreen" : "" ) );
+ }
+ else
+ {
+ // 360 uses hi-res game specific backgrounds
+ char gameName[MAX_PATH];
+ const char *pGameDir = engine->GetGameDirectory();
+ V_FileBase( pGameDir, gameName, sizeof( gameName ) );
+ V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_%s%s", gameName, ( bIsWidescreen ? "_widescreen" : "" ) );
+ }
+
+ if ( m_iBackgroundImageID == -1 )
+ {
+ m_iBackgroundImageID = surface()->CreateNewTextureID();
+ }
+ surface()->DrawSetTextureFile( m_iBackgroundImageID, filename, false, false );
+
+ if ( IsX360() )
+ {
+ // 360 uses a product image during application exit
+ V_snprintf( filename, sizeof( filename ), "vgui/appchooser/background_orange%s", ( bIsWidescreen ? "_widescreen" : "" ) );
+
+ if ( m_iProductImageID == -1 )
+ {
+ m_iProductImageID = surface()->CreateNewTextureID();
+ }
+ surface()->DrawSetTextureFile( m_iProductImageID, filename, false, false );
+ }
+
+ if ( IsPC() )
+ {
+ // load the loading icon
+ if ( m_iLoadingImageID == -1 )
+ {
+ m_iLoadingImageID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_iLoadingImageID, "Console/startup_loading", false, false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: message handler for platform menu; activates the selected module
+//-----------------------------------------------------------------------------
+void CBasePanel::OnActivateModule(int moduleIndex)
+{
+ g_VModuleLoader.ActivateModule(moduleIndex);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Animates menus on gameUI being shown
+//-----------------------------------------------------------------------------
+void CBasePanel::OnGameUIActivated()
+{
+ // If the load failed, we're going to bail out here
+ if ( engine->MapLoadFailed() )
+ {
+ // Don't display this again until it happens again
+ engine->SetMapLoadFailed( false );
+ ShowMessageDialog( MD_LOAD_FAILED_WARNING );
+ }
+
+
+ if ( !m_bEverActivated )
+ {
+ // Layout the first time to avoid focus issues (setting menus visible will grab focus)
+ UpdateGameMenus();
+ m_bEverActivated = true;
+
+#if defined( _X360 )
+
+ // Open all active containers if we have a valid storage device
+ if ( XBX_GetPrimaryUserId() != XBX_INVALID_USER_ID && XBX_GetStorageDeviceId() != XBX_INVALID_STORAGE_ID && XBX_GetStorageDeviceId() != XBX_STORAGE_DECLINED )
+ {
+ // Open user settings and save game container here
+ uint nRet = engine->OnStorageDeviceAttached();
+ if ( nRet != ERROR_SUCCESS )
+ {
+ // Invalidate the device
+ XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID );
+
+ // FIXME: We don't know which device failed!
+ // Pop a dialog explaining that the user's data is corrupt
+ BasePanel()->ShowMessageDialog( MD_STORAGE_DEVICES_CORRUPT );
+ }
+ }
+
+ // determine if we're starting up because of a cross-game invite
+ int fLaunchFlags = XboxLaunch()->GetLaunchFlags();
+ if ( fLaunchFlags & LF_INVITERESTART )
+ {
+ XNKID nSessionID;
+ XboxLaunch()->GetInviteSessionID( &nSessionID );
+ matchmaking->JoinInviteSessionByID( nSessionID );
+ }
+#endif
+
+ // Brute force check to open tf matchmaking ui.
+ if ( GameUI().IsConsoleUI() )
+ {
+ const char *pGame = engine->GetGameDirectory();
+ if ( !Q_stricmp( Q_UnqualifiedFileName( pGame ), "tf" ) )
+ {
+ m_bUseMatchmaking = true;
+ RunMenuCommand( "OpenMatchmakingBasePanel" );
+ }
+ }
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ ArmFirstMenuItem();
+ }
+ if ( GameUI().IsInLevel() )
+ {
+ if ( !m_bUseMatchmaking )
+ {
+ OnCommand( "OpenPauseMenu" );
+ }
+ else
+ {
+ RunMenuCommand( "OpenMatchmakingBasePanel" );
+ }
+
+ if ( m_hAchievementsDialog.Get() )
+ {
+ // Achievement dialog refreshes it's data if the player looks at the pause menu
+ m_hAchievementsDialog->OnCommand( "OnGameUIActivated" );
+ }
+ }
+ else // not the pause menu, update presence
+ {
+ if ( IsX360() )
+ {
+ UpdateRichPresenceInfo();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: executes a menu command
+//-----------------------------------------------------------------------------
+void CBasePanel::RunMenuCommand(const char *command)
+{
+ if ( !Q_stricmp( command, "OpenGameMenu" ) )
+ {
+ if ( m_pGameMenu )
+ {
+ PostMessage( m_pGameMenu, new KeyValues("Command", "command", "Open") );
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenPlayerListDialog" ) )
+ {
+ OnOpenPlayerListDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenNewGameDialog" ) )
+ {
+ OnOpenNewGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadGameDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenLoadGameDialog();
+ }
+ else
+ {
+ OnOpenLoadGameDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenSaveGameDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenSaveGameDialog();
+ }
+ else
+ {
+ OnOpenSaveGameDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenBonusMapsDialog" ) )
+ {
+ OnOpenBonusMapsDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenOptionsDialog" ) )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ OnOpenOptionsDialog();
+ }
+ else
+ {
+ OnOpenOptionsDialog_Xbox();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenControllerDialog" ) )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ OnOpenControllerDialog();
+ }
+ }
+ else if ( !Q_stricmp( command, "OpenBenchmarkDialog" ) )
+ {
+ OnOpenBenchmarkDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenServerBrowser" ) )
+ {
+ OnOpenServerBrowser();
+ }
+ else if ( !Q_stricmp( command, "OpenFriendsDialog" ) )
+ {
+ OnOpenFriendsDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadDemoDialog" ) )
+ {
+ OnOpenDemoDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenCreateMultiplayerGameDialog" ) )
+ {
+ OnOpenCreateMultiplayerGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenChangeGameDialog" ) )
+ {
+ OnOpenChangeGameDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadCommentaryDialog" ) )
+ {
+ OnOpenLoadCommentaryDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenLoadSingleplayerCommentaryDialog" ) )
+ {
+ OpenLoadSingleplayerCommentaryDialog();
+ }
+ else if ( !Q_stricmp( command, "OpenMatchmakingBasePanel" ) )
+ {
+ OnOpenMatchmakingBasePanel();
+ }
+ else if ( !Q_stricmp( command, "OpenAchievementsDialog" ) )
+ {
+ if ( IsPC() )
+ {
+ if ( !steamapicontext->SteamUser() || !steamapicontext->SteamUser()->BLoggedOn() )
+ {
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox("#GameUI_Achievements_SteamRequired_Title", "#GameUI_Achievements_SteamRequired_Message");
+ pMessageBox->DoModal();
+ return;
+ }
+ OnOpenAchievementsDialog();
+ }
+ else
+ {
+ OnOpenAchievementsDialog_Xbox();
+ }
+ }
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ else if ( !Q_stricmp( command, "OpenCSAchievementsDialog" ) )
+ {
+ if ( IsPC() )
+ {
+ if ( !steamapicontext->SteamUser() || !steamapicontext->SteamUser()->BLoggedOn() )
+ {
+ vgui::MessageBox *pMessageBox = new vgui::MessageBox("#GameUI_Achievements_SteamRequired_Title", "#GameUI_Achievements_SteamRequired_Message", this );
+ pMessageBox->DoModal();
+ return;
+ }
+
+ OnOpenCSAchievementsDialog();
+ }
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ else if ( !Q_stricmp( command, "AchievementsDialogClosing" ) )
+ {
+ if ( IsX360() )
+ {
+ if ( m_hAchievementsDialog.Get() )
+ {
+ m_hAchievementsDialog->Close();
+ }
+ }
+ }
+ else if ( !Q_stricmp( command, "Quit" ) )
+ {
+ OnOpenQuitConfirmationDialog();
+ }
+ else if ( !Q_stricmp( command, "QuitNoConfirm" ) )
+ {
+ if ( IsX360() )
+ {
+ // start the shutdown process
+ StartExitingProcess();
+ }
+ else
+ {
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Shut down achievements panel
+ //=============================================================================
+
+ if ( GameClientExports() )
+ {
+ GameClientExports()->ShutdownAchievementPanel();
+ }
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ // hide everything while we quit
+ SetVisible( false );
+ vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
+ engine->ClientCmd_Unrestricted( "quit\n" );
+ }
+ }
+ else if ( !Q_stricmp( command, "QuitRestartNoConfirm" ) )
+ {
+ if ( IsX360() )
+ {
+ // start the shutdown process
+ m_bRestartSameGame = true;
+ StartExitingProcess();
+ }
+ }
+ else if ( !Q_stricmp( command, "ResumeGame" ) )
+ {
+ GameUI().HideGameUI();
+ }
+ else if ( !Q_stricmp( command, "Disconnect" ) )
+ {
+ if ( IsX360() )
+ {
+ OnOpenDisconnectConfirmationDialog();
+ }
+ else
+ {
+ engine->ClientCmd_Unrestricted( "disconnect" );
+ }
+ }
+ else if ( !Q_stricmp( command, "DisconnectNoConfirm" ) )
+ {
+ ConVarRef commentary( "commentary" );
+ if ( commentary.IsValid() && commentary.GetBool() )
+ {
+ engine->ClientCmd_Unrestricted( "disconnect" );
+
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->CloseAllDialogs( false );
+ pBase->OnCommand( "OpenWelcomeDialog" );
+ }
+ }
+ else
+ {
+ // Leave our current session, if we have one
+ matchmaking->KickPlayerFromSession( 0 );
+ }
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ }
+ else if ( Q_stristr( command, "engine " ) )
+ {
+ const char *engineCMD = strstr( command, "engine " ) + strlen( "engine " );
+ if ( strlen( engineCMD ) > 0 )
+ {
+ engine->ClientCmd_Unrestricted( const_cast<char *>( engineCMD ) );
+ }
+ }
+ else if ( !Q_stricmp( command, "ShowSigninUI" ) )
+ {
+ m_bWaitingForUserSignIn = true;
+ xboxsystem->ShowSigninUI( 1, 0 ); // One user, no special flags
+ }
+ else if ( !Q_stricmp( command, "ShowDeviceSelector" ) )
+ {
+ OnChangeStorageDevice();
+ }
+ else if ( !Q_stricmp( command, "SignInDenied" ) )
+ {
+ // The user doesn't care, so re-send the command they wanted and mark that we want to skip checking
+ m_bUserRefusedSignIn = true;
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ OnCommand( m_strPostPromptCommand );
+ }
+ }
+ else if ( !Q_stricmp( command, "RequiredSignInDenied" ) )
+ {
+ m_strPostPromptCommand = "";
+ }
+ else if ( !Q_stricmp( command, "RequiredStorageDenied" ) )
+ {
+ m_strPostPromptCommand = "";
+ }
+ else if ( !Q_stricmp( command, "StorageDeviceDenied" ) )
+ {
+ // The user doesn't care, so re-send the command they wanted and mark that we want to skip checking
+ m_bUserRefusedStorageDevice = true;
+ IssuePostPromptCommand();
+
+ // Set us as declined
+ XBX_SetStorageDeviceId( XBX_STORAGE_DECLINED );
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 2;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ }
+ else if ( !Q_stricmp( command, "clear_storage_deviceID" ) )
+ {
+ XBX_SetStorageDeviceId( XBX_STORAGE_DECLINED );
+ }
+ else if ( !Q_stricmp( command, "RestartWithNewLanguage" ) )
+ {
+ if ( !IsX360() )
+ {
+ char szSteamURL[50];
+
+ // hide everything while we quit
+ SetVisible( false );
+ vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
+ engine->ClientCmd_Unrestricted( "quit\n" );
+
+ // Construct Steam URL. Pattern is steam://run/<appid>/<language>. (e.g. Ep1 In French ==> steam://run/380/french)
+ V_snprintf( szSteamURL, sizeof(szSteamURL), "steam://run/%d/%s", engine->GetAppID(), COptionsSubAudio::GetUpdatedAudioLanguage() );
+
+ // Set Steam URL for re-launch in registry. Launcher will check this registry key and exec it in order to re-load the game in the proper language
+#if defined( WIN32 ) && !defined( _X360 )
+ HKEY hKey;
+
+ if ( IsPC() && RegOpenKeyEx( HKEY_CURRENT_USER, "Software\\Valve\\Source", NULL, KEY_WRITE, &hKey) == ERROR_SUCCESS )
+ {
+ RegSetValueEx( hKey, "Relaunch URL", 0, REG_SZ, (const unsigned char *)szSteamURL, sizeof( szSteamURL ) );
+
+ RegCloseKey(hKey);
+ }
+#elif defined( OSX ) || defined( LINUX )
+ FILE *fp = fopen( "/tmp/hl2_relaunch", "w+" );
+ if ( fp )
+ {
+ fprintf( fp, "%s\n", szSteamURL );
+ }
+ fclose( fp );
+#elif defined( _X360 )
+#else
+#error
+#endif
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Queue a command to be run when XUI Closes
+//-----------------------------------------------------------------------------
+void CBasePanel::QueueCommand( const char *pCommand )
+{
+ if ( m_bXUIVisible )
+ {
+ m_CommandQueue.AddToTail( CUtlString( pCommand ) );
+ }
+ else
+ {
+ OnCommand( pCommand );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run all the commands in the queue
+//-----------------------------------------------------------------------------
+void CBasePanel::RunQueuedCommands()
+{
+ for ( int i = 0; i < m_CommandQueue.Count(); ++i )
+ {
+ OnCommand( m_CommandQueue[i] );
+ }
+ ClearQueuedCommands();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear all queued commands
+//-----------------------------------------------------------------------------
+void CBasePanel::ClearQueuedCommands()
+{
+ m_CommandQueue.Purge();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether this command should cause us to prompt the user if they're not signed in and do not have a storage device
+//-----------------------------------------------------------------------------
+bool CBasePanel::IsPromptableCommand( const char *command )
+{
+ // Blech!
+ if ( !Q_stricmp( command, "OpenNewGameDialog" ) ||
+ !Q_stricmp( command, "OpenLoadGameDialog" ) ||
+ !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenBonusMapsDialog" ) ||
+ !Q_stricmp( command, "OpenOptionsDialog" ) ||
+ !Q_stricmp( command, "OpenControllerDialog" ) ||
+ !Q_stricmp( command, "OpenLoadCommentaryDialog" ) ||
+ !Q_stricmp( command, "OpenLoadSingleplayerCommentaryDialog" ) ||
+ !Q_stricmp( command, "OpenAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenCSAchievementsDialog" ) )
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ {
+ return true;
+ }
+
+ return false;
+}
+
+#ifdef _WIN32
+//-------------------------
+// Purpose: Job wrapper
+//-------------------------
+static unsigned PanelJobWrapperFn( void *pvContext )
+{
+ CBasePanel::CAsyncJobContext *pAsync = reinterpret_cast< CBasePanel::CAsyncJobContext * >( pvContext );
+
+ float const flTimeStart = Plat_FloatTime();
+
+ pAsync->ExecuteAsync();
+
+ float const flElapsedTime = Plat_FloatTime() - flTimeStart;
+
+ if ( flElapsedTime < pAsync->m_flLeastExecuteTime )
+ {
+ ThreadSleep( ( pAsync->m_flLeastExecuteTime - flElapsedTime ) * 1000 );
+ }
+
+ ReleaseThreadHandle( ( ThreadHandle_t ) pAsync->m_hThreadHandle );
+ pAsync->m_hThreadHandle = NULL;
+
+ return 0;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose: Enqueues a job function to be called on a separate thread
+//-----------------------------------------------------------------------------
+void CBasePanel::ExecuteAsync( CAsyncJobContext *pAsync )
+{
+ Assert( !m_pAsyncJob );
+ Assert( pAsync && !pAsync->m_hThreadHandle );
+ m_pAsyncJob = pAsync;
+
+#ifdef _WIN32
+ ThreadHandle_t hHandle = CreateSimpleThread( PanelJobWrapperFn, reinterpret_cast< void * >( pAsync ) );
+ pAsync->m_hThreadHandle = hHandle;
+
+#ifdef _X360
+ ThreadSetAffinity( hHandle, XBOX_PROCESSOR_3 );
+#endif
+
+#else
+ pAsync->ExecuteAsync();
+#endif
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether this command requires the user be signed in
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRequiresSignIn( const char *command )
+{
+ // Blech again!
+ if ( !Q_stricmp( command, "OpenAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Use cs-specific achievements dialog
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenCSAchievementsDialog" ) ||
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ !Q_stricmp( command, "OpenLoadGameDialog" ) ||
+ !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenRankingsDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether the command requires the user to have a valid storage device
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRequiresStorageDevice( const char *command )
+{
+ // Anything which touches the storage device must prompt
+ if ( !Q_stricmp( command, "OpenSaveGameDialog" ) ||
+ !Q_stricmp( command, "OpenLoadGameDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Whether the command requires the user to have a valid profile selected
+//-----------------------------------------------------------------------------
+bool CBasePanel::CommandRespectsSignInDenied( const char *command )
+{
+ // Anything which touches the user profile must prompt
+ if ( !Q_stricmp( command, "OpenOptionsDialog" ) ||
+ !Q_stricmp( command, "OpenControllerDialog" ) )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: A storage device has been connected, update our settings and anything else
+//-----------------------------------------------------------------------------
+
+class CAsyncCtxOnDeviceAttached : public CBasePanel::CAsyncJobContext
+{
+public:
+ CAsyncCtxOnDeviceAttached();
+ ~CAsyncCtxOnDeviceAttached();
+ virtual void ExecuteAsync();
+ virtual void Completed();
+ uint GetContainerOpenResult( void ) { return m_ContainerOpenResult; }
+
+private:
+ uint m_ContainerOpenResult;
+};
+
+CAsyncCtxOnDeviceAttached::CAsyncCtxOnDeviceAttached() :
+ CBasePanel::CAsyncJobContext( 3.0f ), // Storage device info for at least 3 seconds
+ m_ContainerOpenResult( ERROR_SUCCESS )
+{
+ BasePanel()->ShowMessageDialog( MD_CHECKING_STORAGE_DEVICE );
+}
+
+CAsyncCtxOnDeviceAttached::~CAsyncCtxOnDeviceAttached()
+{
+ BasePanel()->CloseMessageDialog( 0 );
+}
+
+void CAsyncCtxOnDeviceAttached::ExecuteAsync()
+{
+ // Asynchronously do the tasks that don't interact with the command buffer
+
+ // Open user settings and save game container here
+ m_ContainerOpenResult = engine->OnStorageDeviceAttached();
+ if ( m_ContainerOpenResult != ERROR_SUCCESS )
+ return;
+
+ // Make the QOS system initialized for multiplayer games
+ if ( !ModInfo().IsSinglePlayerOnly() )
+ {
+#if defined( _X360 )
+ ( void ) matchmaking->GetQosWithLIVE();
+#endif
+ }
+}
+
+void CAsyncCtxOnDeviceAttached::Completed()
+{
+ BasePanel()->OnCompletedAsyncDeviceAttached( this );
+}
+
+
+void CBasePanel::OnDeviceAttached( void )
+{
+ ExecuteAsync( new CAsyncCtxOnDeviceAttached );
+}
+
+void CBasePanel::OnCompletedAsyncDeviceAttached( CAsyncCtxOnDeviceAttached *job )
+{
+ uint nRet = job->GetContainerOpenResult();
+ if ( nRet != ERROR_SUCCESS )
+ {
+ // Invalidate the device
+ XBX_SetStorageDeviceId( XBX_INVALID_STORAGE_ID );
+
+ // FIXME: We don't know which device failed!
+ // Pop a dialog explaining that the user's data is corrupt
+ BasePanel()->ShowMessageDialog( MD_STORAGE_DEVICES_CORRUPT );
+ }
+
+ // First part of the device checking completed asynchronously,
+ // perform the rest of duties that require to run on main thread.
+ engine->ReadConfiguration();
+ engine->ExecuteClientCmd( "refreshplayerstats" );
+
+ BonusMapsDatabase()->ReadBonusMapSaveData();
+
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ {
+ m_hSaveGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ }
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ {
+ m_hLoadGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ }
+ if ( m_hOptionsDialog_Xbox.Get() )
+ {
+ m_hOptionsDialog_Xbox->OnCommand( "RefreshOptions" );
+ }
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 1;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+
+ // Finish their command
+ IssuePostPromptCommand();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: FIXME: Only TF takes this path...
+//-----------------------------------------------------------------------------
+bool CBasePanel::ValidateStorageDevice( void )
+{
+ if ( m_bUserRefusedStorageDevice == false )
+ {
+#if defined( _X360 )
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID )
+ {
+ // Try to discover content on the user's storage devices
+ DWORD nFoundDevice = xboxsystem->DiscoverUserData( XBX_GetPrimaryUserId(), COM_GetModDirectory() );
+ if ( nFoundDevice == XBX_INVALID_STORAGE_ID )
+ {
+ // They don't have a device, so ask for one
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE );
+ return false;
+ }
+ else
+ {
+ // Take this device
+ XBX_SetStorageDeviceId( nFoundDevice );
+ OnDeviceAttached();
+ }
+ // Fall through
+ }
+#endif
+ }
+ return true;
+}
+
+bool CBasePanel::ValidateStorageDevice( int *pStorageDeviceValidated )
+{
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ if ( pStorageDeviceValidated != m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = -1;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ if ( pStorageDeviceValidated )
+ {
+ if ( HandleStorageDeviceRequest( "" ) )
+ return true;
+
+ m_pStorageDeviceValidatedNotify = pStorageDeviceValidated;
+ return false;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Monitor commands for certain necessary cases
+// Input : *command - What menu command we're policing
+//-----------------------------------------------------------------------------
+bool CBasePanel::HandleSignInRequest( const char *command )
+{
+#ifdef _X360
+ // If we have a post-prompt command, we're coming back into the call from that prompt
+ bool bQueuedCall = ( m_strPostPromptCommand.IsEmpty() == false );
+
+ XUSER_SIGNIN_INFO info;
+ bool bValidUser = ( XUserGetSigninInfo( XBX_GetPrimaryUserId(), 0, &info ) == ERROR_SUCCESS );
+
+ if ( bValidUser )
+ return true;
+
+ // Queued command means we're returning from a prompt or blade
+ if ( bQueuedCall )
+ {
+ // Blade has returned with nothing
+ if ( m_bUserRefusedSignIn )
+ return true;
+
+ // User has not denied the storage device, so ask
+ ShowMessageDialog( MD_PROMPT_SIGNIN );
+ m_strPostPromptCommand = command;
+
+ // Do not run command
+ return false;
+ }
+ else
+ {
+ // If the user refused the sign-in and we respect that on this command, we're done
+ if ( m_bUserRefusedSignIn && CommandRespectsSignInDenied( command ) )
+ return true;
+
+ // If the message is required first, then do that instead
+ if ( CommandRequiresSignIn( command ) )
+ {
+ ShowMessageDialog( MD_PROMPT_SIGNIN_REQUIRED );
+ m_strPostPromptCommand = command;
+ return false;
+ }
+
+ // Pop a blade out
+ xboxsystem->ShowSigninUI( 1, 0 );
+ m_strPostPromptCommand = command;
+ m_bWaitingForUserSignIn = true;
+ m_bUserRefusedSignIn = false;
+ return false;
+ }
+#endif // _X360
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+bool CBasePanel::HandleStorageDeviceRequest( const char *command )
+{
+ // If we don't have a valid sign-in, then we do nothing!
+ if ( m_bUserRefusedSignIn )
+ return true;
+
+ // If we have a valid storage device, there's nothing to prompt for
+ if ( XBX_GetStorageDeviceId() != XBX_INVALID_STORAGE_ID && XBX_GetStorageDeviceId() != XBX_STORAGE_DECLINED )
+ return true;
+
+ // If we have a post-prompt command, we're coming back into the call from that prompt
+ bool bQueuedCall = ( m_strPostPromptCommand.IsEmpty() == false );
+
+ // Are we returning from a prompt?
+ if ( bQueuedCall && m_bStorageBladeShown )
+ {
+ // User has declined
+ if ( m_bUserRefusedStorageDevice )
+ return true;
+
+ // Prompt them
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE );
+ m_strPostPromptCommand = command;
+
+ // Do not run the command
+ return false;
+ }
+ else
+ {
+ // If the user refused the sign-in and we respect that on this command, we're done
+ if ( m_bUserRefusedStorageDevice && CommandRespectsSignInDenied( command ) )
+ return true;
+
+#if 0 // This attempts to find user data, but may not be cert-worthy even though it's a bit nicer for the user
+ // Attempt to automatically find a device
+ DWORD nFoundDevice = xboxsystem->DiscoverUserData( XBX_GetPrimaryUserId(), COM_GetModDirectory() );
+ if ( nFoundDevice != XBX_INVALID_STORAGE_ID )
+ {
+ // Take this device
+ XBX_SetStorageDeviceId( nFoundDevice );
+ OnDeviceAttached();
+ return true;
+ }
+#endif //
+
+ // If the message is required first, then do that instead
+ if ( CommandRequiresStorageDevice( command ) )
+ {
+ ShowMessageDialog( MD_PROMPT_STORAGE_DEVICE_REQUIRED );
+ m_strPostPromptCommand = command;
+ return false;
+ }
+
+ // This is a misnomer of the first order!
+ OnChangeStorageDevice();
+ m_strPostPromptCommand = command;
+ m_bStorageBladeShown = true;
+ m_bUserRefusedStorageDevice = false;
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear the command we've queued once it has succeeded in being called
+//-----------------------------------------------------------------------------
+void CBasePanel::ClearPostPromptCommand( const char *pCompletedCommand )
+{
+ if ( !Q_stricmp( m_strPostPromptCommand, pCompletedCommand ) )
+ {
+ // All commands are executed, so stop holding this
+ m_strPostPromptCommand = "";
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Issue our queued command to either the base panel or the matchmaking panel
+//-----------------------------------------------------------------------------
+void CBasePanel::IssuePostPromptCommand( void )
+{
+ // The device is valid, so launch any pending commands
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ if ( m_bSinglePlayer )
+ {
+ OnCommand( m_strPostPromptCommand );
+ }
+ else
+ {
+ CMatchmakingBasePanel *pMatchMaker = GetMatchmakingBasePanel();
+ if ( pMatchMaker )
+ {
+ pMatchMaker->OnCommand( m_strPostPromptCommand );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: message handler for menu selections
+//-----------------------------------------------------------------------------
+void CBasePanel::OnCommand( const char *command )
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+#if defined( _X360 )
+
+ // See if this is a command we need to intercept
+ if ( IsPromptableCommand( command ) )
+ {
+ // Handle the sign in case
+ if ( HandleSignInRequest( command ) == false )
+ return;
+
+ // Handle storage
+ if ( HandleStorageDeviceRequest( command ) == false )
+ return;
+
+ // If we fall through, we'll need to track this again
+ m_bStorageBladeShown = false;
+
+ // Fall through
+ }
+#endif // _X360
+
+ RunAnimationWithCallback( this, command, new KeyValues( "RunMenuCommand", "command", command ) );
+
+ // Clear our pending command if we just executed it
+ ClearPostPromptCommand( command );
+ }
+ else
+ {
+ RunMenuCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an animation sequence, then calls a message mapped function
+// when the animation is complete.
+//-----------------------------------------------------------------------------
+void CBasePanel::RunAnimationWithCallback( vgui::Panel *parent, const char *animName, KeyValues *msgFunc )
+{
+ if ( !m_pConsoleAnimationController )
+ return;
+
+ m_pConsoleAnimationController->StartAnimationSequence( animName );
+ float sequenceLength = m_pConsoleAnimationController->GetAnimationSequenceLength( animName );
+ if ( sequenceLength )
+ {
+ sequenceLength += g_flAnimationPadding;
+ }
+ if ( parent && msgFunc )
+ {
+ PostMessage( parent, msgFunc, sequenceLength );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: trinary choice query "save & quit", "quit", "cancel"
+//-----------------------------------------------------------------------------
+class CSaveBeforeQuitQueryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CSaveBeforeQuitQueryDialog, vgui::Frame );
+public:
+ CSaveBeforeQuitQueryDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+ {
+ LoadControlSettings("resource/SaveBeforeQuitDialog.res");
+ SetDeleteSelfOnClose(true);
+ SetSizeable(false);
+ }
+
+ void DoModal()
+ {
+ BaseClass::Activate();
+ input()->SetAppModalSurface(GetVPanel());
+ MoveToCenterOfScreen();
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+
+ GameUI().PreventEngineHideGameUI();
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // ESC cancels
+ if ( code == KEY_ESCAPE )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ void OnKeyCodePressed(KeyCode code)
+ {
+ // ESC cancels
+ if ( code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B || code == STEAMCONTROLLER_START )
+ {
+ Close();
+ }
+ else if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ OnCommand( "SaveAndQuit" );
+ }
+ else if ( code == KEY_XBUTTON_X || code == STEAMCONTROLLER_X )
+ {
+ OnCommand( "Quit" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+ virtual void OnCommand(const char *command)
+ {
+ if (!Q_stricmp(command, "Quit"))
+ {
+ PostMessage(GetVParent(), new KeyValues("Command", "command", "QuitNoConfirm"));
+ }
+ else if (!Q_stricmp(command, "SaveAndQuit"))
+ {
+ // find a new name to save
+ char saveName[128];
+ CSaveGameDialog::FindSaveSlot( saveName, sizeof(saveName) );
+ if ( saveName[ 0 ] )
+ {
+ // save the game
+ char sz[ 256 ];
+ Q_snprintf(sz, sizeof( sz ), "save %s\n", saveName );
+ engine->ClientCmd_Unrestricted( sz );
+ }
+
+ // quit
+ PostMessage(GetVParent(), new KeyValues("Command", "command", "QuitNoConfirm"));
+ }
+ else if (!Q_stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+ }
+
+ virtual void OnClose()
+ {
+ BaseClass::OnClose();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().AllowEngineHideGameUI();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: simple querybox that accepts escape
+//-----------------------------------------------------------------------------
+class CQuitQueryBox : public vgui::QueryBox
+{
+ DECLARE_CLASS_SIMPLE( CQuitQueryBox, vgui::QueryBox );
+public:
+ CQuitQueryBox(const char *title, const char *info, Panel *parent) : BaseClass( title, info, parent )
+ {
+ }
+
+ void DoModal( Frame* pFrameOver )
+ {
+ BaseClass::DoModal( pFrameOver );
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+ GameUI().PreventEngineHideGameUI();
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // ESC cancels
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ void OnKeyCodePressed(KeyCode code)
+ {
+ // ESC cancels
+ if (code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+ virtual void OnClose()
+ {
+ BaseClass::OnClose();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().AllowEngineHideGameUI();
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: asks user how they feel about quiting
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenQuitConfirmationDialog()
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ // single player, progress will be lost...
+ ShowMessageDialog( MD_SAVE_BEFORE_QUIT );
+ }
+ else
+ {
+ if ( m_bUseMatchmaking )
+ {
+ ShowMessageDialog( MD_QUIT_CONFIRMATION_TF );
+ }
+ else
+ {
+ ShowMessageDialog( MD_QUIT_CONFIRMATION );
+ }
+ }
+ return;
+ }
+
+
+ if ( GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ // prompt for saving current game before quiting
+ CSaveBeforeQuitQueryDialog *box = new CSaveBeforeQuitQueryDialog(this, "SaveBeforeQuitQueryDialog");
+ box->DoModal();
+ }
+ else
+ {
+ // simple ok/cancel prompt
+ QueryBox *box = new CQuitQueryBox("#GameUI_QuitConfirmationTitle", "#GameUI_QuitConfirmationText", this);
+ box->SetOKButtonText("#GameUI_Quit");
+ box->SetOKCommand(new KeyValues("Command", "command", "QuitNoConfirm"));
+ box->SetCancelCommand(new KeyValues("Command", "command", "ReleaseModalWindow"));
+ box->AddActionSignalTarget(this);
+ box->DoModal();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: asks user how they feel about disconnecting
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenDisconnectConfirmationDialog()
+{
+ // THis is for disconnecting from a multiplayer server
+ Assert( m_bUseMatchmaking );
+ Assert( IsX360() );
+
+ if ( GameUI().IsConsoleUI() && GameUI().IsInLevel() )
+ {
+ if ( engine->GetLocalPlayer() == 1 )
+ {
+ ShowMessageDialog( MD_DISCONNECT_CONFIRMATION_HOST );
+ }
+ else
+ {
+ ShowMessageDialog( MD_DISCONNECT_CONFIRMATION );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenNewGameDialog(const char *chapter )
+{
+ if ( !m_hNewGameDialog.Get() )
+ {
+ m_hNewGameDialog = new CNewGameDialog(this, false);
+ PositionDialog( m_hNewGameDialog );
+ }
+
+ if ( chapter )
+ {
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetSelectedChapter(chapter);
+ }
+
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetCommentaryMode( false );
+ m_hNewGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenBonusMapsDialog( void )
+{
+ if ( !m_hBonusMapsDialog.Get() )
+ {
+ m_hBonusMapsDialog = new CBonusMapsDialog(this);
+ PositionDialog( m_hBonusMapsDialog );
+ }
+
+ m_hBonusMapsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadGameDialog()
+{
+ if ( !m_hLoadGameDialog.Get() )
+ {
+ m_hLoadGameDialog = new CLoadGameDialog(this);
+ PositionDialog( m_hLoadGameDialog );
+ }
+ m_hLoadGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadGameDialog_Xbox()
+{
+ if ( !m_hLoadGameDialog_Xbox.Get() )
+ {
+ m_hLoadGameDialog_Xbox = new CLoadGameDialogXbox(this);
+ PositionDialog( m_hLoadGameDialog_Xbox );
+ }
+ m_hLoadGameDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenSaveGameDialog()
+{
+ if ( !m_hSaveGameDialog.Get() )
+ {
+ m_hSaveGameDialog = new CSaveGameDialog(this);
+ PositionDialog( m_hSaveGameDialog );
+ }
+ m_hSaveGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenSaveGameDialog_Xbox()
+{
+ if ( !m_hSaveGameDialog_Xbox.Get() )
+ {
+ m_hSaveGameDialog_Xbox = new CSaveGameDialogXbox(this);
+ PositionDialog( m_hSaveGameDialog_Xbox );
+ }
+ m_hSaveGameDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenOptionsDialog()
+{
+ if ( !m_hOptionsDialog.Get() )
+ {
+ m_hOptionsDialog = new COptionsDialog(this);
+ g_hOptionsDialog = m_hOptionsDialog;
+ PositionDialog( m_hOptionsDialog );
+ }
+
+ m_hOptionsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenOptionsDialog_Xbox()
+{
+ if ( !m_hOptionsDialog_Xbox.Get() )
+ {
+ m_hOptionsDialog_Xbox = new COptionsDialogXbox( this );
+ PositionDialog( m_hOptionsDialog_Xbox );
+ }
+
+ m_hOptionsDialog_Xbox->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: forces any changed options dialog settings to be applied immediately, if it's open
+//-----------------------------------------------------------------------------
+void CBasePanel::ApplyOptionsDialogSettings()
+{
+ if (m_hOptionsDialog.Get())
+ {
+ m_hOptionsDialog->ApplyChanges();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenControllerDialog()
+{
+ if ( !m_hControllerDialog.Get() )
+ {
+ m_hControllerDialog = new CControllerDialog( this );
+ PositionDialog( m_hControllerDialog );
+ }
+
+ m_hControllerDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenBenchmarkDialog()
+{
+ if (!m_hBenchmarkDialog.Get())
+ {
+ m_hBenchmarkDialog = new CBenchmarkDialog(this, "BenchmarkDialog");
+ PositionDialog( m_hBenchmarkDialog );
+ }
+ m_hBenchmarkDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenServerBrowser()
+{
+ g_VModuleLoader.ActivateModule("Servers");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenFriendsDialog()
+{
+ g_VModuleLoader.ActivateModule("Friends");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenDemoDialog()
+{
+/* if ( !m_hDemoPlayerDialog.Get() )
+ {
+ m_hDemoPlayerDialog = new CDemoPlayerDialog(this);
+ PositionDialog( m_hDemoPlayerDialog );
+ }
+ m_hDemoPlayerDialog->Activate();*/
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenCreateMultiplayerGameDialog()
+{
+ if (!m_hCreateMultiplayerGameDialog.Get())
+ {
+ m_hCreateMultiplayerGameDialog = new CCreateMultiplayerGameDialog(this);
+ PositionDialog(m_hCreateMultiplayerGameDialog);
+ }
+ m_hCreateMultiplayerGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenChangeGameDialog()
+{
+#ifdef POSIX
+ // Alfred says this is old legacy code that allowed you to walk through looking for
+ // gameinfos and switch and it's not needed anymore. So I'm killing this assert...
+#else
+ if (!m_hChangeGameDialog.Get())
+ {
+ m_hChangeGameDialog = new CChangeGameDialog(this);
+ PositionDialog(m_hChangeGameDialog);
+ }
+ m_hChangeGameDialog->Activate();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenPlayerListDialog()
+{
+ if (!m_hPlayerListDialog.Get())
+ {
+ m_hPlayerListDialog = new CPlayerListDialog(this);
+ PositionDialog(m_hPlayerListDialog);
+ }
+ m_hPlayerListDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenLoadCommentaryDialog()
+{
+ if (!m_hPlayerListDialog.Get())
+ {
+ m_hLoadCommentaryDialog = new CLoadCommentaryDialog(this);
+ PositionDialog(m_hLoadCommentaryDialog);
+ }
+ m_hLoadCommentaryDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OpenLoadSingleplayerCommentaryDialog()
+{
+ if ( !m_hNewGameDialog.Get() )
+ {
+ m_hNewGameDialog = new CNewGameDialog(this,true);
+ PositionDialog( m_hNewGameDialog );
+ }
+
+ ((CNewGameDialog *)m_hNewGameDialog.Get())->SetCommentaryMode( true );
+ m_hNewGameDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenAchievementsDialog()
+{
+ if (!m_hAchievementsDialog.Get())
+ {
+ m_hAchievementsDialog = new CAchievementsDialog( this );
+ PositionDialog(m_hAchievementsDialog);
+ }
+ m_hAchievementsDialog->Activate();
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [dwenger] Use cs-specific achievements dialog
+//=============================================================================
+
+void CBasePanel::OnOpenCSAchievementsDialog()
+{
+ if ( GameClientExports() )
+ {
+ int screenWide = 0;
+ int screenHeight = 0;
+ engine->GetScreenSize( screenWide, screenHeight );
+
+ // [smessick] For lower resolutions, open the Steam achievements instead of the CSS achievements screen.
+ if ( screenWide < GameClientExports()->GetAchievementsPanelMinWidth() )
+ {
+ ISteamFriends *friends = steamapicontext->SteamFriends();
+ if ( friends )
+ {
+ friends->ActivateGameOverlay( "Achievements" );
+ }
+ }
+ else
+ {
+ // Display the CSS achievements screen.
+ GameClientExports()->CreateAchievementsPanel( this );
+ GameClientExports()->DisplayAchievementPanel();
+ }
+ }
+}
+
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+void CBasePanel::OnOpenAchievementsDialog_Xbox()
+{
+ if (!m_hAchievementsDialog.Get())
+ {
+ m_hAchievementsDialog = new CAchievementsDialog_XBox( this );
+ PositionDialog(m_hAchievementsDialog);
+ }
+ m_hAchievementsDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnOpenMatchmakingBasePanel()
+{
+ if (!m_hMatchmakingBasePanel.Get())
+ {
+ m_hMatchmakingBasePanel = new CMatchmakingBasePanel( this );
+ int x, y, wide, tall;
+ GetBounds( x, y, wide, tall );
+ m_hMatchmakingBasePanel->SetBounds( x, y, wide, tall );
+ }
+
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetVisible( false );
+ }
+
+ // Hide the standard game menu
+ for ( int i = 0; i < m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetVisible( false );
+ }
+
+ // Hide the BasePanel's button footer
+ m_pGameMenu->ShowFooter( false );
+
+ m_hMatchmakingBasePanel->SetVisible( true );
+
+ m_hMatchmakingBasePanel->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper function for this common operation
+//-----------------------------------------------------------------------------
+CMatchmakingBasePanel *CBasePanel::GetMatchmakingBasePanel()
+{
+ CMatchmakingBasePanel *pBase = NULL;
+ if ( m_bUseMatchmaking )
+ {
+ pBase = dynamic_cast< CMatchmakingBasePanel* >( m_hMatchmakingBasePanel.Get() );
+ }
+ return pBase;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: moves the game menu button to the right place on the taskbar
+//-----------------------------------------------------------------------------
+void CBasePanel::PositionDialog(vgui::PHandle dlg)
+{
+ if (!dlg.Get())
+ return;
+
+ int x, y, ww, wt, wide, tall;
+ vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
+ dlg->GetSize(wide, tall);
+
+ // Center it, keeping requested size
+ dlg->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add an Xbox 360 message dialog to a dialog stack
+//-----------------------------------------------------------------------------
+void CBasePanel::ShowMessageDialog( const uint nType, vgui::Panel *pOwner )
+{
+ if ( pOwner == NULL )
+ {
+ pOwner = this;
+ }
+
+ m_MessageDialogHandler.ShowMessageDialog( nType, pOwner );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add an Xbox 360 message dialog to a dialog stack
+//-----------------------------------------------------------------------------
+void CBasePanel::CloseMessageDialog( const uint nType )
+{
+ m_MessageDialogHandler.CloseMessageDialog( nType );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification from engine
+//-----------------------------------------------------------------------------
+void CBasePanel::SessionNotification( const int notification, const int param )
+{
+ // This is a job for the matchmaking panel
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SessionNotification( notification, param );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: System notification from engine
+//-----------------------------------------------------------------------------
+void CBasePanel::SystemNotification( const int notification )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SystemNotification( notification );
+ }
+
+ if ( notification == SYSTEMNOTIFY_USER_SIGNEDIN )
+ {
+#if defined( _X360 )
+ // See if it was the active user who signed in
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state != eXUserSigninState_NotSignedIn )
+ {
+ // Reset a bunch of state
+ m_bUserRefusedSignIn = false;
+ m_bUserRefusedStorageDevice = false;
+ m_bStorageBladeShown = false;
+ }
+ UpdateRichPresenceInfo();
+ engine->GetAchievementMgr()->DownloadUserData();
+ engine->GetAchievementMgr()->EnsureGlobalStateLoaded();
+#endif
+ }
+ else if ( notification == SYSTEMNOTIFY_USER_SIGNEDOUT )
+ {
+#if defined( _X360 )
+ // See if it was the active user who signed out
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state != eXUserSigninState_NotSignedIn )
+ {
+ return;
+ }
+
+ // Invalidate their storage ID
+ engine->OnStorageDeviceDetached();
+ m_bUserRefusedStorageDevice = false;
+ m_bUserRefusedSignIn = false;
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ engine->GetAchievementMgr()->InitializeAchievements();
+ m_MessageDialogHandler.CloseAllMessageDialogs();
+
+#endif
+ if ( GameUI().IsInLevel() )
+ {
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetVisible( false );
+ }
+
+ // Hide the standard game menu
+ for ( int i = 0; i < m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetVisible( false );
+ }
+
+ // Hide the BasePanel's button footer
+ m_pGameMenu->ShowFooter( false );
+
+ QueueCommand( "QuitNoConfirm" );
+ }
+ else
+ {
+ CloseBaseDialogs();
+ }
+
+ OnCommand( "OpenMainMenu" );
+ }
+ else if ( notification == SYSTEMNOTIFY_STORAGEDEVICES_CHANGED )
+ {
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ m_hSaveGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ m_hLoadGameDialog_Xbox->OnCommand( "RefreshSaveGames" );
+
+ // FIXME: This code is incorrect, they do NOT need a storage device, it is only recommended that they do
+ if ( GameUI().IsInLevel() )
+ {
+ // They wanted to use a storage device and are already playing!
+ // They need a storage device now or we're quitting the game!
+ m_bNeedStorageDeviceHandle = true;
+ ShowMessageDialog( MD_STORAGE_DEVICES_NEEDED, this );
+ }
+ else
+ {
+ ShowMessageDialog( MD_STORAGE_DEVICES_CHANGED, this );
+ }
+ }
+ else if ( notification == SYSTEMNOTIFY_XUIOPENING )
+ {
+ m_bXUIVisible = true;
+ }
+ else if ( notification == SYSTEMNOTIFY_XUICLOSED )
+ {
+ m_bXUIVisible = false;
+
+ if ( m_bWaitingForStorageDeviceHandle )
+ {
+ DWORD ret = xboxsystem->GetOverlappedResult( m_hStorageDeviceChangeHandle, NULL, true );
+ if ( ret != ERROR_IO_INCOMPLETE )
+ {
+ // Done waiting
+ xboxsystem->ReleaseAsyncHandle( m_hStorageDeviceChangeHandle );
+
+ m_bWaitingForStorageDeviceHandle = false;
+
+ // If we selected something, validate it
+ if ( m_iStorageID != XBX_INVALID_STORAGE_ID )
+ {
+ // Check to see if there is enough room on this storage device
+ if ( xboxsystem->DeviceCapacityAdequate( m_iStorageID, COM_GetModDirectory() ) == false )
+ {
+ ShowMessageDialog( MD_STORAGE_DEVICES_TOO_FULL, this );
+ m_bStorageBladeShown = false; // Show the blade again next time
+ m_strPostPromptCommand = ""; // Clear the buffer, we can't return
+ }
+ else
+ {
+ m_bNeedStorageDeviceHandle = false;
+
+ // Set the storage device
+ XBX_SetStorageDeviceId( m_iStorageID );
+ OnDeviceAttached();
+ }
+ }
+ else
+ {
+ if ( m_pStorageDeviceValidatedNotify )
+ {
+ *m_pStorageDeviceValidatedNotify = 2;
+ m_pStorageDeviceValidatedNotify = NULL;
+ }
+ else if ( m_bNeedStorageDeviceHandle )
+ {
+ // They didn't select a storage device!
+ // Remind them that they must pick one or the game will shut down
+ ShowMessageDialog( MD_STORAGE_DEVICES_NEEDED, this );
+ }
+ else
+ {
+ // Start off the command we queued up
+ IssuePostPromptCommand();
+ }
+ }
+ }
+ }
+
+ // If we're waiting for the user to sign in, and check if they selected a usable profile
+ if ( m_bWaitingForUserSignIn )
+ {
+ // Done waiting
+ m_bWaitingForUserSignIn = false;
+ m_bUserRefusedSignIn = false;
+
+ // The UI has closed, so go off and revalidate the state
+ if ( m_strPostPromptCommand.IsEmpty() == false )
+ {
+ // Run the command again
+ OnCommand( m_strPostPromptCommand );
+ }
+ }
+
+ RunQueuedCommands();
+ }
+ else if ( notification == SYSTEMNOTIFY_INVITE_SHUTDOWN )
+ {
+ // Quit the current game without confirmation
+ m_bRestartFromInvite = true;
+ m_bXUIVisible = true;
+ OnCommand( "QuitNoConfirm" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification that a player's info has changed
+//-----------------------------------------------------------------------------
+void CBasePanel::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->UpdatePlayerInfo( nPlayerId, pName, nTeam, cVoiceState, nPlayersNeeded, bHost );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Matchmaking notification to add a session to the browser
+//-----------------------------------------------------------------------------
+void CBasePanel::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping )
+{
+ CMatchmakingBasePanel *pBase = GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->SessionSearchResult( searchIdx, pHostData, pResult, ping );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnChangeStorageDevice( void )
+{
+ if ( m_bWaitingForStorageDeviceHandle == false )
+ {
+ m_bWaitingForStorageDeviceHandle = true;
+ m_hStorageDeviceChangeHandle = xboxsystem->CreateAsyncHandle();
+ m_iStorageID = XBX_INVALID_STORAGE_ID;
+ xboxsystem->ShowDeviceSelector( true, &m_iStorageID, &m_hStorageDeviceChangeHandle );
+ }
+}
+
+void CBasePanel::OnCreditsFinished( void )
+{
+ if ( !IsX360() )
+ {
+ // valid for 360 only
+ Assert( 0 );
+ return;
+ }
+
+ bool bExitToAppChooser = false;
+ if ( bExitToAppChooser )
+ {
+ // unknown state from engine, force to a compliant exiting state
+ // causes an complete exit out of the game back to the app launcher
+ SetVisible( true );
+ m_pGameMenu->SetAlpha( 0 );
+ StartExitingProcess();
+ }
+ else
+ {
+ // expecting to transition from the credits back to the background map
+ // prevent any possibility of using the last transition image
+ m_bUseRenderTargetImage = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::OnGameUIHidden()
+{
+ if ( m_hOptionsDialog.Get() )
+ {
+ PostMessage( m_hOptionsDialog.Get(), new KeyValues( "GameUIHidden" ) );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the alpha of the menu panels
+//-----------------------------------------------------------------------------
+void CBasePanel::SetMenuAlpha(int alpha)
+{
+ if ( GameUI().IsConsoleUI() )
+ {
+ // handled by animation, not code
+ return;
+ }
+
+ m_pGameMenu->SetAlpha(alpha);
+
+ if ( m_pGameLogo )
+ {
+ m_pGameLogo->SetAlpha( alpha );
+ }
+
+ for ( int i=0; i<m_pGameMenuButtons.Count(); ++i )
+ {
+ m_pGameMenuButtons[i]->SetAlpha(alpha);
+ }
+ m_bForceTitleTextUpdate = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CBasePanel::GetMenuAlpha( void )
+{
+ return m_pGameMenu->GetAlpha();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::SetMainMenuOverride( vgui::VPANEL panel )
+{
+ m_hMainMenuOverridePanel = panel;
+
+ if ( m_pGameMenu )
+ {
+ m_pGameMenu->SetMainMenuOverride( panel );
+ }
+
+ if ( m_hMainMenuOverridePanel )
+ {
+ // Parent it to this panel
+ ipanel()->SetParent( m_hMainMenuOverridePanel, GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: starts the game
+//-----------------------------------------------------------------------------
+void CBasePanel::FadeToBlackAndRunEngineCommand( const char *engineCommand )
+{
+ KeyValues *pKV = new KeyValues( "RunEngineCommand", "command", engineCommand );
+
+ // execute immediately, with no delay
+ PostMessage( this, pKV, 0 );
+}
+
+void CBasePanel::SetMenuItemBlinkingState( const char *itemName, bool state )
+{
+ for (int i = 0; i < GetChildCount(); i++)
+ {
+ Panel *child = GetChild(i);
+ CGameMenu *pGameMenu = dynamic_cast<CGameMenu *>(child);
+ if ( pGameMenu )
+ {
+ pGameMenu->SetMenuItemBlinkingState( itemName, state );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an engine command, used for delays
+//-----------------------------------------------------------------------------
+void CBasePanel::RunEngineCommand(const char *command)
+{
+ engine->ClientCmd_Unrestricted(command);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs an animation to close a dialog and cleans up after close
+//-----------------------------------------------------------------------------
+void CBasePanel::RunCloseAnimation( const char *animName )
+{
+ RunAnimationWithCallback( this, animName, new KeyValues( "FinishDialogClose" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: cleans up after a menu closes
+//-----------------------------------------------------------------------------
+void CBasePanel::FinishDialogClose( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: xbox UI panel that displays button icons and help text for all menus
+//-----------------------------------------------------------------------------
+CFooterPanel::CFooterPanel( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
+{
+ SetVisible( true );
+ SetAlpha( 0 );
+ m_pHelpName = NULL;
+
+ m_pSizingLabel = new vgui::Label( this, "SizingLabel", "" );
+ m_pSizingLabel->SetVisible( false );
+
+ m_nButtonGap = 32;
+ m_nButtonGapDefault = 32;
+ m_ButtonPinRight = 100;
+ m_FooterTall = 80;
+
+ int wide, tall;
+ surface()->GetScreenSize(wide, tall);
+
+ if ( tall <= 480 )
+ {
+ m_FooterTall = 60;
+ }
+
+ m_ButtonOffsetFromTop = 0;
+ m_ButtonSeparator = 4;
+ m_TextAdjust = 0;
+
+ m_bPaintBackground = false;
+ m_bCenterHorizontal = false;
+
+ m_szButtonFont[0] = '\0';
+ m_szTextFont[0] = '\0';
+ m_szFGColor[0] = '\0';
+ m_szBGColor[0] = '\0';
+}
+
+CFooterPanel::~CFooterPanel()
+{
+ SetHelpNameAndReset( NULL );
+
+ delete m_pSizingLabel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: apply scheme settings
+//-----------------------------------------------------------------------------
+void CFooterPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_hButtonFont = pScheme->GetFont( ( m_szButtonFont[0] != '\0' ) ? m_szButtonFont : "GameUIButtons" );
+ m_hTextFont = pScheme->GetFont( ( m_szTextFont[0] != '\0' ) ? m_szTextFont : "MenuLarge" );
+
+ SetFgColor( pScheme->GetColor( m_szFGColor, Color( 255, 255, 255, 255 ) ) );
+ SetBgColor( pScheme->GetColor( m_szBGColor, Color( 0, 0, 0, 255 ) ) );
+
+ int x, y, w, h;
+ GetParent()->GetBounds( x, y, w, h );
+ SetBounds( x, h - m_FooterTall, w, m_FooterTall );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: apply settings
+//-----------------------------------------------------------------------------
+void CFooterPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ // gap between hints
+ m_nButtonGap = inResourceData->GetInt( "buttongap", 32 );
+ m_nButtonGapDefault = m_nButtonGap;
+ m_ButtonPinRight = inResourceData->GetInt( "button_pin_right", 100 );
+ m_FooterTall = inResourceData->GetInt( "tall", 80 );
+ m_ButtonOffsetFromTop = inResourceData->GetInt( "buttonoffsety", 0 );
+ m_ButtonSeparator = inResourceData->GetInt( "button_separator", 4 );
+ m_TextAdjust = inResourceData->GetInt( "textadjust", 0 );
+
+ m_bCenterHorizontal = ( inResourceData->GetInt( "center", 0 ) == 1 );
+ m_bPaintBackground = ( inResourceData->GetInt( "paintbackground", 0 ) == 1 );
+
+ // fonts for text and button
+ Q_strncpy( m_szTextFont, inResourceData->GetString( "fonttext", "MenuLarge" ), sizeof( m_szTextFont ) );
+ Q_strncpy( m_szButtonFont, inResourceData->GetString( "fontbutton", "GameUIButtons" ), sizeof( m_szButtonFont ) );
+
+ // fg and bg colors
+ Q_strncpy( m_szFGColor, inResourceData->GetString( "fgcolor", "White" ), sizeof( m_szFGColor ) );
+ Q_strncpy( m_szBGColor, inResourceData->GetString( "bgcolor", "Black" ), sizeof( m_szBGColor ) );
+
+ for ( KeyValues *pButton = inResourceData->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() )
+ {
+ const char *pName = pButton->GetName();
+
+ if ( !Q_stricmp( pName, "button" ) )
+ {
+ // Add a button to the footer
+ const char *pText = pButton->GetString( "text", "NULL" );
+ const char *pIcon = pButton->GetString( "icon", "NULL" );
+ AddNewButtonLabel( pText, pIcon );
+ }
+ }
+
+ InvalidateLayout( false, true ); // force ApplySchemeSettings to run
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds button icons and help text to the footer panel when activating a menu
+//-----------------------------------------------------------------------------
+void CFooterPanel::AddButtonsFromMap( vgui::Frame *pMenu )
+{
+ SetHelpNameAndReset( pMenu->GetName() );
+
+ CControllerMap *pMap = dynamic_cast<CControllerMap*>( pMenu->FindChildByName( "ControllerMap" ) );
+ if ( pMap )
+ {
+ int buttonCt = pMap->NumButtons();
+ for ( int i = 0; i < buttonCt; ++i )
+ {
+ const char *pText = pMap->GetBindingText( i );
+ if ( pText )
+ {
+ AddNewButtonLabel( pText, pMap->GetBindingIcon( i ) );
+ }
+ }
+ }
+}
+
+void CFooterPanel::SetStandardDialogButtons()
+{
+ SetHelpNameAndReset( "Dialog" );
+ AddNewButtonLabel( "#GameUI_Action", "#GameUI_Icons_A_BUTTON" );
+ AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Caller must tag the button layout. May support reserved names
+// to provide stock help layouts trivially.
+//-----------------------------------------------------------------------------
+void CFooterPanel::SetHelpNameAndReset( const char *pName )
+{
+ if ( m_pHelpName )
+ {
+ free( m_pHelpName );
+ m_pHelpName = NULL;
+ }
+
+ if ( pName )
+ {
+ m_pHelpName = strdup( pName );
+ }
+
+ ClearButtons();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Caller must tag the button layout
+//-----------------------------------------------------------------------------
+const char *CFooterPanel::GetHelpName()
+{
+ return m_pHelpName;
+}
+
+void CFooterPanel::ClearButtons( void )
+{
+ m_ButtonLabels.PurgeAndDeleteElements();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: creates a new button label with icon and text
+//-----------------------------------------------------------------------------
+void CFooterPanel::AddNewButtonLabel( const char *text, const char *icon )
+{
+ ButtonLabel_t *button = new ButtonLabel_t;
+
+ Q_strncpy( button->name, text, MAX_PATH );
+ button->bVisible = true;
+
+ // Button icons are a single character
+ wchar_t *pIcon = g_pVGuiLocalize->Find( icon );
+ if ( pIcon )
+ {
+ button->icon[0] = pIcon[0];
+ button->icon[1] = '\0';
+ }
+ else
+ {
+ button->icon[0] = '\0';
+ }
+
+ // Set the help text
+ wchar_t *pText = g_pVGuiLocalize->Find( text );
+ if ( pText )
+ {
+ wcsncpy( button->text, pText, wcslen( pText ) + 1 );
+ }
+ else
+ {
+ button->text[0] = '\0';
+ }
+
+ m_ButtonLabels.AddToTail( button );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shows/Hides a button label
+//-----------------------------------------------------------------------------
+void CFooterPanel::ShowButtonLabel( const char *name, bool show )
+{
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ if ( !Q_stricmp( m_ButtonLabels[ i ]->name, name ) )
+ {
+ m_ButtonLabels[ i ]->bVisible = show;
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Changes a button's text
+//-----------------------------------------------------------------------------
+void CFooterPanel::SetButtonText( const char *buttonName, const char *text )
+{
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ if ( !Q_stricmp( m_ButtonLabels[ i ]->name, buttonName ) )
+ {
+ wchar_t *wtext = g_pVGuiLocalize->Find( text );
+ if ( text )
+ {
+ wcsncpy( m_ButtonLabels[ i ]->text, wtext, wcslen( wtext ) + 1 );
+ }
+ else
+ {
+ m_ButtonLabels[ i ]->text[ 0 ] = '\0';
+ }
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Footer panel background rendering
+//-----------------------------------------------------------------------------
+void CFooterPanel::PaintBackground( void )
+{
+ if ( !m_bPaintBackground )
+ return;
+
+ BaseClass::PaintBackground();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Footer panel rendering
+//-----------------------------------------------------------------------------
+void CFooterPanel::Paint( void )
+{
+ // inset from right edge
+ int wide = GetWide();
+ int right = wide - m_ButtonPinRight;
+
+ // center the text within the button
+ int buttonHeight = vgui::surface()->GetFontTall( m_hButtonFont );
+ int fontHeight = vgui::surface()->GetFontTall( m_hTextFont );
+ int textY = ( buttonHeight - fontHeight )/2 + m_TextAdjust;
+
+ if ( textY < 0 )
+ {
+ textY = 0;
+ }
+
+ int y = m_ButtonOffsetFromTop;
+
+ if ( !m_bCenterHorizontal )
+ {
+ // draw the buttons, right to left
+ int x = right;
+
+ for ( int i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ int iTextWidth = m_pSizingLabel->GetWide();
+
+ if ( iTextWidth == 0 )
+ x += m_nButtonGap; // There's no text, so remove the gap between buttons
+ else
+ x -= iTextWidth;
+
+ // Draw the string
+ vgui::surface()->DrawSetTextFont( m_hTextFont );
+ vgui::surface()->DrawSetTextColor( GetFgColor() );
+ vgui::surface()->DrawSetTextPos( x, y + textY );
+ vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
+
+ // Draw the button
+ // back up button width and a little extra to leave a gap between button and text
+ x -= ( vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator );
+ vgui::surface()->DrawSetTextFont( m_hButtonFont );
+ vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( pButton->icon, 1 );
+
+ // back up to next string
+ x -= m_nButtonGap;
+ }
+ }
+ else
+ {
+ // center the buttons (as a group)
+ int x = wide / 2;
+ int totalWidth = 0;
+ int i = 0;
+ int nButtonCount = 0;
+
+ // need to loop through and figure out how wide our buttons and text are (with gaps between) so we can offset from the center
+ for ( i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ totalWidth += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] );
+ totalWidth += m_ButtonSeparator;
+ totalWidth += m_pSizingLabel->GetWide();
+
+ nButtonCount++; // keep track of how many active buttons we'll be drawing
+ }
+
+ totalWidth += ( nButtonCount - 1 ) * m_nButtonGap; // add in the gaps between the buttons
+ x -= ( totalWidth / 2 );
+
+ for ( i = 0; i < m_ButtonLabels.Count(); ++i )
+ {
+ ButtonLabel_t *pButton = m_ButtonLabels[i];
+ if ( !pButton->bVisible )
+ continue;
+
+ // Get the string length
+ m_pSizingLabel->SetFont( m_hTextFont );
+ m_pSizingLabel->SetText( pButton->text );
+ m_pSizingLabel->SizeToContents();
+
+ int iTextWidth = m_pSizingLabel->GetWide();
+
+ // Draw the icon
+ vgui::surface()->DrawSetTextFont( m_hButtonFont );
+ vgui::surface()->DrawSetTextColor( 255, 255, 255, 255 );
+ vgui::surface()->DrawSetTextPos( x, y );
+ vgui::surface()->DrawPrintText( pButton->icon, 1 );
+ x += vgui::surface()->GetCharacterWidth( m_hButtonFont, pButton->icon[0] ) + m_ButtonSeparator;
+
+ // Draw the string
+ vgui::surface()->DrawSetTextFont( m_hTextFont );
+ vgui::surface()->DrawSetTextColor( GetFgColor() );
+ vgui::surface()->DrawSetTextPos( x, y + textY );
+ vgui::surface()->DrawPrintText( pButton->text, wcslen( pButton->text ) );
+
+ x += iTextWidth + m_nButtonGap;
+ }
+ }
+}
+
+DECLARE_BUILD_FACTORY( CFooterPanel );
+
+#ifdef _X360
+//-----------------------------------------------------------------------------
+// Purpose: Reload the resource files on the Xbox 360
+//-----------------------------------------------------------------------------
+void CBasePanel::Reload_Resources( const CCommand &args )
+{
+ m_pConsoleControlSettings->Clear();
+ if ( m_pConsoleControlSettings->LoadFromFile( g_pFullFileSystem, "resource/UI/XboxDialogs.res" ) )
+ {
+ m_pConsoleControlSettings->ProcessResolutionKeys( surface()->GetResolutionKey() );
+ }
+}
+#endif
+
+
+// X360TBD: Move into a separate module when completed
+CMessageDialogHandler::CMessageDialogHandler()
+{
+ m_iDialogStackTop = -1;
+}
+void CMessageDialogHandler::ShowMessageDialog( int nType, vgui::Panel *pOwner )
+{
+ int iSimpleFrame = 0;
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ iSimpleFrame = MD_SIMPLEFRAME;
+ }
+
+ switch( nType )
+ {
+ case MD_SEARCHING_FOR_GAMES:
+ CreateMessageDialog( MD_CANCEL|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_SearchingForGames",
+ NULL,
+ "CancelOperation",
+ pOwner,
+ true );
+ break;
+
+ case MD_CREATING_GAME:
+ CreateMessageDialog( MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_CreatingGame",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SESSION_SEARCH_FAILED:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_NoGamesFound",
+ "ShowSessionOptionsDialog",
+ "ReturnToMainMenu",
+ pOwner );
+ break;
+
+ case MD_SESSION_CREATE_FAILED:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_CreateFailed",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECTING:
+ CreateMessageDialog( 0,
+ NULL,
+ "#TF_Dlg_Connecting",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SESSION_CONNECT_NOTAVAILABLE:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_JoinRefused",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECT_SESSIONFULL:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_GameFull",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SESSION_CONNECT_FAILED:
+ CreateMessageDialog( MD_OK,
+ NULL,
+ "#TF_Dlg_JoinFailed",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOST_HOST:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_LostHost",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOST_SERVER:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_LostServer",
+ "ReturnToMainMenu",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_MODIFYING_SESSION:
+ CreateMessageDialog( MD_RESTRICTPAINT,
+ NULL,
+ "#TF_Dlg_ModifyingSession",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ case MD_SAVE_BEFORE_QUIT:
+ CreateMessageDialog( MD_YESNO|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_Console_QuitWarning",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMainMenu",
+ pOwner );
+ break;
+
+ case MD_QUIT_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_QuitConfirmationText",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMainMenu",
+ pOwner );
+ break;
+
+ case MD_QUIT_CONFIRMATION_TF:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "#GameUI_QuitConfirmationTitle",
+ "#GameUI_QuitConfirmationText",
+ "QuitNoConfirm",
+ "CloseQuitDialog_OpenMatchmakingMenu",
+ pOwner );
+ break;
+
+ case MD_DISCONNECT_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "",
+ "#GameUI_DisconnectConfirmationText",
+ "DisconnectNoConfirm",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_DISCONNECT_CONFIRMATION_HOST:
+ CreateMessageDialog( MD_YESNO|MD_RESTRICTPAINT,
+ "",
+ "#GameUI_DisconnectHostConfirmationText",
+ "DisconnectNoConfirm",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_KICK_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO,
+ "",
+ "#TF_Dlg_ConfirmKick",
+ "KickPlayer",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_CLIENT_KICKED:
+ CreateMessageDialog( MD_OK|MD_RESTRICTPAINT,
+ "",
+ "#TF_Dlg_ClientKicked",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_EXIT_SESSION_CONFIRMATION:
+ CreateMessageDialog( MD_YESNO,
+ "",
+ "#TF_Dlg_ExitSessionText",
+ "ReturnToMainMenu",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_NEEDED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageRemovedTitle",
+ "#GameUI_Console_StorageNeededBody",
+ "ShowDeviceSelector",
+ "QuitNoConfirm",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_CHANGED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageRemovedTitle",
+ "#GameUI_Console_StorageRemovedBody",
+ "ShowDeviceSelector",
+ "clear_storage_deviceID",
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_TOO_FULL:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_StorageTooFullTitle",
+ "#GameUI_Console_StorageTooFullBody",
+ "ShowDeviceSelector",
+ "StorageDeviceDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_STORAGE_DEVICE:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_Console_NoStorageDeviceSelectedTitle",
+ "#GameUI_Console_NoStorageDeviceSelectedBody",
+ "ShowDeviceSelector",
+ "StorageDeviceDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_STORAGE_DEVICE_REQUIRED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|MD_SIMPLEFRAME,
+ "#GameUI_Console_NoStorageDeviceSelectedTitle",
+ "#GameUI_Console_StorageDeviceRequiredBody",
+ "ShowDeviceSelector",
+ "RequiredStorageDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_SIGNIN:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame,
+ "#GameUI_Console_NoUserProfileSelectedTitle",
+ "#GameUI_Console_NoUserProfileSelectedBody",
+ "ShowSignInUI",
+ "SignInDenied",
+ pOwner );
+ break;
+
+ case MD_PROMPT_SIGNIN_REQUIRED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_COMMANDAFTERCLOSE|iSimpleFrame,
+ "#GameUI_Console_NoUserProfileSelectedTitle",
+ "#GameUI_Console_UserProfileRequiredBody",
+ "ShowSignInUI",
+ "RequiredSignInDenied",
+ pOwner );
+ break;
+
+ case MD_NOT_ONLINE_ENABLED:
+ CreateMessageDialog( MD_YESNO|MD_WARNING,
+ "",
+ "#TF_Dlg_NotOnlineEnabled",
+ "ShowSigninUI",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_NOT_ONLINE_SIGNEDIN:
+ CreateMessageDialog( MD_YESNO|MD_WARNING,
+ "",
+ "#TF_Dlg_NotOnlineSignedIn",
+ "ShowSigninUI",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_DEFAULT_CONTROLS_CONFIRM:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_RestoreDefaults",
+ "#GameUI_ControllerSettingsText",
+ "DefaultControls",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_AUTOSAVE_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmNewGame_Title",
+ "#GameUI_AutoSave_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_CommentaryDialogTitle",
+ "#GAMEUI_Commentary_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_EXPLANATION_MULTI:
+ CreateMessageDialog( MD_OK|MD_WARNING,
+ "#GameUI_CommentaryDialogTitle",
+ "#GAMEUI_Commentary_Console_Explanation",
+ "StartNewGameNoCommentaryExplanation",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION:
+ CreateMessageDialog( MD_OK|MD_WARNING|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_CommentaryDialogTitle",
+ "#GameUI_CommentaryUnlock",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_SAVE_BEFORE_LANGUAGE_CHANGE:
+ CreateMessageDialog( MD_YESNO|MD_WARNING|MD_SIMPLEFRAME|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ChangeLanguageRestart_Title",
+ "#GameUI_ChangeLanguageRestart_Info",
+ "AcceptVocalsLanguageChange",
+ "CancelVocalsLanguageChange",
+ pOwner );
+
+ case MD_SAVE_BEFORE_NEW_GAME:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmNewGame_Title",
+ "#GameUI_NewGameWarning",
+ "StartNewGame",
+ "close_dialog",
+ pOwner );
+ break;
+
+ case MD_SAVE_BEFORE_LOAD:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE|MD_RESTRICTPAINT,
+ "#GameUI_ConfirmLoadGame_Title",
+ "#GameUI_LoadWarning",
+ "LoadGame",
+ "LoadGameCancelled",
+ pOwner );
+ break;
+
+ case MD_DELETE_SAVE_CONFIRM:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmDeleteSaveGame_Title",
+ "#GameUI_ConfirmDeleteSaveGame_Info",
+ "DeleteGame",
+ "DeleteGameCancelled",
+ pOwner );
+ break;
+
+ case MD_SAVE_OVERWRITE:
+ CreateMessageDialog( MD_OKCANCEL|MD_WARNING|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmOverwriteSaveGame_Title",
+ "#GameUI_ConfirmOverwriteSaveGame_Info",
+ "SaveGame",
+ "OverwriteGameCancelled",
+ pOwner );
+ break;
+
+ case MD_SAVING_WARNING:
+ CreateMessageDialog( MD_WARNING|iSimpleFrame|MD_COMMANDONFORCECLOSE,
+ "",
+ "#GameUI_SavingWarning",
+ "SaveSuccess",
+ NULL,
+ pOwner,
+ true);
+ break;
+
+ case MD_SAVE_COMPLETE:
+ CreateMessageDialog( MD_OK|iSimpleFrame|MD_COMMANDAFTERCLOSE,
+ "#GameUI_ConfirmOverwriteSaveGame_Title",
+ "#GameUI_GameSaved",
+ "CloseAndSelectResume",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_LOAD_FAILED_WARNING:
+ CreateMessageDialog( MD_OK |MD_WARNING|iSimpleFrame,
+ "#GameUI_LoadFailed",
+ "#GameUI_LoadFailed_Description",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_OPTION_CHANGE_FROM_X360_DASHBOARD:
+ CreateMessageDialog( MD_OK|iSimpleFrame|MD_RESTRICTPAINT,
+ "#GameUI_SettingChangeFromX360Dashboard_Title",
+ "#GameUI_SettingChangeFromX360Dashboard_Info",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_STANDARD_SAMPLE:
+ CreateMessageDialog( MD_OK,
+ "Standard Dialog",
+ "This is a standard dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_WARNING_SAMPLE:
+ CreateMessageDialog( MD_OK | MD_WARNING,
+ "#GameUI_Dialog_Warning",
+ "This is a warning dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_ERROR_SAMPLE:
+ CreateMessageDialog( MD_OK | MD_ERROR,
+ "Error Dialog",
+ "This is an error dialog",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_STORAGE_DEVICES_CORRUPT:
+ CreateMessageDialog( MD_OK | MD_WARNING | iSimpleFrame | MD_RESTRICTPAINT,
+ "",
+ "#GameUI_Console_FileCorrupt",
+ "close_dialog",
+ NULL,
+ pOwner );
+ break;
+
+ case MD_CHECKING_STORAGE_DEVICE:
+ CreateMessageDialog( iSimpleFrame | MD_RESTRICTPAINT,
+ NULL,
+ "#GameUI_Dlg_CheckingStorageDevice",
+ NULL,
+ NULL,
+ pOwner,
+ true );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void CMessageDialogHandler::CloseAllMessageDialogs()
+{
+ for ( int i = 0; i < MAX_MESSAGE_DIALOGS; ++i )
+ {
+ CMessageDialog *pDlg = m_hMessageDialogs[i];
+ if ( pDlg )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->ReleaseAppModalSurface();
+ }
+
+ pDlg->Close();
+ m_hMessageDialogs[i] = NULL;
+ }
+ }
+}
+
+void CMessageDialogHandler::CloseMessageDialog( const uint nType )
+{
+ int nStackIdx = 0;
+ if ( nType & MD_WARNING )
+ {
+ nStackIdx = DIALOG_STACK_IDX_WARNING;
+ }
+ else if ( nType & MD_ERROR )
+ {
+ nStackIdx = DIALOG_STACK_IDX_ERROR;
+ }
+
+ CMessageDialog *pDlg = m_hMessageDialogs[nStackIdx];
+ if ( pDlg )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->ReleaseAppModalSurface();
+ }
+
+ pDlg->Close();
+ m_hMessageDialogs[nStackIdx] = NULL;
+ }
+}
+
+void CMessageDialogHandler::CreateMessageDialog( const uint nType, const char *pTitle, const char *pMsg, const char *pCmdA, const char *pCmdB, vgui::Panel *pCreator, bool bShowActivity /*= false*/ )
+{
+ int nStackIdx = 0;
+ if ( nType & MD_WARNING )
+ {
+ nStackIdx = DIALOG_STACK_IDX_WARNING;
+ }
+ else if ( nType & MD_ERROR )
+ {
+ nStackIdx = DIALOG_STACK_IDX_ERROR;
+ }
+
+ // Can only show one dialog of each type at a time
+ if ( m_hMessageDialogs[nStackIdx].Get() )
+ {
+ Warning( "Tried to create two dialogs of type %d\n", nStackIdx );
+ return;
+ }
+
+ // Show the new dialog
+ m_hMessageDialogs[nStackIdx] = new CMessageDialog( BasePanel(), nType, pTitle, pMsg, pCmdA, pCmdB, pCreator, bShowActivity );
+
+ m_hMessageDialogs[nStackIdx]->SetControlSettingsKeys( BasePanel()->GetConsoleControlSettings()->FindKey( "MessageDialog.res" ) );
+
+ if ( nType & MD_RESTRICTPAINT )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( m_hMessageDialogs[nStackIdx]->GetVPanel() );
+ }
+
+ ActivateMessageDialog( nStackIdx );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activate a new message dialog
+//-----------------------------------------------------------------------------
+void CMessageDialogHandler::ActivateMessageDialog( int nStackIdx )
+{
+ int x, y, wide, tall;
+ vgui::surface()->GetWorkspaceBounds( x, y, wide, tall );
+ PositionDialog( m_hMessageDialogs[nStackIdx], wide, tall );
+
+ uint nType = m_hMessageDialogs[nStackIdx]->GetType();
+ if ( nType & MD_WARNING )
+ {
+ m_hMessageDialogs[nStackIdx]->SetZPos( 75 );
+ }
+ else if ( nType & MD_ERROR )
+ {
+ m_hMessageDialogs[nStackIdx]->SetZPos( 100 );
+ }
+
+ // Make sure the topmost item on the stack still has focus
+ int idx = MAX_MESSAGE_DIALOGS - 1;
+ for ( idx; idx >= nStackIdx; --idx )
+ {
+ CMessageDialog *pDialog = m_hMessageDialogs[idx];
+ if ( pDialog )
+ {
+ pDialog->Activate();
+ if ( vgui_message_dialog_modal.GetBool() )
+ {
+ vgui::input()->SetAppModalSurface( pDialog->GetVPanel() );
+ }
+ m_iDialogStackTop = idx;
+ break;
+ }
+ }
+}
+
+void CMessageDialogHandler::PositionDialogs( int wide, int tall )
+{
+ for ( int i = 0; i < MAX_MESSAGE_DIALOGS; ++i )
+ {
+ if ( m_hMessageDialogs[i].Get() )
+ {
+ PositionDialog( m_hMessageDialogs[i], wide, tall );
+ }
+ }
+}
+
+void CMessageDialogHandler::PositionDialog( vgui::PHandle dlg, int wide, int tall )
+{
+ int w, t;
+ dlg->GetSize(w, t);
+ dlg->SetPos( (wide - w) / 2, (tall - t) / 2 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Editable panel that can replace the GameMenuButtons in CBasePanel
+//-----------------------------------------------------------------------------
+CMainMenuGameLogo::CMainMenuGameLogo( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name )
+{
+ m_nOffsetX = 0;
+ m_nOffsetY = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainMenuGameLogo::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ m_nOffsetX = inResourceData->GetInt( "offsetX", 0 );
+ m_nOffsetY = inResourceData->GetInt( "offsetY", 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMainMenuGameLogo::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pConditions = new KeyValues( "conditions" );
+ if ( pConditions )
+ {
+ char background[MAX_PATH];
+ engine->GetMainMenuBackgroundName( background, sizeof(background) );
+
+ KeyValues *pSubKey = new KeyValues( background );
+ if ( pSubKey )
+ {
+ pConditions->AddSubKey( pSubKey );
+ }
+ }
+
+ LoadControlSettings( "Resource/GameLogo.res", NULL, NULL, pConditions );
+
+ if ( pConditions )
+ {
+ pConditions->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBasePanel::CloseBaseDialogs( void )
+{
+ if ( m_hNewGameDialog.Get() )
+ m_hNewGameDialog->Close();
+
+ if ( m_hAchievementsDialog.Get() )
+ m_hAchievementsDialog->Close();
+
+ if ( m_hBonusMapsDialog.Get() )
+ m_hBonusMapsDialog->Close();
+
+ if ( m_hControllerDialog.Get() )
+ m_hControllerDialog->Close();
+
+ if ( m_hLoadGameDialog_Xbox.Get() )
+ m_hLoadGameDialog_Xbox->Close();
+
+ if ( m_hOptionsDialog_Xbox.Get() )
+ m_hOptionsDialog_Xbox->Close();
+
+ if ( m_hSaveGameDialog_Xbox.Get() )
+ m_hSaveGameDialog_Xbox->Close();
+
+ if ( m_hLoadCommentaryDialog.Get() )
+ m_hLoadCommentaryDialog->Close();
+
+ if ( m_hCreateMultiplayerGameDialog.Get() )
+ m_hCreateMultiplayerGameDialog->Close();
+}
+
+static void CC_GameUIShowDialog( const CCommand &args )
+{
+ int c = args.ArgC();
+
+ if ( c < 2 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ GameUI().ShowMessageDialog( atoi(args[1]) );
+}
+static ConCommand gameui_show_dialog( "gameui_show_dialog", CC_GameUIShowDialog, "Show an arbitrary Dialog.", 0 );
+
+static void CC_GameUIHideDialog( const CCommand &args )
+{
+ int c = args.ArgC();
+ if ( c < 1 )
+ {
+ Msg( "Usage: gamemenucommand <commandname>\n" );
+ return;
+ }
+
+ GameUI().CloseMessageDialog( 0 );
+}
+static ConCommand gameui_hide_dialog( "gameui_hide_dialog", CC_GameUIHideDialog, "asdf", 0 );
+
+static void RefreshOptionsDialog( const CCommand &args )
+{
+ if ( g_hOptionsDialog )
+ {
+ CBasePanel* pBasePanel = (CBasePanel*) g_hOptionsDialog->GetParent();
+ g_hOptionsDialog->Close();
+ delete g_hOptionsDialog.Get();
+ if ( pBasePanel )
+ {
+ pBasePanel->OnOpenOptionsDialog();
+ COptionsDialog *pOptionsDialog = dynamic_cast<COptionsDialog*>( g_hOptionsDialog.Get() );
+ if ( pOptionsDialog )
+ {
+ pOptionsDialog->GetPropertySheet()->SetActivePage( pOptionsDialog->GetOptionsSubMultiplayer() );
+ }
+ }
+ }
+}
+static ConCommand refresh_options_dialog( "refresh_options_dialog", RefreshOptionsDialog, "Refresh the options dialog.", 0 );
diff --git a/gameui/BasePanel.h b/gameui/BasePanel.h
new file mode 100644
index 0000000..bb1e9b4
--- /dev/null
+++ b/gameui/BasePanel.h
@@ -0,0 +1,462 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BASEPANEL_H
+#define BASEPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Panel.h"
+#include "vgui_controls/PHandle.h"
+#include "vgui_controls/MenuItem.h"
+#include "vgui_controls/MessageDialog.h"
+#include "KeyValues.h"
+#include "utlvector.h"
+#include "tier1/CommandBuffer.h"
+
+#include "ixboxsystem.h"
+
+#if !defined( _X360 )
+#include "xbox/xboxstubs.h"
+#endif
+
+enum
+{
+ DIALOG_STACK_IDX_STANDARD,
+ DIALOG_STACK_IDX_WARNING,
+ DIALOG_STACK_IDX_ERROR,
+};
+
+class CMatchmakingBasePanel;
+class CBackgroundMenuButton;
+class CGameMenu;
+class CAsyncCtxOnDeviceAttached;
+
+// X360TBD: Move into a separate module when finished
+class CMessageDialogHandler
+{
+public:
+ CMessageDialogHandler();
+ void ShowMessageDialog( int nType, vgui::Panel *pOwner );
+ void CloseMessageDialog( const uint nType = 0 );
+ void CloseAllMessageDialogs();
+ void CreateMessageDialog( const uint nType, const char *pTitle, const char *pMsg, const char *pCmdA, const char *pCmdB, vgui::Panel *pCreator, bool bShowActivity = false );
+ void ActivateMessageDialog( int nStackIdx );
+ void PositionDialogs( int wide, int tall );
+ void PositionDialog( vgui::PHandle dlg, int wide, int tall );
+
+private:
+ static const int MAX_MESSAGE_DIALOGS = 3;
+ vgui::DHANDLE< CMessageDialog > m_hMessageDialogs[MAX_MESSAGE_DIALOGS];
+ int m_iDialogStackTop;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Panel that acts as background for button icons and help text in the UI
+//-----------------------------------------------------------------------------
+class CFooterPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CFooterPanel, vgui::EditablePanel );
+
+public:
+ CFooterPanel( Panel *parent, const char *panelName );
+ virtual ~CFooterPanel();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void Paint( void );
+ virtual void PaintBackground( void );
+
+ // caller tags the current hint, used to assist in ownership
+ void SetHelpNameAndReset( const char *pName );
+ const char *GetHelpName();
+
+ void AddButtonsFromMap( vgui::Frame *pMenu );
+ void SetStandardDialogButtons();
+ void AddNewButtonLabel( const char *text, const char *icon );
+ void ShowButtonLabel( const char *name, bool show = true );
+ void SetButtonText( const char *buttonName, const char *text );
+ void ClearButtons();
+ void SetButtonGap( int nButtonGap ){ m_nButtonGap = nButtonGap; }
+ void UseDefaultButtonGap(){ m_nButtonGap = m_nButtonGapDefault; }
+
+private:
+ struct ButtonLabel_t
+ {
+ bool bVisible;
+ char name[MAX_PATH];
+ wchar_t text[MAX_PATH];
+ wchar_t icon[2]; // icon is a single character
+ };
+
+ CUtlVector< ButtonLabel_t* > m_ButtonLabels;
+
+ vgui::Label *m_pSizingLabel; // used to measure font sizes
+
+ bool m_bPaintBackground; // fill the background?
+ bool m_bCenterHorizontal; // center buttons horizontally?
+ int m_ButtonPinRight; // if not centered, this is the distance from the right margin that we use to start drawing buttons (right to left)
+ int m_nButtonGap; // space between buttons when drawing
+ int m_nButtonGapDefault; // space between buttons (initial value)
+ int m_FooterTall; // height of the footer
+ int m_ButtonOffsetFromTop; // how far below the top the buttons should be drawn
+ int m_ButtonSeparator; // space between the button icon and text
+ int m_TextAdjust; // extra adjustment for the text (vertically)...text is centered on the button icon and then this value is applied
+
+ char m_szTextFont[64]; // font for the button text
+ char m_szButtonFont[64]; // font for the button icon
+ char m_szFGColor[64]; // foreground color (text)
+ char m_szBGColor[64]; // background color (fill color)
+
+ vgui::HFont m_hButtonFont;
+ vgui::HFont m_hTextFont;
+ char *m_pHelpName;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: EditablePanel that can replace the GameMenuButtons in CBasePanel
+//-----------------------------------------------------------------------------
+class CMainMenuGameLogo : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CMainMenuGameLogo, vgui::EditablePanel );
+public:
+ CMainMenuGameLogo( vgui::Panel *parent, const char *name );
+
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ int GetOffsetX(){ return m_nOffsetX; }
+ int GetOffsetY(){ return m_nOffsetY; }
+
+private:
+ int m_nOffsetX;
+ int m_nOffsetY;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Transparent menu item designed to sit on the background ingame
+//-----------------------------------------------------------------------------
+class CGameMenuItem : public vgui::MenuItem
+{
+ DECLARE_CLASS_SIMPLE( CGameMenuItem, vgui::MenuItem );
+public:
+ CGameMenuItem(vgui::Menu *parent, const char *name);
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void PaintBackground( void );
+ void SetRightAlignedText( bool state );
+
+private:
+ bool m_bRightAligned;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: This is the panel at the top of the panel hierarchy for GameUI
+// It handles all the menus, background images, and loading dialogs
+//-----------------------------------------------------------------------------
+class CBasePanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CBasePanel, vgui::Panel );
+
+public:
+ CBasePanel();
+ virtual ~CBasePanel();
+
+public:
+ //
+ // Implementation of async jobs
+ // An async job is enqueued by calling "ExecuteAsync" with the proper job context.
+ // Job's function "ExecuteAsync" is called on a separate thread.
+ // After the job finishes the "Completed" function is called on the
+ // main thread.
+ //
+ class CAsyncJobContext
+ {
+ public:
+ CAsyncJobContext( float flLeastExecuteTime = 0.0f ) : m_flLeastExecuteTime( flLeastExecuteTime ), m_hThreadHandle( NULL ) {}
+ virtual ~CAsyncJobContext() {}
+
+ virtual void ExecuteAsync() = 0; // Executed on the secondary thread
+ virtual void Completed() = 0; // Executed on the main thread
+
+ public:
+ void * volatile m_hThreadHandle; // Handle to an async job thread waiting for
+ float m_flLeastExecuteTime; // Least amount of time this job should keep executing
+ };
+
+ CAsyncJobContext *m_pAsyncJob;
+ void ExecuteAsync( CAsyncJobContext *pAsync );
+
+
+public:
+ // notifications
+ void OnLevelLoadingStarted();
+ void OnLevelLoadingFinished();
+
+ // update the taskbar a frame
+ void RunFrame();
+
+ // fades to black then runs an engine command (usually to start a level)
+ void FadeToBlackAndRunEngineCommand( const char *engineCommand );
+
+ // sets the blinking state of a menu item
+ void SetMenuItemBlinkingState( const char *itemName, bool state );
+
+ // handles gameUI being shown
+ void OnGameUIActivated();
+
+ // game dialogs
+ void OnOpenNewGameDialog( const char *chapter = NULL );
+ void OnOpenBonusMapsDialog();
+ void OnOpenLoadGameDialog();
+ void OnOpenLoadGameDialog_Xbox();
+ void OnOpenSaveGameDialog();
+ void OnOpenSaveGameDialog_Xbox();
+ void OnOpenServerBrowser();
+ void OnOpenFriendsDialog();
+ void OnOpenDemoDialog();
+ void OnOpenCreateMultiplayerGameDialog();
+ void OnOpenQuitConfirmationDialog();
+ void OnOpenDisconnectConfirmationDialog();
+ void OnOpenChangeGameDialog();
+ void OnOpenPlayerListDialog();
+ void OnOpenBenchmarkDialog();
+ void OnOpenOptionsDialog();
+ void OnOpenOptionsDialog_Xbox();
+ void OnOpenLoadCommentaryDialog();
+ void OpenLoadSingleplayerCommentaryDialog();
+ void OnOpenAchievementsDialog();
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Specific code for CS Achievements Display
+ //=============================================================================
+
+ // $TODO(HPE): Move this to a game-specific location
+ void OnOpenCSAchievementsDialog();
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ void OnOpenAchievementsDialog_Xbox();
+ void OnOpenControllerDialog();
+
+ // Xbox 360
+ CMatchmakingBasePanel* GetMatchmakingBasePanel();
+ void OnOpenMatchmakingBasePanel();
+ void SessionNotification( const int notification, const int param = 0 );
+ void SystemNotification( const int notification );
+ void ShowMessageDialog( const uint nType, vgui::Panel *pParent = NULL );
+ void CloseMessageDialog( const uint nType );
+ void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost );
+ void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping );
+ void OnChangeStorageDevice();
+ bool ValidateStorageDevice();
+ bool ValidateStorageDevice( int *pStorageDeviceValidated );
+ void OnCreditsFinished();
+
+ KeyValues *GetConsoleControlSettings( void );
+
+ // forces any changed options dialog settings to be applied immediately, if it's open
+ void ApplyOptionsDialogSettings();
+
+ vgui::AnimationController *GetAnimationController( void ) { return m_pConsoleAnimationController; }
+ void RunCloseAnimation( const char *animName );
+ void RunAnimationWithCallback( vgui::Panel *parent, const char *animName, KeyValues *msgFunc );
+ void PositionDialog( vgui::PHandle dlg );
+
+ virtual void OnSizeChanged( int newWide, int newTall );
+
+ void ArmFirstMenuItem( void );
+
+ void OnGameUIHidden();
+
+ void CloseBaseDialogs( void );
+ bool IsWaitingForConsoleUI( void ) { return m_bWaitingForStorageDeviceHandle || m_bWaitingForUserSignIn || m_bXUIVisible; }
+
+#if defined( _X360 )
+ CON_COMMAND_MEMBER_F( CBasePanel, "gameui_reload_resources", Reload_Resources, "Reload the Xbox 360 UI res files", 0 );
+#endif
+
+ int GetMenuAlpha( void );
+
+ void SetMainMenuOverride( vgui::VPANEL panel );
+
+
+
+protected:
+ virtual void PaintBackground();
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+public:
+ // FIXME: This should probably become a friend relationship between the classes
+ bool HandleSignInRequest( const char *command );
+ bool HandleStorageDeviceRequest( const char *command );
+ void ClearPostPromptCommand( const char *pCompletedCommand );
+
+private:
+ enum EBackgroundState
+ {
+ BACKGROUND_INITIAL,
+ BACKGROUND_LOADING,
+ BACKGROUND_MAINMENU,
+ BACKGROUND_LEVEL,
+ BACKGROUND_DISCONNECTED,
+ BACKGROUND_EXITING, // Console has started an exiting state, cannot be stopped
+ };
+ void SetBackgroundRenderState(EBackgroundState state);
+
+ friend class CAsyncCtxOnDeviceAttached;
+ void OnDeviceAttached( void );
+ void OnCompletedAsyncDeviceAttached( CAsyncCtxOnDeviceAttached *job );
+
+ void IssuePostPromptCommand( void );
+
+ void UpdateBackgroundState();
+
+ // sets the menu alpha [0..255]
+ void SetMenuAlpha(int alpha);
+
+ // menu manipulation
+ void CreatePlatformMenu();
+ void CreateGameMenu();
+ void CreateGameLogo();
+ void CheckBonusBlinkState();
+ void UpdateGameMenus();
+ CGameMenu *RecursiveLoadGameMenu(KeyValues *datafile);
+
+ void StartExitingProcess();
+
+ bool IsPromptableCommand( const char *command );
+ bool CommandRequiresSignIn( const char *command );
+ bool CommandRequiresStorageDevice( const char *command );
+ bool CommandRespectsSignInDenied( const char *command );
+
+ void QueueCommand( const char *pCommand );
+ void RunQueuedCommands();
+ void ClearQueuedCommands();
+
+ virtual void OnCommand(const char *command);
+ virtual void PerformLayout();
+ MESSAGE_FUNC_INT( OnActivateModule, "ActivateModule", moduleIndex);
+
+ void UpdateRichPresenceInfo();
+
+ // menu logo
+ CMainMenuGameLogo *m_pGameLogo;
+
+ // menu buttons
+ CUtlVector< CBackgroundMenuButton * >m_pGameMenuButtons;
+ CGameMenu *m_pGameMenu;
+ bool m_bPlatformMenuInitialized;
+ int m_iGameMenuInset;
+
+ vgui::VPANEL m_hMainMenuOverridePanel;
+
+ struct coord {
+ int x;
+ int y;
+ };
+ CUtlVector< coord > m_iGameTitlePos;
+ coord m_iGameMenuPos;
+
+ // base dialogs
+ vgui::DHANDLE<vgui::Frame> m_hNewGameDialog;
+ vgui::DHANDLE<vgui::Frame> m_hBonusMapsDialog;
+ vgui::DHANDLE<vgui::Frame> m_hLoadGameDialog;
+ vgui::DHANDLE<vgui::Frame> m_hLoadGameDialog_Xbox;
+ vgui::DHANDLE<vgui::Frame> m_hSaveGameDialog;
+ vgui::DHANDLE<vgui::Frame> m_hSaveGameDialog_Xbox;
+ vgui::DHANDLE<vgui::PropertyDialog> m_hOptionsDialog;
+ vgui::DHANDLE<vgui::Frame> m_hOptionsDialog_Xbox;
+ vgui::DHANDLE<vgui::Frame> m_hCreateMultiplayerGameDialog;
+ //vgui::DHANDLE<vgui::Frame> m_hDemoPlayerDialog;
+ vgui::DHANDLE<vgui::Frame> m_hChangeGameDialog;
+ vgui::DHANDLE<vgui::Frame> m_hPlayerListDialog;
+ vgui::DHANDLE<vgui::Frame> m_hBenchmarkDialog;
+ vgui::DHANDLE<vgui::Frame> m_hLoadCommentaryDialog;
+ vgui::DHANDLE<vgui::Frame> m_hAchievementsDialog;
+
+ // Xbox 360
+ vgui::DHANDLE<vgui::Frame> m_hMatchmakingBasePanel;
+ vgui::DHANDLE<vgui::Frame> m_hControllerDialog;
+
+ EBackgroundState m_eBackgroundState;
+
+ CMessageDialogHandler m_MessageDialogHandler;
+ CUtlVector< CUtlString > m_CommandQueue;
+
+ vgui::AnimationController *m_pConsoleAnimationController;
+ KeyValues *m_pConsoleControlSettings;
+
+ void DrawBackgroundImage();
+ int m_iBackgroundImageID;
+ int m_iRenderTargetImageID;
+ int m_iLoadingImageID;
+ int m_iProductImageID;
+ bool m_bLevelLoading;
+ bool m_bEverActivated;
+ bool m_bCopyFrameBuffer;
+ bool m_bUseRenderTargetImage;
+ int m_ExitingFrameCount;
+ bool m_bXUIVisible;
+ bool m_bUseMatchmaking;
+ bool m_bRestartFromInvite;
+ bool m_bRestartSameGame;
+
+ // Used for internal state dealing with blades
+ bool m_bUserRefusedSignIn;
+ bool m_bUserRefusedStorageDevice;
+ bool m_bWaitingForUserSignIn;
+ bool m_bStorageBladeShown;
+ CUtlString m_strPostPromptCommand;
+
+ // Storage device changing vars
+ bool m_bWaitingForStorageDeviceHandle;
+ bool m_bNeedStorageDeviceHandle;
+ AsyncHandle_t m_hStorageDeviceChangeHandle;
+ uint m_iStorageID;
+ int *m_pStorageDeviceValidatedNotify;
+
+ // background transition
+ bool m_bFadingInMenus;
+ float m_flFadeMenuStartTime;
+ float m_flFadeMenuEndTime;
+
+ bool m_bRenderingBackgroundTransition;
+ float m_flTransitionStartTime;
+ float m_flTransitionEndTime;
+
+ // Used for rich presence updates on xbox360
+ bool m_bSinglePlayer;
+ uint m_iGameID; // matches context value in hl2orange.spa.h
+
+ // background fill transition
+ bool m_bHaveDarkenedBackground;
+ bool m_bHaveDarkenedTitleText;
+ bool m_bForceTitleTextUpdate;
+ float m_flFrameFadeInTime;
+ Color m_BackdropColor;
+ CPanelAnimationVar( float, m_flBackgroundFillAlpha, "m_flBackgroundFillAlpha", "0" );
+
+ // fading to game
+ MESSAGE_FUNC_CHARPTR( RunEngineCommand, "RunEngineCommand", command );
+ MESSAGE_FUNC( FinishDialogClose, "FinishDialogClose" );
+
+public:
+ MESSAGE_FUNC_CHARPTR( RunMenuCommand, "RunMenuCommand", command );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+extern CBasePanel *BasePanel();
+
+
+#endif // BASEPANEL_H
diff --git a/gameui/BaseSaveGameDialog.cpp b/gameui/BaseSaveGameDialog.cpp
new file mode 100644
index 0000000..99f7fc1
--- /dev/null
+++ b/gameui/BaseSaveGameDialog.cpp
@@ -0,0 +1,668 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "BaseSaveGameDialog.h"
+#include "filesystem.h"
+#include "savegame_version.h"
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Button.h"
+#include "tier1/utlbuffer.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include "filesystem.h"
+
+#include "MouseMessageForwardingPanel.h"
+#include "TGAImagePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+#define TGA_IMAGE_PANEL_WIDTH 180
+#define TGA_IMAGE_PANEL_HEIGHT 100
+
+#define MAX_LISTED_SAVE_GAMES 128
+
+//-----------------------------------------------------------------------------
+// Purpose: Describes the layout of a same game pic
+//-----------------------------------------------------------------------------
+class CSaveGamePanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CSaveGamePanel, vgui::EditablePanel );
+public:
+ CSaveGamePanel( PanelListPanel *parent, const char *name, int saveGameListItemID ) : BaseClass( parent, name )
+ {
+ m_iSaveGameListItemID = saveGameListItemID;
+ m_pParent = parent;
+ m_pSaveGameImage = new CTGAImagePanel( this, "SaveGameImage" );
+ m_pAutoSaveImage = new ImagePanel( this, "AutoSaveImage" );
+ m_pSaveGameScreenshotBackground = new ImagePanel( this, "SaveGameScreenshotBackground" );
+ m_pChapterLabel = new Label( this, "ChapterLabel", "" );
+ m_pTypeLabel = new Label( this, "TypeLabel", "" );
+ m_pElapsedTimeLabel = new Label( this, "ElapsedTimeLabel", "" );
+ m_pFileTimeLabel = new Label( this, "FileTimeLabel", "" );
+
+ CMouseMessageForwardingPanel *panel = new CMouseMessageForwardingPanel(this, NULL);
+ panel->SetZPos(2);
+
+ SetSize( 200, 140 );
+
+ LoadControlSettings( "resource/SaveGamePanel.res" );
+
+ m_FillColor = m_pSaveGameScreenshotBackground->GetFillColor();
+ }
+
+ void SetSaveGameInfo( SaveGameDescription_t &save )
+ {
+ // set the bitmap to display
+ char tga[_MAX_PATH];
+ Q_strncpy( tga, save.szFileName, sizeof(tga) );
+ char *ext = strstr( tga, ".sav" );
+ if ( ext )
+ {
+ strcpy( ext, ".tga" );
+ }
+
+ // If a TGA file exists then it is a user created savegame
+ if ( g_pFullFileSystem->FileExists( tga ) )
+ {
+ m_pSaveGameImage->SetTGA( tga );
+ }
+ // If there is no TGA then it is either an autosave or the user TGA file has been deleted
+ else
+ {
+ m_pSaveGameImage->SetVisible( false );
+ m_pAutoSaveImage->SetVisible( true );
+ m_pAutoSaveImage->SetImage( "resource\\autosave" );
+ }
+
+ // set the title text
+ m_pChapterLabel->SetText( save.szComment );
+
+ // type
+ SetControlString( "TypeLabel", save.szType );
+ SetControlString( "ElapsedTimeLabel", save.szElapsedTime );
+ SetControlString( "FileTimeLabel", save.szFileTime );
+ }
+
+ MESSAGE_FUNC_INT( OnPanelSelected, "PanelSelected", state )
+ {
+ if ( state )
+ {
+ // set the text color to be orange, and the pic border to be orange
+ m_pSaveGameScreenshotBackground->SetFillColor( m_SelectedColor );
+ m_pChapterLabel->SetFgColor( m_SelectedColor );
+ m_pTypeLabel->SetFgColor( m_SelectedColor );
+ m_pElapsedTimeLabel->SetFgColor( m_SelectedColor );
+ m_pFileTimeLabel->SetFgColor( m_SelectedColor );
+ }
+ else
+ {
+ m_pSaveGameScreenshotBackground->SetFillColor( m_FillColor );
+ m_pChapterLabel->SetFgColor( m_TextColor );
+ m_pTypeLabel->SetFgColor( m_TextColor );
+ m_pElapsedTimeLabel->SetFgColor( m_TextColor );
+ m_pFileTimeLabel->SetFgColor( m_TextColor );
+ }
+
+ PostMessage( m_pParent->GetVParent(), new KeyValues("PanelSelected") );
+ }
+
+ virtual void OnMousePressed( vgui::MouseCode code )
+ {
+ m_pParent->SetSelectedPanel( this );
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
+ m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+ }
+
+ virtual void OnMouseDoublePressed( vgui::MouseCode code )
+ {
+ // call the panel
+ OnMousePressed( code );
+ PostMessage( m_pParent->GetParent(), new KeyValues("Command", "command", "loadsave") );
+ }
+
+ int GetSaveGameListItemID()
+ {
+ return m_iSaveGameListItemID;
+ }
+
+private:
+ vgui::PanelListPanel *m_pParent;
+ vgui::Label *m_pChapterLabel;
+ CTGAImagePanel *m_pSaveGameImage;
+ ImagePanel *m_pAutoSaveImage;
+
+ // things to change color when the selection changes
+ ImagePanel *m_pSaveGameScreenshotBackground;
+ Label *m_pTypeLabel;
+ Label *m_pElapsedTimeLabel;
+ Label *m_pFileTimeLabel;
+ Color m_TextColor, m_FillColor, m_SelectedColor;
+
+ int m_iSaveGameListItemID;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBaseSaveGameDialog::CBaseSaveGameDialog( vgui::Panel *parent, const char *name ) : BaseClass( parent, name )
+{
+ CreateSavedGamesList();
+ ScanSavedGames();
+
+ m_pLoadButton = new vgui::Button( this, "loadsave", "" );
+ SetControlEnabled( "loadsave", false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates the load game display list
+//-----------------------------------------------------------------------------
+void CBaseSaveGameDialog::CreateSavedGamesList()
+{
+ m_pGameList = new vgui::PanelListPanel( this, "listpanel_loadgame" );
+ m_pGameList->SetFirstColumnWidth( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the save file name of the selected item
+//-----------------------------------------------------------------------------
+int CBaseSaveGameDialog::GetSelectedItemSaveIndex()
+{
+ CSaveGamePanel *panel = dynamic_cast<CSaveGamePanel *>(m_pGameList->GetSelectedPanel());
+ if ( panel )
+ {
+ // find the panel in the list
+ for ( int i = 0; i < m_SaveGames.Count(); i++ )
+ {
+ if ( i == panel->GetSaveGameListItemID() )
+ {
+ return i;
+ }
+ }
+ }
+ return m_SaveGames.InvalidIndex();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: builds save game list from directory
+//-----------------------------------------------------------------------------
+void CBaseSaveGameDialog::ScanSavedGames()
+{
+ // populate list box with all saved games on record:
+ char szDirectory[_MAX_PATH];
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "save/*.sav" );
+
+ // clear the current list
+ m_pGameList->DeleteAllItems();
+ m_SaveGames.RemoveAll();
+
+ // iterate the saved files
+ FileFindHandle_t handle;
+ const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle );
+ while (pFileName)
+ {
+ if ( !Q_strnicmp(pFileName, "HLSave", strlen( "HLSave" ) ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ char szFileName[_MAX_PATH];
+ Q_snprintf(szFileName, sizeof( szFileName ), "save/%s", pFileName);
+
+ // Only load save games from the current mod's save dir
+ if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ SaveGameDescription_t save;
+ if ( ParseSaveData( szFileName, pFileName, save ) )
+ {
+ m_SaveGames.AddToTail( save );
+ }
+
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ }
+
+ g_pFullFileSystem->FindClose( handle );
+
+ // notify derived classes that save games are being scanned (so they can insert their own)
+ OnScanningSaveGames();
+
+ // sort the save list
+ qsort( m_SaveGames.Base(), m_SaveGames.Count(), sizeof(SaveGameDescription_t), &SaveGameSortFunc );
+
+ // add to the list
+ for ( int saveIndex = 0; saveIndex < m_SaveGames.Count() && saveIndex < MAX_LISTED_SAVE_GAMES; saveIndex++ )
+ {
+ // add the item to the panel
+ AddSaveGameItemToList( saveIndex );
+ }
+
+ // display a message if there are no save games
+ if ( !m_SaveGames.Count() )
+ {
+ vgui::Label *pNoSavesLabel = SETUP_PANEL(new Label(m_pGameList, "NoSavesLabel", "#GameUI_NoSaveGamesToDisplay"));
+ pNoSavesLabel->SetTextColorState(vgui::Label::CS_DULL);
+ m_pGameList->AddItem( NULL, pNoSavesLabel );
+ }
+
+ SetControlEnabled( "loadsave", false );
+ SetControlEnabled( "delete", false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds an item to the list
+//-----------------------------------------------------------------------------
+void CBaseSaveGameDialog::AddSaveGameItemToList( int saveIndex )
+{
+ // create the new panel and add to the list
+ CSaveGamePanel *saveGamePanel = new CSaveGamePanel( m_pGameList, "SaveGamePanel", saveIndex );
+ saveGamePanel->SetSaveGameInfo( m_SaveGames[saveIndex] );
+ m_pGameList->AddItem( NULL, saveGamePanel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses the save game info out of the .sav file header
+//-----------------------------------------------------------------------------
+bool CBaseSaveGameDialog::ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t &save )
+{
+ char szMapName[SAVEGAME_MAPNAME_LEN];
+ char szComment[SAVEGAME_COMMENT_LEN];
+ char szElapsedTime[SAVEGAME_ELAPSED_LEN];
+
+ if ( !pszFileName || !pszShortName )
+ return false;
+
+ Q_strncpy( save.szShortName, pszShortName, sizeof(save.szShortName) );
+ Q_strncpy( save.szFileName, pszFileName, sizeof(save.szFileName) );
+
+ FileHandle_t fh = g_pFullFileSystem->Open( pszFileName, "rb", "MOD" );
+ if (fh == FILESYSTEM_INVALID_HANDLE)
+ return false;
+
+ int readok = SaveReadNameAndComment( fh, szMapName, ARRAYSIZE(szMapName), szComment, ARRAYSIZE(szComment) );
+ g_pFullFileSystem->Close(fh);
+
+ if ( !readok )
+ {
+ return false;
+ }
+
+ Q_strncpy( save.szMapName, szMapName, sizeof(save.szMapName) );
+
+ // Elapsed time is the last 6 characters in comment. (mmm:ss)
+ int i;
+ i = strlen( szComment );
+ Q_strncpy( szElapsedTime, "??", sizeof( szElapsedTime ) );
+ if (i >= 6)
+ {
+ Q_strncpy( szElapsedTime, (char *)&szComment[i - 6], 7 );
+ szElapsedTime[6] = '\0';
+
+ // parse out
+ int minutes = atoi( szElapsedTime );
+ int seconds = atoi( szElapsedTime + 4);
+
+ // reformat
+ if ( minutes )
+ {
+ Q_snprintf( szElapsedTime, sizeof(szElapsedTime), "%d %s %d seconds", minutes, minutes > 1 ? "minutes" : "minute", seconds );
+ }
+ else
+ {
+ Q_snprintf( szElapsedTime, sizeof(szElapsedTime), "%d seconds", seconds );
+ }
+
+ // Chop elapsed out of comment.
+ int n;
+
+ n = i - 6;
+ szComment[n] = '\0';
+
+ n--;
+
+ // Strip back the spaces at the end.
+ while ((n >= 1) &&
+ szComment[n] &&
+ szComment[n] == ' ')
+ {
+ szComment[n--] = '\0';
+ }
+ }
+
+ // calculate the file name to print
+ const char *pszType = "";
+ if (strstr(pszFileName, "quick"))
+ {
+ pszType = "#GameUI_QuickSave";
+ }
+ else if (strstr(pszFileName, "autosave"))
+ {
+ pszType = "#GameUI_AutoSave";
+ }
+
+ Q_strncpy( save.szType, pszType, sizeof(save.szType) );
+ Q_strncpy( save.szComment, szComment, sizeof(save.szComment) );
+ Q_strncpy( save.szElapsedTime, szElapsedTime, sizeof(save.szElapsedTime) );
+
+ // Now get file time stamp.
+ long fileTime = g_pFullFileSystem->GetFileTime(pszFileName);
+ char szFileTime[32];
+ g_pFullFileSystem->FileTimeToString(szFileTime, sizeof(szFileTime), fileTime);
+ char *newline = strstr(szFileTime, "\n");
+ if (newline)
+ {
+ *newline = 0;
+ }
+ Q_strncpy( save.szFileTime, szFileTime, sizeof(save.szFileTime) );
+ save.iTimestamp = fileTime;
+ return true;
+}
+
+void CBaseSaveGameDialog::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_ESCAPE )
+ {
+ OnCommand( "Close" );
+ return;
+ }
+
+ BaseClass::OnKeyCodeTyped( code );
+}
+
+void CBaseSaveGameDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_B )
+ {
+ OnCommand( "Close" );
+ return;
+ }
+ else if ( code == KEY_XSTICK1_DOWN ||
+ code == KEY_XSTICK2_DOWN ||
+ code == KEY_XBUTTON_DOWN ||
+ code == KEY_DOWN )
+ {
+ if ( m_pGameList->GetItemCount() )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( !pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( m_pGameList->FirstItem() ) );
+ m_pGameList->ScrollToItem( m_pGameList->FirstItem() );
+ return;
+ }
+ else
+ {
+ int nNextPanelID = m_pGameList->FirstItem();
+ while ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) == pSelectedPanel )
+ {
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+ if ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( nNextPanelID ) );
+ m_pGameList->ScrollToItem( nNextPanelID );
+ return;
+ }
+
+ break;
+ }
+
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+ }
+ }
+ }
+ }
+ else if ( code == KEY_XSTICK1_UP ||
+ code == KEY_XSTICK2_UP ||
+ code == KEY_XBUTTON_UP ||
+ code == KEY_UP )
+ {
+ if ( m_pGameList->GetItemCount() )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( !pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( m_pGameList->FirstItem() ) );
+ m_pGameList->ScrollToItem( m_pGameList->FirstItem() );
+ return;
+ }
+ else
+ {
+ int nNextPanelID = m_pGameList->FirstItem();
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) != pSelectedPanel )
+ {
+ while ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ int nOldPanelID = nNextPanelID;
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+
+ if ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) == pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( nOldPanelID ) );
+ m_pGameList->ScrollToItem( nOldPanelID );
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( code == KEY_ENTER || code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( pSelectedPanel )
+ {
+ if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ ConVarRef var( "joystick" );
+ if ( var.IsValid() && !var.GetBool() )
+ {
+ var.SetValue( true );
+ }
+
+ ConVarRef var2( "hud_fastswitch" );
+ if ( var2.IsValid() && var2.GetInt() != 2 )
+ {
+ var2.SetValue( 2 );
+ }
+ }
+
+ m_pLoadButton->DoClick();
+ return;
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: timestamp sort function for savegames
+//-----------------------------------------------------------------------------
+int CBaseSaveGameDialog::SaveGameSortFunc( const void *lhs, const void *rhs )
+{
+ const SaveGameDescription_t *s1 = (const SaveGameDescription_t *)lhs;
+ const SaveGameDescription_t *s2 = (const SaveGameDescription_t *)rhs;
+
+ if (s1->iTimestamp < s2->iTimestamp)
+ return 1;
+ else if (s1->iTimestamp > s2->iTimestamp)
+ return -1;
+
+ // timestamps are equal, so just sort by filename
+ return strcmp(s1->szFileName, s2->szFileName);
+}
+
+#define MAKEID(d,c,b,a) ( ((int)(a) << 24) | ((int)(b) << 16) | ((int)(c) << 8) | ((int)(d)) )
+
+int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int nameSize, OUT_Z_CAP(commentSize) char *comment, int commentSize )
+{
+ int i, tag, size, tokenSize, tokenCount;
+ char *pSaveData, *pFieldName, **pTokenList;
+
+ name[0] = '\0';
+ comment[0] = '\0';
+
+ g_pFullFileSystem->Read( &tag, sizeof(int), f );
+ if ( tag != MAKEID('J','S','A','V') )
+ {
+ return 0;
+ }
+
+ g_pFullFileSystem->Read( &tag, sizeof(int), f );
+ if ( tag != SAVEGAME_VERSION ) // Enforce version for now
+ {
+ return 0;
+ }
+
+ g_pFullFileSystem->Read( &size, sizeof(int), f );
+
+ g_pFullFileSystem->Read( &tokenCount, sizeof(int), f ); // These two ints are the token list
+ g_pFullFileSystem->Read( &tokenSize, sizeof(int), f );
+ size += tokenSize;
+
+ // Sanity Check.
+ if ( tokenCount < 0 || tokenCount > 1024*1024*32 )
+ {
+ return 0;
+ }
+
+ if ( tokenSize < 0 || tokenSize > 1024*1024*32 )
+ {
+ return 0;
+ }
+
+ pSaveData = (char *)new char[size];
+ g_pFullFileSystem->Read(pSaveData, size, f);
+
+ int nNumberOfFields;
+
+ char *pData;
+ int nFieldSize;
+
+ pData = pSaveData;
+
+ // Allocate a table for the strings, and parse the table
+ if ( tokenSize > 0 )
+ {
+ pTokenList = new char *[tokenCount];
+
+ // Make sure the token strings pointed to by the pToken hashtable.
+ for( i=0; i<tokenCount; i++ )
+ {
+ pTokenList[i] = *pData ? pData : NULL; // Point to each string in the pToken table
+ while( *pData++ ); // Find next token (after next null)
+ }
+ }
+ else
+ pTokenList = NULL;
+
+ // short, short (size, index of field name)
+ nFieldSize = *(short *)pData;
+ pData += sizeof(short);
+ pFieldName = pTokenList[ *(short *)pData ];
+
+ if (stricmp(pFieldName, "GameHeader"))
+ {
+ delete[] pSaveData;
+ return 0;
+ };
+
+ // int (fieldcount)
+ pData += sizeof(short);
+ nNumberOfFields = *(int*)pData;
+ pData += nFieldSize;
+
+ // Each field is a short (size), short (index of name), binary string of "size" bytes (data)
+ for (i = 0; i < nNumberOfFields; i++)
+ {
+ // Data order is:
+ // Size
+ // szName
+ // Actual Data
+
+ nFieldSize = *(short *)pData;
+ pData += sizeof(short);
+
+ pFieldName = pTokenList[ *(short *)pData ];
+ pData += sizeof(short);
+
+ if (!stricmp(pFieldName, "comment"))
+ {
+ int copySize = MAX(commentSize, nFieldSize);
+ Q_strncpy(comment, pData, copySize);
+ }
+ else if (!stricmp(pFieldName, "mapName"))
+ {
+ int copySize = MAX(nameSize, nFieldSize);
+ Q_strncpy(name, pData, copySize);
+ };
+
+ // Move to Start of next field.
+ pData += nFieldSize;
+ };
+
+ // Delete the string table we allocated
+ delete[] pTokenList;
+ delete[] pSaveData;
+
+ if (strlen(name) > 0 && strlen(comment) > 0)
+ return 1;
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes an existing save game
+//-----------------------------------------------------------------------------
+void CBaseSaveGameDialog::DeleteSaveGame( const char *fileName )
+{
+ if ( !fileName || !fileName[0] )
+ return;
+
+ // delete the save game file
+ g_pFullFileSystem->RemoveFile( fileName, "MOD" );
+
+ // delete the associated tga
+ char tga[_MAX_PATH];
+ Q_strncpy( tga, fileName, sizeof(tga) );
+ char *ext = strstr( tga, ".sav" );
+ if ( ext )
+ {
+ strcpy( ext, ".tga" );
+ }
+ g_pFullFileSystem->RemoveFile( tga, "MOD" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: One item has been selected
+//-----------------------------------------------------------------------------
+void CBaseSaveGameDialog::OnPanelSelected()
+{
+ SetControlEnabled( "loadsave", true );
+ SetControlEnabled( "delete", true );
+}
+
+
diff --git a/gameui/BaseSaveGameDialog.h b/gameui/BaseSaveGameDialog.h
new file mode 100644
index 0000000..43ac6b4
--- /dev/null
+++ b/gameui/BaseSaveGameDialog.h
@@ -0,0 +1,81 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef BASESAVEGAMEDIALOG_H
+#define BASESAVEGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "vgui/MouseCode.h"
+#include "KeyValues.h"
+#include "utlvector.h"
+
+
+#define SAVEGAME_MAPNAME_LEN 32
+#define SAVEGAME_COMMENT_LEN 80
+#define SAVEGAME_ELAPSED_LEN 32
+
+namespace vgui
+{
+ class Button;
+};
+
+
+struct SaveGameDescription_t
+{
+ char szShortName[64];
+ char szFileName[128];
+ char szMapName[SAVEGAME_MAPNAME_LEN];
+ char szComment[SAVEGAME_COMMENT_LEN];
+ char szType[64];
+ char szElapsedTime[SAVEGAME_ELAPSED_LEN];
+ char szFileTime[32];
+ unsigned int iTimestamp;
+ unsigned int iSize;
+};
+
+
+int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP(nameSize) char *name, int nameSize, OUT_Z_CAP(commentSize) char *comment, int commentSize );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Base class for save & load game dialogs
+//-----------------------------------------------------------------------------
+class CBaseSaveGameDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CBaseSaveGameDialog, vgui::Frame );
+
+public:
+ CBaseSaveGameDialog( vgui::Panel *parent, const char *name );
+ static int __cdecl SaveGameSortFunc( const void *lhs, const void *rhs );
+
+protected:
+ CUtlVector<SaveGameDescription_t> m_SaveGames;
+ vgui::PanelListPanel *m_pGameList;
+
+ virtual void OnScanningSaveGames() {}
+
+ void DeleteSaveGame( const char *fileName );
+ void ScanSavedGames();
+ void CreateSavedGamesList();
+ int GetSelectedItemSaveIndex();
+ void AddSaveGameItemToList( int saveIndex );
+
+ bool ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t &save );
+
+ void OnKeyCodeTyped( vgui::KeyCode code );
+ void OnKeyCodePressed( vgui::KeyCode code );
+
+private:
+ MESSAGE_FUNC( OnPanelSelected, "PanelSelected" );
+
+ vgui::Button *m_pLoadButton;
+};
+
+
+#endif // BASESAVEGAMEDIALOG_H
diff --git a/gameui/BenchmarkDialog.cpp b/gameui/BenchmarkDialog.cpp
new file mode 100644
index 0000000..9cf0a1a
--- /dev/null
+++ b/gameui/BenchmarkDialog.cpp
@@ -0,0 +1,130 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BenchmarkDialog.h"
+#include "EngineInterface.h"
+#include "BasePanel.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include "filesystem.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/CheckButton.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CBenchmarkDialog::CBenchmarkDialog(vgui::Panel *parent, const char *name) : BaseClass(parent, name)
+{
+ Button *button = new Button(this, "RunButton", "RunButton");
+ button->SetCommand(new KeyValues("RunBenchmark"));
+ SetSizeable(false);
+ SetDeleteSelfOnClose(true);
+
+ LoadControlSettings("Resource/BenchmarkDialog.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Launches the benchmark
+//-----------------------------------------------------------------------------
+void CBenchmarkDialog::RunBenchmark()
+{
+ // apply settings
+ BasePanel()->ApplyOptionsDialogSettings();
+
+ // launch the map
+ engine->ClientCmd_Unrestricted("disconnect\n");
+ engine->ClientCmd_Unrestricted("wait\n");
+ engine->ClientCmd_Unrestricted("wait\n");
+ engine->ClientCmd_Unrestricted("maxplayers 1\n");
+ engine->ClientCmd_Unrestricted("progress_enable\n");
+ engine->ClientCmd_Unrestricted("map test_hardware\n");
+
+ // close this dialog
+ Close();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays benchmark results
+//-----------------------------------------------------------------------------
+class CBenchmarkResultsDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CBenchmarkResultsDialog, vgui::Frame );
+public:
+ CBenchmarkResultsDialog( vgui::Panel *parent, const char *name ) : BaseClass( parent, name )
+ {
+ SetTitle("#GameUI_BenchmarkResults_Title", true);
+ SetDeleteSelfOnClose(true);
+ SetSizeable(false);
+
+ m_pUploadCheck = new CheckButton( this, "UploadCheck", "#GameUI_BenchmarkResults_UploadNow" );
+
+ LoadControlSettings("Resource/BenchmarkResultsDialog.res");
+
+ m_pUploadCheck->SetSelected( true );
+ MoveToCenterOfScreen();
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+
+ KeyValues *kv = new KeyValues( "Benchmark" );
+ if ( kv->LoadFromFile( g_pFullFileSystem, "results/results.txt", "MOD" ) )
+ {
+ // get the framerate
+ char szFrameRate[32];
+ Q_snprintf( szFrameRate, sizeof(szFrameRate), "%.2f", kv->GetFloat("framerate") );
+ SetDialogVariable( "framerate", szFrameRate );
+ }
+ else
+ {
+ Close();
+ }
+ kv->deleteThis();
+ }
+
+ void OnKeyCodePressed( KeyCode code )
+ {
+ if ( code == KEY_XBUTTON_B )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+private:
+ virtual void OnClose()
+ {
+ if ( m_pUploadCheck->IsSelected() )
+ {
+ engine->ClientCmd_Unrestricted( "bench_upload\n" );
+ }
+ BaseClass::OnClose();
+ }
+
+ vgui::CheckButton *m_pUploadCheck;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Launches the stats dialog
+//-----------------------------------------------------------------------------
+CON_COMMAND_F( bench_showstatsdialog, "Shows a dialog displaying the most recent benchmark results.", FCVAR_CHEAT )
+{
+ static vgui::DHANDLE<CBenchmarkResultsDialog> g_BenchmarkResultsDialog;
+
+ if (!g_BenchmarkResultsDialog.Get())
+ {
+ g_BenchmarkResultsDialog = new CBenchmarkResultsDialog( BasePanel(), "BenchmarkResultsDialog" );
+ }
+
+ g_BenchmarkResultsDialog->Activate();
+}
diff --git a/gameui/BenchmarkDialog.h b/gameui/BenchmarkDialog.h
new file mode 100644
index 0000000..5e323fe
--- /dev/null
+++ b/gameui/BenchmarkDialog.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef BENCHMARKDIALOG_H
+#define BENCHMARKDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Benchmark launch dialog
+//-----------------------------------------------------------------------------
+class CBenchmarkDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CBenchmarkDialog, vgui::Frame );
+public:
+ CBenchmarkDialog(vgui::Panel *parent, const char *name);
+
+ void OnKeyCodePressed( vgui::KeyCode code )
+ {
+ if ( code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B )
+ {
+ Close();
+ }
+ else if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ RunBenchmark();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+private:
+ MESSAGE_FUNC( RunBenchmark, "RunBenchmark" );
+};
+
+
+#endif // BENCHMARKDIALOG_H
diff --git a/gameui/BitmapImagePanel.cpp b/gameui/BitmapImagePanel.cpp
new file mode 100644
index 0000000..b2b3545
--- /dev/null
+++ b/gameui/BitmapImagePanel.cpp
@@ -0,0 +1,78 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BitmapImagePanel.h"
+#include <vgui/ISurface.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+CBitmapImagePanel::CBitmapImagePanel( Panel *parent, char const *panelName,
+ char const *filename /*= NULL*/ ) : Panel( parent, panelName )
+{
+ m_szTexture[ 0 ] = 0;
+ m_bUploaded = false;
+ m_nTextureId = -1;
+
+ SetBounds( 0, 0, 100, 100 );
+
+ if ( filename && filename[ 0 ] )
+ {
+ Q_strncpy( m_szTexture, filename, sizeof( m_szTexture ) );
+ }
+}
+
+void CBitmapImagePanel::PaintBackground()
+{
+ if (!m_szTexture[0])
+ return;
+
+ if ( !m_bUploaded )
+ forceUpload();
+
+ int w, h;
+ GetSize( w, h );
+ surface()->DrawSetColor( Color( 255, 255, 255, 255 ) );
+ surface()->DrawSetTexture( m_nTextureId );
+ surface()->DrawTexturedRect( 0, 0, w, h );
+}
+
+void CBitmapImagePanel::setTexture( char const *filename )
+{
+ Q_strncpy( m_szTexture, filename, sizeof( m_szTexture ) );
+
+ if ( m_bUploaded )
+ {
+ forceReload();
+ }
+ else
+ {
+ forceUpload();
+ }
+}
+
+void CBitmapImagePanel::forceUpload()
+{
+ if ( !m_szTexture[ 0 ] )
+ return;
+
+ m_bUploaded = true;
+
+ m_nTextureId = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_nTextureId, m_szTexture, false, true);
+}
+
+void CBitmapImagePanel::forceReload( void )
+{
+ if ( !m_bUploaded )
+ return;
+
+ // Force texture to re-upload to video card
+ surface()->DrawSetTextureFile( m_nTextureId, m_szTexture, false, true);
+}
diff --git a/gameui/BitmapImagePanel.h b/gameui/BitmapImagePanel.h
new file mode 100644
index 0000000..ce5f28f
--- /dev/null
+++ b/gameui/BitmapImagePanel.h
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BITMAPIMAGEPANEL_H
+#define BITMAPIMAGEPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+
+class CBitmapImagePanel : public vgui::Panel
+{
+public:
+ CBitmapImagePanel( vgui::Panel *parent, char const *panelName, char const *filename = NULL );
+
+ virtual void PaintBackground();
+
+ virtual void setTexture( char const *filename );
+
+ virtual void forceReload( void );
+
+private:
+ typedef vgui::Panel BaseClass;
+
+ void forceUpload();
+
+ bool m_bUploaded;
+ int m_nTextureId;
+ char m_szTexture[ 128 ];
+};
+
+#endif // BITMAPIMAGEPANEL_H
diff --git a/gameui/BonusMapsDatabase.cpp b/gameui/BonusMapsDatabase.cpp
new file mode 100644
index 0000000..7e394ed
--- /dev/null
+++ b/gameui/BonusMapsDatabase.cpp
@@ -0,0 +1,916 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BonusMapsDatabase.h"
+#include "EngineInterface.h"
+
+#include "tier1/convar.h"
+#include "tier1/utlbuffer.h"
+
+#include "filesystem.h"
+#include "ModInfo.h"
+#include "EngineInterface.h"
+#include "ixboxsystem.h"
+#include "KeyValues.h"
+#include "BasePanel.h"
+#include "GameUI_Interface.h"
+#include "BonusMapsDialog.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#define MOD_DIR ( IsXbox() ? "DEFAULT_WRITE_PATH" : "MOD" )
+
+
+const char g_pszMedalNames[4][8] =
+{
+ "none",
+ "bronze",
+ "silver",
+ "gold"
+};
+
+
+const char *COM_GetModDirectory();
+
+
+bool WriteBonusMapSavedData( KeyValues *data )
+{
+ if ( IsX360() && ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ) )
+ return false;
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ data->RecursiveSaveToFile( buf, 0 );
+
+ char szFilename[_MAX_PATH];
+
+ if ( IsX360() )
+ Q_snprintf( szFilename, sizeof( szFilename ), "cfg:/bonus_maps_data.bmd" );
+ else
+ Q_snprintf( szFilename, sizeof( szFilename ), "save/bonus_maps_data.bmd" );
+
+ bool bWriteSuccess = g_pFullFileSystem->WriteFile( szFilename, MOD_DIR, buf );
+
+ xboxsystem->FinishContainerWrites();
+
+ return bWriteSuccess;
+}
+
+void GetBooleanStatus( KeyValues *pBonusFilesKey, BonusMapDescription_t &map )
+{
+ KeyValues *pFileKey = NULL;
+ KeyValues *pBonusKey = NULL;
+
+ for ( pFileKey = pBonusFilesKey->GetFirstSubKey(); pFileKey; pFileKey = pFileKey->GetNextTrueSubKey() )
+ {
+ if ( Q_strcmp( pFileKey->GetName(), map.szFileName ) == 0 )
+ {
+ for ( pBonusKey = pFileKey->GetFirstSubKey(); pBonusKey; pBonusKey = pBonusKey->GetNextKey() )
+ {
+ if ( Q_strcmp( pBonusKey->GetName(), map.szMapName ) == 0 )
+ {
+ // Found the data
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( pBonusKey )
+ {
+ map.bLocked = ( pBonusKey->GetInt( "lock" ) != 0 );
+ map.bComplete = ( pBonusKey->GetInt( "complete" ) != 0 );
+ }
+}
+
+bool SetBooleanStatus( KeyValues *pBonusFilesKey, const char *pchName, const char *pchFileName, const char *pchMapName, bool bValue )
+{
+ // Don't create entries for files that don't exist
+ if ( !IsX360() && ! (g_pFullFileSystem->FileExists( pchFileName, "MOD" ) || g_pFullFileSystem->IsDirectory( pchFileName, "MOD" ) ) )
+ {
+ DevMsg( "Failed to set boolean status for file %s.", pchFileName );
+ return false;
+ }
+
+ bool bChanged = false;
+
+ KeyValues *pFileKey = NULL;
+ KeyValues *pBonusKey = NULL;
+
+ for ( pFileKey = pBonusFilesKey->GetFirstSubKey(); pFileKey; pFileKey = pFileKey->GetNextTrueSubKey() )
+ {
+ if ( Q_strcmp( pFileKey->GetName(), pchFileName ) == 0 )
+ {
+ for ( pBonusKey = pFileKey->GetFirstSubKey(); pBonusKey; pBonusKey = pBonusKey->GetNextKey() )
+ {
+ if ( Q_strcmp( pBonusKey->GetName(), pchMapName ) == 0 )
+ {
+ // Found the data
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( !pFileKey )
+ {
+ // Didn't find it, so create a new spot for the data
+ pFileKey = new KeyValues( pchFileName );
+ pBonusFilesKey->AddSubKey( pFileKey );
+ }
+
+ if ( !pBonusKey )
+ {
+ pBonusKey = new KeyValues( pchMapName, pchName, "0" );
+ pFileKey->AddSubKey( pBonusKey );
+ bChanged = true;
+ }
+
+ if ( ( pBonusKey->GetInt( pchName ) != 0 ) != bValue )
+ {
+ bChanged = true;
+ pBonusKey->SetInt( pchName, bValue );
+ }
+
+ return bChanged;
+}
+
+float GetChallengeBests( KeyValues *pBonusFilesKey, BonusMapDescription_t &challenge )
+{
+ // There's no challenges, so bail and assume 0% challenge completion
+ if ( challenge.m_pChallenges == NULL || challenge.m_pChallenges->Count() == 0 )
+ return 0.0f;
+
+ KeyValues *pFileKey = NULL;
+ KeyValues *pBonusKey = NULL;
+
+ for ( pFileKey = pBonusFilesKey->GetFirstSubKey(); pFileKey; pFileKey = pFileKey->GetNextTrueSubKey() )
+ {
+ if ( Q_strcmp( pFileKey->GetName(), challenge.szFileName ) == 0 )
+ {
+ for ( pBonusKey = pFileKey->GetFirstSubKey(); pBonusKey; pBonusKey = pBonusKey->GetNextKey() )
+ {
+ if ( Q_strcmp( pBonusKey->GetName(), challenge.szMapName ) == 0 )
+ {
+ // Found the data
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ float fChallengePoints = 0.0f;
+
+ for ( int iChallenge = 0; iChallenge < challenge.m_pChallenges->Count(); ++iChallenge )
+ {
+ ChallengeDescription_t *pChallengeDescription = &((*challenge.m_pChallenges)[ iChallenge ]);
+ pChallengeDescription->iBest = ( ( pBonusKey ) ? ( pBonusKey->GetInt( pChallengeDescription->szName, -1 ) ) : ( -1 ) );
+
+ if ( pChallengeDescription->iBest >= 0 )
+ {
+ if ( pChallengeDescription->iBest <= pChallengeDescription->iGold )
+ fChallengePoints += 3.0f;
+ else if ( pChallengeDescription->iBest <= pChallengeDescription->iSilver )
+ fChallengePoints += 2.0f;
+ else if ( pChallengeDescription->iBest <= pChallengeDescription->iBronze )
+ fChallengePoints += 1.0f;
+ }
+ }
+
+ return fChallengePoints / ( challenge.m_pChallenges->Count() * 3.0f );
+}
+
+bool UpdateChallengeBest( KeyValues *pBonusFilesKey, const BonusMapChallenge_t &challenge )
+{
+ // Don't create entries for files that don't exist
+ if ( !IsX360() && !g_pFullFileSystem->FileExists( challenge.szFileName, "MOD" ) )
+ {
+ DevMsg( "Failed to set challenge best for file %s.", challenge.szFileName );
+ return false;
+ }
+
+ bool bChanged = false;
+
+ KeyValues *pFileKey = NULL;
+ KeyValues *pBonusKey = NULL;
+
+ for ( pFileKey = pBonusFilesKey->GetFirstSubKey(); pFileKey; pFileKey = pFileKey->GetNextTrueSubKey() )
+ {
+ if ( Q_strcmp( pFileKey->GetName(), challenge.szFileName ) == 0 )
+ {
+ for ( pBonusKey = pFileKey->GetFirstSubKey(); pBonusKey; pBonusKey = pBonusKey->GetNextKey() )
+ {
+ if ( Q_strcmp( pBonusKey->GetName(), challenge.szMapName ) == 0 )
+ {
+ // Found the challenge
+ break;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( !pFileKey )
+ {
+ // Didn't find it, so create a new spot for data
+ pFileKey = new KeyValues( challenge.szFileName );
+ pBonusFilesKey->AddSubKey( pFileKey );
+ }
+
+ if ( !pBonusKey )
+ {
+ pBonusKey = new KeyValues( challenge.szMapName, challenge.szChallengeName, -1 );
+ pFileKey->AddSubKey( pBonusKey );
+ bChanged = true;
+ }
+
+ int iCurrentBest = pBonusKey->GetInt( challenge.szChallengeName, -1 );
+ if ( iCurrentBest == -1 || iCurrentBest > challenge.iBest )
+ {
+ bChanged = true;
+ pBonusKey->SetInt( challenge.szChallengeName, challenge.iBest );
+ }
+
+ return bChanged;
+}
+
+void GetChallengeMedals( ChallengeDescription_t *pChallengeDescription, int &iBest, int &iEarnedMedal, int &iNext, int &iNextMedal )
+{
+ iBest = pChallengeDescription->iBest;
+
+ if ( iBest == -1 )
+ iEarnedMedal = 0;
+ else if ( iBest <= pChallengeDescription->iGold )
+ iEarnedMedal = 3;
+ else if ( iBest <= pChallengeDescription->iSilver )
+ iEarnedMedal = 2;
+ else if ( iBest <= pChallengeDescription->iBronze )
+ iEarnedMedal = 1;
+ else
+ iEarnedMedal = 0;
+
+ iNext = -1;
+
+ switch ( iEarnedMedal )
+ {
+ case 0:
+ iNext = pChallengeDescription->iBronze;
+ iNextMedal = 1;
+ break;
+ case 1:
+ iNext = pChallengeDescription->iSilver;
+ iNextMedal = 2;
+ break;
+ case 2:
+ iNext = pChallengeDescription->iGold;
+ iNextMedal = 3;
+ break;
+ case 3:
+ iNext = -1;
+ iNextMedal = -1;
+ break;
+ }
+}
+
+
+CBonusMapsDatabase *g_pBonusMapsDatabase = NULL;
+
+CBonusMapsDatabase *BonusMapsDatabase( void )
+{
+ if ( !g_pBonusMapsDatabase )
+ static CBonusMapsDatabase StaticBonusMapsDatabase;
+
+ return g_pBonusMapsDatabase;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:Constructor
+//-----------------------------------------------------------------------------
+CBonusMapsDatabase::CBonusMapsDatabase( void )
+{
+ Assert( g_pBonusMapsDatabase == NULL ); // There should only be 1 bonus maps database
+ g_pBonusMapsDatabase = this;
+
+ RootPath();
+
+ m_pBonusMapsManifest = new KeyValues( "bonus_maps_manifest" );
+ m_pBonusMapsManifest->LoadFromFile( g_pFullFileSystem, "scripts/bonus_maps_manifest.txt", NULL );
+
+ m_iX360BonusesUnlocked = -1; // Only used on X360
+ m_bHasLoadedSaveData = false;
+
+ ReadBonusMapSaveData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBonusMapsDatabase::~CBonusMapsDatabase()
+{
+ g_pBonusMapsDatabase = NULL;
+}
+
+extern bool g_bIsCreatingNewGameMenuForPreFetching;
+
+bool CBonusMapsDatabase::ReadBonusMapSaveData( void )
+{
+ if ( !m_pBonusMapSavedData )
+ m_pBonusMapSavedData = new KeyValues( "bonus_map_saved_data" );
+
+ if ( g_bIsCreatingNewGameMenuForPreFetching )
+ {
+ // Although we may have a storage device it's not going to be able to find our file at this point! BAIL!
+ return false;
+ }
+
+#ifdef _X360
+ // Nothing to read
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
+ return false;
+#endif
+
+ char szFilename[_MAX_PATH];
+
+ if ( IsX360() )
+ Q_snprintf( szFilename, sizeof( szFilename ), "cfg:/bonus_maps_data.bmd" );
+ else
+ Q_snprintf( szFilename, sizeof( szFilename ), "save/bonus_maps_data.bmd" );
+
+ m_pBonusMapSavedData->LoadFromFile( g_pFullFileSystem, szFilename, NULL );
+
+ m_bSavedDataChanged = false;
+ m_bHasLoadedSaveData = true;
+
+ return true;
+}
+
+bool CBonusMapsDatabase::WriteSaveData( void )
+{
+ bool bSuccess = false;
+
+ if ( m_bSavedDataChanged )
+ bSuccess = WriteBonusMapSavedData( m_pBonusMapSavedData );
+
+ if ( bSuccess )
+ m_bSavedDataChanged = false;
+
+ return bSuccess;
+}
+
+void CBonusMapsDatabase::RootPath( void )
+{
+ m_iDirDepth = 0;
+ V_strcpy_safe( m_szCurrentPath, "." );
+}
+
+void CBonusMapsDatabase::AppendPath( const char *pchAppend )
+{
+ ++m_iDirDepth;
+ char szCurPathTmp[MAX_PATH];
+ V_strcpy_safe( szCurPathTmp, m_szCurrentPath );
+ Q_snprintf( m_szCurrentPath, sizeof( m_szCurrentPath ), "%s/%s", szCurPathTmp, pchAppend );
+}
+
+void CBonusMapsDatabase::BackPath( void )
+{
+ if ( m_iDirDepth == 0 )
+ return;
+
+ if ( m_iDirDepth == 1 )
+ {
+ RootPath(); // back to root
+ return;
+ }
+
+ --m_iDirDepth;
+ Q_strrchr( m_szCurrentPath, '/' )[ 0 ] = '\0'; // remove a dir from the end
+}
+
+void CBonusMapsDatabase::SetPath( const char *pchPath, int iDirDepth )
+{
+ V_strcpy_safe( m_szCurrentPath, pchPath );
+ m_iDirDepth = iDirDepth;
+}
+
+void CBonusMapsDatabase::ClearBonusMapsList( void )
+{
+ m_BonusMaps.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: builds bonus map list from directory
+//-----------------------------------------------------------------------------
+void CBonusMapsDatabase::ScanBonusMaps( void )
+{
+ // Don't load in the bonus maps before we've properly read in the save data
+ if ( !m_bHasLoadedSaveData )
+ {
+ if ( ! ReadBonusMapSaveData() )
+ return;
+ }
+
+ char *pCurrentPath = &(m_szCurrentPath[2]);
+
+ // Reset completion percentage
+ m_iCompletableLevels = 0;
+ m_fCurrentCompletion = 0.0f;
+
+ // populate list box with all bonus maps in the current path
+ char szDirectory[_MAX_PATH];
+
+ if ( Q_strcmp( m_szCurrentPath, "." ) == 0 )
+ {
+ // We're at the root, so look at the directories in the manifest
+ KeyValues *pKey = NULL;
+ for ( pKey = m_pBonusMapsManifest->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey() )
+ {
+ const char *pchType = pKey->GetName();
+ if ( Q_strcmp( pchType, "search" ) == 0 )
+ {
+ // Search through the directory
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s/", pKey->GetString() );
+
+ BuildSubdirectoryList( szDirectory, true );
+ BuildBonusMapsList( szDirectory, true );
+ }
+ else if ( Q_strcmp( pchType, "dir" ) == 0 )
+ {
+ AddBonus( "", pKey->GetString(), true );
+ }
+ else if ( Q_strcmp( pchType, "map" ) == 0 )
+ {
+ AddBonus( "", pKey->GetString(), false );
+ }
+ }
+ }
+ else
+ {
+ // Search through the current directory
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s/", pCurrentPath );
+
+ BuildSubdirectoryList( szDirectory, false );
+ BuildBonusMapsList( szDirectory, false );
+ }
+}
+
+void CBonusMapsDatabase::RefreshMapData( void )
+{
+ // Reset completion percentage
+ m_iCompletableLevels = 0;
+ m_fCurrentCompletion = 0.0f;
+
+ for ( int iMap = 0; iMap < m_BonusMaps.Count(); ++iMap )
+ {
+ BonusMapDescription_t *pMap = &m_BonusMaps[ iMap ];
+
+ float fCompletion = GetChallengeBests( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), *pMap );
+
+ // If all the challenges are completed set it as complete
+ if ( fCompletion == 1.0f )
+ SetBooleanStatus( "complete", pMap->szFileName, pMap->szMapName, true );
+
+ GetBooleanStatus( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), *pMap );
+
+ if ( pMap->bComplete )
+ fCompletion = 1.0f;
+
+ if ( !pMap->bIsFolder )
+ {
+ m_fCurrentCompletion += fCompletion;
+ ++m_iCompletableLevels;
+ }
+ }
+}
+
+int CBonusMapsDatabase::BonusCount( void )
+{
+ if ( m_BonusMaps.Count() == 0 )
+ ScanBonusMaps();
+
+ return m_BonusMaps.Count();
+}
+
+bool CBonusMapsDatabase::GetBlink( void )
+{
+ KeyValues *pBlinkKey = m_pBonusMapSavedData->FindKey( "blink" );
+ if ( !pBlinkKey )
+ return false;
+
+ return ( pBlinkKey->GetInt() != 0 );
+}
+
+void CBonusMapsDatabase::SetBlink( bool bState )
+{
+ KeyValues *pBlinkKey = m_pBonusMapSavedData->FindKey( "blink" );
+ if ( pBlinkKey )
+ {
+ bool bCurrentState = ( pBlinkKey->GetInt() != 0 );
+ if ( bState && !bCurrentState )
+ {
+ pBlinkKey->SetStringValue( "1" );
+ m_bSavedDataChanged = true;
+ }
+ else if ( !bState && bCurrentState )
+ {
+ pBlinkKey->SetStringValue( "0" );
+ m_bSavedDataChanged = true;
+ }
+ }
+}
+
+// Only used on X360
+bool CBonusMapsDatabase::BonusesUnlocked( void )
+{
+ if ( m_iX360BonusesUnlocked == -1 )
+ {
+ // Never checked, so set up the proper X360 scan
+ BonusMapsDatabase()->ClearBonusMapsList(); // clear the current list
+ BonusMapsDatabase()->RootPath();
+ BonusMapsDatabase()->ScanBonusMaps();
+
+ m_iX360BonusesUnlocked = 0;
+ }
+
+ if ( m_iX360BonusesUnlocked == 0 )
+ {
+ // Hasn't been recorded as unlocked yet
+ for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap )
+ {
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap );
+ if ( Q_strcmp( pMap->szMapName, "#Bonus_Map_AdvancedChambers" ) == 0 && !pMap->bLocked )
+ {
+ // All bonuses unlocked, remember this and set up the proper X360 scan to get info.
+ m_iX360BonusesUnlocked = 1;
+ break;
+ }
+ }
+ }
+
+ return ( m_iX360BonusesUnlocked != 0 );
+}
+
+void CBonusMapsDatabase::SetCurrentChallengeNames( const char *pchFileName, const char *pchMapName, const char *pchChallengeName )
+{
+ V_strcpy_safe( m_CurrentChallengeNames.szFileName, pchFileName );
+ V_strcpy_safe( m_CurrentChallengeNames.szMapName, pchMapName );
+ V_strcpy_safe( m_CurrentChallengeNames.szChallengeName, pchChallengeName );
+}
+
+void CBonusMapsDatabase::GetCurrentChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName )
+{
+ Q_strcpy( pchFileName, m_CurrentChallengeNames.szFileName );
+ Q_strcpy( pchMapName, m_CurrentChallengeNames.szMapName );
+ Q_strcpy( pchChallengeName, m_CurrentChallengeNames.szChallengeName );
+}
+
+void CBonusMapsDatabase::SetCurrentChallengeObjectives( int iBronze, int iSilver, int iGold )
+{
+ m_CurrentChallengeObjectives.iBronze = iBronze;
+ m_CurrentChallengeObjectives.iSilver = iSilver;
+ m_CurrentChallengeObjectives.iGold = iGold;
+}
+
+void CBonusMapsDatabase::GetCurrentChallengeObjectives( int &iBronze, int &iSilver, int &iGold )
+{
+ iBronze = m_CurrentChallengeObjectives.iBronze;
+ iSilver = m_CurrentChallengeObjectives.iSilver;
+ iGold = m_CurrentChallengeObjectives.iGold;
+}
+
+bool CBonusMapsDatabase::SetBooleanStatus( const char *pchName, const char *pchFileName, const char *pchMapName, bool bValue )
+{
+ bool bChanged = ::SetBooleanStatus( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), pchName, pchFileName, pchMapName, bValue );
+ if ( bChanged )
+ m_bSavedDataChanged = true;
+
+ return bChanged;
+}
+
+bool CBonusMapsDatabase::SetBooleanStatus( const char *pchName, int iIndex, bool bValue )
+{
+ BonusMapDescription_t *pMap = &(m_BonusMaps[iIndex]);
+
+ bool bChanged = SetBooleanStatus( pchName, pMap->szFileName, pMap->szMapName, bValue );
+ GetBooleanStatus( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), *pMap );
+
+ return bChanged;
+}
+
+bool CBonusMapsDatabase::UpdateChallengeBest( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest )
+{
+ BonusMapChallenge_t challenge;
+ V_strcpy_safe( challenge.szFileName, pchFileName );
+ V_strcpy_safe( challenge.szMapName, pchMapName );
+ V_strcpy_safe( challenge.szChallengeName, pchChallengeName );
+ challenge.iBest = iBest;
+
+ bool bChanged = ::UpdateChallengeBest( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), challenge );
+ if ( bChanged )
+ m_bSavedDataChanged = true;
+
+ return bChanged;
+}
+
+float CBonusMapsDatabase::GetCompletionPercentage( void )
+{
+ // Avoid divide by zero
+ if ( m_iCompletableLevels <= 0 )
+ return 0.0f;
+
+ return m_fCurrentCompletion / m_iCompletableLevels;
+}
+
+int CBonusMapsDatabase::NumAdvancedComplete( void )
+{
+ char szCurrentPath[_MAX_PATH];
+ V_strcpy_safe( szCurrentPath, m_szCurrentPath );
+ int iDirDepth = m_iDirDepth;
+
+ BonusMapsDatabase()->ClearBonusMapsList();
+ SetPath( "./scripts/advanced_chambers", 1 );
+ ScanBonusMaps();
+
+ int iNumComplete = 0;
+
+ // Look through all the bonus maps
+ for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap )
+ {
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap );
+
+ if ( pMap && Q_strstr( pMap->szMapName, "Advanced" ) != NULL )
+ {
+ // It's an advanced map, so check if it's complete
+ if ( pMap->bComplete )
+ ++iNumComplete;
+ }
+ }
+
+ BonusMapsDatabase()->ClearBonusMapsList();
+ SetPath( szCurrentPath, iDirDepth );
+ ScanBonusMaps();
+
+ return iNumComplete;
+}
+
+void CBonusMapsDatabase::NumMedals( int piNumMedals[ 3 ] )
+{
+ char szCurrentPath[_MAX_PATH];
+ V_strcpy_safe( szCurrentPath, m_szCurrentPath );
+ int iDirDepth = m_iDirDepth;
+
+ BonusMapsDatabase()->ClearBonusMapsList();
+ SetPath( "./scripts/challenges", 1 );
+ ScanBonusMaps();
+
+ for ( int i = 0; i < 3; ++i )
+ piNumMedals[ i ] = 0;
+
+ // Look through all the bonus maps
+ for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap )
+ {
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap );
+
+ if ( pMap && pMap->m_pChallenges )
+ {
+ for ( int iChallenge = 0; iChallenge < pMap->m_pChallenges->Count(); ++iChallenge )
+ {
+ ChallengeDescription_t *pChallengeDescription = &((*pMap->m_pChallenges)[ iChallenge ]);
+
+ int iBest, iEarnedMedal, iNext, iNextMedal;
+ GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal );
+
+ // Increase the count for this medal and every medal below it
+ while ( iEarnedMedal > 0 )
+ {
+ --iEarnedMedal; // Medals are 1,2&3 so subtract 1 first
+ piNumMedals[ iEarnedMedal ]++;
+ }
+ }
+ }
+ }
+
+ BonusMapsDatabase()->ClearBonusMapsList();
+ SetPath( szCurrentPath, iDirDepth );
+ ScanBonusMaps();
+}
+
+
+void CBonusMapsDatabase::AddBonus( const char *pCurrentPath, const char *pDirFileName, bool bIsFolder )
+{
+ char szFileName[_MAX_PATH];
+ Q_snprintf( szFileName, sizeof( szFileName ), "%s%s", pCurrentPath, pDirFileName );
+
+ // Only load bonus maps from the current mod's maps dir
+ if( !IsX360() && !( g_pFullFileSystem->IsDirectory( szFileName, "MOD" ) || g_pFullFileSystem->FileExists( szFileName, "MOD" ) ))
+ return;
+
+ ParseBonusMapData( szFileName, pDirFileName, bIsFolder );
+}
+
+void CBonusMapsDatabase::BuildSubdirectoryList( const char *pCurrentPath, bool bOutOfRoot )
+{
+ char szDirectory[_MAX_PATH];
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s*", pCurrentPath );
+
+ FileFindHandle_t dirHandle;
+ const char *pDirFileName = g_pFullFileSystem->FindFirst( szDirectory, &dirHandle );
+
+ while (pDirFileName)
+ {
+ // Skip it if it's not a directory, is the root, is back, or is an invalid folder
+ if ( !g_pFullFileSystem->FindIsDirectory( dirHandle ) ||
+ Q_strcmp( pDirFileName, "." ) == 0 ||
+ Q_strcmp( pDirFileName, ".." ) == 0 ||
+ Q_stricmp( pDirFileName, "soundcache" ) == 0 ||
+ Q_stricmp( pDirFileName, "graphs" ) == 0 )
+ {
+ pDirFileName = g_pFullFileSystem->FindNext( dirHandle );
+ continue;
+ }
+
+ if ( !bOutOfRoot )
+ AddBonus( pCurrentPath, pDirFileName, true );
+ else
+ {
+ char szFileName[_MAX_PATH];
+ Q_snprintf( szFileName, sizeof( szFileName ), "%s%s", pCurrentPath, pDirFileName );
+ AddBonus( "", szFileName, true );
+ }
+
+ pDirFileName = g_pFullFileSystem->FindNext( dirHandle );
+ }
+
+ g_pFullFileSystem->FindClose( dirHandle );
+}
+
+void CBonusMapsDatabase::BuildBonusMapsList( const char *pCurrentPath, bool bOutOfRoot )
+{
+ char szDirectory[_MAX_PATH];
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s*.bns", pCurrentPath );
+
+ FileFindHandle_t mapHandle;
+ const char *pMapFileName = g_pFullFileSystem->FindFirst( szDirectory, &mapHandle );
+
+ while ( pMapFileName && Q_strlen(pMapFileName)>0 )
+ {
+ // Skip it if it's a directory or is the folder info
+ if ( g_pFullFileSystem->FindIsDirectory( mapHandle ) || Q_strstr( pMapFileName, "folderinfo.bns" ) )
+ {
+ pMapFileName = g_pFullFileSystem->FindNext( mapHandle );
+ continue;
+ }
+
+ if ( !bOutOfRoot )
+ AddBonus( pCurrentPath, pMapFileName, false );
+ else
+ {
+ char szFileName[_MAX_PATH];
+ Q_snprintf( szFileName, sizeof( szFileName ), "%s%s", pCurrentPath, pMapFileName );
+ AddBonus( "", szFileName, false );
+ }
+
+ pMapFileName = g_pFullFileSystem->FindNext( mapHandle );
+ }
+
+ g_pFullFileSystem->FindClose( mapHandle );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses the save game info out of the .sav file header
+//-----------------------------------------------------------------------------
+void CBonusMapsDatabase::ParseBonusMapData( char const *pszFileName, char const *pszShortName, bool bIsFolder )
+{
+ if ( !pszFileName || !pszShortName )
+ return;
+
+ char szMapInfo[_MAX_PATH];
+
+ // if it's a directory, there's no optional info
+ if ( bIsFolder )
+ {
+ // get the folder info file name
+ Q_snprintf( szMapInfo, sizeof(szMapInfo), "%s/folderinfo.bns", pszFileName );
+ }
+ else
+ {
+ // get the map info file name
+ Q_strncpy( szMapInfo, pszFileName, sizeof(szMapInfo) );
+ }
+
+ KeyValues *kv = new KeyValues( pszShortName );
+ if ( !kv->LoadFromFile( g_pFullFileSystem, szMapInfo, NULL ) )
+ DevMsg( "Unable to load bonus map info file %s\n", szMapInfo );
+
+ while ( kv )
+ {
+ int iMap = m_BonusMaps.AddToTail();
+
+ BonusMapDescription_t *pMap = &m_BonusMaps[ iMap ];
+
+ // set required map data
+ Q_strncpy( pMap->szFileName, pszFileName, sizeof(pMap->szFileName) );
+ Q_strncpy( pMap->szShortName, pszShortName, sizeof(pMap->szShortName) );
+ pMap->bIsFolder = bIsFolder;
+
+ // set optional map data
+ V_strcpy_safe( pMap->szMapName, kv->GetName() );
+ V_strcpy_safe( pMap->szMapFileName, kv->GetString( "map" ) );
+ V_strcpy_safe( pMap->szChapterName, kv->GetString( "chapter" ) );
+ V_strcpy_safe( pMap->szImageName, kv->GetString( "image" ) );
+ V_strcpy_safe( pMap->szComment, kv->GetString( "comment" ) );
+ pMap->bLocked = ( kv->GetInt( "lock", 0 ) != 0 );
+ pMap->bComplete = ( kv->GetInt( "complete", 0 ) != 0 );
+
+ float fCompletion = 0.0f;
+
+ KeyValues *pChallenges = kv->FindKey( "challenges" );
+
+ if ( pChallenges )
+ {
+ for ( KeyValues *pChallengeKey = pChallenges->GetFirstSubKey(); pChallengeKey; pChallengeKey = pChallengeKey->GetNextKey() )
+ {
+ if ( !pMap->m_pChallenges )
+ pMap->m_pChallenges = new CUtlVector<ChallengeDescription_t>;
+
+ int iChallenge = pMap->m_pChallenges->AddToTail();
+
+ ChallengeDescription_t *pChallenge = &(*pMap->m_pChallenges)[ iChallenge ];
+ V_strcpy_safe( pChallenge->szName, pChallengeKey->GetName() );
+ V_strcpy_safe( pChallenge->szComment, pChallengeKey->GetString( "comment" ) );
+ pChallenge->iType = pChallengeKey->GetInt( "type", -1 );
+ pChallenge->iBronze = pChallengeKey->GetInt( "bronze" );
+ pChallenge->iSilver = pChallengeKey->GetInt( "silver" );
+ pChallenge->iGold = pChallengeKey->GetInt( "gold" );
+ }
+
+ fCompletion = GetChallengeBests( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), *pMap );
+
+ // If all the challenges are completed set it as complete
+ if ( fCompletion == 1.0f )
+ SetBooleanStatus( "complete", pMap->szFileName, pMap->szMapName, true );
+ }
+
+ // Get boolean status last because it can be altered if all the challenges were completed
+ GetBooleanStatus( m_pBonusMapSavedData->FindKey( "bonusfiles", true ), *pMap );
+
+ if ( pMap->bComplete )
+ fCompletion = 1.0f;
+
+ if ( !pMap->bIsFolder )
+ {
+ m_fCurrentCompletion += fCompletion;
+ ++m_iCompletableLevels;
+ kv = kv->GetNextTrueSubKey();
+ }
+ else
+ kv = NULL;
+ }
+}
+
+
+void CC_BonusMapUnlock( const CCommand &args )
+{
+ if ( args.ArgC() < 3 )
+ {
+ GameUI().BonusMapUnlock();
+ return;
+ }
+
+ GameUI().BonusMapUnlock( args[ 1 ], args[ 2 ] );
+}
+static ConCommand sv_bonus_map_unlock("sv_bonus_map_unlock", CC_BonusMapUnlock, "Locks a bonus map.", FCVAR_CHEAT );
+
+
+void CC_BonusMapComplete( const CCommand &args )
+{
+ if ( args.ArgC() < 3 )
+ {
+ GameUI().BonusMapComplete();
+ return;
+ }
+
+ GameUI().BonusMapComplete( args[ 1 ], args[ 2 ] );
+}
+static ConCommand sv_bonus_map_complete("sv_bonus_map_complete", CC_BonusMapComplete, "Completes a bonus map.", FCVAR_CHEAT );
+
+
+void CC_BonusMapChallengeUpdate( const CCommand &args )
+{
+ if ( args.ArgC() < 5 )
+ {
+ return;
+ }
+
+ GameUI().BonusMapChallengeUpdate( args[ 1 ], args[ 2 ], args[ 3 ], atoi( args[ 4 ] ) );
+}
+static ConCommand sv_bonus_map_challenge_update("sv_bonus_map_challenge_update", CC_BonusMapChallengeUpdate, "Updates a bonus map challenge score.", FCVAR_CHEAT );
diff --git a/gameui/BonusMapsDatabase.h b/gameui/BonusMapsDatabase.h
new file mode 100644
index 0000000..a3275d3
--- /dev/null
+++ b/gameui/BonusMapsDatabase.h
@@ -0,0 +1,167 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BONUSMAPSDATABASE_H
+#define BONUSMAPSDATABASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+
+#include "utlvector.h"
+
+
+struct ChallengeDescription_t
+{
+ char szName[32];
+ char szComment[256];
+
+ int iType;
+
+ int iBronze;
+ int iSilver;
+ int iGold;
+
+ int iBest;
+};
+
+struct BonusMapDescription_t
+{
+ bool bIsFolder;
+
+ char szShortName[64];
+ char szFileName[128];
+
+ char szMapFileName[128];
+ char szChapterName[128];
+ char szImageName[128];
+
+ char szMapName[64];
+ char szComment[256];
+
+ bool bLocked;
+ bool bComplete;
+
+ CUtlVector<ChallengeDescription_t> *m_pChallenges;
+
+ BonusMapDescription_t( void )
+ {
+ bIsFolder = false;
+
+ szShortName[ 0 ] = '\0';
+ szFileName[ 0 ] = '\0';
+
+ szMapFileName[ 0 ] = '\0';
+ szChapterName[ 0 ] = '\0';
+ szImageName[ 0 ] = '\0';
+
+ szMapName[ 0 ] = '\0';
+ szComment[ 0 ] = '\0';
+
+ bLocked = false;
+ bComplete = false;
+
+ m_pChallenges = NULL;
+ }
+};
+
+struct BonusMapChallenge_t
+{
+ char szFileName[128];
+ char szMapName[32];
+ char szChallengeName[32];
+ int iBest;
+};
+
+
+class KeyValues;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Keeps track of bonus maps on disk
+//-----------------------------------------------------------------------------
+class CBonusMapsDatabase
+{
+
+public:
+ CBonusMapsDatabase( void );
+ ~CBonusMapsDatabase();
+
+ bool ReadBonusMapSaveData( void );
+ bool WriteSaveData( void );
+
+ const char * GetPath( void ) { return m_szCurrentPath; }
+ void RootPath( void );
+ void AppendPath( const char *pchAppend );
+ void BackPath( void );
+ void SetPath( const char *pchPath, int iDirDepth );
+
+ void ClearBonusMapsList( void );
+ void ScanBonusMaps( void );
+ void RefreshMapData( void );
+
+ int BonusCount( void );
+ BonusMapDescription_t * GetBonusData( int iIndex ) { return &(m_BonusMaps[ iIndex ]); }
+ int InvalidIndex( void ) { return m_BonusMaps.InvalidIndex(); }
+ bool IsValidIndex( int iIndex ) { return m_BonusMaps.IsValidIndex( iIndex ); }
+
+ bool GetBlink( void );
+ void SetBlink( bool bState );
+
+ bool BonusesUnlocked( void );
+
+ void SetCurrentChallengeNames( const char *pchFileName, const char *pchMapName, const char *pchChallengeName );
+ void GetCurrentChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName );
+ void SetCurrentChallengeObjectives( int iBronze, int iSilver, int iGold );
+ void GetCurrentChallengeObjectives( int &iBronze, int &iSilver, int &iGold );
+
+ bool SetBooleanStatus( const char *pchName, const char *pchFileName, const char *pchMapName, bool bValue );
+ bool SetBooleanStatus( const char *pchName, int iIndex, bool bValue );
+ bool UpdateChallengeBest( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest );
+
+ float GetCompletionPercentage( void );
+
+ int NumAdvancedComplete( void );
+ void NumMedals( int piNumMedals[ 3 ] );
+
+private:
+
+ void AddBonus( const char *pCurrentPath, const char *pDirFileName, bool bIsFolder );
+ void BuildSubdirectoryList( const char *pCurrentPath, bool bOutOfRoot );
+ void BuildBonusMapsList( const char *pCurrentPath, bool bOutOfRoot );
+
+ void ParseBonusMapData( char const *pszFileName, char const *pszShortName, bool bIsFolder );
+
+private:
+
+ KeyValues *m_pBonusMapsManifest;
+
+ CUtlVector<BonusMapDescription_t> m_BonusMaps;
+
+ KeyValues *m_pBonusMapSavedData;
+ bool m_bSavedDataChanged;
+
+ int m_iX360BonusesUnlocked; // Only used on 360
+ bool m_bHasLoadedSaveData;
+
+ int m_iDirDepth;
+ char m_szCurrentPath[_MAX_PATH];
+ float m_fCurrentCompletion;
+ int m_iCompletableLevels;
+
+ BonusMapChallenge_t m_CurrentChallengeNames;
+ ChallengeDescription_t m_CurrentChallengeObjectives;
+};
+
+
+void GetChallengeMedals( ChallengeDescription_t *pChallengeDescription, int &iBest, int &iEarnedMedal, int &iNext, int &iNextMedal );
+CBonusMapsDatabase *BonusMapsDatabase( void );
+
+extern const char g_pszMedalNames[4][8];
+
+
+#endif // BONUSMAPSDATABASE_H
diff --git a/gameui/BonusMapsDialog.cpp b/gameui/BonusMapsDialog.cpp
new file mode 100644
index 0000000..f5243a7
--- /dev/null
+++ b/gameui/BonusMapsDialog.cpp
@@ -0,0 +1,1006 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BonusMapsDialog.h"
+#include "EngineInterface.h"
+
+#include "vgui/ISystem.h"
+#include "vgui/ISurface.h"
+#include "vgui/IVGui.h"
+#include <vgui/ILocalize.h>
+#include "filesystem.h"
+
+#include "vgui_controls/Button.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/QueryBox.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/BitmapImagePanel.h"
+#include "vgui_controls/FileOpenDialog.h"
+
+#include "TGAImagePanel.h"
+#include "MouseMessageForwardingPanel.h"
+
+#include "BasePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+using namespace vgui;
+
+
+#define MAX_LISTED_BONUS_MAPS 128
+
+
+extern const char *COM_GetModDirectory( void );
+
+
+bool ConstructFullImagePath( const char *pCurrentPath, const char *pchImageName, char *pchImageFileName )
+{
+ char *ext = Q_strstr( pchImageName , ".tga" );
+ if ( ext )
+ {
+ // Use the specified image
+ if ( pchImageName[ 0 ] != '.' )
+ Q_snprintf( pchImageFileName, _MAX_PATH, "%s", pchImageName );
+ else
+ Q_snprintf( pchImageFileName, _MAX_PATH, "%s/%s", pCurrentPath, pchImageName );
+
+ return true;
+ }
+
+ Q_strcpy( pchImageFileName, pchImageName );
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Describes the layout of a same game pic
+//-----------------------------------------------------------------------------
+class CBonusMapPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CBonusMapPanel, vgui::EditablePanel );
+public:
+ CBonusMapPanel( PanelListPanel *parent, const char *name, int bonusMapListItemID ) : BaseClass( parent, name )
+ {
+ m_iBonusMapListItemID = bonusMapListItemID;
+ m_pParent = parent;
+ m_pBonusMapTGAImage = new CTGAImagePanel( this, "BonusMapTGAImage" );
+ m_pBonusMapImage = SETUP_PANEL( new ImagePanel( this, "BonusMapImage" ) );
+ m_pBonusMapScreenshotBackground = SETUP_PANEL( new ImagePanel( this, "BonusMapScreenshotBackground" ) );
+ m_pMapNameLabel = new Label( this, "MapNameLabel", "" );
+ m_pLockIcon = new ImagePanel( this, "LockIcon" );
+ m_pCompleteIcon = new ImagePanel( this, "CompleteIcon" );
+
+ CMouseMessageForwardingPanel *panel = new CMouseMessageForwardingPanel(this, NULL);
+ panel->SetZPos(2);
+
+ SetSize( 200, 140 );
+
+ LoadControlSettings( "resource/BonusMapPanel.res" );
+
+ m_FillColor = m_pBonusMapScreenshotBackground->GetFillColor();
+ }
+
+ void SetBonusMapInfo( const char *pCurrentPath, BonusMapDescription_t &map )
+ {
+ // set the image to display
+ char szImageFileName[_MAX_PATH];
+
+ bool bIsTGA = false;
+
+ if ( map.bIsFolder )
+ {
+ if ( map.szImageName[ 0 ] == '\0' )
+ {
+ // use associate bonus folder icon
+ Q_snprintf( szImageFileName, sizeof(szImageFileName), "%s/foldericon.tga", map.szFileName );
+ bIsTGA = true;
+
+ // use default folder icon
+ if( !g_pFullFileSystem->FileExists( szImageFileName, "MOD" ) )
+ {
+ V_strcpy_safe( szImageFileName, "bonusmaps/icon_bonus_map_folder" );
+ bIsTGA = false;
+ }
+ }
+ else
+ {
+ // Use the specified image
+ bIsTGA = ConstructFullImagePath( pCurrentPath, map.szImageName, szImageFileName );
+ }
+ }
+ else
+ {
+ if ( map.szImageName[ 0 ] == '\0' )
+ {
+ // Didn't specify an image name, so pair it with the name of this file
+ char szImpliedTgaName[_MAX_PATH];
+ Q_snprintf( szImpliedTgaName, sizeof( szImpliedTgaName ), "%s.tga", map.szMapFileName );
+ bIsTGA = ConstructFullImagePath( pCurrentPath, szImpliedTgaName, szImageFileName );
+
+ // if it doesn't exist use default bonus map icon
+ if( !g_pFullFileSystem->FileExists( szImageFileName, "MOD" ) )
+ {
+ V_strcpy_safe( szImageFileName, "bonusmaps/icon_bonus_map_default" );
+ bIsTGA = false;
+ }
+ }
+ else
+ {
+ // Use the specified image
+ bIsTGA = ConstructFullImagePath( pCurrentPath, map.szImageName, szImageFileName );
+ }
+ }
+
+ if ( bIsTGA )
+ {
+ m_pBonusMapTGAImage->SetTGANonMod( szImageFileName );
+ m_pBonusMapTGAImage->SetSize( 180, 100 );
+ m_pBonusMapTGAImage->SetVisible( true );
+ m_pBonusMapImage->SetVisible( false );
+ }
+ else
+ {
+ m_pBonusMapImage->SetImage( szImageFileName );
+ m_pBonusMapImage->SetSize( 180, 100 );
+ m_pBonusMapImage->SetVisible( true );
+ m_pBonusMapTGAImage->SetVisible( false );
+ }
+
+ m_pLockIcon->SetVisible( map.bLocked );
+ m_pCompleteIcon->SetVisible( map.bComplete );
+
+ // set the title text
+ m_pMapNameLabel->SetText( map.szMapName );
+ }
+
+ MESSAGE_FUNC_INT( OnPanelSelected, "PanelSelected", state )
+ {
+ if ( state )
+ {
+ // set the text color to be orange, and the pic border to be orange
+ m_pBonusMapScreenshotBackground->SetFillColor( m_SelectedColor );
+ m_pMapNameLabel->SetFgColor( Color( 0, 0, 0, 255 ) );
+ }
+ else
+ {
+ m_pBonusMapScreenshotBackground->SetFillColor( m_FillColor );
+ m_pMapNameLabel->SetFgColor( m_TextColor );
+ }
+
+ PostMessage( m_pParent->GetVParent(), new KeyValues("PanelSelected") );
+ }
+
+ virtual void OnMousePressed( vgui::MouseCode code )
+ {
+ m_pParent->SetSelectedPanel( this );
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
+ m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+ }
+
+ virtual void OnMouseDoublePressed( vgui::MouseCode code )
+ {
+ // call the panel
+ OnMousePressed( code );
+ PostMessage( m_pParent->GetParent(), new KeyValues("Command", "command", "loadbonusmap") );
+ }
+
+ int GetBonusMapListItemID()
+ {
+ return m_iBonusMapListItemID;
+ }
+
+private:
+ vgui::PanelListPanel *m_pParent;
+ vgui::Label *m_pMapNameLabel;
+ ImagePanel *m_pBonusMapImage;
+ CTGAImagePanel *m_pBonusMapTGAImage;
+
+ ImagePanel *m_pLockIcon;
+ ImagePanel *m_pCompleteIcon;
+
+ // things to change color when the selection changes
+ ImagePanel *m_pBonusMapScreenshotBackground;
+ Color m_TextColor, m_FillColor, m_SelectedColor;
+
+ int m_iBonusMapListItemID;
+};
+
+CBonusMapsDialog *g_pBonusMapsDialog = NULL;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:Constructor
+//-----------------------------------------------------------------------------
+CBonusMapsDialog::CBonusMapsDialog(vgui::Panel *parent) : BaseClass(parent, "BonusMapsDialog")
+{
+ g_pBonusMapsDialog = this;
+ m_hImportBonusMapsDialog = NULL;
+
+ BonusMapsDatabase()->RootPath();
+
+ CreateBonusMapsList();
+
+ BuildMapsList();
+
+ new vgui::Button( this, "loadbonusmap", "" );
+ SetControlEnabled( "loadbonusmap", false );
+
+ SetDeleteSelfOnClose(true);
+ //SetBounds(0, 0, 512, 384);
+ //SetMinimumSize( 256, 300 );
+ SetSizeable( false );
+
+ SetTitle("#GameUI_BonusMaps", true);
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) );
+ m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
+
+ LoadControlSettings("resource/BonusMapsDialog.res");
+
+ // Stop blinking the bonus maps menu item
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ pBasePanel->SetMenuItemBlinkingState( "OpenBonusMapsDialog", false );
+
+ BonusMapsDatabase()->SetBlink( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CBonusMapsDialog::~CBonusMapsDialog()
+{
+ BonusMapsDatabase()->WriteSaveData(); // Closing this dialog is a good time to save
+ g_pBonusMapsDialog = NULL;
+}
+
+
+bool CBonusMapsDialog::ImportZippedBonusMaps( const char *pchZippedFileName )
+{
+ // Get the zip file's name with dir info
+ char *pchShortFileName = Q_strrchr( pchZippedFileName, CORRECT_PATH_SEPARATOR );
+
+ if ( !pchShortFileName )
+ return false;
+
+ // It's going to go in the maps folder
+ char szOutFilename[ 512 ];
+
+ Q_snprintf( szOutFilename, sizeof( szOutFilename ), "maps%s", pchShortFileName );
+ Q_StripExtension( szOutFilename, szOutFilename, sizeof( szOutFilename ) );
+
+ // If there's already a folder by the same name we're going to tack a number onto the end
+ int iOutFilenameLength = Q_strlen( szOutFilename );
+ int iSameFolderCount = 1;
+
+ while ( g_pFullFileSystem->FileExists( szOutFilename, "MOD" ) )
+ {
+ ++iSameFolderCount;
+
+ if ( iSameFolderCount > 99 )
+ {
+ return false;
+ }
+
+ szOutFilename[ iOutFilenameLength ] = '\0';
+ Q_snprintf( szOutFilename, sizeof( szOutFilename ), "%s%02i", szOutFilename, iSameFolderCount );
+ }
+
+ // Pull the files out of the zip
+ if ( g_pFullFileSystem->UnzipFile( pchZippedFileName, "MOD", szOutFilename ) )
+ {
+ // New maps have been imported, so refresh the list
+ BuildMapsList();
+ }
+
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: builds bonus map list from directory
+//-----------------------------------------------------------------------------
+void CBonusMapsDialog::BuildMapsList( void )
+{
+ // clear the current list
+ m_pGameList->DeleteAllItems();
+
+ BonusMapsDatabase()->ClearBonusMapsList();
+ BonusMapsDatabase()->ScanBonusMaps();
+
+ // Enable back button if we're in a sub folder
+ bool bIsRoot = ( Q_strcmp( BonusMapsDatabase()->GetPath(), "." ) == 0 );
+ SetControlEnabled( "Back", !bIsRoot );
+ SetControlVisible( "Back", !bIsRoot );
+ SetControlEnabled( "ImportBonusMaps", bIsRoot );
+ SetControlVisible( "ImportBonusMaps", bIsRoot );
+
+ char szDisplayPath[_MAX_PATH];
+ Q_snprintf( szDisplayPath, _MAX_PATH, "%s/", BonusMapsDatabase()->GetPath() );
+
+ SetControlString( "FileName", szDisplayPath );
+ SetControlString( "CommentLabel", "" );
+
+ int iMapCount = BonusMapsDatabase()->BonusCount();
+
+ // add to the list
+ for ( int iMapIndex = 0; iMapIndex < iMapCount && iMapIndex < MAX_LISTED_BONUS_MAPS; ++iMapIndex )
+ {
+ CBonusMapPanel *bonusMapPanel = new CBonusMapPanel( m_pGameList, "BonusMapPanel", iMapIndex );
+ bonusMapPanel->SetBonusMapInfo( BonusMapsDatabase()->GetPath(), *(BonusMapsDatabase()->GetBonusData( iMapIndex )) );
+ m_pGameList->AddItem( NULL, bonusMapPanel );
+ }
+
+ // display a message if there are no save games
+ if ( iMapCount <= 0 )
+ {
+ vgui::Label *pNoSavesLabel = SETUP_PANEL(new Label(m_pGameList, "NoBonusMapsLabel", "#GameUI_NoBonusMapsToDisplay"));
+ pNoSavesLabel->SetTextColorState(vgui::Label::CS_DULL);
+ m_pGameList->AddItem( NULL, pNoSavesLabel );
+ m_pGameList->SetNumColumns( 1 );
+ }
+ else
+ {
+ m_pGameList->SetNumColumns( 3 );
+ }
+
+ RefreshCompletionPercentage();
+
+ // Disable load button
+ SetControlEnabled( "loadbonusmap", false );
+
+ // Make challenge selection invisible
+ m_pChallengeSelection->SetEnabled( false );
+ m_pChallengeSelection->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates the load game display list
+//-----------------------------------------------------------------------------
+void CBonusMapsDialog::CreateBonusMapsList()
+{
+ m_pGameList = new vgui::PanelListPanel( this, "listpanel_bonusmaps" );
+ m_pGameList->SetFirstColumnWidth( 0 );
+
+ new Label( this, "FileName", "./" );
+ new Label( this, "CommentLabel", "" );
+
+ m_pChallengeSelection = new vgui::ComboBox( this, "ChallengeSelection", 0, false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the save file name of the selected item
+//-----------------------------------------------------------------------------
+int CBonusMapsDialog::GetSelectedItemBonusMapIndex()
+{
+ CBonusMapPanel *panel = dynamic_cast<CBonusMapPanel *>(m_pGameList->GetSelectedPanel());
+ if ( panel && panel->GetBonusMapListItemID() < BonusMapsDatabase()->BonusCount() )
+ return panel->GetBonusMapListItemID();
+
+ return BonusMapsDatabase()->InvalidIndex();
+}
+
+void CBonusMapsDialog::SetSelectedBooleanStatus( const char *pchName, bool bValue )
+{
+ CBonusMapPanel *pSelectedBonusMapPanel = (CBonusMapPanel *)m_pGameList->GetSelectedPanel();
+ if ( !pSelectedBonusMapPanel )
+ return;
+
+ BonusMapsDatabase()->SetBooleanStatus( pchName, pSelectedBonusMapPanel->GetBonusMapListItemID(), bValue );
+
+ // Change the status in the dialog
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( pSelectedBonusMapPanel->GetBonusMapListItemID() );
+ pSelectedBonusMapPanel->SetBonusMapInfo( BonusMapsDatabase()->GetPath(), *pMap );
+
+ RefreshCompletionPercentage();
+ RefreshDialog( pMap );
+}
+
+void CBonusMapsDialog::RefreshData( void )
+{
+ for ( int iMap = 0; iMap < m_pGameList->GetItemCount(); ++iMap )
+ {
+ CBonusMapPanel *pBonusMapPanel = (CBonusMapPanel *)m_pGameList->GetItemPanel( iMap );
+
+ if ( pBonusMapPanel )
+ pBonusMapPanel->SetBonusMapInfo( BonusMapsDatabase()->GetPath(), *(BonusMapsDatabase()->GetBonusData( pBonusMapPanel->GetBonusMapListItemID() ) ) );
+ }
+
+ CBonusMapPanel *pSelectedBonusMapPanel = (CBonusMapPanel *)m_pGameList->GetSelectedPanel();
+ if ( !pSelectedBonusMapPanel )
+ return;
+
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( pSelectedBonusMapPanel->GetBonusMapListItemID() );
+
+ RefreshCompletionPercentage();
+ RefreshDialog( pMap );
+}
+
+int CBonusMapsDialog::GetSelectedChallenge( void )
+{
+ if ( !m_pChallengeSelection->IsEnabled() )
+ return -1;
+
+ KeyValues *pUserDataKey = m_pChallengeSelection->GetActiveItemUserData();
+ return pUserDataKey->GetInt( "challenge" );
+}
+
+void CBonusMapsDialog::RefreshDialog( BonusMapDescription_t *pMap )
+{
+ if ( !pMap || pMap->bLocked || ( m_pChallengeSelection->IsEnabled() && GetSelectedChallenge() == -1 ) )
+ {
+ // It's locked or no challenge is selected, so disable the load button
+ SetControlEnabled( "loadbonusmap", false );
+ }
+ else
+ {
+ // Enable the load button
+ SetControlEnabled( "loadbonusmap", true );
+ }
+
+ RefreshMedalDisplay( pMap );
+
+ if ( pMap )
+ SetControlString( "CommentLabel", pMap->szComment );
+ else
+ SetControlString( "CommentLabel", "" );
+}
+
+void CBonusMapsDialog::RefreshMedalDisplay( BonusMapDescription_t *pMap )
+{
+ {
+ int iFirstChildIndex = FindChildIndexByName( "ChallengeMedalOverview00" );
+ for ( int iMedal = 0; iMedal < 5; ++iMedal )
+ {
+ Panel *pMedalImage = GetChild( iFirstChildIndex + iMedal );
+ pMedalImage->SetVisible( false );
+ }
+ }
+ if ( !pMap || !pMap->m_pChallenges )
+ {
+ SetControlVisible( "ChallengeCommentLabel", false );
+ SetControlVisible( "ChallengeEarnedMedal", false );
+ SetControlVisible( "ChallengeBestLabel", false );
+ SetControlVisible( "ChallengeNextMedal", false );
+ SetControlVisible( "ChallengeNextLabel", false );
+
+ return;
+ }
+
+ char szBuff[ 512 ];
+
+ int iChallenge = GetSelectedChallenge();
+
+ if ( iChallenge < 0 )
+ {
+ SetControlVisible( "ChallengeCommentLabel", false );
+ SetControlVisible( "ChallengeEarnedMedal", false );
+ SetControlVisible( "ChallengeBestLabel", false );
+ SetControlVisible( "ChallengeNextMedal", false );
+ SetControlVisible( "ChallengeNextLabel", false );
+
+ int iFirstChildIndex = FindChildIndexByName( "ChallengeMedalOverview00" );
+ for ( int iChallengeIndex = 0; iChallengeIndex < m_pChallengeSelection->GetItemCount(); ++iChallengeIndex )
+ {
+ KeyValues *pUserDataKey = m_pChallengeSelection->GetItemUserData( iChallengeIndex );
+ int iChallengeNum = pUserDataKey->GetInt( "challenge" );
+
+ if ( iChallengeNum >= 0 )
+ {
+ ChallengeDescription_t *pChallengeDescription = NULL;
+
+ for ( int i = 0 ; i < pMap->m_pChallenges->Count(); ++i )
+ {
+ int iType = ((*pMap->m_pChallenges)[ i ]).iType;
+
+ if ( iType == -1 )
+ {
+ iType = i;
+ }
+
+ if ( iType == iChallengeNum )
+ pChallengeDescription = &((*pMap->m_pChallenges)[ i ]);
+ }
+
+ if ( pChallengeDescription )
+ {
+ int iBest, iEarnedMedal, iNext, iNextMedal;
+ GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal );
+
+ if ( iChallengeNum < 10 )
+ Q_snprintf( szBuff, 256, "medals/medal_0%i_%s", iChallengeNum, g_pszMedalNames[ iEarnedMedal ] );
+ else
+ Q_snprintf( szBuff, 256, "medals/medal_%i_%s", iChallengeNum, g_pszMedalNames[ iEarnedMedal ] );
+ }
+
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( GetChild( iFirstChildIndex + iChallengeNum ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( szBuff );
+ }
+ }
+
+ return;
+ }
+
+ ChallengeDescription_t *pChallengeDescription = NULL;
+
+ for ( int i = 0 ; i < pMap->m_pChallenges->Count(); ++i )
+ {
+ int iType = ((*pMap->m_pChallenges)[ i ]).iType;
+
+ if ( iType == -1 )
+ {
+ iType = i;
+ }
+
+ if ( iType == iChallenge )
+ pChallengeDescription = &((*pMap->m_pChallenges)[ i ]);
+ }
+
+ if ( !pChallengeDescription )
+ return;
+
+ const char *pchChallengeComment = pChallengeDescription->szComment;
+
+ int iBest, iEarnedMedal, iNext, iNextMedal;
+ GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal );
+
+ // Set comment label
+ SetControlString( "ChallengeCommentLabel", pchChallengeComment );
+ SetControlVisible( "ChallengeCommentLabel", true );
+
+ // Set earned medal
+ if ( iEarnedMedal > -1 )
+ {
+ if ( iChallenge < 10 )
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
+ else
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
+
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( szBuff );
+ }
+
+ // Set next medal
+ if ( iNextMedal > 0 )
+ {
+ if ( iChallenge < 10 )
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
+ else
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
+
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeNextMedal" ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( szBuff );
+ }
+ else
+ {
+ SetControlVisible( "ChallengeNextMedal", false );
+ }
+
+ wchar_t szWideBuff[ 64 ];
+ wchar_t szWideBuff2[ 64 ];
+
+ // Best label
+ if ( iBest != -1 )
+ {
+ Q_snprintf( szBuff, sizeof( szBuff ), "%i", iBest );
+ g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsBest" ), 1, szWideBuff2 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ SetControlString( "ChallengeBestLabel", szBuff );
+ SetControlVisible( "ChallengeBestLabel", true );
+ }
+ else
+ SetControlVisible( "ChallengeBestLabel", false );
+
+ // Next label
+ if ( iNext != -1 )
+ {
+ Q_snprintf( szBuff, sizeof( szBuff ), "%i", iNext );
+ g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsGoal" ), 1, szWideBuff2 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ SetControlString( "ChallengeNextLabel", szBuff );
+ SetControlVisible( "ChallengeNextLabel", true );
+ }
+ else
+ SetControlVisible( "ChallengeNextLabel", false );
+}
+
+void CBonusMapsDialog::RefreshCompletionPercentage( void )
+{
+ float fPercentage = BonusMapsDatabase()->GetCompletionPercentage();
+ if ( fPercentage > 0.0f )
+ {
+ char szBuff[ 256 ];
+ if ( fPercentage * 100.0f < 1.0f )
+ Q_snprintf( szBuff, 256, "%.2f%%", fPercentage * 100.0f ); // Show decimal places if less than 1%
+ else
+ Q_snprintf( szBuff, 256, "%.0f%%", fPercentage * 100.0f );
+
+ SetControlString( "PercentageText", szBuff );
+ SetControlVisible( "PercentageText", true );
+ SetControlVisible( "CompletionText", true );
+
+ // Blend the color from backround color 0% to selected color 100%
+ Color cProgressBar = Color( static_cast<float>( m_PercentageBarBackgroundColor.r() ) * ( 1.0f - fPercentage ) + static_cast<float>( m_PercentageBarColor.r() ) * fPercentage,
+ static_cast<float>( m_PercentageBarBackgroundColor.g() ) * ( 1.0f - fPercentage ) + static_cast<float>( m_PercentageBarColor.g() ) * fPercentage,
+ static_cast<float>( m_PercentageBarBackgroundColor.b() ) * ( 1.0f - fPercentage ) + static_cast<float>( m_PercentageBarColor.b() ) * fPercentage,
+ static_cast<float>( m_PercentageBarBackgroundColor.a() ) * ( 1.0f - fPercentage ) + static_cast<float>( m_PercentageBarColor.a() ) * fPercentage );
+
+ m_pPercentageBar->SetFillColor( cProgressBar );
+ m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * fPercentage );
+
+ SetControlVisible( "PercentageBarBackground", true );
+ SetControlVisible( "PercentageBar", true );
+ }
+ else
+ {
+ // 0% complete so don't display
+ SetControlVisible( "PercentageText", false );
+ SetControlVisible( "CompletionText", false );
+ SetControlVisible( "PercentageBarBackground", false );
+ SetControlVisible( "PercentageBar", false );
+ }
+}
+
+
+void CBonusMapsDialog::ApplySchemeSettings( IScheme *pScheme )
+{
+ m_PercentageBarBackgroundColor = Color( 0, 0, 0, 64 );
+ m_PercentageBarColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBonusMapsDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "loadbonusmap" ) )
+ {
+ int mapIndex = GetSelectedItemBonusMapIndex();
+ if ( BonusMapsDatabase()->IsValidIndex( mapIndex ) )
+ {
+ BonusMapDescription_t *pBonusMap = BonusMapsDatabase()->GetBonusData( mapIndex );
+
+ // Don't do anything with locked items
+ if ( pBonusMap->bLocked || ( m_pChallengeSelection->IsEnabled() && GetSelectedChallenge() == -1 ) )
+ return;
+
+ const char *shortName = pBonusMap->szShortName;
+ if ( shortName && shortName[ 0 ] )
+ {
+ if ( pBonusMap->bIsFolder )
+ {
+ BonusMapsDatabase()->AppendPath( shortName );
+
+ // repopulate list with current directory
+ BuildMapsList();
+
+ m_pGameList->MoveScrollBarToTop();
+ }
+ else
+ {
+ // Load the game, return to top and switch to engine
+ char sz[ 256 ];
+
+ // Set the challenge mode if one is selected
+ int iChallenge = GetSelectedChallenge() + 1;
+
+ if ( iChallenge > 0 )
+ {
+ Q_snprintf( sz, sizeof( sz ), "sv_bonus_challenge %i\n", iChallenge );
+ engine->ClientCmd_Unrestricted( sz );
+
+ ChallengeDescription_t *pChallengeDescription = &((*pBonusMap->m_pChallenges)[ iChallenge - 1 ]);
+
+ // Set up medal goals
+ BonusMapsDatabase()->SetCurrentChallengeObjectives( pChallengeDescription->iBronze, pChallengeDescription->iSilver, pChallengeDescription->iGold );
+ BonusMapsDatabase()->SetCurrentChallengeNames( pBonusMap->szFileName, pBonusMap->szMapName, pChallengeDescription->szName );
+ }
+
+ if ( pBonusMap->szMapFileName[ 0 ] != '.' )
+ {
+ Q_snprintf( sz, sizeof( sz ), "map %s\n", pBonusMap->szMapFileName );
+ }
+ else
+ {
+ const char *pchSubDir = Q_strnchr( BonusMapsDatabase()->GetPath(), '/', Q_strlen( BonusMapsDatabase()->GetPath() ) );
+
+ if ( pchSubDir )
+ {
+ pchSubDir = Q_strnchr( pchSubDir + 1, '/', Q_strlen( pchSubDir ) );
+
+ if ( pchSubDir )
+ {
+ ++pchSubDir;
+ const char *pchMapFileName = pBonusMap->szMapFileName + 2;
+ Q_snprintf( sz, sizeof( sz ), "map %s/%s\n", pchSubDir, pchMapFileName );
+ }
+ }
+ }
+
+ engine->ClientCmd_Unrestricted( sz );
+
+ // Close this dialog
+ //OnClose();
+ }
+ }
+ }
+ }
+ else if ( !stricmp( command, "back" ) )
+ {
+ BonusMapsDatabase()->BackPath();
+
+ // repopulate list with current directory
+ BuildMapsList();
+
+ m_pChallengeSelection->RemoveAll();
+ m_pChallengeSelection->AddItem( "<Select A Challenge>", new KeyValues( "ChallengeSelection", "challenge", -1 ) );
+
+ RefreshDialog( NULL );
+
+ m_pGameList->MoveScrollBarToTop();
+ }
+ else if ( !stricmp( command, "ImportBonusMaps" ) )
+ {
+ if ( m_hImportBonusMapsDialog == NULL )
+ {
+ m_hImportBonusMapsDialog = new FileOpenDialog( NULL, "#GameUI_ImportBonusMaps", true );
+ m_hImportBonusMapsDialog->AddFilter( "*.bmz", "#GameUI_BMZ_Files", true );
+ m_hImportBonusMapsDialog->AddActionSignalTarget( this );
+ }
+ m_hImportBonusMapsDialog->DoModal(false);
+ m_hImportBonusMapsDialog->Activate();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+void CBonusMapsDialog::OnKeyCodeTyped( vgui::KeyCode code )
+{
+ if ( code == KEY_ESCAPE )
+ {
+ OnCommand( "Close" );
+ return;
+ }
+
+ BaseClass::OnKeyCodeTyped( code );
+}
+
+void CBonusMapsDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_B )
+ {
+ OnCommand( "Close" );
+ return;
+ }
+ else if ( code == KEY_XSTICK1_RIGHT ||
+ code == KEY_XSTICK2_RIGHT ||
+ code == KEY_XBUTTON_RIGHT ||
+ code == KEY_RIGHT )
+ {
+ if ( m_pGameList->GetItemCount() )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( !pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( m_pGameList->FirstItem() ) );
+ m_pGameList->ScrollToItem( m_pGameList->FirstItem() );
+ return;
+ }
+ else
+ {
+ int nNextPanelID = m_pGameList->FirstItem();
+ while ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) == pSelectedPanel )
+ {
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+ if ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( nNextPanelID ) );
+ m_pGameList->ScrollToItem( nNextPanelID );
+ return;
+ }
+
+ break;
+ }
+
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+ }
+ }
+ }
+ }
+ else if ( code == KEY_XSTICK1_LEFT ||
+ code == KEY_XSTICK2_LEFT ||
+ code == KEY_XBUTTON_LEFT ||
+ code == KEY_LEFT )
+ {
+ if ( m_pGameList->GetItemCount() )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( !pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( m_pGameList->FirstItem() ) );
+ m_pGameList->ScrollToItem( m_pGameList->FirstItem() );
+ return;
+ }
+ else
+ {
+ int nNextPanelID = m_pGameList->FirstItem();
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) != pSelectedPanel )
+ {
+ while ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ int nOldPanelID = nNextPanelID;
+ nNextPanelID = m_pGameList->NextItem( nNextPanelID );
+
+ if ( nNextPanelID != m_pGameList->InvalidItemID() )
+ {
+ if ( m_pGameList->GetItemPanel( nNextPanelID ) == pSelectedPanel )
+ {
+ m_pGameList->SetSelectedPanel( m_pGameList->GetItemPanel( nOldPanelID ) );
+ m_pGameList->ScrollToItem( nOldPanelID );
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( code == KEY_XSTICK1_DOWN ||
+ code == KEY_XSTICK2_DOWN ||
+ code == KEY_XBUTTON_DOWN ||
+ code == KEY_DOWN )
+ {
+ int nOldActiveItem = m_pChallengeSelection->GetActiveItem();
+ int nActiveItem = min( nOldActiveItem + 1, m_pChallengeSelection->GetItemCount() - 1 );
+
+ if ( nOldActiveItem != nActiveItem )
+ {
+ m_pChallengeSelection->ActivateItem( nActiveItem );
+ return;
+ }
+ }
+ else if ( code == KEY_XSTICK1_UP ||
+ code == KEY_XSTICK2_UP ||
+ code == KEY_XBUTTON_UP ||
+ code == KEY_UP )
+ {
+ int nOldActiveItem = m_pChallengeSelection->GetActiveItem();
+ int nActiveItem = max( nOldActiveItem - 1, 0 );
+
+ if ( nOldActiveItem != nActiveItem )
+ {
+ m_pChallengeSelection->ActivateItem( nActiveItem );
+ return;
+ }
+ }
+ else if ( code == KEY_ENTER || code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ Panel *pSelectedPanel = m_pGameList->GetSelectedPanel();
+ if ( pSelectedPanel )
+ {
+ OnCommand( "loadbonusmap" );
+ return;
+ }
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: One item has been selected
+//-----------------------------------------------------------------------------
+void CBonusMapsDialog::OnPanelSelected()
+{
+ CBonusMapPanel *pSelectedBonusMapPanel = (CBonusMapPanel *)m_pGameList->GetSelectedPanel();
+ if ( !pSelectedBonusMapPanel )
+ return;
+
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( pSelectedBonusMapPanel->GetBonusMapListItemID() );
+ if ( !pMap )
+ return;
+
+ SetControlString( "CommentLabel", pMap->szComment );
+
+ // Handle challenge selection box
+ int iNumChallenges = 0;
+
+ if ( pMap->m_pChallenges )
+ {
+ // Get the name of the previously selected challenge so that we can select a matching challenge (if one exists)
+ int iSelectedChallenge = GetSelectedChallenge();
+
+ m_pChallengeSelection->RemoveAll();
+
+ m_pChallengeSelection->AddItem( "<Select A Challenge>", new KeyValues( "ChallengeSelection", "challenge", -1 ) );
+
+ int iFoundSimilar = 0;
+
+ for ( iNumChallenges; iNumChallenges < pMap->m_pChallenges->Count(); ++iNumChallenges )
+ {
+ ChallengeDescription_t *pChallenge = &(*pMap->m_pChallenges)[ iNumChallenges ];
+ int iType = iNumChallenges;
+
+ // If the challenge type was specified then use that instead of (legacy) the order the challenges were listed
+ if ( pChallenge->iType != -1 )
+ iType = pChallenge->iType;
+
+ m_pChallengeSelection->AddItem( pChallenge->szName, new KeyValues( "ChallengeSelection", "challenge", iType ) );
+
+ if ( iSelectedChallenge == iNumChallenges )
+ iFoundSimilar = iNumChallenges + 1;
+ }
+
+ m_pChallengeSelection->ActivateItemByRow( iFoundSimilar );
+ }
+
+ if ( iNumChallenges > 0 )
+ {
+ m_pChallengeSelection->SetEnabled( true );
+ m_pChallengeSelection->SetVisible( true );
+ m_pChallengeSelection->SetNumberOfEditLines( iNumChallenges + 1 );
+ }
+ else
+ {
+ m_pChallengeSelection->SetEnabled( false );
+ m_pChallengeSelection->SetVisible( false );
+ }
+
+ RefreshDialog( pMap );
+}
+
+void CBonusMapsDialog::OnControlModified()
+{
+ CBonusMapPanel *pSelectedBonusMapPanel = (CBonusMapPanel *)m_pGameList->GetSelectedPanel();
+ if ( !pSelectedBonusMapPanel )
+ return;
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( pSelectedBonusMapPanel->GetBonusMapListItemID() );
+ if ( !pMap )
+ return;
+ RefreshDialog( pMap );
+}
+
+// file selected. This can only happen when someone selects an image to be imported as a spray logo.
+void CBonusMapsDialog::OnFileSelected( const char *fullpath )
+{
+ if ( fullpath == NULL || fullpath[ 0 ] == '\0' )
+ return;
+
+ // this can take a while, put up a waiting cursor
+ surface()->SetCursor(dc_hourglass);
+
+ ImportZippedBonusMaps( fullpath );
+
+ // change the cursor back to normal
+ surface()->SetCursor(dc_user);
+}
diff --git a/gameui/BonusMapsDialog.h b/gameui/BonusMapsDialog.h
new file mode 100644
index 0000000..cd7cbae
--- /dev/null
+++ b/gameui/BonusMapsDialog.h
@@ -0,0 +1,75 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BONUSMAPSDIALOG_H
+#define BONUSMAPSDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+
+#include "BonusMapsDatabase.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays and loads available bonus maps
+//-----------------------------------------------------------------------------
+class CBonusMapsDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CBonusMapsDialog, vgui::Frame );
+
+public:
+ CBonusMapsDialog(vgui::Panel *parent);
+ ~CBonusMapsDialog();
+
+ void SetSelectedBooleanStatus( const char *pchName, bool bValue );
+ void RefreshData( void );
+
+ int GetSelectedChallenge( void );
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+
+ void OnKeyCodeTyped( vgui::KeyCode code );
+ void OnKeyCodePressed( vgui::KeyCode code );
+
+private:
+ bool ImportZippedBonusMaps( const char *pchZippedFileName );
+
+ void BuildMapsList( void );
+
+ void CreateBonusMapsList();
+ int GetSelectedItemBonusMapIndex();
+
+ void RefreshDialog( BonusMapDescription_t *pMap );
+ void RefreshMedalDisplay( BonusMapDescription_t *pMap );
+ void RefreshCompletionPercentage( void );
+
+ MESSAGE_FUNC( OnPanelSelected, "PanelSelected" );
+ MESSAGE_FUNC( OnControlModified, "ControlModified" );
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" )
+ {
+ OnControlModified();
+ }
+ MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
+
+private:
+ Color m_PercentageBarBackgroundColor, m_PercentageBarColor;
+
+ vgui::FileOpenDialog *m_hImportBonusMapsDialog;
+ vgui::PanelListPanel *m_pGameList;
+ vgui::ComboBox *m_pChallengeSelection;
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+};
+
+
+extern CBonusMapsDialog *g_pBonusMapsDialog;
+
+
+#endif // BONUSMAPSDIALOG_H
diff --git a/gameui/CDKeyEntryDialog.cpp b/gameui/CDKeyEntryDialog.cpp
new file mode 100644
index 0000000..2ee6791
--- /dev/null
+++ b/gameui/CDKeyEntryDialog.cpp
@@ -0,0 +1,323 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "CDKeyEntryDialog.h"
+#include "EngineInterface.h"
+
+#include "steamcommon.h" // VALVE_AUTH cd key checking code
+#include "ValidateNewValveCDKeyClient.h"
+#include "ValveCDKeyGameAndTerritoryCodes.h"
+
+#include "vgui/IInput.h"
+#include "vgui/IPanel.h"
+#include "vgui/ISystem.h"
+#include "vgui/ISurface.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/MessageBox.h"
+#include "vgui_controls/TextEntry.h"
+#include "vstdlib/random.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#include <ctype.h>
+
+using namespace vgui;
+
+#define FAKE_CDKEY_LEN 49
+#define FAKE_CDKEY_REGKEY "HKEY_CURRENT_USER\\Software\\Valve\\Source\\Settings\\EncryptedCDKey"
+
+//-----------------------------------------------------------------------------
+// Purpose: hacky class to make all input uppercase
+//-----------------------------------------------------------------------------
+class CUpperCaseTextEntry : public vgui::TextEntry
+{
+ DECLARE_CLASS_SIMPLE( CUpperCaseTextEntry, vgui::TextEntry );
+public:
+ CUpperCaseTextEntry(vgui::Panel *parent, const char *name) : TextEntry(parent, name) {}
+
+ virtual void InsertChar(wchar_t unichar)
+ {
+ // only allow input of valid cdkey characters
+ if (unichar >= 'a' && unichar <= 'z')
+ {
+ // force to be uppercase
+ BaseClass::InsertChar(unichar - 'a' + 'A');
+ }
+ else if ((unichar >= 'A' && unichar <= 'Z')
+ || (unichar >= '0' && unichar <= '9'))
+ {
+ BaseClass::InsertChar(unichar);
+ }
+ }
+};
+
+
+class CloseMessageBox : public vgui::MessageBox
+{
+public:
+ CloseMessageBox(const char *title, const char *text, Panel *parent = NULL): MessageBox( title, text, parent) {}
+
+ virtual void OnClose()
+ {
+ engine->ClientCmd_Unrestricted("quit\n");
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCDKeyEntryDialog::CCDKeyEntryDialog(vgui::Panel *parent, bool inConnect) : BaseClass(parent, "CDKeyEntryDialog")
+{
+ // see what type of cdkey we have
+ SetDeleteSelfOnClose(true);
+ m_bInConnect = inConnect;
+ m_iErrCount = 0;
+ m_bEnteredValidCDKey = false;
+
+ m_pOK = new Button(this, "OKButton", "#GameUI_OK");
+ m_pQuitGame = new Button(this, "CancelButton", "#GameUI_Quit");
+ m_pEntry1 = new CUpperCaseTextEntry(this, "Entry1");;
+ m_pEntry2 = new CUpperCaseTextEntry(this, "Entry2");
+ m_pEntry3 = new CUpperCaseTextEntry(this, "Entry3");
+ m_pEntry4 = new CUpperCaseTextEntry(this, "Entry4");
+ m_pEntry5 = new CUpperCaseTextEntry(this, "Entry5");
+
+ m_pEntry1->SetMaximumCharCount(5);
+ m_pEntry2->SetMaximumCharCount(5);
+ m_pEntry3->SetMaximumCharCount(5);
+ m_pEntry4->SetMaximumCharCount(5);
+ m_pEntry5->SetMaximumCharCount(5);
+
+ m_pEntry1->SetAutoProgressOnHittingCharLimit(true);
+ m_pEntry2->SetAutoProgressOnHittingCharLimit(true);
+ m_pEntry3->SetAutoProgressOnHittingCharLimit(true);
+ m_pEntry4->SetAutoProgressOnHittingCharLimit(true);
+ m_pEntry5->SetAutoProgressOnHittingCharLimit(false);
+
+ SetSizeable(false);
+ SetSize(360, 224);
+ SetTitle("#GameUI_CDKey", true);
+
+ LoadControlSettings("Resource/ValveCDKeyEntryDialog.res");
+// MoveToCenterOfScreen();
+
+ SetMinimizeButtonVisible(false);
+ SetMaximizeButtonVisible(false);
+
+ m_pOK->SetEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCDKeyEntryDialog::~CCDKeyEntryDialog()
+{
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if there is a valid weak check key in the registry
+//-----------------------------------------------------------------------------
+bool CCDKeyEntryDialog::IsValidWeakCDKeyInRegistry()
+{
+ char fakekey[FAKE_CDKEY_LEN];
+ if (vgui::system()->GetRegistryString(FAKE_CDKEY_REGKEY, fakekey, sizeof(fakekey)))
+ {
+ if (strlen(fakekey) == (FAKE_CDKEY_LEN - 1)
+ && fakekey[17] == 'E'
+ && fakekey[31] == 'z'
+ && fakekey[43] == 'n')
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCDKeyEntryDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "OK"))
+ {
+ if (IsEnteredKeyValid())
+ {
+ m_bEnteredValidCDKey = true;
+
+ // write out fake key and continue
+ char fakekey[FAKE_CDKEY_LEN];
+ for (int i = 0; i < sizeof(fakekey) - 1; i++)
+ {
+ // pick some random fields for us to check later
+ if (i == 17)
+ {
+ fakekey[i] = 'E';
+ }
+ else if (i == 31)
+ {
+ fakekey[i] = 'z';
+ }
+ else if (i == 43)
+ {
+ fakekey[i] = 'n';
+ }
+ else
+ {
+ fakekey[i] = RandomInt('0', 'z');
+ }
+ }
+ fakekey[sizeof(fakekey) - 1] = 0;
+ vgui::system()->SetRegistryString(FAKE_CDKEY_REGKEY, fakekey);
+
+ if ( m_bInConnect )
+ {
+ engine->ClientCmd_Unrestricted( "retry\n" ); // retry the server connection with this new key...
+ }
+ Close();
+ }
+ else
+ {
+ m_hErrorBox = new MessageBox("#GameUI_CDKey_Invalid_Title","#GameUI_CDKey_Invalid_Text", this);
+ m_hErrorBox->ShowWindow( this );
+ }
+ }
+ else if (!stricmp(command, "Cancel") || !stricmp(command, "Close"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+
+ if (!m_bEnteredValidCDKey) // moved away from the dialog box to make it a little harder to crack...
+ {
+ m_iErrCount++;
+ if( m_iErrCount >= MAX_CDKEY_ERRORS )
+ {
+ // too many bad entries, make em quit
+ CloseMessageBox *bx = new CloseMessageBox("#GameUI_CDKey_Invalid_Title","#GameUI_CDKey_TooManyTries", this);
+ bx->ShowWindow( this );
+ }
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCDKeyEntryDialog::OnClose()
+{
+ if (!m_bEnteredValidCDKey)
+ {
+ // if we don't have a valid key we can't continue
+ engine->ClientCmd_Unrestricted("quit\n");
+ }
+
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCDKeyEntryDialog::OnThink()
+{
+ if (!m_bEnteredValidCDKey)
+ {
+ // force us to be the only thing to draw
+ VPANEL vpanel = m_hErrorBox.Get() ? m_hErrorBox->GetVPanel() : GetVPanel();
+ vgui::surface()->RestrictPaintToSinglePanel(vpanel);
+
+ // make sure we're the focus
+ if (!(input()->GetFocus() && ipanel()->HasParent(input()->GetFocus(), GetVPanel())))
+ {
+ BaseClass::Activate();
+ }
+ }
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns whether or not the key entered by the user passes the simple check
+//-----------------------------------------------------------------------------
+bool CCDKeyEntryDialog::IsEnteredKeyValid()
+{
+ // get the entered text
+ char cdkey[32];
+ m_pEntry1->GetText(cdkey, 6);
+ m_pEntry2->GetText(cdkey + 6, 6);
+ m_pEntry3->GetText(cdkey + 12, 6);
+ m_pEntry4->GetText(cdkey + 18, 6);
+ m_pEntry5->GetText(cdkey + 24, 6);
+
+ // add in the hyphens
+ cdkey[5] = '-';
+ cdkey[11] = '-';
+ cdkey[17] = '-';
+ cdkey[23] = '-';
+
+ // verify the entry
+ for (int i = 0; i < 29; i++)
+ {
+ if (cdkey[i] != '-' && !isalnum(cdkey[i]))
+ return false;
+ }
+#if !defined( NO_STEAM )
+ uint gameCode, salesTerritoryCode, uniqueSerialNumber;
+
+ // test key - this key passes they weak check, but not the strong check
+ // "5J5Q3-QCME2-2SMMV-SBHN9-43S2S"
+ if ( SteamWeakVerifyNewValveCDKey(cdkey, &gameCode, &salesTerritoryCode, &uniqueSerialNumber) == eSteamErrorNone )
+ {
+ // require hl2 retail cdkey (ATI Bundle keys are also in this category)
+ if (gameCode == eHalfLife2)
+ return true;
+ }
+#endif
+ return false;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: handles user entering data in fields
+//-----------------------------------------------------------------------------
+void CCDKeyEntryDialog::OnTextChanged(Panel *entry)
+{
+ char cdkey[32];
+ m_pEntry1->GetText(cdkey, 6);
+ m_pEntry2->GetText(cdkey + 6, 6);
+ m_pEntry3->GetText(cdkey + 12, 6);
+ m_pEntry4->GetText(cdkey + 18, 6);
+ m_pEntry5->GetText(cdkey + 24, 6);
+
+ // add in the hyphens
+ cdkey[5] = '-';
+ cdkey[11] = '-';
+ cdkey[17] = '-';
+ cdkey[23] = '-';
+
+ if (strlen(cdkey) == 29)
+ {
+ m_pOK->SetEnabled(true);
+ }
+ else
+ {
+ m_pOK->SetEnabled(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCDKeyEntryDialog::Activate()
+{
+ BaseClass::Activate();
+ m_pEntry1->RequestFocus();
+}
diff --git a/gameui/CDKeyEntryDialog.h b/gameui/CDKeyEntryDialog.h
new file mode 100644
index 0000000..1200826
--- /dev/null
+++ b/gameui/CDKeyEntryDialog.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CDKEYENTRYDIALOG_H
+#define CDKEYENTRYDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CCDKeyEntryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CCDKeyEntryDialog, vgui::Frame );
+
+public:
+ CCDKeyEntryDialog(vgui::Panel *parent, bool inConnect = false);
+ ~CCDKeyEntryDialog();
+
+ virtual void Activate();
+
+ static bool IsValidWeakCDKeyInRegistry();
+
+private:
+ enum { MAX_CDKEY_ERRORS = 5 };
+
+ virtual void OnCommand(const char *command);
+ virtual void OnClose();
+ virtual void OnThink();
+
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ bool IsEnteredKeyValid();
+
+ vgui::Button *m_pOK;
+ vgui::Button *m_pQuitGame;
+ vgui::TextEntry *m_pEntry1;
+ vgui::TextEntry *m_pEntry2;
+ vgui::TextEntry *m_pEntry3;
+ vgui::TextEntry *m_pEntry4;
+ vgui::TextEntry *m_pEntry5;
+
+ vgui::DHANDLE<vgui::MessageBox> m_hErrorBox;
+
+ bool m_bEnteredValidCDKey;
+
+ bool m_bInConnect;
+ int m_iErrCount;
+};
+
+
+#endif // CDKEYENTRYDIALOG_H
diff --git a/gameui/ChangeGameDialog.cpp b/gameui/ChangeGameDialog.cpp
new file mode 100644
index 0000000..8e6101b
--- /dev/null
+++ b/gameui/ChangeGameDialog.cpp
@@ -0,0 +1,161 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#ifdef _XBOX
+#include "xbox/xbox_platform.h"
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+#if !defined( _X360 )
+#include <windows.h>
+#endif
+#include <stdio.h>
+
+#include "ChangeGameDialog.h"
+#include "ModInfo.h"
+#include "EngineInterface.h"
+
+#include <vgui_controls/ListPanel.h>
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CChangeGameDialog::CChangeGameDialog(vgui::Panel *parent) : Frame(parent, "ChangeGameDialog")
+{
+ SetSize(400, 340);
+ SetMinimumSize(400, 340);
+ SetTitle("#GameUI_ChangeGame", true);
+
+ m_pModList = new ListPanel(this, "ModList");
+ m_pModList->SetEmptyListText("#GameUI_NoOtherGamesAvailable");
+ m_pModList->AddColumnHeader(0, "ModName", "#GameUI_Game", 128);
+
+ LoadModList();
+ LoadControlSettings("Resource/ChangeGameDialog.res");
+
+ // if there's a mod in the list, select the first one
+ if (m_pModList->GetItemCount() > 0)
+ {
+ m_pModList->SetSingleSelectedItem(m_pModList->GetItemIDFromRow(0));
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CChangeGameDialog::~CChangeGameDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fills the mod list
+//-----------------------------------------------------------------------------
+void CChangeGameDialog::LoadModList()
+{
+ // look for third party games
+ char szSearchPath[_MAX_PATH + 5];
+ Q_strncpy(szSearchPath, "*.*", sizeof( szSearchPath ) );
+
+ // use local filesystem since it has to look outside path system, and will never be used under steam
+ WIN32_FIND_DATA wfd;
+ HANDLE hResult;
+ memset(&wfd, 0, sizeof(WIN32_FIND_DATA));
+
+ hResult = FindFirstFile( szSearchPath, &wfd);
+ if (hResult != INVALID_HANDLE_VALUE)
+ {
+ BOOL bMoreFiles;
+ while (1)
+ {
+ if ((wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (Q_strnicmp(wfd.cFileName, ".", 1)))
+ {
+ // Check for dlls\*.dll
+ char szDllDirectory[MAX_PATH + 16];
+ Q_snprintf(szDllDirectory, sizeof( szDllDirectory ), "%s\\gameinfo.txt", wfd.cFileName);
+
+ FILE *f = fopen(szDllDirectory, "rb");
+ if (f)
+ {
+ // find the description
+ fseek(f, 0, SEEK_END);
+ unsigned int size = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ char *buf = (char *)malloc(size + 1);
+ if (fread(buf, 1, size, f) == size)
+ {
+ buf[size] = 0;
+
+ CModInfo modInfo;
+ modInfo.LoadGameInfoFromBuffer(buf);
+
+ if (strcmp(modInfo.GetGameName(), ModInfo().GetGameName()))
+ {
+ // Add the game directory.
+ strlwr(wfd.cFileName);
+ KeyValues *itemData = new KeyValues("Mod");
+ itemData->SetString("ModName", modInfo.GetGameName());
+ itemData->SetString("ModDir", wfd.cFileName);
+ m_pModList->AddItem(itemData, 0, false, false);
+ }
+ }
+ free(buf);
+ fclose(f);
+ }
+ }
+ bMoreFiles = FindNextFile(hResult, &wfd);
+ if (!bMoreFiles)
+ break;
+ }
+
+ FindClose(hResult);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CChangeGameDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "OK"))
+ {
+ if (m_pModList->GetSelectedItemsCount() > 0)
+ {
+ KeyValues *kv = m_pModList->GetItem(m_pModList->GetSelectedItem(0));
+ if (kv)
+ {
+ // change the game dir and restart the engine
+ char szCmd[256];
+ Q_snprintf(szCmd, sizeof( szCmd ), "_setgamedir %s\n", kv->GetString("ModDir"));
+ engine->ClientCmd_Unrestricted(szCmd);
+
+ // Force restart of entire engine
+ engine->ClientCmd_Unrestricted("_restart\n");
+ }
+ }
+ }
+ else if (!stricmp(command, "Cancel"))
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+
+
+
+
+
diff --git a/gameui/ChangeGameDialog.h b/gameui/ChangeGameDialog.h
new file mode 100644
index 0000000..3bd4d7c
--- /dev/null
+++ b/gameui/ChangeGameDialog.h
@@ -0,0 +1,36 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CHANGEGAMEDIALOG_H
+#define CHANGEGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialogs for use to change current loaded mod
+//-----------------------------------------------------------------------------
+class CChangeGameDialog : public vgui::Frame
+{
+public:
+ CChangeGameDialog(vgui::Panel *parent);
+ ~CChangeGameDialog();
+
+ virtual void OnCommand( const char *command );
+
+private:
+ void LoadModList();
+
+ vgui::ListPanel *m_pModList;
+
+ typedef vgui::Frame BaseClass;
+};
+
+
+#endif // CHANGEGAMEDIALOG_H
diff --git a/gameui/CommandCheckButton.cpp b/gameui/CommandCheckButton.cpp
new file mode 100644
index 0000000..1ea98ce
--- /dev/null
+++ b/gameui/CommandCheckButton.cpp
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "CommandCheckButton.h"
+#include "EngineInterface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+CCommandCheckButton::CCommandCheckButton( Panel *parent, const char *panelName, const char *text, const char *downcmd, const char *upcmd )
+ : CheckButton( parent, panelName, text )
+{
+ m_pszDown = downcmd ? strdup( downcmd ) : NULL;
+ m_pszUp = upcmd ? strdup( upcmd ) : NULL;
+}
+
+CCommandCheckButton::~CCommandCheckButton()
+{
+ free( m_pszDown );
+ free( m_pszUp );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CCommandCheckButton::SetSelected( bool state )
+{
+ BaseClass::SetSelected( state );
+
+ if ( IsSelected() && m_pszDown )
+ {
+ engine->ClientCmd_Unrestricted( m_pszDown );
+ engine->ClientCmd_Unrestricted( "\n" );
+ }
+ else if ( !IsSelected() && m_pszUp )
+ {
+ engine->ClientCmd_Unrestricted( m_pszUp );
+ engine->ClientCmd_Unrestricted( "\n" );
+ }
+}
diff --git a/gameui/CommandCheckButton.h b/gameui/CommandCheckButton.h
new file mode 100644
index 0000000..24dbff5
--- /dev/null
+++ b/gameui/CommandCheckButton.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef COMMANDCHECKBUTTON_H
+#define COMMANDCHECKBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/CheckButton.h>
+
+class CCommandCheckButton : public vgui::CheckButton
+{
+public:
+ CCommandCheckButton( vgui::Panel *parent, const char *panelName, const char *text, const char *downcmd, const char *upcmd );
+ ~CCommandCheckButton();
+
+// virtual void OnCheckButtonChecked(vgui::Panel *panel);
+ virtual void SetSelected( bool state );
+private:
+ typedef vgui::CheckButton BaseClass;
+
+ char *m_pszDown;
+ char *m_pszUp;
+};
+#endif // COMMANDCHECKBUTTON_H
diff --git a/gameui/CommentaryDialog.cpp b/gameui/CommentaryDialog.cpp
new file mode 100644
index 0000000..6f3479c
--- /dev/null
+++ b/gameui/CommentaryDialog.cpp
@@ -0,0 +1,255 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "CommentaryDialog.h"
+#include "BasePanel.h"
+#include "convar.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+
+#include <stdio.h>
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommentaryDialog::CCommentaryDialog(vgui::Panel *parent) : BaseClass(parent, "CommentaryDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetSizeable( false );
+
+ input()->SetAppModalSurface(GetVPanel());
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+ GameUI().PreventEngineHideGameUI();
+
+ SetTitle("#GameUI_CommentaryDialogTitle", true);
+
+ LoadControlSettings("Resource/CommentaryDialog.res");
+
+ MoveToCenterOfScreen();
+
+ bool bCommentaryOn = false;
+ ConVarRef commentary( "commentary" );
+ if ( commentary.IsValid() )
+ {
+ bCommentaryOn = commentary.GetBool();
+ }
+
+ // Setup the buttons & labels to reflect the current state of the commentary
+ if ( bCommentaryOn )
+ {
+ SetControlString( "ModeLabel", "#GAMEUI_Commentary_LabelOn" );
+ SetControlString( "TurnOnButton", "#GAMEUI_Commentary_LeaveOn" );
+ SetControlString( "TurnOffButton", "#GAMEUI_Commentary_TurnOff" );
+ }
+ else
+ {
+ SetControlString( "ModeLabel", "#GAMEUI_Commentary_LabelOff" );
+ SetControlString( "TurnOnButton", "#GAMEUI_Commentary_TurnOn" );
+ SetControlString( "TurnOffButton", "#GAMEUI_Commentary_LeaveOff" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommentaryDialog::~CCommentaryDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryDialog::OnClose( void )
+{
+ BaseClass::OnClose();
+
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().AllowEngineHideGameUI();
+
+ // Bring up the post dialog
+ DHANDLE<CPostCommentaryDialog> hPostCommentaryDialog;
+ if ( !hPostCommentaryDialog.Get() )
+ {
+ hPostCommentaryDialog = new CPostCommentaryDialog( BasePanel() );
+ }
+ hPostCommentaryDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CCommentaryDialog::OnCommand( const char *command )
+{
+ if ( !Q_stricmp( command, "TurnOn" ) )
+ {
+ ConVarRef commentary("commentary");
+ commentary.SetValue( 1 );
+ Close();
+ }
+ else if ( !Q_stricmp( command, "TurnOff" ) )
+ {
+ ConVarRef commentary("commentary");
+ commentary.SetValue( 0 );
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryDialog::OnKeyCodePressed(KeyCode code)
+{
+ // Ignore escape key
+ if ( code == KEY_ESCAPE )
+ return;
+
+ if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ OnCommand( "TurnOn" );
+ return;
+ }
+ else if ( code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B )
+ {
+ OnCommand( "TurnOff" );
+ return;
+ }
+
+ BaseClass::OnKeyCodePressed(code);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void OpenCommentaryDialog( void )
+{
+ DHANDLE<CCommentaryDialog> hCommentaryDialog;
+ if ( !hCommentaryDialog.Get() )
+ {
+ hCommentaryDialog = new CCommentaryDialog( BasePanel() );
+ }
+
+ GameUI().ActivateGameUI();
+ hCommentaryDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+ConVar commentary_firstrun("commentary_firstrun", "0", FCVAR_ARCHIVE );
+void CC_CommentaryTestFirstRun( void )
+{
+ // The enable/disable commentary box in the sound options got lost in time;
+ // always prompt the user for commentary mode instead on new game.
+ //if ( !commentary_firstrun.GetBool() )
+ {
+ commentary_firstrun.SetValue(1);
+ OpenCommentaryDialog();
+ }
+}
+static ConCommand commentary_testfirstrun("commentary_testfirstrun", CC_CommentaryTestFirstRun, 0 );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPostCommentaryDialog::CPostCommentaryDialog(vgui::Panel *parent) : BaseClass(parent, "PostCommentaryDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetSizeable( false );
+
+ input()->SetAppModalSurface(GetVPanel());
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+ m_bResetPaintRestrict = false;
+
+ SetTitle("#GameUI_CommentaryDialogTitle", true);
+
+ LoadControlSettings("Resource/PostCommentaryDialog.res");
+
+ MoveToCenterOfScreen();
+
+ bool bCommentaryOn = false;
+ ConVarRef commentary("commentary");
+ if ( commentary.IsValid() )
+ {
+ bCommentaryOn = commentary.GetBool();
+ }
+
+ // Setup the buttons & labels to reflect the current state of the commentary
+ if ( bCommentaryOn )
+ {
+ SetControlString( "PostModeLabel", "#GAMEUI_PostCommentary_ModeLabelOn" );
+ }
+ else
+ {
+ SetControlString( "PostModeLabel", "#GAMEUI_PostCommentary_ModeLabelOff" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPostCommentaryDialog::~CPostCommentaryDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPostCommentaryDialog::OnFinishedClose( void )
+{
+ BaseClass::OnFinishedClose();
+
+ if ( !m_bResetPaintRestrict )
+ {
+ m_bResetPaintRestrict = true;
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ GameUI().HideGameUI();
+ }
+}
+
+void CPostCommentaryDialog::OnKeyCodeTyped(KeyCode code)
+{
+ if ( code == KEY_ESCAPE )
+ {
+ Close();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ m_bResetPaintRestrict = true;
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPostCommentaryDialog::OnKeyCodePressed(KeyCode code)
+{
+ if ( code == KEY_XBUTTON_A || code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B )
+ {
+ Close();
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ m_bResetPaintRestrict = true;
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
diff --git a/gameui/CommentaryDialog.h b/gameui/CommentaryDialog.h
new file mode 100644
index 0000000..c1acae4
--- /dev/null
+++ b/gameui/CommentaryDialog.h
@@ -0,0 +1,55 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef COMMENTARYDIALOG_H
+#define COMMENTARYDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "utlvector.h"
+#include <vgui/KeyCode.h>
+
+class CGameChapterPanel;
+class CSkillSelectionDialog;
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles selection of commentary mode on/off
+//-----------------------------------------------------------------------------
+class CCommentaryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CCommentaryDialog, vgui::Frame );
+
+public:
+ CCommentaryDialog(vgui::Panel *parent);
+ ~CCommentaryDialog();
+
+ virtual void OnClose( void );
+ virtual void OnCommand( const char *command );
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Small dialog to remind players on method of changing commentary mode
+//-----------------------------------------------------------------------------
+class CPostCommentaryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CPostCommentaryDialog, vgui::Frame );
+
+public:
+ CPostCommentaryDialog(vgui::Panel *parent);
+ ~CPostCommentaryDialog();
+
+ virtual void OnFinishedClose( void );
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+
+private:
+ bool m_bResetPaintRestrict;
+};
+
+#endif // COMMENTARYDIALOG_H
diff --git a/gameui/CommentaryExplanationDialog.cpp b/gameui/CommentaryExplanationDialog.cpp
new file mode 100644
index 0000000..e4d88eb
--- /dev/null
+++ b/gameui/CommentaryExplanationDialog.cpp
@@ -0,0 +1,107 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "CommentaryExplanationDialog.h"
+#include "BasePanel.h"
+#include "convar.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+
+#include <stdio.h>
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommentaryExplanationDialog::CCommentaryExplanationDialog(vgui::Panel *parent, char *pszFinishCommand) : BaseClass(parent, "CommentaryExplanationDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetSizeable( false );
+
+ input()->SetAppModalSurface(GetVPanel());
+
+ LoadControlSettings("Resource/CommentaryExplanationDialog.res");
+
+ MoveToCenterOfScreen();
+
+ GameUI().PreventEngineHideGameUI();
+
+ // Save off the finish command
+ Q_snprintf( m_pszFinishCommand, sizeof( m_pszFinishCommand ), "%s", pszFinishCommand );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCommentaryExplanationDialog::~CCommentaryExplanationDialog()
+{
+}
+
+void CCommentaryExplanationDialog::OnKeyCodeTyped(KeyCode code)
+{
+ if ( code == KEY_ESCAPE )
+ {
+ OnCommand( "cancel" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryExplanationDialog::OnKeyCodePressed(KeyCode code)
+{
+ if ( GetBaseButtonCode( code ) == KEY_XBUTTON_B || GetBaseButtonCode( code ) == STEAMCONTROLLER_B )
+ {
+ OnCommand( "cancel" );
+ }
+ else if ( GetBaseButtonCode( code ) == KEY_XBUTTON_A || GetBaseButtonCode( code ) == STEAMCONTROLLER_A )
+ {
+ OnCommand( "ok" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles button commands
+//-----------------------------------------------------------------------------
+void CCommentaryExplanationDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "ok" ) )
+ {
+ Close();
+ BasePanel()->FadeToBlackAndRunEngineCommand( m_pszFinishCommand );
+ }
+ else if ( !stricmp( command, "cancel" ) || !stricmp( command, "close" ) )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCommentaryExplanationDialog::OnClose( void )
+{
+ BaseClass::OnClose();
+ GameUI().AllowEngineHideGameUI();
+}
diff --git a/gameui/CommentaryExplanationDialog.h b/gameui/CommentaryExplanationDialog.h
new file mode 100644
index 0000000..8ee6310
--- /dev/null
+++ b/gameui/CommentaryExplanationDialog.h
@@ -0,0 +1,37 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef COMMENTARYEXPLANATIONDIALOG_H
+#define COMMENTARYEXPLANATIONDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "utlvector.h"
+#include <vgui/KeyCode.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog that explains the commentary mode
+//-----------------------------------------------------------------------------
+class CCommentaryExplanationDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CCommentaryExplanationDialog, vgui::Frame );
+
+public:
+ CCommentaryExplanationDialog(vgui::Panel *parent, char *pszFinishCommand);
+ ~CCommentaryExplanationDialog();
+
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+ virtual void OnCommand( const char *command );
+ virtual void OnClose( void );
+
+private:
+ char m_pszFinishCommand[ 512 ];
+};
+
+#endif // COMMENTARYEXPLANATIONDIALOG_H
diff --git a/gameui/ContentControlDialog.cpp b/gameui/ContentControlDialog.cpp
new file mode 100644
index 0000000..7613914
--- /dev/null
+++ b/gameui/ContentControlDialog.cpp
@@ -0,0 +1,406 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <stdio.h>
+#include <memory.h>
+#if defined( WIN32 ) && !defined( _X360 )
+#include <windows.h>
+#endif
+
+#include "ContentControlDialog.h"
+#include "checksum_md5.h"
+#include "EngineInterface.h"
+
+#include <vgui/IInput.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/RadioButton.h>
+#include <vgui_controls/TextEntry.h>
+#include <tier0/vcrmode.h>
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic help dialog
+//-----------------------------------------------------------------------------
+CContentControlDialog::CContentControlDialog(vgui::Panel *parent) : vgui::Frame(parent, "ContentControlDialog")
+{
+ SetBounds(0, 0, 372, 160);
+ SetSizeable( false );
+
+ SetTitle( "#GameUI_ContentLock", true );
+
+ m_pStatus = new vgui::Label( this, "ContentStatus", "" );
+
+ m_pPasswordLabel = new vgui::Label( this, "PasswordPrompt", "#GameUI_PasswordPrompt" );
+ m_pPassword2Label = new vgui::Label( this, "PasswordReentryPrompt", "#GameUI_PasswordReentryPrompt" );
+
+ m_pExplain = new vgui::Label( this, "ContentControlExplain", "" );
+
+ m_pPassword = new vgui::TextEntry( this, "Password" );
+ m_pPassword2 = new vgui::TextEntry( this, "Password2" );
+
+ m_pOK = new vgui::Button( this, "Ok", "#GameUI_OK" );
+ m_pOK->SetCommand( "Ok" );
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Cancel" );
+
+ m_szGorePW[ 0 ] = 0;
+ ResetPassword();
+
+ LoadControlSettings("Resource\\ContentControlDialog.res");
+
+// Explain("");
+// UpdateContentControlStatus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CContentControlDialog::~CContentControlDialog()
+{
+}
+
+void CContentControlDialog::Activate()
+{
+ BaseClass::Activate();
+
+ m_pPassword->SetText("");
+ m_pPassword->RequestFocus();
+ m_pPassword2->SetText("");
+ Explain("");
+ UpdateContentControlStatus();
+
+ input()->SetAppModalSurface(GetVPanel());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::ResetPassword()
+{
+ // Set initial value
+#ifdef WIN32
+#ifndef _XBOX
+ HKEY key;
+ if ( ERROR_SUCCESS == VCRHook_RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Valve\\Half-Life\\Settings", 0, KEY_READ, &key))
+ {
+ DWORD type;
+ DWORD bufSize = sizeof(m_szGorePW);
+
+ VCRHook_RegQueryValueEx(key, "User Token 2", NULL, &type, (unsigned char *)m_szGorePW, &bufSize );
+ VCRHook_RegCloseKey( key );
+ }
+ else
+#endif
+ {
+ m_szGorePW[ 0 ] = 0;
+ }
+#else
+ vgui::system()->SetRegistryString( "Software\\Valve\\Half-Life\\Settings\\User Token 2", m_szGorePW );
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::ApplyPassword()
+{
+ WriteToken( m_szGorePW );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::Explain( char const *fmt, ... )
+{
+ if ( !m_pExplain )
+ return;
+
+ va_list argptr;
+ char text[1024];
+
+ va_start (argptr,fmt);
+ Q_vsnprintf (text, sizeof(text), fmt, argptr);
+ va_end (argptr);
+
+ m_pExplain->SetText( text );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CContentControlDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "Ok" ) )
+ {
+ bool canclose = false;
+
+ char pw1[ 256 ];
+ char pw2[ 256 ];
+
+ m_pPassword->GetText( pw1, 256 );
+ m_pPassword2->GetText( pw2, 256 );
+
+ // Get text and check
+// bool enabled = PasswordEnabled(); //( m_szGorePW[0]!=0 ) ? true : false;
+// bool pwMatch = stricmp( pw1, pw2 ) == 0 ? true : false;
+
+ if (IsPasswordEnabledInDialog())
+ {
+ canclose = DisablePassword(pw1);
+// canclose = CheckPassword( m_szGorePW, pw1, false );
+ }
+ else if (!strcmp(pw1, pw2))
+ {
+ canclose = EnablePassword(pw1);
+// canclose = CheckPassword( NULL, pw1, true );
+ }
+ else
+ {
+ Explain( "#GameUI_PasswordsDontMatch" );
+ }
+
+ if ( canclose )
+ {
+ OnClose();
+ }
+ }
+ else if ( !stricmp( command, "Cancel" ) )
+ {
+ OnClose();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::OnClose()
+{
+ BaseClass::OnClose();
+ PostActionSignal(new KeyValues("ContentControlClose"));
+// MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::WriteToken( const char *str )
+{
+ // Set initial value
+#ifdef WIN32
+#ifndef _XBOX
+ HKEY key;
+ if ( ERROR_SUCCESS == VCRHook_RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Valve\\Half-Life\\Settings", 0, KEY_WRITE, &key))
+ {
+ DWORD type = REG_SZ;
+ DWORD bufSize = strlen( str ) + 1;
+
+ VCRHook_RegSetValueEx(key, "User Token 2", 0, type, (const unsigned char *)str, bufSize );
+
+ VCRHook_RegCloseKey( key );
+ }
+#endif
+#else
+ vgui::system()->SetRegistryString( "Software\\Valve\\Half-Life\\Settings\\User Token 2", m_szGorePW );
+#endif
+ Q_strncpy( m_szGorePW, str, sizeof( m_szGorePW ) );
+
+ UpdateContentControlStatus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::HashPassword(const char *newPW, char *hashBuffer, int maxlen )
+{
+ // Compute the md5 hash and save it.
+ unsigned char md5_hash[16];
+ MD5Context_t ctx;
+
+ MD5Init( &ctx );
+ MD5Update( &ctx, (unsigned char const *)newPW, strlen( newPW ) );
+ MD5Final( md5_hash, &ctx );
+
+ char hex[ 128 ];
+ Q_binarytohex( md5_hash, sizeof( md5_hash ), hex, sizeof( hex ) );
+
+// char digestedPW[ 128 ];
+ Q_strncpy( hashBuffer, hex, maxlen );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+/*
+bool CContentControlDialog::CheckPassword( char const *oldPW, char const *newPW, bool enableContentControl )
+{
+ char digestedPW[ 128 ];
+ HashPassword(newPW, digestedPW, sizeof( digestedPW ) );
+
+ // Compute the md5 hash and save it.
+ unsigned char md5_hash[16];
+ MD5Context_t ctx;
+
+ MD5Init( &ctx );
+ MD5Update( &ctx, (unsigned char const *)(LPCSTR)newPW, strlen( newPW ) );
+ MD5Final( md5_hash, &ctx );
+
+ char hex[ 128 ];
+ Q_binarytohex( md5_hash, sizeof( md5_hash ), hex, sizeof( hex ) );
+
+ Q_strncpy( digestedPW, hex, sizeof( digestedPW ) );
+*/
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CContentControlDialog::EnablePassword(const char *newPW)
+{
+ if ( !newPW[ 0 ] )
+ {
+ Explain( "#GameUI_MustEnterPassword" );
+ return false;
+ }
+
+ char digestedPW[ 128 ];
+ HashPassword(newPW, digestedPW, sizeof( digestedPW ) );
+
+ // disable violence
+/* engine->Cvar_SetValue("violence_hblood", 0.0 );
+ engine->Cvar_SetValue("violence_hgibs" , 0.0 );
+ engine->Cvar_SetValue("violence_ablood", 0.0 );
+ engine->Cvar_SetValue("violence_agibs" , 0.0 );
+ */
+
+ ConVarRef violence_hblood( "violence_hblood" );
+ violence_hblood.SetValue(false);
+
+ ConVarRef violence_hgibs( "violence_hgibs" );
+ violence_hgibs.SetValue(false);
+
+ ConVarRef violence_ablood( "violence_ablood" );
+ violence_ablood.SetValue(false);
+
+ ConVarRef violence_agibs( "violence_agibs" );
+ violence_agibs.SetValue(false);
+
+ // Store digest to registry
+// WriteToken( digestedPW );
+ Q_strncpy(m_szGorePW, digestedPW, sizeof( m_szGorePW ) );
+ /*
+ }
+ else
+ {
+ if ( stricmp( oldPW, digestedPW ) )
+ {
+ // Warn that password is invalid
+ Explain( "#GameUI_IncorrectPassword" );
+ return false;
+ }
+ }
+ }*/
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CContentControlDialog::DisablePassword(const char *oldPW)
+{
+ if ( !oldPW[ 0 ] )
+ {
+ Explain( "#GameUI_MustEnterPassword" );
+ return false;
+ }
+
+ char digestedPW[ 128 ];
+ HashPassword(oldPW, digestedPW, sizeof( digestedPW ) );
+
+ if( stricmp( m_szGorePW, digestedPW ) )
+ {
+ Explain( "#GameUI_IncorrectPassword" );
+ return false;
+ }
+
+ m_szGorePW[0] = 0;
+
+ // set the violence cvars
+/* engine->Cvar_SetValue("violence_hblood", 1.0 );
+ engine->Cvar_SetValue("violence_hgibs" , 1.0 );
+ engine->Cvar_SetValue("violence_ablood", 1.0 );
+ engine->Cvar_SetValue("violence_agibs" , 1.0 );
+ */
+ ConVarRef violence_hblood( "violence_hblood" );
+ violence_hblood.SetValue(true);
+
+ ConVarRef violence_hgibs( "violence_hgibs" );
+ violence_hgibs.SetValue(true);
+
+ ConVarRef violence_ablood( "violence_ablood" );
+ violence_ablood.SetValue(true);
+
+ ConVarRef violence_agibs( "violence_agibs" );
+ violence_agibs.SetValue(true);
+
+
+// // Remove digest value
+// WriteToken( "" );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CContentControlDialog::IsPasswordEnabledInDialog()
+{
+ return m_szGorePW[0] != 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CContentControlDialog::UpdateContentControlStatus( void )
+{
+ bool enabled = IsPasswordEnabledInDialog(); //( m_szGorePW[0]!=0 ) ? true : false;
+ m_pStatus->SetText( enabled ? "#GameUI_ContentStatusEnabled" : "#GameUI_ContentStatusDisabled" );
+
+ if (enabled)
+ {
+ m_pPasswordLabel->SetText("#GameUI_PasswordDisablePrompt");
+ }
+ else
+ {
+ m_pPasswordLabel->SetText("#GameUI_PasswordPrompt");
+ }
+
+ // hide the re-entry
+ m_pPassword2Label->SetVisible(!enabled);
+ m_pPassword2->SetVisible(!enabled);
+// m_pOK->SetText( enabled ? "#GameUI_Disable" : "#GameUI_Enable" );
+}
diff --git a/gameui/ContentControlDialog.h b/gameui/ContentControlDialog.h
new file mode 100644
index 0000000..f4aeb4d
--- /dev/null
+++ b/gameui/ContentControlDialog.h
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CONTENTCONTROLDIALOG_H
+#define CONTENTCONTROLDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CContentControlDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CContentControlDialog, vgui::Frame );
+
+public:
+ CContentControlDialog(vgui::Panel *parent);
+ ~CContentControlDialog();
+
+ virtual void OnCommand( const char *command );
+ virtual void OnClose();
+ virtual void Activate();
+
+ void ResetPassword();
+ void ApplyPassword();
+ bool IsPasswordEnabledInDialog();
+ bool IsPasswordEnabled() { return ( m_szGorePW[0] != 0 ); }
+
+protected:
+ void WriteToken( const char *str );
+ bool CheckPassword( char const *oldPW, char const *newPW, bool enableContentControl );
+ void UpdateContentControlStatus( void );
+
+ void Explain( PRINTF_FORMAT_STRING char const *fmt, ... );
+
+ void HashPassword(const char *newPW, char *hashBuffer, int maxlen );
+ bool EnablePassword(const char *newPW);
+ bool DisablePassword(const char *oldPW);
+
+ enum
+ {
+ MAX_GORE_PW = 64,
+ };
+
+ char m_szGorePW[ MAX_GORE_PW ];
+
+ bool m_bDefaultPassword;
+ vgui::Label *m_pStatus;
+ vgui::Button *m_pOK;
+ vgui::TextEntry *m_pPassword;
+ vgui::Label *m_pPasswordLabel;
+ vgui::Label *m_pPassword2Label;
+ vgui::TextEntry *m_pPassword2;
+
+ vgui::Label *m_pExplain;
+};
+
+
+#endif // CONTENTCONTROLDIALOG_H
diff --git a/gameui/ControllerDialog.cpp b/gameui/ControllerDialog.cpp
new file mode 100644
index 0000000..69dcf37
--- /dev/null
+++ b/gameui/ControllerDialog.cpp
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "ControllerDialog.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+
+CControllerDialog::CControllerDialog( vgui::Panel *parent ) : BaseClass( parent, true ) // TRUE second param says we want the controller options
+{
+}
+
+void CControllerDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetControlString( "TitleLabel", "#GameUI_Controller" );
+}
diff --git a/gameui/ControllerDialog.h b/gameui/ControllerDialog.h
new file mode 100644
index 0000000..eff42fd
--- /dev/null
+++ b/gameui/ControllerDialog.h
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef CONTROLLERDIALOG_H
+#define CONTROLLERDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "OptionsDialog.h"
+
+class CControllerDialog : public COptionsDialogXbox
+{
+ DECLARE_CLASS_SIMPLE( CControllerDialog, COptionsDialogXbox );
+
+public:
+ CControllerDialog(vgui::Panel *parent);
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+};
+
+#endif // CONTROLLERDIALOG_H
+
diff --git a/gameui/CreateMultiplayerGameBotPage.cpp b/gameui/CreateMultiplayerGameBotPage.cpp
new file mode 100644
index 0000000..0f27128
--- /dev/null
+++ b/gameui/CreateMultiplayerGameBotPage.cpp
@@ -0,0 +1,228 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#include "CreateMultiplayerGameBotPage.h"
+
+using namespace vgui;
+
+#include <KeyValues.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+
+#include "filesystem.h"
+#include "PanelListPanel.h"
+#include "scriptobject.h"
+#include <tier0/vcrmode.h>
+#include "tier1/convar.h"
+#include "EngineInterface.h"
+#include "CvarToggleCheckButton.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+// for join team combo box
+enum BotGUITeamType
+{
+ BOT_GUI_TEAM_RANDOM = 0,
+ BOT_GUI_TEAM_CT = 1,
+ BOT_GUI_TEAM_T = 2
+};
+
+// these must correlate with above enum
+static const char *joinTeamArg[] = { "any", "ct", "t", NULL };
+
+
+// for bot chatter combo box
+enum BotGUIChatterType
+{
+ BOT_GUI_CHATTER_NORMAL = 0,
+ BOT_GUI_CHATTER_MINIMAL = 1,
+ BOT_GUI_CHATTER_RADIO = 2,
+ BOT_GUI_CHATTER_OFF = 3
+};
+
+// these must correlate with above enum
+static const char *chatterArg[] = { "normal", "minimal", "radio", "off", NULL };
+
+
+extern void UTIL_StripInvalidCharacters( char *pszInput );
+
+
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameBotPage::SetJoinTeamCombo( const char *team )
+{
+ if (team)
+ {
+ for( int i=0; joinTeamArg[i]; ++i )
+ if (!stricmp( team, joinTeamArg[i] ))
+ {
+ m_joinTeamCombo->ActivateItemByRow( i );
+ return;
+ }
+ }
+ else
+ {
+ m_joinTeamCombo->ActivateItemByRow( BOT_GUI_TEAM_RANDOM );
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameBotPage::SetChatterCombo( const char *chatter )
+{
+ if (chatter)
+ {
+ for( int i=0; chatterArg[i]; ++i )
+ if (!stricmp( chatter, chatterArg[i] ))
+ {
+ m_chatterCombo->ActivateItemByRow( i );
+ return;
+ }
+ }
+ else
+ {
+ m_joinTeamCombo->ActivateItemByRow( BOT_GUI_CHATTER_NORMAL );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Constructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameBotPage::CCreateMultiplayerGameBotPage( vgui::Panel *parent, const char *name, KeyValues *botKeys ) : PropertyPage( parent, name )
+{
+ m_pSavedData = botKeys;
+
+ m_allowRogues = new CCvarToggleCheckButton( this, "BotAllowRogueCheck", "", "bot_allow_rogues" );
+ m_allowPistols = new CCvarToggleCheckButton( this, "BotAllowPistolsCheck", "", "bot_allow_pistols" );
+ m_allowShotguns = new CCvarToggleCheckButton( this, "BotAllowShotgunsCheck", "", "bot_allow_shotguns" );
+ m_allowSubmachineGuns = new CCvarToggleCheckButton( this, "BotAllowSubmachineGunsCheck", "", "bot_allow_sub_machine_guns" );
+ m_allowRifles = new CCvarToggleCheckButton( this, "BotAllowRiflesCheck", "", "bot_allow_rifles" );
+ m_allowMachineGuns = new CCvarToggleCheckButton( this, "BotAllowMachineGunsCheck", "", "bot_allow_machine_guns" );
+ m_allowGrenades = new CCvarToggleCheckButton( this, "BotAllowGrenadesCheck", "", "bot_allow_grenades" );
+ m_allowSnipers = new CCvarToggleCheckButton( this, "BotAllowSnipersCheck", "", "bot_allow_snipers" );
+#ifdef CS_SHIELD_ENABLED
+ m_allowShields = new CCvarToggleCheckButton( this, "BotAllowShieldCheck", "", "bot_allow_shield" );
+#endif // CS_SHIELD_ENABLED
+
+ m_joinAfterPlayer = new CCvarToggleCheckButton( this, "BotJoinAfterPlayerCheck", "", "bot_join_after_player" );
+
+ m_deferToHuman = new CCvarToggleCheckButton( this, "BotDeferToHumanCheck", "", "bot_defer_to_human" );
+
+ // set up team join combo box
+ // NOTE: If order of AddItem is changed, update the associated enum
+ m_joinTeamCombo = new ComboBox( this, "BotJoinTeamCombo", 3, false );
+ m_joinTeamCombo->AddItem( "#Cstrike_Random", NULL );
+ m_joinTeamCombo->AddItem( "#Cstrike_Team_CT", NULL );
+ m_joinTeamCombo->AddItem( "#Cstrike_Team_T", NULL );
+
+ // set up chatter combo box
+ // NOTE: If order of AddItem is changed, update the associated enum
+ m_chatterCombo = new ComboBox( this, "BotChatterCombo", 4, false );
+ m_chatterCombo->AddItem( "#Cstrike_Bot_Chatter_Normal", NULL );
+ m_chatterCombo->AddItem( "#Cstrike_Bot_Chatter_Minimal", NULL );
+ m_chatterCombo->AddItem( "#Cstrike_Bot_Chatter_Radio", NULL );
+ m_chatterCombo->AddItem( "#Cstrike_Bot_Chatter_Off", NULL );
+
+ // create text entry fields for quota and prefix
+ m_prefixEntry = new TextEntry( this, "BotPrefixEntry" );
+
+ // set positions and sizes from resources file
+ LoadControlSettings( "Resource/CreateMultiplayerGameBotPage.res" );
+
+ // get initial values from bot keys
+ m_joinAfterPlayer->SetSelected( botKeys->GetInt( "bot_join_after_player", 1 ) );
+ m_allowRogues->SetSelected( botKeys->GetInt( "bot_allow_rogues", 1 ) );
+ m_allowPistols->SetSelected( botKeys->GetInt( "bot_allow_pistols", 1 ) );
+ m_allowShotguns->SetSelected( botKeys->GetInt( "bot_allow_shotguns", 1 ) );
+ m_allowSubmachineGuns->SetSelected( botKeys->GetInt( "bot_allow_sub_machine_guns", 1 ) );
+ m_allowMachineGuns->SetSelected( botKeys->GetInt( "bot_allow_machine_guns", 1 ) );
+ m_allowRifles->SetSelected( botKeys->GetInt( "bot_allow_rifles", 1 ) );
+ m_allowSnipers->SetSelected( botKeys->GetInt( "bot_allow_snipers", 1 ) );
+ m_allowGrenades->SetSelected( botKeys->GetInt( "bot_allow_grenades", 1 ) );
+#ifdef CS_SHIELD_ENABLED
+ m_allowShields->SetSelected( botKeys->GetInt( "bot_allow_shield", 1 ) );
+#endif // CS_SHIELD_ENABLED
+ m_deferToHuman->SetSelected( botKeys->GetInt( "bot_defer_to_human", 1 ) );
+
+ SetJoinTeamCombo( botKeys->GetString( "bot_join_team", "any" ) );
+ SetChatterCombo( botKeys->GetString( "bot_chatter", "normal" ) );
+
+ // set bot_prefix
+ const char *prefix = botKeys->GetString( "bot_prefix" );
+ if (prefix)
+ SetControlString( "BotPrefixEntry", prefix );
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameBotPage::~CCreateMultiplayerGameBotPage()
+{
+ // vgui handles deletion of children automatically through the hierarchy
+}
+
+//-----------------------------------------------------------------------------
+// Reset values
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameBotPage::OnResetChanges()
+{
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void UpdateValue( KeyValues *data, const char *cvarName, int value )
+{
+ data->SetInt( cvarName, value );
+
+ ConVarRef var( cvarName );
+ var.SetValue( value );
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void UpdateValue( KeyValues *data, const char *cvarName, const char *value )
+{
+ data->SetString( cvarName, value );
+
+ ConVarRef var( cvarName );
+ var.SetValue( value );
+}
+
+//-----------------------------------------------------------------------------
+// Called to get data from the page
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameBotPage::OnApplyChanges()
+{
+ UpdateValue( m_pSavedData, "bot_join_after_player", m_joinAfterPlayer->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_rogues", m_allowRogues->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_pistols", m_allowPistols->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_shotguns", m_allowShotguns->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_sub_machine_guns", m_allowSubmachineGuns->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_machine_guns", m_allowMachineGuns->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_rifles", m_allowRifles->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_snipers", m_allowSnipers->IsSelected() );
+ UpdateValue( m_pSavedData, "bot_allow_grenades", m_allowGrenades->IsSelected() );
+#ifdef CS_SHIELD_ENABLED
+ UpdateValue( m_pSavedData, "bot_allow_shield", m_allowShields->IsSelected() );
+#endif // CS_SHIELD_ENABLED
+ UpdateValue( m_pSavedData, "bot_defer_to_human", m_deferToHuman->IsSelected() );
+
+ // set bot_join_team
+ UpdateValue( m_pSavedData, "bot_join_team", joinTeamArg[ m_joinTeamCombo->GetActiveItem() ] );
+
+ // set bot_chatter
+ UpdateValue( m_pSavedData, "bot_chatter", chatterArg[ m_chatterCombo->GetActiveItem() ] );
+
+ // set bot_prefix
+ #define BUF_LENGTH 256
+ char entryBuffer[ BUF_LENGTH ];
+ m_prefixEntry->GetText( entryBuffer, BUF_LENGTH );
+ UpdateValue( m_pSavedData, "bot_prefix", entryBuffer );
+}
+
diff --git a/gameui/CreateMultiplayerGameBotPage.h b/gameui/CreateMultiplayerGameBotPage.h
new file mode 100644
index 0000000..d9f698e
--- /dev/null
+++ b/gameui/CreateMultiplayerGameBotPage.h
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CREATEMULTIPLAYERGAMEBOTPAGE_H
+#define CREATEMULTIPLAYERGAMEBOTPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+class CPanelListPanel;
+class CDescription;
+class mpcontrol_t;
+class CCvarToggleCheckButton;
+
+//-----------------------------------------------------------------------------
+// Purpose: advanced bot properties page of the create game server dialog
+//-----------------------------------------------------------------------------
+class CCreateMultiplayerGameBotPage : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CCreateMultiplayerGameBotPage, vgui::PropertyPage );
+
+public:
+ CCreateMultiplayerGameBotPage( vgui::Panel *parent, const char *name, KeyValues *botKeys );
+ ~CCreateMultiplayerGameBotPage();
+
+protected:
+ virtual void OnResetChanges();
+ virtual void OnApplyChanges();
+
+private:
+ CCvarToggleCheckButton *m_joinAfterPlayer;
+
+ CCvarToggleCheckButton *m_allowRogues;
+
+ CCvarToggleCheckButton *m_allowPistols;
+ CCvarToggleCheckButton *m_allowShotguns;
+ CCvarToggleCheckButton *m_allowSubmachineGuns;
+ CCvarToggleCheckButton *m_allowMachineGuns;
+ CCvarToggleCheckButton *m_allowRifles;
+ CCvarToggleCheckButton *m_allowGrenades;
+#ifdef CS_SHIELD_ENABLED
+ CCvarToggleCheckButton *m_allowShields;
+#endif // CS_SHIELD_ENABLED
+ CCvarToggleCheckButton *m_allowSnipers;
+
+ CCvarToggleCheckButton *m_deferToHuman;
+
+ vgui::ComboBox *m_joinTeamCombo;
+ void SetJoinTeamCombo( const char *team );
+
+ vgui::ComboBox *m_chatterCombo;
+ void SetChatterCombo( const char *team );
+
+ vgui::TextEntry *m_prefixEntry;
+
+ KeyValues *m_pSavedData;
+};
+
+
+#endif // CREATEMULTIPLAYERGAMEBOTPAGE_H
diff --git a/gameui/CreateMultiplayerGameDialog.cpp b/gameui/CreateMultiplayerGameDialog.cpp
new file mode 100644
index 0000000..a372255
--- /dev/null
+++ b/gameui/CreateMultiplayerGameDialog.cpp
@@ -0,0 +1,190 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "CreateMultiplayerGameDialog.h"
+#include "CreateMultiplayerGameServerPage.h"
+#include "CreateMultiplayerGameGameplayPage.h"
+#include "CreateMultiplayerGameBotPage.h"
+
+#include "EngineInterface.h"
+#include "ModInfo.h"
+#include "GameUI_Interface.h"
+
+#include <stdio.h>
+
+using namespace vgui;
+
+#include "vgui_controls/ComboBox.h"
+#include <vgui/ILocalize.h>
+
+#include "filesystem.h"
+#include <KeyValues.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameDialog::CCreateMultiplayerGameDialog(vgui::Panel *parent) : PropertyDialog(parent, "CreateMultiplayerGameDialog")
+{
+ m_bBotsEnabled = false;
+ SetDeleteSelfOnClose(true);
+ SetSize(348, 460);
+
+ SetTitle("#GameUI_CreateServer", true);
+ SetOKButtonText("#GameUI_Start");
+
+ if ( ModInfo().UseBots() )
+ {
+ m_bBotsEnabled = true;
+ }
+
+ m_pServerPage = new CCreateMultiplayerGameServerPage(this, "ServerPage");
+ m_pGameplayPage = new CCreateMultiplayerGameGameplayPage(this, "GameplayPage");
+ m_pBotPage = NULL;
+
+ AddPage(m_pServerPage, "#GameUI_Server");
+ AddPage(m_pGameplayPage, "#GameUI_Game");
+
+ // create KeyValues object to load/save config options
+ m_pSavedData = new KeyValues( "ServerConfig" );
+
+ // load the config data
+ if (m_pSavedData)
+ {
+ m_pSavedData->LoadFromFile( g_pFullFileSystem, "ServerConfig.vdf", "GAME" ); // this is game-specific data, so it should live in GAME, not CONFIG
+
+ const char *startMap = m_pSavedData->GetString("map", "");
+ if (startMap[0])
+ {
+ m_pServerPage->SetMap(startMap);
+ }
+ }
+
+ if ( m_bBotsEnabled )
+ {
+ // add a page of advanced bot controls
+ // NOTE: These controls will use the bot keys to initialize their values
+ m_pBotPage = new CCreateMultiplayerGameBotPage( this, "BotPage", m_pSavedData );
+ AddPage( m_pBotPage, "#GameUI_CPUPlayerOptions" );
+ m_pServerPage->EnableBots( m_pSavedData );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameDialog::~CCreateMultiplayerGameDialog()
+{
+ if (m_pSavedData)
+ {
+ m_pSavedData->deleteThis();
+ m_pSavedData = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: runs the server when the OK button is pressed
+//-----------------------------------------------------------------------------
+bool CCreateMultiplayerGameDialog::OnOK(bool applyOnly)
+{
+ // reset server enforced cvars
+ g_pCVar->RevertFlaggedConVars( FCVAR_REPLICATED );
+
+ // Cheats were disabled; revert all cheat cvars to their default values.
+ // This must be done heading into multiplayer games because people can play
+ // demos etc and set cheat cvars with sv_cheats 0.
+ g_pCVar->RevertFlaggedConVars( FCVAR_CHEAT );
+
+ DevMsg( "FCVAR_CHEAT cvars reverted to defaults.\n" );
+
+ BaseClass::OnOK(applyOnly);
+
+ // get these values from m_pServerPage and store them temporarily
+ char szMapName[64], szHostName[64], szPassword[64];
+ strncpy(szMapName, m_pServerPage->GetMapName(), sizeof( szMapName ));
+ strncpy(szHostName, m_pGameplayPage->GetHostName(), sizeof( szHostName ));
+ strncpy(szPassword, m_pGameplayPage->GetPassword(), sizeof( szPassword ));
+
+ // save the config data
+ if (m_pSavedData)
+ {
+ if (m_pServerPage->IsRandomMapSelected())
+ {
+ // it's set to random map, just save an
+ m_pSavedData->SetString("map", "");
+ }
+ else
+ {
+ m_pSavedData->SetString("map", szMapName);
+ }
+
+ // save config to a file
+ m_pSavedData->SaveToFile( g_pFullFileSystem, "ServerConfig.vdf", "GAME" );
+ }
+
+ char szMapCommand[1024];
+
+ // create the command to execute
+ Q_snprintf(szMapCommand, sizeof( szMapCommand ), "disconnect\nwait\nwait\nsv_lan 1\nsetmaster enable\nmaxplayers %i\nsv_password \"%s\"\nhostname \"%s\"\nprogress_enable\nmap %s\n",
+ m_pGameplayPage->GetMaxPlayers(),
+ szPassword,
+ szHostName,
+ szMapName
+ );
+
+ // exec
+ engine->ClientCmd_Unrestricted(szMapCommand);
+
+ return true;
+}
+
+void CCreateMultiplayerGameDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // Handle close here, CBasePanel parent doesn't support "DialogClosing" command
+ ButtonCode_t nButtonCode = GetBaseButtonCode( code );
+
+ if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B )
+ {
+ OnCommand( "Close" );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A )
+ {
+ OnOK( false );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_UP ||
+ nButtonCode == KEY_XSTICK1_UP ||
+ nButtonCode == KEY_XSTICK2_UP ||
+ nButtonCode == STEAMCONTROLLER_DPAD_UP ||
+ nButtonCode == KEY_UP )
+ {
+ int nItem = m_pServerPage->GetMapList()->GetActiveItem() - 1;
+ if ( nItem < 0 )
+ {
+ nItem = m_pServerPage->GetMapList()->GetItemCount() - 1;
+ }
+ m_pServerPage->GetMapList()->ActivateItem( nItem );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_DOWN ||
+ nButtonCode == KEY_XSTICK1_DOWN ||
+ nButtonCode == KEY_XSTICK2_DOWN ||
+ nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
+ nButtonCode == KEY_DOWN )
+ {
+ int nItem = m_pServerPage->GetMapList()->GetActiveItem() + 1;
+ if ( nItem >= m_pServerPage->GetMapList()->GetItemCount() )
+ {
+ nItem = 0;
+ }
+ m_pServerPage->GetMapList()->ActivateItem( nItem );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+} \ No newline at end of file
diff --git a/gameui/CreateMultiplayerGameDialog.h b/gameui/CreateMultiplayerGameDialog.h
new file mode 100644
index 0000000..4507f5f
--- /dev/null
+++ b/gameui/CreateMultiplayerGameDialog.h
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CREATEMULTIPLAYERGAMEDIALOG_H
+#define CREATEMULTIPLAYERGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyDialog.h>
+
+class CCreateMultiplayerGameServerPage;
+class CCreateMultiplayerGameGameplayPage;
+class CCreateMultiplayerGameBotPage;
+
+//-----------------------------------------------------------------------------
+// Purpose: dialog for launching a listenserver
+//-----------------------------------------------------------------------------
+class CCreateMultiplayerGameDialog : public vgui::PropertyDialog
+{
+ DECLARE_CLASS_SIMPLE( CCreateMultiplayerGameDialog, vgui::PropertyDialog );
+
+public:
+ CCreateMultiplayerGameDialog(vgui::Panel *parent);
+ ~CCreateMultiplayerGameDialog();
+
+protected:
+ virtual bool OnOK(bool applyOnly);
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+private:
+ CCreateMultiplayerGameServerPage *m_pServerPage;
+ CCreateMultiplayerGameGameplayPage *m_pGameplayPage;
+ CCreateMultiplayerGameBotPage *m_pBotPage;
+
+ bool m_bBotsEnabled;
+
+ // for loading/saving game config
+ KeyValues *m_pSavedData;
+};
+
+
+#endif // CREATEMULTIPLAYERGAMEDIALOG_H
diff --git a/gameui/CreateMultiplayerGameGameplayPage.cpp b/gameui/CreateMultiplayerGameGameplayPage.cpp
new file mode 100644
index 0000000..4c8e06a
--- /dev/null
+++ b/gameui/CreateMultiplayerGameGameplayPage.cpp
@@ -0,0 +1,475 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <stdio.h>
+#include <time.h>
+
+#include "CreateMultiplayerGameGameplayPage.h"
+
+using namespace vgui;
+
+#include <KeyValues.h>
+#include <vgui/ILocalize.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/TextEntry.h>
+
+#include "filesystem.h"
+#include "PanelListPanel.h"
+#include "scriptobject.h"
+#include <tier0/vcrmode.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#define OPTIONS_DIR "cfg"
+#define DEFAULT_OPTIONS_FILE OPTIONS_DIR "/settings_default.scr"
+#define OPTIONS_FILE OPTIONS_DIR "/settings.scr"
+
+//-----------------------------------------------------------------------------
+// Purpose: class for loading/saving server config file
+//-----------------------------------------------------------------------------
+class CServerDescription : public CDescription
+{
+public:
+ CServerDescription( void );
+
+ void WriteScriptHeader( FileHandle_t fp );
+ void WriteFileHeader( FileHandle_t fp );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameGameplayPage::CCreateMultiplayerGameGameplayPage(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ SetSize( 10, 10 ); // Quiet "parent not sized yet" spew
+ m_pOptionsList = new CPanelListPanel(this, "GameOptions");
+
+ m_pDescription = new CServerDescription();
+ m_pDescription->InitFromFile( DEFAULT_OPTIONS_FILE );
+ m_pDescription->InitFromFile( OPTIONS_FILE );
+ m_pList = NULL;
+
+ LoadControlSettings("Resource/CreateMultiplayerGameGameplayPage.res");
+
+ LoadGameOptionsList();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameGameplayPage::~CCreateMultiplayerGameGameplayPage()
+{
+ delete m_pDescription;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CCreateMultiplayerGameGameplayPage::GetMaxPlayers()
+{
+ return atoi(GetValue("maxplayers", "32"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameGameplayPage::GetPassword()
+{
+ return GetValue("sv_password", "");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameGameplayPage::GetHostName()
+{
+ return GetValue("hostname", "Half-Life");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameGameplayPage::GetValue(const char *cvarName, const char *defaultValue)
+{
+ for (mpcontrol_t *mp = m_pList; mp != NULL; mp = mp->next)
+ {
+ Panel *control = mp->pControl;
+ if (control && !stricmp(mp->GetName(), cvarName))
+ {
+ KeyValues *data = new KeyValues("GetText");
+ static char buf[128];
+ if (control && control->RequestInfo(data))
+ {
+ strncpy(buf, data->GetString("text", defaultValue), sizeof(buf) - 1);
+ }
+ else
+ {
+ // no value found, copy in default text
+ strncpy(buf, defaultValue, sizeof(buf) - 1);
+ }
+
+ // ensure null termination of string
+ buf[sizeof(buf) - 1] = 0;
+
+ // free
+ data->deleteThis();
+ return buf;
+ }
+
+ }
+
+ return defaultValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called to get data from the page
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameGameplayPage::OnApplyChanges()
+{
+ // Get the values from the controls
+ GatherCurrentValues();
+
+ // Create the game.cfg file
+ if ( m_pDescription )
+ {
+ FileHandle_t fp;
+
+ // Add settings to config.cfg
+ m_pDescription->WriteToConfig();
+
+ // save out in the settings file
+ g_pFullFileSystem->CreateDirHierarchy( OPTIONS_DIR, "GAME" );
+ fp = g_pFullFileSystem->Open( OPTIONS_FILE, "wb", "GAME" );
+ if ( fp )
+ {
+ m_pDescription->WriteToScriptFile( fp );
+ g_pFullFileSystem->Close( fp );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates all the controls in the game options list
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameGameplayPage::LoadGameOptionsList()
+{
+ // destroy any existing controls
+ mpcontrol_t *p, *n;
+
+ p = m_pList;
+ while ( p )
+ {
+ n = p->next;
+ //
+ delete p->pControl;
+ delete p->pPrompt;
+ delete p;
+ p = n;
+ }
+
+ m_pList = NULL;
+
+
+ // Go through desciption creating controls
+ CScriptObject *pObj;
+
+ pObj = m_pDescription->pObjList;
+
+ mpcontrol_t *pCtrl;
+
+ CheckButton *pBox;
+ TextEntry *pEdit;
+ ComboBox *pCombo;
+ CScriptListItem *pListItem;
+
+ Panel *objParent = m_pOptionsList;
+
+ while ( pObj )
+ {
+ if ( pObj->type == O_OBSOLETE )
+ {
+ pObj = pObj->pNext;
+ continue;
+ }
+
+ pCtrl = new mpcontrol_t( objParent, pObj->cvarname );
+ pCtrl->type = pObj->type;
+
+ switch ( pCtrl->type )
+ {
+ case O_BOOL:
+ pBox = new CheckButton( pCtrl, "DescCheckButton", pObj->prompt );
+ pBox->SetSelected( pObj->fdefValue != 0.0f ? true : false );
+
+ pCtrl->pControl = (Panel *)pBox;
+ break;
+ case O_STRING:
+ case O_NUMBER:
+ pEdit = new TextEntry( pCtrl, "DescEdit");
+ pEdit->InsertString(pObj->defValue);
+ pCtrl->pControl = (Panel *)pEdit;
+ break;
+ case O_LIST:
+ pCombo = new ComboBox( pCtrl, "DescEdit", 5, false );
+
+ pListItem = pObj->pListItems;
+ while ( pListItem )
+ {
+ pCombo->AddItem(pListItem->szItemText, NULL);
+ pListItem = pListItem->pNext;
+ }
+
+ pCombo->ActivateItemByRow((int)pObj->fdefValue);
+
+ pCtrl->pControl = (Panel *)pCombo;
+ break;
+ default:
+ break;
+ }
+
+ if ( pCtrl->type != O_BOOL )
+ {
+ pCtrl->pPrompt = new vgui::Label( pCtrl, "DescLabel", "" );
+ pCtrl->pPrompt->SetContentAlignment( vgui::Label::a_west );
+ pCtrl->pPrompt->SetTextInset( 5, 0 );
+ pCtrl->pPrompt->SetText( pObj->prompt );
+ }
+
+ pCtrl->pScrObj = pObj;
+ pCtrl->SetSize( 100, 28 );
+ //pCtrl->SetBorder( scheme()->GetBorder(1, "DepressedButtonBorder") );
+ m_pOptionsList->AddItem( pCtrl );
+
+ // Link it in
+ if ( !m_pList )
+ {
+ m_pList = pCtrl;
+ pCtrl->next = NULL;
+ }
+ else
+ {
+ mpcontrol_t *p;
+ p = m_pList;
+ while ( p )
+ {
+ if ( !p->next )
+ {
+ p->next = pCtrl;
+ pCtrl->next = NULL;
+ break;
+ }
+ p = p->next;
+ }
+ }
+
+ pObj = pObj->pNext;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: applies all the values in the page
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameGameplayPage::GatherCurrentValues()
+{
+ if ( !m_pDescription )
+ return;
+
+ // OK
+ CheckButton *pBox;
+ TextEntry *pEdit;
+ ComboBox *pCombo;
+
+ mpcontrol_t *pList;
+
+ CScriptObject *pObj;
+ CScriptListItem *pItem;
+
+ char szValue[256];
+ char strValue[256];
+ wchar_t w_szStrValue[256];
+
+ pList = m_pList;
+ while ( pList )
+ {
+ pObj = pList->pScrObj;
+
+ if ( !pList->pControl )
+ {
+ pObj->SetCurValue( pObj->defValue );
+ pList = pList->next;
+ continue;
+ }
+
+ switch ( pObj->type )
+ {
+ case O_BOOL:
+ pBox = (CheckButton *)pList->pControl;
+ Q_snprintf( szValue, sizeof( szValue ), "%s", pBox->IsSelected() ? "1" : "0" );
+ break;
+ case O_NUMBER:
+ pEdit = ( TextEntry * )pList->pControl;
+ pEdit->GetText( strValue, sizeof( strValue ) );
+ Q_snprintf( szValue, sizeof( szValue ), "%s", strValue );
+ break;
+ case O_STRING:
+ pEdit = ( TextEntry * )pList->pControl;
+ pEdit->GetText( strValue, sizeof( strValue ) );
+ Q_snprintf( szValue, sizeof( szValue ), "%s", strValue );
+ break;
+ case O_LIST:
+ pCombo = ( ComboBox *)pList->pControl;
+ pCombo->GetText( w_szStrValue, sizeof( w_szStrValue ) / sizeof( wchar_t ) );
+
+ pItem = pObj->pListItems;
+
+ while ( pItem )
+ {
+ wchar_t *wLocalizedString = NULL;
+ wchar_t w_szStrTemp[256];
+
+ // Localized string?
+ if ( pItem->szItemText[0] == '#' )
+ {
+ wLocalizedString = g_pVGuiLocalize->Find( pItem->szItemText );
+ }
+
+ if ( wLocalizedString )
+ {
+ // Copy the string we found into our temp array
+ V_wcscpy_safe( w_szStrTemp, wLocalizedString );
+ }
+ else
+ {
+ // Just convert what we have to Unicode
+ g_pVGuiLocalize->ConvertANSIToUnicode( pItem->szItemText, w_szStrTemp, sizeof( w_szStrTemp ) );
+ }
+
+ if ( _wcsicmp( w_szStrTemp, w_szStrValue ) == 0 )
+ {
+ // Found a match!
+ break;
+ }
+
+ pItem = pItem->pNext;
+ }
+
+ if ( pItem )
+ {
+ Q_snprintf( szValue, sizeof( szValue ), "%s", pItem->szValue );
+ }
+ else //Couldn't find index
+ {
+ Q_snprintf( szValue, sizeof( szValue ), "%s", pObj->defValue );
+ }
+ break;
+ }
+
+ // Remove double quotes and % characters
+ UTIL_StripInvalidCharacters( szValue, sizeof( szValue ) );
+
+ Q_strncpy( strValue, szValue, sizeof( strValue ) );
+
+ pObj->SetCurValue( strValue );
+
+ pList = pList->next;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor, load/save server settings object
+//-----------------------------------------------------------------------------
+CServerDescription::CServerDescription( void ) : CDescription()
+{
+ setHint( "// NOTE: THIS FILE IS AUTOMATICALLY REGENERATED, \r\n"
+"//DO NOT EDIT THIS HEADER, YOUR COMMENTS WILL BE LOST IF YOU DO\r\n"
+"// Multiplayer options script\r\n"
+"//\r\n"
+"// Format:\r\n"
+"// Version [float]\r\n"
+"// Options description followed by \r\n"
+"// Options defaults\r\n"
+"//\r\n"
+"// Option description syntax:\r\n"
+"//\r\n"
+"// \"cvar\" { \"Prompt\" { type [ type info ] } { default } }\r\n"
+"//\r\n"
+"// type = \r\n"
+"// BOOL (a yes/no toggle)\r\n"
+"// STRING\r\n"
+"// NUMBER\r\n"
+"// LIST\r\n"
+"//\r\n"
+"// type info:\r\n"
+"// BOOL no type info\r\n"
+"// NUMBER min max range, use -1 -1 for no limits\r\n"
+"// STRING no type info\r\n"
+"// LIST "" delimited list of options value pairs\r\n"
+"//\r\n"
+"//\r\n"
+"// default depends on type\r\n"
+"// BOOL is \"0\" or \"1\"\r\n"
+"// NUMBER is \"value\"\r\n"
+"// STRING is \"value\"\r\n"
+"// LIST is \"index\", where index \"0\" is the first element of the list\r\n\r\n\r\n" );
+
+ setDescription ( "SERVER_OPTIONS" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerDescription::WriteScriptHeader( FileHandle_t fp )
+{
+ char am_pm[] = "AM";
+ tm newtime;
+ VCRHook_LocalTime( &newtime );
+
+ if( newtime.tm_hour > 12 ) /* Set up extension. */
+ Q_strncpy( am_pm, "PM", sizeof( am_pm ) );
+ if( newtime.tm_hour > 12 ) /* Convert from 24-hour */
+ newtime.tm_hour -= 12; /* to 12-hour clock. */
+ if( newtime.tm_hour == 0 ) /*Set hour to 12 if midnight. */
+ newtime.tm_hour = 12;
+
+ g_pFullFileSystem->FPrintf( fp, (char *)getHint() );
+
+// Write out the comment and Cvar Info:
+ g_pFullFileSystem->FPrintf( fp, "// Half-Life Server Configuration Layout Script (stores last settings chosen, too)\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
+ g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
+
+ g_pFullFileSystem->FPrintf( fp, "VERSION %.1f\r\n\r\n", SCRIPT_VERSION );
+
+ g_pFullFileSystem->FPrintf( fp, "DESCRIPTION SERVER_OPTIONS\r\n{\r\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CServerDescription::WriteFileHeader( FileHandle_t fp )
+{
+ char am_pm[] = "AM";
+ tm newtime;
+ VCRHook_LocalTime( &newtime );
+
+ if( newtime.tm_hour > 12 ) /* Set up extension. */
+ Q_strncpy( am_pm, "PM", sizeof( am_pm ) );
+ if( newtime.tm_hour > 12 ) /* Convert from 24-hour */
+ newtime.tm_hour -= 12; /* to 12-hour clock. */
+ if( newtime.tm_hour == 0 ) /*Set hour to 12 if midnight. */
+ newtime.tm_hour = 12;
+
+ g_pFullFileSystem->FPrintf( fp, "// Half-Life Server Configuration Settings\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// DO NOT EDIT, GENERATED BY HALF-LIFE\r\n" );
+ g_pFullFileSystem->FPrintf( fp, "// File generated: %.19s %s\r\n", asctime( &newtime ), am_pm );
+ g_pFullFileSystem->FPrintf( fp, "//\r\n//\r\n// Cvar\t-\tSetting\r\n\r\n" );
+}
diff --git a/gameui/CreateMultiplayerGameGameplayPage.h b/gameui/CreateMultiplayerGameGameplayPage.h
new file mode 100644
index 0000000..e0cc788
--- /dev/null
+++ b/gameui/CreateMultiplayerGameGameplayPage.h
@@ -0,0 +1,48 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CREATEMULTIPLAYERGAMEGAMEPLAYPAGE_H
+#define CREATEMULTIPLAYERGAMEGAMEPLAYPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+class CPanelListPanel;
+class CDescription;
+class mpcontrol_t;
+
+//-----------------------------------------------------------------------------
+// Purpose: server options page of the create game server dialog
+//-----------------------------------------------------------------------------
+class CCreateMultiplayerGameGameplayPage : public vgui::PropertyPage
+{
+public:
+ CCreateMultiplayerGameGameplayPage(vgui::Panel *parent, const char *name);
+ ~CCreateMultiplayerGameGameplayPage();
+
+ // returns currently entered information about the server
+ int GetMaxPlayers();
+ const char *GetPassword();
+ const char *GetHostName();
+
+protected:
+ virtual void OnApplyChanges();
+
+private:
+ const char *GetValue(const char *cvarName, const char *defaultValue);
+ void LoadGameOptionsList();
+ void GatherCurrentValues();
+
+ CDescription *m_pDescription;
+ mpcontrol_t *m_pList;
+ CPanelListPanel *m_pOptionsList;
+};
+
+
+#endif // CREATEMULTIPLAYERGAMEGAMEPLAYPAGE_H
diff --git a/gameui/CreateMultiplayerGameServerPage.cpp b/gameui/CreateMultiplayerGameServerPage.cpp
new file mode 100644
index 0000000..58f2ad5
--- /dev/null
+++ b/gameui/CreateMultiplayerGameServerPage.cpp
@@ -0,0 +1,313 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "CreateMultiplayerGameServerPage.h"
+
+using namespace vgui;
+
+#include <KeyValues.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/RadioButton.h>
+#include <vgui_controls/CheckButton.h>
+#include "filesystem.h"
+#include "tier1/convar.h"
+#include "EngineInterface.h"
+#include "CvarToggleCheckButton.h"
+
+#include "ModInfo.h"
+
+// for SRC
+#include <vstdlib/random.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#define RANDOM_MAP "#GameUI_RandomMap"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameServerPage::CCreateMultiplayerGameServerPage(vgui::Panel *parent, const char *name) : PropertyPage(parent, name)
+{
+ m_pSavedData = NULL;
+
+ // we can use this if we decide we want to put "listen server" at the end of the game name
+ m_pMapList = new ComboBox(this, "MapList", 12, false);
+
+ m_pEnableBotsCheck = new CheckButton( this, "EnableBotsCheck", "" );
+ m_pEnableBotsCheck->SetVisible( false );
+ m_pEnableBotsCheck->SetEnabled( false );
+
+ LoadControlSettings("Resource/CreateMultiplayerGameServerPage.res");
+
+ LoadMapList();
+ m_szMapName[0] = 0;
+
+ // initialize hostname
+ SetControlString("ServerNameEdit", ModInfo().GetGameName());//szHostName);
+
+ // initialize password
+// SetControlString("PasswordEdit", engine->pfnGetCvarString("sv_password"));
+ ConVarRef var( "sv_password" );
+ if ( var.IsValid() )
+ {
+ SetControlString("PasswordEdit", var.GetString() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CCreateMultiplayerGameServerPage::~CCreateMultiplayerGameServerPage()
+{
+}
+
+void CCreateMultiplayerGameServerPage::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_LEFT || code == KEY_XSTICK1_LEFT || code == KEY_XSTICK2_LEFT )
+ {
+ int nItem = m_pMapList->GetActiveItem();
+ nItem -= 1;
+ if ( nItem < 0 )
+ {
+ nItem = m_pMapList->GetItemCount() - 1;
+ }
+
+ m_pMapList->SilentActivateItem( nItem );
+ }
+ else if ( code == KEY_XBUTTON_RIGHT || code == KEY_XSTICK1_RIGHT || code == KEY_XSTICK2_RIGHT )
+ {
+ int nItem = m_pMapList->GetActiveItem();
+ nItem += 1;
+ if ( nItem >= m_pMapList->GetItemCount() )
+ {
+ nItem = 0;
+ }
+
+ m_pMapList->SilentActivateItem( nItem );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::EnableBots( KeyValues *data )
+{
+ m_pSavedData = data;
+
+ int quota = data->GetInt( "bot_quota", 0 );
+ SetControlInt( "BotQuotaCombo", quota );
+ m_pEnableBotsCheck->SetSelected( (quota > 0) );
+
+ int difficulty = data->GetInt( "bot_difficulty", 0 );
+ difficulty = max( difficulty, 0 );
+ difficulty = min( 3, difficulty );
+
+ char buttonName[64];
+ Q_snprintf( buttonName, sizeof( buttonName ), "SkillLevel%d", difficulty );
+ vgui::RadioButton *button = dynamic_cast< vgui::RadioButton * >(FindChildByName( buttonName ));
+ if ( button )
+ {
+ button->SetSelected( true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called to get the info from the dialog
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::OnApplyChanges()
+{
+ KeyValues *kv = m_pMapList->GetActiveItemUserData();
+ strncpy(m_szMapName, kv->GetString("mapname", ""), DATA_STR_LENGTH);
+
+ if ( m_pSavedData )
+ {
+ int quota = GetControlInt( "BotQuotaCombo", 0 );
+ if ( !m_pEnableBotsCheck->IsSelected() )
+ {
+ quota = 0;
+ }
+ m_pSavedData->SetInt( "bot_quota", quota );
+ ConVarRef bot_quota( "bot_quota" );
+ bot_quota.SetValue( quota );
+
+ int difficulty = 0;
+ for ( int i=0; i<4; ++i )
+ {
+ char buttonName[64];
+ Q_snprintf( buttonName, sizeof( buttonName ), "SkillLevel%d", i );
+ vgui::RadioButton *button = dynamic_cast< vgui::RadioButton * >(FindChildByName( buttonName ));
+ if ( button )
+ {
+ if ( button->IsSelected() )
+ {
+ difficulty = i;
+ break;
+ }
+ }
+ }
+ m_pSavedData->SetInt( "bot_difficulty", difficulty );
+ ConVarRef bot_difficulty( "bot_difficulty" );
+ bot_difficulty.SetValue( difficulty );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads the list of available maps into the map list
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::LoadMaps( const char *pszPathID )
+{
+ FileFindHandle_t findHandle = NULL;
+
+ KeyValues *hiddenMaps = ModInfo().GetHiddenMaps();
+
+ const char *pszFilename = g_pFullFileSystem->FindFirstEx( "maps/*.bsp", pszPathID, &findHandle );
+ while ( pszFilename )
+ {
+ char mapname[256];
+ char *ext, *str;
+
+ // FindFirst ignores the pszPathID, so check it here
+ // TODO: this doesn't find maps in fallback dirs
+ _snprintf( mapname, sizeof(mapname), "maps/%s", pszFilename );
+ if ( !g_pFullFileSystem->FileExists( mapname, pszPathID ) )
+ {
+ goto nextFile;
+ }
+
+ // remove the text 'maps/' and '.bsp' from the file name to get the map name
+
+ str = Q_strstr( pszFilename, "maps" );
+ if ( str )
+ {
+ strncpy( mapname, str + 5, sizeof(mapname) - 1 ); // maps + \\ = 5
+ }
+ else
+ {
+ strncpy( mapname, pszFilename, sizeof(mapname) - 1 );
+ }
+ ext = Q_strstr( mapname, ".bsp" );
+ if ( ext )
+ {
+ *ext = 0;
+ }
+
+ //!! hack: strip out single player HL maps
+ // this needs to be specified in a seperate file
+ if ( !stricmp( ModInfo().GetGameName(), "Half-Life" ) && ( mapname[0] == 'c' || mapname[0] == 't') && mapname[2] == 'a' && mapname[1] >= '0' && mapname[1] <= '5' )
+ {
+ goto nextFile;
+ }
+
+ // strip out maps that shouldn't be displayed
+ if ( hiddenMaps )
+ {
+ if ( hiddenMaps->GetInt( mapname, 0 ) )
+ {
+ goto nextFile;
+ }
+ }
+
+ // add to the map list
+ m_pMapList->AddItem( mapname, new KeyValues( "data", "mapname", mapname ) );
+
+ // get the next file
+ nextFile:
+ pszFilename = g_pFullFileSystem->FindNext( findHandle );
+ }
+ g_pFullFileSystem->FindClose( findHandle );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: loads the list of available maps into the map list
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::LoadMapList()
+{
+ // clear the current list (if any)
+ m_pMapList->DeleteAllItems();
+
+ // add special "name" to represent loading a randomly selected map
+ m_pMapList->AddItem( RANDOM_MAP, new KeyValues( "data", "mapname", RANDOM_MAP ) );
+
+ // Load the GameDir maps
+ LoadMaps( "GAME" );
+
+ // set the first item to be selected
+ m_pMapList->ActivateItem( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CCreateMultiplayerGameServerPage::IsRandomMapSelected()
+{
+ const char *mapname = m_pMapList->GetActiveItemUserData()->GetString("mapname");
+ if (!stricmp( mapname, RANDOM_MAP ))
+ {
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *CCreateMultiplayerGameServerPage::GetMapName()
+{
+ int count = m_pMapList->GetItemCount();
+
+ // if there is only one entry it's the special "select random map" entry
+ if( count <= 1 )
+ return NULL;
+
+ const char *mapname = m_pMapList->GetActiveItemUserData()->GetString("mapname");
+ if (!strcmp( mapname, RANDOM_MAP ))
+ {
+ int which = RandomInt( 1, count - 1 );
+ mapname = m_pMapList->GetItemUserData( which )->GetString("mapname");
+ }
+
+ return mapname;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets currently selected map in the map combobox
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::SetMap(const char *mapName)
+{
+ for (int i = 0; i < m_pMapList->GetItemCount(); i++)
+ {
+ if (!m_pMapList->IsItemIDValid(i))
+ continue;
+
+ if (!stricmp(m_pMapList->GetItemUserData(i)->GetString("mapname"), mapName))
+ {
+ m_pMapList->ActivateItem(i);
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCreateMultiplayerGameServerPage::OnCheckButtonChecked()
+{
+ SetControlEnabled("SkillLevel0", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("SkillLevel1", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("SkillLevel2", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("SkillLevel3", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("BotQuotaCombo", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("BotQuotaLabel", m_pEnableBotsCheck->IsSelected());
+ SetControlEnabled("BotDifficultyLabel", m_pEnableBotsCheck->IsSelected());
+}
diff --git a/gameui/CreateMultiplayerGameServerPage.h b/gameui/CreateMultiplayerGameServerPage.h
new file mode 100644
index 0000000..227177b
--- /dev/null
+++ b/gameui/CreateMultiplayerGameServerPage.h
@@ -0,0 +1,60 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CREATEMULTIPLAYERGAMESERVERPAGE_H
+#define CREATEMULTIPLAYERGAMESERVERPAGE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+#include "CvarToggleCheckButton.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: server options page of the create game server dialog
+//-----------------------------------------------------------------------------
+class CCreateMultiplayerGameServerPage : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( CCreateMultiplayerGameServerPage, vgui::PropertyPage );
+
+public:
+ CCreateMultiplayerGameServerPage(vgui::Panel *parent, const char *name);
+ ~CCreateMultiplayerGameServerPage();
+
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+ // returns currently entered information about the server
+ void SetMap(const char *name);
+ bool IsRandomMapSelected();
+ const char *GetMapName();
+
+ vgui::ComboBox *GetMapList( void ) { return m_pMapList; }
+
+ // CS Bots
+ void EnableBots( KeyValues *data );
+ int GetBotQuota( void );
+ bool GetBotsEnabled( void );
+
+protected:
+ virtual void OnApplyChanges();
+ MESSAGE_FUNC( OnCheckButtonChecked, "CheckButtonChecked" );
+
+private:
+ void LoadMapList();
+ void LoadMaps( const char *pszPathID );
+
+ vgui::ComboBox *m_pMapList;
+ vgui::CheckButton *m_pEnableBotsCheck;
+ CCvarToggleCheckButton *m_pEnableTutorCheck;
+ KeyValues *m_pSavedData;
+
+ enum { DATA_STR_LENGTH = 64 };
+ char m_szMapName[DATA_STR_LENGTH];
+};
+
+
+#endif // CREATEMULTIPLAYERGAMESERVERPAGE_H
diff --git a/gameui/CustomTabExplanationDialog.cpp b/gameui/CustomTabExplanationDialog.cpp
new file mode 100644
index 0000000..f58c1cb
--- /dev/null
+++ b/gameui/CustomTabExplanationDialog.cpp
@@ -0,0 +1,93 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "CustomTabExplanationDialog.h"
+#include "BasePanel.h"
+#include "convar.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+#include "ModInfo.h"
+#include <stdio.h>
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCustomTabExplanationDialog::CCustomTabExplanationDialog(vgui::Panel *parent) : BaseClass(parent, "CustomTabExplanationDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetSizeable( false );
+
+ input()->SetAppModalSurface(GetVPanel());
+
+ LoadControlSettings("Resource/CustomTabExplanationDialog.res");
+
+ MoveToCenterOfScreen();
+
+ GameUI().PreventEngineHideGameUI();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CCustomTabExplanationDialog::~CCustomTabExplanationDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCustomTabExplanationDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetDialogVariable( "game", ModInfo().GetGameName() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCustomTabExplanationDialog::OnKeyCodePressed(KeyCode code)
+{
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles button commands
+//-----------------------------------------------------------------------------
+void CCustomTabExplanationDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "ok" ) || !stricmp( command, "cancel" ) || !stricmp( command, "close" ) )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCustomTabExplanationDialog::OnClose( void )
+{
+ BaseClass::OnClose();
+ GameUI().AllowEngineHideGameUI();
+}
diff --git a/gameui/CustomTabExplanationDialog.h b/gameui/CustomTabExplanationDialog.h
new file mode 100644
index 0000000..754391b
--- /dev/null
+++ b/gameui/CustomTabExplanationDialog.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef CUSTOMTABEXPLANATIONDIALOG_H
+#define CUSTOMTABEXPLANATIONDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "utlvector.h"
+#include <vgui/KeyCode.h>
+#include "vgui_controls/URLLabel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog that explains the custom tab
+//-----------------------------------------------------------------------------
+class CCustomTabExplanationDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CCustomTabExplanationDialog, vgui::Frame );
+
+public:
+ CCustomTabExplanationDialog(vgui::Panel *parent);
+ ~CCustomTabExplanationDialog();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+ virtual void OnCommand( const char *command );
+ virtual void OnClose( void );
+};
+
+#endif // CUSTOMTABEXPLANATIONDIALOG_H
diff --git a/gameui/CvarNegateCheckButton.cpp b/gameui/CvarNegateCheckButton.cpp
new file mode 100644
index 0000000..8f9e3cb
--- /dev/null
+++ b/gameui/CvarNegateCheckButton.cpp
@@ -0,0 +1,136 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "CvarNegateCheckButton.h"
+#include "EngineInterface.h"
+#include <vgui/IVGui.h>
+#include "IGameUIFuncs.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+CCvarNegateCheckButton::CCvarNegateCheckButton( Panel *parent, const char *panelName, const char *text,
+ const char *cvarname )
+ : CheckButton( parent, panelName, text )
+{
+ m_pszCvarName = cvarname ? strdup( cvarname ) : NULL;
+ Reset();
+ AddActionSignalTarget( this );
+}
+
+CCvarNegateCheckButton::~CCvarNegateCheckButton()
+{
+ free( m_pszCvarName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCvarNegateCheckButton::Paint()
+{
+ if ( !m_pszCvarName )
+ {
+ BaseClass::Paint();
+ return;
+ }
+
+ // Look up current value
+// float value = engine->pfnGetCvarFloat( m_pszCvarName );
+ ConVarRef var( m_pszCvarName );
+ if ( !var.IsValid() )
+ return;
+
+ float value = var.GetFloat();
+
+ if ( value < 0 )
+ {
+ if ( !m_bStartState )
+ {
+ SetSelected( true );
+ m_bStartState = true;
+ }
+ }
+ else
+ {
+ if ( m_bStartState )
+ {
+ SetSelected( false );
+ m_bStartState = false;
+ }
+ }
+ BaseClass::Paint();
+}
+
+void CCvarNegateCheckButton::Reset()
+{
+ // Look up current value
+// float value = engine->pfnGetCvarFloat( m_pszCvarName );
+ ConVarRef var( m_pszCvarName );
+ if ( !var.IsValid() )
+ return;
+
+ float value = var.GetFloat();
+
+ if ( value < 0 )
+ {
+ m_bStartState = true;
+ }
+ else
+ {
+ m_bStartState = false;
+ }
+ SetSelected(m_bStartState);
+}
+
+bool CCvarNegateCheckButton::HasBeenModified()
+{
+ return IsSelected() != m_bStartState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CCvarNegateCheckButton::SetSelected( bool state )
+{
+ BaseClass::SetSelected( state );
+}
+
+void CCvarNegateCheckButton::ApplyChanges()
+{
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ return;
+
+ ConVarRef var( m_pszCvarName );
+ float value = var.GetFloat();
+
+ value = (float)fabs( value );
+ if (value < 0.00001)
+ {
+ // correct the value if it's not set
+ value = 0.022f;
+ }
+
+ m_bStartState = IsSelected();
+ value = -value;
+
+ float ans = m_bStartState ? value : -value;
+ var.SetValue( ans );
+}
+
+
+void CCvarNegateCheckButton::OnButtonChecked()
+{
+ if (HasBeenModified())
+ {
+ PostActionSignal(new KeyValues("ControlModified"));
+ }
+}
diff --git a/gameui/CvarNegateCheckButton.h b/gameui/CvarNegateCheckButton.h
new file mode 100644
index 0000000..9eb1d94
--- /dev/null
+++ b/gameui/CvarNegateCheckButton.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CVARNEGATECHECKBUTTON_H
+#define CVARNEGATECHECKBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/CheckButton.h>
+
+class CCvarNegateCheckButton : public vgui::CheckButton
+{
+ DECLARE_CLASS_SIMPLE( CCvarNegateCheckButton, vgui::CheckButton );
+
+public:
+ CCvarNegateCheckButton( vgui::Panel *parent, const char *panelName, const char *text,
+ char const *cvarname );
+ ~CCvarNegateCheckButton();
+
+ virtual void SetSelected( bool state );
+ virtual void Paint();
+
+ void Reset();
+ void ApplyChanges();
+ bool HasBeenModified();
+
+private:
+ MESSAGE_FUNC( OnButtonChecked, "CheckButtonChecked" );
+
+ char *m_pszCvarName;
+ bool m_bStartState;
+};
+
+#endif // CVARNEGATECHECKBUTTON_H
diff --git a/gameui/CvarTextEntry.cpp b/gameui/CvarTextEntry.cpp
new file mode 100644
index 0000000..8f8e926
--- /dev/null
+++ b/gameui/CvarTextEntry.cpp
@@ -0,0 +1,112 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "CvarTextEntry.h"
+#include "EngineInterface.h"
+#include <vgui/IVGui.h>
+#include "IGameUIFuncs.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+static const int MAX_CVAR_TEXT = 64;
+
+CCvarTextEntry::CCvarTextEntry( Panel *parent, const char *panelName, char const *cvarname )
+ : TextEntry( parent, panelName)
+{
+ m_pszCvarName = cvarname ? strdup( cvarname ) : NULL;
+ m_pszStartValue[0] = 0;
+
+ if ( m_pszCvarName )
+ {
+ Reset();
+ }
+
+ AddActionSignalTarget( this );
+}
+
+CCvarTextEntry::~CCvarTextEntry()
+{
+ if ( m_pszCvarName )
+ {
+ free( m_pszCvarName );
+ }
+}
+
+void CCvarTextEntry::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+ if (GetMaximumCharCount() < 0 || GetMaximumCharCount() > MAX_CVAR_TEXT)
+ {
+ SetMaximumCharCount(MAX_CVAR_TEXT - 1);
+ }
+}
+
+void CCvarTextEntry::ApplyChanges( bool immediate )
+{
+ if ( !m_pszCvarName )
+ return;
+
+ char szText[ MAX_CVAR_TEXT ];
+ GetText( szText, MAX_CVAR_TEXT );
+
+ if ( !szText[ 0 ] )
+ return;
+
+ if ( immediate )
+ {
+ // set immediately - don't wait for the next frame
+ ConVarRef newCvar( m_pszCvarName );
+ newCvar.SetValue( szText );
+ }
+ else
+ {
+ char szCommand[ 256 ];
+ sprintf( szCommand, "%s \"%s\"\n", m_pszCvarName, szText );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+
+ Q_strncpy( m_pszStartValue, szText, sizeof( m_pszStartValue ) );
+}
+
+void CCvarTextEntry::Reset()
+{
+// char *value = engine->pfnGetCvarString( m_pszCvarName );
+ ConVarRef var( m_pszCvarName );
+ if ( !var.IsValid() )
+ return;
+ const char *value = var.GetString();
+ if ( value && value[ 0 ] )
+ {
+ SetText( value );
+ Q_strncpy( m_pszStartValue, value, sizeof( m_pszStartValue ) );
+ }
+}
+
+bool CCvarTextEntry::HasBeenModified()
+{
+ char szText[ MAX_CVAR_TEXT ];
+ GetText( szText, MAX_CVAR_TEXT );
+
+ return stricmp( szText, m_pszStartValue );
+}
+
+
+void CCvarTextEntry::OnTextChanged()
+{
+ if ( !m_pszCvarName )
+ return;
+
+ if (HasBeenModified())
+ {
+ PostActionSignal(new KeyValues("ControlModified"));
+ }
+}
diff --git a/gameui/CvarTextEntry.h b/gameui/CvarTextEntry.h
new file mode 100644
index 0000000..8e3ad14
--- /dev/null
+++ b/gameui/CvarTextEntry.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CVARTEXTENTRY_H
+#define CVARTEXTENTRY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/TextEntry.h>
+
+class CCvarTextEntry : public vgui::TextEntry
+{
+ DECLARE_CLASS_SIMPLE( CCvarTextEntry, vgui::TextEntry );
+
+public:
+ CCvarTextEntry( vgui::Panel *parent, const char *panelName, char const *cvarname );
+ ~CCvarTextEntry();
+
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" );
+ void ApplyChanges( bool immediate = false );
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+ void Reset();
+ bool HasBeenModified();
+
+private:
+ char *m_pszCvarName;
+ char m_pszStartValue[64];
+};
+
+#endif // CVARTEXTENTRY_H
diff --git a/gameui/CvarToggleCheckButton.cpp b/gameui/CvarToggleCheckButton.cpp
new file mode 100644
index 0000000..f8d3141
--- /dev/null
+++ b/gameui/CvarToggleCheckButton.cpp
@@ -0,0 +1,159 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "CvarToggleCheckButton.h"
+#include "EngineInterface.h"
+#include <vgui/IVGui.h>
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include "IGameUIFuncs.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+vgui::Panel *CvarToggleCheckButton_Factory()
+{
+ return new CCvarToggleCheckButton( NULL, NULL, "CvarToggleCheckButton", NULL );
+}
+DECLARE_BUILD_FACTORY_CUSTOM( CCvarToggleCheckButton, CvarToggleCheckButton_Factory );
+
+CCvarToggleCheckButton::CCvarToggleCheckButton( Panel *parent, const char *panelName, const char *text,
+ char const *cvarname )
+ : CheckButton( parent, panelName, text )
+{
+ m_pszCvarName = cvarname ? strdup( cvarname ) : NULL;
+
+ if (m_pszCvarName)
+ {
+ Reset();
+ }
+ AddActionSignalTarget( this );
+}
+
+CCvarToggleCheckButton::~CCvarToggleCheckButton()
+{
+ if ( m_pszCvarName )
+ {
+ free( m_pszCvarName );
+ }
+}
+
+void CCvarToggleCheckButton::Paint()
+{
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ {
+ BaseClass::Paint();
+ return;
+ }
+
+ // Look up current value
+// bool value = engine->pfnGetCvarFloat( m_pszCvarName ) > 0.0f ? true : false;
+ ConVarRef var( m_pszCvarName, true );
+ if ( !var.IsValid() )
+ return;
+ bool value = var.GetBool();
+
+ if ( value != m_bStartValue )
+ //if ( value != IsSelected() )
+ {
+ SetSelected( value );
+ m_bStartValue = value;
+ }
+ BaseClass::Paint();
+}
+
+void CCvarToggleCheckButton::ApplyChanges()
+{
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ return;
+
+ m_bStartValue = IsSelected();
+// engine->Cvar_SetValue( m_pszCvarName, m_bStartValue ? 1.0f : 0.0f );
+ ConVarRef var( m_pszCvarName, true );
+ if ( !var.IsValid() )
+ return;
+ var.SetValue( m_bStartValue );
+}
+
+void CCvarToggleCheckButton::Reset()
+{
+// m_bStartValue = engine->pfnGetCvarFloat( m_pszCvarName ) > 0.0f ? true : false;
+
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ return;
+
+ ConVarRef var( m_pszCvarName, true );
+ if ( !var.IsValid() )
+ return;
+ m_bStartValue = var.GetBool();
+ SetSelected(m_bStartValue);
+}
+
+bool CCvarToggleCheckButton::HasBeenModified()
+{
+ return IsSelected() != m_bStartValue;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+void CCvarToggleCheckButton::SetSelected( bool state )
+{
+ BaseClass::SetSelected( state );
+
+ if ( !m_pszCvarName || !m_pszCvarName[ 0 ] )
+ return;
+/*
+ // Look up current value
+ bool value = state;
+
+ engine->Cvar_SetValue( m_pszCvarName, value ? 1.0f : 0.0f );*/
+}
+
+
+//-----------------------------------------------------------------------------
+void CCvarToggleCheckButton::OnButtonChecked()
+{
+ if (HasBeenModified())
+ {
+ PostActionSignal(new KeyValues("ControlModified"));
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCvarToggleCheckButton::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ const char *cvarName = inResourceData->GetString("cvar_name", "");
+ const char *cvarValue = inResourceData->GetString("cvar_value", "");
+
+ if( Q_stricmp( cvarName, "") == 0 )
+ return;// Doesn't have cvar set up in res file, must have been constructed with it.
+
+ if( m_pszCvarName )
+ free( m_pszCvarName );// got a "", not a NULL from the create-control call
+
+ m_pszCvarName = cvarName ? strdup( cvarName ) : NULL;
+
+ if( Q_stricmp( cvarValue, "1") == 0 )
+ m_bStartValue = true;
+ else
+ m_bStartValue = false;
+
+ const ConVar *var = cvar->FindVar( m_pszCvarName );
+ if ( var )
+ {
+ if( var->GetBool() )
+ SetSelected( true );
+ else
+ SetSelected( false );
+ }
+} \ No newline at end of file
diff --git a/gameui/CvarToggleCheckButton.h b/gameui/CvarToggleCheckButton.h
new file mode 100644
index 0000000..2294745
--- /dev/null
+++ b/gameui/CvarToggleCheckButton.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef CVARTOGGLECHECKBUTTON_H
+#define CVARTOGGLECHECKBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/CheckButton.h>
+
+class CCvarToggleCheckButton : public vgui::CheckButton
+{
+ DECLARE_CLASS_SIMPLE( CCvarToggleCheckButton, vgui::CheckButton );
+
+public:
+ CCvarToggleCheckButton( vgui::Panel *parent, const char *panelName, const char *text,
+ char const *cvarname );
+ ~CCvarToggleCheckButton();
+
+ virtual void SetSelected( bool state );
+
+ virtual void Paint();
+
+ void Reset();
+ void ApplyChanges();
+ bool HasBeenModified();
+ virtual void ApplySettings( KeyValues *inResourceData );
+
+private:
+ MESSAGE_FUNC( OnButtonChecked, "CheckButtonChecked" );
+
+ char *m_pszCvarName;
+ bool m_bStartValue;
+};
+
+#endif // CVARTOGGLECHECKBUTTON_H
diff --git a/gameui/EngineInterface.h b/gameui/EngineInterface.h
new file mode 100644
index 0000000..c2ad78b
--- /dev/null
+++ b/gameui/EngineInterface.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Includes all the headers/declarations necessary to access the
+// engine interface
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ENGINEINTERFACE_H
+#define ENGINEINTERFACE_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+// these stupid set of includes are required to use the cdll_int interface
+#include "mathlib/vector.h"
+//#include "wrect.h"
+#define IN_BUTTONS_H
+
+// engine interface
+#include "cdll_int.h"
+#include "icvar.h"
+
+// engine interface singleton accessors
+extern IVEngineClient *engine;
+extern class IGameUIFuncs *gameuifuncs;
+extern class IEngineSound *enginesound;
+extern class IMatchmaking *matchmaking;
+extern class IXboxSystem *xboxsystem;
+extern class IAchievementMgr *achievementmgr;
+extern class CSteamAPIContext *steamapicontext;
+
+#endif // ENGINEINTERFACE_H
diff --git a/gameui/GameApp.cpp b/gameui/GameApp.cpp
new file mode 100644
index 0000000..db4f992
--- /dev/null
+++ b/gameui/GameApp.cpp
@@ -0,0 +1 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
diff --git a/gameui/GameApp.h b/gameui/GameApp.h
new file mode 100644
index 0000000..db4f992
--- /dev/null
+++ b/gameui/GameApp.h
@@ -0,0 +1 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
diff --git a/gameui/GameConsole.cpp b/gameui/GameConsole.cpp
new file mode 100644
index 0000000..5f1cb0c
--- /dev/null
+++ b/gameui/GameConsole.cpp
@@ -0,0 +1,169 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include <stdio.h>
+
+#include "GameConsole.h"
+#include "GameConsoleDialog.h"
+#include "LoadingDialog.h"
+#include "vgui/ISurface.h"
+
+#include "KeyValues.h"
+#include "vgui/VGUI.h"
+#include "vgui/IVGui.h"
+#include "vgui_controls/Panel.h"
+#include "convar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+static CGameConsole g_GameConsole;
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CGameConsole &GameConsole()
+{
+ return g_GameConsole;
+}
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameConsole, IGameConsole, GAMECONSOLE_INTERFACE_VERSION, g_GameConsole);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CGameConsole::CGameConsole()
+{
+ m_bInitialized = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CGameConsole::~CGameConsole()
+{
+ m_bInitialized = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up the console for use
+//-----------------------------------------------------------------------------
+void CGameConsole::Initialize()
+{
+#ifndef _XBOX
+ m_pConsole = vgui::SETUP_PANEL( new CGameConsoleDialog() ); // we add text before displaying this so set it up now!
+
+ // set the console to taking up most of the right-half of the screen
+ int swide, stall;
+ vgui::surface()->GetScreenSize(swide, stall);
+ int offsetx = vgui::scheme()->GetProportionalScaledValue(16);
+ int offsety = vgui::scheme()->GetProportionalScaledValue(64);
+
+ m_pConsole->SetBounds(
+ swide / 2 - offsetx,
+ offsety,
+ swide / 2,
+ stall - (offsety * 2));
+
+ m_bInitialized = true;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: activates the console, makes it visible and brings it to the foreground
+//-----------------------------------------------------------------------------
+void CGameConsole::Activate()
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return;
+
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ m_pConsole->Activate();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: hides the console
+//-----------------------------------------------------------------------------
+void CGameConsole::Hide()
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return;
+
+ m_pConsole->Hide();
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: clears the console
+//-----------------------------------------------------------------------------
+void CGameConsole::Clear()
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return;
+
+ m_pConsole->Clear();
+#endif
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the console is currently in focus
+//-----------------------------------------------------------------------------
+bool CGameConsole::IsConsoleVisible()
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return false;
+
+ return m_pConsole->IsVisible();
+#else
+ return false;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: activates the console after a delay
+//-----------------------------------------------------------------------------
+void CGameConsole::ActivateDelayed(float time)
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return;
+
+ m_pConsole->PostMessage(m_pConsole, new KeyValues("Activate"), time);
+#endif
+}
+
+void CGameConsole::SetParent( int parent )
+{
+#ifndef _XBOX
+ if (!m_bInitialized)
+ return;
+
+ m_pConsole->SetParent( static_cast<vgui::VPANEL>( parent ));
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: static command handler
+//-----------------------------------------------------------------------------
+void CGameConsole::OnCmdCondump()
+{
+#ifndef _XBOX
+ g_GameConsole.m_pConsole->DumpConsoleTextToFile();
+#endif
+}
+
+#ifndef _XBOX
+CON_COMMAND( condump, "dump the text currently in the console to condumpXX.log" )
+{
+ g_GameConsole.OnCmdCondump();
+}
+#endif
diff --git a/gameui/GameConsole.h b/gameui/GameConsole.h
new file mode 100644
index 0000000..f3ed1ce
--- /dev/null
+++ b/gameui/GameConsole.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GAMECONSOLE_H
+#define GAMECONSOLE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "GameUI/IGameConsole.h"
+
+class CGameConsoleDialog;
+
+//-----------------------------------------------------------------------------
+// Purpose: VGui implementation of the game/dev console
+//-----------------------------------------------------------------------------
+class CGameConsole : public IGameConsole
+{
+public:
+ CGameConsole();
+ ~CGameConsole();
+
+ // sets up the console for use
+ void Initialize();
+
+ // activates the console, makes it visible and brings it to the foreground
+ virtual void Activate();
+ // hides the console
+ virtual void Hide();
+ // clears the console
+ virtual void Clear();
+
+ // returns true if the console is currently in focus
+ virtual bool IsConsoleVisible();
+
+ // activates the console after a delay
+ void ActivateDelayed(float time);
+
+ void SetParent( int parent );
+
+ static void OnCmdCondump();
+private:
+
+ bool m_bInitialized;
+ CGameConsoleDialog *m_pConsole;
+};
+
+extern CGameConsole &GameConsole();
+
+#endif // GAMECONSOLE_H
diff --git a/gameui/GameConsoleDialog.cpp b/gameui/GameConsoleDialog.cpp
new file mode 100644
index 0000000..430102c
--- /dev/null
+++ b/gameui/GameConsoleDialog.cpp
@@ -0,0 +1,99 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "GameConsoleDialog.h"
+#include "GameUI_Interface.h"
+#include "vgui/IInput.h"
+#include "vgui/ISurface.h"
+#include "vgui/KeyCode.h"
+#include "LoadingDialog.h"
+#include "IGameUIFuncs.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CGameConsoleDialog::CGameConsoleDialog() : BaseClass( NULL, "GameConsole", false )
+{
+ AddActionSignalTarget( this );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: generic vgui command handler
+//-----------------------------------------------------------------------------
+void CGameConsoleDialog::OnCommand(const char *command)
+{
+ if ( !Q_stricmp( command, "Close" ) )
+ {
+ if ( GameUI().IsInBackgroundLevel() )
+ {
+ // Tell the engine we've hid the console, so that it unpauses the game
+ // even though we're still sitting at the menu.
+ engine->ClientCmd_Unrestricted( "unpause" );
+ }
+ }
+
+ BaseClass::OnCommand(command);
+}
+
+
+//-----------------------------------------------------------------------------
+// HACK: Allow F key bindings to operate even when typing in the text entry field
+//-----------------------------------------------------------------------------
+void CGameConsoleDialog::OnKeyCodeTyped(KeyCode code)
+{
+ BaseClass::OnKeyCodeTyped(code);
+
+ // check for processing
+ if ( m_pConsolePanel->TextEntryHasFocus() )
+ {
+ // HACK: Allow F key bindings to operate even here
+ if ( code >= KEY_F1 && code <= KEY_F12 )
+ {
+ // See if there is a binding for the FKey
+ const char *binding = gameuifuncs->GetBindingForButtonCode( code );
+ if ( binding && binding[0] )
+ {
+ // submit the entry as a console commmand
+ char szCommand[256];
+ Q_strncpy( szCommand, binding, sizeof( szCommand ) );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Submits a command
+//-----------------------------------------------------------------------------
+void CGameConsoleDialog::OnCommandSubmitted( const char *pCommand )
+{
+ engine->ClientCmd_Unrestricted( pCommand );
+}
+
+
+//-----------------------------------------------------------------------------
+// Submits a command
+//-----------------------------------------------------------------------------
+void CGameConsoleDialog::OnClosedByHittingTilde()
+{
+ if ( !LoadingDialog() )
+ {
+ GameUI().HideGameUI();
+ }
+ else
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( LoadingDialog()->GetVPanel() );
+ }
+}
diff --git a/gameui/GameConsoleDialog.h b/gameui/GameConsoleDialog.h
new file mode 100644
index 0000000..5d57ef1
--- /dev/null
+++ b/gameui/GameConsoleDialog.h
@@ -0,0 +1,40 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef GAMECONSOLEDIALOG_H
+#define GAMECONSOLEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/consoledialog.h"
+#include <Color.h>
+#include "utlvector.h"
+#include "EngineInterface.h"
+#include "vgui_controls/Frame.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Game/dev console dialog
+//-----------------------------------------------------------------------------
+class CGameConsoleDialog : public vgui::CConsoleDialog
+{
+ DECLARE_CLASS_SIMPLE( CGameConsoleDialog, vgui::CConsoleDialog );
+
+public:
+ CGameConsoleDialog();
+
+private:
+ MESSAGE_FUNC( OnClosedByHittingTilde, "ClosedByHittingTilde" );
+ MESSAGE_FUNC_CHARPTR( OnCommandSubmitted, "CommandSubmitted", command );
+
+ virtual void OnKeyCodeTyped( vgui::KeyCode code );
+ virtual void OnCommand( const char *command );
+};
+
+
+#endif // GAMECONSOLEDIALOG_H
diff --git a/gameui/GameUI.h b/gameui/GameUI.h
new file mode 100644
index 0000000..8d17348
--- /dev/null
+++ b/gameui/GameUI.h
@@ -0,0 +1,25 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GAMEUI_H
+#define GAMEUI_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class IGameUI;
+
+//-----------------------------------------------------------------------------
+// Purpose: Accessor function to get game ui interface
+//-----------------------------------------------------------------------------
+inline IGameUI *gameui()
+{
+ extern IGameUI *g_pGameUI;
+ return g_pGameUI;
+}
+
+#endif // GAMEUI_H
diff --git a/gameui/GameUI.vpc b/gameui/GameUI.vpc
new file mode 100644
index 0000000..bf782c2
--- /dev/null
+++ b/gameui/GameUI.vpc
@@ -0,0 +1,258 @@
+//-----------------------------------------------------------------------------
+// GAMEUI.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$macro SRCDIR ".."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$include "$SRCDIR\vpc_scripts\source_dll_base.vpc"
+$Include "$SRCDIR\vpc_scripts\source_saxxyawards.vpc"
+$include "$SRCDIR\vpc_scripts\source_cryptlib_include.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE;.\;$SRCDIR\vgui2\include;$SRCDIR\vgui2\controls;$SRCDIR\common\GameUI"
+ $PreprocessorDefinitions "$BASE;GAMEUI_EXPORTS;VERSION_SAFE_STEAM_API_INTERFACES"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Ws2_32.lib odbc32.lib odbccp32.lib Shlwapi.lib" [$WIN32]
+ $SystemLibraries "iconv;z" [$OSXALL]
+ $SystemLibraries "rt" [$LINUXALL && !$DEDICATED]
+ $GCC_ExtraLinkerFlags "-L/usr/lib32 -L/usr/lib" [$LINUXALL && !$DEDICATED]
+ }
+}
+
+$Configuration "Debug"
+{
+ $Linker [$X360]
+ {
+ $AdditionalDependencies "$BASE Xonlined.lib"
+ }
+}
+
+$Configuration "Release"
+{
+ $Linker [$X360]
+ {
+ $AdditionalDependencies "$BASE Xonline.lib"
+ }
+}
+
+$Project "GameUI"
+{
+ $Folder "Source Files"
+ {
+ $File "BackgroundMenuButton.cpp"
+ $File "BasePanel.cpp"
+ $File "GameConsole.cpp"
+ $File "GameUI_Interface.cpp"
+ $File "LogoFile.cpp" [!$POSIX]
+ $File "ModInfo.cpp"
+ $File "MouseMessageForwardingPanel.cpp"
+ $File "$SRCDIR\Tracker\common\msgbuffer.cpp" [!$POSIX]
+ $File "$SRCDIR\Tracker\common\netapi.cpp" [!$POSIX]
+ $File "$SRCDIR\common\GameUI\ObjectList.cpp"
+ $File "PanelListPanel.cpp"
+ $File "RunGameEngine.cpp"
+ $File "$SRCDIR\common\GameUI\scriptobject.cpp"
+ $File "$SRCDIR\Tracker\common\Socket.cpp" [!$POSIX]
+ $File "Sys_Utils.cpp"
+ $File "TextEntryBox.cpp"
+ $File "TGAImagePanel.cpp"
+ $File "$SRCDIR\public\vgui_controls\vgui_controls.cpp"
+ $File "VGuiSystemModuleLoader.cpp"
+ $File "BonusMapsDatabase.cpp"
+ $File "BonusMapsDatabase.h"
+ $File "$SRCDIR\common\language.cpp"
+ $File "$SRCDIR\common\imageutils.cpp"
+ $File "SaveGameBrowserDialog.cpp"
+ $File "gameui_util.cpp"
+ $File "gameui_util.h"
+ }
+
+ $Folder "Header Files"
+ {
+ $File "BackgroundMenuButton.h"
+ $File "BasePanel.h"
+ $File "BaseSaveGameDialog.h"
+ $File "CDKeyEntryDialog.h"
+ $File "ChangeGameDialog.h"
+ $File "CreateMultiplayerGameBotPage.h"
+ $File "CreateMultiplayerGameDialog.h"
+ $File "CreateMultiplayerGameGameplayPage.h"
+ $File "CreateMultiplayerGameServerPage.h"
+ $File "EngineInterface.h"
+ $File "GameConsole.h"
+ $File "GameUI_Interface.h"
+ $File "LoadingDialog.h"
+ $File "$SRCDIR\vgui2\src\Memorybitmap.h"
+ $File "ModInfo.h"
+ $File "MouseMessageForwardingPanel.h"
+ $File "PanelListPanel.h"
+ $File "$SRCDIR\common\GameUI\scriptobject.h"
+ $File "Sys_Utils.h"
+ $File "TextEntryBox.h"
+ $File "TGAImagePanel.h"
+ $File "VGuiSystemModuleLoader.h"
+ $File "SaveGameBrowserDialog.h"
+ }
+
+ $Folder "Public Header Files"
+ {
+ $File "$SRCDIR\public\iachievementmgr.h"
+ $File "$SRCDIR\public\game\client\IGameClientExports.h"
+ $File "$SRCDIR\common\GameUI\IGameUI.h"
+ $File "$SRCDIR\public\IGameUIFuncs.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "$SRCDIR\common\IObjectContainer.h"
+ $File "$SRCDIR\common\IRunGameEngine.h"
+ $File "$SRCDIR\common\IVguiModule.h"
+ $File "$SRCDIR\common\IVGuiModuleLoader.h"
+ $File "$SRCDIR\common\GameUI\ObjectList.h"
+ $File "$SRCDIR\public\savegame_version.h"
+ $File "$SRCDIR\Tracker\common\TrackerMessageFlags.h"
+ $File "$SRCDIR\common\ValveCDKeyGameAndTerritoryCodes.h"
+ $File "$SRCDIR\common\language.h"
+ $File "$SRCDIR\common\imageutils.h"
+ }
+
+ $Folder "Controls"
+ {
+ $File "BitmapImagePanel.cpp"
+ $File "BitmapImagePanel.h"
+ $File "CommandCheckButton.cpp"
+ $File "CommandCheckButton.h"
+ $File "CvarNegateCheckButton.cpp"
+ $File "CvarNegateCheckButton.h"
+ $File "$SRCDIR\common\GameUI\cvarslider.cpp"
+ $File "$SRCDIR\common\GameUI\cvarslider.h"
+ $File "CvarTextEntry.cpp"
+ $File "CvarTextEntry.h"
+ $File "CvarToggleCheckButton.cpp"
+ $File "CvarToggleCheckButton.h"
+ $File "HapticControlBox.cpp"
+ $File "HapticControlBox.h"
+ $File "KeyToggleCheckButton.cpp"
+ $File "KeyToggleCheckButton.h"
+ $File "LabeledCommandComboBox.cpp"
+ $File "LabeledCommandComboBox.h"
+ $File "URLButton.cpp"
+ $File "URLButton.h"
+ $File "vcontrolslistpanel.cpp"
+ $File "vcontrolslistpanel.h"
+ }
+
+ $Folder "Dialogs"
+ {
+ $File "BenchmarkDialog.cpp"
+ $File "BenchmarkDialog.h"
+ $File "BonusMapsDialog.cpp"
+ $File "BonusMapsDialog.h"
+ $File "CommentaryDialog.cpp"
+ $File "CommentaryDialog.h"
+ $File "CommentaryExplanationDialog.cpp"
+ $File "CommentaryExplanationDialog.h"
+ $File "ContentControlDialog.cpp"
+ $File "ContentControlDialog.h"
+ $File "CustomTabExplanationDialog.cpp"
+ $File "CustomTabExplanationDialog.h"
+ $File "GameConsoleDialog.cpp"
+ $File "GameConsoleDialog.h"
+ $File "LoadGameDialog_Xbox.cpp"
+ $File "LoadGameDialog.cpp"
+ $File "LoadGameDialog.h"
+ $File "MultiplayerAdvancedDialog.cpp"
+ $File "MultiplayerAdvancedDialog.h"
+ $File "NewGameDialog.cpp"
+ $File "NewGameDialog.h"
+ $File "PlayerListDialog.cpp"
+ $File "PlayerListDialog.h"
+ $File "SaveGameDialog_Xbox.cpp"
+ $File "SaveGameDialog.cpp"
+ $File "SaveGameDialog.h"
+ $File "LoadCommentaryDialog.cpp"
+ $File "LoadingDialog.cpp"
+ $File "BaseSaveGameDialog.cpp"
+ $File "ChangeGameDialog.cpp" [!$POSIX]
+ $File "CreateMultiplayerGameBotPage.cpp"
+ $File "CreateMultiplayerGameDialog.cpp"
+ $File "CreateMultiplayerGameGameplayPage.cpp"
+ $File "CreateMultiplayerGameServerPage.cpp"
+ $File "OptionsDialog_Xbox.cpp"
+ $File "ControllerDialog.cpp"
+ $File "ControllerDialog.h"
+ }
+
+ $Folder "Matchmaking"
+ {
+ $File "matchmaking\achievementsdialog.cpp"
+ $File "matchmaking\achievementsdialog.h"
+ $File "matchmaking\basedialog.cpp"
+ $File "matchmaking\basedialog.h"
+ $File "matchmaking\dialogmenu.cpp"
+ $File "matchmaking\dialogmenu.h"
+ $File "matchmaking\leaderboarddialog.cpp"
+ $File "matchmaking\leaderboarddialog.h"
+ $File "matchmaking\matchmakingbasepanel.cpp"
+ $File "matchmaking\matchmakingbasepanel.h"
+ $File "matchmaking\pausedialog.cpp"
+ $File "matchmaking\pausedialog.h"
+ $File "matchmaking\sessionlobbydialog.cpp"
+ $File "matchmaking\sessionlobbydialog.h"
+ $File "matchmaking\sessionoptionsdialog.cpp"
+ $File "matchmaking\sessionoptionsdialog.h"
+ $File "matchmaking\sessionbrowserdialog.cpp"
+ $File "matchmaking\sessionbrowserdialog.h"
+ $File "matchmaking\welcomedialog.cpp"
+ $File "matchmaking\welcomedialog.h"
+ }
+
+ $Folder "Options Dialog"
+ {
+ $File "OptionsDialog.cpp"
+ $File "OptionsDialog.h"
+ $File "OptionsSubAudio.cpp"
+ $File "OptionsSubAudio.h"
+ $File "OptionsSubDifficulty.cpp"
+ $File "OptionsSubDifficulty.h"
+ $File "OptionsSubGame.cpp"
+ $File "OptionsSubGame.h"
+ $File "OptionsSubHaptics.cpp" [$WIN32]
+ $File "OptionsSubHaptics.h" [$WIN32]
+ $File "OptionsSubKeyboard.cpp"
+ $File "OptionsSubKeyboard.h"
+ $File "OptionsSubMouse.cpp"
+ $File "OptionsSubMouse.h"
+ $File "OptionsSubMultiplayer.cpp"
+ $File "OptionsSubMultiplayer.h"
+ $File "OptionsSubPortal.cpp"
+ $File "OptionsSubPortal.h"
+ $File "OptionsSubVideo.cpp"
+ $File "OptionsSubVideo.h"
+ $File "OptionsSubVoice.cpp"
+ $File "OptionsSubVoice.h"
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib bitmap
+ $Lib mathlib
+ $Lib matsys_controls
+ $Lib tier2
+ $Lib tier3
+ $Lib vgui_controls
+ $Lib vtf
+ $Lib "$LIBCOMMON/libjpeg" [!$DEDICATED]
+ $ImpLib steam_api
+ $Lib libpng [!$VS2015&&!$DEDICATED]
+ $Lib $LIBCOMMON/libpng [$VS2015&&!$DEDICATED]
+ $Lib libz [!$DEDICATED]
+ $ImpLib SDL2 [$SDL]
+ }
+}
diff --git a/gameui/GameUIPanel.h b/gameui/GameUIPanel.h
new file mode 100644
index 0000000..6b61566
--- /dev/null
+++ b/gameui/GameUIPanel.h
@@ -0,0 +1,22 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GAMEUIPANEL_H
+#define GAMEUIPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// Retrieve the root panel for the GameUI subsystem
+namespace vgui
+{
+class Panel;
+};
+
+vgui::Panel *GetGameUIRootPanel( void );
+
+#endif // GAMEUIPANEL_H
diff --git a/gameui/GameUI_Interface.cpp b/gameui/GameUI_Interface.cpp
new file mode 100644
index 0000000..01c7b39
--- /dev/null
+++ b/gameui/GameUI_Interface.cpp
@@ -0,0 +1,1285 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Implements all the functions exported by the GameUI dll
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifdef WIN32
+#if !defined( _X360 )
+#include <windows.h>
+#endif
+#include <io.h>
+#include <direct.h>
+#elif defined( POSIX )
+#include <sys/time.h>
+#else
+#error
+#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <tier0/dbg.h>
+
+#ifdef SendMessage
+#undef SendMessage
+#endif
+
+#include "filesystem.h"
+#include "GameUI_Interface.h"
+#include "Sys_Utils.h"
+#include "string.h"
+#include "tier0/icommandline.h"
+
+// interface to engine
+#include "EngineInterface.h"
+
+#include "replay/ienginereplay.h"
+#include "replay/ireplaysystem.h"
+
+#include "VGuiSystemModuleLoader.h"
+#include "bitmap/tgaloader.h"
+
+#include "GameConsole.h"
+#include "LoadingDialog.h"
+#include "CDKeyEntryDialog.h"
+#include "ModInfo.h"
+#include "game/client/IGameClientExports.h"
+#include "materialsystem/imaterialsystem.h"
+#include "engine/imatchmaking.h"
+#include "ixboxsystem.h"
+#include "iachievementmgr.h"
+#include "IGameUIFuncs.h"
+#include <ienginevgui.h>
+#include "steam/steam_api.h"
+#include "BonusMapsDatabase.h"
+#include "BonusMapsDialog.h"
+#include "sourcevr/isourcevirtualreality.h"
+
+// vgui2 interface
+// note that GameUI project uses ..\vgui2\include, not ..\utils\vgui\include
+#include "BasePanel.h"
+
+#include <vgui/Cursor.h>
+#include <KeyValues.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IPanel.h>
+#include <vgui/IScheme.h>
+#include <vgui/IVGui.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/Menu.h>
+#include <vgui_controls/PHandle.h>
+#include "tier3/tier3.h"
+#include "tier0/vcrmode.h"
+#include "matsys_controls/matsyscontrols.h"
+#include "steam/steam_api.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+#include "tier0/dbg.h"
+#include "engine/IEngineSound.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+IGameUIFuncs *gameuifuncs = NULL;
+IEngineVGui *enginevguifuncs = NULL;
+IMatchmaking *matchmaking = NULL;
+IXboxSystem *xboxsystem = NULL; // 360 only
+vgui::ISurface *enginesurfacefuncs = NULL;
+IVEngineClient *engine = NULL;
+IEngineSound *enginesound = NULL;
+IAchievementMgr *achievementmgr = NULL;
+IEngineClientReplay *g_pEngineClientReplay = NULL;
+ISourceVirtualReality *g_pSourceVR = NULL;
+
+static CSteamAPIContext g_SteamAPIContext;
+CSteamAPIContext *steamapicontext = &g_SteamAPIContext;
+
+static CBasePanel *staticPanel = NULL;
+
+class CGameUI;
+CGameUI *g_pGameUI = NULL;
+
+class CLoadingDialog;
+vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
+vgui::VPANEL g_hLoadingBackgroundDialog = NULL;
+
+static CGameUI g_GameUI;
+static WHANDLE g_hMutex = NULL;
+static WHANDLE g_hWaitMutex = NULL;
+
+static IGameClientExports *g_pGameClientExports = NULL;
+IGameClientExports *GameClientExports()
+{
+ return g_pGameClientExports;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CGameUI &GameUI()
+{
+ return g_GameUI;
+}
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameUI, IGameUI, GAMEUI_INTERFACE_VERSION, g_GameUI);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CGameUI::CGameUI()
+{
+ g_pGameUI = this;
+ m_bTryingToLoadFriends = false;
+ m_iFriendsLoadPauseFrames = 0;
+ m_iGameIP = 0;
+ m_iGameConnectionPort = 0;
+ m_iGameQueryPort = 0;
+ m_bActivatedUI = false;
+ m_szPreviousStatusText[0] = 0;
+ m_bIsConsoleUI = false;
+ m_bHasSavedThisMenuSession = false;
+ m_bOpenProgressOnStart = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CGameUI::~CGameUI()
+{
+ g_pGameUI = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Initialization
+//-----------------------------------------------------------------------------
+void CGameUI::Initialize( CreateInterfaceFn factory )
+{
+ ConnectTier1Libraries( &factory, 1 );
+ ConnectTier2Libraries( &factory, 1 );
+ ConVar_Register( FCVAR_CLIENTDLL );
+ ConnectTier3Libraries( &factory, 1 );
+
+ enginesound = (IEngineSound *)factory(IENGINESOUND_CLIENT_INTERFACE_VERSION, NULL);
+ engine = (IVEngineClient *)factory( VENGINE_CLIENT_INTERFACE_VERSION, NULL );
+
+ steamapicontext->Init();
+
+ ConVarRef var( "gameui_xbox" );
+ m_bIsConsoleUI = var.IsValid() && var.GetBool();
+
+ vgui::VGui_InitInterfacesList( "GameUI", &factory, 1 );
+ vgui::VGui_InitMatSysInterfacesList( "GameUI", &factory, 1 );
+
+ // load localization file
+ g_pVGuiLocalize->AddFile( "Resource/gameui_%language%.txt", "GAME", true );
+
+ // load mod info
+ ModInfo().LoadCurrentGameInfo();
+
+ // load localization file for kb_act.lst
+ g_pVGuiLocalize->AddFile( "Resource/valve_%language%.txt", "GAME", true );
+
+ enginevguifuncs = (IEngineVGui *)factory( VENGINE_VGUI_VERSION, NULL );
+ enginesurfacefuncs = (vgui::ISurface *)factory(VGUI_SURFACE_INTERFACE_VERSION, NULL);
+ gameuifuncs = (IGameUIFuncs *)factory( VENGINE_GAMEUIFUNCS_VERSION, NULL );
+ matchmaking = (IMatchmaking *)factory( VENGINE_MATCHMAKING_VERSION, NULL );
+ xboxsystem = (IXboxSystem *)factory( XBOXSYSTEM_INTERFACE_VERSION, NULL );
+ g_pEngineClientReplay = (IEngineClientReplay *)factory( ENGINE_REPLAY_CLIENT_INTERFACE_VERSION, NULL );
+
+ if ( ModInfo().SupportsVR() && CommandLine()->CheckParm( "-vr" ) )
+ {
+ g_pSourceVR = (ISourceVirtualReality *)factory( SOURCE_VIRTUAL_REALITY_INTERFACE_VERSION, NULL );
+ }
+
+ // NOTE: g_pEngineReplay intentionally not checked here
+ if ( !enginesurfacefuncs || !gameuifuncs || !enginevguifuncs || !xboxsystem || (IsX360() && !matchmaking) )
+ {
+ Error( "CGameUI::Initialize() failed to get necessary interfaces\n" );
+ }
+
+ // setup base panel
+ staticPanel = new CBasePanel();
+ staticPanel->SetBounds(0, 0, 400, 300 );
+ staticPanel->SetPaintBorderEnabled( false );
+ staticPanel->SetPaintBackgroundEnabled( true );
+ staticPanel->SetPaintEnabled( false );
+ staticPanel->SetVisible( true );
+ staticPanel->SetMouseInputEnabled( false );
+ staticPanel->SetKeyBoardInputEnabled( false );
+
+ vgui::VPANEL rootpanel = enginevguifuncs->GetPanel( PANEL_GAMEUIDLL );
+ staticPanel->SetParent( rootpanel );
+}
+
+void CGameUI::PostInit()
+{
+ if ( IsX360() )
+ {
+ enginesound->PrecacheSound( "UI/buttonrollover.wav", true, true );
+ enginesound->PrecacheSound( "UI/buttonclick.wav", true, true );
+ enginesound->PrecacheSound( "UI/buttonclickrelease.wav", true, true );
+ enginesound->PrecacheSound( "player/suit_denydevice.wav", true, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the specified panel as the background panel for the loading
+// dialog. If NULL, default background is used. If you set a panel,
+// it should be full-screen with an opaque background, and must be a VGUI popup.
+//-----------------------------------------------------------------------------
+void CGameUI::SetLoadingBackgroundDialog( vgui::VPANEL panel )
+{
+ g_hLoadingBackgroundDialog = panel;
+}
+
+void CGameUI::BonusMapUnlock( const char *pchFileName, const char *pchMapName )
+{
+ if ( !pchFileName || pchFileName[ 0 ] == '\0' ||
+ !pchMapName || pchMapName[ 0 ] == '\0' )
+ {
+ if ( !g_pBonusMapsDialog )
+ return;
+
+ g_pBonusMapsDialog->SetSelectedBooleanStatus( "lock", false );
+ return;
+ }
+
+ if ( BonusMapsDatabase()->SetBooleanStatus( "lock", pchFileName, pchMapName, false ) )
+ {
+ BonusMapsDatabase()->RefreshMapData();
+
+ if ( !g_pBonusMapsDialog )
+ {
+ // It unlocked without the bonus maps menu open, so flash the menu item
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ {
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( Q_stricmp( pchFileName, "scripts/advanced_chambers" ) == 0 )
+ {
+ pBasePanel->SetMenuItemBlinkingState( "OpenNewGameDialog", true );
+ }
+ }
+ else
+ {
+ pBasePanel->SetMenuItemBlinkingState( "OpenBonusMapsDialog", true );
+ }
+ }
+
+ BonusMapsDatabase()->SetBlink( true );
+ }
+ else
+ g_pBonusMapsDialog->RefreshData(); // Update the open dialog
+ }
+}
+
+void CGameUI::BonusMapComplete( const char *pchFileName, const char *pchMapName )
+{
+ if ( !pchFileName || pchFileName[ 0 ] == '\0' ||
+ !pchMapName || pchMapName[ 0 ] == '\0' )
+ {
+ if ( !g_pBonusMapsDialog )
+ return;
+
+ g_pBonusMapsDialog->SetSelectedBooleanStatus( "complete", true );
+ BonusMapsDatabase()->RefreshMapData();
+ g_pBonusMapsDialog->RefreshData();
+ return;
+ }
+
+ if ( BonusMapsDatabase()->SetBooleanStatus( "complete", pchFileName, pchMapName, true ) )
+ {
+ BonusMapsDatabase()->RefreshMapData();
+
+ // Update the open dialog
+ if ( g_pBonusMapsDialog )
+ g_pBonusMapsDialog->RefreshData();
+ }
+}
+
+void CGameUI::BonusMapChallengeUpdate( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest )
+{
+ if ( !pchFileName || pchFileName[ 0 ] == '\0' ||
+ !pchMapName || pchMapName[ 0 ] == '\0' ||
+ !pchChallengeName || pchChallengeName[ 0 ] == '\0' )
+ {
+ return;
+ }
+ else
+ {
+ if ( BonusMapsDatabase()->UpdateChallengeBest( pchFileName, pchMapName, pchChallengeName, iBest ) )
+ {
+ // The challenge best changed, so write it to the file
+ BonusMapsDatabase()->WriteSaveData();
+ BonusMapsDatabase()->RefreshMapData();
+
+ // Update the open dialog
+ if ( g_pBonusMapsDialog )
+ g_pBonusMapsDialog->RefreshData();
+ }
+ }
+}
+
+void CGameUI::BonusMapChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName )
+{
+ if ( !pchFileName || !pchMapName || !pchChallengeName )
+ return;
+
+ BonusMapsDatabase()->GetCurrentChallengeNames( pchFileName, pchMapName, pchChallengeName );
+}
+
+void CGameUI::BonusMapChallengeObjectives( int &iBronze, int &iSilver, int &iGold )
+{
+ BonusMapsDatabase()->GetCurrentChallengeObjectives( iBronze, iSilver, iGold );
+}
+
+void CGameUI::BonusMapDatabaseSave( void )
+{
+ BonusMapsDatabase()->WriteSaveData();
+}
+
+int CGameUI::BonusMapNumAdvancedCompleted( void )
+{
+ return BonusMapsDatabase()->NumAdvancedComplete();
+}
+
+void CGameUI::BonusMapNumMedals( int piNumMedals[ 3 ] )
+{
+ BonusMapsDatabase()->NumMedals( piNumMedals );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: connects to client interfaces
+//-----------------------------------------------------------------------------
+void CGameUI::Connect( CreateInterfaceFn gameFactory )
+{
+ g_pGameClientExports = (IGameClientExports *)gameFactory(GAMECLIENTEXPORTS_INTERFACE_VERSION, NULL);
+
+ achievementmgr = engine->GetAchievementMgr();
+
+ if (!g_pGameClientExports)
+ {
+ Error("CGameUI::Initialize() failed to get necessary interfaces\n");
+ }
+
+ m_GameFactory = gameFactory;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Callback function; sends platform Shutdown message to specified window
+//-----------------------------------------------------------------------------
+int __stdcall SendShutdownMsgFunc(WHANDLE hwnd, int lparam)
+{
+ Sys_PostMessage(hwnd, Sys_RegisterWindowMessage("ShutdownValvePlatform"), 0, 1);
+ return 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Searches for GameStartup*.mp3 files in the sound/ui folder and plays one
+//-----------------------------------------------------------------------------
+void CGameUI::PlayGameStartupSound()
+{
+ if ( IsX360() )
+ return;
+
+ if ( CommandLine()->FindParm( "-nostartupsound" ) )
+ return;
+
+ FileFindHandle_t fh;
+
+ CUtlVector<char *> fileNames;
+ char path[ 512 ];
+
+ bool bHolidayFound = false;
+
+ // only want to run the holiday check for TF2
+ const char *pGameName = CommandLine()->ParmValue( "-game", "hl2" );
+ if ( ( Q_stricmp( pGameName, "tf" ) == 0 ) || ( Q_stricmp( pGameName, "tf_beta" ) == 0 ) )
+ {
+ // check for a holiday sound file
+ const char *pszHoliday = NULL;
+
+ if ( GameClientExports() )
+ {
+ pszHoliday = GameClientExports()->GetHolidayString();
+ if ( pszHoliday && pszHoliday[0] )
+ {
+ Q_snprintf( path, sizeof( path ), "sound/ui/holiday/gamestartup_%s*.mp3", pszHoliday );
+ Q_FixSlashes( path );
+
+ char const *fn = g_pFullFileSystem->FindFirstEx( path, "MOD", &fh );
+ {
+ if ( fn )
+ {
+ bHolidayFound = true;
+ }
+ }
+ }
+ }
+ }
+
+ // only want to do this if we haven't found a holiday file
+ if ( !bHolidayFound )
+ {
+ Q_snprintf( path, sizeof( path ), "sound/ui/gamestartup*.mp3" );
+ Q_FixSlashes( path );
+ }
+
+ char const *fn = g_pFullFileSystem->FindFirstEx( path, "MOD", &fh );
+ if ( fn )
+ {
+ do
+ {
+ char ext[ 10 ];
+ Q_ExtractFileExtension( fn, ext, sizeof( ext ) );
+
+ if ( !Q_stricmp( ext, "mp3" ) )
+ {
+ char temp[ 512 ];
+ if ( bHolidayFound )
+ {
+ Q_snprintf( temp, sizeof( temp ), "ui/holiday/%s", fn );
+ }
+ else
+ {
+ Q_snprintf( temp, sizeof( temp ), "ui/%s", fn );
+ }
+
+ char *found = new char[ strlen( temp ) + 1 ];
+ Q_strncpy( found, temp, strlen( temp ) + 1 );
+
+ Q_FixSlashes( found );
+ fileNames.AddToTail( found );
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+
+ } while ( fn );
+
+ g_pFullFileSystem->FindClose( fh );
+ }
+
+ // did we find any?
+ if ( fileNames.Count() > 0 )
+ {
+#ifdef WIN32
+ SYSTEMTIME SystemTime;
+ GetSystemTime( &SystemTime );
+ int index = SystemTime.wMilliseconds % fileNames.Count();
+#else
+ struct timeval tm;
+ gettimeofday( &tm, NULL );
+ int index = tm.tv_usec/1000 % fileNames.Count();
+#endif
+
+ if ( fileNames.IsValidIndex( index ) && fileNames[index] )
+ {
+ // Play the Saxxy music if we're in saxxy mode.
+#if defined( SAXXYMAINMENU_ENABLED )
+ bool bIsTF = false;
+ const char *pGameDir = engine->GetGameDirectory();
+ if ( pGameDir )
+ {
+ // Is the game TF?
+ const int nStrLen = V_strlen( pGameDir );
+ bIsTF = nStrLen
+ && nStrLen >= 2 &&
+ pGameDir[nStrLen-2] == 't' &&
+ pGameDir[nStrLen-1] == 'f';
+ }
+
+ // escape chars "*#" make it stream, and be affected by snd_musicvolume
+ const char *pSoundFile = bIsTF ? "ui/holiday/gamestartup_saxxy.mp3" : fileNames[index];
+#else
+ const char *pSoundFile = fileNames[index];
+#endif
+
+ char found[ 512 ];
+ Q_snprintf( found, sizeof( found ), "play *#%s", pSoundFile );
+
+ engine->ClientCmd_Unrestricted( found );
+ }
+
+ fileNames.PurgeAndDeleteElements();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called to setup the game UI
+//-----------------------------------------------------------------------------
+void CGameUI::Start()
+{
+ // determine Steam location for configuration
+ if ( !FindPlatformDirectory( m_szPlatformDir, sizeof( m_szPlatformDir ) ) )
+ return;
+
+ if ( IsPC() )
+ {
+ // setup config file directory
+ char szConfigDir[512];
+ Q_strncpy( szConfigDir, m_szPlatformDir, sizeof( szConfigDir ) );
+ Q_strncat( szConfigDir, "config", sizeof( szConfigDir ), COPY_ALL_CHARACTERS );
+
+ Msg( "Steam config directory: %s\n", szConfigDir );
+
+ g_pFullFileSystem->AddSearchPath(szConfigDir, "CONFIG");
+ g_pFullFileSystem->CreateDirHierarchy("", "CONFIG");
+
+ // user dialog configuration
+ vgui::system()->SetUserConfigFile("InGameDialogConfig.vdf", "CONFIG");
+
+ g_pFullFileSystem->AddSearchPath( "platform", "PLATFORM" );
+ }
+
+ // localization
+ g_pVGuiLocalize->AddFile( "Resource/platform_%language%.txt");
+ g_pVGuiLocalize->AddFile( "Resource/vgui_%language%.txt");
+
+ Sys_SetLastError( SYS_NO_ERROR );
+
+ if ( IsPC() )
+ {
+ if ( !IsPosix() )
+ {
+ // Alfred says this is really, really old code that does some wacky crap that only
+ // happened in the first version of HL and it's the only game that does this and
+ // it was a steam testing type thing and we don't need to do it on Posix, etc.
+
+ g_hMutex = Sys_CreateMutex( "ValvePlatformUIMutex" );
+ g_hWaitMutex = Sys_CreateMutex( "ValvePlatformWaitMutex" );
+ if ( g_hMutex == 0 || g_hWaitMutex == 0 || Sys_GetLastError() == SYS_ERROR_INVALID_HANDLE )
+ {
+ // error, can't get handle to mutex
+ if (g_hMutex)
+ {
+ Sys_ReleaseMutex(g_hMutex);
+ }
+ if (g_hWaitMutex)
+ {
+ Sys_ReleaseMutex(g_hWaitMutex);
+ }
+ g_hMutex = NULL;
+ g_hWaitMutex = NULL;
+ Error("Steam Error: Could not access Steam, bad mutex\n");
+ return;
+ }
+ unsigned int waitResult = Sys_WaitForSingleObject(g_hMutex, 0);
+ if (!(waitResult == SYS_WAIT_OBJECT_0 || waitResult == SYS_WAIT_ABANDONED))
+ {
+ // mutex locked, need to deactivate Steam (so we have the Friends/ServerBrowser data files)
+ // get the wait mutex, so that Steam.exe knows that we're trying to acquire ValveTrackerMutex
+ waitResult = Sys_WaitForSingleObject(g_hWaitMutex, 0);
+#ifdef WIN32
+ if (waitResult == SYS_WAIT_OBJECT_0 || waitResult == SYS_WAIT_ABANDONED)
+ {
+ Sys_EnumWindows(SendShutdownMsgFunc, 1);
+ }
+#endif
+ }
+ }
+
+ // Delay playing the startup music until the first frame
+ m_bPlayGameStartupSound = true;
+
+ // now we are set up to check every frame to see if we can friends/server browser
+ m_bTryingToLoadFriends = true;
+ m_iFriendsLoadPauseFrames = 1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Validates the user has a cdkey in the registry
+//-----------------------------------------------------------------------------
+void CGameUI::ValidateCDKey()
+{
+ // this check is disabled, since we have no plans for an offline version of hl2
+#if 0
+ //!! hack, write out a regkey for now so developers don't have to type it in
+ //!! undo this before release
+ vgui::system()->SetRegistryString("HKEY_CURRENT_USER\\Software\\Valve\\Source\\Settings\\EncryptedCDKey", "QOgi:JXrJj<Eb8abkESf4Pg;OfofJwDzRsyH>AdjtyPnV[FB");
+
+ // see what's in the registry
+ if (!CCDKeyEntryDialog::IsValidWeakCDKeyInRegistry())
+ {
+ m_hCDKeyEntryDialog = new CCDKeyEntryDialog(NULL, false);
+ m_hCDKeyEntryDialog->Activate();
+ }
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finds which directory the platform resides in
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CGameUI::FindPlatformDirectory(char *platformDir, int bufferSize)
+{
+ platformDir[0] = '\0';
+
+ if ( platformDir[0] == '\0' )
+ {
+ // we're not under steam, so setup using path relative to game
+ if ( IsPC() )
+ {
+#ifdef WIN32
+ if ( ::GetModuleFileName( ( HINSTANCE )GetModuleHandle( NULL ), platformDir, bufferSize ) )
+ {
+ char *lastslash = strrchr(platformDir, '\\'); // this should be just before the filename
+ if ( lastslash )
+ {
+ *lastslash = 0;
+ Q_strncat(platformDir, "\\platform\\", bufferSize, COPY_ALL_CHARACTERS );
+ return true;
+ }
+ }
+#else
+ if ( getcwd( platformDir, bufferSize ) )
+ {
+ V_AppendSlash( platformDir, bufferSize );
+ Q_strncat(platformDir, "platform", bufferSize, COPY_ALL_CHARACTERS );
+ V_AppendSlash( platformDir, bufferSize );
+ return true;
+ }
+#endif
+ }
+ else
+ {
+ // xbox fetches the platform path from exisiting platform search path
+ // path to executeable is not correct for xbox remote configuration
+ if ( g_pFullFileSystem->GetSearchPath( "PLATFORM", false, platformDir, bufferSize ) )
+ {
+ char *pSeperator = strchr( platformDir, ';' );
+ if ( pSeperator )
+ *pSeperator = '\0';
+ return true;
+ }
+ }
+
+ Error( "Unable to determine platform directory\n" );
+ return false;
+ }
+
+ return (platformDir[0] != 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called to Shutdown the game UI system
+//-----------------------------------------------------------------------------
+void CGameUI::Shutdown()
+{
+ // notify all the modules of Shutdown
+ g_VModuleLoader.ShutdownPlatformModules();
+
+ // unload the modules them from memory
+ g_VModuleLoader.UnloadPlatformModules();
+
+ ModInfo().FreeModInfo();
+
+ // release platform mutex
+ // close the mutex
+ if (g_hMutex)
+ {
+ Sys_ReleaseMutex(g_hMutex);
+ }
+ if (g_hWaitMutex)
+ {
+ Sys_ReleaseMutex(g_hWaitMutex);
+ }
+
+ BonusMapsDatabase()->WriteSaveData();
+
+ steamapicontext->Clear();
+
+
+ ConVar_Unregister();
+ DisconnectTier3Libraries();
+ DisconnectTier2Libraries();
+ DisconnectTier1Libraries();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: just wraps an engine call to activate the gameUI
+//-----------------------------------------------------------------------------
+void CGameUI::ActivateGameUI()
+{
+ engine->ExecuteClientCmd("gameui_activate");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: just wraps an engine call to hide the gameUI
+//-----------------------------------------------------------------------------
+void CGameUI::HideGameUI()
+{
+ engine->ExecuteClientCmd("gameui_hide");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Toggle allowing the engine to hide the game UI with the escape key
+//-----------------------------------------------------------------------------
+void CGameUI::PreventEngineHideGameUI()
+{
+ engine->ExecuteClientCmd("gameui_preventescape");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Toggle allowing the engine to hide the game UI with the escape key
+//-----------------------------------------------------------------------------
+void CGameUI::AllowEngineHideGameUI()
+{
+ engine->ExecuteClientCmd("gameui_allowescape");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activate the game UI
+//-----------------------------------------------------------------------------
+void CGameUI::OnGameUIActivated()
+{
+ m_bActivatedUI = true;
+
+ // hide/show the main panel to Activate all game ui
+ staticPanel->SetVisible( true );
+
+ // pause the server in single player
+ if ( engine->GetMaxClients() <= 1 )
+ {
+ engine->ClientCmd_Unrestricted( "setpause" );
+ }
+
+ SetSavedThisMenuSession( false );
+
+ // notify taskbar
+ BasePanel()->OnGameUIActivated();
+
+ if ( GameClientExports() )
+ {
+ const char *pGameName = CommandLine()->ParmValue( "-game", "hl2" );
+ // only want to run this for TF2
+ if ( ( Q_stricmp( pGameName, "tf" ) == 0 ) || ( Q_stricmp( pGameName, "tf_beta" ) == 0 ) )
+ {
+ GameClientExports()->OnGameUIActivated();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the game ui, in whatever state it's in
+//-----------------------------------------------------------------------------
+void CGameUI::OnGameUIHidden()
+{
+ if ( GameClientExports() )
+ {
+ const char *pGameName = CommandLine()->ParmValue( "-game", "hl2" );
+ // only want to run this for TF2
+ if ( ( Q_stricmp( pGameName, "tf" ) == 0 ) || ( Q_stricmp( pGameName, "tf_beta" ) == 0 ) )
+ {
+ GameClientExports()->OnGameUIHidden();
+ }
+ }
+
+ // unpause the game when leaving the UI
+ if ( engine->GetMaxClients() <= 1 )
+ {
+ engine->ClientCmd_Unrestricted("unpause");
+ }
+
+ BasePanel()->OnGameUIHidden();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: paints all the vgui elements
+//-----------------------------------------------------------------------------
+void CGameUI::RunFrame()
+{
+ if ( IsX360() && m_bOpenProgressOnStart )
+ {
+ StartProgressBar();
+ m_bOpenProgressOnStart = false;
+ }
+
+ // resize the background panel to the screen size
+ int wide, tall;
+ vgui::surface()->GetScreenSize(wide, tall);
+ staticPanel->SetSize(wide,tall);
+
+ // Run frames
+ g_VModuleLoader.RunFrame();
+ BasePanel()->RunFrame();
+
+ // Play the start-up music the first time we run frame
+ if ( IsPC() && m_bPlayGameStartupSound )
+ {
+ PlayGameStartupSound();
+ m_bPlayGameStartupSound = false;
+ }
+
+ if ( IsPC() && ( ( IsPosix() && m_bTryingToLoadFriends ) ||
+ ( m_bTryingToLoadFriends && m_iFriendsLoadPauseFrames-- < 1 && g_hMutex && g_hWaitMutex ) ) )
+ {
+ // try and load Steam platform files
+ unsigned int waitResult = Sys_WaitForSingleObject(g_hMutex, 0);
+ if ( IsPosix() || ( waitResult == SYS_WAIT_OBJECT_0 || waitResult == SYS_WAIT_ABANDONED ))
+ {
+ // we got the mutex, so load Friends/Serverbrowser
+ // clear the loading flag
+ m_bTryingToLoadFriends = false;
+ g_VModuleLoader.LoadPlatformModules(&m_GameFactory, 1, false);
+
+ // release the wait mutex
+ if ( !IsPosix() )
+ Sys_ReleaseMutex(g_hWaitMutex);
+
+ // notify the game of our game name
+ const char *fullGamePath = engine->GetGameDirectory();
+ const char *pathSep = strrchr( fullGamePath, '/' );
+ if ( !pathSep )
+ {
+ pathSep = strrchr( fullGamePath, '\\' );
+ }
+ if ( pathSep )
+ {
+ KeyValues *pKV = new KeyValues("ActiveGameName" );
+ pKV->SetString( "name", pathSep + 1 );
+ pKV->SetInt( "appid", engine->GetAppID() );
+ KeyValues *modinfo = new KeyValues("ModInfo");
+ if ( modinfo->LoadFromFile( g_pFullFileSystem, "gameinfo.txt" ) )
+ {
+ pKV->SetString( "game", modinfo->GetString( "game", "" ) );
+ }
+ modinfo->deleteThis();
+
+ g_VModuleLoader.PostMessageToAllModules( pKV );
+ }
+
+ // notify the ui of a game connect if we're already in a game
+ if (m_iGameIP)
+ {
+ SendConnectedToGameMessage();
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the game connects to a server
+//-----------------------------------------------------------------------------
+void CGameUI::OLD_OnConnectToServer(const char *game, int IP, int port)
+{
+ // Nobody should use this anymore because the query port and the connection port can be different.
+ // Use OnConnectToServer2 instead.
+ Assert( false );
+ OnConnectToServer2( game, IP, port, port );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the game connects to a server
+//-----------------------------------------------------------------------------
+void CGameUI::OnConnectToServer2(const char *game, int IP, int connectionPort, int queryPort)
+{
+ m_iGameIP = IP;
+ m_iGameConnectionPort = connectionPort;
+ m_iGameQueryPort = queryPort;
+
+ SendConnectedToGameMessage();
+}
+
+
+void CGameUI::SendConnectedToGameMessage()
+{
+ KeyValues *kv = new KeyValues( "ConnectedToGame" );
+ kv->SetInt( "ip", m_iGameIP );
+ kv->SetInt( "connectionport", m_iGameConnectionPort );
+ kv->SetInt( "queryport", m_iGameQueryPort );
+
+ g_VModuleLoader.PostMessageToAllModules( kv );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the game disconnects from a server
+//-----------------------------------------------------------------------------
+void CGameUI::OnDisconnectFromServer( uint8 eSteamLoginFailure )
+{
+ m_iGameIP = 0;
+ m_iGameConnectionPort = 0;
+ m_iGameQueryPort = 0;
+
+ g_VModuleLoader.PostMessageToAllModules(new KeyValues("DisconnectedFromGame"));
+
+ if ( eSteamLoginFailure == STEAMLOGINFAILURE_NOSTEAMLOGIN )
+ {
+ if ( g_hLoadingDialog )
+ {
+ g_hLoadingDialog->DisplayNoSteamConnectionError();
+ }
+ }
+ else if ( eSteamLoginFailure == STEAMLOGINFAILURE_VACBANNED )
+ {
+ if ( g_hLoadingDialog )
+ {
+ g_hLoadingDialog->DisplayVACBannedError();
+ }
+ }
+ else if ( eSteamLoginFailure == STEAMLOGINFAILURE_LOGGED_IN_ELSEWHERE )
+ {
+ if ( g_hLoadingDialog )
+ {
+ g_hLoadingDialog->DisplayLoggedInElsewhereError();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: activates the loading dialog on level load start
+//-----------------------------------------------------------------------------
+void CGameUI::OnLevelLoadingStarted( bool bShowProgressDialog )
+{
+ g_VModuleLoader.PostMessageToAllModules( new KeyValues( "LoadingStarted" ) );
+
+ // notify
+ BasePanel()->OnLevelLoadingStarted();
+
+ if ( bShowProgressDialog )
+ {
+ StartProgressBar();
+ }
+
+ // Don't play the start game sound if this happens before we get to the first frame
+ m_bPlayGameStartupSound = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: closes any level load dialog
+//-----------------------------------------------------------------------------
+void CGameUI::OnLevelLoadingFinished(bool bError, const char *failureReason, const char *extendedReason)
+{
+ StopProgressBar( bError, failureReason, extendedReason );
+
+ // notify all the modules
+ g_VModuleLoader.PostMessageToAllModules( new KeyValues( "LoadingFinished" ) );
+
+ // hide the UI
+ HideGameUI();
+
+ // notify
+ BasePanel()->OnLevelLoadingFinished();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates progress bar
+// Output : Returns true if screen should be redrawn
+//-----------------------------------------------------------------------------
+bool CGameUI::UpdateProgressBar(float progress, const char *statusText)
+{
+ // if either the progress bar or the status text changes, redraw the screen
+ bool bRedraw = false;
+
+ if ( ContinueProgressBar( progress ) )
+ {
+ bRedraw = true;
+ }
+
+ if ( SetProgressBarStatusText( statusText ) )
+ {
+ bRedraw = true;
+ }
+
+ return bRedraw;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGameUI::StartProgressBar()
+{
+ if ( !g_hLoadingDialog.Get() )
+ {
+ g_hLoadingDialog = new CLoadingDialog(staticPanel);
+ }
+
+ // open a loading dialog
+ m_szPreviousStatusText[0] = 0;
+ g_hLoadingDialog->SetProgressPoint(0.0f);
+ g_hLoadingDialog->Open();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the screen should be updated
+//-----------------------------------------------------------------------------
+bool CGameUI::ContinueProgressBar( float progressFraction )
+{
+ if (!g_hLoadingDialog.Get())
+ return false;
+
+ g_hLoadingDialog->Activate();
+ return g_hLoadingDialog->SetProgressPoint(progressFraction);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: stops progress bar, displays error if necessary
+//-----------------------------------------------------------------------------
+void CGameUI::StopProgressBar(bool bError, const char *failureReason, const char *extendedReason)
+{
+ if (!g_hLoadingDialog.Get() && bError)
+ {
+ g_hLoadingDialog = new CLoadingDialog(staticPanel);
+ }
+
+ if (!g_hLoadingDialog.Get())
+ return;
+
+ if ( !IsX360() && bError )
+ {
+ // turn the dialog to error display mode
+ g_hLoadingDialog->DisplayGenericError(failureReason, extendedReason);
+ }
+ else
+ {
+ // close loading dialog
+ g_hLoadingDialog->Close();
+ g_hLoadingDialog = NULL;
+ }
+ // should update the background to be in a transition here
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets loading info text
+//-----------------------------------------------------------------------------
+bool CGameUI::SetProgressBarStatusText(const char *statusText)
+{
+ if (!g_hLoadingDialog.Get())
+ return false;
+
+ if (!statusText)
+ return false;
+
+ if (!stricmp(statusText, m_szPreviousStatusText))
+ return false;
+
+ g_hLoadingDialog->SetStatusText(statusText);
+ Q_strncpy(m_szPreviousStatusText, statusText, sizeof(m_szPreviousStatusText));
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGameUI::SetSecondaryProgressBar(float progress /* range [0..1] */)
+{
+ if (!g_hLoadingDialog.Get())
+ return;
+
+ g_hLoadingDialog->SetSecondaryProgress(progress);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGameUI::SetSecondaryProgressBarText(const char *statusText)
+{
+ if (!g_hLoadingDialog.Get())
+ return;
+
+ g_hLoadingDialog->SetSecondaryProgressText(statusText);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns prev settings
+//-----------------------------------------------------------------------------
+bool CGameUI::SetShowProgressText( bool show )
+{
+ if (!g_hLoadingDialog.Get())
+ return false;
+
+ return g_hLoadingDialog->SetShowProgressText( show );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're currently playing the game
+//-----------------------------------------------------------------------------
+bool CGameUI::IsInLevel()
+{
+ const char *levelName = engine->GetLevelName();
+ if (levelName && levelName[0] && !engine->IsLevelMainMenuBackground())
+ {
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're at the main menu and a background level is loaded
+//-----------------------------------------------------------------------------
+bool CGameUI::IsInBackgroundLevel()
+{
+ const char *levelName = engine->GetLevelName();
+ if (levelName && levelName[0] && engine->IsLevelMainMenuBackground())
+ {
+ return true;
+ }
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're in a multiplayer game
+//-----------------------------------------------------------------------------
+bool CGameUI::IsInMultiplayer()
+{
+ return (IsInLevel() && engine->GetMaxClients() > 1);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're playing back a replay
+//-----------------------------------------------------------------------------
+bool CGameUI::IsInReplay()
+{
+ return g_pEngineClientReplay && g_pEngineClientReplay->IsPlayingReplayDemo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're console ui
+//-----------------------------------------------------------------------------
+bool CGameUI::IsConsoleUI()
+{
+ return m_bIsConsoleUI;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we've saved without closing the menu
+//-----------------------------------------------------------------------------
+bool CGameUI::HasSavedThisMenuSession()
+{
+ return m_bHasSavedThisMenuSession;
+}
+
+void CGameUI::SetSavedThisMenuSession( bool bState )
+{
+ m_bHasSavedThisMenuSession = bState;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGameUI::ShowNewGameDialog( int chapter )
+{
+ char val[32];
+ Q_snprintf( val, sizeof(val), "%d", chapter);
+ staticPanel->OnOpenNewGameDialog(val);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes the loading background dialog visible, if one has been set
+//-----------------------------------------------------------------------------
+void CGameUI::ShowLoadingBackgroundDialog()
+{
+ if ( g_hLoadingBackgroundDialog )
+ {
+ vgui::ipanel()->SetParent( g_hLoadingBackgroundDialog, staticPanel->GetVPanel() );
+ vgui::ipanel()->PerformApplySchemeSettings( g_hLoadingBackgroundDialog );
+ vgui::ipanel()->SetVisible( g_hLoadingBackgroundDialog, true );
+ vgui::ipanel()->MoveToFront( g_hLoadingBackgroundDialog );
+ vgui::ipanel()->SendMessage( g_hLoadingBackgroundDialog, new KeyValues( "activate" ), staticPanel->GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hides the loading background dialog, if one has been set
+//-----------------------------------------------------------------------------
+void CGameUI::HideLoadingBackgroundDialog()
+{
+ if ( g_hLoadingBackgroundDialog )
+ {
+ vgui::ipanel()->SetParent( g_hLoadingBackgroundDialog, NULL );
+ vgui::ipanel()->SetVisible( g_hLoadingBackgroundDialog, false );
+ vgui::ipanel()->MoveToBack( g_hLoadingBackgroundDialog );
+ vgui::ipanel()->SendMessage( g_hLoadingBackgroundDialog, new KeyValues( "deactivate" ), staticPanel->GetVPanel() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns whether a loading background dialog has been set
+//-----------------------------------------------------------------------------
+bool CGameUI::HasLoadingBackgroundDialog()
+{
+ return ( 0 != g_hLoadingBackgroundDialog );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Xbox 360 calls from engine to GameUI
+//-----------------------------------------------------------------------------
+void CGameUI::SessionNotification( const int notification, const int param )
+{
+ BasePanel()->SessionNotification( notification, param );
+}
+void CGameUI::SystemNotification( const int notification )
+{
+ BasePanel()->SystemNotification( notification );
+}
+void CGameUI::ShowMessageDialog( const uint nType, vgui::Panel *pOwner )
+{
+ BasePanel()->ShowMessageDialog( nType, pOwner );
+}
+void CGameUI::CloseMessageDialog( const uint nType )
+{
+ BasePanel()->CloseMessageDialog( nType );
+}
+void CGameUI::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost )
+{
+ BasePanel()->UpdatePlayerInfo( nPlayerId, pName, nTeam, cVoiceState, nPlayersNeeded, bHost );
+}
+void CGameUI::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping )
+{
+ BasePanel()->SessionSearchResult( searchIdx, pHostData, pResult, ping );
+}
+void CGameUI::OnCreditsFinished( void )
+{
+ BasePanel()->OnCreditsFinished();
+}
+bool CGameUI::ValidateStorageDevice( int *pStorageDeviceValidated )
+{
+ return BasePanel()->ValidateStorageDevice( pStorageDeviceValidated );
+}
+
+void CGameUI::SetProgressOnStart()
+{
+ m_bOpenProgressOnStart = true;
+}
+
+void CGameUI::OnConfirmQuit( void )
+{
+ BasePanel()->OnOpenQuitConfirmationDialog();
+}
+
+bool CGameUI::IsMainMenuVisible( void )
+{
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ return (pBasePanel->IsVisible() && pBasePanel->GetMenuAlpha() > 0 );
+ return false;
+}
+
+// Client DLL is providing us with a panel that it wants to replace the main menu with
+void CGameUI::SetMainMenuOverride( vgui::VPANEL panel )
+{
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ {
+ pBasePanel->SetMainMenuOverride( panel );
+ }
+}
+
+// Client DLL is telling us that a main menu command was issued, probably from its custom main menu panel
+void CGameUI::SendMainMenuCommand( const char *pszCommand )
+{
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ {
+ pBasePanel->RunMenuCommand( pszCommand );
+ }
+} \ No newline at end of file
diff --git a/gameui/GameUI_Interface.h b/gameui/GameUI_Interface.h
new file mode 100644
index 0000000..cee5c77
--- /dev/null
+++ b/gameui/GameUI_Interface.h
@@ -0,0 +1,159 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Defines the interface that the GameUI dll exports
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef GAMEUI_INTERFACE_H
+#define GAMEUI_INTERFACE_H
+#pragma once
+
+#include "GameUI/IGameUI.h"
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/PHandle.h>
+
+class IGameClientExports;
+
+//-----------------------------------------------------------------------------
+// Purpose: Implementation of GameUI's exposed interface
+//-----------------------------------------------------------------------------
+class CGameUI : public IGameUI
+{
+public:
+ CGameUI();
+ ~CGameUI();
+
+ virtual void Initialize( CreateInterfaceFn appFactory );
+ virtual void Connect( CreateInterfaceFn gameFactory );
+ virtual void Start();
+ virtual void Shutdown();
+ virtual void RunFrame();
+ virtual void PostInit();
+
+ // plays the startup mp3 when GameUI starts
+ void PlayGameStartupSound();
+
+ // Engine wrappers for activating / hiding the gameUI
+ void ActivateGameUI();
+ void HideGameUI();
+
+ // Toggle allowing the engine to hide the game UI with the escape key
+ void PreventEngineHideGameUI();
+ void AllowEngineHideGameUI();
+
+ virtual void SetLoadingBackgroundDialog( vgui::VPANEL panel );
+
+ // Bonus maps interfaces
+ virtual void BonusMapUnlock( const char *pchFileName = NULL, const char *pchMapName = NULL );
+ virtual void BonusMapComplete( const char *pchFileName = NULL, const char *pchMapName = NULL );
+ virtual void BonusMapChallengeUpdate( const char *pchFileName, const char *pchMapName, const char *pchChallengeName, int iBest );
+ virtual void BonusMapChallengeNames( char *pchFileName, char *pchMapName, char *pchChallengeName );
+ virtual void BonusMapChallengeObjectives( int &iBronze, int &iSilver, int &iGold );
+ virtual void BonusMapDatabaseSave( void );
+ virtual int BonusMapNumAdvancedCompleted( void );
+ virtual void BonusMapNumMedals( int piNumMedals[ 3 ] );
+
+ // notifications
+ virtual void OnGameUIActivated();
+ virtual void OnGameUIHidden();
+ virtual void OLD_OnConnectToServer( const char *game, int IP, int port ); // OLD: use OnConnectToServer2
+ virtual void OnConnectToServer2( const char *game, int IP, int connectionPort, int queryPort );
+ virtual void OnDisconnectFromServer( uint8 eSteamLoginFailure );
+ virtual void OnLevelLoadingStarted( bool bShowProgressDialog );
+ virtual void OnLevelLoadingFinished( bool bError, const char *failureReason, const char *extendedReason );
+ virtual void OnDisconnectFromServer_OLD( uint8 eSteamLoginFailure, const char *username ) { OnDisconnectFromServer( eSteamLoginFailure ); }
+
+ // progress
+ virtual bool UpdateProgressBar(float progress, const char *statusText);
+ // Shows progress desc, returns previous setting... (used with custom progress bars )
+ virtual bool SetShowProgressText( bool show );
+
+ // brings up the new game dialog
+ virtual void ShowNewGameDialog( int chapter );
+
+ // Xbox 360
+ virtual void SessionNotification( const int notification, const int param = 0 );
+ virtual void SystemNotification( const int notification );
+ virtual void ShowMessageDialog( const uint nType, vgui::Panel *pOwner = NULL );
+ virtual void CloseMessageDialog( const uint nType = 0 );
+ virtual void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost );
+ virtual void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping );
+ virtual void OnCreditsFinished( void );
+
+ // X360 Storage device validation:
+ // returns true right away if storage device has been previously selected.
+ // otherwise returns false and will set the variable pointed by pStorageDeviceValidated to 1
+ // once the storage device is selected by user.
+ virtual bool ValidateStorageDevice( int *pStorageDeviceValidated );
+
+ virtual void SetProgressOnStart();
+
+ virtual void OnConfirmQuit( void );
+
+ virtual bool IsMainMenuVisible( void );
+
+ // Client DLL is providing us with a panel that it wants to replace the main menu with
+ virtual void SetMainMenuOverride( vgui::VPANEL panel );
+ // Client DLL is telling us that a main menu command was issued, probably from its custom main menu panel
+ virtual void SendMainMenuCommand( const char *pszCommand );
+
+ // state
+ bool IsInLevel();
+ bool IsInBackgroundLevel();
+ bool IsInMultiplayer();
+ bool IsInReplay();
+ bool IsConsoleUI();
+ bool HasSavedThisMenuSession();
+ void SetSavedThisMenuSession( bool bState );
+
+ void ShowLoadingBackgroundDialog();
+ void HideLoadingBackgroundDialog();
+ bool HasLoadingBackgroundDialog();
+
+private:
+ void SendConnectedToGameMessage();
+
+ virtual void StartProgressBar();
+ virtual bool ContinueProgressBar(float progressFraction);
+ virtual void StopProgressBar(bool bError, const char *failureReason, const char *extendedReason = NULL);
+ virtual bool SetProgressBarStatusText(const char *statusText);
+
+ //!! these functions currently not implemented
+ virtual void SetSecondaryProgressBar(float progress /* range [0..1] */);
+ virtual void SetSecondaryProgressBarText(const char *statusText);
+
+ bool FindPlatformDirectory(char *platformDir, int bufferSize);
+ void GetUpdateVersion( char *pszProd, char *pszVer);
+ void ValidateCDKey();
+
+ CreateInterfaceFn m_GameFactory;
+
+ bool m_bPlayGameStartupSound : 1;
+ bool m_bTryingToLoadFriends : 1;
+ bool m_bActivatedUI : 1;
+ bool m_bIsConsoleUI : 1;
+ bool m_bHasSavedThisMenuSession : 1;
+ bool m_bOpenProgressOnStart : 1;
+
+ int m_iGameIP;
+ int m_iGameConnectionPort;
+ int m_iGameQueryPort;
+
+ int m_iFriendsLoadPauseFrames;
+
+ char m_szPreviousStatusText[128];
+ char m_szPlatformDir[MAX_PATH];
+
+ vgui::DHANDLE<class CCDKeyEntryDialog> m_hCDKeyEntryDialog;
+};
+
+// Purpose: singleton accessor
+extern CGameUI &GameUI();
+
+// expose client interface
+extern IGameClientExports *GameClientExports();
+
+
+#endif // GAMEUI_INTERFACE_H
diff --git a/gameui/HapticControlBox.cpp b/gameui/HapticControlBox.cpp
new file mode 100644
index 0000000..10a240f
--- /dev/null
+++ b/gameui/HapticControlBox.cpp
@@ -0,0 +1,191 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+#include "HapticControlBox.h"
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Panel.h>
+#include "cvarslider.h"
+#include "mathlib/vmatrix.h"
+#include <vgui/ISurface.h>
+#include "KeyValues.h"
+#include <vgui/ISystem.h>
+ControlBoxVisual::ControlBoxVisual(vgui::Panel *parent,const char *panelName, CCvarSlider *n, CCvarSlider *r, CCvarSlider *u, CCvarSlider *f, CCvarSlider *l, CCvarSlider *d) :
+BaseClass(parent,panelName)
+{
+ m_iMouseOver = -1;
+ m_flTime=0;
+
+ //disable mouse input.
+ SetMouseInputEnabled(false);
+
+ SlideValues = new CCvarSliderCube(n, r, u, f, l, d);
+
+ SlideValues->Down->AddActionSignalTarget(GetVPanel());
+ SlideValues->Far->AddActionSignalTarget(GetVPanel());
+ SlideValues->Up->AddActionSignalTarget(GetVPanel());
+ SlideValues->Near->AddActionSignalTarget(GetVPanel());
+ SlideValues->Left->AddActionSignalTarget(GetVPanel());
+ SlideValues->Right->AddActionSignalTarget(GetVPanel());
+ SetWide(64);
+ SetTall(64);
+}
+
+void ControlBoxVisual::OnSlideEnter(KeyValues*data)
+{
+ vgui::VPANEL fromPanel = data->GetInt("VPANEL");
+ if(fromPanel == SlideValues->Up->GetVPanel())
+ m_iMouseOver = HUI_BOX_UP;
+ else if(fromPanel == SlideValues->Down->GetVPanel())
+ m_iMouseOver = HUI_BOX_DOWN;
+ else if(fromPanel == SlideValues->Right->GetVPanel())
+ m_iMouseOver = HUI_BOX_RIGHT;
+ else if(fromPanel == SlideValues->Left->GetVPanel())
+ m_iMouseOver = HUI_BOX_LEFT;
+ else if(fromPanel == SlideValues->Far->GetVPanel())
+ m_iMouseOver = HUI_BOX_FAR;
+ else if(fromPanel == SlideValues->Near->GetVPanel())
+ m_iMouseOver = HUI_BOX_NEAR;
+}
+void ControlBoxVisual::OnSlideExit(KeyValues*data)
+{
+ //vgui::VPANEL fromPanel = data->GetInt("VPANEL");
+ m_iMouseOver=-1;
+}
+void ControlBoxVisual::Paint()
+{
+ m_flTime = vgui::system()->GetFrameTime();
+ BaseClass::Paint();
+ vgui::surface()->DrawSetColor(0,0,0,255);
+ DrawCube();
+ vgui::surface()->DrawSetColor(255,255,255,255);
+
+ //first draw the cube once.
+ DrawCube( SlideValues->Near->GetSliderValue()*-1,
+ SlideValues->Right->GetSliderValue()*-1,
+ SlideValues->Up->GetSliderValue()*-1,
+ SlideValues->Far->GetSliderValue(),
+ SlideValues->Left->GetSliderValue(),
+ SlideValues->Down->GetSliderValue());
+ //then check if we have something selected
+ if(m_iMouseOver!=-1)
+ {
+ vgui::surface()->DrawSetColor(255,0,0,255);
+ // if we do, draw a special cube.
+ DrawCube( SlideValues->Near->GetSliderValue()*-1,
+ SlideValues->Right->GetSliderValue()*-1,
+ SlideValues->Up->GetSliderValue()*-1,
+ SlideValues->Far->GetSliderValue(),
+ SlideValues->Left->GetSliderValue(),
+ SlideValues->Down->GetSliderValue(),
+ m_iMouseOver);
+
+
+ }
+}
+
+void ControlBoxVisual::DrawCube(float n, float r, float u, float f, float l, float d, int specialside)
+{
+
+
+ l*=-1;
+ r*=-1;//flip
+
+
+
+ Vector right[4];
+ //right side
+ right[0]= Vector(f,r,d);
+ right[1]= Vector(f,r,u);
+ right[2]= Vector(n,r,u);
+ right[3]= Vector(n,r,d);
+
+ Vector left[4];
+ //left side
+ left[0]= Vector(f,l,d);
+ left[1]= Vector(f,l,u);
+ left[2]= Vector(n,l,u);
+ left[3]= Vector(n,l,d);
+ //yikes, this is kind of alot of typing.
+ switch(specialside)
+ {
+ case HUI_BOX_UP:
+ left[0] = left[1];
+ left[3] = left[2];
+ left[1] =Vector(1,-1,-1);
+ left[2] =Vector(-1,-1,-1);
+ right[0]= right[1];
+ right[3]= right[2];
+ right[1]=Vector(1,1,-1);
+ right[2]=Vector(-1,1,-1);
+ break;
+ case HUI_BOX_DOWN:
+ left[1] = left[0];
+ left[2] = left[3];
+ left[0] =Vector(1,-1,1);
+ left[3] =Vector(-1,-1,1);
+ right[1] = right[0];
+ right[2] = right[3];
+ right[0] =Vector(1,1,1);
+ right[3] =Vector(-1,1,1);
+ break;
+ case HUI_BOX_LEFT:
+ right[0] = left[0];
+ right[1] = left[1];
+ right[2] = left[2];
+ right[3] = left[3];
+ left[0] =Vector(1,-1,1);
+ left[1] =Vector(1,-1,-1);
+ left[2] =Vector(-1,-1,-1);
+ left[3] =Vector(-1,-1,1);
+ break;
+ case HUI_BOX_RIGHT:
+ left[0] = right[0];
+ left[1] = right[1];
+ left[2] = right[2];
+ left[3] = right[3];
+ right[0] =Vector(1,1,1);
+ right[1] =Vector(1,1,-1);
+ right[2] =Vector(-1,1,-1);
+ right[3] =Vector(-1,1,1);
+ break;
+ case HUI_BOX_FAR:
+ left[3] = left[0];
+ left[2] = left[1];
+ left[0] =Vector(1,-1,1);
+ left[1] =Vector(1,-1,-1);
+ right[3] = right[0];
+ right[2] = right[1];
+ right[0] =Vector(1,1,1);
+ right[1] =Vector(1,1,-1);
+ break;
+ case HUI_BOX_NEAR:
+ left[0] = left[3];
+ left[1] = left[2];
+ left[3] =Vector(-1,-1,1);
+ left[2] =Vector(-1,-1,-1);
+ right[0] = right[3];
+ right[1] = right[2];
+ right[3] =Vector(-1,1,1);
+ right[2] =Vector(-1,1,-1);
+ break;
+ default:
+ break;
+ }
+
+ Vector pos = Vector(0,0.25 + sin(m_flTime),0.5);
+ VMatrix Project = SetupMatrixProjection(pos,VPlane(Vector(1,0,0),-3));
+ Vector vdrawsize = Vector(1,(float)GetWide()/10.0f,(float)GetTall()/10.0f);
+ for(int i=0;i!=4;i++)
+ {
+ right[i] = Project.VMul3x3(right[i])*vdrawsize;
+ left[i] = Project.VMul3x3(left[i])*vdrawsize;
+ }
+ vdrawsize *=5;
+ for(int i = 0;i!=4;i++)
+ {
+ int next = i+1;
+ if(next>3)
+ next = 0;
+ vgui::surface()->DrawLine(vdrawsize.y+left[i].y,vdrawsize.z+left[i].z,vdrawsize.y+left[next].y,vdrawsize.z+left[next].z);
+ vgui::surface()->DrawLine(vdrawsize.y+right[i].y,vdrawsize.z+right[i].z,vdrawsize.y+right[next].y,vdrawsize.z+right[next].z);
+ vgui::surface()->DrawLine(vdrawsize.y+left[i].y,vdrawsize.z+left[i].z,vdrawsize.y+right[i].y,vdrawsize.z+right[i].z);
+ }
+} \ No newline at end of file
diff --git a/gameui/HapticControlBox.h b/gameui/HapticControlBox.h
new file mode 100644
index 0000000..37073a9
--- /dev/null
+++ b/gameui/HapticControlBox.h
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+#ifndef HAPTICCONTROLBOX_H
+#define HAPTICCONTROLBOX_H
+
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Panel.h>
+#include "cvarslider.h"
+class ControlBoxVisual : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE(ControlBoxVisual,vgui::Panel);
+public:
+ ControlBoxVisual(vgui::Panel *parent, const char *panelName, CCvarSlider *near, CCvarSlider *right, CCvarSlider *up, CCvarSlider *far, CCvarSlider *left, CCvarSlider *down);
+ virtual void Paint();
+ MESSAGE_FUNC_PARAMS(OnSlideEnter, "CursorEnteredSlider", data);
+ MESSAGE_FUNC_PARAMS(OnSlideExit, "CursorExitedSlider", data);
+protected:
+ void DrawCube(float Near=-1, float Right=-1, float Up=-1, float Far=1, float Left=1, float Down=1, int specialside=-1);
+ enum eBoxID
+ {
+ HUI_BOX_UP =0,
+ HUI_BOX_RIGHT,
+ HUI_BOX_NEAR,
+ HUI_BOX_DOWN,
+ HUI_BOX_LEFT,
+ HUI_BOX_FAR,
+ HUI_BOX_SLIDERCOUNT,
+ };
+
+ struct CCvarSliderCube
+ {
+ CCvarSliderCube(CCvarSlider *n,CCvarSlider *r,CCvarSlider *u,CCvarSlider *f,CCvarSlider *l,CCvarSlider *d)
+ {
+ Near = n;
+ Right = r;
+ Up = u;
+ Far = f;
+ Left = l;
+ Down = d;
+ };
+ CCvarSlider *Near;
+ CCvarSlider *Right;
+ CCvarSlider *Up;
+ CCvarSlider *Far;
+ CCvarSlider *Left;
+ CCvarSlider *Down;
+ };
+
+ CCvarSliderCube *SlideValues;// up right near down left far and spingk
+ int m_iMouseOver;
+ float m_flTime;
+};
+
+#endif \ No newline at end of file
diff --git a/gameui/KeyToggleCheckButton.cpp b/gameui/KeyToggleCheckButton.cpp
new file mode 100644
index 0000000..de13117
--- /dev/null
+++ b/gameui/KeyToggleCheckButton.cpp
@@ -0,0 +1,118 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "KeyToggleCheckButton.h"
+#include "EngineInterface.h"
+#include <vgui/IVGui.h>
+#include "IGameUIFuncs.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+CKeyToggleCheckButton::CKeyToggleCheckButton( Panel *parent, const char *panelName, const char *text,
+ char const *key, char const *cmdname )
+ : CheckButton( parent, panelName, text )
+{
+ m_pszKeyName = key ? strdup( key ) : NULL;
+ m_pszCmdName = cmdname ? strdup( cmdname ) : NULL;
+
+ if (m_pszKeyName)
+ {
+ Reset();
+ }
+ //m_bNoCommand = false;
+}
+
+CKeyToggleCheckButton::~CKeyToggleCheckButton()
+{
+ free( m_pszKeyName );
+ free( m_pszCmdName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyToggleCheckButton::Paint()
+{
+ BaseClass::Paint();
+
+ if ( !m_pszKeyName )
+ return;
+
+ // Fixme, look up key state
+ bool isdown;
+ if ( gameuifuncs->IsKeyDown( m_pszKeyName, isdown ) )
+ {
+ // if someone changed the value using the consoel
+ if ( m_bStartValue != isdown )
+ {
+ SetSelected( isdown );
+ m_bStartValue = isdown;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *panel -
+//-----------------------------------------------------------------------------
+/*
+void CKeyToggleCheckButton::SetSelected( bool state )
+{
+ BaseClass::SetSelected( state );
+
+ if ( !m_pszCmdName || !m_pszCmdName[ 0 ] )
+ return;
+
+ if ( m_bNoCommand )
+ return;
+
+ char szCommand[ 256 ];
+
+ Q_snprintf( szCommand, sizeof( szCommand ), "%c%s\n", IsSelected() ? '+' : '-',
+ m_pszCmdName );
+
+ engine->pfnClientCmd( szCommand );
+}*/
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyToggleCheckButton::Reset()
+{
+ gameuifuncs->IsKeyDown( m_pszKeyName, m_bStartValue );
+ if ( IsSelected() != m_bStartValue)
+ {
+ SetSelected( m_bStartValue );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CKeyToggleCheckButton::ApplyChanges()
+{
+ if ( !m_pszCmdName || !m_pszCmdName[ 0 ] )
+ return;
+
+ char szCommand[ 256 ];
+
+ Q_snprintf( szCommand, sizeof( szCommand ), "%c%s\n", IsSelected() ? '+' : '-',
+ m_pszCmdName );
+
+ engine->ClientCmd_Unrestricted( szCommand );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CKeyToggleCheckButton::HasBeenModified()
+{
+ return IsSelected() != m_bStartValue;
+} \ No newline at end of file
diff --git a/gameui/KeyToggleCheckButton.h b/gameui/KeyToggleCheckButton.h
new file mode 100644
index 0000000..0160df9
--- /dev/null
+++ b/gameui/KeyToggleCheckButton.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef KEYTOGGLECHECKBUTTON_H
+#define KEYTOGGLECHECKBUTTON_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/CheckButton.h>
+
+class CKeyToggleCheckButton : public vgui::CheckButton
+{
+public:
+ CKeyToggleCheckButton( vgui::Panel *parent, const char *panelName, const char *text,
+ char const *keyname, char const *cmdname );
+ ~CKeyToggleCheckButton();
+
+ //virtual void SetSelected( bool state );
+ virtual void Paint();
+
+ void Reset();
+ void ApplyChanges();
+ bool HasBeenModified();
+
+private:
+ typedef vgui::CheckButton BaseClass;
+
+ char *m_pszKeyName;
+ char *m_pszCmdName;
+
+ bool m_bStartValue;
+};
+#endif // KEYTOGGLECHECKBUTTON_H
diff --git a/gameui/LabeledCommandComboBox.cpp b/gameui/LabeledCommandComboBox.cpp
new file mode 100644
index 0000000..020f6be
--- /dev/null
+++ b/gameui/LabeledCommandComboBox.cpp
@@ -0,0 +1,131 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "LabeledCommandComboBox.h"
+#include "EngineInterface.h"
+#include <KeyValues.h>
+#include <vgui/ILocalize.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+CLabeledCommandComboBox::CLabeledCommandComboBox( vgui::Panel *parent, const char *panelName ) : vgui::ComboBox( parent, panelName, 6, false )
+{
+ AddActionSignalTarget(this);
+ m_iCurrentSelection = -1;
+ m_iStartSelection = -1;
+}
+
+CLabeledCommandComboBox::~CLabeledCommandComboBox( void )
+{
+}
+
+void CLabeledCommandComboBox::DeleteAllItems()
+{
+ BaseClass::DeleteAllItems();
+ m_Items.RemoveAll();
+}
+
+void CLabeledCommandComboBox::AddItem( char const *text, char const *engineCommand )
+{
+ int idx = m_Items.AddToTail();
+ COMMANDITEM *item = &m_Items[ idx ];
+
+ item->comboBoxID = BaseClass::AddItem( text, NULL );
+
+ Q_strncpy( item->name, text, sizeof( item->name ) );
+
+ if (text[0] == '#')
+ {
+ // need to localize the string
+ wchar_t *localized = g_pVGuiLocalize->Find(text);
+ if (localized)
+ {
+ g_pVGuiLocalize->ConvertUnicodeToANSI(localized, item->name, sizeof(item->name));
+ }
+ }
+
+ Q_strncpy( item->command, engineCommand, sizeof( item->command ) );
+}
+
+void CLabeledCommandComboBox::ActivateItem(int index)
+{
+ if ( index< m_Items.Count() )
+ {
+ int comboBoxID = m_Items[index].comboBoxID;
+ BaseClass::ActivateItem(comboBoxID);
+ m_iCurrentSelection = index;
+ }
+}
+
+void CLabeledCommandComboBox::SetInitialItem(int index)
+{
+ if ( index< m_Items.Count() )
+ {
+ m_iStartSelection = index;
+ int comboBoxID = m_Items[index].comboBoxID;
+ ActivateItem(comboBoxID);
+ }
+}
+
+void CLabeledCommandComboBox::OnTextChanged( char const *text )
+{
+ int i;
+ for ( i = 0; i < m_Items.Size(); i++ )
+ {
+ COMMANDITEM *item = &m_Items[ i ];
+ if ( !stricmp( item->name, text ) )
+ {
+ // engine->pfnClientCmd( item->command );
+ m_iCurrentSelection = i;
+ break;
+ }
+ }
+
+ if (HasBeenModified())
+ {
+ PostActionSignal(new KeyValues("ControlModified"));
+ }
+// PostMessage( GetParent()->GetVPanel(), new vgui::KeyValues( "TextChanged", "text", text ) );
+}
+
+const char *CLabeledCommandComboBox::GetActiveItemCommand()
+{
+ if (m_iCurrentSelection == -1)
+ return NULL;
+
+ COMMANDITEM *item = &m_Items[ m_iCurrentSelection ];
+ return item->command;
+}
+
+void CLabeledCommandComboBox::ApplyChanges()
+{
+ if (m_iCurrentSelection == -1)
+ return;
+ if (m_Items.Size() < 1)
+ return;
+
+ Assert( m_iCurrentSelection < m_Items.Size() );
+ COMMANDITEM *item = &m_Items[ m_iCurrentSelection ];
+ engine->ClientCmd_Unrestricted( item->command );
+ m_iStartSelection = m_iCurrentSelection;
+}
+
+bool CLabeledCommandComboBox::HasBeenModified()
+{
+ return m_iStartSelection != m_iCurrentSelection;
+}
+
+void CLabeledCommandComboBox::Reset()
+{
+ if (m_iStartSelection != -1)
+ {
+ ActivateItem(m_iStartSelection);
+ }
+}
diff --git a/gameui/LabeledCommandComboBox.h b/gameui/LabeledCommandComboBox.h
new file mode 100644
index 0000000..104ce2e
--- /dev/null
+++ b/gameui/LabeledCommandComboBox.h
@@ -0,0 +1,59 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef LABELEDCOMMANDCOMBOBOX_H
+#define LABELEDCOMMANDCOMBOBOX_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Panel.h>
+#include "utlvector.h"
+
+class CLabeledCommandComboBox : public vgui::ComboBox
+{
+ DECLARE_CLASS_SIMPLE( CLabeledCommandComboBox, vgui::ComboBox );
+
+public:
+ CLabeledCommandComboBox(vgui::Panel *parent, const char *panelName);
+ ~CLabeledCommandComboBox();
+
+ virtual void DeleteAllItems();
+ virtual void AddItem(char const *text, char const *engineCommand);
+ virtual void ActivateItem(int itemIndex);
+ const char *GetActiveItemCommand();
+
+ void SetInitialItem(int itemIndex);
+
+ void ApplyChanges();
+ void Reset();
+ bool HasBeenModified();
+
+ enum
+ {
+ MAX_NAME_LEN = 256,
+ MAX_COMMAND_LEN = 256
+ };
+
+private:
+ MESSAGE_FUNC_CHARPTR( OnTextChanged, "TextChanged", text );
+
+ struct COMMANDITEM
+ {
+ char name[ MAX_NAME_LEN ];
+ char command[ MAX_COMMAND_LEN ];
+ int comboBoxID;
+ };
+
+ CUtlVector< COMMANDITEM > m_Items;
+ int m_iCurrentSelection;
+ int m_iStartSelection;
+};
+
+#endif // LABELEDCOMMANDCOMBOBOX_H
diff --git a/gameui/LoadCommentaryDialog.cpp b/gameui/LoadCommentaryDialog.cpp
new file mode 100644
index 0000000..1c70b11
--- /dev/null
+++ b/gameui/LoadCommentaryDialog.cpp
@@ -0,0 +1,411 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#include "LoadCommentaryDialog.h"
+#include "EngineInterface.h"
+#include "IGameUIFuncs.h"
+
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include "filesystem.h"
+
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/QueryBox.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "BasePanel.h"
+
+#include "GameUI_Interface.h"
+
+#include "MouseMessageForwardingPanel.h"
+#include "TGAImagePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+void OpenLoadCommentaryDialog( void )
+{
+ DHANDLE<CLoadCommentaryDialog> hCommentaryDialog;
+ if ( !hCommentaryDialog.Get() )
+ {
+ hCommentaryDialog = new CLoadCommentaryDialog( BasePanel() );
+ }
+
+ GameUI().ActivateGameUI();
+ hCommentaryDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CC_LoadCommentary_Test( void )
+{
+ OpenLoadCommentaryDialog();
+}
+static ConCommand commentary_testfirstrun("loadcommentary", CC_LoadCommentary_Test, 0 );
+
+//-----------------------------------------------------------------------------
+// Purpose: Describes the layout of a commentary map list item
+//-----------------------------------------------------------------------------
+class CCommentaryItemPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CCommentaryItemPanel, vgui::EditablePanel );
+public:
+ CCommentaryItemPanel( PanelListPanel *parent, const char *name, int iListItemID ) : BaseClass( parent, name )
+ {
+ m_iListItemID = iListItemID;
+ m_pParent = parent;
+ m_pCommentaryScreenshot = new CTGAImagePanel( this, "CommentaryMapScreenshot" );
+ m_pCommentaryScreenshotBackground = new ImagePanel( this, "CommentaryScreenshotBackground" );
+
+ // map name
+ m_pMapNameLabel = new Label( this, "MapName", "" );
+
+ // description
+ m_pDescriptionLabel = new Label( this, "Description", "" );
+
+ CMouseMessageForwardingPanel *panel = new CMouseMessageForwardingPanel(this, NULL);
+ panel->SetZPos(2);
+
+ SetSize( 200, 140 );
+
+ LoadControlSettings( "resource/CommentaryItem.res" );
+
+ m_FillColor = m_pCommentaryScreenshotBackground->GetFillColor();
+ }
+
+ void SetCommentaryInfo( CommentaryItem_t &item )
+ {
+ // set the bitmap to display
+ char tga[_MAX_PATH];
+ Q_strncpy( tga, item.szMapFileName, sizeof(tga) );
+ char *ext = strstr( tga, ".txt" );
+ if ( ext )
+ {
+ strcpy( ext, ".tga" );
+ }
+ m_pCommentaryScreenshot->SetTGA( tga );
+
+ // set the title text
+ m_pMapNameLabel->SetText( item.szPrintName );
+ m_pDescriptionLabel->SetText( item.szDescription );
+ }
+
+ MESSAGE_FUNC_INT( OnPanelSelected, "PanelSelected", state )
+ {
+ if ( state )
+ {
+ // set the text color to be orange, and the pic border to be orange
+ m_pCommentaryScreenshotBackground->SetFillColor( m_SelectedColor );
+ m_pMapNameLabel->SetFgColor( m_SelectedColor );
+ m_pDescriptionLabel->SetFgColor( m_SelectedColor );
+ }
+ else
+ {
+ m_pCommentaryScreenshotBackground->SetFillColor( m_FillColor );
+ m_pMapNameLabel->SetFgColor( m_TextColor );
+ m_pDescriptionLabel->SetFgColor( m_TextColor );
+ }
+
+ PostMessage( m_pParent->GetVParent(), new KeyValues("PanelSelected") );
+ }
+
+ virtual void OnMousePressed( vgui::MouseCode code )
+ {
+ m_pParent->SetSelectedPanel( this );
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
+ m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+ }
+
+ virtual void OnMouseDoublePressed( vgui::MouseCode code )
+ {
+ // call the panel
+ OnMousePressed( code );
+ PostMessage( m_pParent->GetParent(), new KeyValues("Command", "command", "loadcommentary") );
+ }
+
+ int GetListItemID()
+ {
+ return m_iListItemID;
+ }
+
+private:
+ vgui::PanelListPanel *m_pParent;
+
+ vgui::Label *m_pMapNameLabel;
+ vgui::Label *m_pDescriptionLabel;
+ CTGAImagePanel *m_pCommentaryScreenshot;
+ ImagePanel *m_pCommentaryScreenshotBackground;
+
+ Color m_TextColor, m_FillColor, m_SelectedColor;
+
+ int m_iListItemID;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:Constructor
+//-----------------------------------------------------------------------------
+CLoadCommentaryDialog::CLoadCommentaryDialog(vgui::Panel *parent) : BaseClass(parent, "LoadCommentaryDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 512, 384);
+ SetMinimumSize( 256, 300 );
+ SetSizeable( true );
+
+ SetTitle("#GameUI_LoadCommentary", true);
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ CreateCommentaryItemList();
+
+ new vgui::Button( this, "loadcommentary", "" );
+ SetControlEnabled( "loadcommentary", false );
+
+ LoadControlSettings("resource/LoadCommentaryDialog.res");
+
+ // Look for commentary .txt files in the map directory
+ ScanCommentaryFiles();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::OnCommand( const char *command )
+{
+ if ( !Q_stricmp( command, "loadcommentary" ) )
+ {
+ int itemIndex = GetSelectedItemIndex();
+ if ( m_CommentaryItems.IsValidIndex(itemIndex) )
+ {
+ const char *mapName = m_CommentaryItems[itemIndex].szMapName;
+ if ( mapName && mapName[ 0 ] )
+ {
+ // Load the game, return to top and switch to engine
+ char sz[ 256 ];
+ Q_snprintf(sz, sizeof( sz ), "progress_enable\ncommentary 1\nmap %s\n", mapName );
+
+ // Close this dialog
+ OnClose();
+
+ engine->ClientCmd_Unrestricted( sz );
+ }
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+void CLoadCommentaryDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ OnCommand( "loadcommentary" );
+ return;
+ }
+ else if ( code == KEY_XBUTTON_B )
+ {
+ OnCommand( "Close" );
+ return;
+ }
+
+ BaseClass::OnKeyCodePressed(code);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates the load game display list
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::CreateCommentaryItemList()
+{
+ m_pGameList = new vgui::PanelListPanel( this, "listpanel_commentary" );
+ m_pGameList->SetFirstColumnWidth( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the save file name of the selected item
+//-----------------------------------------------------------------------------
+int CLoadCommentaryDialog::GetSelectedItemIndex()
+{
+ CCommentaryItemPanel *panel = dynamic_cast<CCommentaryItemPanel *>(m_pGameList->GetSelectedPanel());
+ if ( panel )
+ {
+ // find the panel in the list
+ for ( int i = 0; i < m_CommentaryItems.Count(); i++ )
+ {
+ if ( i == panel->GetListItemID() )
+ {
+ return i;
+ }
+ }
+ }
+ return m_CommentaryItems.InvalidIndex();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: builds save game list from directory
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::ScanCommentaryFiles()
+{
+ // populate list box with all saved games on record:
+ char szDirectory[_MAX_PATH];
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "maps/*commentary.txt" );
+
+ // clear the current list
+ m_pGameList->DeleteAllItems();
+ m_CommentaryItems.RemoveAll();
+
+ // iterate the files
+ FileFindHandle_t handle;
+ const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle );
+ while (pFileName)
+ {
+ char szFileName[_MAX_PATH];
+ Q_snprintf(szFileName, sizeof( szFileName ), "maps/%s", pFileName);
+
+ // Only load save games from the current mod's save dir
+ if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ ParseCommentaryFile( szFileName, pFileName );
+
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ }
+
+ g_pFullFileSystem->FindClose( handle );
+
+ // sort the save list
+ qsort( m_CommentaryItems.Base(), m_CommentaryItems.Count(), sizeof(CommentaryItem_t), &SaveGameSortFunc );
+
+ // add to the list
+ for ( int saveIndex = 0; saveIndex < m_CommentaryItems.Count() && saveIndex < MAX_LISTED_COMMENTARY_ITEMS; saveIndex++ )
+ {
+ // add the item to the panel
+ AddCommentaryItemToList( saveIndex );
+ }
+
+ // display a message if there are no save games
+ if ( !m_CommentaryItems.Count() )
+ {
+ vgui::Label *pNoCommentaryItemsLabel = SETUP_PANEL(new Label(m_pGameList, "NoCommentaryItemsLabel", "#GameUI_NoCommentaryItemsToDisplay"));
+ pNoCommentaryItemsLabel->SetTextColorState(vgui::Label::CS_DULL);
+ m_pGameList->AddItem( NULL, pNoCommentaryItemsLabel );
+ }
+
+ SetControlEnabled( "loadcommentary", false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Adds an item to the list
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::AddCommentaryItemToList( int itemIndex )
+{
+ // create the new panel and add to the list
+ CCommentaryItemPanel *commentaryItemPanel = new CCommentaryItemPanel( m_pGameList, "CommentaryItemPanel", itemIndex );
+ commentaryItemPanel->SetCommentaryInfo( m_CommentaryItems[itemIndex] );
+ m_pGameList->AddItem( NULL, commentaryItemPanel );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses the save game info out of the .sav file header
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::ParseCommentaryFile( char const *pszFileName, char const *pszShortName )
+{
+ if ( !pszFileName || !pszShortName )
+ return;
+
+ // load the file as keyvalues
+ KeyValues *pData = new KeyValues( "commentary_data" );
+
+ if ( false == pData->LoadFromFile( g_pFullFileSystem, pszFileName, "MOD" ) )
+ {
+ pData->deleteThis();
+ return;
+ }
+
+ // walk the platform menu loading all the interfaces
+ KeyValues *menuKeys = pData->FindKey("trackinfo", false);
+ if ( menuKeys )
+ {
+ for (KeyValues *track = menuKeys->GetFirstSubKey(); track != NULL; track = track->GetNextKey())
+ {
+ //Msg( "track found: %s %s\n", track->GetString("map", "?"), track->GetString( "description", "asdf" ) );
+
+ CommentaryItem_t item;
+ Q_strncpy( item.szMapFileName, pszFileName, sizeof(item.szMapFileName) );
+ Q_strncpy( item.szMapName, track->GetString( "map", "" ), sizeof(item.szMapName) );
+ Q_strncpy( item.szPrintName, track->GetString( "printname", "" ), sizeof(item.szPrintName) );
+ Q_strncpy( item.szDescription, track->GetString( "description", "" ), sizeof(item.szDescription) );
+
+ //item.iChannel = track->GetInt( "channel" );
+
+ m_CommentaryItems.AddToTail( item );
+ }
+ }
+ else
+ {
+ CommentaryItem_t item;
+ Q_strncpy( item.szMapFileName, pszFileName, sizeof(item.szMapFileName) );
+
+ char mapname[_MAX_PATH];
+ Q_strncpy( mapname, pszFileName, sizeof(item.szMapName) );
+ char *ext = strstr( mapname, "_commentary" );
+ if ( !ext )
+ return;
+
+ *ext = '\0';
+ Q_FileBase( mapname, item.szMapName, sizeof(item.szMapName) );
+
+ Q_strncpy( item.szPrintName, "No trackinfo found.", sizeof(item.szPrintName) );
+ Q_strncpy( item.szDescription, "No trackinfo found.", sizeof(item.szDescription) );
+ m_CommentaryItems.AddToTail( item );
+ }
+
+ return;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: timestamp sort function for savegames
+//-----------------------------------------------------------------------------
+int CLoadCommentaryDialog::SaveGameSortFunc( const void *lhs, const void *rhs )
+{
+ // Sort by map name
+ const CommentaryItem_t *s1 = (const CommentaryItem_t *)lhs;
+ const CommentaryItem_t *s2 = (const CommentaryItem_t *)rhs;
+
+ return Q_stricmp( s1->szPrintName, s2->szPrintName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: One item has been selected
+//-----------------------------------------------------------------------------
+void CLoadCommentaryDialog::OnPanelSelected()
+{
+ SetControlEnabled( "loadcommentary", true );
+}
diff --git a/gameui/LoadCommentaryDialog.h b/gameui/LoadCommentaryDialog.h
new file mode 100644
index 0000000..aa728b6
--- /dev/null
+++ b/gameui/LoadCommentaryDialog.h
@@ -0,0 +1,63 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef LOADCOMMENTARYDIALOG_H
+#define LOADCOMMENTARYDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "filesystem.h"
+#include "utlvector.h"
+
+
+#define COMMENTARY_MAPFILENAME_MAX_LEN MAX_PATH
+#define COMMENTARY_MAPNAME_MAX_LEN 32
+#define COMMENTARY_DESCRIP_MAX_LEN 512
+#define MAX_LISTED_COMMENTARY_ITEMS 32
+
+struct CommentaryItem_t
+{
+ char szMapFileName[COMMENTARY_MAPFILENAME_MAX_LEN]; // file location of the map
+ char szMapName[COMMENTARY_MAPNAME_MAX_LEN]; // clean name of the map, eg "dod_kalt"
+ char szPrintName[COMMENTARY_MAPNAME_MAX_LEN]; // printable name "Kalt"
+ char szDescription[COMMENTARY_DESCRIP_MAX_LEN]; // track description "This map is fun, and people like it!"
+
+ //int iChannel; // TODO: multiple channels within a single map, loaded into separate commentary tracks
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Base class for save & load game dialogs
+//-----------------------------------------------------------------------------
+class CLoadCommentaryDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CLoadCommentaryDialog, vgui::Frame );
+
+public:
+ CLoadCommentaryDialog( vgui::Panel *parent );
+
+protected:
+ CUtlVector<CommentaryItem_t> m_CommentaryItems;
+ vgui::PanelListPanel *m_pGameList;
+
+ virtual void OnCommand( const char *command );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+ void ScanCommentaryFiles();
+ void CreateCommentaryItemList();
+ int GetSelectedItemIndex();
+ void AddCommentaryItemToList( int saveIndex );
+
+ void ParseCommentaryFile( char const *pszFileName, char const *pszShortName );
+ static int __cdecl SaveGameSortFunc( const void *lhs, const void *rhs );
+
+private:
+ MESSAGE_FUNC( OnPanelSelected, "PanelSelected" );
+};
+
+
+#endif // LOADCOMMENTARYDIALOG_H
diff --git a/gameui/LoadGameDialog.cpp b/gameui/LoadGameDialog.cpp
new file mode 100644
index 0000000..0b54cb8
--- /dev/null
+++ b/gameui/LoadGameDialog.cpp
@@ -0,0 +1,107 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "LoadGameDialog.h"
+#include "EngineInterface.h"
+
+#include "vgui/ISystem.h"
+#include "vgui/ISurface.h"
+#include "vgui/IVGui.h"
+#include "KeyValues.h"
+#include "filesystem.h"
+
+#include "vgui_controls/Button.h"
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/QueryBox.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose:Constructor
+//-----------------------------------------------------------------------------
+CLoadGameDialog::CLoadGameDialog(vgui::Panel *parent) : BaseClass(parent, "LoadGameDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 512, 384);
+ SetMinimumSize( 256, 300 );
+ SetSizeable( true );
+
+ SetTitle("#GameUI_LoadGame", true);
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ LoadControlSettings("resource/LoadGameDialog.res");
+
+ SetControlEnabled( "delete", false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CLoadGameDialog::~CLoadGameDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadGameDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "loadsave" ) )
+ {
+ int saveIndex = GetSelectedItemSaveIndex();
+ if ( m_SaveGames.IsValidIndex(saveIndex) )
+ {
+ const char *shortName = m_SaveGames[saveIndex].szShortName;
+ if ( shortName && shortName[ 0 ] )
+ {
+ // Load the game, return to top and switch to engine
+ char sz[ 256 ];
+ Q_snprintf(sz, sizeof( sz ), "progress_enable\nload %s\n", shortName );
+
+ engine->ClientCmd_Unrestricted( sz );
+
+ // Close this dialog
+ OnClose();
+ }
+ }
+ }
+ else if ( !stricmp( command, "Delete" ) )
+ {
+ int saveIndex = GetSelectedItemSaveIndex();
+ if ( m_SaveGames.IsValidIndex(saveIndex) )
+ {
+ // confirm the deletion
+ QueryBox *box = new QueryBox( "#GameUI_ConfirmDeleteSaveGame_Title", "#GameUI_ConfirmDeleteSaveGame_Info" );
+ box->AddActionSignalTarget(this);
+ box->SetOKButtonText("#GameUI_ConfirmDeleteSaveGame_OK");
+ box->SetOKCommand(new KeyValues("Command", "command", "DeleteConfirmed"));
+ box->DoModal();
+ }
+ }
+ else if ( !stricmp( command, "DeleteConfirmed" ) )
+ {
+ int saveIndex = GetSelectedItemSaveIndex();
+ if ( m_SaveGames.IsValidIndex(saveIndex) )
+ {
+ DeleteSaveGame( m_SaveGames[saveIndex].szFileName );
+
+ // reset the list
+ ScanSavedGames();
+ m_pGameList->MoveScrollBarToTop();
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
diff --git a/gameui/LoadGameDialog.h b/gameui/LoadGameDialog.h
new file mode 100644
index 0000000..4e8de64
--- /dev/null
+++ b/gameui/LoadGameDialog.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef LOADGAMEDIALOG_H
+#define LOADGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "BaseSaveGameDialog.h"
+#include "SaveGameDialog.h"
+#include "SaveGameBrowserDialog.h"
+#include "BasePanel.h"
+#include "vgui_controls/KeyRepeat.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays game loading options
+//-----------------------------------------------------------------------------
+class CLoadGameDialog : public CBaseSaveGameDialog
+{
+ DECLARE_CLASS_SIMPLE( CLoadGameDialog, CBaseSaveGameDialog );
+
+public:
+ CLoadGameDialog(vgui::Panel *parent);
+ ~CLoadGameDialog();
+
+ virtual void OnCommand( const char *command );
+};
+
+//
+//
+//
+
+class CLoadGameDialogXbox : public CSaveGameBrowserDialog
+{
+ DECLARE_CLASS_SIMPLE( CLoadGameDialogXbox, CSaveGameBrowserDialog );
+
+public:
+ CLoadGameDialogXbox( vgui::Panel *parent );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand(const char *command);
+ virtual void PerformSelectedAction( void );
+ virtual void PerformDeletion( void );
+ virtual void UpdateFooterOptions( void );
+
+private:
+ void DeleteSaveGame( const SaveGameDescription_t *pSaveDesc );
+};
+
+#endif // LOADGAMEDIALOG_H
diff --git a/gameui/LoadGameDialog_Xbox.cpp b/gameui/LoadGameDialog_Xbox.cpp
new file mode 100644
index 0000000..742a0ea
--- /dev/null
+++ b/gameui/LoadGameDialog_Xbox.cpp
@@ -0,0 +1,219 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "LoadGameDialog.h"
+
+#include "winlite.h"
+#include "vgui/ISurface.h"
+
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "ixboxsystem.h"
+#include "filesystem.h"
+
+#include "SaveGameBrowserDialog.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+CLoadGameDialogXbox::CLoadGameDialogXbox( vgui::Panel *parent ) : BaseClass( parent )
+{
+ m_bFilterAutosaves = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ vgui::Label *pTitle = (Label *) FindChildByName( "TitleLabel" );
+ if ( pTitle )
+ {
+ pTitle->SetText( "#GameUI_LoadGame" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::PerformSelectedAction( void )
+{
+ BaseClass::PerformSelectedAction();
+
+ if ( !GetNumPanels() )
+ return;
+
+ SetControlDisabled( true );
+
+ // Warn the player if they're already in a map
+ if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ BasePanel()->ShowMessageDialog( MD_SAVE_BEFORE_LOAD, this );
+ }
+ else
+ {
+ // Otherwise just do it
+ OnCommand( "LoadGame" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::PerformDeletion( void )
+{
+ // Cannot delete autosaves!
+ CGameSavePanel *pPanel = GetActivePanel();
+ if ( pPanel == NULL || ( pPanel && pPanel->IsAutoSaveType() ) )
+ return;
+
+ BaseClass::PerformDeletion();
+
+ SetControlDisabled( true );
+
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ BasePanel()->ShowMessageDialog( MD_DELETE_SAVE_CONFIRM, this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bNewSaveSelected -
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::UpdateFooterOptions( void )
+{
+ CFooterPanel *pFooter = GetFooterPanel();
+
+ // Show available buttons
+ pFooter->ClearButtons();
+
+ // Make sure we have panels to show
+ if ( HasActivePanels() )
+ {
+ pFooter->AddNewButtonLabel( "#GameUI_Load", "#GameUI_Icons_A_BUTTON" );
+
+ // Don't allow deletions of autosaves!
+ CGameSavePanel *pPanel = GetActivePanel();
+ if ( pPanel && pPanel->IsAutoSaveType() == false )
+ {
+ pFooter->AddNewButtonLabel( "#GameUI_Delete", "#GameUI_Icons_X_BUTTON" );
+ }
+ }
+
+ // Always allow storage devices changes and cancelling
+ pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ pFooter->AddNewButtonLabel( "#GameUI_Console_StorageChange", "#GameUI_Icons_Y_BUTTON" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::OnCommand( const char *command )
+{
+ m_KeyRepeat.Reset();
+
+ if ( !Q_stricmp( command, "LoadGame" ) )
+ {
+ // Must have an active panel to perform this action
+ if ( GetNumPanels() == 0 )
+ {
+ SetControlDisabled( false );
+ return;
+ }
+
+ const SaveGameDescription_t *pSave = GetActivePanelSaveDescription();
+
+ // Load the saved game
+ char szCmd[ 256 ];
+ Q_snprintf( szCmd, sizeof( szCmd ), "xload %s", pSave->szShortName );
+ engine->ClientCmd_Unrestricted( szCmd );
+
+ // Ignore all other input while we're open
+ OnClose();
+ }
+ else if ( !Q_stricmp( command, "DeleteGame" ) )
+ {
+ // Must have an active panel to perform this action
+ if ( GetNumPanels() == 0 )
+ {
+ SetControlDisabled( false );
+ return;
+ }
+
+ // Delete the game they've selected
+ const SaveGameDescription_t *pSave = GetActivePanelSaveDescription();
+ DeleteSaveGame( pSave );
+ RemoveActivePanel();
+ }
+ else if ( !Q_stricmp( command, "RefreshSaveGames" ) )
+ {
+ // FIXME: At this point the rug has been pulled out from undereath us!
+ RefreshSaveGames();
+ }
+ else if ( !Q_stricmp( command, "LoadGameCancelled" ) )
+ {
+ SetControlDisabled( false );
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( NULL );
+ }
+ else if ( !Q_stricmp( command, "DeleteGameCancelled" ) )
+ {
+ SetControlDisabled( false );
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: deletes an existing save game
+//-----------------------------------------------------------------------------
+void CLoadGameDialogXbox::DeleteSaveGame( const SaveGameDescription_t *pSaveDesc )
+{
+ if ( pSaveDesc == NULL )
+ {
+ SetControlDisabled( false );
+ return;
+ }
+
+ // If we're deleting our more recent save game, we need to make sure we setup the engine to properly load the last most recent
+ if ( Q_stristr( engine->GetMostRecentSaveGame(), pSaveDesc->szShortName ) )
+ {
+ // We must have at least two active save games that we know about
+ if ( GetNumPanels() > 1 )
+ {
+ // The panels are sorted by how recent they are, so the first element is the most recent
+ const SaveGameDescription_t *pDesc = GetPanelSaveDecription( 0 );
+ if ( pDesc == pSaveDesc )
+ {
+ // If we're deleting our most recent, we need to pick the next most recent
+ pDesc = GetPanelSaveDecription( 1 );
+ }
+
+ // Remember this filename for the next time we need to reload
+ if ( pDesc )
+ {
+ engine->SetMostRecentSaveGame( pDesc->szShortName );
+ }
+ }
+ }
+
+ // Delete the save game file
+ g_pFullFileSystem->RemoveFile( pSaveDesc->szFileName, "MOD" );
+
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ // Return control
+ SetControlDisabled( false );
+}
diff --git a/gameui/LoadingDialog.cpp b/gameui/LoadingDialog.cpp
new file mode 100644
index 0000000..b0d6be6
--- /dev/null
+++ b/gameui/LoadingDialog.cpp
@@ -0,0 +1,669 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include "LoadingDialog.h"
+#include "EngineInterface.h"
+#include "IGameUIFuncs.h"
+
+#include <vgui/IInput.h>
+#include <vgui/ISurface.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISystem.h>
+#include <vgui_controls/ProgressBar.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/HTML.h>
+#include <vgui_controls/RichText.h>
+#include "tier0/icommandline.h"
+
+#include "GameUI_Interface.h"
+#include "ModInfo.h"
+#include "BasePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CLoadingDialog::CLoadingDialog( vgui::Panel *parent ) : Frame(parent, "LoadingDialog")
+{
+ SetDeleteSelfOnClose(true);
+
+ // Use console style
+ m_bConsoleStyle = GameUI().IsConsoleUI();
+
+ if ( !m_bConsoleStyle )
+ {
+ SetSize( 416, 100 );
+ SetTitle( "#GameUI_Loading", true );
+ }
+
+ // center the loading dialog, unless we have another dialog to show in the background
+ m_bCenter = !GameUI().HasLoadingBackgroundDialog();
+
+ m_bShowingSecondaryProgress = false;
+ m_flSecondaryProgress = 0.0f;
+ m_flLastSecondaryProgressUpdateTime = 0.0f;
+ m_flSecondaryProgressStartTime = 0.0f;
+
+ m_pProgress = new ProgressBar( this, "Progress" );
+ m_pProgress2 = new ProgressBar( this, "Progress2" );
+ m_pInfoLabel = new Label( this, "InfoLabel", "" );
+ m_pCancelButton = new Button( this, "CancelButton", "#GameUI_Cancel" );
+ m_pTimeRemainingLabel = new Label( this, "TimeRemainingLabel", "" );
+ m_pCancelButton->SetCommand( "Cancel" );
+
+ if ( ModInfo().IsSinglePlayerOnly() == false && m_bConsoleStyle == true )
+ {
+ m_pLoadingBackground = new Panel( this, "LoadingDialogBG" );
+ }
+ else
+ {
+ m_pLoadingBackground = NULL;
+ }
+
+ SetMinimizeButtonVisible( false );
+ SetMaximizeButtonVisible( false );
+ SetCloseButtonVisible( false );
+ SetSizeable( false );
+ SetMoveable( false );
+
+ if ( m_bConsoleStyle )
+ {
+ m_bCenter = false;
+ m_pProgress->SetVisible( false );
+ m_pProgress2->SetVisible( false );
+ m_pInfoLabel->SetVisible( false );
+ m_pCancelButton->SetVisible( false );
+ m_pTimeRemainingLabel->SetVisible( false );
+ m_pCancelButton->SetVisible( false );
+
+ SetMinimumSize( 0, 0 );
+ SetTitleBarVisible( false );
+
+ m_flProgressFraction = 0;
+ }
+ else
+ {
+ m_pInfoLabel->SetBounds(20, 32, 392, 24);
+ m_pProgress->SetBounds(20, 64, 300, 24);
+ m_pCancelButton->SetBounds(330, 64, 72, 24);
+ m_pProgress2->SetVisible(false);
+ }
+
+ SetupControlSettings( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CLoadingDialog::~CLoadingDialog()
+{
+ if ( input()->GetAppModalSurface() == GetVPanel() )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( NULL );
+ }
+}
+
+void CLoadingDialog::PaintBackground()
+{
+ if ( !m_bConsoleStyle )
+ {
+ BaseClass::PaintBackground();
+ return;
+ }
+
+ // draw solid progress bar with curved endcaps
+ int panelWide, panelTall;
+ GetSize( panelWide, panelTall );
+ int barWide, barTall;
+ m_pProgress->GetSize( barWide, barTall );
+ int x = ( panelWide - barWide )/2;
+ int y = panelTall - barTall;
+
+ if ( m_pLoadingBackground )
+ {
+ vgui::HScheme scheme = vgui::scheme()->GetScheme( "ClientScheme" );
+ Color color = GetSchemeColor( "TanDarker", Color(255, 255, 255, 255), vgui::scheme()->GetIScheme(scheme) );
+
+ m_pLoadingBackground->SetFgColor( color );
+ m_pLoadingBackground->SetBgColor( color );
+
+ m_pLoadingBackground->SetPaintBackgroundEnabled( true );
+ }
+
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ DrawBox( x, y, barWide, barTall, Color( 0, 0, 0, 255 ), 1.0f );
+ }
+
+ DrawBox( x+2, y+2, barWide-4, barTall-4, Color( 100, 100, 100, 255 ), 1.0f );
+
+ barWide = m_flProgressFraction * ( barWide - 4 );
+ if ( barWide >= 12 )
+ {
+ // cannot draw a curved box smaller than 12 without artifacts
+ DrawBox( x+2, y+2, barWide, barTall-4, Color( 200, 100, 0, 255 ), 1.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up dialog layout
+//-----------------------------------------------------------------------------
+void CLoadingDialog::SetupControlSettings( bool bForceShowProgressText )
+{
+ m_bShowingVACInfo = false;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ KeyValues *pControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "LoadingDialogNoBanner.res" );
+ LoadControlSettings( "null", NULL, pControlSettings );
+ return;
+ }
+
+ if ( ModInfo().IsSinglePlayerOnly() && !bForceShowProgressText )
+ {
+ LoadControlSettings("Resource/LoadingDialogNoBannerSingle.res");
+ }
+ else if ( gameuifuncs->IsConnectedToVACSecureServer() )
+ {
+ LoadControlSettings("Resource/LoadingDialogVAC.res");
+ m_bShowingVACInfo = true;
+ }
+ else
+ {
+ LoadControlSettings("Resource/LoadingDialogNoBanner.res");
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Activates the loading screen, initializing and making it visible
+//-----------------------------------------------------------------------------
+void CLoadingDialog::Open()
+{
+ if ( !m_bConsoleStyle )
+ {
+ SetTitle( "#GameUI_Loading", true );
+ }
+
+ HideOtherDialogs( true );
+ BaseClass::Activate();
+
+ if ( !m_bConsoleStyle )
+ {
+ m_pProgress->SetVisible( true );
+ if ( !ModInfo().IsSinglePlayerOnly() )
+ {
+ m_pInfoLabel->SetVisible( true );
+ }
+ m_pInfoLabel->SetText("");
+
+ m_pCancelButton->SetText("#GameUI_Cancel");
+ m_pCancelButton->SetCommand("Cancel");
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: error display file
+//-----------------------------------------------------------------------------
+void CLoadingDialog::SetupControlSettingsForErrorDisplay( const char *settingsFile )
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ m_bCenter = true;
+ SetTitle("#GameUI_Disconnected", true);
+ m_pInfoLabel->SetText("");
+ LoadControlSettings( settingsFile );
+ HideOtherDialogs( true );
+
+ BaseClass::Activate();
+
+ m_pProgress->SetVisible(false);
+
+ m_pInfoLabel->SetVisible(true);
+ m_pCancelButton->SetText("#GameUI_Close");
+ m_pCancelButton->SetCommand("Close");
+ m_pInfoLabel->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: shows or hides other top-level dialogs
+//-----------------------------------------------------------------------------
+void CLoadingDialog::HideOtherDialogs( bool bHide )
+{
+ if ( bHide )
+ {
+ if ( GameUI().HasLoadingBackgroundDialog() )
+ {
+ // if we have a loading background dialog, hide any other dialogs by moving the full-screen background dialog to the
+ // front, then moving ourselves in front of it
+ GameUI().ShowLoadingBackgroundDialog();
+ vgui::ipanel()->MoveToFront( GetVPanel() );
+ vgui::input()->SetAppModalSurface( GetVPanel() );
+ }
+ else
+ {
+ // if there is no loading background dialog, use VGUI paint restrictions to hide other dialogs
+ vgui::surface()->RestrictPaintToSinglePanel(GetVPanel());
+ }
+ }
+ else
+ {
+ if ( GameUI().HasLoadingBackgroundDialog() )
+ {
+ GameUI().HideLoadingBackgroundDialog();
+ vgui::input()->SetAppModalSurface( NULL );
+ }
+ else
+ {
+ // remove any rendering restrictions
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Turns dialog into error display
+//-----------------------------------------------------------------------------
+void CLoadingDialog::DisplayGenericError(const char *failureReason, const char *extendedReason)
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ // In certain race conditions, DisplayGenericError can get called AFTER OnClose() has been called.
+ // If that happens and we don't call Activate(), then it'll continue closing when we don't want it to.
+ Activate();
+
+ SetupControlSettingsForErrorDisplay("Resource/LoadingDialogError.res");
+
+ if ( extendedReason && strlen( extendedReason ) > 0 )
+ {
+ wchar_t compositeReason[256], finalMsg[512], formatStr[256];
+ if ( extendedReason[0] == '#' )
+ {
+ wcsncpy(compositeReason, g_pVGuiLocalize->Find(extendedReason), sizeof( compositeReason ) / sizeof( wchar_t ) );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode(extendedReason, compositeReason, sizeof( compositeReason ));
+ }
+
+ if ( failureReason[0] == '#' )
+ {
+ wcsncpy(formatStr, g_pVGuiLocalize->Find(failureReason), sizeof( formatStr ) / sizeof( wchar_t ) );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConvertANSIToUnicode(failureReason, formatStr, sizeof( formatStr ));
+ }
+
+ g_pVGuiLocalize->ConstructString(finalMsg, sizeof( finalMsg ), formatStr, 1, compositeReason);
+ m_pInfoLabel->SetText(finalMsg);
+ }
+ else
+ {
+ m_pInfoLabel->SetText(failureReason);
+ }
+
+ int wide, tall;
+ int x,y;
+ m_pInfoLabel->GetContentSize( wide, tall );
+ m_pInfoLabel->GetPos( x, y );
+ SetTall( tall + y + 50 );
+
+ int buttonX, buttonY;
+ m_pCancelButton->GetPos( buttonX, buttonY );
+ m_pCancelButton->SetPos( buttonX, tall + y + 6 );
+
+ m_pCancelButton->RequestFocus();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: explain to the user they can't join secure servers due to a VAC ban
+//-----------------------------------------------------------------------------
+void CLoadingDialog::DisplayVACBannedError()
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorVACBanned.res");
+ SetTitle("#VAC_ConnectionRefusedTitle", true);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: explain to the user they can't connect to public servers due to
+// not having a valid connection to Steam
+// this should only happen if they are a pirate
+//-----------------------------------------------------------------------------
+void CLoadingDialog::DisplayNoSteamConnectionError()
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorNoSteamConnection.res");
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: explain to the user they got kicked from a server due to that same account
+// logging in from another location. This also triggers the refresh login dialog on OK
+// being pressed.
+//-----------------------------------------------------------------------------
+void CLoadingDialog::DisplayLoggedInElsewhereError()
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ SetupControlSettingsForErrorDisplay("Resource/LoadingDialogErrorLoggedInElsewhere.res");
+ m_pCancelButton->SetText("#GameUI_RefreshLogin_Login");
+ m_pCancelButton->SetCommand("Login");
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: sets status info text
+//-----------------------------------------------------------------------------
+void CLoadingDialog::SetStatusText(const char *statusText)
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ m_pInfoLabel->SetText(statusText);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the previous state
+//-----------------------------------------------------------------------------
+bool CLoadingDialog::SetShowProgressText( bool show )
+{
+ if ( m_bConsoleStyle )
+ {
+ return false;
+ }
+
+ bool bret = m_pInfoLabel->IsVisible();
+ if ( bret != show )
+ {
+ SetupControlSettings( show );
+ m_pInfoLabel->SetVisible( show );
+ }
+ return bret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: updates time remaining
+//-----------------------------------------------------------------------------
+void CLoadingDialog::OnThink()
+{
+ BaseClass::OnThink();
+
+ if ( !m_bConsoleStyle && m_bShowingSecondaryProgress )
+ {
+ // calculate the time remaining string
+ wchar_t unicode[512];
+ if (m_flSecondaryProgress >= 1.0f)
+ {
+ m_pTimeRemainingLabel->SetText("complete");
+ }
+ else if (ProgressBar::ConstructTimeRemainingString(unicode, sizeof(unicode), m_flSecondaryProgressStartTime, (float)system()->GetFrameTime(), m_flSecondaryProgress, m_flLastSecondaryProgressUpdateTime, true))
+ {
+ m_pTimeRemainingLabel->SetText(unicode);
+ }
+ else
+ {
+ m_pTimeRemainingLabel->SetText("");
+ }
+ }
+
+ SetAlpha( 255 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadingDialog::PerformLayout()
+{
+ if ( m_bConsoleStyle )
+ {
+ // place in lower center
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );
+ int wide,tall;
+ GetSize( wide, tall );
+ int x = 0;
+ int y = 0;
+
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ x = ( screenWide - wide ) * 0.50f;
+ y = ( screenTall - tall ) * 0.86f;
+ }
+ else
+ {
+ x = ( screenWide - ( wide * 1.30f ) );
+ y = ( ( screenTall * 0.875f ) );
+ }
+
+ SetPos( x, y );
+ }
+ else if ( m_bCenter )
+ {
+ MoveToCenterOfScreen();
+ }
+ else
+ {
+ // if we're not supposed to be centered, move ourselves to the lower right hand corner of the screen
+ int x, y, screenWide, screenTall;
+ surface()->GetWorkspaceBounds( x, y, screenWide, screenTall );
+ int wide,tall;
+ GetSize( wide, tall );
+
+ if ( IsPC() )
+ {
+ x = screenWide - ( wide + 10 );
+ y = screenTall - ( tall + 10 );
+ }
+ else
+ {
+ // Move farther in so we're title safe
+ x = screenWide - wide - (screenWide * 0.05);
+ y = screenTall - tall - (screenTall * 0.05);
+ }
+
+ x -= m_iAdditionalIndentX;
+ y -= m_iAdditionalIndentY;
+
+ SetPos( x, y );
+ }
+
+ BaseClass::PerformLayout();
+
+ vgui::ipanel()->MoveToFront( GetVPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the number of ticks has changed
+//-----------------------------------------------------------------------------
+bool CLoadingDialog::SetProgressPoint( float fraction )
+{
+ if ( m_bConsoleStyle )
+ {
+ if ( fraction >= 0.99f )
+ {
+ // show the progress artifically completed to fill in 100%
+ fraction = 1.0f;
+ }
+ fraction = clamp( fraction, 0.0f, 1.0f );
+ if ( (int)(fraction * 25) != (int)(m_flProgressFraction * 25) )
+ {
+ m_flProgressFraction = fraction;
+ return true;
+ }
+ return IsX360();
+ }
+
+ if ( !m_bShowingVACInfo && gameuifuncs->IsConnectedToVACSecureServer() )
+ {
+ SetupControlSettings( false );
+ }
+
+ int nOldDrawnSegments = m_pProgress->GetDrawnSegmentCount();
+ m_pProgress->SetProgress( fraction );
+ int nNewDrawSegments = m_pProgress->GetDrawnSegmentCount();
+ return (nOldDrawnSegments != nNewDrawSegments) || IsX360();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets and shows the secondary progress bar
+//-----------------------------------------------------------------------------
+void CLoadingDialog::SetSecondaryProgress( float progress )
+{
+ if ( m_bConsoleStyle )
+ return;
+
+ // don't show the progress if we've jumped right to completion
+ if (!m_bShowingSecondaryProgress && progress > 0.99f)
+ return;
+
+ // if we haven't yet shown secondary progress then reconfigure the dialog
+ if (!m_bShowingSecondaryProgress)
+ {
+ LoadControlSettings("Resource/LoadingDialogDualProgress.res");
+ m_bShowingSecondaryProgress = true;
+ m_pProgress2->SetVisible(true);
+ m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
+ }
+
+ // if progress has increased then update the progress counters
+ if (progress > m_flSecondaryProgress)
+ {
+ m_pProgress2->SetProgress(progress);
+ m_flSecondaryProgress = progress;
+ m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
+ }
+
+ // if progress has decreased then reset progress counters
+ if (progress < m_flSecondaryProgress)
+ {
+ m_pProgress2->SetProgress(progress);
+ m_flSecondaryProgress = progress;
+ m_flLastSecondaryProgressUpdateTime = (float)system()->GetFrameTime();
+ m_flSecondaryProgressStartTime = (float)system()->GetFrameTime();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadingDialog::SetSecondaryProgressText(const char *statusText)
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ SetControlString( "SecondaryProgressLabel", statusText );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLoadingDialog::OnClose()
+{
+ // remove any rendering restrictions
+ HideOtherDialogs( false );
+
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: command handler
+//-----------------------------------------------------------------------------
+void CLoadingDialog::OnCommand(const char *command)
+{
+ if ( !stricmp(command, "Cancel") )
+ {
+ // disconnect from the server
+ engine->ClientCmd_Unrestricted("disconnect\n");
+
+ // close
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+void CLoadingDialog::OnKeyCodeTyped(KeyCode code)
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ if ( code == KEY_ESCAPE )
+ {
+ OnCommand("Cancel");
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Maps ESC to quiting loading
+//-----------------------------------------------------------------------------
+void CLoadingDialog::OnKeyCodePressed(KeyCode code)
+{
+ if ( m_bConsoleStyle )
+ {
+ return;
+ }
+
+ ButtonCode_t nButtonCode = GetBaseButtonCode( code );
+
+ if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A || nButtonCode == STEAMCONTROLLER_B )
+ {
+ OnCommand("Cancel");
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Singleton accessor
+//-----------------------------------------------------------------------------
+extern vgui::DHANDLE<CLoadingDialog> g_hLoadingDialog;
+CLoadingDialog *LoadingDialog()
+{
+ return g_hLoadingDialog.Get();
+}
diff --git a/gameui/LoadingDialog.h b/gameui/LoadingDialog.h
new file mode 100644
index 0000000..e38765c
--- /dev/null
+++ b/gameui/LoadingDialog.h
@@ -0,0 +1,77 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef LOADINGDIALOG_H
+#define LOADINGDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include <vgui_controls/HTML.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Dialog for displaying level loading status
+//-----------------------------------------------------------------------------
+class CLoadingDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CLoadingDialog, vgui::Frame );
+public:
+ CLoadingDialog( vgui::Panel *parent );
+ ~CLoadingDialog();
+
+ void Open();
+ bool SetProgressPoint(float fraction);
+ void SetStatusText(const char *statusText);
+ void SetSecondaryProgress(float progress);
+ void SetSecondaryProgressText(const char *statusText);
+ bool SetShowProgressText( bool show );
+
+ void DisplayGenericError(const char *failureReason, const char *extendedReason = NULL);
+ void DisplayVACBannedError();
+ void DisplayNoSteamConnectionError();
+ void DisplayLoggedInElsewhereError();
+
+protected:
+ virtual void OnCommand(const char *command);
+ virtual void PerformLayout();
+ virtual void OnThink();
+ virtual void OnClose();
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+ virtual void OnKeyCodePressed(vgui::KeyCode code);
+ virtual void PaintBackground( void );
+
+private:
+ void SetupControlSettings( bool bForceShowProgressText );
+ void SetupControlSettingsForErrorDisplay( const char *settingsFile );
+ void HideOtherDialogs( bool bHide );
+
+ vgui::ProgressBar *m_pProgress;
+ vgui::ProgressBar *m_pProgress2;
+ vgui::Label *m_pInfoLabel;
+ vgui::Label *m_pTimeRemainingLabel;
+ vgui::Button *m_pCancelButton;
+ vgui::Panel *m_pLoadingBackground;
+
+ bool m_bShowingSecondaryProgress;
+ float m_flSecondaryProgress;
+ float m_flLastSecondaryProgressUpdateTime;
+ float m_flSecondaryProgressStartTime;
+ bool m_bShowingVACInfo;
+ bool m_bCenter;
+ bool m_bConsoleStyle;
+ float m_flProgressFraction;
+
+ CPanelAnimationVar( int, m_iAdditionalIndentX, "AdditionalIndentX", "0" );
+ CPanelAnimationVar( int, m_iAdditionalIndentY, "AdditionalIndentY", "0" );
+};
+
+// singleton accessor
+CLoadingDialog *LoadingDialog();
+
+
+#endif // LOADINGDIALOG_H
diff --git a/gameui/LogoFile.cpp b/gameui/LogoFile.cpp
new file mode 100644
index 0000000..f1327ab
--- /dev/null
+++ b/gameui/LogoFile.cpp
@@ -0,0 +1,287 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+
+#if !defined( _X360 )
+#include <windows.h>
+#endif
+#include <stdio.h>
+#include "tier1/utlbuffer.h"
+#include <vgui/VGUI.h>
+#include <vgui_controls/Controls.h>
+#include "filesystem.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+#define TYP_LUMPY 64 // 64 + grab command number
+
+typedef struct
+{
+ char identification[4]; // should be WAD2 or 2DAW
+ int numlumps;
+ int infotableofs;
+} wadinfo_t;
+
+typedef struct
+{
+ int filepos;
+ int disksize;
+ int size; // uncompressed
+ char type;
+ char compression;
+ char pad1, pad2;
+ char name[16]; // must be null terminated
+} lumpinfo_t;
+
+typedef struct
+{
+ char name[16];
+ unsigned width, height;
+ unsigned offsets[4]; // four mip maps stored
+} miptex_t;
+
+unsigned char pixdata[256];
+
+float linearpalette[256][3];
+float d_red, d_green, d_blue;
+int colors_used;
+int color_used[256];
+float maxdistortion;
+unsigned char palLogo[768];
+
+/*
+=============
+AveragePixels
+=============
+*/
+unsigned char AveragePixels (int count)
+{
+ return pixdata[0];
+}
+
+/*
+==============
+GrabMip
+
+filename MIP x y width height
+must be multiples of sixteen
+==============
+*/
+int GrabMip ( HANDLE hdib, unsigned char *lump_p, char *lumpname, COLORREF crf, int *width, int *height)
+{
+ int i,x,y,xl,yl,xh,yh,w,h;
+ unsigned char *screen_p, *source;
+ miptex_t *qtex;
+ int miplevel, mipstep;
+ int xx, yy;
+ int count;
+ int byteimagewidth, byteimageheight;
+ unsigned char *byteimage;
+ LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0)
+
+ /* get pointer to BITMAPINFO (Win 3.0) */
+ lpbmi = (LPBITMAPINFO)::GlobalLock((HGLOBAL)hdib);
+ unsigned char *lump_start = lump_p;
+
+ xl = yl = 0;
+ w = lpbmi->bmiHeader.biWidth;
+ h = lpbmi->bmiHeader.biHeight;
+
+ *width = w;
+ *height = h;
+
+ byteimage = (unsigned char *)((LPSTR)lpbmi + sizeof( BITMAPINFOHEADER ) + 256 * sizeof( RGBQUAD ) );
+
+ if ( (w & 15) || (h & 15) )
+ return 0; //Error ("line %i: miptex sizes must be multiples of 16", scriptline);
+
+ xh = xl+w;
+ yh = yl+h;
+
+ qtex = (miptex_t *)lump_p;
+ qtex->width = (unsigned)(w);
+ qtex->height = (unsigned)(h);
+ Q_strncpy (qtex->name, lumpname, sizeof( qtex->name) );
+
+ lump_p = (unsigned char *)&qtex->offsets[4];
+
+ byteimagewidth = w;
+ byteimageheight = h;
+
+ source = (unsigned char *)lump_p;
+ qtex->offsets[0] = (unsigned)((unsigned char *)lump_p - (unsigned char *)qtex);
+
+ // We're reading from a dib, so go bottom up
+ screen_p = byteimage + (h - 1) * w;
+ for (y=yl ; y<yh ; y++)
+ {
+ for (x=xl ; x<xh ; x++)
+ *lump_p++ = *screen_p++;
+
+ screen_p -= 2 * w;
+ }
+
+ // calculate gamma corrected linear palette
+ for (i = 0; i < 256; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ float f = (float)(palLogo[i*3+j] / 255.0);
+ linearpalette[i][j] = f; //pow((double)f, 2); // assume textures are done at 2.2, we want to remap them at 1.0
+ }
+ }
+
+ maxdistortion = 0;
+ // assume palette full if it's a transparent texture
+ colors_used = 256;
+ for (i = 0; i < 256; i++)
+ color_used[i] = 1;
+
+
+ //
+ // subsample for greater mip levels
+ //
+
+ for (miplevel = 1 ; miplevel<4 ; miplevel++)
+ {
+ d_red = d_green = d_blue = 0; // no distortion yet
+ qtex->offsets[miplevel] = (unsigned)(lump_p - (unsigned char *)qtex);
+
+ mipstep = 1<<miplevel;
+
+ for (y=0 ; y<h ; y+=mipstep)
+ {
+ for (x = 0 ; x<w ; x+= mipstep)
+ {
+ count = 0;
+ for (yy=0 ; yy<mipstep ; yy++)
+ {
+ for (xx=0 ; xx<mipstep ; xx++)
+ pixdata[count++] = source[(y+yy)*w + x + xx ];
+ }
+
+ *lump_p++ = AveragePixels (count);
+ }
+ }
+ }
+
+ ::GlobalUnlock(lpbmi);
+
+ // Write out palette in 16bit mode
+ *(unsigned short *) lump_p = 256; // palette size
+ lump_p += sizeof(short);
+
+ memcpy(lump_p, &palLogo[0], 765);
+ lump_p += 765;
+
+ *lump_p++ = (unsigned char)(crf & 0xFF);
+
+ *lump_p++ = (unsigned char)((crf >> 8) & 0xFF);
+
+ *lump_p++ = (unsigned char)((crf >> 16) & 0xFF);
+
+ return lump_p - lump_start;
+}
+
+
+void UpdateLogoWAD( void *phdib, int r, int g, int b )
+{
+ char logoname[ 32 ];
+ char *pszName;
+ Q_strncpy( logoname, "LOGO", sizeof( logoname ) );
+ pszName = &logoname[ 0 ];
+
+ HANDLE hdib = (HANDLE)phdib;
+ COLORREF crf = RGB( r, g, b );
+
+ if ((!pszName) || (pszName[0] == 0) || (hdib == NULL))
+ return;
+ // Generate lump
+
+ unsigned char *buf = (unsigned char *)_alloca( 16384 );
+
+ CUtlBuffer buffer( 0, 16384 );
+
+ int width, height;
+
+ int length = GrabMip (hdib, buf, pszName, crf, &width, &height);
+ if ( length == 0 )
+ {
+ return;
+ }
+
+ bool sizevalid = false;
+
+ if ( width == height )
+ {
+ if ( width == 16 ||
+ width == 32 ||
+ width == 64 )
+ {
+ sizevalid = true;
+ }
+ }
+
+ if ( !sizevalid )
+ return;
+
+ while (length & 3)
+ length++;
+
+ // Write Header
+ wadinfo_t header;
+ header.identification[0] = 'W';
+ header.identification[1] = 'A';
+ header.identification[2] = 'D';
+ header.identification[3] = '3';
+ header.numlumps = 1;
+ header.infotableofs = 0;
+
+ buffer.Put( &header, sizeof( wadinfo_t ) );
+
+ // Fill Ino info table
+ lumpinfo_t info;
+ Q_memset (&info, 0, sizeof(info));
+ Q_strncpy(info.name, pszName, sizeof( info.name ) );
+ info.filepos = (int)sizeof(wadinfo_t);
+ info.size = info.disksize = length;
+ info.type = TYP_LUMPY;
+ info.compression = 0;
+
+ // Write Lump
+ buffer.Put( buf, length );
+
+ // Write info table
+ buffer.Put( &info, sizeof( lumpinfo_t ) );
+
+ int savepos = buffer.TellPut();
+
+ buffer.SeekPut( CUtlBuffer::SEEK_HEAD, 0 );
+
+ header.infotableofs = length + sizeof(wadinfo_t);
+
+ buffer.Put( &header, sizeof( wadinfo_t ) );
+
+ buffer.SeekPut( CUtlBuffer::SEEK_HEAD, savepos );
+
+ // Output to file
+ FileHandle_t file;
+ file = g_pFullFileSystem->Open( "pldecal.wad", "wb" );
+ if ( file != FILESYSTEM_INVALID_HANDLE )
+ {
+ g_pFullFileSystem->Write( buffer.Base(), buffer.TellPut(), file );
+ g_pFullFileSystem->Close( file );
+ }
+
+} \ No newline at end of file
diff --git a/gameui/ModInfo.cpp b/gameui/ModInfo.cpp
new file mode 100644
index 0000000..d61fd13
--- /dev/null
+++ b/gameui/ModInfo.cpp
@@ -0,0 +1,251 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#include "ModInfo.h"
+#include "KeyValues.h"
+#include "vgui_controls/Controls.h"
+#include "filesystem.h"
+#include "EngineInterface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: singleton accessor
+//-----------------------------------------------------------------------------
+CModInfo &ModInfo()
+{
+ static CModInfo s_ModInfo;
+ return s_ModInfo;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CModInfo::CModInfo()
+{
+ m_pModData = new KeyValues("ModData");
+ m_wcsGameTitle[0] = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CModInfo::~CModInfo()
+{
+ FreeModInfo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CModInfo::FreeModInfo()
+{
+ if (m_pModData)
+ {
+ m_pModData->deleteThis();
+ m_pModData = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::IsMultiplayerOnly()
+{
+ return (stricmp(m_pModData->GetString("type", ""), "multiplayer_only") == 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::IsSinglePlayerOnly()
+{
+#ifndef _XBOX
+ return (stricmp(m_pModData->GetString("type", ""), "singleplayer_only") == 0);
+#else
+ // xboxissue - no support for disparate mounted content
+ return true;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *CModInfo::GetFallbackDir()
+{
+ return m_pModData->GetString("fallback_dir", "");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const wchar_t *CModInfo::GetGameTitle()
+{
+ if (!m_wcsGameTitle[0])
+ {
+ // for some reason, the standard ILocalize::ConvertANSIToUnicode() strips off
+ // the '�' character in 'HALF-LIFE�' - so just do a straight upconvert to unicode
+ const char *title = m_pModData->GetString("title", "");
+ int i = 0;
+ for (; title[i] != 0; ++i)
+ {
+ m_wcsGameTitle[i] = (wchar_t)title[i];
+ }
+ m_wcsGameTitle[i] = 0;
+ }
+
+ return m_wcsGameTitle;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const wchar_t *CModInfo::GetGameTitle2()
+{
+ if (!m_wcsGameTitle2[0])
+ {
+ // for some reason, the standard ILocalize::ConvertANSIToUnicode() strips off
+ // the '�' character in 'HALF-LIFE�' - so just do a straight upconvert to unicode
+ const char *title2 = m_pModData->GetString("title2", "");
+ int i = 0;
+ for (; title2[i] != 0; ++i)
+ {
+ m_wcsGameTitle2[i] = (wchar_t)title2[i];
+ }
+ m_wcsGameTitle2[i] = 0;
+ }
+
+ return m_wcsGameTitle2;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+const char *CModInfo::GetGameName()
+{
+ return m_pModData->GetString("game", "");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+KeyValues *CModInfo::GetHiddenMaps()
+{
+ return m_pModData->FindKey( "hidden_maps" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::HasPortals()
+{
+ return (stricmp(m_pModData->GetString("hasportals", "0"), "1") == 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::HasHDContent()
+{
+ return (stricmp(m_pModData->GetString("hashdcontent", "0"), "1") == 0);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::NoDifficulty()
+{
+ return (stricmp(m_pModData->GetString("nodifficulty", "0"), "1") == 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::NoModels()
+{
+ return (stricmp(m_pModData->GetString("nomodels", "0"), "1") == 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::NoHiModel()
+{
+ return (stricmp(m_pModData->GetString("nohimodel", "0"), "1") == 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::NoCrosshair()
+{
+ return (stricmp(m_pModData->GetString("nocrosshair", "1"), "1") == 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::AdvCrosshair()
+{
+ return ( m_pModData->GetInt( "advcrosshair" ) > 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+int CModInfo::AdvCrosshairLevel()
+{
+ return m_pModData->GetInt( "advcrosshair" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CModInfo::LoadCurrentGameInfo()
+{
+ // Load up gameinfo for the current mod
+ char const *filename = "gameinfo.txt";
+ m_pModData->LoadFromFile( g_pFullFileSystem, filename );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: loads file from null-terminated buffer
+//-----------------------------------------------------------------------------
+void CModInfo::LoadGameInfoFromBuffer( const char *buffer )
+{
+ // Load up gameinfo.txt for the current mod
+ m_pModData->LoadFromBuffer( "", buffer );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::UseGameLogo()
+{
+ return ( Q_stricmp( m_pModData->GetString( "gamelogo", "0" ), "1" ) == 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::UseBots()
+{
+ return ( Q_stricmp( m_pModData->GetString( "bots", "0" ), "1" ) == 0 );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CModInfo::SupportsVR()
+{
+ return (m_pModData->GetInt( "supportsvr" ) > 0);
+}
diff --git a/gameui/ModInfo.h b/gameui/ModInfo.h
new file mode 100644
index 0000000..c2d71e1
--- /dev/null
+++ b/gameui/ModInfo.h
@@ -0,0 +1,68 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MODINFO_H
+#define MODINFO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose: contains all the data entered about a mod in gameinfo.txt
+//-----------------------------------------------------------------------------
+class CModInfo
+{
+public:
+ CModInfo();
+ ~CModInfo();
+ void FreeModInfo();
+
+ // loads mod info from gameinfo.txt
+ void LoadCurrentGameInfo();
+
+ // loads gameinfo from null-terminated string
+ void LoadGameInfoFromBuffer( const char *buffer );
+
+ // data accessors
+ const wchar_t *GetGameTitle();
+ const wchar_t *GetGameTitle2();
+ const char *GetGameName();
+
+ bool IsMultiplayerOnly();
+ bool IsSinglePlayerOnly();
+
+ bool HasPortals();
+
+ bool NoDifficulty();
+ bool NoModels();
+ bool NoHiModel();
+ bool NoCrosshair();
+ bool AdvCrosshair();
+ int AdvCrosshairLevel();
+ const char *GetFallbackDir();
+ bool UseGameLogo();
+ bool UseBots();
+ bool HasHDContent();
+ bool SupportsVR();
+
+ KeyValues *GetHiddenMaps();
+
+private:
+ wchar_t m_wcsGameTitle[128];
+ wchar_t m_wcsGameTitle2[128];
+ KeyValues *m_pModData;
+};
+
+
+// singleton accessor
+extern CModInfo &ModInfo();
+
+#endif // MODINFO_H
diff --git a/gameui/MouseMessageForwardingPanel.cpp b/gameui/MouseMessageForwardingPanel.cpp
new file mode 100644
index 0000000..b02583d
--- /dev/null
+++ b/gameui/MouseMessageForwardingPanel.cpp
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "MouseMessageForwardingPanel.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+CMouseMessageForwardingPanel::CMouseMessageForwardingPanel( Panel *parent, const char *name ) : BaseClass( parent, name )
+{
+ // don't draw an
+ SetPaintEnabled(false);
+ SetPaintBackgroundEnabled(false);
+ SetPaintBorderEnabled(false);
+}
+
+void CMouseMessageForwardingPanel::PerformLayout()
+{
+ // fill out the whole area
+ int w, t;
+ GetParent()->GetSize(w, t);
+ SetBounds(0, 0, w, t);
+}
+
+void CMouseMessageForwardingPanel::OnMousePressed( vgui::MouseCode code )
+{
+ CallParentFunction( new KeyValues("MousePressed", "code", code) );
+}
+
+void CMouseMessageForwardingPanel::OnMouseDoublePressed( vgui::MouseCode code )
+{
+ CallParentFunction( new KeyValues("MouseDoublePressed", "code", code) );
+} \ No newline at end of file
diff --git a/gameui/MouseMessageForwardingPanel.h b/gameui/MouseMessageForwardingPanel.h
new file mode 100644
index 0000000..604fe6b
--- /dev/null
+++ b/gameui/MouseMessageForwardingPanel.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef MOUSEMESSAGEFORWARDINGPANEL_H
+#define MOUSEMESSAGEFORWARDINGPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Panel.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Invisible panel that forwards up mouse movement
+//-----------------------------------------------------------------------------
+class CMouseMessageForwardingPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CMouseMessageForwardingPanel, vgui::Panel );
+public:
+ CMouseMessageForwardingPanel( Panel *parent, const char *name );
+
+ virtual void PerformLayout( void );
+ virtual void OnMousePressed( vgui::MouseCode code );
+ virtual void OnMouseDoublePressed( vgui::MouseCode code );
+};
+
+#endif //MOUSEMESSAGEFORWARDINGPANEL_H \ No newline at end of file
diff --git a/gameui/MultiplayerAdvancedDialog.cpp b/gameui/MultiplayerAdvancedDialog.cpp
new file mode 100644
index 0000000..bbc7133
--- /dev/null
+++ b/gameui/MultiplayerAdvancedDialog.cpp
@@ -0,0 +1,431 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <time.h>
+
+#include "MultiplayerAdvancedDialog.h"
+
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/ListPanel.h>
+#include <KeyValues.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/TextEntry.h>
+#include "cvarslider.h"
+#include "PanelListPanel.h"
+#include <vgui/IInput.h>
+#include <steam/steam_api.h>
+#include "EngineInterface.h"
+#include "fmtstr.h"
+
+#include "filesystem.h"
+
+#include <tier0/vcrmode.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+#define OPTIONS_DIR "cfg"
+#define DEFAULT_OPTIONS_FILE OPTIONS_DIR "/user_default.scr"
+#define OPTIONS_FILE OPTIONS_DIR "/user.scr"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CMultiplayerAdvancedDialog::CMultiplayerAdvancedDialog(vgui::Panel *parent) : BaseClass(NULL, "MultiplayerAdvancedDialog")
+{
+ SetBounds(0, 0, 372, 160);
+ SetSizeable( false );
+
+ SetTitle("#GameUI_MultiplayerAdvanced", true);
+
+ Button *cancel = new Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ Button *ok = new Button( this, "OK", "#GameUI_OK" );
+ ok->SetCommand( "Ok" );
+
+ m_pListPanel = new CPanelListPanel( this, "PanelListPanel" );
+
+ m_pList = NULL;
+
+ m_pDescription = new CInfoDescription();
+ m_pDescription->InitFromFile( DEFAULT_OPTIONS_FILE );
+ m_pDescription->InitFromFile( OPTIONS_FILE );
+ m_pDescription->TransferCurrentValues( NULL );
+
+ LoadControlSettings("Resource\\MultiplayerAdvancedDialog.res");
+ CreateControls();
+
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+ SetDeleteSelfOnClose( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CMultiplayerAdvancedDialog::~CMultiplayerAdvancedDialog()
+{
+ delete m_pDescription;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::Activate()
+{
+ BaseClass::Activate();
+ input()->SetAppModalSurface(GetVPanel());
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::OnClose()
+{
+ BaseClass::OnClose();
+ MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *command -
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "Ok" ) )
+ {
+ // OnApplyChanges();
+ SaveValues();
+ OnClose();
+ return;
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void CMultiplayerAdvancedDialog::OnKeyCodeTyped(KeyCode code)
+{
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::GatherCurrentValues()
+{
+ if ( !m_pDescription )
+ return;
+
+ // OK
+ CheckButton *pBox;
+ TextEntry *pEdit;
+ ComboBox *pCombo;
+ CCvarSlider *pSlider;
+
+ mpcontrol_t *pList;
+
+ CScriptObject *pObj;
+ CScriptListItem *pItem;
+
+ char szValue[256];
+ char strValue[ 256 ];
+
+ pList = m_pList;
+ while ( pList )
+ {
+ pObj = pList->pScrObj;
+
+ if ( pObj->type == O_CATEGORY )
+ {
+ pList = pList->next;
+ continue;
+ }
+
+ if ( !pList->pControl )
+ {
+ pObj->SetCurValue( pObj->defValue );
+ pList = pList->next;
+ continue;
+ }
+
+ switch ( pObj->type )
+ {
+ case O_BOOL:
+ pBox = (CheckButton *)pList->pControl;
+ sprintf( szValue, "%s", pBox->IsSelected() ? "1" : "0" );
+ break;
+ case O_NUMBER:
+ pEdit = ( TextEntry * )pList->pControl;
+ pEdit->GetText( strValue, sizeof( strValue ) );
+ sprintf( szValue, "%s", strValue );
+ break;
+ case O_STRING:
+ pEdit = ( TextEntry * )pList->pControl;
+ pEdit->GetText( strValue, sizeof( strValue ) );
+ sprintf( szValue, "%s", strValue );
+ break;
+ case O_LIST:
+ {
+ pCombo = (ComboBox *)pList->pControl;
+ // pCombo->GetText( strValue, sizeof( strValue ) );
+ int activeItem = pCombo->GetActiveItem();
+
+ pItem = pObj->pListItems;
+ // int n = (int)pObj->fdefValue;
+
+ while ( pItem )
+ {
+ if (!activeItem--)
+ break;
+
+ pItem = pItem->pNext;
+ }
+
+ if ( pItem )
+ {
+ sprintf( szValue, "%s", pItem->szValue );
+ }
+ else // Couln't find index
+ {
+ //assert(!("Couldn't find string in list, using default value"));
+ sprintf( szValue, "%s", pObj->defValue );
+ }
+ break;
+ }
+ case O_SLIDER:
+ pSlider = ( CCvarSlider * )pList->pControl;
+ sprintf( szValue, "%.2f", pSlider->GetSliderValue() );
+ break;
+ }
+
+ // Remove double quotes and % characters
+ UTIL_StripInvalidCharacters( szValue, sizeof(szValue) );
+
+ strcpy( strValue, szValue );
+
+ pObj->SetCurValue( strValue );
+
+ pList = pList->next;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::CreateControls()
+{
+ DestroyControls();
+
+ // Go through desciption creating controls
+ CScriptObject *pObj;
+
+ pObj = m_pDescription->pObjList;
+
+ // Build out the clan dropdown
+ CScriptObject *pClanObj = m_pDescription->FindObject( "cl_clanid" );
+ ISteamFriends *pFriends = steamapicontext->SteamFriends();
+ if ( pFriends && pClanObj )
+ {
+ pClanObj->RemoveAndDeleteAllItems();
+ int iGroupCount = pFriends->GetClanCount();
+ pClanObj->AddItem( new CScriptListItem( "#Cstrike_ClanTag_None", "0" ) );
+ for ( int k = 0; k < iGroupCount; ++ k )
+ {
+ CSteamID clanID = pFriends->GetClanByIndex( k );
+ const char *pName = pFriends->GetClanName( clanID );
+ const char *pTag = pFriends->GetClanTag( clanID );
+
+ char id[12];
+ Q_snprintf( id, sizeof( id ), "%d", clanID.GetAccountID() );
+ pClanObj->AddItem( new CScriptListItem( CFmtStr( "%s (%s)", pTag, pName ), id ) );
+ }
+ }
+
+ mpcontrol_t *pCtrl;
+
+ CheckButton *pBox;
+ TextEntry *pEdit;
+ ComboBox *pCombo;
+ CCvarSlider *pSlider;
+ CScriptListItem *pListItem;
+
+ Panel *objParent = m_pListPanel;
+
+ while ( pObj )
+ {
+ if ( pObj->type == O_OBSOLETE || pObj->type == O_CATEGORY )
+ {
+ pObj = pObj->pNext;
+ continue;
+ }
+
+ pCtrl = new mpcontrol_t( objParent, "mpcontrol_t" );
+ pCtrl->type = pObj->type;
+
+ switch ( pCtrl->type )
+ {
+ case O_BOOL:
+ pBox = new CheckButton( pCtrl, "DescCheckButton", pObj->prompt );
+ pBox->SetSelected( pObj->fdefValue != 0.0f ? true : false );
+
+ pCtrl->pControl = (Panel *)pBox;
+ break;
+ case O_STRING:
+ case O_NUMBER:
+ pEdit = new TextEntry( pCtrl, "DescTextEntry");
+ pEdit->InsertString(pObj->defValue);
+ pCtrl->pControl = (Panel *)pEdit;
+ break;
+ case O_LIST:
+ {
+ pCombo = new ComboBox( pCtrl, "DescComboBox", 5, false );
+
+ // track which row matches the current value
+ int iRow = -1;
+ int iCount = 0;
+ pListItem = pObj->pListItems;
+ while ( pListItem )
+ {
+ if ( iRow == -1 && !Q_stricmp( pListItem->szValue, pObj->curValue ) )
+ iRow = iCount;
+
+ pCombo->AddItem( pListItem->szItemText, NULL );
+ pListItem = pListItem->pNext;
+ ++iCount;
+ }
+
+
+ pCombo->ActivateItemByRow( iRow );
+
+ pCtrl->pControl = (Panel *)pCombo;
+ }
+ break;
+ case O_SLIDER:
+ pSlider = new CCvarSlider( pCtrl, "DescSlider", "Test", pObj->fMin, pObj->fMax, pObj->cvarname, false );
+ pCtrl->pControl = (Panel *)pSlider;
+ break;
+ default:
+ break;
+ }
+
+ if ( pCtrl->type != O_BOOL )
+ {
+ pCtrl->pPrompt = new vgui::Label( pCtrl, "DescLabel", "" );
+ pCtrl->pPrompt->SetContentAlignment( vgui::Label::a_west );
+ pCtrl->pPrompt->SetTextInset( 5, 0 );
+ pCtrl->pPrompt->SetText( pObj->prompt );
+ }
+
+ pCtrl->pScrObj = pObj;
+
+ switch ( pCtrl->type )
+ {
+ case O_BOOL:
+ case O_STRING:
+ case O_NUMBER:
+ case O_LIST:
+ pCtrl->SetSize( 100, 28 );
+ break;
+ case O_SLIDER:
+ pCtrl->SetSize( 100, 40 );
+ break;
+ default:
+ break;
+ }
+ //pCtrl->SetBorder( scheme()->GetBorder(1, "DepressedButtonBorder") );
+ m_pListPanel->AddItem( pCtrl );
+
+ // Link it in
+ if ( !m_pList )
+ {
+ m_pList = pCtrl;
+ pCtrl->next = NULL;
+ }
+ else
+ {
+ mpcontrol_t *p;
+ p = m_pList;
+ while ( p )
+ {
+ if ( !p->next )
+ {
+ p->next = pCtrl;
+ pCtrl->next = NULL;
+ break;
+ }
+ p = p->next;
+ }
+ }
+
+ pObj = pObj->pNext;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::DestroyControls()
+{
+ mpcontrol_t *p, *n;
+
+ p = m_pList;
+ while ( p )
+ {
+ n = p->next;
+ //
+ delete p->pControl;
+ delete p->pPrompt;
+ delete p;
+ p = n;
+ }
+
+ m_pList = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMultiplayerAdvancedDialog::SaveValues()
+{
+ // Get the values from the controls:
+ GatherCurrentValues();
+
+ // Create the game.cfg file
+ if ( m_pDescription )
+ {
+ FileHandle_t fp;
+
+ // Add settings to config.cfg
+ m_pDescription->WriteToConfig();
+
+ g_pFullFileSystem->CreateDirHierarchy( OPTIONS_DIR );
+ fp = g_pFullFileSystem->Open( OPTIONS_FILE, "wb" );
+ if ( fp )
+ {
+ m_pDescription->WriteToScriptFile( fp );
+ g_pFullFileSystem->Close( fp );
+ }
+ }
+}
+
diff --git a/gameui/MultiplayerAdvancedDialog.h b/gameui/MultiplayerAdvancedDialog.h
new file mode 100644
index 0000000..7465173
--- /dev/null
+++ b/gameui/MultiplayerAdvancedDialog.h
@@ -0,0 +1,52 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MULTIPLAYERADVANCEDDIALOG_H
+#define MULTIPLAYERADVANCEDDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include "scriptobject.h"
+#include <vgui/KeyCode.h>
+
+class CPanelListPanel;
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays a game-specific list of options
+//-----------------------------------------------------------------------------
+class CMultiplayerAdvancedDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CMultiplayerAdvancedDialog, vgui::Frame );
+
+public:
+ CMultiplayerAdvancedDialog(vgui::Panel *parent);
+ ~CMultiplayerAdvancedDialog();
+
+ virtual void Activate();
+
+private:
+
+ void CreateControls();
+ void DestroyControls();
+ void GatherCurrentValues();
+ void SaveValues();
+
+ CInfoDescription *m_pDescription;
+
+ mpcontrol_t *m_pList;
+
+ CPanelListPanel *m_pListPanel;
+
+ virtual void OnCommand( const char *command );
+ virtual void OnClose();
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+};
+
+
+#endif // MULTIPLAYERADVANCEDDIALOG_H
diff --git a/gameui/NewGameDialog.cpp b/gameui/NewGameDialog.cpp
new file mode 100644
index 0000000..2d76861
--- /dev/null
+++ b/gameui/NewGameDialog.cpp
@@ -0,0 +1,1724 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "NewGameDialog.h"
+#include "EngineInterface.h"
+#include "vgui_controls/Button.h"
+#include "vgui_controls/CheckButton.h"
+#include "KeyValues.h"
+#include "vgui/ISurface.h"
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include <vgui/ISystem.h>
+#include "vgui_controls/RadioButton.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Frame.h"
+#include "vgui_controls/ControllerMap.h"
+#include "filesystem.h"
+#include "ModInfo.h"
+#include "tier1/convar.h"
+#include "GameUI_Interface.h"
+#include "tier0/icommandline.h"
+#include "vgui_controls/AnimationController.h"
+#include "CommentaryExplanationDialog.h"
+#include "vgui_controls/BitmapImagePanel.h"
+#include "BonusMapsDatabase.h"
+
+#include <stdio.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+static float g_ScrollSpeedSlow;
+static float g_ScrollSpeedFast;
+
+// sort function used in displaying chapter list
+struct chapter_t
+{
+ char filename[32];
+};
+static int __cdecl ChapterSortFunc(const void *elem1, const void *elem2)
+{
+ chapter_t *c1 = (chapter_t *)elem1;
+ chapter_t *c2 = (chapter_t *)elem2;
+
+ // compare chapter number first
+ static int chapterlen = strlen("chapter");
+ if (atoi(c1->filename + chapterlen) > atoi(c2->filename + chapterlen))
+ return 1;
+ else if (atoi(c1->filename + chapterlen) < atoi(c2->filename + chapterlen))
+ return -1;
+
+ // compare length second (longer string show up later in the list, eg. chapter9 before chapter9a)
+ if (strlen(c1->filename) > strlen(c2->filename))
+ return 1;
+ else if (strlen(c1->filename) < strlen(c2->filename))
+ return -1;
+
+ // compare strings third
+ return strcmp(c1->filename, c2->filename);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: invisible panel used for selecting a chapter panel
+//-----------------------------------------------------------------------------
+class CSelectionOverlayPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CSelectionOverlayPanel, Panel );
+ int m_iChapterIndex;
+ CNewGameDialog *m_pSelectionTarget;
+public:
+ CSelectionOverlayPanel( Panel *parent, CNewGameDialog *selectionTarget, int chapterIndex ) : BaseClass( parent, NULL )
+ {
+ m_iChapterIndex = chapterIndex;
+ m_pSelectionTarget = selectionTarget;
+ SetPaintEnabled(false);
+ SetPaintBackgroundEnabled(false);
+ }
+
+ virtual void OnMousePressed( vgui::MouseCode code )
+ {
+ if (GetParent()->IsEnabled())
+ {
+ m_pSelectionTarget->SetSelectedChapterIndex( m_iChapterIndex );
+ }
+ }
+
+ virtual void OnMouseDoublePressed( vgui::MouseCode code )
+ {
+ // call the panel
+ OnMousePressed( code );
+ if (GetParent()->IsEnabled())
+ {
+ PostMessage( m_pSelectionTarget, new KeyValues("Command", "command", "play") );
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: selectable item with screenshot for an individual chapter in the dialog
+//-----------------------------------------------------------------------------
+class CGameChapterPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CGameChapterPanel, vgui::EditablePanel );
+
+ ImagePanel *m_pLevelPicBorder;
+ ImagePanel *m_pLevelPic;
+ ImagePanel *m_pCommentaryIcon;
+ Label *m_pChapterLabel;
+ Label *m_pChapterNameLabel;
+
+ Color m_TextColor;
+ Color m_DisabledColor;
+ Color m_SelectedColor;
+ Color m_FillColor;
+
+ char m_szConfigFile[_MAX_PATH];
+ char m_szChapter[32];
+
+ bool m_bTeaserChapter;
+ bool m_bHasBonus;
+ bool m_bCommentaryMode;
+
+ bool m_bIsSelected;
+
+public:
+ CGameChapterPanel( CNewGameDialog *parent, const char *name, const char *chapterName, int chapterIndex, const char *chapterNumber, const char *chapterConfigFile, bool bCommentary ) : BaseClass( parent, name )
+ {
+ Q_strncpy( m_szConfigFile, chapterConfigFile, sizeof(m_szConfigFile) );
+ Q_strncpy( m_szChapter, chapterNumber, sizeof(m_szChapter) );
+
+ m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) );
+ m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) );
+ m_pCommentaryIcon = NULL;
+ m_bCommentaryMode = bCommentary;
+ m_bIsSelected = false;
+
+ wchar_t text[32];
+ wchar_t num[32];
+ wchar_t *chapter = g_pVGuiLocalize->Find("#GameUI_Chapter");
+ g_pVGuiLocalize->ConvertANSIToUnicode( chapterNumber, num, sizeof(num) );
+ _snwprintf( text, ARRAYSIZE(text), L"%ls %ls", chapter ? chapter : L"CHAPTER", num );
+
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ m_pChapterLabel = new Label( this, "ChapterLabel", text );
+ m_pChapterNameLabel = new Label( this, "ChapterNameLabel", chapterName );
+ }
+ else
+ {
+ m_pChapterLabel = new Label( this, "ChapterLabel", chapterName );
+ m_pChapterNameLabel = new Label( this, "ChapterNameLabel", "#GameUI_LoadCommentary" );
+ }
+
+ SetPaintBackgroundEnabled( false );
+
+ // the image has the same name as the config file
+ char szMaterial[ MAX_PATH ];
+ Q_snprintf( szMaterial, sizeof(szMaterial), "chapters/%s", chapterConfigFile );
+ char *ext = strstr( szMaterial, "." );
+ if ( ext )
+ {
+ *ext = 0;
+ }
+ m_pLevelPic->SetImage( szMaterial );
+
+ KeyValues *pKeys = NULL;
+ if ( GameUI().IsConsoleUI() )
+ {
+ pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameChapterPanel.res" );
+ }
+ LoadControlSettings( "Resource/NewGameChapterPanel.res", NULL, pKeys );
+
+ int px, py;
+ m_pLevelPicBorder->GetPos( px, py );
+ SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() );
+
+ // create a selection panel the size of the page
+ CSelectionOverlayPanel *overlay = new CSelectionOverlayPanel( this, parent, chapterIndex );
+ overlay->SetBounds(0, 0, GetWide(), GetTall());
+ overlay->MoveToFront();
+
+ // HACK: Detect new episode teasers by the "Coming Soon" text
+ wchar_t w_szStrTemp[256];
+ m_pChapterNameLabel->GetText( w_szStrTemp, sizeof(w_szStrTemp) );
+ m_bTeaserChapter = !wcscmp(w_szStrTemp, L"Coming Soon");
+ m_bHasBonus = false;
+ }
+
+ virtual void ApplySchemeSettings( IScheme *pScheme )
+ {
+ m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
+ m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) );
+ m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 255) );
+ m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // Hide chapter numbers for new episode teasers
+ if ( m_bTeaserChapter )
+ {
+ m_pChapterLabel->SetVisible( false );
+ }
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pChapterNameLabel->SetVisible( false );
+ }
+
+ m_pCommentaryIcon = dynamic_cast<ImagePanel*>( FindChildByName( "CommentaryIcon" ) );
+ if ( m_pCommentaryIcon )
+ m_pCommentaryIcon->SetVisible( m_bCommentaryMode );
+ }
+
+ bool IsSelected( void ) const { return m_bIsSelected; }
+
+ void SetSelected( bool state )
+ {
+ m_bIsSelected = state;
+
+ // update the text/border colors
+ if ( !IsEnabled() )
+ {
+ m_pChapterLabel->SetFgColor( m_DisabledColor );
+ m_pChapterNameLabel->SetFgColor( Color(0, 0, 0, 0) );
+ m_pLevelPicBorder->SetFillColor( m_DisabledColor );
+ m_pLevelPic->SetAlpha( GameUI().IsConsoleUI() ? 64 : 128 );
+ return;
+ }
+
+ if ( state )
+ {
+ if ( !GameUI().IsConsoleUI() )
+ {
+ m_pChapterLabel->SetFgColor( m_SelectedColor );
+ m_pChapterNameLabel->SetFgColor( m_SelectedColor );
+ }
+ m_pLevelPicBorder->SetFillColor( m_SelectedColor );
+ }
+ else
+ {
+ m_pChapterLabel->SetFgColor( m_TextColor );
+ m_pChapterNameLabel->SetFgColor( m_TextColor );
+ m_pLevelPicBorder->SetFillColor( m_FillColor );
+ }
+ m_pLevelPic->SetAlpha( 255 );
+ }
+
+ const char *GetConfigFile()
+ {
+ return m_szConfigFile;
+ }
+
+ const char *GetChapter()
+ {
+ return m_szChapter;
+ }
+
+ bool IsTeaserChapter()
+ {
+ return m_bTeaserChapter;
+ }
+
+ bool HasBonus()
+ {
+ return m_bHasBonus;
+ }
+
+ void SetCommentaryMode( bool bCommentaryMode )
+ {
+ m_bCommentaryMode = bCommentaryMode;
+ if ( m_pCommentaryIcon )
+ m_pCommentaryIcon->SetVisible( m_bCommentaryMode );
+ }
+};
+
+const char *COM_GetModDirectory()
+{
+ static char modDir[MAX_PATH];
+ if ( Q_strlen( modDir ) == 0 )
+ {
+ const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) );
+ Q_strncpy( modDir, gamedir, sizeof(modDir) );
+ if ( strchr( modDir, '/' ) || strchr( modDir, '\\' ) )
+ {
+ Q_StripLastDir( modDir, sizeof(modDir) );
+ int dirlen = Q_strlen( modDir );
+ Q_strncpy( modDir, gamedir + dirlen, sizeof(modDir) - dirlen );
+ }
+ }
+
+ return modDir;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: new game chapter selection
+//-----------------------------------------------------------------------------
+CNewGameDialog::CNewGameDialog(vgui::Panel *parent, bool bCommentaryMode) : BaseClass(parent, "NewGameDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 372, 160);
+ SetSizeable( false );
+ m_iSelectedChapter = -1;
+ m_ActiveTitleIdx = 0;
+
+ m_bCommentaryMode = bCommentaryMode;
+ m_bMapStarting = false;
+ m_bScrolling = false;
+ m_ScrollCt = 0;
+ m_ScrollSpeed = 0.f;
+ m_ButtonPressed = SCROLL_NONE;
+ m_ScrollDirection = SCROLL_NONE;
+ m_pCommentaryLabel = NULL;
+
+ m_iBonusSelection = 0;
+ m_bScrollToFirstBonusMap = false;
+
+ SetTitle("#GameUI_NewGame", true);
+
+ m_pNextButton = new Button( this, "Next", "#gameui_next" );
+ m_pPrevButton = new Button( this, "Prev", "#gameui_prev" );
+ m_pPlayButton = new CNewGamePlayButton( this, "Play", "#GameUI_Play" );
+ m_pPlayButton->SetCommand( "Play" );
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) );
+ m_pCenterBg->SetVisible( false );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ m_pNextButton->SetVisible( false );
+ m_pPrevButton->SetVisible( false );
+ m_pPlayButton->SetVisible( false );
+ cancel->SetVisible( false );
+
+ m_pCenterBg->SetPaintBackgroundType( 2 );
+ m_pCenterBg->SetVisible( true );
+
+ m_pChapterTitleLabels[0] = SETUP_PANEL( new Label( this, "ChapterTitleLabel", "" ) );
+ m_pChapterTitleLabels[0]->SetVisible( true );
+ m_pChapterTitleLabels[0]->SetFgColor( Color( 255, 255, 255, 255 ) );
+
+ m_pChapterTitleLabels[1] = SETUP_PANEL( new Label( this, "ChapterTitleLabel2", "" ) );
+ m_pChapterTitleLabels[1]->SetVisible( true );
+ m_pChapterTitleLabels[1]->SetAlpha( 0 );
+ m_pChapterTitleLabels[1]->SetFgColor( Color( 255, 255, 255, 255 ) );
+
+ m_pBonusSelection = SETUP_PANEL( new Label( this, "BonusSelectionLabel", "#GameUI_BonusMapsStandard" ) );
+ m_pBonusSelectionBorder = SETUP_PANEL( new ImagePanel( this, "BonusSelectionBorder" ) );
+
+ m_pFooter = new CFooterPanel( parent, "NewGameFooter" );
+ m_pFooter->AddNewButtonLabel( "#GameUI_Play", "#GameUI_Icons_A_BUTTON" );
+ m_pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ }
+ else
+ {
+ m_pFooter = NULL;
+ }
+
+ // parse out the chapters off disk
+ static const int MAX_CHAPTERS = 32;
+ chapter_t chapters[MAX_CHAPTERS];
+
+ char szFullFileName[MAX_PATH];
+ int chapterIndex = 0;
+
+ if ( IsPC() || !IsX360() )
+ {
+ FileFindHandle_t findHandle = FILESYSTEM_INVALID_FIND_HANDLE;
+ const char *fileName = "cfg/chapter*.cfg";
+ fileName = g_pFullFileSystem->FindFirst( fileName, &findHandle );
+ while ( fileName && chapterIndex < MAX_CHAPTERS )
+ {
+ if ( fileName[0] )
+ {
+ // Only load chapter configs from the current mod's cfg dir
+ // or else chapters appear that we don't want!
+ Q_snprintf( szFullFileName, sizeof(szFullFileName), "cfg/%s", fileName );
+ FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
+ if ( f )
+ {
+ // don't load chapter files that are empty, used in the demo
+ if ( g_pFullFileSystem->Size(f) > 0 )
+ {
+ Q_strncpy(chapters[chapterIndex].filename, fileName, sizeof(chapters[chapterIndex].filename));
+ ++chapterIndex;
+ }
+ g_pFullFileSystem->Close( f );
+ }
+ }
+ fileName = g_pFullFileSystem->FindNext(findHandle);
+ }
+ }
+ else if ( IsX360() )
+ {
+ int ChapterStringIndex = 0;
+ bool bExists = true;
+ while ( bExists && chapterIndex < MAX_CHAPTERS )
+ {
+ Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter%d.cfg", ChapterStringIndex+1 );
+
+ FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
+ if ( f )
+ {
+ Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename));
+ ++chapterIndex;
+ ++ChapterStringIndex;
+ g_pFullFileSystem->Close( f );
+ }
+ else
+ {
+ bExists = false;
+ }
+ //Hack to account for xbox360 missing chapter9a
+ if ( ChapterStringIndex == 10 )
+ {
+ Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter9a.cfg" );
+ FileHandle_t fChap = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
+ if ( fChap )
+ {
+ Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename));
+ ++chapterIndex;
+ g_pFullFileSystem->Close( fChap );
+ }
+ }
+
+ }
+
+ }
+
+ bool bBonusesUnlocked = false;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !m_bCommentaryMode )
+ {
+ // Scan to see if the bonus maps have been unlocked
+ bBonusesUnlocked = BonusMapsDatabase()->BonusesUnlocked();
+ }
+ }
+
+ // sort the chapters
+ qsort(chapters, chapterIndex, sizeof(chapter_t), &ChapterSortFunc);
+
+ // work out which chapters are unlocked
+ ConVarRef var( "sv_unlockedchapters" );
+
+ if ( bBonusesUnlocked )
+ {
+ // Bonuses are unlocked so we need to unlock all the chapters too
+ var.SetValue( 15 );
+ }
+
+ const char *unlockedChapter = var.IsValid() ? var.GetString() : "1";
+ int iUnlockedChapter = atoi(unlockedChapter);
+
+ // add chapters to combobox
+ for (int i = 0; i < chapterIndex; i++)
+ {
+ const char *fileName = chapters[i].filename;
+ char chapterID[32] = { 0 };
+ sscanf(fileName, "chapter%s", chapterID);
+ // strip the extension
+ char *ext = V_stristr(chapterID, ".cfg");
+ if (ext)
+ {
+ *ext = 0;
+ }
+
+ const char *pGameDir = COM_GetModDirectory();
+
+ char chapterName[64];
+ Q_snprintf(chapterName, sizeof(chapterName), "#%s_Chapter%s_Title", pGameDir, chapterID);
+
+ Q_snprintf( szFullFileName, sizeof( szFullFileName ), "%s", fileName );
+ CGameChapterPanel *chapterPanel = SETUP_PANEL( new CGameChapterPanel( this, NULL, chapterName, i, chapterID, szFullFileName, m_bCommentaryMode ) );
+ chapterPanel->SetVisible( false );
+
+ UpdatePanelLockedStatus( iUnlockedChapter, i + 1, chapterPanel );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( bBonusesUnlocked )
+ {
+ // check to see if it has associated challenges
+ for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap )
+ {
+ BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap );
+ if ( Q_stricmp( pMap->szChapterName, szFullFileName ) == 0 && !pMap->bLocked )
+ {
+ chapterPanel->m_bHasBonus = true;
+ chapterPanel->SetControlVisible( "HasBonusLabel", true );
+ }
+ }
+ }
+ }
+
+ m_ChapterPanels.AddToTail( chapterPanel );
+ }
+
+ KeyValues *pKeys = NULL;
+ if ( GameUI().IsConsoleUI() )
+ {
+ pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameDialog.res" );
+ }
+ LoadControlSettings( "Resource/NewGameDialog.res", NULL, pKeys );
+
+ // Reset all properties
+ for ( int i = 0; i < NUM_SLOTS; ++i )
+ {
+ m_PanelIndex[i] = INVALID_INDEX;
+ }
+
+ if ( !m_ChapterPanels.Count() )
+ {
+ UpdateMenuComponents( SCROLL_NONE );
+ return;
+ }
+
+ // Layout panel positions relative to the dialog center.
+ int panelWidth = m_ChapterPanels[0]->GetWide() + 16;
+ int dialogWidth = GetWide();
+
+ m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + 8;
+
+ if (m_ChapterPanels.Count() > 1)
+ {
+ m_PanelXPos[1] = m_PanelXPos[2] - panelWidth;
+ m_PanelXPos[0] = m_PanelXPos[1];
+ m_PanelXPos[3] = m_PanelXPos[2] + panelWidth;
+ m_PanelXPos[4] = m_PanelXPos[3];
+ }
+ else
+ {
+ m_PanelXPos[0] = m_PanelXPos[1] = m_PanelXPos[3] =
+ m_PanelXPos[4] = m_PanelXPos[2];
+ }
+
+
+ m_PanelAlpha[0] = 0;
+ m_PanelAlpha[1] = 255;
+ m_PanelAlpha[2] = 255;
+ m_PanelAlpha[3] = 255;
+ m_PanelAlpha[4] = 0;
+
+ int panelHeight;
+ m_ChapterPanels[0]->GetSize( panelWidth, panelHeight );
+ m_pCenterBg->SetWide( panelWidth + 16 );
+ m_pCenterBg->SetPos( m_PanelXPos[2] - 8, m_PanelYPos[2] - (m_pCenterBg->GetTall() - panelHeight) + 8 );
+ m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) );
+
+ // start the first item selected
+ SetSelectedChapterIndex( 0 );
+}
+
+CNewGameDialog::~CNewGameDialog()
+{
+ delete m_pFooter;
+ m_pFooter = NULL;
+}
+
+void CNewGameDialog::Activate( void )
+{
+ m_bMapStarting = false;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ // Stop blinking the menu item now that we've seen the unlocked stuff
+ CBasePanel *pBasePanel = BasePanel();
+ if ( pBasePanel )
+ pBasePanel->SetMenuItemBlinkingState( "OpenNewGameDialog", false );
+
+ BonusMapsDatabase()->SetBlink( false );
+ }
+
+ // Commentary stuff is set up on activate because in XBox the new game menu is never deleted
+ SetTitle( ( ( m_bCommentaryMode ) ? ( "#GameUI_LoadCommentary" ) : ( "#GameUI_NewGame") ), true);
+
+ if ( m_pCommentaryLabel )
+ m_pCommentaryLabel->SetVisible( m_bCommentaryMode );
+
+ // work out which chapters are unlocked
+ ConVarRef var( "sv_unlockedchapters" );
+ const char *unlockedChapter = var.IsValid() ? var.GetString() : "1";
+ int iUnlockedChapter = atoi(unlockedChapter);
+
+ for ( int i = 0; i < m_ChapterPanels.Count(); i++)
+ {
+ CGameChapterPanel *pChapterPanel = m_ChapterPanels[ i ];
+
+ if ( pChapterPanel )
+ {
+ pChapterPanel->SetCommentaryMode( m_bCommentaryMode );
+
+ UpdatePanelLockedStatus( iUnlockedChapter, i + 1, pChapterPanel );
+ }
+ }
+
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Apply special properties of the menu
+//-----------------------------------------------------------------------------
+void CNewGameDialog::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ int ypos = inResourceData->GetInt( "chapterypos", 40 );
+ for ( int i = 0; i < NUM_SLOTS; ++i )
+ {
+ m_PanelYPos[i] = ypos;
+ }
+
+ m_pCenterBg->SetTall( inResourceData->GetInt( "centerbgtall", 0 ) );
+
+ g_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f );
+ g_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f );
+ SetFastScroll( false );
+}
+
+void CNewGameDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ if ( m_pFooter )
+ {
+ KeyValues *pFooterControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameFooter.res" );
+ m_pFooter->LoadControlSettings( "null", NULL, pFooterControlSettings );
+ }
+
+ UpdateMenuComponents( SCROLL_NONE );
+
+ m_pCommentaryLabel = dynamic_cast<vgui::Label*>( FindChildByName( "CommentaryUnlock" ) );
+ if ( m_pCommentaryLabel )
+ m_pCommentaryLabel->SetVisible( m_bCommentaryMode );
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( !m_bCommentaryMode && BonusMapsDatabase()->BonusesUnlocked() && !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() )
+ {
+ // Find the first bonus
+ ScrollSelectionPanels( SCROLL_LEFT );
+ m_bScrollToFirstBonusMap = true;
+ }
+ }
+}
+
+static float GetArrowAlpha( void )
+{
+ // X360TBD: Pulsing arrows
+ return 255.f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the correct properties for visible components
+//-----------------------------------------------------------------------------
+void CNewGameDialog::UpdateMenuComponents( EScrollDirection dir )
+{
+ // This is called prior to any scrolling,
+ // so we need to look ahead to the post-scroll state
+ int centerIdx = SLOT_CENTER;
+ if ( dir == SCROLL_LEFT )
+ {
+ ++centerIdx;
+ }
+ else if ( dir == SCROLL_RIGHT )
+ {
+ --centerIdx;
+ }
+ int leftIdx = centerIdx - 1;
+ int rightIdx = centerIdx + 1;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ bool bHasBonus = false;
+ if ( m_PanelIndex[centerIdx] != INVALID_INDEX )
+ {
+ wchar_t buffer[ MAX_PATH ];
+ m_ChapterPanels[ m_PanelIndex[centerIdx] ]->m_pChapterNameLabel->GetText( buffer, sizeof(buffer) );
+ m_pChapterTitleLabels[(unsigned)m_ActiveTitleIdx]->SetText( buffer );
+
+ // If it has bonuses show the scroll up and down arrows
+ bHasBonus = m_ChapterPanels[ m_PanelIndex[centerIdx] ]->HasBonus();
+ }
+
+ vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" );
+ vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" );
+ if ( leftArrow )
+ {
+ if ( m_PanelIndex[leftIdx] != INVALID_INDEX )
+ {
+ leftArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) );
+ }
+ else
+ {
+ leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
+ }
+ }
+ if ( rightArrow )
+ {
+ if ( m_PanelIndex[rightIdx] != INVALID_INDEX )
+ {
+ rightArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) );
+ }
+ else
+ {
+ rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
+ }
+ }
+
+ if ( bHasBonus )
+ {
+ // Find the bonus description for this panel
+ for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus )
+ {
+ m_pBonusMapDescription = BonusMapsDatabase()->GetBonusData( iBonus );
+ if ( Q_stricmp( m_pBonusMapDescription->szChapterName, m_ChapterPanels[ m_PanelIndex[centerIdx] ]->GetConfigFile() ) == 0 )
+ break;
+ }
+ }
+ else
+ {
+ m_pBonusMapDescription = NULL;
+ }
+
+ vgui::Panel *upArrow = this->FindChildByName( "UpArrow" );
+ vgui::Panel *downArrow = this->FindChildByName( "DownArrow" );
+
+ if ( upArrow )
+ upArrow->SetVisible( bHasBonus );
+ if ( downArrow )
+ downArrow->SetVisible( bHasBonus );
+
+ m_pBonusSelection->SetVisible( bHasBonus );
+ m_pBonusSelectionBorder->SetVisible( bHasBonus );
+
+ UpdateBonusSelection();
+ }
+
+ // No buttons in the xbox ui
+ if ( !GameUI().IsConsoleUI() )
+ {
+ if ( m_PanelIndex[leftIdx] == INVALID_INDEX || m_PanelIndex[leftIdx] == 0 )
+ {
+ m_pPrevButton->SetVisible( false );
+ m_pPrevButton->SetEnabled( false );
+ }
+ else
+ {
+ m_pPrevButton->SetVisible( true );
+ m_pPrevButton->SetEnabled( true );
+ }
+
+ if ( m_ChapterPanels.Count() < 4 ) // if there are less than 4 chapters show the next button but disabled
+ {
+ m_pNextButton->SetVisible( true );
+ m_pNextButton->SetEnabled( false );
+ }
+ else if ( m_PanelIndex[rightIdx] == INVALID_INDEX || m_PanelIndex[rightIdx] == m_ChapterPanels.Count()-1 )
+ {
+ m_pNextButton->SetVisible( false );
+ m_pNextButton->SetEnabled( false );
+ }
+ else
+ {
+ m_pNextButton->SetVisible( true );
+ m_pNextButton->SetEnabled( true );
+ }
+ }
+}
+
+void CNewGameDialog::UpdateBonusSelection( void )
+{
+ int iNumChallenges = 0;
+ if ( m_pBonusMapDescription )
+ {
+ if ( m_pBonusMapDescription->m_pChallenges )
+ iNumChallenges = m_pBonusMapDescription->m_pChallenges->Count();
+
+ // Wrap challenge selection to fit number of possible selections
+ if ( m_iBonusSelection < 0 )
+ m_iBonusSelection = iNumChallenges + 1;
+ else if ( m_iBonusSelection >= iNumChallenges + 2 )
+ m_iBonusSelection = 0;
+ }
+ else
+ {
+ // No medals to show
+ SetControlVisible( "ChallengeEarnedMedal", false );
+ SetControlVisible( "ChallengeBestLabel", false );
+ SetControlVisible( "ChallengeNextMedal", false );
+ SetControlVisible( "ChallengeNextLabel", false );
+ return;
+ }
+
+ if ( m_iBonusSelection == 0 )
+ {
+ m_pBonusSelection->SetText( "#GameUI_BonusMapsStandard" );
+ SetControlVisible( "ChallengeEarnedMedal", false );
+ SetControlVisible( "ChallengeBestLabel", false );
+ SetControlVisible( "ChallengeNextMedal", false );
+ SetControlVisible( "ChallengeNextLabel", false );
+ }
+ else if ( m_iBonusSelection == 1 )
+ {
+ m_pBonusSelection->SetText( "#GameUI_BonusMapsAdvanced" );
+ SetControlVisible( "ChallengeEarnedMedal", false );
+ SetControlVisible( "ChallengeBestLabel", false );
+ SetControlVisible( "ChallengeNextMedal", false );
+ SetControlVisible( "ChallengeNextLabel", false );
+
+ char szMapAdvancedName[ 256 ] = "";
+ if ( m_pBonusMapDescription )
+ {
+ Q_snprintf( szMapAdvancedName, sizeof( szMapAdvancedName ), "%s_advanced", m_pBonusMapDescription->szMapFileName );
+ }
+
+ BonusMapDescription_t *pAdvancedDescription = NULL;
+
+ // Find the bonus description for this panel
+ for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus )
+ {
+ pAdvancedDescription = BonusMapsDatabase()->GetBonusData( iBonus );
+ if ( Q_stricmp( szMapAdvancedName, pAdvancedDescription->szMapFileName ) == 0 )
+ break;
+ }
+
+ if ( pAdvancedDescription && pAdvancedDescription->bComplete )
+ {
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( "hud/icon_complete" );
+ }
+ }
+ else
+ {
+ int iChallenge = m_iBonusSelection - 2;
+ ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge ]);
+
+ // Set the display text for the selected challenge
+ m_pBonusSelection->SetText( pChallengeDescription->szName );
+
+ int iBest, iEarnedMedal, iNext, iNextMedal;
+ GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal );
+
+ char szBuff[ 512 ];
+
+ // Set earned medal
+ if ( iEarnedMedal > -1 && iBest != -1 )
+ {
+ if ( iChallenge < 10 )
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
+ else
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
+
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( szBuff );
+ }
+ else
+ {
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
+ pBitmap->SetVisible( false );
+ }
+
+ // Set next medal
+ if ( iNextMedal > 0 )
+ {
+ if ( iChallenge < 10 )
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
+ else
+ Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
+
+ CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeNextMedal" ) );
+ pBitmap->SetVisible( true );
+ pBitmap->setTexture( szBuff );
+ }
+ else
+ {
+ SetControlVisible( "ChallengeNextMedal", false );
+ }
+
+ wchar_t szWideBuff[ 64 ];
+ wchar_t szWideBuff2[ 64 ];
+
+ // Best label
+ if ( iBest != -1 )
+ {
+ Q_snprintf( szBuff, sizeof( szBuff ), "%i", iBest );
+ g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsBest" ), 1, szWideBuff2 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ SetControlString( "ChallengeBestLabel", szBuff );
+ SetControlVisible( "ChallengeBestLabel", true );
+ }
+ else
+ {
+ SetControlVisible( "ChallengeBestLabel", false );
+ }
+
+ // Next label
+ if ( iNext != -1 )
+ {
+ Q_snprintf( szBuff, sizeof( szBuff ), "%i", iNext );
+ g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsGoal" ), 1, szWideBuff2 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ SetControlString( "ChallengeNextLabel", szBuff );
+ SetControlVisible( "ChallengeNextLabel", true );
+ }
+ else
+ {
+ SetControlVisible( "ChallengeNextLabel", false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets a chapter as selected
+//-----------------------------------------------------------------------------
+void CNewGameDialog::SetSelectedChapterIndex( int index )
+{
+ m_iSelectedChapter = index;
+
+ for (int i = 0; i < m_ChapterPanels.Count(); i++)
+ {
+ if ( i == index )
+ {
+ m_ChapterPanels[i]->SetSelected( true );
+ }
+ else
+ {
+ m_ChapterPanels[i]->SetSelected( false );
+ }
+ }
+
+ if ( m_pPlayButton )
+ {
+ m_pPlayButton->SetEnabled( true );
+ }
+
+ // Setup panels to the left of the selected panel
+ int selectedSlot = GameUI().IsConsoleUI() ? SLOT_CENTER : index % 3 + 1;
+ int currIdx = index;
+ for ( int i = selectedSlot; i >= 0 && currIdx >= 0; --i )
+ {
+ m_PanelIndex[i] = currIdx;
+ --currIdx;
+ InitPanelIndexForDisplay( i );
+ }
+
+ // Setup panels to the right of the selected panel
+ currIdx = index + 1;
+ for ( int i = selectedSlot + 1; i < NUM_SLOTS && currIdx < m_ChapterPanels.Count(); ++i )
+ {
+ m_PanelIndex[i] = currIdx;
+ ++currIdx;
+ InitPanelIndexForDisplay( i );
+ }
+
+ UpdateMenuComponents( SCROLL_NONE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets a chapter as selected
+//-----------------------------------------------------------------------------
+void CNewGameDialog::SetSelectedChapter( const char *chapter )
+{
+ Assert( chapter );
+ for (int i = 0; i < m_ChapterPanels.Count(); i++)
+ {
+ if ( chapter && !Q_stricmp(m_ChapterPanels[i]->GetChapter(), chapter) )
+ {
+ m_iSelectedChapter = i;
+ m_ChapterPanels[m_iSelectedChapter]->SetSelected( true );
+ }
+ else
+ {
+ m_ChapterPanels[i]->SetSelected( false );
+ }
+ }
+
+ if ( m_pPlayButton )
+ {
+ m_pPlayButton->SetEnabled( true );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// iUnlockedChapter - the value of sv_unlockedchapters, 1-based. A value of 0
+// is treated as a 1, since at least one chapter must be unlocked.
+//
+// i - the 1-based index of the chapter we're considering.
+//-----------------------------------------------------------------------------
+void CNewGameDialog::UpdatePanelLockedStatus( int iUnlockedChapter, int i, CGameChapterPanel *pChapterPanel )
+{
+ if ( iUnlockedChapter <= 0 )
+ {
+ iUnlockedChapter = 1;
+ }
+
+ // Commentary mode requires chapters to be finished before they can be chosen
+ bool bLocked = false;
+
+ if ( m_bCommentaryMode )
+ {
+ bLocked = ( iUnlockedChapter <= i );
+ }
+ else
+ {
+ if ( iUnlockedChapter < i )
+ {
+ // Never lock the first chapter
+ bLocked = ( i != 0 );
+ }
+ }
+
+ pChapterPanel->SetEnabled( !bLocked );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called before a panel scroll starts.
+//-----------------------------------------------------------------------------
+void CNewGameDialog::PreScroll( EScrollDirection dir )
+{
+ int hideIdx = INVALID_INDEX;
+ if ( dir == SCROLL_LEFT )
+ {
+ hideIdx = m_PanelIndex[SLOT_LEFT];
+ }
+ else if ( dir == SCROLL_RIGHT )
+ {
+ hideIdx = m_PanelIndex[SLOT_RIGHT];
+ }
+ if ( hideIdx != INVALID_INDEX )
+ {
+ // Push back the panel that's about to be hidden
+ // so the next panel scrolls over the top of it.
+ m_ChapterPanels[hideIdx]->SetZPos( 0 );
+ }
+
+ // Flip the active title label prior to the crossfade
+ m_ActiveTitleIdx ^= 0x01;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called after a panel scroll finishes.
+//-----------------------------------------------------------------------------
+void CNewGameDialog::PostScroll( EScrollDirection dir )
+{
+ int index = INVALID_INDEX;
+ if ( dir == SCROLL_LEFT )
+ {
+ index = m_PanelIndex[SLOT_RIGHT];
+ }
+ else if ( dir == SCROLL_RIGHT )
+ {
+ index = m_PanelIndex[SLOT_LEFT];
+ }
+
+ // Fade in the revealed panel
+ if ( index != INVALID_INDEX )
+ {
+ CGameChapterPanel *panel = m_ChapterPanels[index];
+ panel->SetZPos( 50 );
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( BonusMapsDatabase()->BonusesUnlocked() && m_bScrollToFirstBonusMap )
+ {
+ if ( !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() )
+ {
+ // Find the first bonus
+ ScrollSelectionPanels( SCROLL_LEFT );
+ }
+ else
+ {
+ // Found a bonus, stop scrolling
+ m_bScrollToFirstBonusMap = false;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initiates a panel scroll and starts the animation.
+//-----------------------------------------------------------------------------
+void CNewGameDialog::ScrollSelectionPanels( EScrollDirection dir )
+{
+ // Only initiate a scroll if panels aren't currently scrolling
+ if ( !m_bScrolling )
+ {
+ // Handle any pre-scroll setup
+ PreScroll( dir );
+
+ if ( dir == SCROLL_LEFT)
+ {
+ m_ScrollCt += SCROLL_LEFT;
+ }
+ else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 )
+ {
+ m_ScrollCt += SCROLL_RIGHT;
+ }
+
+ m_bScrolling = true;
+ AnimateSelectionPanels();
+
+ // Update the arrow colors, help text, and buttons. Doing it here looks better than having
+ // the components change after the entire scroll animation has finished.
+ UpdateMenuComponents( m_ScrollDirection );
+ }
+}
+
+void CNewGameDialog::ScrollBonusSelection( EScrollDirection dir )
+{
+ // Don't scroll if there's no bonuses for this panel
+ if ( !m_pBonusMapDescription )
+ return;
+
+ m_iBonusSelection += dir;
+
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ UpdateBonusSelection();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initiates the scripted scroll and fade effects of all five slotted panels
+//-----------------------------------------------------------------------------
+void CNewGameDialog::AnimateSelectionPanels( void )
+{
+ int idxOffset = 0;
+ int startIdx = SLOT_LEFT;
+ int endIdx = SLOT_RIGHT;
+
+ // Don't scroll outside the bounds of the panel list
+ if ( m_ScrollCt >= SCROLL_LEFT && (m_PanelIndex[SLOT_CENTER] < m_ChapterPanels.Count() - 1 || !GameUI().IsConsoleUI()) )
+ {
+ idxOffset = -1;
+ endIdx = SLOT_OFFRIGHT;
+ m_ScrollDirection = SCROLL_LEFT;
+ }
+ else if ( m_ScrollCt <= SCROLL_RIGHT && (m_PanelIndex[SLOT_CENTER] > 0 || !GameUI().IsConsoleUI()) )
+ {
+ idxOffset = 1;
+ startIdx = SLOT_OFFLEFT;
+ m_ScrollDirection = SCROLL_RIGHT;
+ }
+
+ if ( 0 == idxOffset )
+ {
+ // Kill the scroll, it's outside the bounds
+ m_ScrollCt = 0;
+ m_bScrolling = false;
+ m_ScrollDirection = SCROLL_NONE;
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ return;
+ }
+
+ // Should never happen
+ if ( startIdx > endIdx )
+ return;
+
+ for ( int i = startIdx; i <= endIdx; ++i )
+ {
+ if ( m_PanelIndex[i] != INVALID_INDEX )
+ {
+ int nextIdx = i + idxOffset;
+ CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[i] ];
+ GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+ }
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ // Animate the center background panel
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ // Crossfade the chapter title labels
+ int inactiveTitleIdx = m_ActiveTitleIdx ^ 0x01;
+ GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[(unsigned)m_ActiveTitleIdx], "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[inactiveTitleIdx], "alpha", 0, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ // Scrolling up through chapters, offset is negative
+ m_iSelectedChapter -= idxOffset;
+ }
+
+ PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: After a scroll, each panel slot holds the index of a panel that has
+// scrolled to an adjacent slot. This function updates each slot so
+// it holds the index of the panel that is actually in that slot's position.
+//-----------------------------------------------------------------------------
+void CNewGameDialog::ShiftPanelIndices( int offset )
+{
+ // Shift all the elements over one slot, then calculate what the last slot's index should be.
+ int lastSlot = NUM_SLOTS - 1;
+ if ( offset > 0 )
+ {
+ // Hide the panel that's dropping out of the slots
+ if ( IsValidPanel( m_PanelIndex[0] ) )
+ {
+ m_ChapterPanels[ m_PanelIndex[0] ]->SetVisible( false );
+ }
+
+ // Scrolled panels to the right, so shift the indices one slot to the left
+ Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) );
+ if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
+ {
+ int num = m_PanelIndex[ lastSlot ] + 1;
+ if ( IsValidPanel( num ) )
+ {
+ m_PanelIndex[lastSlot] = num;
+ InitPanelIndexForDisplay( lastSlot );
+ }
+ else
+ {
+ m_PanelIndex[lastSlot] = INVALID_INDEX;
+ }
+ }
+ }
+ else
+ {
+ // Hide the panel that's dropping out of the slots
+ if ( IsValidPanel( m_PanelIndex[lastSlot] ) )
+ {
+ m_ChapterPanels[ m_PanelIndex[lastSlot] ]->SetVisible( false );
+ }
+
+ // Scrolled panels to the left, so shift the indices one slot to the right
+ Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) );
+ if ( m_PanelIndex[0] != INVALID_INDEX )
+ {
+ int num = m_PanelIndex[0] - 1;
+ if ( IsValidPanel( num ) )
+ {
+ m_PanelIndex[0] = num;
+ InitPanelIndexForDisplay( 0 );
+ }
+ else
+ {
+ m_PanelIndex[0] = INVALID_INDEX;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Validates an index into the selection panels vector
+//-----------------------------------------------------------------------------
+bool CNewGameDialog::IsValidPanel( const int idx )
+{
+ if ( idx < 0 || idx >= m_ChapterPanels.Count() )
+ return false;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up a panel's properties before it is displayed
+//-----------------------------------------------------------------------------
+void CNewGameDialog::InitPanelIndexForDisplay( const int idx )
+{
+ CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[idx] ];
+ if ( panel )
+ {
+ panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] );
+ panel->SetAlpha( m_PanelAlpha[idx] );
+ panel->SetVisible( true );
+ if ( m_PanelAlpha[idx] )
+ {
+ panel->SetZPos( 50 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets which scroll speed should be used
+//-----------------------------------------------------------------------------
+void CNewGameDialog::SetFastScroll( bool fast )
+{
+ m_ScrollSpeed = fast ? g_ScrollSpeedFast : g_ScrollSpeedSlow;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks if a button is being held down, and speeds up the scroll
+//-----------------------------------------------------------------------------
+void CNewGameDialog::ContinueScrolling( void )
+{
+ if ( !GameUI().IsConsoleUI() )
+ {
+ if ( m_PanelIndex[SLOT_CENTER-1] % 3 )
+ {
+ // m_ButtonPressed = m_ScrollDirection;
+ ScrollSelectionPanels( m_ScrollDirection );
+ }
+ return;
+ }
+
+ if ( m_ButtonPressed == m_ScrollDirection )
+ {
+ SetFastScroll( true );
+ ScrollSelectionPanels( m_ScrollDirection );
+ }
+ else if ( m_ButtonPressed != SCROLL_NONE )
+ {
+ // The other direction has been pressed - start a slow scroll
+ SetFastScroll( false );
+ ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed );
+ }
+ else
+ {
+ SetFastScroll( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when a scroll distance of one slot has been completed
+//-----------------------------------------------------------------------------
+void CNewGameDialog::FinishScroll( void )
+{
+ // Fade the center bg panel back in
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ ShiftPanelIndices( m_ScrollDirection );
+ m_bScrolling = false;
+ m_ScrollCt = 0;
+
+ // End of scroll step
+ PostScroll( m_ScrollDirection );
+
+ // Continue scrolling if necessary
+ ContinueScrolling();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: starts the game at the specified skill level
+//-----------------------------------------------------------------------------
+void CNewGameDialog::StartGame( void )
+{
+ if ( m_ChapterPanels.IsValidIndex( m_iSelectedChapter ) )
+ {
+ char mapcommand[512];
+ mapcommand[0] = 0;
+ Q_snprintf( mapcommand, sizeof( mapcommand ), "disconnect\ndeathmatch 0\nprogress_enable\nexec %s\n", m_ChapterPanels[m_iSelectedChapter]->GetConfigFile() );
+
+ // Set commentary
+ ConVarRef commentary( "commentary" );
+ commentary.SetValue( m_bCommentaryMode );
+
+ ConVarRef sv_cheats( "sv_cheats" );
+ sv_cheats.SetValue( m_bCommentaryMode );
+
+ if ( IsPC() )
+ {
+ // If commentary is on, we go to the explanation dialog (but not for teaser trailers)
+ if ( m_bCommentaryMode && !m_ChapterPanels[m_iSelectedChapter]->IsTeaserChapter() )
+ {
+ // Check our current state and disconnect us from any multiplayer server we're connected to.
+ // This fixes an exploit where players would click "start" on the commentary dialog to enable
+ // sv_cheats on the client (via the code above) and then hit <esc> to get out of the explanation dialog.
+ if ( GameUI().IsInMultiplayer() )
+ {
+ engine->ExecuteClientCmd( "disconnect" );
+ }
+
+ DHANDLE<CCommentaryExplanationDialog> hCommentaryExplanationDialog;
+ if ( !hCommentaryExplanationDialog.Get() )
+ {
+ hCommentaryExplanationDialog = new CCommentaryExplanationDialog( BasePanel(), mapcommand );
+ }
+ hCommentaryExplanationDialog->Activate();
+ }
+ else
+ {
+ // start map
+ BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand );
+ }
+ }
+ else if ( IsX360() )
+ {
+ if ( m_ChapterPanels[m_iSelectedChapter]->HasBonus() && m_iBonusSelection > 0 )
+ {
+ if ( m_iBonusSelection == 1 )
+ {
+ // Run the advanced chamber instead of the config file
+ char *pLastSpace = Q_strrchr( mapcommand, '\n' );
+ pLastSpace[ 0 ] = '\0';
+ pLastSpace = Q_strrchr( mapcommand, '\n' );
+
+ Q_snprintf( pLastSpace, sizeof( mapcommand ) - Q_strlen( mapcommand ), "\nmap %s_advanced\n", m_pBonusMapDescription->szMapFileName );
+ }
+ else
+ {
+ char sz[ 256 ];
+
+ int iChallenge = m_iBonusSelection - 1;
+
+ // Set up the challenge mode
+ Q_snprintf( sz, sizeof( sz ), "sv_bonus_challenge %i\n", iChallenge );
+ engine->ClientCmd_Unrestricted( sz );
+
+ ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge - 1 ]);
+
+ // Set up medal goals
+ BonusMapsDatabase()->SetCurrentChallengeObjectives( pChallengeDescription->iBronze, pChallengeDescription->iSilver, pChallengeDescription->iGold );
+ BonusMapsDatabase()->SetCurrentChallengeNames( m_pBonusMapDescription->szFileName, m_pBonusMapDescription->szMapName, pChallengeDescription->szName );
+ }
+ }
+
+ m_bMapStarting = true;
+ BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand );
+ }
+
+ OnClose();
+ }
+}
+
+void CNewGameDialog::OnClose( void )
+{
+ m_KeyRepeat.Reset();
+
+ if ( GameUI().IsConsoleUI() && !m_bMapStarting )
+ {
+ BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" );
+ BonusMapsDatabase()->WriteSaveData(); // Closing this dialog is a good time to save
+ }
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles button commands
+//-----------------------------------------------------------------------------
+void CNewGameDialog::OnCommand( const char *command )
+{
+ bool bReset = true;
+
+ if ( !stricmp( command, "Play" ) )
+ {
+ if ( m_bMapStarting )
+ return;
+
+ if ( GameUI().IsConsoleUI() )
+ {
+ if ( m_ChapterPanels[m_iSelectedChapter]->IsEnabled() )
+ {
+ if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ BasePanel()->ShowMessageDialog( MD_SAVE_BEFORE_NEW_GAME, this );
+ }
+ else
+ {
+ OnCommand( "StartNewGame" );
+ }
+ }
+ else
+ {
+ // This chapter isn't unlocked!
+ m_bMapStarting = false;
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+
+ if ( m_bCommentaryMode )
+ {
+ BasePanel()->ShowMessageDialog( MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION, this );
+ }
+ }
+ }
+ else
+ {
+ StartGame();
+ }
+ }
+
+#ifdef _X360
+ else if ( !stricmp( command, "StartNewGame" ) )
+ {
+ ConVarRef commentary( "commentary" );
+
+ if ( m_bCommentaryMode && !commentary.GetBool() )
+ {
+ // Using the commentary menu, but not already in commentary mode, explain the rules
+ PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithCommentaryExplanation" ), 0.2f );
+ }
+ else
+ {
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED ||
+ !ModInfo().IsSinglePlayerOnly() )
+ {
+ // Multiplayer or no storage device so don't bore them with autosave details
+ m_bMapStarting = true;
+ OnCommand( "StartNewGameNoCommentaryExplanation" );
+ }
+ else
+ {
+ // Don't allow other inputs
+ m_bMapStarting = true;
+
+ // Remind them how autosaves work
+ PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithAutosaveExplanation" ), 0.2f );
+ }
+ }
+ }
+ else if ( !stricmp( command, "StartNewGameWithAutosaveExplanation" ) )
+ {
+ BasePanel()->ShowMessageDialog( MD_AUTOSAVE_EXPLANATION, this );
+ }
+ else if ( !stricmp( command, "StartNewGameWithCommentaryExplanation" ) )
+ {
+ if ( ModInfo().IsSinglePlayerOnly() )
+ {
+ // Don't allow other inputs
+ m_bMapStarting = true;
+ BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION, this );
+ }
+ else
+ {
+ // Don't allow other inputs
+ m_bMapStarting = true;
+ BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION_MULTI, this );
+ }
+ }
+ else if ( !stricmp( command, "StartNewGameNoCommentaryExplanation" ) )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ BasePanel()->RunAnimationWithCallback( this, "CloseNewGameDialog", new KeyValues( "StartGame" ) );
+ }
+#endif
+
+ else if ( !stricmp( command, "Next" ) )
+ {
+ if ( m_bMapStarting )
+ return;
+
+ ScrollSelectionPanels( SCROLL_LEFT );
+ bReset = false;
+ }
+ else if ( !stricmp( command, "Prev" ) )
+ {
+ if ( m_bMapStarting )
+ return;
+
+ ScrollSelectionPanels( SCROLL_RIGHT );
+ bReset = false;
+ }
+ else if ( !stricmp( command, "Mode_Next" ) )
+ {
+ if ( m_bMapStarting )
+ return;
+
+ ScrollBonusSelection( SCROLL_LEFT );
+ bReset = false;
+ }
+ else if ( !stricmp( command, "Mode_Prev" ) )
+ {
+ if ( m_bMapStarting )
+ return;
+
+ ScrollBonusSelection( SCROLL_RIGHT );
+ bReset = false;
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+
+ if ( bReset )
+ {
+ m_KeyRepeat.Reset();
+ }
+}
+
+void CNewGameDialog::PaintBackground()
+{
+ if ( !GameUI().IsConsoleUI() )
+ {
+ BaseClass::PaintBackground();
+ return;
+ }
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ Color col = GetBgColor();
+ DrawBox( 0, 0, wide, tall, col, 1.0f );
+
+ int y = 0;
+ if ( m_pChapterTitleLabels[0] )
+ {
+ // offset by title
+ int titleX, titleY, titleWide, titleTall;
+ m_pChapterTitleLabels[0]->GetBounds( titleX, titleY, titleWide, titleTall );
+ y += titleY + titleTall;
+ }
+ else
+ {
+ y = 8;
+ }
+
+ // draw an inset
+ Color darkColor;
+ darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() );
+ vgui::surface()->DrawSetColor( darkColor );
+ vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 );
+}
+
+void CNewGameDialog::OnKeyCodePressed( KeyCode code )
+{
+ switch ( code )
+ {
+ case KEY_XBUTTON_LEFT:
+ case KEY_XSTICK1_LEFT:
+ case KEY_XSTICK2_LEFT:
+ case KEY_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ if ( !m_bScrolling )
+ {
+ for ( int i = 0; i < m_ChapterPanels.Count(); ++i )
+ {
+ if ( m_ChapterPanels[ i ]->IsSelected() )
+ {
+ int nNewChapter = i - 1;
+ if ( nNewChapter >= 0 )
+ {
+ if ( nNewChapter < m_PanelIndex[ SLOT_LEFT ] && m_PanelIndex[ SLOT_LEFT ] != -1 )
+ {
+ ScrollSelectionPanels( SCROLL_RIGHT );
+ }
+ else if ( m_ChapterPanels[ nNewChapter ]->IsEnabled() )
+ {
+ SetSelectedChapterIndex( nNewChapter );
+ }
+ }
+ break;
+ }
+ }
+ }
+ return;
+
+ case KEY_XBUTTON_RIGHT:
+ case KEY_XSTICK1_RIGHT:
+ case KEY_XSTICK2_RIGHT:
+ case KEY_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ if ( !m_bScrolling )
+ {
+ for ( int i = 0; i < m_ChapterPanels.Count(); ++i )
+ {
+ if ( m_ChapterPanels[ i ]->IsSelected() )
+ {
+ int nNewChapter = i + 1;
+ if ( nNewChapter < m_ChapterPanels.Count() )
+ {
+ if ( nNewChapter > m_PanelIndex[ SLOT_RIGHT ] && m_PanelIndex[ SLOT_RIGHT ] != -1 )
+ {
+ ScrollSelectionPanels( SCROLL_LEFT );
+ }
+ else if ( m_ChapterPanels[ nNewChapter ]->IsEnabled() )
+ {
+ SetSelectedChapterIndex( nNewChapter );
+ }
+ }
+ break;
+ }
+ }
+ }
+ return;
+
+ case KEY_XBUTTON_B:
+ case STEAMCONTROLLER_B:
+ OnCommand( "Close" );
+ return;
+
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+ OnCommand( "Play" );
+ return;
+ }
+
+ m_KeyRepeat.KeyDown( code );
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+void CNewGameDialog::OnKeyCodeReleased( vgui::KeyCode code )
+{
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+}
+
+void CNewGameDialog::OnThink()
+{
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ OnKeyCodeTyped( code );
+ }
+
+ BaseClass::OnThink();
+}
diff --git a/gameui/NewGameDialog.h b/gameui/NewGameDialog.h
new file mode 100644
index 0000000..03aebd4
--- /dev/null
+++ b/gameui/NewGameDialog.h
@@ -0,0 +1,155 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef NEWGAMEDIALOG_H
+#define NEWGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+#include "vgui_controls/KeyRepeat.h"
+#include "utlvector.h"
+
+class CGameChapterPanel;
+class CSkillSelectionDialog;
+
+// Slot indices in new game menu
+#define INVALID_INDEX -1
+#define SLOT_OFFLEFT 0
+#define SLOT_LEFT 1
+#define SLOT_CENTER 2
+#define SLOT_RIGHT 3
+#define SLOT_OFFRIGHT 4
+#define NUM_SLOTS 5
+
+
+class CNewGamePlayButton : public vgui::Button
+{
+ DECLARE_CLASS_SIMPLE( CNewGamePlayButton, vgui::Button );
+
+public:
+
+ CNewGamePlayButton( Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget=NULL, const char *pCmd=NULL )
+ : vgui::Button( parent, panelName, text, pActionSignalTarget, pCmd )
+ {
+ }
+
+ void OnKeyCodePressed( vgui::KeyCode code )
+ {
+ if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ ConVarRef var( "joystick" );
+ if ( var.IsValid() && !var.GetBool() )
+ {
+ var.SetValue( true );
+ }
+
+ ConVarRef var2( "hud_fastswitch" );
+ if ( var2.IsValid() && var2.GetInt() != 2 )
+ {
+ var2.SetValue( 2 );
+ }
+ DoClick();
+ return;
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles starting a new game, skill and chapter selection
+//-----------------------------------------------------------------------------
+class CNewGameDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CNewGameDialog, vgui::Frame );
+
+public:
+ MESSAGE_FUNC( FinishScroll, "FinishScroll" );
+ MESSAGE_FUNC( StartGame, "StartGame" );
+
+ CNewGameDialog(vgui::Panel *parent, bool bCommentaryMode );
+ ~CNewGameDialog();
+
+ virtual void Activate( void );
+
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnCommand( const char *command );
+ virtual void OnClose( void );
+ virtual void PaintBackground();
+ void SetSelectedChapterIndex( int index );
+ void SetSelectedChapter( const char *chapter );
+ void UpdatePanelLockedStatus( int iUnlockedChapter, int i, CGameChapterPanel *pChapterPanel );
+
+ void SetCommentaryMode( bool bCommentary ) { m_bCommentaryMode = bCommentary; }
+
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnKeyCodeReleased( vgui::KeyCode code );
+ virtual void OnThink();
+
+ // Xbox: Defined values are also used to shift the slot indices
+ enum EScrollDirection
+ {
+ SCROLL_RIGHT = -1,
+ SCROLL_NONE = 0,
+ SCROLL_LEFT = 1
+ };
+ EScrollDirection m_ScrollDirection;
+
+private:
+ int m_iSelectedChapter;
+
+ CUtlVector<CGameChapterPanel *> m_ChapterPanels;
+
+ vgui::DHANDLE<CSkillSelectionDialog> m_hSkillSelectionDialog;
+
+ vgui::Button *m_pPlayButton;
+ vgui::Button *m_pNextButton;
+ vgui::Button *m_pPrevButton;
+ vgui::Panel *m_pCenterBg;
+ vgui::Label *m_pChapterTitleLabels[2];
+ vgui::Label *m_pBonusSelection;
+ vgui::ImagePanel *m_pBonusSelectionBorder;
+ CFooterPanel *m_pFooter;
+ bool m_bCommentaryMode;
+ vgui::Label *m_pCommentaryLabel;
+
+ // Xbox
+ void ScrollSelectionPanels( EScrollDirection dir );
+ void ScrollBonusSelection( EScrollDirection dir );
+ void PreScroll( EScrollDirection dir );
+ void PostScroll( EScrollDirection dir );
+ void SetFastScroll( bool fast );
+ void ContinueScrolling( void );
+ void AnimateSelectionPanels( void );
+ void ShiftPanelIndices( int offset );
+ bool IsValidPanel( const int idx );
+ void InitPanelIndexForDisplay( const int idx );
+ void UpdateMenuComponents( EScrollDirection dir );
+ void UpdateBonusSelection( void );
+
+ int m_PanelXPos[ NUM_SLOTS ];
+ int m_PanelYPos[ NUM_SLOTS ];
+ float m_PanelAlpha[ NUM_SLOTS ];
+ int m_PanelIndex[ NUM_SLOTS ];
+ float m_ScrollSpeed;
+ int m_ButtonPressed;
+ int m_ScrollCt;
+ bool m_bScrolling;
+ char m_ActiveTitleIdx;
+ bool m_bMapStarting;
+ int m_iBonusSelection;
+ bool m_bScrollToFirstBonusMap;
+
+ struct BonusMapDescription_t *m_pBonusMapDescription;
+
+ vgui::CKeyRepeatHandler m_KeyRepeat;
+};
+
+#endif // NEWGAMEDIALOG_H
diff --git a/gameui/OptionsDialog.cpp b/gameui/OptionsDialog.cpp
new file mode 100644
index 0000000..b1dedfe
--- /dev/null
+++ b/gameui/OptionsDialog.cpp
@@ -0,0 +1,155 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "OptionsDialog.h"
+
+#include "vgui_controls/Button.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/PropertySheet.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/QueryBox.h"
+
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+
+#include "KeyValues.h"
+#include "OptionsSubKeyboard.h"
+#include "OptionsSubMouse.h"
+#include "OptionsSubAudio.h"
+#include "OptionsSubVideo.h"
+#include "OptionsSubVoice.h"
+#include "OptionsSubMultiplayer.h"
+#include "OptionsSubDifficulty.h"
+#include "OptionsSubPortal.h"
+#ifdef WIN32
+// NVNT haptic configuration dialog
+#include "OptionsSubHaptics.h"
+#endif
+#include "ModInfo.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic help dialog
+//-----------------------------------------------------------------------------
+COptionsDialog::COptionsDialog(vgui::Panel *parent) : PropertyDialog(parent, "OptionsDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 512, 406);
+ SetSizeable( false );
+
+ SetTitle("#GameUI_Options", true);
+
+ // debug timing code, this function takes too long
+// double s4 = system()->GetCurrentTime();
+
+#if defined( WIN32 ) && !defined( _X360 )
+ // NVNT START see if the user has a haptic device via convar. if so create haptics dialog.
+ ConVarRef checkHap("hap_HasDevice");
+ checkHap.Init("hap_HasDevice",true);
+ if(checkHap.GetBool())
+ {
+ AddPage(new COptionsSubHaptics(this), "#GameUI_Haptics_TabTitle");
+ }
+ // NVNT END
+#endif
+ if (ModInfo().IsSinglePlayerOnly() && !ModInfo().NoDifficulty())
+ {
+ AddPage(new COptionsSubDifficulty(this), "#GameUI_Difficulty");
+ }
+
+ if (ModInfo().HasPortals())
+ {
+ AddPage(new COptionsSubPortal(this), "#GameUI_Portal");
+ }
+
+ AddPage(new COptionsSubKeyboard(this), "#GameUI_Keyboard");
+ AddPage(new COptionsSubMouse(this), "#GameUI_Mouse");
+
+ m_pOptionsSubAudio = new COptionsSubAudio(this);
+ AddPage(m_pOptionsSubAudio, "#GameUI_Audio");
+ m_pOptionsSubVideo = new COptionsSubVideo(this);
+ AddPage(m_pOptionsSubVideo, "#GameUI_Video");
+
+ if ( !ModInfo().IsSinglePlayerOnly() )
+ {
+ AddPage(new COptionsSubVoice(this), "#GameUI_Voice");
+ }
+
+ // add the multiplay page last, if we're combo single/multi or just multi
+ if ( (ModInfo().IsMultiplayerOnly() && !ModInfo().IsSinglePlayerOnly()) ||
+ (!ModInfo().IsMultiplayerOnly() && !ModInfo().IsSinglePlayerOnly()) )
+ {
+ m_pOptionsSubMultiplayer = new COptionsSubMultiplayer(this);
+ AddPage(m_pOptionsSubMultiplayer, "#GameUI_Multiplayer");
+ }
+
+// double s5 = system()->GetCurrentTime();
+// Msg("COptionsDialog::COptionsDialog(): %.3fms\n", (float)(s5 - s4) * 1000.0f);
+
+ SetApplyButtonVisible(true);
+ GetPropertySheet()->SetTabWidth(84);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+COptionsDialog::~COptionsDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Brings the dialog to the fore
+//-----------------------------------------------------------------------------
+void COptionsDialog::Activate()
+{
+ BaseClass::Activate();
+ EnableApplyButton(false);
+}
+
+void COptionsDialog::OnKeyCodePressed( KeyCode code )
+{
+ switch ( GetBaseButtonCode( code ) )
+ {
+ case KEY_XBUTTON_B:
+ OnCommand( "Cancel" );
+ return;
+ }
+
+ BaseClass::OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens the dialog
+//-----------------------------------------------------------------------------
+void COptionsDialog::Run()
+{
+ SetTitle("#GameUI_Options", true);
+ Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when the GameUI is hidden
+//-----------------------------------------------------------------------------
+void COptionsDialog::OnGameUIHidden()
+{
+ // tell our children about it
+ for ( int i = 0 ; i < GetChildCount() ; i++ )
+ {
+ Panel *pChild = GetChild( i );
+ if ( pChild )
+ {
+ PostMessage( pChild, new KeyValues( "GameUIHidden" ) );
+ }
+ }
+}
diff --git a/gameui/OptionsDialog.h b/gameui/OptionsDialog.h
new file mode 100644
index 0000000..c21baa9
--- /dev/null
+++ b/gameui/OptionsDialog.h
@@ -0,0 +1,141 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONSDIALOG_H
+#define OPTIONSDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PropertyDialog.h"
+#include "vgui_controls/KeyRepeat.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Holds all the game option pages
+//-----------------------------------------------------------------------------
+class COptionsDialog : public vgui::PropertyDialog
+{
+ DECLARE_CLASS_SIMPLE( COptionsDialog, vgui::PropertyDialog );
+
+public:
+ COptionsDialog(vgui::Panel *parent);
+ ~COptionsDialog();
+
+ void Run();
+ virtual void Activate();
+
+ void OnKeyCodePressed( vgui::KeyCode code );
+
+ vgui::PropertyPage* GetOptionsSubMultiplayer( void ) { return m_pOptionsSubMultiplayer; }
+
+ MESSAGE_FUNC( OnGameUIHidden, "GameUIHidden" ); // called when the GameUI is hidden
+
+private:
+ class COptionsSubAudio *m_pOptionsSubAudio;
+ class COptionsSubVideo *m_pOptionsSubVideo;
+ vgui::PropertyPage *m_pOptionsSubMultiplayer;
+};
+
+
+#define OPTIONS_MAX_NUM_ITEMS 15
+
+struct OptionData_t;
+
+//-----------------------------------------------------------------------------
+// Purpose: Holds all the game option pages
+//-----------------------------------------------------------------------------
+class COptionsDialogXbox : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsDialogXbox, vgui::Frame );
+
+public:
+ COptionsDialogXbox( vgui::Panel *parent, bool bControllerOptions = false );
+ ~COptionsDialogXbox();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void OnClose();
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnCommand(const char *command);
+
+ virtual void OnKeyCodeReleased( vgui::KeyCode code);
+ virtual void OnThink();
+
+private:
+ void HandleInactiveKeyCodePressed( vgui::KeyCode code );
+ void HandleActiveKeyCodePressed( vgui::KeyCode code );
+ void HandleBindKeyCodePressed( vgui::KeyCode code );
+
+ int GetSelectionLabel( void ) { return m_iSelection - m_iScroll; }
+
+ void ActivateSelection( void );
+ void DeactivateSelection( void );
+
+ void ChangeSelection( int iChange );
+ void UpdateFooter( void );
+ void UpdateSelection( void );
+ void UpdateScroll( void );
+
+ void UncacheChoices( void );
+ void GetChoiceFromConvar( OptionData_t *pOption );
+ void ChangeValue( float fChange );
+ void UnbindOption( OptionData_t *pOption, int iLabel );
+
+ void UpdateValue( OptionData_t *pOption, int iLabel );
+ void UpdateBind( OptionData_t *pOption, int iLabel, ButtonCode_t codeIgnore = BUTTON_CODE_INVALID, ButtonCode_t codeAdd = BUTTON_CODE_INVALID );
+ void UpdateAllBinds( ButtonCode_t code );
+
+ void FillInDefaultBindings( void );
+
+ bool ShouldSkipOption( KeyValues *pKey );
+ void ReadOptionsFromFile( const char *pchFileName );
+ void SortOptions( void );
+
+ void InitializeSliderDefaults( void );
+
+private:
+ bool m_bControllerOptions;
+ bool m_bOptionsChanged;
+ bool m_bOldForceEnglishAudio;
+
+ CFooterPanel *m_pFooter;
+
+ CUtlVector<OptionData_t*> *m_pOptions;
+
+ bool m_bSelectionActive;
+ OptionData_t *m_pSelectedOption;
+
+ int m_iSelection;
+ int m_iScroll;
+ int m_iSelectorYStart;
+ int m_iOptionSpacing;
+ int m_iNumItems;
+
+ int m_iXAxisState;
+ int m_iYAxisState;
+ float m_fNextChangeTime;
+
+ vgui::Panel *m_pOptionsSelectionLeft;
+ vgui::Panel *m_pOptionsSelectionLeft2;
+ vgui::Label *m_pOptionsUpArrow;
+ vgui::Label *m_pOptionsDownArrow;
+
+ vgui::Label *(m_pOptionLabels[ OPTIONS_MAX_NUM_ITEMS ]);
+ vgui::Label *(m_pValueLabels[ OPTIONS_MAX_NUM_ITEMS ]);
+ vgui::AnalogBar *(m_pValueBars[ OPTIONS_MAX_NUM_ITEMS ]);
+
+ vgui::HFont m_hLabelFont;
+ vgui::HFont m_hButtonFont;
+
+ Color m_SelectedColor;
+
+ vgui::CKeyRepeatHandler m_KeyRepeat;
+
+ int m_nButtonGap;
+};
+
+#endif // OPTIONSDIALOG_H
diff --git a/gameui/OptionsDialog_Xbox.cpp b/gameui/OptionsDialog_Xbox.cpp
new file mode 100644
index 0000000..9db9d0a
--- /dev/null
+++ b/gameui/OptionsDialog_Xbox.cpp
@@ -0,0 +1,1683 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "OptionsDialog.h"
+
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+
+#include <vgui_controls/AnalogBar.h>
+
+#ifdef _X360
+ #include "xbox/xbox_launch.h"
+#endif
+#include "IGameUIFuncs.h"
+#include "GameUI_Interface.h"
+#include "inputsystem/iinputsystem.h"
+#include "EngineInterface.h"
+#include "KeyValues.h"
+#include "ModInfo.h"
+#include "matchmaking/matchmakingbasepanel.h"
+#include "vgui_controls/AnimationController.h"
+
+#include "tier1/utlbuffer.h"
+#include "filesystem.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#define OPTION_STRING_LENGTH 64
+
+
+ConVar binds_per_command( "binds_per_command", "1", 0 );
+
+ConVar x360_resolution_widescreen_mode( "x360_resolution_widescreen_mode", "0", 0, "This is only used for reference. Changing this value does nothing" );
+ConVar x360_resolution_width( "x360_resolution_width", "640", 0, "This is only used for reference. Changing this value does nothing" );
+ConVar x360_resolution_height( "x360_resolution_height", "480", 0, "This is only used for reference. Changing this value does nothing" );
+ConVar x360_resolution_interlaced( "x360_resolution_interlaced", "0", 0, "This is only used for reference. Changing this value does nothing" );
+
+ConVar x360_audio_english("x360_audio_english", "0", 0, "Keeps track of whether we're forcing english in a localized language." );
+
+
+enum OptionType_e
+{
+ OPTION_TYPE_BINARY = 0,
+ OPTION_TYPE_SLIDER,
+ OPTION_TYPE_CHOICE,
+ OPTION_TYPE_BIND,
+
+ OPTION_TYPE_TOTAL
+};
+
+
+enum SliderHomeType_e
+{
+ SLIDER_HOME_NONE = 0,
+ SLIDER_HOME_PREV,
+ SLIDER_HOME_MIN,
+ SLIDER_HOME_CENTER,
+ SLIDER_HOME_MAX,
+
+ SLIDER_HOME_TYPE_TOTAL
+};
+
+
+
+struct OptionChoiceData_t
+{
+ char szName[ OPTION_STRING_LENGTH ];
+ char szValue[ OPTION_STRING_LENGTH ];
+};
+
+struct OptionData_t
+{
+ char szName[ OPTION_STRING_LENGTH ];
+ char szDisplayName[ OPTION_STRING_LENGTH ];
+
+ union
+ {
+ char szConvar[ OPTION_STRING_LENGTH ]; // Used by all types except binds
+ char szCommand[ OPTION_STRING_LENGTH ]; // Used exclusively by bind types
+ };
+
+ char szConvar2[ OPTION_STRING_LENGTH ]; // Used for choice types that use 2 convars
+
+ char szConvarDef[ OPTION_STRING_LENGTH ];
+
+ int iPriority;
+
+ OptionType_e eOptionType;
+
+ bool bUnchangeable;
+ bool bVocalsLanguage;
+
+ // Slider types exclusively use these
+ float fMinValue;
+ float fMaxValue;
+ float fIncValue;
+ float fSliderHomeValue;
+
+ union
+ {
+ SliderHomeType_e eSliderHomeType; // Slider types exclusively use this int
+ int iCurrentChoice; // Choice types exclusively use this int
+ int iNumBinds; // Bind types exclusively use this int
+ };
+
+ CUtlVector<OptionChoiceData_t> m_Choices;
+};
+
+
+class OptionsDataContainer
+{
+public:
+
+ ~OptionsDataContainer()
+ {
+ for ( int iOption = 0; iOption < m_pOptions.Count(); ++iOption )
+ {
+ delete (m_pOptions[ iOption ]);
+ m_pOptions[ iOption ] = 0;
+ }
+
+ for ( int iOption = 0; iOption < m_pControllerOptions.Count(); ++iOption )
+ {
+ delete (m_pControllerOptions[ iOption ]);
+ m_pControllerOptions[ iOption ] = 0;
+ }
+ }
+
+public:
+
+ CUtlVector<OptionData_t*> m_pOptions;
+ CUtlVector<OptionData_t*> m_pControllerOptions;
+
+};
+
+
+static OptionsDataContainer s_OptionsDataContainer;
+
+static CUtlVector<OptionChoiceData_t> s_DisabledOptions;
+
+
+const char *UTIL_Parse( const char *data, char *token, int sizeofToken );
+
+
+bool ActionsAreTheSame( const char *pchAction1, const char *pchAction2 )
+{
+ if ( Q_stricmp( pchAction1, pchAction2 ) == 0 )
+ return true;
+
+ if ( ( Q_stricmp( pchAction1, "+duck" ) == 0 || Q_stricmp( pchAction1, "toggle_duck" ) == 0 ) &&
+ ( Q_stricmp( pchAction2, "+duck" ) == 0 || Q_stricmp( pchAction2, "toggle_duck" ) == 0 ) )
+ {
+ // +duck and toggle_duck are interchangable
+ return true;
+ }
+
+ if ( ( Q_stricmp( pchAction1, "+zoom" ) == 0 || Q_stricmp( pchAction1, "toggle_zoom" ) == 0 ) &&
+ ( Q_stricmp( pchAction2, "+zoom" ) == 0 || Q_stricmp( pchAction2, "toggle_zoom" ) == 0 ) )
+ {
+ // +zoom and toggle_zoom are interchangable
+ return true;
+ }
+
+ return false;
+}
+
+
+COptionsDialogXbox::COptionsDialogXbox( vgui::Panel *parent, bool bControllerOptions ) : BaseClass( parent, "OptionsDialog" )
+{
+#ifdef _X360
+ // Get out current resolution and stuff it into convars for later reference
+ XVIDEO_MODE videoMode;
+ XGetVideoMode( &videoMode );
+ x360_resolution_widescreen_mode.SetValue( videoMode.fIsWideScreen );
+ x360_resolution_width.SetValue( static_cast<int>( videoMode.dwDisplayWidth ) );
+ x360_resolution_height.SetValue( static_cast<int>( videoMode.dwDisplayHeight ) );
+ x360_resolution_interlaced.SetValue( videoMode.fIsInterlaced );
+#endif
+
+ //Figure out which way duck is bound, and set the option_duck_method convar the correct way.
+ const char *pDuckKey = engine->Key_LookupBinding( "+duck" );
+ ButtonCode_t code = g_pInputSystem->StringToButtonCode( pDuckKey );
+ const char *pDuckMode = engine->Key_BindingForKey( code );
+
+ // NOW. If duck key is bound to +DUCK, set the convar to 0. Else, set it to 1.
+ ConVarRef varOption( "option_duck_method" );
+
+ if( pDuckMode != NULL )
+ {
+ if( !Q_stricmp(pDuckMode,"+duck") )
+ {
+ varOption.SetValue( 0 );
+ }
+ else
+ {
+ varOption.SetValue( 1 );
+ }
+ }
+
+ SetSize( 32, 32 );
+ SetDeleteSelfOnClose( true );
+ SetTitleBarVisible( false );
+ SetCloseButtonVisible( false );
+ SetSizeable( false );
+
+ m_pFooter = new CFooterPanel( parent, "OptionsFooter" );
+ m_pFooter->SetStandardDialogButtons();
+
+ m_bControllerOptions = bControllerOptions;
+
+ m_bOptionsChanged = false;
+
+ // Store the old vocal language setting
+ m_bOldForceEnglishAudio = x360_audio_english.GetBool();
+
+ // Get the correct options list
+ if ( !m_bControllerOptions )
+ m_pOptions = &s_OptionsDataContainer.m_pOptions;
+ else
+ m_pOptions = &s_OptionsDataContainer.m_pControllerOptions;
+
+ if ( m_pOptions->Count() == 0 )
+ {
+ // Populate it if it's hasn't been filled
+ ReadOptionsFromFile( "scripts/mod_options.360.txt" );
+ ReadOptionsFromFile( "scripts/options.360.txt" );
+ SortOptions();
+ }
+
+ m_pSelectedOption = NULL;
+
+ m_iSelection = 0;
+ m_iScroll = 0;
+
+ m_iXAxisState = 0;
+ m_iYAxisState = 0;
+ m_fNextChangeTime = 0.0f;
+
+ m_pOptionsSelectionLeft = SETUP_PANEL( new Panel( this, "OptionsSelectionLeft" ) );
+ m_pOptionsSelectionLeft2 = SETUP_PANEL( new Panel( this, "OptionsSelectionLeft2" ) );
+ m_pOptionsUpArrow = new vgui::Label( this, "UpArrow", "" );
+ m_pOptionsDownArrow = new vgui::Label( this, "DownArrow", "" );
+
+ for ( int iLabel = 0; iLabel < OPTIONS_MAX_NUM_ITEMS; ++iLabel )
+ {
+ char szLabelName[ 64 ];
+
+ Q_snprintf( szLabelName, sizeof( szLabelName), "OptionLabel%i", iLabel );
+ m_pOptionLabels[ iLabel ] = new vgui::Label( this, szLabelName, "" );
+
+ Q_snprintf( szLabelName, sizeof( szLabelName), "ValueLabel%i", iLabel );
+ m_pValueLabels[ iLabel ] = new vgui::Label( this, szLabelName, "" );
+
+ Q_snprintf( szLabelName, sizeof( szLabelName), "ValueBar%i", iLabel );
+ m_pValueBars[ iLabel ] = new AnalogBar( this, szLabelName );
+ }
+
+ // Faster repeats for sideways
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XBUTTON_LEFT, 0.08 );
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XBUTTON_RIGHT, 0.08 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::InitializeSliderDefaults( void )
+{
+ for ( int iOption = 0; iOption < m_pOptions->Count(); ++iOption )
+ {
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ if ( pOption->eOptionType != OPTION_TYPE_SLIDER )
+ continue;
+
+ if( pOption->eSliderHomeType != SLIDER_HOME_PREV )
+ continue;
+
+ const char *pszConvarName = pOption->szConvar;
+ if ( pOption->szConvarDef && pOption->szConvarDef[0] )
+ {
+ // They've specified a different convar to use as the default
+ pszConvarName = pOption->szConvarDef;
+ }
+
+ ConVarRef varOption( pszConvarName );
+ pOption->fSliderHomeValue = varOption.GetFloat();
+ }
+}
+
+COptionsDialogXbox::~COptionsDialogXbox()
+{
+ if ( m_bOldForceEnglishAudio != x360_audio_english.GetBool() )
+ {
+#ifdef _X360
+ XboxLaunch()->SetForceEnglish( x360_audio_english.GetBool() );
+#endif
+ PostMessage( BasePanel()->GetVPanel(), new KeyValues( "command", "command", "QuitRestartNoConfirm" ), 0.0f );
+ }
+
+ delete m_pFooter;
+ m_pFooter = NULL;
+}
+
+
+void COptionsDialogXbox::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ m_nButtonGap = inResourceData->GetInt( "footer_buttongap", -1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "OptionsDialog.res" );
+ LoadControlSettings( "null", NULL, pControlSettings );
+
+ if ( m_pFooter )
+ {
+ KeyValues *pFooterControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "OptionsFooter.res" );
+ m_pFooter->LoadControlSettings( "null", NULL, pFooterControlSettings );
+ }
+
+ m_SelectedColor = pScheme->GetColor( "SectionedListPanel.SelectedBgColor", Color(255, 255, 255, 255) );
+
+ m_pOptionsSelectionLeft->SetBgColor( m_SelectedColor );
+ m_pOptionsSelectionLeft->SetAlpha( 96 );
+
+ m_pOptionsSelectionLeft2->SetBgColor( Color(0,0,0,96) );
+
+ int iX, iY;
+ m_pOptionsSelectionLeft->GetPos( iX, m_iSelectorYStart );
+ m_iOptionSpacing = (m_pOptionLabels[ 0 ])->GetTall();
+
+ m_hLabelFont = pScheme->GetFont( "MenuLarge" );
+ m_hButtonFont = pScheme->GetFont( "GameUIButtons" );
+
+ // Decide how many items will fit
+ int iTall = GetTall();
+ m_iNumItems = ( iTall - 70 ) / m_iOptionSpacing;
+
+ if ( m_iNumItems > m_pOptions->Count() )
+ {
+ // There's more space in the dialog than needed, shrink it down
+ m_iNumItems = m_pOptions->Count();
+ iTall = m_iNumItems * m_iOptionSpacing + 70;
+ SetTall( iTall );
+ }
+
+ MoveToCenterOfScreen();
+
+ // Adjust sizes for the number of items
+ vgui::Panel *pPanel = FindChildByName( "OptionsBackgroundLeft" );
+ pPanel->SetTall( iTall - 70 );
+ pPanel = FindChildByName( "OptionsBackgroundRight" );
+ pPanel->SetTall( iTall - 70 );
+
+ m_pOptionsUpArrow->GetPos( iX, iY );
+ m_pOptionsUpArrow->SetPos( iX, iTall - 32 );
+ m_pOptionsDownArrow->GetPos( iX, iY );
+ m_pOptionsDownArrow->SetPos( iX, iTall - 32 );
+
+ m_pValueBars[ 0 ]->SetFgColor( Color( 255, 255, 255, 200 ) );
+ m_pValueBars[ 0 ]->SetBgColor( Color( 255, 255, 255, 32 ) );
+ m_pValueBars[ 0 ]->SetHomeColor( Color( m_SelectedColor[0], m_SelectedColor[1], m_SelectedColor[2], 96 ) );
+
+ // Get proper setting for items for orginal in res file
+ vgui::Panel *(pPanelList[3]) = { m_pOptionLabels[ 0 ], m_pValueLabels[ 0 ], m_pValueBars[ 0 ] };
+
+ for ( int iPanelList = 0; iPanelList < 3; ++iPanelList )
+ {
+ pPanel = pPanelList[ iPanelList ];
+
+ int iZ, iWide;
+ bool bVisible;
+ pPanel->GetPos( iX, iY );
+ iZ = ipanel()->GetZPos( pPanel->GetVPanel() );
+ iWide = pPanel->GetWide();
+ iTall = pPanel->GetTall();
+ bVisible = pPanel->IsVisible();
+
+ for ( int iLabel = 1; iLabel < m_iNumItems; ++iLabel )
+ {
+ if ( iPanelList == 0 )
+ {
+ pPanel = m_pOptionLabels[ iLabel ];
+ m_pOptionLabels[ iLabel ]->SetFont( m_pOptionLabels[ 0 ]->GetFont() );
+ }
+ else if ( iPanelList == 1 )
+ {
+ pPanel = m_pValueLabels[ iLabel ];
+ m_pValueLabels[ iLabel ]->SetFont( m_pValueLabels[ 0 ]->GetFont() );
+ }
+ else if ( iPanelList == 2 )
+ {
+ pPanel = m_pValueBars[ iLabel ];
+ m_pValueBars[ iLabel ]->SetFgColor( m_pValueBars[ 0 ]->GetFgColor() );
+ m_pValueBars[ iLabel ]->SetBgColor( m_pValueBars[ 0 ]->GetBgColor() );
+ m_pValueBars[ iLabel ]->SetHomeColor( m_pValueBars[ 0 ]->GetHomeColor() );
+ }
+
+ pPanel->SetPos( iX, iY + iLabel * m_iOptionSpacing );
+ pPanel->SetZPos( iZ );
+ pPanel->SetWide( iWide );
+ pPanel->SetTall( iTall );
+ pPanel->SetVisible( bVisible );
+ }
+ }
+
+ // Make unused items invisible
+ for ( int iLabel = m_iNumItems; iLabel < OPTIONS_MAX_NUM_ITEMS; ++iLabel )
+ {
+ m_pOptionLabels[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( false );
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ }
+
+ InitializeSliderDefaults();
+ UpdateScroll();
+ DeactivateSelection();
+ UpdateFooter();
+
+ // Don't fade the background for options so that brightness can be easily adjusted
+ if ( !m_bControllerOptions )
+ vgui::GetAnimationController()->RunAnimationCommand( BasePanel(), "m_flBackgroundFillAlpha", 0.01f, 0.0f, 1.0f, AnimationController::INTERPOLATOR_LINEAR );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::OnClose( void )
+{
+ CMatchmakingBasePanel *pBase = BasePanel()->GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->ShowFooter( true );
+ }
+
+ ConVarRef varOption( "option_duck_method" );
+
+ char szCommand[ 256 ];
+
+ for ( int iCode = 0; iCode < BUTTON_CODE_LAST; ++iCode )
+ {
+ ButtonCode_t code = static_cast<ButtonCode_t>( iCode );
+
+ const char *pDuckKeyName = gameuifuncs->GetBindingForButtonCode( code );
+
+ // Check if there's a binding for this key
+ if ( !pDuckKeyName || !pDuckKeyName[0] )
+ continue;
+
+ // If we use this binding, display the key in our list
+ if ( ActionsAreTheSame( pDuckKeyName, "+duck" ) )
+ {
+ if( varOption.GetBool() )
+ {
+ // Bind DUCK key to toggle_duck
+ Q_snprintf( szCommand, sizeof( szCommand ), "bind \"%s\" \"%s\"", g_pInputSystem->ButtonCodeToString( code ), "toggle_duck" );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ else
+ {
+ // Bind DUCK key to +DUCK
+ Q_snprintf( szCommand, sizeof( szCommand ), "bind \"%s\" \"%s\"", g_pInputSystem->ButtonCodeToString( code ), "+DUCK" );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ }
+ }
+
+ // Save these settings!
+ if ( m_bOptionsChanged )
+ engine->ClientCmd_Unrestricted( "host_writeconfig" );
+
+ BasePanel()->RunCloseAnimation( "CloseOptionsDialog_OpenMainMenu" );
+ if ( !m_bControllerOptions )
+ vgui::GetAnimationController()->RunAnimationCommand( BasePanel(), "m_flBackgroundFillAlpha", 120.0f, 0.0f, 1.0f, AnimationController::INTERPOLATOR_LINEAR );
+
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( IsX360() )
+ {
+ if ( GetAlpha() != 255 )
+ {
+ // inhibit key activity during transitions
+ return;
+ }
+ }
+
+ if ( !m_bSelectionActive )
+ HandleInactiveKeyCodePressed( code );
+ else if ( m_pSelectedOption->eOptionType != OPTION_TYPE_BIND )
+ HandleActiveKeyCodePressed( code );
+ else
+ HandleBindKeyCodePressed( code );
+}
+
+void COptionsDialogXbox::OnCommand(const char *command)
+{
+ m_KeyRepeat.Reset();
+
+ if ( !Q_stricmp( command, "DefaultControls" ) )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+ FillInDefaultBindings();
+ }
+ else if ( !Q_stricmp( command, "RefreshOptions" ) )
+ {
+ UncacheChoices();
+ UpdateScroll();
+ }
+ else if ( !Q_stricmp( command, "AcceptVocalsLanguageChange" ) )
+ {
+ OnClose();
+ }
+ else if ( !Q_stricmp( command, "CancelVocalsLanguageChange" ) )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+ x360_audio_english.SetValue( m_bOldForceEnglishAudio );
+ OnCommand( "RefreshOptions" );
+ OnClose();
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel(NULL);
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::OnKeyCodeReleased( vgui::KeyCode code )
+{
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::OnThink()
+{
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ OnKeyCodePressed( code );
+ }
+
+ BaseClass::OnThink();
+}
+
+void COptionsDialogXbox::HandleInactiveKeyCodePressed( vgui::KeyCode code )
+{
+ m_KeyRepeat.KeyDown( code );
+
+ OptionType_e eOptionType = (*m_pOptions)[ m_iSelection ]->eOptionType;
+ switch( code )
+ {
+ // Change the selected value
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+ if ( !(*m_pOptions)[ m_iSelection ]->bUnchangeable )
+ {
+ // Don't allow more binds if it's already maxed out
+ if ( eOptionType == OPTION_TYPE_BIND && ( (*m_pOptions)[ m_iSelection ]->iNumBinds < binds_per_command.GetInt() || binds_per_command.GetInt() == 1 ) )
+ {
+ ActivateSelection();
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ }
+ else if ( eOptionType == OPTION_TYPE_BINARY || eOptionType == OPTION_TYPE_CHOICE )
+ {
+ ActivateSelection();
+ ChangeValue( 1 );
+ DeactivateSelection();
+ }
+ }
+ else if ( !(*m_pOptions)[ m_iSelection ]->bVocalsLanguage )
+ {
+ BasePanel()->ShowMessageDialog( MD_OPTION_CHANGE_FROM_X360_DASHBOARD, this );
+ }
+ break;
+
+ // To the main menu
+ case KEY_XBUTTON_B:
+ case STEAMCONTROLLER_B:
+ if ( m_bOldForceEnglishAudio != x360_audio_english.GetBool() )
+ {
+ // Pop up a dialog to confirm changing the language
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ BasePanel()->ShowMessageDialog( MD_SAVE_BEFORE_LANGUAGE_CHANGE, this );
+ }
+ else
+ {
+ OnClose();
+ }
+ break;
+
+ // Move the selection up and down
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ ChangeSelection( -1 );
+ break;
+
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ ChangeSelection( 1 );
+ break;
+
+ // Quickly change in the negative direction
+ case KEY_XBUTTON_LEFT:
+ case KEY_XSTICK1_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ if ( !(*m_pOptions)[ m_iSelection ]->bUnchangeable )
+ {
+ if ( eOptionType != OPTION_TYPE_BIND )
+ {
+ ActivateSelection();
+ ChangeValue( -1 );
+ DeactivateSelection();
+ }
+ }
+ else if ( !(*m_pOptions)[ m_iSelection ]->bVocalsLanguage )
+ {
+ BasePanel()->ShowMessageDialog( MD_OPTION_CHANGE_FROM_X360_DASHBOARD, this );
+ }
+ break;
+
+ // Quickly change in the positive direction
+ case KEY_XBUTTON_RIGHT:
+ case KEY_XSTICK1_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ if ( !(*m_pOptions)[ m_iSelection ]->bUnchangeable )
+ {
+ if ( eOptionType != OPTION_TYPE_BIND )
+ {
+ ActivateSelection();
+ ChangeValue( 1 );
+ DeactivateSelection();
+ }
+ }
+ else if ( !(*m_pOptions)[ m_iSelection ]->bVocalsLanguage )
+ {
+ BasePanel()->ShowMessageDialog( MD_OPTION_CHANGE_FROM_X360_DASHBOARD, this );
+ }
+ break;
+
+ case KEY_XBUTTON_X:
+ case STEAMCONTROLLER_X:
+ if ( !(*m_pOptions)[ m_iSelection ]->bUnchangeable )
+ {
+ if ( eOptionType == OPTION_TYPE_BIND )
+ {
+ if ( (*m_pOptions)[ m_iSelection ]->iNumBinds != 0 )
+ {
+ ActivateSelection();
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+ UnbindOption( m_pSelectedOption, GetSelectionLabel() );
+ DeactivateSelection();
+ }
+ }
+ }
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ if ( m_bControllerOptions )
+ {
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ BasePanel()->ShowMessageDialog( MD_DEFAULT_CONTROLS_CONFIRM, this );
+ }
+ else
+ {
+ BasePanel()->OnChangeStorageDevice();
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void COptionsDialogXbox::HandleActiveKeyCodePressed( vgui::KeyCode code )
+{
+ // Only binds types should become active!
+ DeactivateSelection();
+}
+
+void COptionsDialogXbox::HandleBindKeyCodePressed( vgui::KeyCode code )
+{
+ // Don't let stick movements be bound
+ if ( ( code >= KEY_XSTICK1_RIGHT && code <= KEY_XSTICK1_UP ) ||
+ ( code >= KEY_XSTICK2_RIGHT && code <= KEY_XSTICK2_UP ) )
+ return;
+
+ if ( code == KEY_XBUTTON_START )
+ {
+ vgui::surface()->PlaySound( "UI/buttonrollover.wav" );
+ UpdateValue( m_pSelectedOption, GetSelectionLabel() );
+ }
+ else
+ ChangeValue( static_cast<int>( code ) );
+
+ DeactivateSelection();
+}
+
+void COptionsDialogXbox::ActivateSelection( void )
+{
+ m_bSelectionActive = true;
+ m_pSelectedOption = (*m_pOptions)[ m_iSelection ];
+
+ if ( !m_pSelectedOption || m_pSelectedOption->eOptionType != OPTION_TYPE_BIND )
+ return;
+
+ m_KeyRepeat.Reset();
+
+ m_pOptionsSelectionLeft->SetAlpha( 255 );
+
+ int iLabel = GetSelectionLabel();
+
+ m_pOptionLabels[ iLabel ]->SetFgColor( Color( 0, 0, 0, 255 ) );
+
+ m_pValueLabels[ iLabel ]->SetFont( m_hLabelFont );
+ m_pValueLabels[ iLabel ]->SetText( "#GameUI_SetNewButton" );
+
+ UpdateFooter();
+}
+
+void COptionsDialogXbox::DeactivateSelection( void )
+{
+ m_bSelectionActive = false;
+
+ if ( !m_pSelectedOption || m_pSelectedOption->eOptionType != OPTION_TYPE_BIND )
+ return;
+
+ m_pOptionsSelectionLeft->SetAlpha( 96 );
+
+ int iLabel = GetSelectionLabel();
+
+ m_pOptionLabels[ iLabel ]->SetFgColor( Color( 255, 255, 255, 255 ) );
+ m_pValueLabels[ iLabel ]->SetFgColor( Color( 255, 255, 255, 255 ) );
+
+ UpdateFooter();
+}
+
+void COptionsDialogXbox::ChangeSelection( int iChange )
+{
+ m_iSelection += iChange;
+
+ if ( m_iSelection < 0 )
+ {
+ m_iSelection = 0;
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+ else if ( m_iSelection >= m_pOptions->Count() )
+ {
+ m_iSelection = m_pOptions->Count() - 1;
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "UI/buttonrollover.wav" );
+ }
+
+ // Make sure the selected item in in the window
+ if ( m_iSelection < m_iScroll )
+ {
+ m_iScroll = m_iSelection;
+ UpdateScroll();
+ }
+ else if ( GetSelectionLabel() >= m_iNumItems )
+ {
+ m_iScroll = m_iSelection - m_iNumItems + 1;
+ UpdateScroll();
+ }
+
+ UpdateFooter();
+
+ UpdateSelection();
+}
+
+void COptionsDialogXbox::UpdateFooter( void )
+{
+ m_pFooter->ClearButtons();
+
+ if ( !m_bSelectionActive )
+ {
+ if ( !(*m_pOptions)[ m_iSelection ]->bUnchangeable )
+ {
+ switch ( (*m_pOptions)[ m_iSelection ]->eOptionType )
+ {
+ case OPTION_TYPE_BINARY:
+ m_pFooter->AddNewButtonLabel( "#GameUI_Modify", "#GameUI_Icons_DPAD" );
+ break;
+
+ case OPTION_TYPE_SLIDER:
+ m_pFooter->AddNewButtonLabel( "#GameUI_Modify", "#GameUI_Icons_DPAD" );
+ break;
+
+ case OPTION_TYPE_CHOICE:
+ m_pFooter->AddNewButtonLabel( ( (*m_pOptions)[ m_iSelection ]->m_Choices.Count() == 2 ) ? ( "#GameUI_Toggle" ) : ( "#GameUI_Modify" ), "#GameUI_Icons_DPAD" );
+ break;
+
+ case OPTION_TYPE_BIND:
+ {
+ if ( (*m_pOptions)[ m_iSelection ]->iNumBinds < binds_per_command.GetInt() || binds_per_command.GetInt() == 1 )
+ m_pFooter->AddNewButtonLabel( "#GameUI_Modify", "#GameUI_Icons_A_BUTTON" );
+ if ( (*m_pOptions)[ m_iSelection ]->iNumBinds != 0 )
+ m_pFooter->AddNewButtonLabel( "#GameUI_ClearButton", "#GameUI_Icons_X_BUTTON" );
+ break;
+ }
+ }
+ }
+
+ if ( m_bControllerOptions )
+ m_pFooter->AddNewButtonLabel( "#GameUI_DefaultButtons", "#GameUI_Icons_Y_BUTTON" );
+ else
+ m_pFooter->AddNewButtonLabel( "#GameUI_Console_StorageChange", "#GameUI_Icons_Y_BUTTON" );
+
+ m_pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ }
+ else if ( m_pSelectedOption )
+ {
+ switch ( m_pSelectedOption->eOptionType )
+ {
+ case OPTION_TYPE_BIND:
+ m_pFooter->AddNewButtonLabel( "#GameUI_Cancel", "#GameUI_Icons_START" );
+ break;
+ }
+ }
+
+ if ( m_nButtonGap > 0 )
+ {
+ m_pFooter->SetButtonGap( m_nButtonGap );
+ }
+ else
+ {
+ m_pFooter->UseDefaultButtonGap();
+ }
+
+ CMatchmakingBasePanel *pBase = BasePanel()->GetMatchmakingBasePanel();
+ if ( pBase )
+ {
+ pBase->ShowFooter( false );
+ }
+}
+
+void COptionsDialogXbox::UpdateSelection( void )
+{
+ int iYPos = m_iSelectorYStart + m_iOptionSpacing * ( GetSelectionLabel() );
+
+ int iX, iY;
+ m_pOptionsSelectionLeft->GetPos( iX, iY );
+ m_pOptionsSelectionLeft->SetPos( iX, iYPos );
+ m_pOptionsSelectionLeft2->GetPos( iX, iY );
+ m_pOptionsSelectionLeft2->SetPos( iX, iYPos + 2 );
+}
+
+void COptionsDialogXbox::UpdateScroll( void )
+{
+ for ( int iLabel = 0; iLabel < m_iNumItems; ++iLabel )
+ {
+ int iOption = m_iScroll + iLabel;
+
+ if ( iOption >= m_pOptions->Count() )
+ break;
+
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ m_pOptionLabels[ iLabel ]->SetText( pOption->szDisplayName );
+
+ UpdateValue( pOption, iLabel );
+
+ if ( pOption->bUnchangeable )
+ {
+ m_pOptionLabels[ iLabel ]->SetFgColor( Color( 128, 128, 128, 255 ) );
+ m_pValueLabels[ iLabel ]->SetFgColor( Color( 128, 128, 128, 255 ) );
+ }
+ else
+ {
+ m_pOptionLabels[ iLabel ]->SetFgColor( Color( 200, 200, 200, 255 ) );
+ m_pValueLabels[ iLabel ]->SetFgColor( Color( 200, 200, 200, 255 ) );
+ }
+
+ }
+
+ // Draw arrows if there's more items to scroll to
+ m_pOptionsUpArrow->SetAlpha( ( m_iScroll > 0 ) ? ( 255 ) : ( 64 ) );
+ m_pOptionsDownArrow->SetAlpha( ( m_iScroll + m_iNumItems < m_pOptions->Count() ) ? ( 255 ) : ( 64 ) );
+}
+
+void COptionsDialogXbox::UncacheChoices( void )
+{
+ for ( int iOption = 0; iOption < m_pOptions->Count(); ++iOption )
+ {
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ if ( pOption->eOptionType != OPTION_TYPE_CHOICE )
+ continue;
+
+ pOption->iCurrentChoice = -1;
+ }
+}
+
+void COptionsDialogXbox::GetChoiceFromConvar( OptionData_t *pOption )
+{
+ if ( pOption->iCurrentChoice < 0 )
+ {
+ // Don't have a proper choice yet, so see if the convars value matches one of our choices
+ if ( pOption->szConvar2[ 0 ] == '\0' )
+ {
+ ConVarRef varOption( pOption->szConvar );
+ const char *pchValue = varOption.GetString();
+
+ // Only one convar to check
+ for ( int iChoice = 0; iChoice < pOption->m_Choices.Count(); ++iChoice )
+ {
+ if ( Q_stricmp( pOption->m_Choices[ iChoice ].szValue, pchValue ) == 0 )
+ {
+ pOption->iCurrentChoice = iChoice;
+ break;
+ }
+
+ // We need to compare values in case we have "0" & "0.00000".
+ if ( (pchValue[0] >= '0' && pchValue[0] <= '9') || pchValue[0] == '-' )
+ {
+ float flVal = atof(pchValue);
+ float flChoiceVal = atof(pOption->m_Choices[ iChoice ].szValue);
+ if ( flVal == flChoiceVal )
+ {
+ pOption->iCurrentChoice = iChoice;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Two convars to contend with
+ ConVarRef varOption( pOption->szConvar );
+ ConVarRef varOption2( pOption->szConvar2 );
+
+ const char *pchValue = varOption.GetString();
+ const char *pchValue2 = varOption2.GetString();
+
+ for ( int iChoice = 0; iChoice < pOption->m_Choices.Count(); ++iChoice )
+ {
+ char szOptionValue[ OPTION_STRING_LENGTH ];
+ Q_strncpy( szOptionValue, pOption->m_Choices[ iChoice ].szValue, sizeof( szOptionValue ) );
+
+ char *pchOptionValue2 = const_cast<char*>( Q_strnchr( szOptionValue, ';', sizeof( szOptionValue ) ) );
+
+ AssertMsg( pchOptionValue2, "Option uses 2 convars but an option doesn't have 2 ; separated values!" );
+
+ pchOptionValue2[ 0 ] = '\0'; // Set this as the end of the other value
+ ++pchOptionValue2; // Point at next char
+
+ if ( Q_stricmp( szOptionValue, pchValue ) == 0 && Q_stricmp( pchOptionValue2, pchValue2 ) == 0 )
+ {
+ pOption->iCurrentChoice = iChoice;
+ break;
+ }
+ }
+ }
+ }
+}
+
+#if !defined(_X360)
+// BUGBUG: This won't compile because it includes windows.h and this interface function is #defined to something else
+// see below system()->GetCurrentTime
+#undef GetCurrentTime
+#endif
+
+void COptionsDialogXbox::ChangeValue( float fChange )
+{
+ switch ( m_pSelectedOption->eOptionType )
+ {
+ case OPTION_TYPE_BINARY:
+ {
+ ConVarRef varOption( m_pSelectedOption->szConvar );
+ varOption.SetValue( !varOption.GetBool() );
+
+ UpdateValue( m_pSelectedOption, GetSelectionLabel() );
+
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ break;
+ }
+
+ case OPTION_TYPE_SLIDER:
+ {
+ if ( system()->GetCurrentTime() > m_fNextChangeTime )
+ {
+ ConVarRef varOption( m_pSelectedOption->szConvar );
+
+ float fNumSegments = m_pValueBars[ 0 ]->GetTotalSegmentCount();
+ if ( fNumSegments <= 0.0f )
+ fNumSegments = 1.0f;
+
+ float fIncValue;
+
+ if ( m_pSelectedOption->fIncValue == 0.0f )
+ fIncValue = ( m_pSelectedOption->fMaxValue - m_pSelectedOption->fMinValue ) * ( 1.0f / fNumSegments );
+ else
+ fIncValue = m_pSelectedOption->fIncValue * ( m_pSelectedOption->fMaxValue - m_pSelectedOption->fMinValue ) * ( 1.0f / fNumSegments );
+
+ fIncValue *= fChange;
+
+ float fOldValue = varOption.GetFloat();
+ float fValue = clamp( fOldValue + fIncValue, m_pSelectedOption->fMinValue, m_pSelectedOption->fMaxValue );
+
+ if ( fOldValue != fValue )
+ {
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ varOption.SetValue( fValue );
+ UpdateValue( m_pSelectedOption, GetSelectionLabel() );
+ }
+ else
+ {
+ // Play the invalid sound
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+ }
+
+ break;
+ }
+
+ case OPTION_TYPE_CHOICE:
+ {
+ GetChoiceFromConvar( m_pSelectedOption );
+
+ if ( m_pSelectedOption->iCurrentChoice >= 0 )
+ {
+ m_pSelectedOption->iCurrentChoice += fChange;
+
+ while ( m_pSelectedOption->iCurrentChoice >= m_pSelectedOption->m_Choices.Count() )
+ m_pSelectedOption->iCurrentChoice -= m_pSelectedOption->m_Choices.Count();
+
+ while ( m_pSelectedOption->iCurrentChoice < 0 )
+ m_pSelectedOption->iCurrentChoice += m_pSelectedOption->m_Choices.Count();
+
+ if ( m_pSelectedOption->szConvar2[ 0 ] == '\0' )
+ {
+ // Only one convar to set
+ ConVarRef varOption( m_pSelectedOption->szConvar );
+ varOption.SetValue( m_pSelectedOption->m_Choices[ m_pSelectedOption->iCurrentChoice ].szValue );
+ }
+ else
+ {
+ // Two convars to deal with
+ char szOptionValue[ OPTION_STRING_LENGTH ];
+ Q_strncpy( szOptionValue, m_pSelectedOption->m_Choices[ m_pSelectedOption->iCurrentChoice ].szValue, sizeof( szOptionValue ) );
+
+ char *pchOptionValue2 = const_cast<char*>( Q_strnchr( szOptionValue, ';', sizeof( szOptionValue ) ) );
+
+ AssertMsg( pchOptionValue2, "Option uses to convars but an option doesn't have 2 ; separated values!" );
+
+ pchOptionValue2[ 0 ] = '\0'; // Set this as the end of the other value
+ ++pchOptionValue2; // Point at next char
+
+ ConVarRef varOption( m_pSelectedOption->szConvar );
+ ConVarRef varOption2( m_pSelectedOption->szConvar2 );
+
+ varOption.SetValue( szOptionValue );
+ varOption2.SetValue( pchOptionValue2 );
+ }
+ }
+ else
+ {
+ DevWarning( "ConVar \"%s\" set to value that's not a choice used by \"%s\" option.", m_pSelectedOption->szConvar, m_pSelectedOption->szDisplayName );
+ }
+
+ UpdateValue( m_pSelectedOption, GetSelectionLabel() );
+
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ break;
+ }
+
+ case OPTION_TYPE_BIND:
+ {
+ // If we only allow one bind replace the previous
+ if ( binds_per_command.GetInt() == 1 )
+ UnbindOption( m_pSelectedOption, GetSelectionLabel() );
+
+ ButtonCode_t code = static_cast<ButtonCode_t>( static_cast<int>( fChange ) );
+
+ char szCommand[ 256 ];
+ Q_snprintf( szCommand, sizeof( szCommand ), "bind \"%s\" \"%s\"", g_pInputSystem->ButtonCodeToString( code ), m_pSelectedOption->szCommand );
+ engine->ClientCmd_Unrestricted( szCommand );
+
+ // After binding we need to update all bindings so they display the correct keys
+ UpdateAllBinds( code );
+
+ m_bOptionsChanged = true;
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ break;
+ }
+ }
+}
+
+void COptionsDialogXbox::UnbindOption( OptionData_t *pOption, int iLabel )
+{
+ if ( pOption->eOptionType != OPTION_TYPE_BIND )
+ return;
+
+ for ( int iCode = 0; iCode < BUTTON_CODE_LAST; ++iCode )
+ {
+ ButtonCode_t code = static_cast<ButtonCode_t>( iCode );
+
+ const char *pBinding = gameuifuncs->GetBindingForButtonCode( code );
+
+ // Check if there's a binding for this key
+ if ( !pBinding || !pBinding[0] )
+ continue;
+
+ // If we use this binding, display the key in our list
+ if ( ActionsAreTheSame( pBinding, pOption->szCommand ) )
+ {
+ char szCommand[ 256 ];
+ Q_snprintf( szCommand, sizeof( szCommand ), "unbind %s", g_pInputSystem->ButtonCodeToString( code ) );
+ engine->ClientCmd_Unrestricted( szCommand );
+ }
+ }
+
+ pOption->iNumBinds = 0;
+
+ if ( iLabel < 0 || iLabel >= m_iNumItems )
+ return;
+
+ m_pValueLabels[ iLabel ]->SetFont( m_hLabelFont );
+ m_pValueLabels[ iLabel ]->SetText( "" );
+}
+
+void COptionsDialogXbox::UpdateValue( OptionData_t *pOption, int iLabel )
+{
+ if ( pOption->bVocalsLanguage )
+ {
+ // Can't change vocal language while in game
+ pOption->bUnchangeable = GameUI().IsInLevel();
+ }
+
+ switch ( pOption->eOptionType )
+ {
+ case OPTION_TYPE_BINARY:
+ {
+ ConVarRef varOption( pOption->szConvar );
+
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( true );
+ m_pValueLabels[ iLabel ]->SetFont( m_hLabelFont );
+ m_pValueLabels[ iLabel ]->SetText( ( varOption.GetBool() ) ? ( "#GameUI_Enable" ) : ( "#GameUI_Disable" ) );
+ break;
+ }
+
+ case OPTION_TYPE_SLIDER:
+ {
+ ConVarRef varOption( pOption->szConvar );
+
+ m_pValueLabels[ iLabel ]->SetVisible( false );
+ m_pValueBars[ iLabel ]->SetVisible( true );
+
+ // If it's very close to the home value set it as the home value
+ float fNumSegments = m_pValueBars[ 0 ]->GetTotalSegmentCount();
+ if ( fNumSegments <= 0.0f )
+ fNumSegments = 1.0f;
+
+ float fIncValue;
+
+ if ( pOption->fIncValue == 0.0f )
+ fIncValue = ( pOption->fMaxValue - pOption->fMinValue ) * ( 1.0f / fNumSegments );
+ else
+ fIncValue = pOption->fIncValue * ( pOption->fMaxValue - pOption->fMinValue ) * ( 1.0f / fNumSegments );
+
+ float fNormalizeHome = fabsf( ( pOption->fMinValue - pOption->fSliderHomeValue ) / ( pOption->fMaxValue - pOption->fMinValue ) );
+ if ( pOption->fIncValue < 0.0f )
+ fNormalizeHome = 1.0f - fNormalizeHome;
+ m_pValueBars[ iLabel ]->SetHomeValue( fNormalizeHome );
+
+ float fNormalizeValue = fabsf( ( pOption->fMinValue - varOption.GetFloat() ) / ( pOption->fMaxValue - pOption->fMinValue ) );
+ if ( pOption->fIncValue < 0.0f )
+ fNormalizeValue = 1.0f - fNormalizeValue;
+
+ // atof accuracy for convar isn't so good, so snap to the home value if we're near it.
+ if ( fabsf( fNormalizeValue - fNormalizeHome ) < fabsf( fIncValue * 0.1f ) )
+ fNormalizeValue = fNormalizeHome;
+
+ m_pValueBars[ iLabel ]->SetAnalogValue( fNormalizeValue );
+
+ break;
+ }
+
+ case OPTION_TYPE_CHOICE:
+ {
+ GetChoiceFromConvar( pOption );
+
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( true );
+ m_pValueLabels[ iLabel ]->SetFont( m_hLabelFont );
+ if ( pOption->iCurrentChoice >= 0 )
+ {
+ m_pValueLabels[ iLabel ]->SetText( pOption->m_Choices[ pOption->iCurrentChoice ].szName );
+ }
+ else
+ {
+ if ( pOption->bUnchangeable )
+ {
+ if ( pOption->szConvar2[ 0 ] == '\0' )
+ {
+ ConVarRef varOption( pOption->szConvar );
+ m_pValueLabels[ iLabel ]->SetText( varOption.GetString() );
+ }
+ else
+ {
+ // This is used for displaying the resolution settings
+ ConVarRef varOption( pOption->szConvar );
+ ConVarRef varOption2( pOption->szConvar2 );
+ char szBuff[ 256 ];
+ Q_snprintf( szBuff, sizeof( szBuff ), "%sx%s%s", varOption.GetString(), varOption2.GetString(), ( x360_resolution_interlaced.GetBool() ) ? ( "i" ) : ( "p" ) );
+ m_pValueLabels[ iLabel ]->SetText( szBuff );
+ }
+ }
+ else
+ {
+ DevWarning( "ConVar \"%s\" set to value that's not a choice used by \"%s\" option.", pOption->szConvar, pOption->szDisplayName );
+ m_pValueLabels[ iLabel ]->SetText( "#GameUI_NoOptionsYet" );
+ }
+ }
+
+ break;
+ }
+
+ case OPTION_TYPE_BIND:
+ {
+ UpdateBind( pOption, iLabel );
+ break;
+ }
+ }
+}
+
+void COptionsDialogXbox::UpdateBind( OptionData_t *pOption, int iLabel, ButtonCode_t codeIgnore, ButtonCode_t codeAdd )
+{
+ int iNumBinds = 0;
+ char szBinds[ OPTION_STRING_LENGTH ];
+
+ char szBuff[ 512 ];
+ wchar_t szWideBuff[ 64 ];
+
+ for ( int iCode = 0; iCode < BUTTON_CODE_LAST; ++iCode )
+ {
+ ButtonCode_t code = static_cast<ButtonCode_t>( iCode );
+
+ // Don't show this key in our list
+ if ( code == codeIgnore )
+ continue;
+
+ bool bUseThisKey = ( codeAdd == code );
+
+ if ( !bUseThisKey )
+ {
+ // If this binding is being replaced only allow the new binding to show
+ if ( binds_per_command.GetInt() == 1 && codeAdd != BUTTON_CODE_INVALID )
+ continue;
+
+ // Only check against bind name if we haven't already forced this binding to be used
+ const char *pBinding = gameuifuncs->GetBindingForButtonCode( code );
+
+ if ( !pBinding )
+ continue;
+
+ bUseThisKey = ActionsAreTheSame( pBinding, pOption->szCommand );
+ }
+
+ // Don't use this bind in out list
+ if ( !bUseThisKey )
+ continue;
+
+ // Turn localized string into icon character
+ Q_snprintf( szBuff, sizeof( szBuff ), "#GameUI_Icons_%s", g_pInputSystem->ButtonCodeToString( static_cast<ButtonCode_t>( iCode ) ) );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( szBuff ), 0 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ // Add this icon to our list of keys to display
+ szBinds[ iNumBinds ] = szBuff[ 0 ];
+ ++iNumBinds;
+ }
+
+ if ( iNumBinds == 0 )
+ {
+ // No keys for this bind
+ pOption->iNumBinds = 0;
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( true );
+ m_pValueLabels[ iLabel ]->SetFont( m_hLabelFont );
+ m_pValueLabels[ iLabel ]->SetText( "" );
+ }
+ else
+ {
+ // Show icons for list of keys
+ szBinds[ iNumBinds ] = '\0';
+ pOption->iNumBinds = iNumBinds;
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( true );
+ m_pValueLabels[ iLabel ]->SetFont( m_hButtonFont );
+ m_pValueLabels[ iLabel ]->SetText( szBinds );
+ }
+}
+
+void COptionsDialogXbox::UpdateAllBinds( ButtonCode_t code )
+{
+ // Loop through all the items
+ for ( int iLabel = 0; iLabel < m_iNumItems; ++iLabel )
+ {
+ int iOption = m_iScroll + iLabel;
+
+ if ( iOption >= m_pOptions->Count() )
+ break;
+
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ if ( pOption->eOptionType == OPTION_TYPE_BIND )
+ {
+ if ( pOption == m_pSelectedOption )
+ {
+ // We just added a key to this binding so add it to the list
+ UpdateBind( pOption, iLabel, BUTTON_CODE_INVALID, code );
+ }
+ else
+ {
+ // We just added a key so don't let it show up for any other bindings
+ UpdateBind( pOption, iLabel, code );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Read in defaults from game's default config file and populate list
+// using those defaults
+//-----------------------------------------------------------------------------
+void COptionsDialogXbox::FillInDefaultBindings( void )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ if ( !g_pFullFileSystem->ReadFile( "cfg/config.360.cfg", NULL, buf ) )
+ return;
+
+ // Clear out all current bindings
+ for ( int iOption = 0; iOption < m_pOptions->Count(); ++iOption )
+ UnbindOption( (*m_pOptions)[ iOption ], iOption - m_iScroll );
+
+ const char *data = (const char*)buf.Base();
+
+ // loop through all the binding
+ while ( data != NULL )
+ {
+ char cmd[64];
+ data = UTIL_Parse( data, cmd, sizeof(cmd) );
+ if ( strlen( cmd ) <= 0 )
+ break;
+
+ if ( !stricmp(cmd, "bind") )
+ {
+ // Key name
+ char szKeyName[256];
+ data = UTIL_Parse( data, szKeyName, sizeof(szKeyName) );
+ if ( strlen( szKeyName ) <= 0 )
+ break; // Error
+
+ char szBinding[256];
+ data = UTIL_Parse( data, szBinding, sizeof(szBinding) );
+ if ( strlen( szKeyName ) <= 0 )
+ break; // Error
+
+ // Bind it
+ char szCommand[ 256 ];
+ Q_snprintf( szCommand, sizeof( szCommand ), "bind \"%s\" \"%s\"", szKeyName, szBinding );
+ engine->ClientCmd_Unrestricted( szCommand );
+
+ // Loop through all the items
+ for ( int iLabel = 0; iLabel < m_iNumItems; ++iLabel )
+ {
+ int iOption = m_iScroll + iLabel;
+
+ if ( iOption >= m_pOptions->Count() )
+ break;
+
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ // Check if this bind is for this option
+ if ( pOption->eOptionType == OPTION_TYPE_BIND && ActionsAreTheSame( pOption->szCommand, szBinding ) )
+ {
+ char szBuff[ 512 ];
+ wchar_t szWideBuff[ 64 ];
+ char szBinds[ OPTION_STRING_LENGTH ];
+ if ( pOption->iNumBinds > 0 )
+ m_pValueLabels[ iLabel ]->GetText( szBinds, sizeof( szBinds ) );
+
+ // Turn localized string into icon character
+ Q_snprintf( szBuff, sizeof( szBuff ), "#GameUI_Icons_%s", szKeyName );
+ g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( szBuff ), 0 );
+ g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
+
+ // Add this icon to our list of keys to display
+ szBinds[ pOption->iNumBinds ] = szBuff[ 0 ];
+ ++pOption->iNumBinds;
+
+ // Show icons for list of keys
+ szBinds[ pOption->iNumBinds ] = '\0';
+ m_pValueBars[ iLabel ]->SetVisible( false );
+ m_pValueLabels[ iLabel ]->SetVisible( true );
+ m_pValueLabels[ iLabel ]->SetFont( m_hButtonFont );
+ m_pValueLabels[ iLabel ]->SetText( szBinds );
+ }
+ }
+ }
+ }
+
+ // Reset any options with default convar values
+ for ( int iLabel = 0; iLabel < m_iNumItems; ++iLabel )
+ {
+ int iOption = m_iScroll + iLabel;
+
+ if ( iOption >= m_pOptions->Count() )
+ break;
+
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+
+ if ( pOption->szConvarDef && pOption->szConvarDef[0] )
+ {
+ ConVarRef varDefault( pOption->szConvarDef );
+ ConVarRef varOption( pOption->szConvar );
+ varOption.SetValue( varDefault.GetFloat() );
+ pOption->iCurrentChoice = -1;
+ UpdateValue( pOption, iLabel );
+ }
+ }
+}
+
+bool COptionsDialogXbox::ShouldSkipOption( KeyValues *pKey )
+{
+ // Skip the option if not in developer mode and this is a developer only option
+ ConVarRef developer( "developer" );
+ if ( !developer.GetBool() && ( pKey->GetInt( "dev", 0 ) != 0 ) )
+ return true;
+
+ // Skip the option if it doesn't match the controller/non-controller list
+ if ( m_bControllerOptions != ( pKey->GetInt( "control", 0 ) != 0 ) )
+ return true;
+
+ // Skip portal options if this mod doesn't have portals (defined in gameinfo.txt)
+ if ( !ModInfo().HasPortals() && ( pKey->GetInt( "portals", 0 ) != 0 ) )
+ return true;
+
+ // Skip multiplayer only options for single player (or combo) games
+ if ( ModInfo().IsSinglePlayerOnly() && !ModInfo().IsMultiplayerOnly() && ( pKey->GetInt( "multiplayer", 0 ) != 0 ) )
+ return true;
+
+ // Skip difficulty options for games that don't want them
+ if ( !( ModInfo().IsSinglePlayerOnly() && !ModInfo().NoDifficulty() ) && ( pKey->GetInt( "difficulty", 0 ) != 0 ) )
+ return true;
+
+ // Skip voice options for single player games
+ if ( ModInfo().IsSinglePlayerOnly() && !ModInfo().IsMultiplayerOnly() && ( pKey->GetInt( "voice", 0 ) != 0 ) )
+ return true;
+
+ // Skip if it's the vocal language option but we're not in german or french
+ if ( pKey->GetInt( "vocalslanguage", 0 ) != 0 )
+ {
+ if ( !XBX_IsLocalized() )
+ {
+ return true;
+ }
+ }
+
+ // Don't create options if there's already an entry by the same name
+ char szName[ OPTION_STRING_LENGTH ];
+ Q_strncpy( szName, pKey->GetName(), sizeof( szName ) );
+
+ for ( int iOption = 0; iOption < m_pOptions->Count(); ++iOption )
+ {
+ OptionData_t *pOption = (*m_pOptions)[ iOption ];
+ if ( Q_strcmp( pOption->szName, szName ) == 0 )
+ return true;
+ }
+
+ for ( int iOption = 0; iOption < s_DisabledOptions.Count(); ++iOption )
+ {
+ OptionChoiceData_t *pOption = &(s_DisabledOptions[ iOption ]);
+ if ( Q_strcmp( pOption->szName, szName ) == 0 )
+ return true;
+ }
+
+ return false;
+}
+
+void COptionsDialogXbox::ReadOptionsFromFile( const char *pchFileName )
+{
+ KeyValues *pOptionKeys = new KeyValues( "options_x360" );
+ pOptionKeys->LoadFromFile( g_pFullFileSystem, pchFileName, NULL );
+
+ KeyValues *pKey = NULL;
+ for ( pKey = pOptionKeys->GetFirstTrueSubKey(); pKey; pKey = pKey->GetNextTrueSubKey() )
+ {
+ // Skip disabled options
+ if ( pKey->GetInt( "disable", 0 ) != 0 )
+ {
+ // Remember disabled options so we don't create another with the same name
+ int iDisabledOption = s_DisabledOptions.AddToTail();
+ OptionChoiceData_t *pDisabledOption = &(s_DisabledOptions[ iDisabledOption ]);
+ Q_strncpy( pDisabledOption->szName, pKey->GetName(), sizeof( pDisabledOption->szName ) );
+
+ continue;
+ }
+
+ if ( ShouldSkipOption( pKey ) )
+ continue;
+
+ int iOption = m_pOptions->AddToTail();
+ OptionData_t **pNewOption = &((*m_pOptions)[ iOption ]);
+ *pNewOption = new OptionData_t;
+
+ // Get common values
+ Q_strncpy( (*pNewOption)->szName, pKey->GetName(), sizeof( (*pNewOption)->szName ) );
+ Q_strncpy( (*pNewOption)->szDisplayName, pKey->GetString( "name", "" ), sizeof( (*pNewOption)->szDisplayName ) );
+
+ Q_strncpy( (*pNewOption)->szConvar, pKey->GetString( "convar", "" ), sizeof( (*pNewOption)->szConvar ) );
+ if ( (*pNewOption)->szConvar[ 0 ] == '\0' )
+ Q_strncpy( (*pNewOption)->szCommand, pKey->GetString( "command", "" ), sizeof( (*pNewOption)->szCommand ) );
+
+ Q_strncpy( (*pNewOption)->szConvarDef, pKey->GetString( "convar_def", "" ), sizeof( (*pNewOption)->szConvarDef ) );
+
+ (*pNewOption)->iPriority = pKey->GetInt( "priority", 0 );
+ (*pNewOption)->bUnchangeable = ( pKey->GetInt( "unchangeable", 0 ) != 0 );
+ (*pNewOption)->bVocalsLanguage = ( pKey->GetInt( "vocalslanguage", 0 ) != 0 );
+
+ // Determine the type
+ char szType[ OPTION_STRING_LENGTH ];
+ Q_strncpy( szType, pKey->GetString( "type", "binary" ), sizeof( szType ) );
+
+ if ( Q_stricmp( szType, "binary" ) == 0 )
+ (*pNewOption)->eOptionType = OPTION_TYPE_BINARY;
+ else if ( Q_stricmp( szType, "slider" ) == 0 )
+ (*pNewOption)->eOptionType = OPTION_TYPE_SLIDER;
+ else if ( Q_stricmp( szType, "choice" ) == 0 )
+ (*pNewOption)->eOptionType = OPTION_TYPE_CHOICE;
+ else if ( Q_stricmp( szType, "bind" ) == 0 )
+ (*pNewOption)->eOptionType = OPTION_TYPE_BIND;
+
+ // Get type specific values
+ switch ( (*pNewOption)->eOptionType )
+ {
+ case OPTION_TYPE_SLIDER:
+ {
+ (*pNewOption)->fMinValue = pKey->GetFloat( "minvalue", 0.0f );
+ (*pNewOption)->fMaxValue = pKey->GetFloat( "maxvalue", 1.0f );
+ (*pNewOption)->fIncValue = pKey->GetFloat( "incvalue", 0.0f );
+
+ char szSliderHomeType[ OPTION_STRING_LENGTH ];
+ Q_strncpy( szSliderHomeType, pKey->GetString( "sliderhome", "none" ), sizeof( szSliderHomeType ) );
+
+ if ( Q_stricmp( szSliderHomeType, "prev" ) == 0 )
+ (*pNewOption)->eSliderHomeType = SLIDER_HOME_PREV;
+ else if ( Q_stricmp( szSliderHomeType, "min" ) == 0 )
+ (*pNewOption)->eSliderHomeType = SLIDER_HOME_MIN;
+ else if ( Q_stricmp( szSliderHomeType, "center" ) == 0 )
+ (*pNewOption)->eSliderHomeType = SLIDER_HOME_CENTER;
+ else if ( Q_stricmp( szSliderHomeType, "max" ) == 0 )
+ (*pNewOption)->eSliderHomeType = SLIDER_HOME_MAX;
+ else
+ (*pNewOption)->eSliderHomeType = SLIDER_HOME_NONE;
+
+ switch ( (*pNewOption)->eSliderHomeType )
+ {
+ case SLIDER_HOME_MIN:
+ (*pNewOption)->fSliderHomeValue = (*pNewOption)->fMinValue;
+ break;
+
+ case SLIDER_HOME_CENTER:
+ (*pNewOption)->fSliderHomeValue = ( (*pNewOption)->fMaxValue + (*pNewOption)->fMinValue ) * 0.5f;
+ break;
+
+ case SLIDER_HOME_MAX:
+ (*pNewOption)->fSliderHomeValue = (*pNewOption)->fMaxValue;
+ break;
+
+ default:
+ (*pNewOption)->fSliderHomeValue = 0.0f;
+ }
+
+ break;
+ }
+
+ case OPTION_TYPE_CHOICE:
+ {
+ Q_strncpy( (*pNewOption)->szConvar2, pKey->GetString( "convar2", "" ), sizeof( (*pNewOption)->szConvar ) );
+
+ if ( (*pNewOption)->bVocalsLanguage )
+ {
+ (*pNewOption)->iCurrentChoice = -1;
+ int iChoice = (*pNewOption)->m_Choices.AddToTail();
+ OptionChoiceData_t *pNewOptionChoice = &((*pNewOption)->m_Choices[ iChoice ]);
+
+ Q_strncpy( pNewOptionChoice->szName, "#GameUI_Language_English", sizeof( pNewOptionChoice->szName ) );
+ Q_strncpy( pNewOptionChoice->szValue, "1", sizeof( pNewOptionChoice->szValue ) );
+
+ iChoice = (*pNewOption)->m_Choices.AddToTail();
+ pNewOptionChoice = &((*pNewOption)->m_Choices[ iChoice ]);
+
+ char szLanguage[ 256 ];
+ Q_snprintf( szLanguage, sizeof( szLanguage ), "#GameUI_Language_%s", XBX_GetLanguageString() );
+ Q_strncpy( pNewOptionChoice->szName, szLanguage, sizeof( pNewOptionChoice->szName ) );
+ Q_strncpy( pNewOptionChoice->szValue, "0", sizeof( pNewOptionChoice->szValue ) );
+ }
+ else
+ {
+ (*pNewOption)->iCurrentChoice = -1;
+ KeyValues *pChoicesKey = pKey->FindKey( "choices" );
+
+ if ( pChoicesKey )
+ {
+ KeyValues *pSubKey = NULL;
+ for ( pSubKey = pChoicesKey->GetFirstSubKey(); pSubKey; pSubKey = pSubKey->GetNextKey() )
+ {
+ int iChoice = (*pNewOption)->m_Choices.AddToTail();
+ OptionChoiceData_t *pNewOptionChoice = &((*pNewOption)->m_Choices[ iChoice ]);
+
+ Q_strncpy( pNewOptionChoice->szName, pSubKey->GetName(), sizeof( pNewOptionChoice->szName ) );
+ Q_strncpy( pNewOptionChoice->szValue, pSubKey->GetString(), sizeof( pNewOptionChoice->szValue ) );
+ }
+
+ if ( (*pNewOption)->m_Choices.Count() < 2 )
+ {
+ DevWarning( "Option \"%s\" is type CHOICE but has less than 2 choices!", (*pNewOption)->szDisplayName );
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+int __cdecl SortByPriority( OptionData_t * const *pLeft, OptionData_t * const *pRight )
+{
+ return (*pLeft)->iPriority - (*pRight)->iPriority;
+}
+
+void COptionsDialogXbox::SortOptions( void )
+{
+ m_pOptions->Sort( SortByPriority );
+}
diff --git a/gameui/OptionsSubAudio.cpp b/gameui/OptionsSubAudio.cpp
new file mode 100644
index 0000000..9a4d6ae
--- /dev/null
+++ b/gameui/OptionsSubAudio.cpp
@@ -0,0 +1,432 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "OptionsSubAudio.h"
+
+#include "cvarslider.h"
+#include "EngineInterface.h"
+#include "ModInfo.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/QueryBox.h"
+#include "CvarToggleCheckButton.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include <vgui/IInput.h>
+#include <steam/steam_api.h>
+#include <tier1/strtools.h>
+
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+// This member is static so that the updated audio language can be referenced during shutdown
+char* COptionsSubAudio::m_pchUpdatedAudioLanguage = (char*)GetLanguageShortName( k_Lang_English );
+
+enum SoundQuality_e
+{
+ SOUNDQUALITY_LOW,
+ SOUNDQUALITY_MEDIUM,
+ SOUNDQUALITY_HIGH,
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+COptionsSubAudio::COptionsSubAudio(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+ m_pSFXSlider = new CCvarSlider( this, "SFXSlider", "#GameUI_SoundEffectVolume", 0.0f, 1.0f, "volume" );
+ m_pMusicSlider = new CCvarSlider( this, "MusicSlider", "#GameUI_MusicVolume", 0.0f, 1.0f, "Snd_MusicVolume" );
+
+ m_pCloseCaptionCombo = new ComboBox( this, "CloseCaptionCheck", 6, false );
+ m_pCloseCaptionCombo->AddItem( "#GameUI_NoClosedCaptions", NULL );
+ m_pCloseCaptionCombo->AddItem( "#GameUI_SubtitlesAndSoundEffects", NULL );
+ m_pCloseCaptionCombo->AddItem( "#GameUI_Subtitles", NULL );
+
+ m_pSoundQualityCombo = new ComboBox( this, "SoundQuality", 6, false );
+ m_pSoundQualityCombo->AddItem( "#GameUI_High", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_HIGH) );
+ m_pSoundQualityCombo->AddItem( "#GameUI_Medium", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_MEDIUM) );
+ m_pSoundQualityCombo->AddItem( "#GameUI_Low", new KeyValues("SoundQuality", "quality", SOUNDQUALITY_LOW) );
+
+ m_pSpeakerSetupCombo = new ComboBox( this, "SpeakerSetup", 6, false );
+#ifndef POSIX
+ m_pSpeakerSetupCombo->AddItem( "#GameUI_Headphones", new KeyValues("SpeakerSetup", "speakers", 0) );
+#endif
+ m_pSpeakerSetupCombo->AddItem( "#GameUI_2Speakers", new KeyValues("SpeakerSetup", "speakers", 2) );
+#ifndef POSIX
+ m_pSpeakerSetupCombo->AddItem( "#GameUI_4Speakers", new KeyValues("SpeakerSetup", "speakers", 4) );
+ m_pSpeakerSetupCombo->AddItem( "#GameUI_5Speakers", new KeyValues("SpeakerSetup", "speakers", 5) );
+ m_pSpeakerSetupCombo->AddItem( "#GameUI_7Speakers", new KeyValues("SpeakerSetup", "speakers", 7) );
+#endif
+ m_pSpokenLanguageCombo = new ComboBox (this, "AudioSpokenLanguage", 6, false );
+
+ m_pSoundMuteLoseFocusCheckButton = new CCvarToggleCheckButton( this, "snd_mute_losefocus", "#GameUI_SndMuteLoseFocus", "snd_mute_losefocus" );
+
+ LoadControlSettings("Resource\\OptionsSubAudio.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+COptionsSubAudio::~COptionsSubAudio()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reloads data
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::OnResetData()
+{
+ m_bRequireRestart = false;
+ m_pSFXSlider->Reset();
+ m_pMusicSlider->Reset();
+
+
+ // reset the combo boxes
+
+ // close captions
+ ConVarRef closecaption("closecaption");
+ ConVarRef cc_subtitles("cc_subtitles");
+ if (closecaption.GetBool())
+ {
+ if (cc_subtitles.GetBool())
+ {
+ m_pCloseCaptionCombo->ActivateItem(2);
+ }
+ else
+ {
+ m_pCloseCaptionCombo->ActivateItem(1);
+ }
+ }
+ else
+ {
+ m_pCloseCaptionCombo->ActivateItem(0);
+ }
+
+ // speakers
+ ConVarRef snd_surround_speakers("Snd_Surround_Speakers");
+ int speakers = snd_surround_speakers.GetInt();
+
+#ifdef POSIX
+ // On Posix there is no headphone option, so we upgrade to 2 speakers if Snd_Surround_Speakers == 0
+ if ( speakers == 0 )
+ speakers = 2;
+#endif
+
+ // if Snd_Surround_Speakers is -1, then upgrade to 2 speakers
+ if ( speakers < 0 )
+ speakers = 2;
+
+ {for (int itemID = 0; itemID < m_pSpeakerSetupCombo->GetItemCount(); itemID++)
+ {
+ KeyValues *kv = m_pSpeakerSetupCombo->GetItemUserData( itemID );
+ if (kv && kv->GetInt( "speakers" ) == speakers)
+ {
+ m_pSpeakerSetupCombo->ActivateItem( itemID );
+ break;
+ }
+ }}
+
+ // sound quality is made up from several cvars
+ ConVarRef Snd_PitchQuality("Snd_PitchQuality");
+ ConVarRef dsp_slow_cpu("dsp_slow_cpu");
+ int quality = SOUNDQUALITY_LOW;
+ if (dsp_slow_cpu.GetBool() == false)
+ {
+ quality = SOUNDQUALITY_MEDIUM;
+ }
+ if (Snd_PitchQuality.GetBool())
+ {
+ quality = SOUNDQUALITY_HIGH;
+ }
+ // find the item in the list and activate it
+ {for (int itemID = 0; itemID < m_pSoundQualityCombo->GetItemCount(); itemID++)
+ {
+ KeyValues *kv = m_pSoundQualityCombo->GetItemUserData(itemID);
+ if (kv && kv->GetInt("quality") == quality)
+ {
+ m_pSoundQualityCombo->ActivateItem(itemID);
+ }
+ }}
+
+ //
+ // Audio Languages
+ //
+ char szCurrentLanguage[50];
+ char szAvailableLanguages[512];
+ szCurrentLanguage[0] = 0;
+ szAvailableLanguages[0] = 0;
+
+ // Fallback to current engine language
+ engine->GetUILanguage( szCurrentLanguage, sizeof( szCurrentLanguage ));
+
+ // In a Steam environment we get the current language
+#if !defined( NO_STEAM )
+ // When Steam isn't running we can't get the language info...
+ if ( steamapicontext->SteamApps() )
+ {
+ Q_strncpy( szCurrentLanguage, steamapicontext->SteamApps()->GetCurrentGameLanguage(), sizeof(szCurrentLanguage) );
+ Q_strncpy( szAvailableLanguages, steamapicontext->SteamApps()->GetAvailableGameLanguages(), sizeof(szAvailableLanguages) );
+ }
+#endif
+
+ // Get the spoken language and store it for comparison purposes
+ m_nCurrentAudioLanguage = PchLanguageToELanguage( szCurrentLanguage );
+
+ // Check to see if we have a list of languages from Steam
+ if ( V_strlen( szAvailableLanguages ) )
+ {
+ // Populate the combo box with each available language
+ CUtlVector<char*> languagesList;
+ V_SplitString( szAvailableLanguages, ",", languagesList );
+
+ for ( int i=0; i < languagesList.Count(); i++ )
+ {
+ const ELanguage languageCode = PchLanguageToELanguage( languagesList[i] );
+ m_pSpokenLanguageCombo->AddItem( GetLanguageVGUILocalization( languageCode ), new KeyValues ("Audio Languages", "language", languageCode) );
+ }
+
+ languagesList.PurgeAndDeleteElements();
+ }
+ else
+ {
+ // Add the current language to the combo
+ m_pSpokenLanguageCombo->AddItem( GetLanguageVGUILocalization( m_nCurrentAudioLanguage ), new KeyValues ("Audio Languages", "language", m_nCurrentAudioLanguage) );
+ }
+
+ // Activate the current language in the combo
+ {for (int itemID = 0; itemID < m_pSpokenLanguageCombo->GetItemCount(); itemID++)
+ {
+ KeyValues *kv = m_pSpokenLanguageCombo->GetItemUserData( itemID );
+ if ( kv && kv->GetInt( "language" ) == m_nCurrentAudioLanguage )
+ {
+ m_pSpokenLanguageCombo->ActivateItem( itemID );
+ break;
+ }
+ }}
+
+ m_pSoundMuteLoseFocusCheckButton->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Applies changes
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::OnApplyChanges()
+{
+ m_pSFXSlider->ApplyChanges();
+ m_pMusicSlider->ApplyChanges();
+
+ // set the cvars appropriately
+ // Tracker 28933: Note we can't do this because closecaption is marked
+ // FCVAR_USERINFO and it won't get sent to server is we direct set it, we
+ // need to pass it along to the engine parser!!!
+ // ConVar *closecaption = (ConVar *)cvar->FindVar("closecaption");
+ int closecaption_value = 0;
+
+ ConVarRef cc_subtitles( "cc_subtitles" );
+ switch (m_pCloseCaptionCombo->GetActiveItem())
+ {
+ default:
+ case 0:
+ closecaption_value = 0;
+ cc_subtitles.SetValue( 0 );
+ break;
+ case 1:
+ closecaption_value = 1;
+ cc_subtitles.SetValue( 0 );
+ break;
+ case 2:
+ closecaption_value = 1;
+ cc_subtitles.SetValue( 1 );
+ break;
+ }
+
+ // Stuff the close caption change to the console so that it can be
+ // sent to the server (FCVAR_USERINFO) so that you don't have to restart
+ // the level for the change to take effect.
+ char cmd[ 64 ];
+ Q_snprintf( cmd, sizeof( cmd ), "closecaption %i\n", closecaption_value );
+ engine->ClientCmd_Unrestricted( cmd );
+
+ ConVarRef snd_surround_speakers( "Snd_Surround_Speakers" );
+ int speakers = m_pSpeakerSetupCombo->GetActiveItemUserData()->GetInt( "speakers" );
+ snd_surround_speakers.SetValue( speakers );
+
+ // quality
+ ConVarRef Snd_PitchQuality( "Snd_PitchQuality" );
+ ConVarRef dsp_slow_cpu( "dsp_slow_cpu" );
+ int quality = m_pSoundQualityCombo->GetActiveItemUserData()->GetInt( "quality" );
+ switch ( quality )
+ {
+ case SOUNDQUALITY_LOW:
+ dsp_slow_cpu.SetValue(true);
+ Snd_PitchQuality.SetValue(false);
+ break;
+ case SOUNDQUALITY_MEDIUM:
+ dsp_slow_cpu.SetValue(false);
+ Snd_PitchQuality.SetValue(false);
+ break;
+ default:
+ Assert("Undefined sound quality setting.");
+ case SOUNDQUALITY_HIGH:
+ dsp_slow_cpu.SetValue(false);
+ Snd_PitchQuality.SetValue(true);
+ break;
+ };
+
+ // headphones at high quality get enhanced stereo turned on
+ ConVarRef dsp_enhance_stereo( "dsp_enhance_stereo" );
+ if (speakers == 0 && quality == SOUNDQUALITY_HIGH)
+ {
+ dsp_enhance_stereo.SetValue( 1 );
+ }
+ else
+ {
+ dsp_enhance_stereo.SetValue( 0 );
+ }
+
+ // Audio spoken language
+ KeyValues *kv = m_pSpokenLanguageCombo->GetItemUserData( m_pSpokenLanguageCombo->GetActiveItem() );
+ const ELanguage nUpdatedAudioLanguage = (ELanguage)( kv ? kv->GetInt( "language" ) : k_Lang_English );
+
+ if ( nUpdatedAudioLanguage != m_nCurrentAudioLanguage )
+ {
+ // Store new language in static member so that it can be accessed during shutdown when this instance is gone
+ m_pchUpdatedAudioLanguage = (char *) GetLanguageShortName( nUpdatedAudioLanguage );
+
+ // Inform user that they need to restart in order change language at this time
+ QueryBox *qb = new QueryBox( "#GameUI_ChangeLanguageRestart_Title", "#GameUI_ChangeLanguageRestart_Info", GetParent()->GetParent()->GetParent() );
+ if (qb != NULL)
+ {
+ qb->SetOKCommand( new KeyValues( "Command", "command", "RestartWithNewLanguage" ) );
+ qb->SetOKButtonText( "#GameUI_ChangeLanguageRestart_OkButton" );
+ qb->SetCancelButtonText( "#GameUI_ChangeLanguageRestart_CancelButton" );
+ qb->AddActionSignalTarget( GetParent()->GetParent()->GetParent() );
+ qb->DoModal();
+ }
+ }
+
+ m_pSoundMuteLoseFocusCheckButton->ApplyChanges();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called on controls changing, enables the Apply button
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::OnControlModified()
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the engine needs to be restarted
+//-----------------------------------------------------------------------------
+bool COptionsSubAudio::RequiresRestart()
+{
+ // nothing in audio requires a restart like now
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "TestSpeakers" ) )
+ {
+ // ask them if they REALLY want to test the speakers if they're in a game already.
+ if (engine->IsConnected())
+ {
+ QueryBox *qb = new QueryBox("#GameUI_TestSpeakersWarning_Title", "#GameUI_TestSpeakersWarning_Info" );
+ if (qb != NULL)
+ {
+ qb->SetOKCommand(new KeyValues("RunTestSpeakers"));
+ qb->SetOKButtonText("#GameUI_TestSpeakersWarning_OkButton");
+ qb->SetCancelButtonText("#GameUI_TestSpeakersWarning_CancelButton");
+ qb->AddActionSignalTarget( this );
+ qb->DoModal();
+ }
+ else
+ {
+ // couldn't create the warning dialog for some reason, so just test the speakers.
+ RunTestSpeakers();
+ }
+ }
+ else
+ {
+ // player isn't connected to a game so there's no reason to warn them about being disconnected.
+ // create the command to execute
+ RunTestSpeakers();
+ }
+ }
+ else if ( !stricmp( command, "ShowThirdPartyAudioCredits" ) )
+ {
+ OpenThirdPartySoundCreditsDialog();
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Run the test speakers map.
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::RunTestSpeakers()
+{
+ engine->ClientCmd_Unrestricted( "disconnect\nwait\nwait\nsv_lan 1\nsetmaster enable\nmaxplayers 1\n\nhostname \"Speaker Test\"\nprogress_enable\nmap test_speakers\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: third-party audio credits dialog
+//-----------------------------------------------------------------------------
+class COptionsSubAudioThirdPartyCreditsDlg : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubAudioThirdPartyCreditsDlg, vgui::Frame );
+public:
+ COptionsSubAudioThirdPartyCreditsDlg( vgui::VPANEL hParent ) : BaseClass( NULL, NULL )
+ {
+ // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
+
+ SetTitle("#GameUI_ThirdPartyAudio_Title", true);
+ SetSize( 500, 200 );
+ LoadControlSettings( "resource/OptionsSubAudioThirdPartyDlg.res" );
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+ SetDeleteSelfOnClose( true );
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+
+ input()->SetAppModalSurface(GetVPanel());
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Open third party audio credits dialog
+//-----------------------------------------------------------------------------
+void COptionsSubAudio::OpenThirdPartySoundCreditsDialog()
+{
+ if (!m_OptionsSubAudioThirdPartyCreditsDlg.Get())
+ {
+ m_OptionsSubAudioThirdPartyCreditsDlg = new COptionsSubAudioThirdPartyCreditsDlg(GetVParent());
+ }
+ m_OptionsSubAudioThirdPartyCreditsDlg->Activate();
+}
diff --git a/gameui/OptionsSubAudio.h b/gameui/OptionsSubAudio.h
new file mode 100644
index 0000000..e5e5a84
--- /dev/null
+++ b/gameui/OptionsSubAudio.h
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_AUDIO_H
+#define OPTIONS_SUB_AUDIO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PropertyPage.h"
+#include <language.h>
+
+class CLabeledCommandComboBox;
+class CCvarSlider;
+class CCvarToggleCheckButton;
+
+//-----------------------------------------------------------------------------
+// Purpose: Audio Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubAudio : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubAudio, vgui::PropertyPage );
+
+public:
+ COptionsSubAudio(vgui::Panel *parent);
+ ~COptionsSubAudio();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+ virtual void OnCommand( const char *command );
+ bool RequiresRestart();
+ static char* GetUpdatedAudioLanguage() { return m_pchUpdatedAudioLanguage; }
+
+private:
+ MESSAGE_FUNC( OnControlModified, "ControlModified" );
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" )
+ {
+ OnControlModified();
+ }
+
+ MESSAGE_FUNC( RunTestSpeakers, "RunTestSpeakers" );
+
+ vgui::ComboBox *m_pSpeakerSetupCombo;
+ vgui::ComboBox *m_pSoundQualityCombo;
+ CCvarSlider *m_pSFXSlider;
+ CCvarSlider *m_pMusicSlider;
+ vgui::ComboBox *m_pCloseCaptionCombo;
+ bool m_bRequireRestart;
+
+ vgui::ComboBox *m_pSpokenLanguageCombo;
+ MESSAGE_FUNC( OpenThirdPartySoundCreditsDialog, "OpenThirdPartySoundCreditsDialog" );
+ vgui::DHANDLE<class COptionsSubAudioThirdPartyCreditsDlg> m_OptionsSubAudioThirdPartyCreditsDlg;
+ ELanguage m_nCurrentAudioLanguage;
+ static char *m_pchUpdatedAudioLanguage;
+
+ CCvarToggleCheckButton *m_pSoundMuteLoseFocusCheckButton;
+};
+
+
+
+#endif // OPTIONS_SUB_AUDIO_H
diff --git a/gameui/OptionsSubDifficulty.cpp b/gameui/OptionsSubDifficulty.cpp
new file mode 100644
index 0000000..2e2e47f
--- /dev/null
+++ b/gameui/OptionsSubDifficulty.cpp
@@ -0,0 +1,79 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "OptionsSubDifficulty.h"
+#include "tier1/convar.h"
+#include "EngineInterface.h"
+#include "tier1/KeyValues.h"
+
+#include "vgui_controls/RadioButton.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+COptionsSubDifficulty::COptionsSubDifficulty(vgui::Panel *parent) : BaseClass(parent, NULL)
+{
+ m_pEasyRadio = new RadioButton(this, "Skill1Radio", "#GameUI_SkillEasy");
+ m_pNormalRadio = new RadioButton(this, "Skill2Radio", "#GameUI_SkillNormal");
+ m_pHardRadio = new RadioButton(this, "Skill3Radio", "#GameUI_SkillHard");
+
+ LoadControlSettings("Resource/OptionsSubDifficulty.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: resets controls
+//-----------------------------------------------------------------------------
+void COptionsSubDifficulty::OnResetData()
+{
+ ConVarRef var( "skill" );
+
+ if (var.GetInt() == 1)
+ {
+ m_pEasyRadio->SetSelected(true);
+ }
+ else if (var.GetInt() == 3)
+ {
+ m_pHardRadio->SetSelected(true);
+ }
+ else
+ {
+ m_pNormalRadio->SetSelected(true);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets data based on control settings
+//-----------------------------------------------------------------------------
+void COptionsSubDifficulty::OnApplyChanges()
+{
+ ConVarRef var( "skill" );
+
+ if ( m_pEasyRadio->IsSelected() )
+ {
+ var.SetValue( 1 );
+ }
+ else if ( m_pHardRadio->IsSelected() )
+ {
+ var.SetValue( 3 );
+ }
+ else
+ {
+ var.SetValue( 2 );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: enables apply button on radio buttons being pressed
+//-----------------------------------------------------------------------------
+void COptionsSubDifficulty::OnRadioButtonChecked()
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+}
diff --git a/gameui/OptionsSubDifficulty.h b/gameui/OptionsSubDifficulty.h
new file mode 100644
index 0000000..947a172
--- /dev/null
+++ b/gameui/OptionsSubDifficulty.h
@@ -0,0 +1,38 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_DIFFICULTY_H
+#define OPTIONS_SUB_DIFFICULTY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PropertyPage.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Difficulty selection options
+//-----------------------------------------------------------------------------
+class COptionsSubDifficulty : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubDifficulty, vgui::PropertyPage );
+
+public:
+ COptionsSubDifficulty(vgui::Panel *parent);
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+
+ MESSAGE_FUNC( OnRadioButtonChecked, "RadioButtonChecked" );
+
+private:
+ vgui::RadioButton *m_pEasyRadio;
+ vgui::RadioButton *m_pNormalRadio;
+ vgui::RadioButton *m_pHardRadio;
+};
+
+
+#endif // OPTIONS_SUB_DIFFICULTY_H \ No newline at end of file
diff --git a/gameui/OptionsSubGame.cpp b/gameui/OptionsSubGame.cpp
new file mode 100644
index 0000000..3092ea1
--- /dev/null
+++ b/gameui/OptionsSubGame.cpp
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "OptionsSubGame.h"
+#include "BasePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+COptionsSubGame::COptionsSubGame( vgui::Panel *parent, const char *name ) : BaseClass( parent, name )
+{
+ SetDeleteSelfOnClose( true );
+ LoadControlSettings( "Resource/OptionsSubGame.res" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+COptionsSubGame::~COptionsSubGame()
+{
+}
+
+void COptionsSubGame::OnClose( void )
+{
+ BasePanel()->RunCloseAnimation( "CloseOptionsSubGame" );
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubGame::OnCommand( const char *command )
+{
+ BaseClass::OnCommand( command );
+}
diff --git a/gameui/OptionsSubGame.h b/gameui/OptionsSubGame.h
new file mode 100644
index 0000000..f3c9b63
--- /dev/null
+++ b/gameui/OptionsSubGame.h
@@ -0,0 +1,35 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_GAME_H
+#define OPTIONS_SUB_GAME_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Frame.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Game Settings, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubGame : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubGame, vgui::Frame );
+
+public:
+ COptionsSubGame( vgui::Panel *parent, const char *name );
+ ~COptionsSubGame( void );
+
+ virtual void OnCommand( const char *command );
+ virtual void OnClose( void );
+
+private:
+};
+
+
+
+#endif // OPTIONS_SUB_GAME_H
diff --git a/gameui/OptionsSubHaptics.cpp b/gameui/OptionsSubHaptics.cpp
new file mode 100644
index 0000000..a567dbd
--- /dev/null
+++ b/gameui/OptionsSubHaptics.cpp
@@ -0,0 +1,196 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "OptionsSubHaptics.h"
+//#include "CommandCheckButton.h"
+#include "KeyToggleCheckButton.h"
+#include "CvarNegateCheckButton.h"
+#include "CvarToggleCheckButton.h"
+#include "cvarslider.h"
+
+#include "EngineInterface.h"
+
+#include <KeyValues.h>
+#include <vgui/IScheme.h>
+#include "tier1/convar.h"
+#include <stdio.h>
+#include <vgui_controls/TextEntry.h>
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+bool HasFalcon() {
+ ConVarRef hap_hasDevice("hap_hasDevice");
+ return (hap_hasDevice.IsValid() && hap_hasDevice.GetBool());
+}
+
+void COptionsSubHaptics::OnCommand(const char *command)
+{
+ if ( !stricmp( command, "DoDefaults" ) )
+ {
+ engine->ClientCmd_Unrestricted("exec haptics_default.cfg");
+ OnResetData();
+ }
+
+}
+COptionsSubHaptics::COptionsSubHaptics(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+
+ m_pForceMasterPreLabel = new Label(this, "ForceMasterPreLabel", "#GameUI_Haptics_ForceMasterScale" );
+ m_pForceMasterSlider = new CCvarSlider( this, "ForceMasterSlider", "#GameUI_Haptics_ForceMasterScale",
+ 0.000001f, 3.0f, "hap_ForceMasterScale", true );
+
+ m_pForceRecoilPreLabel = new Label(this, "ForceRecoilPreLabel", "#GameUI_Haptics_RecoilScale" );
+ m_pForceRecoilSlider = new CCvarSlider( this, "ForceRecoilSlider", "#GameUI_Haptics_RecoilScale",
+ 0.000001f, 3.0f, "hap_ForceRecoilScale", true );
+
+ m_pForceDamagePreLabel = new Label(this, "ForceDamagePreLabel", "#GameUI_Haptics_DamageScale" );
+ m_pForceDamageSlider = new CCvarSlider( this, "ForceDamageSlider", "#GameUI_Haptics_DamageScale",
+ 0.000001f, 5.0f, "hap_ForceDamageScale" , true );
+
+ m_pForceMovementPreLabel = new Label(this, "ForceMovementPreLabel", "#GameUI_Haptics_MovementScale" );
+ m_pForceMovementSlider = new CCvarSlider( this, "ForceMovementSlider", "#GameUI_Haptics_MovementScale",
+ 0.000001f, 3.0f, "hap_ForceMovementScale", true );
+
+ //Player scaling
+ m_pPlayerBoxPreLabel = new Label(this, "PlayerBoxPreLabel", "#GameUI_Haptics_PlayerBoxLabel" );
+ m_pPlayerBoxScalePreLabel = new Label(this, "PlayerScalePreLabel", "#GameUI_Haptics_Scale" );
+ m_pPlayerBoxScale = new CCvarSlider( this, "PlayerBoxScaleSlider", "#GameUI_Haptics_PlayerBoxScale",
+ 0.1f, 0.9f, "hap_PlayerBoxScale", true );
+ m_pPlayerBoxVisual = new ControlBoxVisual(this, "PlayerBoxVisual", m_pPlayerBoxScale, m_pPlayerBoxScale, m_pPlayerBoxScale, m_pPlayerBoxScale, m_pPlayerBoxScale, m_pPlayerBoxScale);
+ m_pPlayerBoxStiffnessPreLabel = new Label(this, "PlayerStiffnessPreLabel", "#GameUI_Haptics_PlayerBoxStiffness" );
+ m_pPlayerBoxStiffnessSlider = new CCvarSlider( this, "PlayerStiffnessSlider", "#GameUI_Haptics_PlayerBoxScale",
+ 0.0f, 3.0f, "hap_PlayerBoxStiffness", true );
+ m_pPlayerBoxTurnPreLabel = new Label(this, "PlayerTurnPreLabel", "#GameUI_Haptics_Turning" );
+ m_pPlayerBoxTurnSlider = new CCvarSlider( this, "PlayerTurnSlider", "#GameUI_Haptics_Turning",
+ 0.0f, 2.0f, "hap_PlayerTurnScale", true );
+ m_pPlayerBoxAimPreLabel = new Label(this, "PlayerAimPreLabel", "#GameUI_Haptics_Aiming" );
+ m_pPlayerBoxAimSlider = new CCvarSlider( this, "PlayerAimSlider", "#GameUI_Haptics_Aiming",
+ 0.0f, 2.0f, "hap_PlayerAimScale", true );
+
+
+ //Vehicle Scaling
+ m_pVehicleBoxPreLabel = new Label(this, "VehicleBoxPreLabel", "#GameUI_Haptics_VehicleBoxLabel" );
+ m_pVehicleBoxScalePreLabel = new Label(this, "VehicleScalePreLabel", "#GameUI_Haptics_Scale" );
+ m_pVehicleBoxScale = new CCvarSlider( this, "VehicleBoxScaleSlider", "#GameUI_Haptics_VehicleBoxScale",
+ 0.1f, 0.6f, "hap_VehicleBoxScale", true );
+ m_pVehicleBoxVisual = new ControlBoxVisual(this, "VehicleBoxVisual", m_pVehicleBoxScale, m_pVehicleBoxScale, m_pVehicleBoxScale, m_pVehicleBoxScale, m_pVehicleBoxScale, m_pVehicleBoxScale);
+ m_pVehicleBoxStiffnessPreLabel = new Label(this, "VehicleStiffnessPreLabel", "#GameUI_Haptics_VehicleBoxStiffness" );
+ m_pVehicleBoxStiffnessSlider = new CCvarSlider( this, "VehicleStiffnessSlider", "#GameUI_Haptics_VehicleBoxScale",
+ 0.0f, 3.0f, "hap_VehicleBoxStiffness", true );
+ m_pVehicleBoxTurnPreLabel = new Label(this, "VehicleTurnPreLabel", "#GameUI_Haptics_Turning" );
+ m_pVehicleBoxTurnSlider = new CCvarSlider( this, "VehicleTurnSlider", "#GameUI_Haptics_Turning",
+ 0.0f, 2.0f, "hap_VehicleTurnScale", true );
+ m_pVehicleBoxAimPreLabel = new Label(this, "VehicleAimPreLabel", "#GameUI_Haptics_Aiming" );
+ m_pVehicleBoxAimSlider = new CCvarSlider( this, "VehicleAimSlider", "#GameUI_Haptics_Aiming",
+ 0.0f, 2.0f, "hap_VehicleAimScale", true );
+
+
+ vgui::Button *defaults = new vgui::Button( this, "Defaults", "Use Defaults" );
+ defaults->SetCommand("DoDefaults");
+
+ LoadControlSettings("Resource\\OptionsSubHaptics.res");
+ UpdateVehicleEnabled();
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubHaptics::~COptionsSubHaptics()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubHaptics::OnResetData()
+{
+ m_pForceMasterSlider->Reset();
+ m_pForceDamageSlider->Reset();
+ m_pForceRecoilSlider->Reset();
+ m_pForceMovementSlider->Reset();
+
+ m_pPlayerBoxScale->Reset();
+ m_pPlayerBoxStiffnessSlider->Reset();
+ m_pPlayerBoxTurnSlider->Reset();
+ m_pPlayerBoxAimSlider->Reset();
+
+ m_pVehicleBoxScale->Reset();
+ m_pVehicleBoxStiffnessSlider->Reset();
+ m_pVehicleBoxTurnSlider->Reset();
+ m_pVehicleBoxAimSlider->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubHaptics::OnApplyChanges()
+{
+ m_pForceMasterSlider->ApplyChanges();
+ m_pForceDamageSlider->ApplyChanges();
+ m_pForceRecoilSlider->ApplyChanges();
+ m_pForceMovementSlider->ApplyChanges();
+
+ m_pPlayerBoxScale->ApplyChanges();
+ m_pPlayerBoxStiffnessSlider->ApplyChanges();
+ m_pPlayerBoxTurnSlider->ApplyChanges();
+ m_pPlayerBoxAimSlider->ApplyChanges();
+
+ m_pVehicleBoxScale->ApplyChanges();
+ m_pVehicleBoxStiffnessSlider->ApplyChanges();
+ m_pVehicleBoxTurnSlider->ApplyChanges();
+ m_pVehicleBoxAimSlider->ApplyChanges();
+
+
+ //Write out our config file
+ engine->ClientCmd_Unrestricted("writehapticconfig");
+ engine->ClientCmd_Unrestricted("reloadhaptics");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets background color & border
+//-----------------------------------------------------------------------------
+void COptionsSubHaptics::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubHaptics::OnControlModified(Panel *panel)
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubHaptics::OnTextChanged(Panel *panel)
+{
+}
+
+void COptionsSubHaptics::UpdateVehicleEnabled()
+{
+ ConVarRef checkVehicle("hap_ui_vehicles");
+ checkVehicle.Init("hap_ui_vehicles",true);
+ bool bEnabled = checkVehicle.GetBool();
+
+ m_pVehicleBoxPreLabel->SetEnabled( bEnabled );
+ m_pVehicleBoxScalePreLabel->SetEnabled( bEnabled );
+ m_pVehicleBoxScale->SetEnabled( bEnabled );
+ m_pVehicleBoxStiffnessPreLabel->SetEnabled( bEnabled );
+ m_pVehicleBoxStiffnessSlider->SetEnabled( bEnabled );
+ m_pVehicleBoxTurnPreLabel->SetEnabled( bEnabled );
+ m_pVehicleBoxTurnSlider->SetEnabled( bEnabled );
+ m_pVehicleBoxAimPreLabel ->SetEnabled( bEnabled );
+ m_pVehicleBoxAimSlider ->SetEnabled( bEnabled );
+}
diff --git a/gameui/OptionsSubHaptics.h b/gameui/OptionsSubHaptics.h
new file mode 100644
index 0000000..d623cec
--- /dev/null
+++ b/gameui/OptionsSubHaptics.h
@@ -0,0 +1,100 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_HAPTICS_H
+#define OPTIONS_SUB_HAPTICS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+#include "HapticControlBox.h"
+
+
+class CCvarNegateCheckButton;
+class CKeyToggleCheckButton;
+class CCvarToggleCheckButton;
+class CCvarSlider;
+
+namespace vgui
+{
+ class Label;
+ class Panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Mouse Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubHaptics : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubHaptics, vgui::PropertyPage );
+
+public:
+ COptionsSubHaptics(vgui::Panel *parent);
+ ~COptionsSubHaptics();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+ virtual void OnCommand(const char *command);
+ virtual void UpdateVehicleEnabled(void);
+
+protected:
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+private:
+ MESSAGE_FUNC_PTR( OnControlModified, "ControlModified", panel );
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel )
+ {
+ OnControlModified( panel );
+ }
+
+ vgui::Label *m_pForceMasterPreLabel;
+ CCvarSlider *m_pForceMasterSlider;
+
+ vgui::Label *m_pForceRecoilPreLabel;
+ CCvarSlider *m_pForceRecoilSlider;
+
+
+ vgui::Label *m_pForceDamagePreLabel;
+ CCvarSlider *m_pForceDamageSlider;
+
+ vgui::Label *m_pForceMovementPreLabel;
+ CCvarSlider *m_pForceMovementSlider;
+
+
+
+ //Player
+ vgui::Label *m_pPlayerBoxPreLabel;
+ vgui::Label *m_pPlayerBoxScalePreLabel;
+ CCvarSlider * m_pPlayerBoxScale;
+ ControlBoxVisual* m_pPlayerBoxVisual;
+ vgui::Label *m_pPlayerBoxStiffnessPreLabel;
+ CCvarSlider *m_pPlayerBoxStiffnessSlider;
+ vgui::Label *m_pPlayerBoxTurnPreLabel;
+ CCvarSlider *m_pPlayerBoxTurnSlider;
+ vgui::Label *m_pPlayerBoxAimPreLabel;
+ CCvarSlider *m_pPlayerBoxAimSlider;
+
+ //Vehicle
+ vgui::Label *m_pVehicleBoxPreLabel;
+ vgui::Label *m_pVehicleBoxScalePreLabel;
+ CCvarSlider * m_pVehicleBoxScale;
+ ControlBoxVisual* m_pVehicleBoxVisual;
+ vgui::Label *m_pVehicleBoxStiffnessPreLabel;
+ CCvarSlider * m_pVehicleBoxStiffnessSlider;
+ vgui::Label *m_pVehicleBoxTurnPreLabel;
+ CCvarSlider *m_pVehicleBoxTurnSlider;
+ vgui::Label *m_pVehicleBoxAimPreLabel;
+ CCvarSlider *m_pVehicleBoxAimSlider;
+
+ //Control Box Stuff
+};
+
+
+
+#endif // OPTIONS_SUB_MOUSE_H \ No newline at end of file
diff --git a/gameui/OptionsSubKeyboard.cpp b/gameui/OptionsSubKeyboard.cpp
new file mode 100644
index 0000000..f545917
--- /dev/null
+++ b/gameui/OptionsSubKeyboard.cpp
@@ -0,0 +1,839 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+
+#include "OptionsSubKeyboard.h"
+#include "EngineInterface.h"
+#include "vcontrolslistpanel.h"
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/ListPanel.h>
+#include <vgui_controls/QueryBox.h>
+
+#include <vgui/Cursor.h>
+#include <vgui/IVGui.h>
+#include <vgui/ISurface.h>
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include <vgui/KeyCode.h>
+#include <vgui/MouseCode.h>
+#include <vgui/ISystem.h>
+#include <vgui/IInput.h>
+
+#include "filesystem.h"
+#include "tier1/utlbuffer.h"
+#include "IGameUIFuncs.h"
+#include <vstdlib/IKeyValuesSystem.h>
+#include "tier2/tier2.h"
+#include "inputsystem/iinputsystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+COptionsSubKeyboard::COptionsSubKeyboard(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+ memset( m_Bindings, 0, sizeof( m_Bindings ));
+
+ // create the key bindings list
+ CreateKeyBindingList();
+ // Store all current key bindings
+ SaveCurrentBindings();
+ // Parse default descriptions
+ ParseActionDescriptions();
+
+ m_pSetBindingButton = new Button(this, "ChangeKeyButton", "");
+ m_pClearBindingButton = new Button(this, "ClearKeyButton", "");
+
+ LoadControlSettings("Resource/OptionsSubKeyboard.res");
+
+ m_pSetBindingButton->SetEnabled(false);
+ m_pClearBindingButton->SetEnabled(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+COptionsSubKeyboard::~COptionsSubKeyboard()
+{
+ DeleteSavedBindings();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: reloads current keybinding
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnResetData()
+{
+ // Populate list based on current settings
+ FillInCurrentBindings();
+ if ( IsVisible() )
+ {
+ m_pKeyBindList->SetSelectedItem(0);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: saves out keybinding changes
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnApplyChanges()
+{
+ ApplyAllBindings();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create key bindings list control
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::CreateKeyBindingList()
+{
+ // Create the control
+ m_pKeyBindList = new VControlsListPanel(this, "listpanel_keybindlist");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: binds double-clicking or hitting enter in the keybind list to changing the key
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnKeyCodeTyped(vgui::KeyCode code)
+{
+ if (code == KEY_ENTER)
+ {
+ OnCommand("ChangeKey");
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: command handler
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "Defaults" ) )
+ {
+ // open a box asking if we want to restore defaults
+ QueryBox *box = new QueryBox("#GameUI_KeyboardSettings", "#GameUI_KeyboardSettingsText");
+ box->AddActionSignalTarget(this);
+ box->SetOKCommand(new KeyValues("Command", "command", "DefaultsOK"));
+ box->DoModal();
+ }
+ else if ( !stricmp(command, "DefaultsOK"))
+ {
+ // Restore defaults from default keybindings file
+ FillInDefaultBindings();
+ m_pKeyBindList->RequestFocus();
+ }
+ else if ( !m_pKeyBindList->IsCapturing() && !stricmp( command, "ChangeKey" ) )
+ {
+ m_pKeyBindList->StartCaptureMode(dc_blank);
+ }
+ else if ( !m_pKeyBindList->IsCapturing() && !stricmp( command, "ClearKey" ) )
+ {
+ OnKeyCodePressed(KEY_DELETE);
+ m_pKeyBindList->RequestFocus();
+ }
+ else if ( !stricmp(command, "Advanced") )
+ {
+ OpenKeyboardAdvancedDialog();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+const char *UTIL_Parse( const char *data, char *token, int sizeofToken )
+{
+ data = engine->ParseFile( data, token, sizeofToken );
+ return data;
+}
+static char *UTIL_CopyString( const char *in )
+{
+ int len = strlen( in ) + 1;
+ char *out = new char[ len ];
+ Q_strncpy( out, in, len );
+ return out;
+}
+
+#ifndef _XBOX
+char *UTIL_va(char *format, ...)
+{
+ va_list argptr;
+ static char string[4][1024];
+ static int curstring = 0;
+
+ curstring = ( curstring + 1 ) % 4;
+
+ va_start (argptr, format);
+ Q_vsnprintf( string[curstring], 1024, format, argptr );
+ va_end (argptr);
+
+ return string[curstring];
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::ParseActionDescriptions( void )
+{
+ char szBinding[256];
+ char szDescription[256];
+
+ KeyValues *item;
+
+ // Load the default keys list
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ if ( !g_pFullFileSystem->ReadFile( "scripts/kb_act.lst", NULL, buf ) )
+ return;
+
+ const char *data = (const char*)buf.Base();
+
+ int sectionIndex = 0;
+ char token[512];
+ while ( 1 )
+ {
+ data = UTIL_Parse( data, token, sizeof(token) );
+ // Done.
+ if ( strlen( token ) <= 0 )
+ break;
+
+ Q_strncpy( szBinding, token, sizeof( szBinding ) );
+
+ data = UTIL_Parse( data, token, sizeof(token) );
+ if ( strlen(token) <= 0 )
+ {
+ break;
+ }
+
+ Q_strncpy(szDescription, token, sizeof( szDescription ) );
+
+ // Skip '======' rows
+ if ( szDescription[ 0 ] != '=' )
+ {
+ // Flag as special header row if binding is "blank"
+ if (!stricmp(szBinding, "blank"))
+ {
+ // add header item
+ m_pKeyBindList->AddSection(++sectionIndex, szDescription);
+ m_pKeyBindList->AddColumnToSection(sectionIndex, "Action", szDescription, SectionedListPanel::COLUMN_BRIGHT, 286);
+ m_pKeyBindList->AddColumnToSection(sectionIndex, "Key", "#GameUI_KeyButton", SectionedListPanel::COLUMN_BRIGHT, 128);
+ }
+ else
+ {
+ // Create a new: blank item
+ item = new KeyValues( "Item" );
+
+ // fill in data
+ item->SetString("Action", szDescription);
+ item->SetString("Binding", szBinding);
+ item->SetString("Key", "");
+
+ // Add to list
+ m_pKeyBindList->AddItem(sectionIndex, item);
+ item->deleteThis();
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Search current data set for item which has the specified binding string
+// Input : *binding - string to find
+// Output : KeyValues or NULL on failure
+//-----------------------------------------------------------------------------
+KeyValues *COptionsSubKeyboard::GetItemForBinding( const char *binding )
+{
+ static int bindingSymbol = KeyValuesSystem()->GetSymbolForString("Binding");
+
+ // Loop through all items
+ for (int i = 0; i < m_pKeyBindList->GetItemCount(); i++)
+ {
+ KeyValues *item = m_pKeyBindList->GetItemData(m_pKeyBindList->GetItemIDFromRow(i));
+ if ( !item )
+ continue;
+
+ KeyValues *bindingItem = item->FindKey(bindingSymbol);
+ const char *bindString = bindingItem->GetString();
+
+ // Check the "Binding" key
+ if (!stricmp(bindString, binding))
+ return item;
+ }
+ // Didn't find it
+ return NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Bind the specified keyname to the specified item
+// Input : *item - Item to which to add the key
+// *keyname - The key to be added
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::AddBinding( KeyValues *item, const char *keyname )
+{
+ // See if it's already there as a binding
+ if ( !stricmp( item->GetString( "Key", "" ), keyname ) )
+ return;
+
+ // Make sure it doesn't live anywhere
+ RemoveKeyFromBindItems( item, keyname );
+
+ const char *binding = item->GetString( "Binding", "" );
+
+ // Loop through all the key bindings and set all entries that have
+ // the same binding. This allows us to have multiple entries pointing
+ // to the same binding.
+ for (int i = 0; i < m_pKeyBindList->GetItemCount(); i++)
+ {
+ KeyValues *curitem = m_pKeyBindList->GetItemData(m_pKeyBindList->GetItemIDFromRow(i));
+ if ( !curitem )
+ continue;
+
+ const char *curbinding = curitem->GetString( "Binding", "" );
+
+ if (!stricmp(curbinding, binding))
+ {
+ curitem->SetString( "Key", keyname );
+ m_pKeyBindList->InvalidateItem(i);
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all keys from list
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::ClearBindItems( void )
+{
+ for (int i = 0; i < m_pKeyBindList->GetItemCount(); i++)
+ {
+ KeyValues *item = m_pKeyBindList->GetItemData(m_pKeyBindList->GetItemIDFromRow(i));
+ if ( !item )
+ continue;
+
+ // Reset keys
+ item->SetString( "Key", "" );
+
+ m_pKeyBindList->InvalidateItem(i);
+ }
+
+ m_pKeyBindList->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove all instances of the specified key from bindings
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::RemoveKeyFromBindItems( KeyValues *org_item, const char *key )
+{
+ Assert( key && key[ 0 ] );
+ if ( !key || !key[ 0 ] )
+ return;
+
+ int len = Q_strlen( key );
+ char *pszKey = new char[len + 1];
+
+ if ( !pszKey )
+ return;
+
+ Q_memcpy( pszKey, key, len+1 );
+
+ for (int i = 0; i < m_pKeyBindList->GetItemCount(); i++)
+ {
+ KeyValues *item = m_pKeyBindList->GetItemData(m_pKeyBindList->GetItemIDFromRow(i));
+ if ( !item )
+ continue;
+
+ // If it's bound to the primary: then remove it
+ if ( !stricmp( pszKey, item->GetString( "Key", "" ) ) )
+ {
+ bool bClearEntry = true;
+
+ if ( org_item )
+ {
+ // Only clear it out if the actual binding isn't the same. This allows
+ // us to have the same key bound to multiple entries in the keybinding list
+ // if they point to the same command.
+ const char *org_binding = org_item->GetString( "Binding", "" );
+ const char *binding = item->GetString( "Binding", "" );
+ if ( !stricmp( org_binding, binding ) )
+ {
+ bClearEntry = false;
+ }
+ }
+
+ if ( bClearEntry )
+ {
+ item->SetString( "Key", "" );
+ m_pKeyBindList->InvalidateItem(i);
+ }
+ }
+ }
+
+ delete [] pszKey;
+
+ // Make sure the display is up to date
+ m_pKeyBindList->InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Ask the engine for all bindings and set up the list
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::FillInCurrentBindings( void )
+{
+ // reset the unbind list
+ // we only unbind keys used by the normal config items (not custom binds)
+ m_KeysToUnbind.RemoveAll();
+
+ // Clear any current settings
+ ClearBindItems();
+
+ bool bJoystick = false;
+ ConVarRef var( "joystick" );
+ if ( var.IsValid() )
+ {
+ bJoystick = var.GetBool();
+ }
+
+ // NVNT see if we have a falcon connected.
+ bool bFalcon = false;
+ ConVarRef falconVar("hap_HasDevice");
+ if ( var.IsValid() )
+ {
+ bFalcon = var.GetBool();
+ }
+
+ for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
+ {
+ // Look up binding
+ const char *binding = gameuifuncs->GetBindingForButtonCode( (ButtonCode_t)i );
+ if ( !binding )
+ continue;
+
+ // See if there is an item for this one?
+ KeyValues *item = GetItemForBinding( binding );
+ if ( item )
+ {
+ // Bind it by name
+ const char *keyName = g_pInputSystem->ButtonCodeToString( (ButtonCode_t)i );
+
+ // Already in list, means user had two keys bound to this item. We'll only note the first one we encounter
+ char const *currentKey = item->GetString( "Key", "" );
+ if ( currentKey && currentKey[ 0 ] )
+ {
+ ButtonCode_t currentBC = (ButtonCode_t)gameuifuncs->GetButtonCodeForBind( currentKey );
+
+ // If we're using a joystick, joystick bindings override keyboard ones
+ bool bShouldOverride = bJoystick && IsJoystickCode((ButtonCode_t)i) && !IsJoystickCode(currentBC);
+ // NVNT If we're not using a joystick, falcon bindings override keyboard ones
+ if( !bShouldOverride && bFalcon && IsNovintCode((ButtonCode_t)i) && !IsNovintCode(currentBC) )
+ bShouldOverride = true;
+
+ if ( !bShouldOverride )
+ continue;
+
+ // Remove the key we're about to override from the unbinding list
+ m_KeysToUnbind.FindAndRemove( currentKey );
+ }
+
+ AddBinding( item, keyName );
+
+ // remember to apply unbinding of this key when we apply
+ m_KeysToUnbind.AddToTail( keyName );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clean up memory used by saved bindings
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::DeleteSavedBindings( void )
+{
+ for ( int i = 0; i < BUTTON_CODE_LAST; i++ )
+ {
+ if ( m_Bindings[ i ].binding )
+ {
+ delete[] m_Bindings[ i ].binding;
+ m_Bindings[ i ].binding = NULL;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Copy all bindings into save array
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::SaveCurrentBindings( void )
+{
+ DeleteSavedBindings();
+ for (int i = 0; i < BUTTON_CODE_LAST; i++)
+ {
+ const char *binding = gameuifuncs->GetBindingForButtonCode( (ButtonCode_t)i );
+ if ( !binding || !binding[0])
+ continue;
+
+ // Copy the binding string
+ m_Bindings[ i ].binding = UTIL_CopyString( binding );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tells the engine to bind a key
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::BindKey( const char *key, const char *binding )
+{
+#ifndef _XBOX
+ engine->ClientCmd_Unrestricted( UTIL_va( "bind \"%s\" \"%s\"\n", key, binding ) );
+#else
+ char buff[256];
+ Q_snprintf(buff, sizeof(buff), "bind \"%s\" \"%s\"\n", key, binding);
+ engine->ClientCmd_Unrestricted(buff);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tells the engine to unbind a key
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::UnbindKey( const char *key )
+{
+#ifndef _XBOX
+ engine->ClientCmd_Unrestricted( UTIL_va( "unbind \"%s\"\n", key ) );
+#else
+ char buff[256];
+ Q_snprintf(buff, sizeof(buff), "unbind \"%s\"\n", key);
+ engine->ClientCmd_Unrestricted(buff);
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Go through list and bind specified keys to actions
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::ApplyAllBindings( void )
+{
+ // unbind everything that the user unbound
+ {for (int i = 0; i < m_KeysToUnbind.Count(); i++)
+ {
+ UnbindKey(m_KeysToUnbind[i].String());
+ }}
+ m_KeysToUnbind.RemoveAll();
+
+ // free binding memory
+ DeleteSavedBindings();
+
+ for (int i = 0; i < m_pKeyBindList->GetItemCount(); i++)
+ {
+ KeyValues *item = m_pKeyBindList->GetItemData(m_pKeyBindList->GetItemIDFromRow(i));
+ if ( !item )
+ continue;
+
+ // See if it has a binding
+ const char *binding = item->GetString( "Binding", "" );
+ if ( !binding || !binding[ 0 ] )
+ continue;
+
+ const char *keyname;
+
+ // Check main binding
+ keyname = item->GetString( "Key", "" );
+ if ( keyname && keyname[ 0 ] )
+ {
+ // Tell the engine
+ BindKey( keyname, binding );
+ ButtonCode_t code = g_pInputSystem->StringToButtonCode( keyname );
+ if ( code != BUTTON_CODE_INVALID )
+ {
+ m_Bindings[ code ].binding = UTIL_CopyString( binding );
+ }
+ }
+ }
+
+ // Now exec their custom bindings
+ engine->ClientCmd_Unrestricted( "exec userconfig.cfg\nhost_writeconfig\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Read in defaults from game's default config file and populate list
+// using those defaults
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::FillInDefaultBindings( void )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+ if ( !g_pFullFileSystem->ReadFile( "cfg/config_default.cfg", NULL, buf ) )
+ return;
+
+ // Clear out all current bindings
+ ClearBindItems();
+
+ const char *data = (const char*)buf.Base();
+
+ // loop through all the binding
+ while ( data != NULL )
+ {
+ char cmd[64];
+ data = UTIL_Parse( data, cmd, sizeof(cmd) );
+ if ( strlen( cmd ) <= 0 )
+ break;
+
+ if ( !stricmp(cmd, "bind") )
+ {
+ // Key name
+ char szKeyName[256];
+ data = UTIL_Parse( data, szKeyName, sizeof(szKeyName) );
+ if ( strlen( szKeyName ) <= 0 )
+ break; // Error
+
+ char szBinding[256];
+ data = UTIL_Parse( data, szBinding, sizeof(szBinding) );
+ if ( strlen( szKeyName ) <= 0 )
+ break; // Error
+
+ // Find item
+ KeyValues *item = GetItemForBinding( szBinding );
+ if ( item )
+ {
+ // Bind it
+ AddBinding( item, szKeyName );
+ }
+ }
+ }
+
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+
+ // Make sure console and escape key are always valid
+ KeyValues *item = GetItemForBinding( "toggleconsole" );
+ if (item)
+ {
+ // Bind it
+ AddBinding( item, "`" );
+ }
+ item = GetItemForBinding( "cancelselect" );
+ if (item)
+ {
+ // Bind it
+ AddBinding( item, "ESCAPE" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: User clicked on item: remember where last active row/column was
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::ItemSelected(int itemID)
+{
+ m_pKeyBindList->SetItemOfInterest(itemID);
+
+ if (m_pKeyBindList->IsItemIDValid(itemID))
+ {
+ // find the details, see if we should be enabled/clear/whatever
+ m_pSetBindingButton->SetEnabled(true);
+
+ KeyValues *kv = m_pKeyBindList->GetItemData(itemID);
+ if (kv)
+ {
+ const char *key = kv->GetString("Key", NULL);
+ if (key && *key)
+ {
+ m_pClearBindingButton->SetEnabled(true);
+ }
+ else
+ {
+ m_pClearBindingButton->SetEnabled(false);
+ }
+
+ if (kv->GetInt("Header"))
+ {
+ m_pSetBindingButton->SetEnabled(false);
+ }
+ }
+ }
+ else
+ {
+ m_pSetBindingButton->SetEnabled(false);
+ m_pClearBindingButton->SetEnabled(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: called when the capture has finished
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::Finish( ButtonCode_t code )
+{
+ int r = m_pKeyBindList->GetItemOfInterest();
+
+ // Retrieve clicked row and column
+ m_pKeyBindList->EndCaptureMode( dc_arrow );
+
+ // Find item for this row
+ KeyValues *item = m_pKeyBindList->GetItemData(r);
+ if ( item )
+ {
+ // Handle keys: but never rebind the escape key
+ // Esc just exits bind mode silently
+ if ( code != BUTTON_CODE_NONE && code != KEY_ESCAPE && code != BUTTON_CODE_INVALID )
+ {
+ // Bind the named key
+ AddBinding( item, g_pInputSystem->ButtonCodeToString( code ) );
+ PostActionSignal( new KeyValues( "ApplyButtonEnable" ) );
+ }
+
+ m_pKeyBindList->InvalidateItem(r);
+ }
+
+ m_pSetBindingButton->SetEnabled(true);
+ m_pClearBindingButton->SetEnabled(true);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Scans for captured key presses
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnThink()
+{
+ BaseClass::OnThink();
+
+ if ( m_pKeyBindList->IsCapturing() )
+ {
+ ButtonCode_t code = BUTTON_CODE_INVALID;
+ if ( engine->CheckDoneKeyTrapping( code ) )
+ {
+ Finish( code );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check for enter key and go into keybinding mode if it was pressed
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OnKeyCodePressed(vgui::KeyCode code)
+{
+ // Enter key pressed and not already trapping next key/button press
+ if ( !m_pKeyBindList->IsCapturing() )
+ {
+ // Grab which item was set as interesting
+ int r = m_pKeyBindList->GetItemOfInterest();
+
+ // Check that it's visible
+ int x, y, w, h;
+ bool visible = m_pKeyBindList->GetCellBounds(r, 1, x, y, w, h);
+ if (visible)
+ {
+ if ( KEY_DELETE == code )
+ {
+ // find the current binding and remove it
+ KeyValues *kv = m_pKeyBindList->GetItemData(r);
+
+ const char *key = kv->GetString("Key", NULL);
+ if (key && *key)
+ {
+ RemoveKeyFromBindItems(NULL, key);
+ }
+
+ m_pClearBindingButton->SetEnabled(false);
+ m_pKeyBindList->InvalidateItem(r);
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+
+ // message handled, don't pass on
+ return;
+ }
+ }
+ }
+
+ // Allow base class to process message instead
+ BaseClass::OnKeyCodePressed( code );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: advanced keyboard settings dialog
+//-----------------------------------------------------------------------------
+class COptionsSubKeyboardAdvancedDlg : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubKeyboardAdvancedDlg, vgui::Frame );
+public:
+ COptionsSubKeyboardAdvancedDlg( vgui::VPANEL hParent ) : BaseClass( NULL, NULL )
+ {
+ // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
+
+ SetTitle("#GameUI_KeyboardAdvanced_Title", true);
+ SetSize( 280, 140 );
+ LoadControlSettings( "resource/OptionsSubKeyboardAdvancedDlg.res" );
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+ SetDeleteSelfOnClose( true );
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+
+ input()->SetAppModalSurface(GetVPanel());
+
+ // reset the data
+ ConVarRef con_enable( "con_enable" );
+ if ( con_enable.IsValid() )
+ {
+ SetControlInt("ConsoleCheck", con_enable.GetInt() ? 1 : 0);
+ }
+
+ ConVarRef hud_fastswitch( "hud_fastswitch" );
+ if ( hud_fastswitch.IsValid() )
+ {
+ SetControlInt("FastSwitchCheck", hud_fastswitch.GetInt() ? 1 : 0);
+ }
+ }
+
+ virtual void OnApplyData()
+ {
+ // apply data
+ ConVarRef con_enable( "con_enable" );
+ con_enable.SetValue( GetControlInt( "ConsoleCheck", 0 ) );
+
+ ConVarRef hud_fastswitch( "hud_fastswitch" );
+ hud_fastswitch.SetValue( GetControlInt( "FastSwitchCheck", 0 ) );
+ }
+
+ virtual void OnCommand( const char *command )
+ {
+ if ( !stricmp(command, "OK") )
+ {
+ // apply the data
+ OnApplyData();
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Open advanced keyboard options
+//-----------------------------------------------------------------------------
+void COptionsSubKeyboard::OpenKeyboardAdvancedDialog()
+{
+ if (!m_OptionsSubKeyboardAdvancedDlg.Get())
+ {
+ m_OptionsSubKeyboardAdvancedDlg = new COptionsSubKeyboardAdvancedDlg(GetVParent());
+ }
+ m_OptionsSubKeyboardAdvancedDlg->Activate();
+}
diff --git a/gameui/OptionsSubKeyboard.h b/gameui/OptionsSubKeyboard.h
new file mode 100644
index 0000000..92b2818
--- /dev/null
+++ b/gameui/OptionsSubKeyboard.h
@@ -0,0 +1,101 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef OPTIONS_SUB_KEYBOARD_H
+#define OPTIONS_SUB_KEYBOARD_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+#include "utlsymbol.h"
+
+#include <vgui_controls/PropertyPage.h>
+class VControlsListPanel;
+
+//-----------------------------------------------------------------------------
+// Purpose: Keyboard Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubKeyboard : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubKeyboard, vgui::PropertyPage );
+
+public:
+ COptionsSubKeyboard(vgui::Panel *parent);
+ ~COptionsSubKeyboard();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnThink();
+
+ // Trap row selection message
+ MESSAGE_FUNC_INT( ItemSelected, "ItemSelected", itemID );
+
+private:
+ void Finish( ButtonCode_t code );
+
+ //-----------------------------------------------------------------------------
+ // Purpose: Used for saving engine keybindings in case user hits cancel button
+ //-----------------------------------------------------------------------------
+ struct KeyBinding
+ {
+ char *binding;
+ };
+
+ // Create the key binding list control
+ void CreateKeyBindingList( void );
+
+ virtual void OnCommand( const char *command );
+
+ // Tell engine to bind/unbind a key
+ void BindKey( const char *key, const char *binding );
+ void UnbindKey( const char *key );
+
+ // Save/restore/cleanup engine's current bindings ( for handling cancel button )
+ void SaveCurrentBindings( void );
+ void DeleteSavedBindings( void );
+
+ // Get column 0 action descriptions for all keys
+ void ParseActionDescriptions( void );
+
+ // Populate list of actions with current engine keybindings
+ void FillInCurrentBindings( void );
+ // Remove all current bindings from list of bindings
+ void ClearBindItems( void );
+ // Fill in bindings with mod-specified defaults
+ void FillInDefaultBindings( void );
+ // Copy bindings out of list and set them in the engine
+ void ApplyAllBindings( void );
+
+ // Bind a key to the item
+ void AddBinding( KeyValues *item, const char *keyname );
+
+ // Remove all instances of a key from all bindings
+ void RemoveKeyFromBindItems( KeyValues *org_item, const char *key );
+
+ // Find item by binding name
+ KeyValues *GetItemForBinding( const char *binding );
+
+private:
+ void OpenKeyboardAdvancedDialog();
+ vgui::DHANDLE<class COptionsSubKeyboardAdvancedDlg> m_OptionsSubKeyboardAdvancedDlg;
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+
+ VControlsListPanel *m_pKeyBindList;
+
+ vgui::Button *m_pSetBindingButton;
+ vgui::Button *m_pClearBindingButton;
+
+ // List of saved bindings for the keys
+ KeyBinding m_Bindings[ BUTTON_CODE_LAST ];
+
+ // List of all the keys that need to have their binding removed
+ CUtlVector<CUtlSymbol> m_KeysToUnbind;
+};
+
+#endif // OPTIONS_SUB_KEYBOARD_H \ No newline at end of file
diff --git a/gameui/OptionsSubMouse.cpp b/gameui/OptionsSubMouse.cpp
new file mode 100644
index 0000000..806b6fd
--- /dev/null
+++ b/gameui/OptionsSubMouse.cpp
@@ -0,0 +1,261 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "OptionsSubMouse.h"
+//#include "CommandCheckButton.h"
+#include "KeyToggleCheckButton.h"
+#include "CvarNegateCheckButton.h"
+#include "CvarToggleCheckButton.h"
+#include "cvarslider.h"
+
+#include "EngineInterface.h"
+
+#include <KeyValues.h>
+#include <vgui/IScheme.h>
+#include "tier1/convar.h"
+#include <stdio.h>
+#include <vgui_controls/TextEntry.h>
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+COptionsSubMouse::COptionsSubMouse(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+ m_pReverseMouseCheckBox = new CCvarNegateCheckButton(
+ this,
+ "ReverseMouse",
+ "#GameUI_ReverseMouse",
+ "m_pitch" );
+
+ m_pMouseFilterCheckBox = new CCvarToggleCheckButton(
+ this,
+ "MouseFilter",
+ "#GameUI_MouseFilter",
+ "m_filter" );
+
+ m_pMouseRawCheckBox = new CCvarToggleCheckButton(
+ this,
+ "MouseRaw",
+ "#GameUI_MouseRaw",
+ "m_rawinput" );
+
+ m_pMouseAccelerationCheckBox = new CheckButton(
+ this,
+ "MouseAccelerationCheckbox",
+ "#GameUI_MouseCustomAccel" );
+
+
+ m_pJoystickCheckBox = new CCvarToggleCheckButton(
+ this,
+ "Joystick",
+ "#GameUI_Joystick",
+ "joystick" );
+
+ m_pJoystickSouthpawCheckBox = new CCvarToggleCheckButton(
+ this,
+ "JoystickSouthpaw",
+ "#GameUI_JoystickSouthpaw",
+ "joy_movement_stick" );
+
+ m_pReverseJoystickCheckBox = new CCvarToggleCheckButton(
+ this,
+ "ReverseJoystick",
+ "#GameUI_ReverseJoystick",
+ "joy_inverty" );
+
+ m_pQuickInfoCheckBox = new CCvarToggleCheckButton(
+ this,
+ "HudQuickInfo",
+ "#GameUI_HudQuickInfo",
+ "hud_quickinfo" );
+
+ m_pMouseSensitivitySlider = new CCvarSlider( this, "Slider", "#GameUI_MouseSensitivity",
+ 0.1f, 6.0f, "sensitivity", true );
+
+ m_pMouseSensitivityLabel = new TextEntry(this, "SensitivityLabel");
+ m_pMouseSensitivityLabel->AddActionSignalTarget(this);
+
+ m_pMouseAccelExponentSlider = new CCvarSlider( this, "MouseAccelerationSlider", "#GameUI_MouseAcceleration",
+ 1.0f, 1.4f, "m_customaccel_exponent", true );
+
+ m_pMouseAccelExponentLabel = new TextEntry(this, "MouseAccelerationLabel");
+ m_pMouseAccelExponentLabel->AddActionSignalTarget(this);
+
+ m_pJoyYawSensitivitySlider = new CCvarSlider( this, "JoystickYawSlider", "#GameUI_JoystickYawSensitivity",
+ -0.5f, -7.0f, "joy_yawsensitivity", true );
+ m_pJoyYawSensitivityPreLabel = new Label(this, "JoystickYawSensitivityPreLabel", "#GameUI_JoystickLookSpeedYaw" );
+
+ m_pJoyPitchSensitivitySlider = new CCvarSlider( this, "JoystickPitchSlider", "#GameUI_JoystickPitchSensitivity",
+ 0.5f, 7.0f, "joy_pitchsensitivity", true );
+ m_pJoyPitchSensitivityPreLabel = new Label(this, "JoystickPitchSensitivityPreLabel", "#GameUI_JoystickLookSpeedPitch" );
+
+ LoadControlSettings("Resource\\OptionsSubMouse.res");
+
+ UpdateSensitivityLabel();
+ UpdateAccelerationLabel();
+
+ UpdateJoystickPanels();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubMouse::~COptionsSubMouse()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::OnResetData()
+{
+ m_pReverseMouseCheckBox->Reset();
+ m_pMouseFilterCheckBox->Reset();
+ m_pMouseRawCheckBox->Reset();
+ m_pJoystickCheckBox->Reset();
+ m_pJoystickSouthpawCheckBox->Reset();
+ m_pMouseSensitivitySlider->Reset();
+ m_pMouseAccelExponentSlider->Reset();
+ m_pQuickInfoCheckBox->Reset();
+ m_pReverseJoystickCheckBox->Reset();
+ m_pJoyYawSensitivitySlider->Reset();
+ m_pJoyPitchSensitivitySlider->Reset();
+
+ ConVarRef m_customacel("m_customaccel");
+ if ( m_customacel.IsValid() )
+ m_pMouseAccelerationCheckBox->SetSelected( m_customacel.GetBool() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::OnApplyChanges()
+{
+ m_pReverseMouseCheckBox->ApplyChanges();
+ m_pMouseFilterCheckBox->ApplyChanges();
+ m_pMouseRawCheckBox->ApplyChanges();
+ m_pJoystickCheckBox->ApplyChanges();
+ m_pJoystickSouthpawCheckBox->ApplyChanges();
+ m_pMouseSensitivitySlider->ApplyChanges();
+ m_pMouseAccelExponentSlider->ApplyChanges();
+ m_pQuickInfoCheckBox->ApplyChanges();
+ m_pReverseJoystickCheckBox->ApplyChanges();
+ m_pJoyYawSensitivitySlider->ApplyChanges();
+ m_pJoyPitchSensitivitySlider->ApplyChanges();
+
+ engine->ClientCmd_Unrestricted( "joyadvancedupdate" );
+
+ ConVarRef m_customacel("m_customaccel");
+ if ( m_customacel.IsValid() )
+ m_customacel.SetValue(m_pMouseAccelerationCheckBox->IsSelected() ? 3 : 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets background color & border
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::OnControlModified(Panel *panel)
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+
+ // the HasBeenModified() check is so that if the value is outside of the range of the
+ // slider, it won't use the slider to determine the display value but leave the
+ // real value that we determined in the constructor
+ if (panel == m_pMouseSensitivitySlider && m_pMouseSensitivitySlider->HasBeenModified())
+ {
+ UpdateSensitivityLabel();
+ }
+ else if (panel == m_pMouseAccelExponentSlider && m_pMouseAccelExponentSlider->HasBeenModified())
+ {
+ UpdateAccelerationLabel();
+ }
+ else if (panel == m_pJoystickCheckBox)
+ {
+ UpdateJoystickPanels();
+ }
+ else if (panel == m_pMouseAccelerationCheckBox)
+ {
+ m_pMouseAccelExponentSlider->SetEnabled(m_pMouseAccelerationCheckBox->IsSelected());
+ m_pMouseAccelExponentLabel->SetEnabled(m_pMouseAccelerationCheckBox->IsSelected());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::OnTextChanged(Panel *panel)
+{
+ if ( panel == m_pMouseSensitivityLabel )
+ {
+ char buf[64];
+ m_pMouseSensitivityLabel->GetText(buf, 64);
+
+ float fValue;
+ int numParsed = sscanf(buf, "%f", &fValue);
+ if ( ( numParsed == 1 ) && ( fValue >= 0.0f ) )
+ {
+ m_pMouseSensitivitySlider->SetSliderValue(fValue);
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+ }
+ return;
+ }
+
+ if ( panel == m_pMouseAccelExponentLabel )
+ {
+ char buf[64];
+ m_pMouseAccelExponentLabel->GetText(buf, 64);
+
+ float fValue = (float) atof(buf);
+ if (fValue >= 1.0)
+ {
+ m_pMouseAccelExponentSlider->SetSliderValue(fValue);
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::UpdateSensitivityLabel()
+{
+ char buf[64];
+ Q_snprintf(buf, sizeof( buf ), " %.2f", m_pMouseSensitivitySlider->GetSliderValue());
+ m_pMouseSensitivityLabel->SetText(buf);
+}
+
+
+void COptionsSubMouse::UpdateAccelerationLabel()
+{
+ char buf[64];
+ Q_snprintf(buf, sizeof( buf ), " %.2f", m_pMouseAccelExponentSlider->GetSliderValue());
+ m_pMouseAccelExponentLabel->SetText(buf);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMouse::UpdateJoystickPanels()
+{
+ bool bEnabled = m_pJoystickCheckBox->IsSelected();
+
+ m_pReverseJoystickCheckBox->SetEnabled( bEnabled );
+ m_pJoystickSouthpawCheckBox->SetEnabled( bEnabled );
+ m_pJoyYawSensitivitySlider->SetEnabled( bEnabled );
+ m_pJoyYawSensitivityPreLabel->SetEnabled( bEnabled );
+ m_pJoyPitchSensitivitySlider->SetEnabled( bEnabled );
+ m_pJoyPitchSensitivityPreLabel->SetEnabled( bEnabled );
+} \ No newline at end of file
diff --git a/gameui/OptionsSubMouse.h b/gameui/OptionsSubMouse.h
new file mode 100644
index 0000000..9ed4c80
--- /dev/null
+++ b/gameui/OptionsSubMouse.h
@@ -0,0 +1,80 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_MOUSE_H
+#define OPTIONS_SUB_MOUSE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+class CCvarNegateCheckButton;
+class CKeyToggleCheckButton;
+class CCvarToggleCheckButton;
+class CCvarSlider;
+
+namespace vgui
+{
+ class Label;
+ class Panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Mouse Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubMouse : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubMouse, vgui::PropertyPage );
+
+public:
+ COptionsSubMouse(vgui::Panel *parent);
+ ~COptionsSubMouse();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+
+protected:
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ MESSAGE_FUNC_PTR( OnControlModified, "ControlModified", panel );
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel )
+ {
+ OnControlModified( panel );
+ }
+
+ void UpdateSensitivityLabel();
+ void UpdateAccelerationLabel();
+ void UpdateJoystickPanels();
+
+private:
+ CCvarNegateCheckButton *m_pReverseMouseCheckBox;
+ CCvarToggleCheckButton *m_pMouseFilterCheckBox;
+ CCvarToggleCheckButton *m_pMouseRawCheckBox;
+ vgui::CheckButton *m_pMouseAccelerationCheckBox;
+
+ CCvarToggleCheckButton *m_pJoystickCheckBox;
+ CCvarToggleCheckButton *m_pJoystickSouthpawCheckBox;
+ CCvarToggleCheckButton *m_pQuickInfoCheckBox;
+ CCvarToggleCheckButton *m_pReverseJoystickCheckBox;
+
+ CCvarSlider *m_pMouseSensitivitySlider;
+ vgui::TextEntry *m_pMouseSensitivityLabel;
+
+ CCvarSlider *m_pMouseAccelExponentSlider;
+ vgui::TextEntry *m_pMouseAccelExponentLabel;
+
+ CCvarSlider *m_pJoyYawSensitivitySlider;
+ vgui::Label *m_pJoyYawSensitivityPreLabel;
+ CCvarSlider *m_pJoyPitchSensitivitySlider;
+ vgui::Label *m_pJoyPitchSensitivityPreLabel;
+};
+
+
+
+#endif // OPTIONS_SUB_MOUSE_H \ No newline at end of file
diff --git a/gameui/OptionsSubMultiplayer.cpp b/gameui/OptionsSubMultiplayer.cpp
new file mode 100644
index 0000000..3a262d0
--- /dev/null
+++ b/gameui/OptionsSubMultiplayer.cpp
@@ -0,0 +1,1890 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+
+#if defined( WIN32 ) && !defined( _X360 )
+#include <windows.h> // SRC only!!
+#endif
+
+#include "OptionsSubMultiplayer.h"
+#include "MultiplayerAdvancedDialog.h"
+#include <stdio.h>
+
+#include <vgui_controls/Button.h>
+#include <vgui_controls/QueryBox.h>
+#include <vgui_controls/CheckButton.h>
+#include "tier1/KeyValues.h"
+#include <vgui_controls/Label.h>
+#include <vgui/ISystem.h>
+#include <vgui/ISurface.h>
+#include <vgui/Cursor.h>
+#include <vgui_controls/RadioButton.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui_controls/FileOpenDialog.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <vgui/IPanel.h>
+#include <vgui_controls/MessageBox.h>
+
+#include "CvarTextEntry.h"
+#include "CvarToggleCheckButton.h"
+#include "cvarslider.h"
+#include "LabeledCommandComboBox.h"
+#include "filesystem.h"
+#include "EngineInterface.h"
+#include "BitmapImagePanel.h"
+#include "tier1/utlbuffer.h"
+#include "ModInfo.h"
+#include "tier1/convar.h"
+#include "tier0/icommandline.h"
+
+#include "materialsystem/imaterial.h"
+#include "materialsystem/imesh.h"
+#include "materialsystem/imaterialvar.h"
+
+// use the JPEGLIB_USE_STDIO define so that we can read in jpeg's from outside the game directory tree. For Spray Import.
+#define JPEGLIB_USE_STDIO
+#include "jpeglib/jpeglib.h"
+#undef JPEGLIB_USE_STDIO
+
+#include <setjmp.h>
+
+#include "bitmap/tgawriter.h"
+#include "ivtex.h"
+#ifdef WIN32
+#include <io.h>
+#endif
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+
+#define DEFAULT_SUIT_HUE 30
+#define DEFAULT_PLATE_HUE 6
+
+void UpdateLogoWAD( void *hdib, int r, int g, int b );
+
+struct ColorItem_t
+{
+ const char *name;
+ int r, g, b;
+};
+
+static ColorItem_t itemlist[]=
+{
+ { "#Valve_Orange", 255, 120, 24 },
+ { "#Valve_Yellow", 225, 180, 24 },
+ { "#Valve_Blue", 0, 60, 255 },
+ { "#Valve_Ltblue", 0, 167, 255 },
+ { "#Valve_Green", 0, 167, 0 },
+ { "#Valve_Red", 255, 43, 0 },
+ { "#Valve_Brown", 123, 73, 0 },
+ { "#Valve_Ltgray", 100, 100, 100 },
+ { "#Valve_Dkgray", 36, 36, 36 },
+};
+
+static ColorItem_t s_crosshairColors[] =
+{
+ { "#Valve_Green", 50, 250, 50 },
+ { "#Valve_Red", 250, 50, 50 },
+ { "#Valve_Blue", 50, 50, 250 },
+ { "#Valve_Yellow", 250, 250, 50 },
+ { "#Valve_Ltblue", 50, 250, 250 },
+};
+static const int NumCrosshairColors = ARRAYSIZE(s_crosshairColors);
+
+
+//-----------------------------------------------------------------------------
+class CrosshairImagePanelSimple : public CrosshairImagePanelBase
+{
+ DECLARE_CLASS_SIMPLE( CrosshairImagePanelSimple, CrosshairImagePanelBase );
+public:
+ CrosshairImagePanelSimple( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
+ virtual void Paint();
+ virtual void ResetData();
+ virtual void ApplyChanges();
+ static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );
+
+protected:
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+
+ void InitCrosshairColorEntries();
+ void InitCrosshairSizeList();
+ void UpdateCrosshair();
+
+private:
+ COptionsSubMultiplayer* m_pOptionsPanel;
+ vgui::ComboBox *m_pCrosshairColorCombo;
+ CLabeledCommandComboBox *m_pCrosshairSizeCombo;
+ CCvarToggleCheckButton *m_pCrosshairTranslucencyCheckbox;
+ int m_R, m_G, m_B;
+ int m_barSize;
+ int m_barGap;
+ int m_iCrosshairTextureID;
+};
+
+//-----------------------------------------------------------------------------
+CrosshairImagePanelSimple::CrosshairImagePanelSimple( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
+{
+ m_pOptionsPanel = pOptionsPanel;
+ m_pCrosshairTranslucencyCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairTranslucencyCheckbox", "#GameUI_Translucent", "cl_crosshairusealpha");
+ m_pCrosshairColorCombo = new ComboBox(m_pOptionsPanel, "CrosshairColorComboBox", 6, false);
+ m_pCrosshairSizeCombo = new CLabeledCommandComboBox(m_pOptionsPanel, "CrosshairSizeComboBox");
+
+ m_pCrosshairColorCombo->AddActionSignalTarget( this );
+ m_pCrosshairSizeCombo->AddActionSignalTarget( this );
+
+ m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, "vgui/white_additive" , true, false);
+
+ InitCrosshairSizeList();
+ InitCrosshairColorEntries();
+ ResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initialize the crosshair size list.
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::InitCrosshairSizeList()
+{
+ // add in the auto, small, medium, and large size selections.
+ m_pCrosshairSizeCombo->AddItem("#GameUI_Auto", "cl_crosshairscale 0");
+ m_pCrosshairSizeCombo->AddItem("#GameUI_Small", "cl_crosshairscale 1200");
+ m_pCrosshairSizeCombo->AddItem("#GameUI_Medium", "cl_crosshairscale 768");
+ m_pCrosshairSizeCombo->AddItem("#GameUI_Large", "cl_crosshairscale 600");
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::InitCrosshairColorEntries()
+{
+ if (m_pCrosshairColorCombo != NULL)
+ {
+ KeyValues *data = new KeyValues("data");
+
+ // add in the "Default" selection
+ data->Clear();
+
+ // add in the colors for the color list
+ for ( int i = 0; i < NumCrosshairColors; i++ )
+ {
+ data->SetInt("color", i);
+ m_pCrosshairColorCombo->AddItem( s_crosshairColors[ i ].name, data);
+ }
+
+ data->deleteThis();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::DrawCrosshairRect( int x0, int y0, int x1, int y1, bool bAdditive )
+{
+ if ( bAdditive )
+ vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
+ else
+ vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
+}
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::Paint()
+{
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );;
+
+ BaseClass::Paint();
+
+ if ( !m_pCrosshairTranslucencyCheckbox )
+ return;
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ bool bAdditive = !m_pCrosshairTranslucencyCheckbox->IsSelected();
+
+ int a = 200;
+ ConVarRef cl_crosshairalpha( "cl_crosshairalpha", true );
+ if ( !bAdditive && cl_crosshairalpha.IsValid() )
+ {
+ a = clamp( cl_crosshairalpha.GetInt(), 0, 255 );
+ }
+ vgui::surface()->DrawSetColor( m_R, m_G, m_B, a );
+
+ if ( bAdditive )
+ {
+ vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
+ }
+
+ int centerX = wide / 2;
+ int centerY = tall / 2;
+ int iCrosshairDistance = m_barGap;
+
+ int iBarThickness = 1;
+ int iBarSize = m_barSize;
+
+ // draw horizontal crosshair lines
+ int iInnerLeft = centerX - iCrosshairDistance - iBarThickness / 2;
+ int iInnerRight = iInnerLeft + 2 * iCrosshairDistance + iBarThickness;
+ int iOuterLeft = iInnerLeft - iBarSize;
+ int iOuterRight = iInnerRight + iBarSize;
+ int y0 = centerY - iBarThickness / 2;
+ int y1 = y0 + iBarThickness;
+ DrawCrosshairRect( iOuterLeft, y0, iInnerLeft, y1, bAdditive );
+ DrawCrosshairRect( iInnerRight, y0, iOuterRight, y1, bAdditive );
+
+ // draw vertical crosshair lines
+ int iInnerTop = centerY - iCrosshairDistance - iBarThickness / 2;
+ int iInnerBottom = iInnerTop + 2 * iCrosshairDistance + iBarThickness;
+ int iOuterTop = iInnerTop - iBarSize;
+ int iOuterBottom = iInnerBottom + iBarSize;
+ int x0 = centerX - iBarThickness / 2;
+ int x1 = x0 + iBarThickness;
+ DrawCrosshairRect( x0, iOuterTop, x1, iInnerTop, bAdditive );
+ DrawCrosshairRect( x0, iInnerBottom, x1, iOuterBottom, bAdditive );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: takes the settings from the crosshair settings combo boxes and sliders
+// and apply it to the crosshair illustrations.
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::UpdateCrosshair()
+{
+ // get the color selected in the combo box.
+ KeyValues *data = m_pCrosshairColorCombo->GetActiveItemUserData();
+ int colorIndex = data->GetInt("color");
+ colorIndex = clamp( colorIndex, 0, NumCrosshairColors );
+
+ int selectedColor = 0;
+ int actualVal = 0;
+ if (m_pCrosshairColorCombo != NULL)
+ {
+ selectedColor = m_pCrosshairColorCombo->GetActiveItem();
+ }
+
+ ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
+ if ( cl_crosshaircolor.IsValid() )
+ {
+ actualVal = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
+ }
+
+ m_R = s_crosshairColors[selectedColor].r;
+ m_G = s_crosshairColors[selectedColor].g;
+ m_B = s_crosshairColors[selectedColor].b;
+
+ if ( m_pCrosshairSizeCombo )
+ {
+ int size = m_pCrosshairSizeCombo->GetActiveItem();
+
+ if ( size == 0 )
+ {
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );
+ if ( screenTall <= 600 )
+ {
+ // if the screen height is 600 or less, set the crosshair num to 3 (large)
+ size = 3;
+ }
+ else if ( screenTall <= 768 )
+ {
+ // if the screen height is between 600 and 768, set the crosshair num to 2 (medium)
+ size = 2;
+ }
+ else
+ {
+ // if the screen height is greater than 768, set the crosshair num to 1 (small)
+ size = 1;
+ }
+ }
+
+ int scaleBase;
+ switch( size )
+ {
+ case 1:
+ scaleBase = 1200;
+ break;
+ case 2:
+ scaleBase = 768;
+ break;
+ case 3:
+ scaleBase = 600;
+ break;
+ default:
+ scaleBase = 1200;
+ break;
+ }
+
+ m_barSize = (int) 9 * 1200 / scaleBase;
+ m_barGap = (int) 5 * 1200 / scaleBase;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever color combo changes
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelSimple::OnTextChanged(vgui::Panel *panel)
+{
+ m_pOptionsPanel->OnControlModified();
+ UpdateCrosshair();
+}
+
+
+void CrosshairImagePanelSimple::ResetData()
+{
+ m_pCrosshairTranslucencyCheckbox->Reset();
+
+ // parse out the size value from the cvar and set the initial value.
+ int initialScale = 0;
+ ConVarRef cl_crosshairscale( "cl_crosshairscale", true );
+ if ( cl_crosshairscale.IsValid() )
+ {
+ initialScale = cl_crosshairscale.GetInt();
+ if ( initialScale <= 0 )
+ {
+ initialScale = 0;
+ }
+ else if ( initialScale <= 600 )
+ {
+ initialScale = 3;
+ }
+ else if ( initialScale <= 768 )
+ {
+ initialScale = 2;
+ }
+ else
+ {
+ initialScale = 1;
+ }
+ }
+ m_pCrosshairSizeCombo->SetInitialItem( initialScale );
+
+ // parse the string for the custom color settings and get the initial settings.
+ ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
+ int index = 0;
+ if ( cl_crosshaircolor.IsValid() )
+ {
+ index = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors );
+ }
+ m_pCrosshairColorCombo->ActivateItemByRow(index);
+
+ UpdateCrosshair();
+}
+
+void CrosshairImagePanelSimple::ApplyChanges()
+{
+ m_pCrosshairTranslucencyCheckbox->ApplyChanges();
+
+ char cmd[256];
+ cmd[0] = 0;
+
+ if (m_pCrosshairColorCombo != NULL)
+ {
+ int val = m_pCrosshairColorCombo->GetActiveItem();
+ Q_snprintf( cmd, sizeof(cmd), "cl_crosshaircolor %d\n", val );
+ engine->ClientCmd_Unrestricted( cmd );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+class CrosshairImagePanelCS : public CrosshairImagePanelBase
+{
+ DECLARE_CLASS_SIMPLE( CrosshairImagePanelCS, CrosshairImagePanelBase );
+
+public:
+ CrosshairImagePanelCS( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
+ virtual void ResetData();
+ virtual void ApplyChanges();
+
+protected:
+ MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", data );
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ MESSAGE_FUNC( OnCheckButtonChecked, "CheckButtonChecked" );
+
+ virtual void Paint();
+ static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );
+ void InitCrosshairColorEntries();
+ void UpdateCrosshair();
+
+private:
+ COptionsSubMultiplayer* m_pOptionsPanel;
+ vgui::ComboBox *m_pColorComboBox;
+ CCvarToggleCheckButton *m_pAlphaCheckbox;
+ CCvarToggleCheckButton *m_pDynamicCheckbox;
+ CCvarToggleCheckButton *m_pDotCheckbox;
+ CCvarSlider *m_pColorAlphaSlider;
+ CCvarSlider *m_pColorRSlider;
+ CCvarSlider *m_pColorGSlider;
+ CCvarSlider *m_pColorBSlider;
+ CCvarSlider *m_pSizeSlider;
+ CCvarSlider *m_pThicknessSlider;
+ int m_R, m_G, m_B;
+ float m_barSize;
+ float m_barThickness;
+ int m_iCrosshairTextureID;
+};
+
+//-----------------------------------------------------------------------------
+CrosshairImagePanelCS::CrosshairImagePanelCS( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
+{
+ m_pOptionsPanel = pOptionsPanel;
+ m_pColorComboBox = new ComboBox(m_pOptionsPanel, "CrosshairColorComboBox", 6, false);
+ m_pAlphaCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairTranslucencyCheckbox", "#GameUI_Crosshair_Blend", "cl_crosshairusealpha");
+ m_pDynamicCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairDynamicCheckbox", "#GameUI_CrosshairDynamic", "cl_dynamiccrosshair");
+ m_pDotCheckbox = new CCvarToggleCheckButton(m_pOptionsPanel, "CrosshairDotCheckbox", "#GameUI_CrosshairDot", "cl_crosshairdot");
+ m_pColorAlphaSlider = new CCvarSlider( m_pOptionsPanel, "Alpha Slider", "#GameUI_CrosshairColor_Alpha",
+ 0.0f, 255.0f, "cl_crosshairalpha" );
+ m_pColorRSlider = new CCvarSlider( m_pOptionsPanel, "Red Color Slider", "#GameUI_CrosshairColor_Red",
+ 0.0f, 255.0f, "cl_crosshaircolor_r" );
+ m_pColorGSlider = new CCvarSlider( m_pOptionsPanel, "Green Color Slider", "#GameUI_CrosshairColor_Green",
+ 0.0f, 255.0f, "cl_crosshaircolor_g" );
+ m_pColorBSlider = new CCvarSlider( m_pOptionsPanel, "Blue Color Slider", "#GameUI_CrosshairColor_Blue",
+ 0.0f, 255.0f, "cl_crosshaircolor_b" );
+ m_pSizeSlider = new CCvarSlider( m_pOptionsPanel, "Size Slider", "#GameUI_Crosshair_Size",
+ 0.0f, 12.0f, "cl_crosshairsize" );
+ m_pThicknessSlider = new CCvarSlider( m_pOptionsPanel, "Thickness Slider", "#GameUI_Crosshair_Thickness",
+ 0.0f, 3.0f, "cl_crosshairthickness" );
+
+ m_pColorAlphaSlider->SetTickCaptions("", "");
+ m_pColorRSlider->SetTickCaptions("", "");
+ m_pColorGSlider->SetTickCaptions("", "");
+ m_pColorBSlider->SetTickCaptions("", "");
+ m_pSizeSlider->SetTickCaptions("", "");
+ m_pThicknessSlider->SetTickCaptions("", "");
+
+ m_pAlphaCheckbox->AddActionSignalTarget(this);
+ m_pDynamicCheckbox->AddActionSignalTarget(this);
+ m_pDotCheckbox->AddActionSignalTarget(this);
+ m_pColorComboBox->AddActionSignalTarget( this );
+ m_pColorAlphaSlider->AddActionSignalTarget( this );
+ m_pColorRSlider->AddActionSignalTarget( this );
+ m_pColorGSlider->AddActionSignalTarget( this );
+ m_pColorBSlider->AddActionSignalTarget( this );
+ m_pSizeSlider->AddActionSignalTarget( this );
+ m_pThicknessSlider->AddActionSignalTarget( this );
+
+ InitCrosshairColorEntries();
+
+ m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, "vgui/white_additive" , true, false);
+
+ ResetData();
+}
+
+void CrosshairImagePanelCS::InitCrosshairColorEntries()
+{
+ if (m_pColorComboBox != NULL)
+ {
+ KeyValues *data = new KeyValues("data");
+
+ // add in the "Default" selection
+ data->Clear();
+
+ // add in the colors for the color list
+ for ( int i = 0; i < NumCrosshairColors; i++ )
+ {
+ data->SetInt("color", i);
+ m_pColorComboBox->AddItem( s_crosshairColors[ i ].name, data);
+ }
+
+ data->SetInt("color", NumCrosshairColors);
+ m_pColorComboBox->AddItem( "Custom", data);
+
+ data->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelCS::DrawCrosshairRect( int x0, int y0, int x1, int y1, bool bAdditive )
+{
+ if ( bAdditive )
+ vgui::surface()->DrawTexturedRect( x0, y0, x1, y1 );
+ else
+ vgui::surface()->DrawFilledRect( x0, y0, x1, y1 );
+}
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelCS::Paint()
+{
+ int screenWide, screenTall;
+ surface()->GetScreenSize( screenWide, screenTall );;
+
+ BaseClass::Paint();
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ bool bAdditive = !m_pAlphaCheckbox->IsSelected();
+ bool bDynamic = m_pDynamicCheckbox->IsSelected();
+
+ int a = 255;
+ if ( !bAdditive )
+ a = m_pColorAlphaSlider->GetSliderValue();
+
+ vgui::surface()->DrawSetColor( m_R, m_G, m_B, a );
+
+ if ( bAdditive )
+ {
+ vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
+ }
+
+ int centerX = wide / 2;
+ int centerY = tall / 2;
+
+ int iBarSize = RoundFloatToInt(m_barSize * screenTall / 480.0f);
+ int iBarThickness = max(1, RoundFloatToInt(m_barThickness * (float)screenTall / 480.0f));
+
+ float fBarGap = 4.0f;
+ if ( bDynamic )
+ {
+ float curtime = system()->GetFrameTime();
+ fBarGap *= (1.0f + cosf(curtime * 1.5f) * 0.5f);
+ }
+
+ int iBarGap = RoundFloatToInt(fBarGap * screenTall / 480.0f);
+
+ // draw horizontal crosshair lines
+ int iInnerLeft = centerX - iBarGap - iBarThickness / 2;
+ int iInnerRight = iInnerLeft + 2 * iBarGap + iBarThickness;
+ int iOuterLeft = iInnerLeft - iBarSize;
+ int iOuterRight = iInnerRight + iBarSize;
+ int y0 = centerY - iBarThickness / 2;
+ int y1 = y0 + iBarThickness;
+ DrawCrosshairRect( iOuterLeft, y0, iInnerLeft, y1, bAdditive );
+ DrawCrosshairRect( iInnerRight, y0, iOuterRight, y1, bAdditive );
+
+ // draw vertical crosshair lines
+ int iInnerTop = centerY - iBarGap - iBarThickness / 2;
+ int iInnerBottom = iInnerTop + 2 * iBarGap + iBarThickness;
+ int iOuterTop = iInnerTop - iBarSize;
+ int iOuterBottom = iInnerBottom + iBarSize;
+ int x0 = centerX - iBarThickness / 2;
+ int x1 = x0 + iBarThickness;
+ DrawCrosshairRect( x0, iOuterTop, x1, iInnerTop, bAdditive );
+ DrawCrosshairRect( x0, iInnerBottom, x1, iOuterBottom, bAdditive );
+
+ // draw dot
+ if ( m_pDotCheckbox->IsSelected() )
+ {
+ x0 = centerX - iBarThickness / 2;
+ x1 = x0 + iBarThickness;
+ y0 = centerY - iBarThickness / 2;
+ y1 = y0 + iBarThickness;
+ DrawCrosshairRect( x0, y0, x1, y1, bAdditive );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: takes the settings from the crosshair settings combo boxes and sliders
+// and apply it to the crosshair illustrations.
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelCS::UpdateCrosshair()
+{
+ // get the color selected in the combo box.
+ KeyValues *data = m_pColorComboBox->GetActiveItemUserData();
+ int colorIndex = data->GetInt("color");
+ colorIndex = clamp( colorIndex, 0, NumCrosshairColors + 1 );
+
+ int actualVal = 0;
+ int selectedColor = m_pColorComboBox->GetActiveItem();
+
+ ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
+ if ( cl_crosshaircolor.IsValid() )
+ {
+ actualVal = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors + 1 );
+ }
+
+ if ( selectedColor != NumCrosshairColors ) // not custom
+ {
+ m_R = s_crosshairColors[selectedColor].r;
+ m_G = s_crosshairColors[selectedColor].g;
+ m_B = s_crosshairColors[selectedColor].b;
+ m_pColorRSlider->SetSliderValue(m_R);
+ m_pColorGSlider->SetSliderValue(m_G);
+ m_pColorBSlider->SetSliderValue(m_B);
+ }
+ else
+ {
+ m_R = clamp( m_pColorRSlider->GetSliderValue(), 0, 255 );
+ m_G = clamp( m_pColorGSlider->GetSliderValue(), 0, 255 );
+ m_B = clamp( m_pColorBSlider->GetSliderValue(), 0, 255 );
+ }
+
+ m_barSize = m_pSizeSlider->GetSliderValue();
+ m_barThickness = m_pThicknessSlider->GetSliderValue();
+}
+
+
+void CrosshairImagePanelCS::OnSliderMoved(KeyValues *data)
+{
+ vgui::Panel* pPanel = static_cast<vgui::Panel*>(data->GetPtr("panel"));
+
+ if ( pPanel == m_pColorRSlider || pPanel == m_pColorGSlider || pPanel == m_pColorBSlider )
+ {
+ m_pColorComboBox->ActivateItem(NumCrosshairColors);
+ }
+ m_pOptionsPanel->OnControlModified();
+
+ UpdateCrosshair();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever color combo changes
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelCS::OnTextChanged(vgui::Panel *panel)
+{
+ m_pOptionsPanel->OnControlModified();
+ UpdateCrosshair();
+}
+
+void CrosshairImagePanelCS::OnCheckButtonChecked()
+{
+ m_pColorAlphaSlider->SetEnabled(m_pAlphaCheckbox->IsSelected());
+ m_pOptionsPanel->OnControlModified();
+ UpdateCrosshair();
+}
+
+void CrosshairImagePanelCS::ResetData()
+{
+ // parse the string for the custom color settings and get the initial settings.
+ ConVarRef cl_crosshaircolor( "cl_crosshaircolor", true );
+ int index = 0;
+ if ( cl_crosshaircolor.IsValid() )
+ {
+ index = clamp( cl_crosshaircolor.GetInt(), 0, NumCrosshairColors + 1);
+ }
+ m_pColorComboBox->ActivateItemByRow(index);
+
+ m_pAlphaCheckbox->Reset();
+ m_pDynamicCheckbox->Reset();
+ m_pDotCheckbox->Reset();
+ m_pColorRSlider->Reset();
+ m_pColorGSlider->Reset();
+ m_pColorBSlider->Reset();
+ m_pColorAlphaSlider->Reset();
+ m_pSizeSlider->Reset();
+ m_pThicknessSlider->Reset();
+
+ UpdateCrosshair();
+}
+
+void CrosshairImagePanelCS::ApplyChanges()
+{
+ m_pAlphaCheckbox->ApplyChanges();
+ m_pDynamicCheckbox->ApplyChanges();
+ m_pDotCheckbox->ApplyChanges();
+ m_pColorRSlider->ApplyChanges();
+ m_pColorGSlider->ApplyChanges();
+ m_pColorBSlider->ApplyChanges();
+ m_pColorAlphaSlider->ApplyChanges();
+ m_pSizeSlider->ApplyChanges();
+ m_pThicknessSlider->ApplyChanges();
+
+ char cmd[256];
+ cmd[0] = 0;
+
+ if (m_pColorComboBox != NULL)
+ {
+ int val = m_pColorComboBox->GetActiveItem();
+ Q_snprintf( cmd, sizeof(cmd), "cl_crosshaircolor %d\n", val );
+ engine->ClientCmd_Unrestricted( cmd );
+ }
+}
+
+//-----------------------------------------------------------------------------
+class CrosshairImagePanelAdvanced : public CrosshairImagePanelBase
+{
+ DECLARE_CLASS_SIMPLE( CrosshairImagePanelAdvanced, CrosshairImagePanelBase );
+public:
+ CrosshairImagePanelAdvanced( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel );
+ virtual ~CrosshairImagePanelAdvanced();
+
+ virtual void ResetData();
+ virtual void ApplyChanges();
+ virtual void UpdateVisibility();
+
+protected:
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ MESSAGE_FUNC_PARAMS( OnSliderMoved, "SliderMoved", data );
+
+ virtual void Paint();
+ static void DrawCrosshairRect( int x, int y, int w, int h, bool bAdditive );
+ void InitAdvCrosshairStyleList();
+ void SetCrosshairTexture( const char *crosshairname );
+ void UpdateCrosshair();
+
+private:
+ COptionsSubMultiplayer* m_pOptionsPanel;
+
+ // --- advanced crosshair controls
+ CCvarSlider *m_pAdvCrosshairRedSlider;
+ CCvarSlider *m_pAdvCrosshairBlueSlider;
+ CCvarSlider *m_pAdvCrosshairGreenSlider;
+ CCvarSlider *m_pAdvCrosshairScaleSlider;
+
+ CLabeledCommandComboBox *m_pAdvCrosshairStyle;
+
+ int m_R, m_G, m_B;
+ float m_flScale;
+
+ // material
+ int m_iCrosshairTextureID;
+ IVguiMatInfo *m_pAdvCrosshairMaterial;
+
+ // animation
+ IVguiMatInfoVar *m_pFrameVar;
+ float m_flNextFrameChange;
+ int m_nNumFrames;
+ bool m_bAscending; // animating forward or in reverse?
+};
+
+//-----------------------------------------------------------------------------
+CrosshairImagePanelAdvanced::CrosshairImagePanelAdvanced( Panel *parent, const char *name, COptionsSubMultiplayer* pOptionsPanel ) : CrosshairImagePanelBase( parent, name )
+{
+ m_pOptionsPanel = pOptionsPanel;
+ m_pAdvCrosshairMaterial = NULL;
+ m_pFrameVar = NULL;
+
+ m_pAdvCrosshairRedSlider = new CCvarSlider( pOptionsPanel, "Red Color Slider", "#GameUI_CrosshairColor_Red",
+ 0.0f, 255.0f, "cl_crosshair_red" );
+ m_pAdvCrosshairGreenSlider = new CCvarSlider( pOptionsPanel, "Green Color Slider", "#GameUI_CrosshairColor_Green",
+ 0.0f, 255.0f, "cl_crosshair_green" );
+ m_pAdvCrosshairBlueSlider = new CCvarSlider( pOptionsPanel, "Blue Color Slider", "#GameUI_CrosshairColor_Blue",
+ 0.0f, 255.0f, "cl_crosshair_blue" );
+
+ m_pAdvCrosshairRedSlider->SetTickCaptions("", "");
+ m_pAdvCrosshairGreenSlider->SetTickCaptions("", "");
+ m_pAdvCrosshairBlueSlider->SetTickCaptions("", "");
+
+ m_pAdvCrosshairScaleSlider = new CCvarSlider( pOptionsPanel, "Scale Slider", "#GameUI_CrosshairScale",
+ 16.0f, 48.0f, "cl_crosshair_scale" );
+
+ m_pAdvCrosshairStyle = new CLabeledCommandComboBox( pOptionsPanel, "AdvCrosshairList" );
+
+ m_pAdvCrosshairRedSlider->AddActionSignalTarget( this );
+ m_pAdvCrosshairGreenSlider->AddActionSignalTarget( this );
+ m_pAdvCrosshairBlueSlider->AddActionSignalTarget( this );
+ m_pAdvCrosshairScaleSlider->AddActionSignalTarget( this );
+ m_pAdvCrosshairStyle->AddActionSignalTarget(this);
+
+ InitAdvCrosshairStyleList();
+
+ m_iCrosshairTextureID = vgui::surface()->CreateNewTextureID();
+ SetCrosshairTexture("vgui/crosshairs/crosshair1");
+
+ UpdateCrosshair();
+}
+
+CrosshairImagePanelAdvanced::~CrosshairImagePanelAdvanced()
+{
+ if ( m_pFrameVar )
+ {
+ delete m_pFrameVar;
+ m_pFrameVar = NULL;
+ }
+
+ if ( m_pAdvCrosshairMaterial )
+ {
+ delete m_pAdvCrosshairMaterial;
+ m_pAdvCrosshairMaterial = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelAdvanced::SetCrosshairTexture( const char *crosshairname )
+{
+ if ( !crosshairname || !crosshairname[0] )
+ {
+ SetVisible( false );
+ return;
+ }
+
+ SetVisible( true );
+
+ vgui::surface()->DrawSetTextureFile( m_iCrosshairTextureID, crosshairname, true, false );
+
+ if ( m_pAdvCrosshairMaterial )
+ {
+ delete m_pAdvCrosshairMaterial;
+ }
+
+ m_pAdvCrosshairMaterial = vgui::surface()->DrawGetTextureMatInfoFactory( m_iCrosshairTextureID );
+
+ Assert(m_pAdvCrosshairMaterial);
+
+ m_pFrameVar = m_pAdvCrosshairMaterial->FindVarFactory( "$frame", NULL );
+ m_nNumFrames = m_pAdvCrosshairMaterial->GetNumAnimationFrames();
+
+ m_flNextFrameChange = system()->GetFrameTime() + 0.2;
+ m_bAscending = true;
+}
+
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelAdvanced::Paint()
+{
+ BaseClass::Paint();
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ int iClipX0, iClipY0, iClipX1, iClipY1;
+ ipanel()->GetClipRect(GetVPanel(), iClipX0, iClipY0, iClipX1, iClipY1 );
+
+ // scroll through all frames
+ if ( m_pFrameVar )
+ {
+ float curtime = system()->GetFrameTime();
+
+ if ( curtime >= m_flNextFrameChange )
+ {
+ m_flNextFrameChange = curtime + 0.2;
+
+ int frame = m_pFrameVar->GetIntValue();
+
+ if ( m_bAscending )
+ {
+ frame++;
+ if ( frame >= m_nNumFrames )
+ {
+ m_bAscending = !m_bAscending;
+ frame--;
+ }
+ }
+ else
+ {
+ frame--;
+ if ( frame < 0 )
+ {
+ m_bAscending = !m_bAscending;
+ frame++;
+ }
+ }
+
+ m_pFrameVar->SetIntValue(frame);
+ }
+ }
+
+ float x, y;
+
+ // assume square
+ float flDrawWidth = ( m_flScale/48.0 ) * (float)wide;
+ int flHalfWidth = (int)( flDrawWidth / 2 );
+
+ x = wide/2 - flHalfWidth;
+ y = tall/2 - flHalfWidth;
+
+ vgui::surface()->DrawSetColor( m_R, m_G, m_B, 255 );
+ vgui::surface()->DrawSetTexture( m_iCrosshairTextureID );
+ vgui::surface()->DrawTexturedRect( x, y, x+flDrawWidth, y+flDrawWidth );
+ vgui::surface()->DrawSetTexture(0);
+}
+
+void CrosshairImagePanelAdvanced::UpdateCrosshair()
+{
+ // get the color selected in the combo box.
+ m_R = clamp( m_pAdvCrosshairRedSlider->GetSliderValue(), 0, 255 );
+ m_G = clamp( m_pAdvCrosshairGreenSlider->GetSliderValue(), 0, 255 );
+ m_B = clamp( m_pAdvCrosshairBlueSlider->GetSliderValue(), 0, 255 );
+
+ m_flScale = m_pAdvCrosshairScaleSlider->GetSliderValue();
+
+ if ( m_pAdvCrosshairStyle )
+ {
+ char crosshairname[256];
+ m_pAdvCrosshairStyle->GetText( crosshairname, sizeof(crosshairname) );
+
+ if ( ModInfo().AdvCrosshairLevel() == 1 && m_pAdvCrosshairStyle->GetActiveItem() == 0 ) // this is the "none" selection
+ {
+ SetCrosshairTexture(NULL);
+ }
+ else
+ {
+ char texture[ 256 ];
+ Q_snprintf ( texture, sizeof( texture ), "vgui/crosshairs/%s", crosshairname );
+ SetCrosshairTexture( texture );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: initialize the crosshair style list
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelAdvanced::InitAdvCrosshairStyleList()
+{
+ // Find out images
+ FileFindHandle_t fh;
+ char directory[ 512 ];
+
+ ConVarRef cl_crosshair_file( "cl_crosshair_file", true );
+ if ( !cl_crosshair_file.IsValid() )
+ return;
+
+ m_pAdvCrosshairStyle->DeleteAllItems();
+
+ if ( ModInfo().AdvCrosshairLevel() == 1 )
+ {
+ m_pAdvCrosshairStyle->AddItem( "#GameUI_None", "" );
+ }
+
+ char crosshairfile[256];
+ Q_snprintf( crosshairfile, sizeof(crosshairfile), "materials/vgui/crosshairs/%s.vtf", cl_crosshair_file.GetString() );
+
+ Q_snprintf( directory, sizeof( directory ), "materials/vgui/crosshairs/*.vtf" );
+ const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
+ int i = 0, initialItem = 0;
+ while (fn)
+ {
+ char filename[ 512 ];
+ Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
+ if ( strlen( filename ) >= 4 )
+ {
+ filename[ strlen( filename ) - 4 ] = 0;
+ Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
+ if ( g_pFullFileSystem->FileExists( filename ) )
+ {
+ // strip off the extension
+ Q_strncpy( filename, fn, sizeof( filename ) );
+ filename[ strlen( filename ) - 4 ] = 0;
+ m_pAdvCrosshairStyle->AddItem( filename, "" );
+
+ // check to see if this is the one we have set
+ if ( crosshairfile[0] )
+ {
+ Q_snprintf( filename, sizeof(filename), "materials/vgui/crosshairs/%s", fn );
+ if (!stricmp(filename, crosshairfile))
+ {
+ if ( ModInfo().AdvCrosshairLevel() == 1 )
+ {
+ initialItem = i+1;
+ }
+ else
+ {
+ initialItem = i;
+ }
+ }
+ }
+
+ ++i;
+ }
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+ }
+
+ g_pFullFileSystem->FindClose( fh );
+ m_pAdvCrosshairStyle->SetInitialItem(initialItem);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever style combo changes
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelAdvanced::OnTextChanged(vgui::Panel *panel)
+{
+ m_pOptionsPanel->OnControlModified();
+ UpdateCrosshair();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever one of the color or scale sliders move
+//-----------------------------------------------------------------------------
+void CrosshairImagePanelAdvanced::OnSliderMoved(KeyValues *data)
+{
+ m_pOptionsPanel->OnControlModified();
+ UpdateCrosshair();
+}
+
+void CrosshairImagePanelAdvanced::ResetData()
+{
+ m_pAdvCrosshairRedSlider->Reset();
+ m_pAdvCrosshairGreenSlider->Reset();
+ m_pAdvCrosshairBlueSlider->Reset();
+ m_pAdvCrosshairScaleSlider->Reset();
+
+ // TODO: update style combo from cvar
+}
+
+void CrosshairImagePanelAdvanced::ApplyChanges()
+{
+ m_pAdvCrosshairRedSlider->ApplyChanges();
+ m_pAdvCrosshairGreenSlider->ApplyChanges();
+ m_pAdvCrosshairBlueSlider->ApplyChanges();
+ m_pAdvCrosshairScaleSlider->ApplyChanges();
+
+ // save the crosshair
+ char cmd[512];
+ char crosshair[256];
+ m_pAdvCrosshairStyle->GetText(crosshair, sizeof(crosshair));
+
+ if ( ModInfo().AdvCrosshairLevel() == 1 && m_pAdvCrosshairStyle->GetActiveItem() == 0 ) // this is the "none" selection
+ {
+ engine->ClientCmd_Unrestricted("cl_crosshair_file \"\"");
+ }
+ else
+ {
+ Q_snprintf(cmd, sizeof(cmd), "cl_crosshair_file %s\n", crosshair);
+ engine->ClientCmd_Unrestricted(cmd);
+ }
+}
+
+void CrosshairImagePanelAdvanced::UpdateVisibility()
+{
+ SetVisible(true);
+ m_pAdvCrosshairRedSlider->SetVisible(true);
+ m_pAdvCrosshairBlueSlider->SetVisible(true);
+ m_pAdvCrosshairGreenSlider->SetVisible(true);
+ m_pAdvCrosshairScaleSlider->SetVisible(true);
+ m_pAdvCrosshairStyle->SetVisible(true);
+
+ if ( ModInfo().NoCrosshair() )
+ {
+ Panel *pTempPanel = NULL;
+
+ pTempPanel = FindSiblingByName( "CrosshairImage" );
+ pTempPanel->SetVisible( false );
+
+ pTempPanel = FindSiblingByName( "CrosshairLabel" );
+ if ( pTempPanel )
+ pTempPanel->SetVisible( false );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Basic help dialog
+//-----------------------------------------------------------------------------
+COptionsSubMultiplayer::COptionsSubMultiplayer(vgui::Panel *parent) : vgui::PropertyPage(parent, "OptionsSubMultiplayer")
+{
+ Button *cancel = new Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ Button *ok = new Button( this, "OK", "#GameUI_OK" );
+ ok->SetCommand( "Ok" );
+
+ Button *apply = new Button( this, "Apply", "#GameUI_Apply" );
+ apply->SetCommand( "Apply" );
+
+ Button *advanced = new Button( this, "Advanced", "#GameUI_AdvancedEllipsis" );
+ advanced->SetCommand( "Advanced" );
+
+ Button *importSprayImage = new Button( this, "ImportSprayImage", "#GameUI_ImportSprayEllipsis" );
+ importSprayImage->SetCommand("ImportSprayImage");
+
+ m_hImportSprayDialog = NULL;
+
+ m_pPrimaryColorSlider = new CCvarSlider( this, "Primary Color Slider", "#GameUI_PrimaryColor",
+ 0.0f, 255.0f, "topcolor" );
+
+ m_pSecondaryColorSlider = new CCvarSlider( this, "Secondary Color Slider", "#GameUI_SecondaryColor",
+ 0.0f, 255.0f, "bottomcolor" );
+
+ m_pHighQualityModelCheckBox = new CCvarToggleCheckButton( this, "High Quality Models", "#GameUI_HighModels", "cl_himodels" );
+
+ m_pModelList = new CLabeledCommandComboBox( this, "Player model" );
+ m_ModelName[0] = 0;
+ InitModelList( m_pModelList );
+
+ m_pLogoList = new CLabeledCommandComboBox( this, "SpraypaintList" );
+ m_LogoName[0] = 0;
+ InitLogoList( m_pLogoList );
+
+ m_pModelImage = new CBitmapImagePanel( this, "ModelImage", NULL );
+ m_pModelImage->AddActionSignalTarget( this );
+
+ m_pLogoImage = new ImagePanel( this, "LogoImage" );
+ m_pLogoImage->AddActionSignalTarget( this );
+
+ m_nLogoR = 255;
+ m_nLogoG = 255;
+ m_nLogoB = 255;
+
+ m_pCrosshairImage = NULL;
+ switch ( ModInfo().AdvCrosshairLevel() )
+ {
+ case 0:
+ if ( !ModInfo().NoCrosshair() )
+ m_pCrosshairImage = new CrosshairImagePanelSimple( this, "CrosshairImage", this );
+ break;
+
+ case 1: // TF
+ case 2: // DOD
+ m_pCrosshairImage = new CrosshairImagePanelAdvanced( this, "AdvCrosshairImage", this );
+ break;
+
+ case 3: // Counter-Strike
+ m_pCrosshairImage = new CrosshairImagePanelCS( this, "CrosshairImage", this );
+ break;
+
+ }
+
+ m_pLockRadarRotationCheckbox = new CCvarToggleCheckButton( this, "LockRadarRotationCheckbox", "#Cstrike_RadarLocked", "cl_radar_locked" );
+
+ m_pDownloadFilterCombo = new ComboBox( this, "DownloadFilterCheck", 4, false );
+ m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_ALL", NULL );
+ m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_NoSounds", NULL );
+ m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_MapsOnly", NULL );
+ m_pDownloadFilterCombo->AddItem( "#GameUI_DownloadFilter_None", NULL );
+
+ //=========
+
+ LoadControlSettings("Resource/OptionsSubMultiplayer.res");
+
+ // this is necessary because some of the game .res files don't have visiblity flags set up correctly for their controls
+ if ( m_pCrosshairImage )
+ m_pCrosshairImage->UpdateVisibility();
+
+ // turn off model selection stuff if the mod specifies "nomodels" in the gameinfo.txt file
+ if ( ModInfo().NoModels() )
+ {
+ Panel *pTempPanel = NULL;
+
+ if ( m_pModelImage )
+ {
+ m_pModelImage->SetVisible( false );
+ }
+
+ if ( m_pModelList )
+ {
+ m_pModelList->SetVisible( false );
+ }
+
+ if ( m_pPrimaryColorSlider )
+ {
+ m_pPrimaryColorSlider->SetVisible( false );
+ }
+
+ if ( m_pSecondaryColorSlider )
+ {
+ m_pSecondaryColorSlider->SetVisible( false );
+ }
+
+ // #GameUI_PlayerModel (from "Resource/OptionsSubMultiplayer.res")
+ pTempPanel = FindChildByName( "Label1" );
+
+ if ( pTempPanel )
+ {
+ pTempPanel->SetVisible( false );
+ }
+
+ // #GameUI_ColorSliders (from "Resource/OptionsSubMultiplayer.res")
+ pTempPanel = FindChildByName( "Colors" );
+
+ if ( pTempPanel )
+ {
+ pTempPanel->SetVisible( false );
+ }
+ }
+
+ // turn off the himodel stuff if the mod specifies "nohimodel" in the gameinfo.txt file
+ if ( ModInfo().NoHiModel() )
+ {
+ if ( m_pHighQualityModelCheckBox )
+ {
+ m_pHighQualityModelCheckBox->SetVisible( false );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubMultiplayer::~COptionsSubMultiplayer()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "Advanced" ) )
+ {
+#ifndef _XBOX
+ if (!m_hMultiplayerAdvancedDialog.Get())
+ {
+ m_hMultiplayerAdvancedDialog = new CMultiplayerAdvancedDialog( this );
+ }
+ m_hMultiplayerAdvancedDialog->Activate();
+#endif
+ }
+ else if (!stricmp( command, "ImportSprayImage" ) )
+ {
+ if (m_hImportSprayDialog == NULL)
+ {
+ m_hImportSprayDialog = new FileOpenDialog(NULL, "#GameUI_ImportSprayImage", true);
+#ifdef WIN32
+ m_hImportSprayDialog->AddFilter("*.tga,*.jpg,*.bmp,*.vtf", "#GameUI_All_Images", true);
+#else
+ m_hImportSprayDialog->AddFilter("*.tga,*.jpg,*.vtf", "#GameUI_All_ImagesNoBmp", true);
+#endif
+ m_hImportSprayDialog->AddFilter("*.tga", "#GameUI_TGA_Images", false);
+ m_hImportSprayDialog->AddFilter("*.jpg", "#GameUI_JPEG_Images", false);
+#ifdef WIN32
+ m_hImportSprayDialog->AddFilter("*.bmp", "#GameUI_BMP_Images", false);
+#endif
+ m_hImportSprayDialog->AddFilter("*.vtf", "#GameUI_VTF_Images", false);
+ m_hImportSprayDialog->AddActionSignalTarget(this);
+ }
+ m_hImportSprayDialog->DoModal(false);
+ m_hImportSprayDialog->Activate();
+ }
+
+ else if ( !stricmp( command, "ResetStats" ) )
+ {
+ QueryBox *box = new QueryBox("#GameUI_ConfirmResetStatsTitle", "#GameUI_ConfirmResetStatsText", this);
+ box->SetOKButtonText("#GameUI_Reset");
+ box->SetOKCommand(new KeyValues("Command", "command", "ResetStats_NoConfirm"));
+ box->SetCancelCommand(new KeyValues("Command", "command", "ReleaseModalWindow"));
+ box->AddActionSignalTarget(this);
+ box->DoModal();
+ }
+
+ else if ( !stricmp( command, "ResetStats_NoConfirm" ) )
+ {
+ engine->ClientCmd_Unrestricted("stats_reset");
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+void COptionsSubMultiplayer::ConversionError( ConversionErrorType nError )
+{
+ const char *pErrorText = NULL;
+
+ switch ( nError )
+ {
+ case CE_MEMORY_ERROR:
+ pErrorText = "#GameUI_Spray_Import_Error_Memory";
+ break;
+
+ case CE_CANT_OPEN_SOURCE_FILE:
+ pErrorText = "#GameUI_Spray_Import_Error_Reading_Image";
+ break;
+
+ case CE_ERROR_PARSING_SOURCE:
+ pErrorText = "#GameUI_Spray_Import_Error_Image_File_Corrupt";
+ break;
+
+ case CE_SOURCE_FILE_SIZE_NOT_SUPPORTED:
+ pErrorText = "#GameUI_Spray_Import_Image_Wrong_Size";
+ break;
+
+ case CE_SOURCE_FILE_FORMAT_NOT_SUPPORTED:
+ pErrorText = "#GameUI_Spray_Import_Image_Wrong_Size";
+ break;
+
+ case CE_SOURCE_FILE_TGA_FORMAT_NOT_SUPPORTED:
+ pErrorText = "#GameUI_Spray_Import_Error_TGA_Format_Not_Supported";
+ break;
+
+ case CE_SOURCE_FILE_BMP_FORMAT_NOT_SUPPORTED:
+ pErrorText = "#GameUI_Spray_Import_Error_BMP_Format_Not_Supported";
+ break;
+
+ case CE_ERROR_WRITING_OUTPUT_FILE:
+ pErrorText = "#GameUI_Spray_Import_Error_Writing_Temp_Output";
+ break;
+
+ case CE_ERROR_LOADING_DLL:
+ pErrorText = "#GameUI_Spray_Import_Error_Cant_Load_VTEX_DLL";
+ break;
+ }
+
+ if ( pErrorText )
+ {
+ // Create the dialog
+ vgui::MessageBox *pErrorDlg = new vgui::MessageBox("#GameUI_Spray_Import_Error_Title", pErrorText ); Assert( pErrorDlg );
+
+ // Display
+ if ( pErrorDlg ) // Check for a NULL just to be extra cautious...
+ {
+ pErrorDlg->DoModal();
+ }
+ }
+}
+
+void COptionsSubMultiplayer::OnFileSelected(const char *fullpath)
+{
+#ifndef _XBOX
+ // this can take a while, put up a waiting cursor
+ surface()->SetCursor(dc_hourglass);
+
+ ConversionErrorType nErrorCode = ImgUtl_ConvertToVTFAndDumpVMT( fullpath, IsPosix() ? "/vgui/logos" : "\\vgui\\logos", 256, 256 );
+ if ( nErrorCode == CE_SUCCESS )
+ {
+ // refresh the logo list so the new spray shows up.
+ InitLogoList(m_pLogoList);
+
+ // Get the filename
+ char szRootFilename[MAX_PATH];
+ V_FileBase( fullpath, szRootFilename, sizeof( szRootFilename ) );
+
+ // automatically select the logo that was just imported.
+ SelectLogo(szRootFilename);
+ }
+ else
+ {
+ ConversionError( nErrorCode );
+ }
+
+ // change the cursor back to normal
+ surface()->SetCursor(dc_user);
+#endif
+}
+
+struct ValveJpegErrorHandler_t
+{
+ // The default manager
+ struct jpeg_error_mgr m_Base;
+ // For handling any errors
+ jmp_buf m_ErrorContext;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: We'll override the default error handler so we can deal with errors without having to exit the engine
+//-----------------------------------------------------------------------------
+static void ValveJpegErrorHandler( j_common_ptr cinfo )
+{
+ ValveJpegErrorHandler_t *pError = reinterpret_cast< ValveJpegErrorHandler_t * >( cinfo->err );
+
+ char buffer[ JMSG_LENGTH_MAX ];
+
+ /* Create the message */
+ ( *cinfo->err->format_message )( cinfo, buffer );
+
+ Warning( "%s\n", buffer );
+
+ // Bail
+ longjmp( pError->m_ErrorContext, 1 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds the list of logos
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::InitLogoList( CLabeledCommandComboBox *cb )
+{
+ // Find out images
+ FileFindHandle_t fh;
+ char directory[ 512 ];
+
+ ConVarRef cl_logofile( "cl_logofile", true );
+ if ( !cl_logofile.IsValid() )
+ return;
+
+ cb->DeleteAllItems();
+
+ const char *logofile = cl_logofile.GetString();
+ Q_snprintf( directory, sizeof( directory ), "materials/vgui/logos/*.vtf" );
+ const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
+ int i = 0, initialItem = 0;
+ while (fn)
+ {
+ char filename[ 512 ];
+ Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
+ if ( strlen( filename ) >= 4 )
+ {
+ filename[ strlen( filename ) - 4 ] = 0;
+ Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
+ if ( g_pFullFileSystem->FileExists( filename ) )
+ {
+ // strip off the extension
+ Q_strncpy( filename, fn, sizeof( filename ) );
+ filename[ strlen( filename ) - 4 ] = 0;
+ cb->AddItem( filename, "" );
+
+ // check to see if this is the one we have set
+ Q_snprintf( filename, sizeof(filename), "materials/vgui/logos/%s", fn );
+ if (!Q_stricmp(filename, logofile))
+ {
+ initialItem = i;
+ }
+
+ ++i;
+ }
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+ }
+
+ g_pFullFileSystem->FindClose( fh );
+ cb->SetInitialItem(initialItem);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Selects the given logo in the logo list.
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::SelectLogo(const char *logoName)
+{
+ int numEntries = m_pLogoList->GetItemCount();
+ int index;
+ wchar_t itemText[MAX_PATH];
+ wchar_t itemToSelectText[MAX_PATH];
+
+ // convert the logo filename to unicode
+ g_pVGuiLocalize->ConvertANSIToUnicode(logoName, itemToSelectText, sizeof(itemToSelectText));
+
+ // find the index of the spray we want.
+ for (index = 0; index < numEntries; ++index)
+ {
+ m_pLogoList->GetItemText(index, itemText, sizeof(itemText));
+ if (!wcscmp(itemText, itemToSelectText))
+ {
+ break;
+ }
+ }
+
+ if (index < numEntries)
+ {
+ // select the logo.
+ m_pLogoList->ActivateItem(index);
+ }
+}
+
+#define MODEL_MATERIAL_BASE_FOLDER "materials/vgui/playermodels/"
+
+
+void StripStringOutOfString( const char *pPattern, const char *pIn, char *pOut )
+{
+ int iLengthBase = strlen( pPattern );
+ int iLengthString = strlen( pIn );
+
+ int k = 0;
+
+ for ( int j = iLengthBase; j < iLengthString; j++ )
+ {
+ pOut[k] = pIn[j];
+ k++;
+ }
+
+ pOut[k] = 0;
+}
+
+void FindVMTFilesInFolder( const char *pFolder, const char *pFolderName, CLabeledCommandComboBox *cb, int &iCount, int &iInitialItem )
+{
+ ConVarRef cl_modelfile( "cl_playermodel", true );
+ if ( !cl_modelfile.IsValid() )
+ return;
+
+ char directory[ 512 ];
+ Q_snprintf( directory, sizeof( directory ), "%s/*.*", pFolder );
+
+ FileFindHandle_t fh;
+
+ const char *fn = g_pFullFileSystem->FindFirst( directory, &fh );
+ const char *modelfile = cl_modelfile.GetString();
+
+ while ( fn )
+ {
+ if ( !stricmp( fn, ".") || !stricmp( fn, "..") )
+ {
+ fn = g_pFullFileSystem->FindNext( fh );
+ continue;
+ }
+
+ if ( g_pFullFileSystem->FindIsDirectory( fh ) )
+ {
+ char folderpath[512];
+
+ Q_snprintf( folderpath, sizeof( folderpath ), "%s/%s", pFolder, fn );
+
+ FindVMTFilesInFolder( folderpath, fn, cb, iCount, iInitialItem );
+ fn = g_pFullFileSystem->FindNext( fh );
+ continue;
+ }
+
+ if ( !strstr( fn, ".vmt" ) )
+ {
+ fn = g_pFullFileSystem->FindNext( fh );
+ continue;
+ }
+
+
+ char filename[ 512 ];
+ Q_snprintf( filename, sizeof(filename), "%s/%s", pFolder, fn );
+ if ( strlen( filename ) >= 4 )
+ {
+ filename[ strlen( filename ) - 4 ] = 0;
+ Q_strncat( filename, ".vmt", sizeof( filename ), COPY_ALL_CHARACTERS );
+ if ( g_pFullFileSystem->FileExists( filename ) )
+ {
+ char displayname[ 512 ];
+ char texturepath[ 512 ];
+ // strip off the extension
+ Q_strncpy( displayname, fn, sizeof( displayname ) );
+ StripStringOutOfString( MODEL_MATERIAL_BASE_FOLDER, filename, texturepath );
+
+ displayname[ strlen( displayname ) - 4 ] = 0;
+
+ if ( CORRECT_PATH_SEPARATOR == texturepath[0] )
+ cb->AddItem( displayname, texturepath + 1 ); // ignore the initial "/" in texture path
+ else
+ cb->AddItem( displayname, texturepath );
+
+
+ char realname[ 512 ];
+ Q_FileBase( modelfile, realname, sizeof( realname ) );
+ Q_FileBase( filename, filename, sizeof( filename ) );
+
+ if (!stricmp(filename, realname))
+ {
+ iInitialItem = iCount;
+ }
+
+ ++iCount;
+ }
+ }
+
+ fn = g_pFullFileSystem->FindNext( fh );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Builds model list
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::InitModelList( CLabeledCommandComboBox *cb )
+{
+ // Find out images
+ int i = 0, initialItem = 0;
+
+ cb->DeleteAllItems();
+ FindVMTFilesInFolder( MODEL_MATERIAL_BASE_FOLDER, "", cb, i, initialItem );
+ cb->SetInitialItem( initialItem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::RemapLogo()
+{
+ char logoname[256];
+
+ m_pLogoList->GetText( logoname, sizeof( logoname ) );
+ if( !logoname[ 0 ] )
+ return;
+
+ char fullLogoName[512];
+
+ // make sure there is a version with the proper shader
+ g_pFullFileSystem->CreateDirHierarchy( "materials/VGUI/logos/UI", "GAME" );
+ Q_snprintf( fullLogoName, sizeof( fullLogoName ), "materials/VGUI/logos/UI/%s.vmt", logoname );
+ if ( !g_pFullFileSystem->FileExists( fullLogoName ) )
+ {
+ FileHandle_t fp = g_pFullFileSystem->Open( fullLogoName, "wb" );
+ if ( !fp )
+ return;
+
+ char data[1024];
+ Q_snprintf( data, sizeof( data ), "\"UnlitGeneric\"\n\
+{\n\
+ // Original shader: BaseTimesVertexColorAlphaBlendNoOverbright\n\
+ \"$translucent\" 1\n\
+ \"$basetexture\" \"VGUI/logos/%s\"\n\
+ \"$vertexcolor\" 1\n\
+ \"$vertexalpha\" 1\n\
+ \"$no_fullbright\" 1\n\
+ \"$ignorez\" 1\n\
+}\n\
+", logoname );
+
+ g_pFullFileSystem->Write( data, strlen( data ), fp );
+ g_pFullFileSystem->Close( fp );
+ }
+
+ Q_snprintf( fullLogoName, sizeof( fullLogoName ), "logos/UI/%s", logoname );
+ m_pLogoImage->SetImage( fullLogoName );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::RemapModel()
+{
+ const char *pModelName = m_pModelList->GetActiveItemCommand();
+
+ if( pModelName == NULL )
+ return;
+
+ char texture[ 256 ];
+ Q_snprintf ( texture, sizeof( texture ), "vgui/playermodels/%s", pModelName );
+ texture[ strlen( texture ) - 4 ] = 0;
+
+ m_pModelImage->setTexture( texture );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Called whenever model name changes
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::OnTextChanged(vgui::Panel *panel)
+{
+ RemapModel();
+ RemapLogo();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::OnControlModified()
+{
+ PostMessage(GetParent(), new KeyValues("ApplyButtonEnable"));
+ InvalidateLayout();
+}
+
+#define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B')
+#define SUIT_HUE_START 192
+#define SUIT_HUE_END 223
+#define PLATE_HUE_START 160
+#define PLATE_HUE_END 191
+
+#ifdef POSIX
+typedef struct tagRGBQUAD {
+ uint8 rgbBlue;
+ uint8 rgbGreen;
+ uint8 rgbRed;
+ uint8 rgbReserved;
+} RGBQUAD;
+#endif
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+static void PaletteHueReplace( RGBQUAD *palSrc, int newHue, int Start, int end )
+{
+ int i;
+ float r, b, g;
+ float maxcol, mincol;
+ float hue, val, sat;
+
+ hue = (float)(newHue * (360.0 / 255));
+
+ for (i = Start; i <= end; i++)
+ {
+ b = palSrc[ i ].rgbBlue;
+ g = palSrc[ i ].rgbGreen;
+ r = palSrc[ i ].rgbRed;
+
+ maxcol = max( max( r, g ), b ) / 255.0f;
+ mincol = min( min( r, g ), b ) / 255.0f;
+
+ val = maxcol;
+ sat = (maxcol - mincol) / maxcol;
+
+ mincol = val * (1.0f - sat);
+
+ if (hue <= 120)
+ {
+ b = mincol;
+ if (hue < 60)
+ {
+ r = val;
+ g = mincol + hue * (val - mincol)/(120 - hue);
+ }
+ else
+ {
+ g = val;
+ r = mincol + (120 - hue)*(val-mincol)/hue;
+ }
+ }
+ else if (hue <= 240)
+ {
+ r = mincol;
+ if (hue < 180)
+ {
+ g = val;
+ b = mincol + (hue - 120)*(val-mincol)/(240 - hue);
+ }
+ else
+ {
+ b = val;
+ g = mincol + (240 - hue)*(val-mincol)/(hue - 120);
+ }
+ }
+ else
+ {
+ g = mincol;
+ if (hue < 300)
+ {
+ b = val;
+ r = mincol + (hue - 240)*(val-mincol)/(360 - hue);
+ }
+ else
+ {
+ r = val;
+ b = mincol + (360 - hue)*(val-mincol)/(hue - 240);
+ }
+ }
+
+ palSrc[ i ].rgbBlue = (unsigned char)(b * 255);
+ palSrc[ i ].rgbGreen = (unsigned char)(g * 255);
+ palSrc[ i ].rgbRed = (unsigned char)(r * 255);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::ColorForName( char const *pszColorName, int&r, int&g, int&b )
+{
+ r = g = b = 0;
+
+ int count = sizeof( itemlist ) / sizeof( itemlist[0] );
+
+ for ( int i = 0; i < count; i++ )
+ {
+ if (!Q_strnicmp(pszColorName, itemlist[ i ].name, strlen(itemlist[ i ].name)))
+ {
+ r = itemlist[ i ].r;
+ g = itemlist[ i ].g;
+ b = itemlist[ i ].b;
+ return;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::OnResetData()
+{
+ // reset the DownloadFilter combo box
+ if ( m_pDownloadFilterCombo )
+ {
+ // cl_downloadfilter
+ ConVarRef cl_downloadfilter( "cl_downloadfilter");
+
+ if ( Q_stricmp( cl_downloadfilter.GetString(), "none" ) == 0 )
+ {
+ m_pDownloadFilterCombo->ActivateItem( 3 );
+ }
+ else if ( Q_stricmp( cl_downloadfilter.GetString(), "nosounds" ) == 0 )
+ {
+ m_pDownloadFilterCombo->ActivateItem( 1 );
+ }
+ else if ( Q_stricmp( cl_downloadfilter.GetString(), "mapsonly" ) == 0 )
+ {
+ m_pDownloadFilterCombo->ActivateItem( 2 );
+ }
+ else
+ {
+ m_pDownloadFilterCombo->ActivateItem( 0 );
+ }
+ }
+
+ if ( m_pCrosshairImage )
+ m_pCrosshairImage->ResetData();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubMultiplayer::OnApplyChanges()
+{
+ m_pPrimaryColorSlider->ApplyChanges();
+ m_pSecondaryColorSlider->ApplyChanges();
+// m_pModelList->ApplyChanges();
+ m_pLogoList->ApplyChanges();
+ m_pLogoList->GetText(m_LogoName, sizeof(m_LogoName));
+ m_pHighQualityModelCheckBox->ApplyChanges();
+
+ for ( int i=0; i<m_cvarToggleCheckButtons.GetCount(); ++i )
+ {
+ CCvarToggleCheckButton *toggleButton = m_cvarToggleCheckButtons[i];
+ if( toggleButton->IsVisible() && toggleButton->IsEnabled() )
+ {
+ toggleButton->ApplyChanges();
+ }
+ }
+
+ if ( m_pLockRadarRotationCheckbox != NULL )
+ {
+ m_pLockRadarRotationCheckbox->ApplyChanges();
+ }
+
+ if ( m_pCrosshairImage != NULL )
+ m_pCrosshairImage->ApplyChanges();
+
+ // save the logo name
+ char cmd[512];
+ if ( m_LogoName[ 0 ] )
+ {
+ Q_snprintf(cmd, sizeof(cmd), "cl_logofile materials/vgui/logos/%s.vtf\n", m_LogoName);
+ }
+ else
+ {
+ Q_strncpy( cmd, "cl_logofile \"\"\n", sizeof( cmd ) );
+ }
+ engine->ClientCmd_Unrestricted(cmd);
+
+ if ( m_pModelList && m_pModelList->IsVisible() && m_pModelList->GetActiveItemCommand() )
+ {
+ Q_strncpy( m_ModelName, m_pModelList->GetActiveItemCommand(), sizeof( m_ModelName ) );
+ Q_StripExtension( m_ModelName, m_ModelName, sizeof ( m_ModelName ) );
+
+ // save the player model name
+ Q_snprintf(cmd, sizeof(cmd), "cl_playermodel models/%s.mdl\n", m_ModelName );
+ engine->ClientCmd_Unrestricted(cmd);
+ }
+ else
+ {
+ m_ModelName[0] = 0;
+ }
+
+ // set the DownloadFilter cvar
+ if ( m_pDownloadFilterCombo )
+ {
+ ConVarRef cl_downloadfilter( "cl_downloadfilter" );
+
+ switch ( m_pDownloadFilterCombo->GetActiveItem() )
+ {
+ default:
+ case 0:
+ cl_downloadfilter.SetValue( "all" );
+ break;
+ case 1:
+ cl_downloadfilter.SetValue( "nosounds" );
+ break;
+ case 2:
+ cl_downloadfilter.SetValue( "mapsonly" );
+ break;
+ case 3:
+ cl_downloadfilter.SetValue( "none" );
+ break;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Allow the res file to create controls on per-mod basis
+//-----------------------------------------------------------------------------
+Panel *COptionsSubMultiplayer::CreateControlByName( const char *controlName )
+{
+ if( !Q_stricmp( "CCvarToggleCheckButton", controlName ) )
+ {
+ CCvarToggleCheckButton *newButton = new CCvarToggleCheckButton( this, controlName, "", "" );
+ m_cvarToggleCheckButtons.AddElement( newButton );
+ return newButton;
+ }
+ else
+ {
+ return BaseClass::CreateControlByName( controlName );
+ }
+}
+
diff --git a/gameui/OptionsSubMultiplayer.h b/gameui/OptionsSubMultiplayer.h
new file mode 100644
index 0000000..85577bb
--- /dev/null
+++ b/gameui/OptionsSubMultiplayer.h
@@ -0,0 +1,113 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONSSUBMULTIPLAYER_H
+#define OPTIONSSUBMULTIPLAYER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+#include <vgui_controls/ImagePanel.h>
+#include "imageutils.h"
+
+class CLabeledCommandComboBox;
+class CBitmapImagePanel;
+
+class CCvarToggleCheckButton;
+class CCvarTextEntry;
+class CCvarSlider;
+
+class CMultiplayerAdvancedDialog;
+
+class COptionsSubMultiplayer;
+
+class CrosshairImagePanelBase : public vgui::ImagePanel
+{
+ DECLARE_CLASS_SIMPLE( CrosshairImagePanelBase, vgui::ImagePanel );
+public:
+ CrosshairImagePanelBase( Panel *parent, const char *name ) : BaseClass(parent, name) {}
+ virtual void ResetData() {}
+ virtual void ApplyChanges() {}
+ virtual void UpdateVisibility() {}
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: multiplayer options property page
+//-----------------------------------------------------------------------------
+class COptionsSubMultiplayer : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubMultiplayer, vgui::PropertyPage );
+
+public:
+ COptionsSubMultiplayer(vgui::Panel *parent);
+ ~COptionsSubMultiplayer();
+
+ virtual vgui::Panel *CreateControlByName(const char *controlName);
+
+ MESSAGE_FUNC( OnControlModified, "ControlModified" );
+
+protected:
+ // Called when page is loaded. Data should be reloaded from document into controls.
+ virtual void OnResetData();
+ // Called when the OK / Apply button is pressed. Changed data should be written into document.
+ virtual void OnApplyChanges();
+
+ virtual void OnCommand( const char *command );
+
+private:
+ void InitModelList(CLabeledCommandComboBox *cb);
+ void InitLogoList(CLabeledCommandComboBox *cb);
+
+ void RemapModel();
+ void RemapLogo();
+
+ void ConversionError( ConversionErrorType nError );
+
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel );
+ MESSAGE_FUNC_CHARPTR( OnFileSelected, "FileSelected", fullpath );
+
+ void ColorForName(char const *pszColorName, int &r, int &g, int &b);
+
+ CBitmapImagePanel *m_pModelImage;
+ CLabeledCommandComboBox *m_pModelList;
+ char m_ModelName[128];
+
+ vgui::ImagePanel *m_pLogoImage;
+ CLabeledCommandComboBox *m_pLogoList;
+ char m_LogoName[128];
+
+ CCvarSlider *m_pPrimaryColorSlider;
+ CCvarSlider *m_pSecondaryColorSlider;
+ CCvarToggleCheckButton *m_pHighQualityModelCheckBox;
+
+ // Mod specific general checkboxes
+ vgui::Dar< CCvarToggleCheckButton * > m_cvarToggleCheckButtons;
+
+ CCvarToggleCheckButton *m_pLockRadarRotationCheckbox;
+
+ CrosshairImagePanelBase *m_pCrosshairImage;
+
+ // --- client download filter
+ vgui::ComboBox *m_pDownloadFilterCombo;
+
+ // Begin Spray Import Functions
+ ConversionErrorType WriteSprayVMT(const char *vtfPath);
+ void SelectLogo(const char *logoName);
+ // End Spray Import Functions
+
+ int m_nLogoR;
+ int m_nLogoG;
+ int m_nLogoB;
+
+#ifndef _XBOX
+ vgui::DHANDLE<CMultiplayerAdvancedDialog> m_hMultiplayerAdvancedDialog;
+#endif
+ vgui::FileOpenDialog *m_hImportSprayDialog;
+};
+
+#endif // OPTIONSSUBMULTIPLAYER_H
diff --git a/gameui/OptionsSubPortal.cpp b/gameui/OptionsSubPortal.cpp
new file mode 100644
index 0000000..a6ad724
--- /dev/null
+++ b/gameui/OptionsSubPortal.cpp
@@ -0,0 +1,98 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "OptionsSubPortal.h"
+#include "CvarToggleCheckButton.h"
+#include "vgui_controls/ComboBox.h"
+
+#include "EngineInterface.h"
+
+#include <KeyValues.h>
+#include <vgui/IScheme.h>
+#include "tier1/convar.h"
+#include <stdio.h>
+#include <vgui_controls/TextEntry.h>
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+COptionsSubPortal::COptionsSubPortal(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+ m_pPortalFunnelCheckBox = new CCvarToggleCheckButton(
+ this,
+ "PortalFunnel",
+ "#GameUI_PortalFunnel",
+ "sv_player_funnel_into_portals" );
+
+ m_pPortalDepthCombo = new ComboBox( this, "PortalDepth", 6, false );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth0", new KeyValues("PortalDepth", "depth", 0) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth1", new KeyValues("PortalDepth", "depth", 1) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth2", new KeyValues("PortalDepth", "depth", 2) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth3", new KeyValues("PortalDepth", "depth", 3) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth4", new KeyValues("PortalDepth", "depth", 4) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth5", new KeyValues("PortalDepth", "depth", 5) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth6", new KeyValues("PortalDepth", "depth", 6) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth7", new KeyValues("PortalDepth", "depth", 7) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth8", new KeyValues("PortalDepth", "depth", 8) );
+ m_pPortalDepthCombo->AddItem( "#GameUI_PortalDepth9", new KeyValues("PortalDepth", "depth", 9) );
+
+ LoadControlSettings("Resource\\OptionsSubPortal.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubPortal::~COptionsSubPortal()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubPortal::OnResetData()
+{
+ m_pPortalFunnelCheckBox->Reset();
+
+ // Portal render depth
+ ConVarRef r_portal_stencil_depth("r_portal_stencil_depth");
+ if ( r_portal_stencil_depth.IsValid() )
+ {
+ m_pPortalDepthCombo->ActivateItem(r_portal_stencil_depth.GetInt());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubPortal::OnApplyChanges()
+{
+ m_pPortalFunnelCheckBox->ApplyChanges();
+
+ // Portal render depth
+ if ( m_pPortalDepthCombo->IsEnabled() )
+ {
+ ConVarRef r_portal_stencil_depth( "r_portal_stencil_depth" );
+ r_portal_stencil_depth.SetValue( m_pPortalDepthCombo->GetActiveItem() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets background color & border
+//-----------------------------------------------------------------------------
+void COptionsSubPortal::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubPortal::OnControlModified()
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+}
diff --git a/gameui/OptionsSubPortal.h b/gameui/OptionsSubPortal.h
new file mode 100644
index 0000000..1d92280
--- /dev/null
+++ b/gameui/OptionsSubPortal.h
@@ -0,0 +1,59 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_PORTAL_H
+#define OPTIONS_SUB_PORTAL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+class CLabeledCommandComboBox;
+class CCvarToggleCheckButton;
+
+namespace vgui
+{
+ class Label;
+ class Panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Mouse Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubPortal : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubPortal, vgui::PropertyPage );
+
+public:
+ COptionsSubPortal(vgui::Panel *parent);
+ ~COptionsSubPortal();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+
+protected:
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+private:
+ MESSAGE_FUNC( OnCheckButtonChecked, "CheckButtonChecked" )
+ {
+ OnControlModified();
+ }
+ MESSAGE_FUNC( OnControlModified, "ControlModified" );
+ MESSAGE_FUNC( OnTextChanged, "TextChanged" )
+ {
+ OnControlModified();
+ }
+
+ CCvarToggleCheckButton *m_pPortalFunnelCheckBox;
+ vgui::ComboBox *m_pPortalDepthCombo;
+};
+
+
+
+#endif // OPTIONS_SUB_MOUSE_H \ No newline at end of file
diff --git a/gameui/OptionsSubVideo.cpp b/gameui/OptionsSubVideo.cpp
new file mode 100644
index 0000000..57db401
--- /dev/null
+++ b/gameui/OptionsSubVideo.cpp
@@ -0,0 +1,1763 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "OptionsSubVideo.h"
+#include "cvarslider.h"
+#include "EngineInterface.h"
+#include "BasePanel.h"
+#include "IGameUIFuncs.h"
+#include "modes.h"
+#include "materialsystem/materialsystem_config.h"
+#include "filesystem.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/Frame.h"
+#include "vgui_controls/QueryBox.h"
+#include "CvarToggleCheckButton.h"
+#include "tier1/KeyValues.h"
+#include "vgui/IInput.h"
+#include "vgui/ILocalize.h"
+#include "vgui/ISystem.h"
+#include "tier0/icommandline.h"
+#include "tier1/convar.h"
+#include "ModInfo.h"
+#include "vgui_controls/Tooltip.h"
+#include "sourcevr/isourcevirtualreality.h"
+
+#if defined( USE_SDL )
+#include "SDL.h"
+#endif
+
+#include "inetchannelinfo.h"
+
+extern IMaterialSystem *materials;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: aspect ratio mappings (for normal/widescreen combo)
+//-----------------------------------------------------------------------------
+struct RatioToAspectMode_t
+{
+ int anamorphic;
+ float aspectRatio;
+};
+RatioToAspectMode_t g_RatioToAspectModes[] =
+{
+ { 0, 4.0f / 3.0f },
+ { 1, 16.0f / 9.0f },
+ { 2, 16.0f / 10.0f },
+ { 2, 1.0f },
+};
+
+struct AAMode_t
+{
+ int m_nNumSamples;
+ int m_nQualityLevel;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: list of valid dx levels
+//-----------------------------------------------------------------------------
+int g_DirectXLevels[] =
+{
+ 70,
+ 80,
+ 81,
+ 90,
+#if DX_TO_GL_ABSTRACTION
+ 92,
+#endif
+ 95,
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the string name of a given dxlevel
+//-----------------------------------------------------------------------------
+void GetNameForDXLevel( int dxlevel, char *name, int bufferSize)
+{
+ if ( ( dxlevel >= 92 ) && ( dxlevel <= 95 ) )
+ {
+ Q_snprintf( name, bufferSize, "DirectX v9.0+" );
+ }
+ else
+ {
+ Q_snprintf( name, bufferSize, "DirectX v%.1f", dxlevel / 10.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the aspect ratio mode number for the given resolution
+//-----------------------------------------------------------------------------
+int GetScreenAspectMode( int width, int height )
+{
+ float aspectRatio = (float)width / (float)height;
+
+ // just find the closest ratio
+ float closestAspectRatioDist = 99999.0f;
+ int closestAnamorphic = 0;
+ for (int i = 0; i < ARRAYSIZE(g_RatioToAspectModes); i++)
+ {
+ float dist = fabs( g_RatioToAspectModes[i].aspectRatio - aspectRatio );
+ if (dist < closestAspectRatioDist)
+ {
+ closestAspectRatioDist = dist;
+ closestAnamorphic = g_RatioToAspectModes[i].anamorphic;
+ }
+ }
+
+ return closestAnamorphic;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the string name of the specified resolution mode
+//-----------------------------------------------------------------------------
+static void GetResolutionName( vmode_t *mode, char *sz, int sizeofsz, int desktopWidth, int desktopHeight )
+{
+ Q_snprintf( sz, sizeofsz, "%i x %i%s", mode->width, mode->height,
+ ( mode->width == desktopWidth ) && ( mode->height == desktopHeight ) ? " (native)": "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gamma-adjust dialog
+//-----------------------------------------------------------------------------
+class CGammaDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CGammaDialog, vgui::Frame );
+public:
+ CGammaDialog( vgui::VPANEL hParent ) : BaseClass( NULL, "OptionsSubVideoGammaDlg" )
+ {
+ // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
+ SetTitle("#GameUI_AdjustGamma_Title", true);
+ SetSize( 400, 260 );
+ SetDeleteSelfOnClose( true );
+
+ m_pGammaSlider = new CCvarSlider( this, "Gamma", "#GameUI_Gamma", 1.6f, 2.6f, "mat_monitorgamma" );
+ m_pGammaLabel = new Label( this, "Gamma label", "#GameUI_Gamma" );
+ m_pGammaEntry = new TextEntry( this, "GammaEntry" );
+
+ Button *ok = new Button( this, "OKButton", "#vgui_ok" );
+ ok->SetCommand( new KeyValues("OK") );
+
+ LoadControlSettings( "resource/OptionsSubVideoGammaDlg.res" );
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+
+ m_pGammaSlider->SetTickCaptions( "#GameUI_Light", "#GameUI_Dark" );
+ }
+
+ MESSAGE_FUNC_PTR( OnGammaChanged, "SliderMoved", panel )
+ {
+ if (panel == m_pGammaSlider)
+ {
+ m_pGammaSlider->ApplyChanges();
+ }
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+ m_flOriginalGamma = m_pGammaSlider->GetValue();
+ UpdateGammaLabel();
+ }
+
+ MESSAGE_FUNC( OnOK, "OK" )
+ {
+ // make the gamma stick
+ m_flOriginalGamma = m_pGammaSlider->GetValue();
+ Close();
+ }
+
+ virtual void OnClose()
+ {
+ // reset to the original gamma
+ m_pGammaSlider->SetValue( m_flOriginalGamma );
+ m_pGammaSlider->ApplyChanges();
+ BaseClass::OnClose();
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ MESSAGE_FUNC_PTR( OnControlModified, "ControlModified", panel )
+ {
+ // the HasBeenModified() check is so that if the value is outside of the range of the
+ // slider, it won't use the slider to determine the display value but leave the
+ // real value that we determined in the constructor
+ if (panel == m_pGammaSlider && m_pGammaSlider->HasBeenModified())
+ {
+ UpdateGammaLabel();
+ }
+ }
+
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel )
+ {
+ if (panel == m_pGammaEntry)
+ {
+ char buf[64];
+ m_pGammaEntry->GetText(buf, 64);
+
+ float fValue = (float) atof(buf);
+ if (fValue >= 1.0)
+ {
+ m_pGammaSlider->SetSliderValue(fValue);
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+ }
+ }
+ }
+
+ void UpdateGammaLabel()
+ {
+ char buf[64];
+ Q_snprintf(buf, sizeof( buf ), " %.1f", m_pGammaSlider->GetSliderValue());
+ m_pGammaEntry->SetText(buf);
+ }
+
+
+private:
+ CCvarSlider *m_pGammaSlider;
+ vgui::Label *m_pGammaLabel;
+ vgui::TextEntry *m_pGammaEntry;
+ float m_flOriginalGamma;
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: advanced keyboard settings dialog
+//-----------------------------------------------------------------------------
+class COptionsSubVideoAdvancedDlg : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubVideoAdvancedDlg, vgui::Frame );
+public:
+ COptionsSubVideoAdvancedDlg( vgui::Panel *parent ) : BaseClass( parent , "OptionsSubVideoAdvancedDlg" )
+ {
+ SetTitle("#GameUI_VideoAdvanced_Title", true);
+ SetSize( 260, 400 );
+
+ m_pDXLevel = new ComboBox(this, "dxlabel", 6, false );
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+ KeyValues *pKeyValues = new KeyValues( "config" );
+ materials->GetRecommendedConfigurationInfo( 0, pKeyValues );
+ m_pDXLevel->DeleteAllItems();
+ for (int i = 0; i < ARRAYSIZE(g_DirectXLevels); i++)
+ {
+ // don't allow choice of lower dxlevels than the default,
+ // unless we're already at that lower level or have it forced
+ if (!CommandLine()->CheckParm("-dxlevel") &&
+ g_DirectXLevels[i] != config.dxSupportLevel &&
+ g_DirectXLevels[i] < pKeyValues->GetInt("ConVar.mat_dxlevel"))
+ continue;
+
+ KeyValues *pTempKV = new KeyValues("config");
+ if (g_DirectXLevels[i] == pKeyValues->GetInt("ConVar.mat_dxlevel")
+ || materials->GetRecommendedConfigurationInfo( g_DirectXLevels[i], pTempKV ))
+ {
+ // add the configuration in the combo
+ char szDXLevelName[64];
+ GetNameForDXLevel( g_DirectXLevels[i], szDXLevelName, sizeof(szDXLevelName) );
+ m_pDXLevel->AddItem( szDXLevelName, new KeyValues("dxlevel", "dxlevel", g_DirectXLevels[i]) );
+ }
+
+ pTempKV->deleteThis();
+ }
+ pKeyValues->deleteThis();
+
+ m_pModelDetail = new ComboBox( this, "ModelDetail", 6, false );
+ m_pModelDetail->AddItem("#gameui_low", NULL);
+ m_pModelDetail->AddItem("#gameui_medium", NULL);
+ m_pModelDetail->AddItem("#gameui_high", NULL);
+
+ m_pTextureDetail = new ComboBox( this, "TextureDetail", 6, false );
+ m_pTextureDetail->AddItem("#gameui_low", NULL);
+ m_pTextureDetail->AddItem("#gameui_medium", NULL);
+ m_pTextureDetail->AddItem("#gameui_high", NULL);
+ m_pTextureDetail->AddItem("#gameui_ultra", NULL);
+
+ // Build list of MSAA and CSAA modes, based upon those which are supported by the device
+ //
+ // The modes that we've seen in the wild to date are as follows (in perf order, fastest to slowest)
+ //
+ // 2x 4x 6x 8x 16x 8x 16xQ
+ // Texture/Shader Samples 1 1 1 1 1 1 1
+ // Stored Color/Z Samples 2 4 6 4 4 8 8
+ // Coverage Samples 2 4 6 8 16 8 16
+ // MSAA or CSAA M M M C C M C
+ //
+ // The CSAA modes are nVidia only (added in the G80 generation of GPUs)
+ //
+ m_nNumAAModes = 0;
+ m_pAntialiasingMode = new ComboBox( this, "AntialiasingMode", 10, false );
+ m_pAntialiasingMode->AddItem("#GameUI_None", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 1;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
+ m_nNumAAModes++;
+
+ if ( materials->SupportsMSAAMode(2) )
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_2X", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 2;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsMSAAMode(4) )
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_4X", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsMSAAMode(6) )
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_6X", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 6;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsCSAAMode(4, 2) ) // nVidia CSAA "8x"
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_8X_CSAA", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 2;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsCSAAMode(4, 4) ) // nVidia CSAA "16x"
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_16X_CSAA", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 4;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 4;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsMSAAMode(8) )
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_8X", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 8;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 0;
+ m_nNumAAModes++;
+ }
+
+ if ( materials->SupportsCSAAMode(8, 2) ) // nVidia CSAA "16xQ"
+ {
+ m_pAntialiasingMode->AddItem("#GameUI_16XQ_CSAA", NULL);
+ m_nAAModes[m_nNumAAModes].m_nNumSamples = 8;
+ m_nAAModes[m_nNumAAModes].m_nQualityLevel = 2;
+ m_nNumAAModes++;
+ }
+
+ m_pFilteringMode = new ComboBox( this, "FilteringMode", 6, false );
+ m_pFilteringMode->AddItem("#GameUI_Bilinear", NULL);
+ m_pFilteringMode->AddItem("#GameUI_Trilinear", NULL);
+ m_pFilteringMode->AddItem("#GameUI_Anisotropic2X", NULL);
+ m_pFilteringMode->AddItem("#GameUI_Anisotropic4X", NULL);
+ m_pFilteringMode->AddItem("#GameUI_Anisotropic8X", NULL);
+ m_pFilteringMode->AddItem("#GameUI_Anisotropic16X", NULL);
+
+ m_pShadowDetail = new ComboBox( this, "ShadowDetail", 6, false );
+ m_pShadowDetail->AddItem("#gameui_low", NULL);
+ m_pShadowDetail->AddItem("#gameui_medium", NULL);
+ if ( materials->SupportsShadowDepthTextures() )
+ {
+ m_pShadowDetail->AddItem("#gameui_high", NULL);
+ }
+
+ ConVarRef mat_dxlevel( "mat_dxlevel" );
+
+ m_pHDR = new ComboBox( this, "HDR", 6, false );
+ m_pHDR->AddItem("#GameUI_hdr_level0", NULL);
+ m_pHDR->AddItem("#GameUI_hdr_level1", NULL);
+
+ if ( materials->SupportsHDRMode( HDR_TYPE_INTEGER ) )
+ {
+ m_pHDR->AddItem("#GameUI_hdr_level2", NULL);
+ }
+#if 0
+ if ( materials->SupportsHDRMode( HDR_TYPE_FLOAT ) )
+ {
+ m_pHDR->AddItem("#GameUI_hdr_level3", NULL);
+ }
+#endif
+
+ m_pHDR->SetEnabled( mat_dxlevel.GetInt() >= 80 );
+
+ m_pWaterDetail = new ComboBox( this, "WaterDetail", 6, false );
+ m_pWaterDetail->AddItem("#gameui_noreflections", NULL);
+ m_pWaterDetail->AddItem("#gameui_reflectonlyworld", NULL);
+ m_pWaterDetail->AddItem("#gameui_reflectall", NULL);
+
+ m_pVSync = new ComboBox( this, "VSync", 2, false );
+ m_pVSync->AddItem("#gameui_disabled", NULL);
+ m_pVSync->AddItem("#gameui_enabled", NULL);
+
+ m_pMulticore = new ComboBox( this, "Multicore", 2, false );
+ m_pMulticore->AddItem("#gameui_disabled", NULL);
+ m_pMulticore->AddItem("#gameui_enabled", NULL);
+
+ m_pShaderDetail = new ComboBox( this, "ShaderDetail", 6, false );
+ m_pShaderDetail->AddItem("#gameui_low", NULL);
+ m_pShaderDetail->AddItem("#gameui_high", NULL);
+
+ m_pColorCorrection = new ComboBox( this, "ColorCorrection", 2, false );
+ m_pColorCorrection->AddItem("#gameui_disabled", NULL);
+ m_pColorCorrection->AddItem("#gameui_enabled", NULL);
+
+ m_pMotionBlur = new ComboBox( this, "MotionBlur", 2, false );
+ m_pMotionBlur->AddItem("#gameui_disabled", NULL);
+ m_pMotionBlur->AddItem("#gameui_enabled", NULL);
+
+ LoadControlSettings( "resource/OptionsSubVideoAdvancedDlg.res" );
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+
+ m_pDXLevel->SetEnabled(false);
+
+ m_pColorCorrection->SetEnabled( mat_dxlevel.GetInt() >= 90 );
+ m_pMotionBlur->SetEnabled( mat_dxlevel.GetInt() >= 90 );
+
+ if ( g_pCVar->FindVar( "fov_desired" ) == NULL )
+ {
+ Panel *pFOV = FindChildByName( "FovSlider" );
+ if ( pFOV )
+ {
+ pFOV->SetVisible( false );
+ }
+
+ pFOV = FindChildByName( "FovLabel" );
+ if ( pFOV )
+ {
+ pFOV->SetVisible( false );
+ }
+ }
+
+ MarkDefaultSettingsAsRecommended();
+
+ m_bUseChanges = false;
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+
+ input()->SetAppModalSurface(GetVPanel());
+
+ if (!m_bUseChanges)
+ {
+ // reset the data
+ OnResetData();
+ }
+ }
+
+ void SetComboItemAsRecommended( vgui::ComboBox *combo, int iItem )
+ {
+ // get the item text
+ wchar_t text[512];
+ combo->GetItemText(iItem, text, sizeof(text));
+
+ // append the recommended flag
+ wchar_t newText[512];
+ _snwprintf( newText, sizeof(newText) / sizeof(wchar_t), L"%ls *", text );
+
+ // reset
+ combo->UpdateItem(iItem, newText, NULL);
+ }
+
+ int FindMSAAMode( int nAASamples, int nAAQuality )
+ {
+ // Run through the AA Modes supported by the device
+ for ( int nAAMode = 0; nAAMode < m_nNumAAModes; nAAMode++ )
+ {
+ // If we found the mode that matches what we're looking for, return the index
+ if ( ( m_nAAModes[nAAMode].m_nNumSamples == nAASamples) && ( m_nAAModes[nAAMode].m_nQualityLevel == nAAQuality) )
+ {
+ return nAAMode;
+ }
+ }
+
+ return 0; // Didn't find what we're looking for, so no AA
+ }
+
+ MESSAGE_FUNC_PTR( OnTextChanged, "TextChanged", panel )
+ {
+ if ( panel == m_pDXLevel && RequiresRestart() )
+ {
+ // notify the user that this will require a disconnect
+ QueryBox *box = new QueryBox("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info");
+ box->AddActionSignalTarget( this );
+ box->SetCancelCommand(new KeyValues("ResetDXLevelCombo"));
+ box->DoModal();
+ }
+ }
+
+ MESSAGE_FUNC( OnGameUIHidden, "GameUIHidden" ) // called when the GameUI is hidden
+ {
+ Close();
+ }
+
+ MESSAGE_FUNC( ResetDXLevelCombo, "ResetDXLevelCombo" )
+ {
+ ConVarRef mat_dxlevel( "mat_dxlevel" );
+ for (int i = 0; i < m_pDXLevel->GetItemCount(); i++)
+ {
+ KeyValues *kv = m_pDXLevel->GetItemUserData(i);
+ if ( kv->GetInt("dxlevel") == mat_dxlevel.GetInt( ) )
+ {
+ m_pDXLevel->ActivateItem( i );
+ break;
+ }
+ }
+
+ // Reset HDR too
+ if ( m_pHDR->IsEnabled() )
+ {
+ ConVarRef mat_hdr_level("mat_hdr_level");
+ Assert( mat_hdr_level.IsValid() );
+ m_pHDR->ActivateItem( clamp( mat_hdr_level.GetInt(), 0, 2 ) );
+ }
+ }
+
+ MESSAGE_FUNC( OK_Confirmed, "OK_Confirmed" )
+ {
+ m_bUseChanges = true;
+ Close();
+ }
+
+ void MarkDefaultSettingsAsRecommended()
+ {
+ // Pull in data from dxsupport.cfg database (includes fine-grained per-vendor/per-device config data)
+ KeyValues *pKeyValues = new KeyValues( "config" );
+ materials->GetRecommendedConfigurationInfo( 0, pKeyValues );
+
+ // Read individual values from keyvalues which came from dxsupport.cfg database
+ int nSkipLevels = pKeyValues->GetInt( "ConVar.mat_picmip", 0 );
+ int nAnisotropicLevel = pKeyValues->GetInt( "ConVar.mat_forceaniso", 1 );
+ int nForceTrilinear = pKeyValues->GetInt( "ConVar.mat_trilinear", 0 );
+ int nAASamples = pKeyValues->GetInt( "ConVar.mat_antialias", 0 );
+ int nAAQuality = pKeyValues->GetInt( "ConVar.mat_aaquality", 0 );
+ int nRenderToTextureShadows = pKeyValues->GetInt( "ConVar.r_shadowrendertotexture", 0 );
+ int nShadowDepthTextureShadows = pKeyValues->GetInt( "ConVar.r_flashlightdepthtexture", 0 );
+#ifndef _X360
+ int nWaterUseRealtimeReflection = pKeyValues->GetInt( "ConVar.r_waterforceexpensive", 0 );
+#endif
+ int nWaterUseEntityReflection = pKeyValues->GetInt( "ConVar.r_waterforcereflectentities", 0 );
+ int nMatVSync = pKeyValues->GetInt( "ConVar.mat_vsync", 1 );
+ int nRootLOD = pKeyValues->GetInt( "ConVar.r_rootlod", 0 );
+ int nReduceFillRate = pKeyValues->GetInt( "ConVar.mat_reducefillrate", 0 );
+ int nDXLevel = pKeyValues->GetInt( "ConVar.mat_dxlevel", 0 );
+ int nColorCorrection = pKeyValues->GetInt( "ConVar.mat_colorcorrection", 0 );
+ int nMotionBlur = pKeyValues->GetInt( "ConVar.mat_motion_blur_enabled", 0 );
+ // It doesn't make sense to retrieve this convar from dxsupport, because we'll then have materialsystem setting this config at loadtime. (Also, it only has very minimal support for CPU related configuration.)
+ //int nMulticore = pKeyValues->GetInt( "ConVar.mat_queue_mode", 0 );
+ int nMulticore = GetCPUInformation()->m_nPhysicalProcessors >= 2;
+
+ // Only recommend a dxlevel if there is more than one available
+ if ( m_pDXLevel->GetItemCount() > 1 )
+ {
+ for (int i = 0; i < m_pDXLevel->GetItemCount(); i++)
+ {
+ KeyValues *kv = m_pDXLevel->GetItemUserData(i);
+ if (kv->GetInt("dxlevel") == pKeyValues->GetInt("ConVar.mat_dxlevel"))
+ {
+ SetComboItemAsRecommended( m_pDXLevel, i );
+ break;
+ }
+ }
+ }
+
+ SetComboItemAsRecommended( m_pModelDetail, 2 - nRootLOD );
+ SetComboItemAsRecommended( m_pTextureDetail, 2 - nSkipLevels );
+
+ switch ( nAnisotropicLevel )
+ {
+ case 2:
+ SetComboItemAsRecommended( m_pFilteringMode, 2 );
+ break;
+ case 4:
+ SetComboItemAsRecommended( m_pFilteringMode, 3 );
+ break;
+ case 8:
+ SetComboItemAsRecommended( m_pFilteringMode, 4 );
+ break;
+ case 16:
+ SetComboItemAsRecommended( m_pFilteringMode, 5 );
+ break;
+ case 0:
+ default:
+ if ( nForceTrilinear != 0 )
+ {
+ SetComboItemAsRecommended( m_pFilteringMode, 1 );
+ }
+ else
+ {
+ SetComboItemAsRecommended( m_pFilteringMode, 0 );
+ }
+ break;
+ }
+
+ // Map desired mode to list item number
+ int nMSAAMode = FindMSAAMode( nAASamples, nAAQuality );
+ SetComboItemAsRecommended( m_pAntialiasingMode, nMSAAMode );
+
+ if ( nShadowDepthTextureShadows )
+ SetComboItemAsRecommended( m_pShadowDetail, 2 ); // Shadow depth mapping (in addition to RTT shadows)
+ else if ( nRenderToTextureShadows )
+ SetComboItemAsRecommended( m_pShadowDetail, 1 ); // RTT shadows
+ else
+ SetComboItemAsRecommended( m_pShadowDetail, 0 ); // Blobbies
+
+ SetComboItemAsRecommended( m_pShaderDetail, nReduceFillRate ? 0 : 1 );
+
+#ifndef _X360
+ if ( nWaterUseRealtimeReflection )
+#endif
+ {
+ if ( nWaterUseEntityReflection )
+ {
+ SetComboItemAsRecommended( m_pWaterDetail, 2 );
+ }
+ else
+ {
+ SetComboItemAsRecommended( m_pWaterDetail, 1 );
+ }
+ }
+#ifndef _X360
+ else
+ {
+ SetComboItemAsRecommended( m_pWaterDetail, 0 );
+ }
+#endif
+
+ SetComboItemAsRecommended( m_pVSync, nMatVSync != 0 );
+
+ SetComboItemAsRecommended( m_pMulticore, nMulticore != 0 );
+
+ SetComboItemAsRecommended( m_pHDR, nDXLevel >= 90 ? 2 : 0 );
+
+ SetComboItemAsRecommended( m_pColorCorrection, nColorCorrection );
+
+ SetComboItemAsRecommended( m_pMotionBlur, nMotionBlur );
+
+ pKeyValues->deleteThis();
+ }
+
+ void ApplyChangesToConVar( const char *pConVarName, int value )
+ {
+ Assert( cvar->FindVar( pConVarName ) );
+ char szCmd[256];
+ Q_snprintf( szCmd, sizeof(szCmd), "%s %d\n", pConVarName, value );
+ engine->ClientCmd_Unrestricted( szCmd );
+ }
+
+ virtual void ApplyChanges()
+ {
+ if ( !m_bUseChanges )
+ return;
+
+ KeyValues *pActiveItem = m_pDXLevel->GetActiveItemUserData();
+ if ( pActiveItem )
+ {
+ ApplyChangesToConVar( "mat_dxlevel", pActiveItem->GetInt( "dxlevel" ) );
+ }
+
+ ApplyChangesToConVar( "r_rootlod", 2 - m_pModelDetail->GetActiveItem());
+ ApplyChangesToConVar( "mat_picmip", 2 - m_pTextureDetail->GetActiveItem());
+
+ // reset everything tied to the filtering mode, then the switch sets the appropriate one
+ ApplyChangesToConVar( "mat_trilinear", false );
+ ApplyChangesToConVar( "mat_forceaniso", 1 );
+ switch ( m_pFilteringMode->GetActiveItem() )
+ {
+ case 0:
+ break;
+ case 1:
+ ApplyChangesToConVar( "mat_trilinear", true );
+ break;
+ case 2:
+ ApplyChangesToConVar( "mat_forceaniso", 2 );
+ break;
+ case 3:
+ ApplyChangesToConVar( "mat_forceaniso", 4 );
+ break;
+ case 4:
+ ApplyChangesToConVar( "mat_forceaniso", 8 );
+ break;
+ case 5:
+ ApplyChangesToConVar( "mat_forceaniso", 16 );
+ break;
+ default:
+ // Trilinear.
+ ApplyChangesToConVar( "mat_forceaniso", 1 );
+ break;
+ }
+
+ // Set the AA convars according to the menu item chosen
+ int nActiveAAItem = m_pAntialiasingMode->GetActiveItem();
+ ApplyChangesToConVar( "mat_antialias", m_nAAModes[nActiveAAItem].m_nNumSamples );
+ ApplyChangesToConVar( "mat_aaquality", m_nAAModes[nActiveAAItem].m_nQualityLevel );
+
+ if( m_pHDR->IsEnabled() )
+ {
+ ConVarRef mat_hdr_level("mat_hdr_level");
+ Assert( mat_hdr_level.IsValid() );
+ mat_hdr_level.SetValue(m_pHDR->GetActiveItem());
+ }
+
+ if ( m_pShadowDetail->GetActiveItem() == 0 ) // Blobby shadows
+ {
+ ApplyChangesToConVar( "r_shadowrendertotexture", 0 ); // Turn off RTT shadows
+ ApplyChangesToConVar( "r_flashlightdepthtexture", 0 ); // Turn off shadow depth textures
+ }
+ else if ( m_pShadowDetail->GetActiveItem() == 1 ) // RTT shadows only
+ {
+ ApplyChangesToConVar( "r_shadowrendertotexture", 1 ); // Turn on RTT shadows
+ ApplyChangesToConVar( "r_flashlightdepthtexture", 0 ); // Turn off shadow depth textures
+ }
+ else if ( m_pShadowDetail->GetActiveItem() == 2 ) // Shadow depth textures
+ {
+ ApplyChangesToConVar( "r_shadowrendertotexture", 1 ); // Turn on RTT shadows
+ ApplyChangesToConVar( "r_flashlightdepthtexture", 1 ); // Turn on shadow depth textures
+ }
+
+ ApplyChangesToConVar( "mat_reducefillrate", ( m_pShaderDetail->GetActiveItem() > 0 ) ? 0 : 1 );
+
+ switch ( m_pWaterDetail->GetActiveItem() )
+ {
+ default:
+ case 0:
+#ifndef _X360
+ ApplyChangesToConVar( "r_waterforceexpensive", false );
+#endif
+ ApplyChangesToConVar( "r_waterforcereflectentities", false );
+ break;
+ case 1:
+#ifndef _X360
+ ApplyChangesToConVar( "r_waterforceexpensive", true );
+#endif
+ ApplyChangesToConVar( "r_waterforcereflectentities", false );
+ break;
+ case 2:
+#ifndef _X360
+ ApplyChangesToConVar( "r_waterforceexpensive", true );
+#endif
+ ApplyChangesToConVar( "r_waterforcereflectentities", true );
+ break;
+ }
+
+ ApplyChangesToConVar( "mat_vsync", m_pVSync->GetActiveItem() );
+
+ int iMC = m_pMulticore->GetActiveItem();
+ ApplyChangesToConVar( "mat_queue_mode", (iMC == 0) ? 0 : -1 );
+
+ ApplyChangesToConVar( "mat_colorcorrection", m_pColorCorrection->GetActiveItem() );
+
+ ApplyChangesToConVar( "mat_motion_blur_enabled", m_pMotionBlur->GetActiveItem() );
+
+ CCvarSlider *pFOV = (CCvarSlider *)FindChildByName( "FOVSlider" );
+ if ( pFOV )
+ {
+ pFOV->ApplyChanges();
+ }
+ }
+
+ virtual void OnResetData()
+ {
+ ConVarRef mat_dxlevel( "mat_dxlevel" );
+ ConVarRef r_rootlod( "r_rootlod" );
+ ConVarRef mat_picmip( "mat_picmip" );
+ ConVarRef mat_trilinear( "mat_trilinear" );
+ ConVarRef mat_forceaniso( "mat_forceaniso" );
+ ConVarRef mat_antialias( "mat_antialias" );
+ ConVarRef mat_aaquality( "mat_aaquality" );
+ ConVarRef mat_vsync( "mat_vsync" );
+ ConVarRef mat_queue_mode( "mat_queue_mode" );
+ ConVarRef r_flashlightdepthtexture( "r_flashlightdepthtexture" );
+#ifndef _X360
+ ConVarRef r_waterforceexpensive( "r_waterforceexpensive" );
+#endif
+ ConVarRef r_waterforcereflectentities( "r_waterforcereflectentities" );
+ ConVarRef mat_reducefillrate("mat_reducefillrate" );
+ ConVarRef mat_hdr_level( "mat_hdr_level" );
+ ConVarRef mat_colorcorrection( "mat_colorcorrection" );
+ ConVarRef mat_motion_blur_enabled( "mat_motion_blur_enabled" );
+ ConVarRef r_shadowrendertotexture( "r_shadowrendertotexture" );
+
+ ResetDXLevelCombo();
+
+ m_pModelDetail->ActivateItem( 2 - clamp(r_rootlod.GetInt(), 0, 2) );
+ m_pTextureDetail->ActivateItem( 2 - clamp(mat_picmip.GetInt(), -1, 2) );
+
+ if ( r_flashlightdepthtexture.GetBool() ) // If we're doing flashlight shadow depth texturing...
+ {
+ r_shadowrendertotexture.SetValue( 1 ); // ...be sure render to texture shadows are also on
+ m_pShadowDetail->ActivateItem( 2 );
+ }
+ else if ( r_shadowrendertotexture.GetBool() ) // RTT shadows, but not shadow depth texturing
+ {
+ m_pShadowDetail->ActivateItem( 1 );
+ }
+ else // Lowest shadow quality
+ {
+ m_pShadowDetail->ActivateItem( 0 );
+ }
+
+ m_pShaderDetail->ActivateItem( mat_reducefillrate.GetBool() ? 0 : 1 );
+ m_pHDR->ActivateItem(clamp(mat_hdr_level.GetInt(), 0, 2));
+
+ switch (mat_forceaniso.GetInt())
+ {
+ case 2:
+ m_pFilteringMode->ActivateItem( 2 );
+ break;
+ case 4:
+ m_pFilteringMode->ActivateItem( 3 );
+ break;
+ case 8:
+ m_pFilteringMode->ActivateItem( 4 );
+ break;
+ case 16:
+ m_pFilteringMode->ActivateItem( 5 );
+ break;
+ case 0:
+ default:
+ if (mat_trilinear.GetBool())
+ {
+ m_pFilteringMode->ActivateItem( 1 );
+ }
+ else
+ {
+ m_pFilteringMode->ActivateItem( 0 );
+ }
+ break;
+ }
+
+ // Map convar to item on AA drop-down
+ int nAASamples = mat_antialias.GetInt();
+ int nAAQuality = mat_aaquality.GetInt();
+ int nMSAAMode = FindMSAAMode( nAASamples, nAAQuality );
+ m_pAntialiasingMode->ActivateItem( nMSAAMode );
+
+ m_pAntialiasingMode->SetEnabled( m_nNumAAModes > 1 );
+
+#ifndef _X360
+ if ( r_waterforceexpensive.GetBool() )
+#endif
+ {
+ if ( r_waterforcereflectentities.GetBool() )
+ {
+ m_pWaterDetail->ActivateItem( 2 );
+ }
+ else
+ {
+ m_pWaterDetail->ActivateItem( 1 );
+ }
+ }
+#ifndef _X360
+ else
+ {
+ m_pWaterDetail->ActivateItem( 0 );
+ }
+#endif
+
+ m_pVSync->ActivateItem( mat_vsync.GetInt() );
+
+ int iMC = mat_queue_mode.GetInt();
+
+ // We (Rick!) have now switched -2 to mean enabled. So this comment has been rendered obsolete:
+ // -- For testing, we have -2, the legacy default setting as meaning multicore is disabled.
+ // -- After that, we'll switch -2 to mean it's enabled.
+ m_pMulticore->ActivateItem( (iMC == 0) ? 0 : 1 );
+
+ m_pColorCorrection->ActivateItem( mat_colorcorrection.GetInt() );
+
+ m_pMotionBlur->ActivateItem( mat_motion_blur_enabled.GetInt() );
+
+ // get current hardware dx support level
+ char dxVer[64];
+ GetNameForDXLevel( mat_dxlevel.GetInt(), dxVer, sizeof( dxVer ) );
+ SetControlString("dxlabel", dxVer);
+
+ // get installed version
+ char szVersion[64];
+ szVersion[0] = 0;
+ system()->GetRegistryString( "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\DirectX\\Version", szVersion, sizeof(szVersion) );
+ int os = 0, majorVersion = 0, minorVersion = 0, subVersion = 0;
+ sscanf(szVersion, "%d.%d.%d.%d", &os, &majorVersion, &minorVersion, &subVersion);
+ Q_snprintf(dxVer, sizeof(dxVer), "DirectX v%d.%d", majorVersion, minorVersion);
+ SetControlString("dxinstalledlabel", dxVer);
+ }
+
+ virtual void OnCommand( const char *command )
+ {
+ if ( !stricmp(command, "OK") )
+ {
+ if ( RequiresRestart() )
+ {
+ // Bring up the confirmation dialog
+ QueryBox *box = new QueryBox("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info");
+ box->AddActionSignalTarget( this );
+ box->SetOKCommand(new KeyValues("OK_Confirmed"));
+ box->SetCancelCommand(new KeyValues("ResetDXLevelCombo"));
+ box->DoModal();
+ box->MoveToFront();
+ return;
+ }
+
+ m_bUseChanges = true;
+ Close();
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+
+ bool RequiresRestart()
+ {
+ if ( GameUI().IsInLevel() )
+ {
+ if ( GameUI().IsInBackgroundLevel() )
+ return false;
+ if ( !GameUI().IsInMultiplayer() )
+ return false;
+
+ ConVarRef mat_dxlevel( "mat_dxlevel" );
+ KeyValues *pUserData = m_pDXLevel->GetActiveItemUserData();
+ Assert( pUserData );
+ if ( pUserData && mat_dxlevel.GetInt() != pUserData->GetInt("dxlevel") )
+ {
+ return true;
+ }
+
+ // HDR changed?
+ if ( m_pHDR->IsEnabled() )
+ {
+ ConVarRef mat_hdr_level("mat_hdr_level");
+ Assert( mat_hdr_level.IsValid() );
+ if ( mat_hdr_level.GetInt() != m_pHDR->GetActiveItem() )
+ return true;
+ }
+ }
+ return false;
+ }
+
+private:
+ bool m_bUseChanges;
+ vgui::ComboBox *m_pModelDetail, *m_pTextureDetail, *m_pAntialiasingMode, *m_pFilteringMode;
+ vgui::ComboBox *m_pShadowDetail, *m_pHDR, *m_pWaterDetail, *m_pVSync, *m_pMulticore, *m_pShaderDetail;
+ vgui::ComboBox *m_pColorCorrection;
+ vgui::ComboBox *m_pMotionBlur;
+ vgui::ComboBox *m_pDXLevel;
+
+ int m_nNumAAModes;
+ AAMode_t m_nAAModes[16];
+};
+
+#if defined( USE_SDL )
+
+//-----------------------------------------------------------------------------
+// Purpose: Get display index we will go fullscreen on.
+//-----------------------------------------------------------------------------
+static int getSDLDisplayIndex()
+{
+ static ConVarRef sdl_displayindex( "sdl_displayindex" );
+
+ Assert( sdl_displayindex.IsValid() );
+ return sdl_displayindex.IsValid() ? sdl_displayindex.GetInt() : 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get display index we are currently fullscreen on. (or -1 if none).
+//-----------------------------------------------------------------------------
+static int getSDLDisplayIndexFullscreen()
+{
+ static ConVarRef sdl_displayindex_fullscreen( "sdl_displayindex_fullscreen" );
+
+ Assert( sdl_displayindex_fullscreen.IsValid() );
+ return sdl_displayindex_fullscreen.IsValid() ? sdl_displayindex_fullscreen.GetInt() : -1;
+}
+
+#endif // USE_SDL
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubVideo::COptionsSubVideo(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+ m_bRequireRestart = false;
+
+ m_bDisplayedVRModeMessage = false;
+
+ m_pGammaButton = new Button( this, "GammaButton", "#GameUI_AdjustGamma" );
+ m_pGammaButton->SetCommand(new KeyValues("OpenGammaDialog"));
+ m_pMode = new ComboBox(this, "Resolution", 8, false);
+ m_pAspectRatio = new ComboBox( this, "AspectRatio", 6, false );
+ m_pVRMode = new ComboBox( this, "VRMode", 2, false );
+ m_pAdvanced = new Button( this, "AdvancedButton", "#GameUI_AdvancedEllipsis" );
+ m_pAdvanced->SetCommand(new KeyValues("OpenAdvanced"));
+ m_pBenchmark = new Button( this, "BenchmarkButton", "#GameUI_LaunchBenchmark" );
+ m_pBenchmark->SetCommand(new KeyValues("LaunchBenchmark"));
+ m_pThirdPartyCredits = new URLButton(this, "ThirdPartyVideoCredits", "#GameUI_ThirdPartyTechCredits");
+ m_pThirdPartyCredits->SetCommand(new KeyValues("OpenThirdPartyVideoCreditsDialog"));
+ m_pHDContent = new CheckButton( this, "HDContentButton", "#GameUI_HDContent" );
+
+ char pszAspectName[3][64];
+ const wchar_t *unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectNormal");
+ g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[0], 32);
+ unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectWide16x9");
+ g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[1], 32);
+ unicodeText = g_pVGuiLocalize->Find("#GameUI_AspectWide16x10");
+ g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszAspectName[2], 32);
+
+ int iNormalItemID = m_pAspectRatio->AddItem( pszAspectName[0], NULL );
+ int i16x9ItemID = m_pAspectRatio->AddItem( pszAspectName[1], NULL );
+ int i16x10ItemID = m_pAspectRatio->AddItem( pszAspectName[2], NULL );
+
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ int iAspectMode = GetScreenAspectMode( config.m_VideoMode.m_Width, config.m_VideoMode.m_Height );
+ switch ( iAspectMode )
+ {
+ default:
+ case 0:
+ m_pAspectRatio->ActivateItem( iNormalItemID );
+ break;
+ case 1:
+ m_pAspectRatio->ActivateItem( i16x9ItemID );
+ break;
+ case 2:
+ m_pAspectRatio->ActivateItem( i16x10ItemID );
+ break;
+ }
+
+ char pszVRModeName[2][64];
+ unicodeText = g_pVGuiLocalize->Find("#GameUI_Disabled");
+ g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszVRModeName[0], 32);
+ unicodeText = g_pVGuiLocalize->Find("#GameUI_Enabled");
+ g_pVGuiLocalize->ConvertUnicodeToANSI(unicodeText, pszVRModeName[1], 32);
+
+ m_pVRMode->AddItem( pszVRModeName[0], NULL );
+ m_pVRMode->AddItem( pszVRModeName[1], NULL );
+
+ // Multimonitor under Direct3D requires you to destroy and recreate the device,
+ // which is an operation we don't support as it currently stands. The user can
+ // pass -adapter N to use a different device.
+#if defined( USE_SDL ) && defined( DX_TO_GL_ABSTRACTION )
+ int numVideoDisplays = SDL_GetNumVideoDisplays();
+
+ m_pWindowed = new vgui::ComboBox( this, "DisplayModeCombo", 5 + numVideoDisplays, false );
+
+ if ( numVideoDisplays <= 1 )
+ {
+ m_pWindowed->AddItem( "#GameUI_Fullscreen", NULL );
+ m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
+ }
+ else
+ {
+ // Add something like this:
+ // Full Screen (0)
+ // Full Screen (1)
+ // Windowed
+ wchar_t *fullscreenText = g_pVGuiLocalize->Find( "#GameUI_Fullscreen" );
+
+ for ( int i = 0; i < numVideoDisplays; i++ )
+ {
+ wchar_t ItemText[ 256 ];
+
+ V_swprintf_safe( ItemText, L"%ls (%d)", fullscreenText, i );
+ m_pWindowed->AddItem( ItemText, NULL );
+ }
+
+ m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
+ }
+
+#else
+ m_pWindowed = new vgui::ComboBox( this, "DisplayModeCombo", 6, false );
+
+ m_pWindowed->AddItem( "#GameUI_Fullscreen", NULL );
+ m_pWindowed->AddItem( "#GameUI_Windowed", NULL );
+#endif
+
+ LoadControlSettings("Resource\\OptionsSubVideo.res");
+
+ // Moved down here so we can set the Drop down's
+ // menu state after the default (disabled) value is loaded
+ PrepareResolutionList();
+
+ // only show the benchmark button if they have the benchmark map
+ if ( !g_pFullFileSystem->FileExists("maps/test_hardware.bsp") )
+ {
+ m_pBenchmark->SetVisible( false );
+ }
+
+ if ( ModInfo().HasHDContent() )
+ {
+ m_pHDContent->SetVisible( true );
+ }
+
+ // if VR mode isn't available, disable the dropdown
+ if( !g_pSourceVR )
+ {
+ // if sourcevr.dll is missing entirely that means VR mode is not
+ // supported in this game. Hide the mode dropdown and its label
+ m_pVRMode->SetVisible( false );
+
+ Panel *label = FindChildByName( "VRModeLabel" );
+ if( label )
+ label->SetVisible( false );
+ }
+ else if( !g_pSourceVR->IsHmdConnected() )
+ {
+ m_pVRMode->ActivateItem( 0 );
+ m_pVRMode->SetEnabled( false );
+ m_pVRMode->GetTooltip()->SetText( "#GameUI_NoVRTooltip" );
+ EnableOrDisableWindowedForVR();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Generates resolution list
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::PrepareResolutionList()
+{
+ // get the currently selected resolution
+ char sz[256];
+ m_pMode->GetText(sz, 256);
+ int currentWidth = 0, currentHeight = 0;
+ sscanf( sz, "%i x %i", &currentWidth, &currentHeight );
+
+ // Clean up before filling the info again.
+ m_pMode->DeleteAllItems();
+ m_pAspectRatio->SetItemEnabled(1, false);
+ m_pAspectRatio->SetItemEnabled(2, false);
+
+ // get full video mode list
+ vmode_t *plist = NULL;
+ int count = 0;
+ gameuifuncs->GetVideoModes( &plist, &count );
+
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ // Windowed is the last item in the combobox.
+ bool bWindowed = ( m_pWindowed->GetActiveItem() >= ( m_pWindowed->GetItemCount() - 1 ) );
+ int desktopWidth, desktopHeight;
+ gameuifuncs->GetDesktopResolution( desktopWidth, desktopHeight );
+
+#if defined( USE_SDL )
+ bool bFullScreenWithMultipleDisplays = ( !bWindowed && ( SDL_GetNumVideoDisplays() > 1 ) );
+ if ( bFullScreenWithMultipleDisplays )
+ {
+ SDL_Rect rect;
+#if defined( DX_TO_GL_ABSTRACTION )
+ int displayIndex = m_pWindowed->GetActiveItem();
+#else
+ int displayIndex = materials->GetCurrentAdapter();
+#endif
+
+ if ( !SDL_GetDisplayBounds( displayIndex, &rect ) )
+ {
+ desktopWidth = rect.w;
+ desktopHeight = rect.h;
+ }
+ }
+
+ // If we are switching to fullscreen, and this isn't the mode we're currently in, then
+ // fake things out so the native fullscreen resolution is selected. Stuck this in
+ // because I assume most people will go fullscreen at native resolution, and it's sometimes
+ // difficult to find the native resolution with all the aspect ratio options.
+ bool bNewFullscreenDisplay = ( !bWindowed && ( getSDLDisplayIndexFullscreen() != m_pWindowed->GetActiveItem() ) );
+ if ( bNewFullscreenDisplay )
+ {
+ currentWidth = desktopWidth;
+ currentHeight = desktopHeight;
+ }
+#endif
+
+ // iterate all the video modes adding them to the dropdown
+ bool bFoundWidescreen = false;
+ int selectedItemID = -1;
+ for (int i = 0; i < count; i++, plist++)
+ {
+#if !defined( USE_SDL )
+ // don't show modes bigger than the desktop for windowed mode
+ if ( bWindowed )
+#endif
+ {
+ if ( plist->width > desktopWidth || plist->height > desktopHeight )
+ {
+ // Filter out sizes larger than our desktop.
+ continue;
+ }
+ }
+
+ GetResolutionName( plist, sz, sizeof( sz ), desktopWidth, desktopHeight );
+
+ int itemID = -1;
+ int iAspectMode = GetScreenAspectMode( plist->width, plist->height );
+ if ( iAspectMode > 0 )
+ {
+ m_pAspectRatio->SetItemEnabled( iAspectMode, true );
+ bFoundWidescreen = true;
+ }
+
+ // filter the list for those matching the current aspect
+ if ( iAspectMode == m_pAspectRatio->GetActiveItem() )
+ {
+ itemID = m_pMode->AddItem( sz, NULL);
+ }
+
+ // try and find the best match for the resolution to be selected
+ if ( plist->width == currentWidth && plist->height == currentHeight )
+ {
+ selectedItemID = itemID;
+ }
+ else if ( selectedItemID == -1 && plist->width == config.m_VideoMode.m_Width && plist->height == config.m_VideoMode.m_Height )
+ {
+ selectedItemID = itemID;
+ }
+ }
+
+ // disable ratio selection if we can't display widescreen.
+ m_pAspectRatio->SetEnabled( bFoundWidescreen );
+
+ m_nSelectedMode = selectedItemID;
+
+ if ( selectedItemID != -1 )
+ {
+ m_pMode->ActivateItem( selectedItemID );
+ }
+ else
+ {
+ int Width = config.m_VideoMode.m_Width;
+ int Height = config.m_VideoMode.m_Height;
+
+#if defined( USE_SDL )
+ // If we are switching to a new display, or the size is greater than the desktop, then
+ // display the desktop width and height.
+ if ( bNewFullscreenDisplay || ( Width > desktopWidth ) || ( Height > desktopHeight ) )
+ {
+ Width = desktopWidth;
+ Height = desktopHeight;
+ }
+#endif
+
+ Q_snprintf( sz, ARRAYSIZE( sz ), "%d x %d", Width, Height );
+ m_pMode->SetText( sz );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubVideo::~COptionsSubVideo()
+{
+ if (m_hOptionsSubVideoAdvancedDlg.Get())
+ {
+ m_hOptionsSubVideoAdvancedDlg->MarkForDeletion();
+ }
+}
+
+
+FILE *FOpenGameHDFile( const char *pchMode )
+{
+ const char *pGameDir = engine->GetGameDirectory();
+ char szModSteamInfPath[ 1024 ];
+ V_ComposeFileName( pGameDir, "game_hd.txt", szModSteamInfPath, sizeof( szModSteamInfPath ) );
+
+ FILE *fp = fopen( szModSteamInfPath, pchMode );
+ return fp;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool COptionsSubVideo::BUseHDContent()
+{
+ FILE *fp = FOpenGameHDFile( "rb" );
+ if ( fp )
+ {
+ fclose(fp);
+ return true;
+ }
+ return false;
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: hint the engine to load HD content if possible, logic must match with engine/common.cpp BLoadHDContent
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::SetUseHDContent( bool bUse )
+{
+ if ( bUse )
+ {
+ FILE *fp = FOpenGameHDFile( "wb+" );
+ if ( fp )
+ {
+ fprintf( fp, "If this file exists on disk HD content will be loaded.\n" );
+ fclose( fp );
+ }
+ }
+ else
+ {
+ const char *pGameDir = engine->GetGameDirectory();
+ char szModSteamInfPath[ 1024 ];
+ V_ComposeFileName( pGameDir, "game_hd.txt", szModSteamInfPath, sizeof( szModSteamInfPath ) );
+ _unlink( szModSteamInfPath );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OnResetData()
+{
+ m_bRequireRestart = false;
+
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ // reset UI elements
+#if defined( USE_SDL ) && defined( DX_TO_GL_ABSTRACTION )
+ int ItemIndex;
+
+ if ( config.Windowed() )
+ {
+ // Last item in the combobox is Windowed.
+ ItemIndex = ( m_pWindowed->GetItemCount() - 1 );
+ }
+ else
+ {
+ // Check which fullscreen displayindex is currently selected, and pick it.
+ ItemIndex = getSDLDisplayIndex();
+
+ if ( ( ItemIndex < 0 ) || ItemIndex >= ( m_pWindowed->GetItemCount() - 1 ) )
+ {
+ Assert( 0 );
+ ItemIndex = 0;
+ }
+ }
+
+ m_pWindowed->ActivateItem( ItemIndex );
+#else
+ m_pWindowed->ActivateItem( config.Windowed() ? 1 : 0 );
+#endif
+
+ // reset gamma control
+ m_pGammaButton->SetEnabled( !config.Windowed() );
+
+ m_pHDContent->SetSelected( BUseHDContent() );
+
+ SetCurrentResolutionComboItem();
+
+ bool bVREnabled = config.m_nVRModeAdapter != -1;
+ m_pVRMode->ActivateItem( bVREnabled ? 1 : 0 );
+ EnableOrDisableWindowedForVR();
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::SetCurrentResolutionComboItem()
+{
+ vmode_t *plist = NULL;
+ int count = 0;
+ gameuifuncs->GetVideoModes( &plist, &count );
+
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ int resolution = -1;
+ for ( int i = 0; i < count; i++, plist++ )
+ {
+ if ( plist->width == config.m_VideoMode.m_Width &&
+ plist->height == config.m_VideoMode.m_Height )
+ {
+ resolution = i;
+ break;
+ }
+ }
+
+ if (resolution != -1)
+ {
+ char sz[256];
+ int desktopWidth, desktopHeight;
+
+ gameuifuncs->GetDesktopResolution( desktopWidth, desktopHeight );
+
+#if defined( USE_SDL )
+ SDL_Rect rect;
+#if defined( DX_TO_GL_ABSTRACTION )
+ int displayIndex = getSDLDisplayIndex();
+#else
+ int displayIndex = materials->GetCurrentAdapter();
+#endif
+
+ if ( !SDL_GetDisplayBounds( displayIndex, &rect ) )
+ {
+ desktopWidth = rect.w;
+ desktopHeight = rect.h;
+ }
+#endif
+
+ GetResolutionName( plist, sz, sizeof(sz), desktopWidth, desktopHeight );
+ m_pMode->SetText(sz);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: restarts the game
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OnApplyChanges()
+{
+ if ( RequiresRestart() )
+ {
+ INetChannelInfo *nci = engine->GetNetChannelInfo();
+ if ( nci )
+ {
+ // Only retry if we're not running the server
+ const char *pAddr = nci->GetAddress();
+ if ( pAddr )
+ {
+ if ( Q_strncmp(pAddr,"127.0.0.1",9) && Q_strncmp(pAddr,"localhost",9) )
+ {
+ engine->ClientCmd_Unrestricted( "retry\n" );
+ }
+ else
+ {
+ engine->ClientCmd_Unrestricted( "disconnect\n" );
+ }
+ }
+ }
+ }
+
+ // apply advanced options
+ if (m_hOptionsSubVideoAdvancedDlg.Get())
+ {
+ m_hOptionsSubVideoAdvancedDlg->ApplyChanges();
+ }
+
+ // resolution
+ char sz[256];
+ if ( m_nSelectedMode == -1 )
+ {
+ m_pMode->GetText( sz, 256 );
+ }
+ else
+ {
+ m_pMode->GetItemText( m_nSelectedMode, sz, 256 );
+ }
+
+ int width = 0, height = 0;
+ sscanf( sz, "%i x %i", &width, &height );
+
+ // windowed
+ bool bConfigChanged = false;
+ bool windowed = ( m_pWindowed->GetActiveItem() == ( m_pWindowed->GetItemCount() - 1 ) ) ? true : false;
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ bool bVRMode = m_pVRMode->GetActiveItem() != 0;
+ if( ( -1 != config.m_nVRModeAdapter ) != bVRMode )
+ {
+ // let engine fill in mat_vrmode_adapter
+ char szCmd[256];
+ Q_snprintf( szCmd, sizeof(szCmd), "mat_enable_vrmode %d\n", bVRMode ? 1 : 0 );
+ engine->ClientCmd_Unrestricted( szCmd );
+
+ // force windowed. VR mode ignores this flag and desktop mode needs to be in a window always
+ windowed = bVRMode;
+ }
+
+
+ // make sure there is a change
+ if ( config.m_VideoMode.m_Width != width
+ || config.m_VideoMode.m_Height != height
+ || config.Windowed() != windowed )
+ {
+ bConfigChanged = true;
+ }
+
+#if defined( USE_SDL )
+ if ( !windowed )
+ {
+ SDL_Rect rect;
+ int displayIndexTarget = m_pWindowed->GetActiveItem();
+ int displayIndexCurrent = getSDLDisplayIndexFullscreen();
+
+ // Handle going fullscreen from display X to display Y.
+ if ( displayIndexCurrent != displayIndexTarget )
+ {
+ static ConVarRef sdl_displayindex( "sdl_displayindex" );
+
+ if ( sdl_displayindex.IsValid() )
+ {
+ // Set the displayindex we want to go fullscreen on now.
+ sdl_displayindex.SetValue( displayIndexTarget );
+ bConfigChanged = true;
+ }
+ }
+
+ if ( !SDL_GetDisplayBounds( displayIndexTarget, &rect ) )
+ {
+ // If we are going non-native fullscreen, tweak the resolution to have the same aspect ratio as the display.
+ if ( ( width != rect.w ) || ( height != rect.h ) )
+ {
+ // TODO: We may want a convar to allow folks to mess with their aspect ratio?
+ height = ( width * rect.h ) / rect.w;
+ bConfigChanged = true;
+ }
+ }
+ }
+#endif // USE_SDL
+
+ if ( bConfigChanged )
+ {
+ // set mode
+ char szCmd[ 256 ];
+ Q_snprintf( szCmd, sizeof( szCmd ), "mat_setvideomode %i %i %i\n", width, height, windowed ? 1 : 0 );
+ engine->ClientCmd_Unrestricted( szCmd );
+ }
+
+ if ( ModInfo().HasHDContent() )
+ {
+ if ( BUseHDContent() != m_pHDContent->IsSelected() )
+ {
+ SetUseHDContent( m_pHDContent->IsSelected() );
+ // Bring up the confirmation dialog
+ MessageBox *box = new MessageBox("#GameUI_OptionsRestartRequired_Title", "#GameUI_HDRestartRequired_Info");
+ box->DoModal();
+ box->MoveToFront();
+ }
+ }
+
+ // apply changes
+ engine->ClientCmd_Unrestricted( "mat_savechanges\n" );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( m_pGammaButton )
+ {
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+ m_pGammaButton->SetEnabled( !config.Windowed() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: enables apply button on data changing
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OnTextChanged(Panel *pPanel, const char *pszText)
+{
+ if (pPanel == m_pMode)
+ {
+ const MaterialSystem_Config_t &config = materials->GetCurrentConfigForVideoCard();
+
+ m_nSelectedMode = m_pMode->GetActiveItem();
+
+ int w = 0, h = 0;
+ sscanf(pszText, "%i x %i", &w, &h);
+ if ( config.m_VideoMode.m_Width != w || config.m_VideoMode.m_Height != h )
+ {
+ OnDataChanged();
+ }
+ }
+ else if (pPanel == m_pAspectRatio)
+ {
+ PrepareResolutionList();
+ }
+ else if (pPanel == m_pWindowed)
+ {
+ PrepareResolutionList();
+ OnDataChanged();
+ }
+ else if ( pPanel == m_pVRMode )
+ {
+ if ( !m_bDisplayedVRModeMessage )
+ {
+ bool bVRNowEnabled = m_pVRMode->GetActiveItem() == 1;
+ bool bVRWasEnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter != -1;
+ if( bVRWasEnabled != bVRNowEnabled )
+ {
+ m_bDisplayedVRModeMessage = true;
+ MessageBox *box = new MessageBox( "#GameUI_VRMode", "#GameUI_VRModeRelaunchMsg", this );
+ box->MoveToFront();
+ box->DoModal();
+ }
+ }
+
+ EnableOrDisableWindowedForVR();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: enables windowed combo box
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::EnableOrDisableWindowedForVR()
+{
+ bool bCanBeEnabled = g_pSourceVR && g_pSourceVR->IsHmdConnected();
+ bool bVRNowEnabled = m_pVRMode->GetActiveItem() == 1;
+ bool bVRWasEnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter != -1;
+ if( bCanBeEnabled && ( bVRNowEnabled || bVRWasEnabled ) )
+ {
+ m_pWindowed->SetEnabled( false );
+ m_pWindowed->ActivateItem( m_pWindowed->GetItemCount() - 1 );
+ m_pWindowed->GetTooltip()->SetText( "#GameUI_WindowedTooltip" );
+ }
+ else
+ {
+ m_pWindowed->SetEnabled( true );
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: enables apply button
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OnDataChanged()
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks to see if the changes requires a restart to take effect
+//-----------------------------------------------------------------------------
+bool COptionsSubVideo::RequiresRestart()
+{
+ if ( m_hOptionsSubVideoAdvancedDlg.Get()
+ && m_hOptionsSubVideoAdvancedDlg->RequiresRestart() )
+ {
+ return true;
+ }
+
+ // make sure there is a change
+ return m_bRequireRestart;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens advanced video mode options dialog
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OpenAdvanced()
+{
+ if ( !m_hOptionsSubVideoAdvancedDlg.Get() )
+ {
+ m_hOptionsSubVideoAdvancedDlg = new COptionsSubVideoAdvancedDlg( BasePanel()->FindChildByName( "OptionsDialog" ) ); // we'll parent this to the OptionsDialog directly
+ }
+
+ m_hOptionsSubVideoAdvancedDlg->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens gamma-adjusting dialog
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OpenGammaDialog()
+{
+ if ( !m_hGammaDialog.Get() )
+ {
+ m_hGammaDialog = new CGammaDialog( GetVParent() );
+ }
+
+ m_hGammaDialog->Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens benchmark dialog
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::LaunchBenchmark()
+{
+ BasePanel()->OnOpenBenchmarkDialog();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: third-party audio credits dialog
+//-----------------------------------------------------------------------------
+class COptionsSubVideoThirdPartyCreditsDlg : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubVideoThirdPartyCreditsDlg, vgui::Frame );
+public:
+ COptionsSubVideoThirdPartyCreditsDlg( vgui::VPANEL hParent ) : BaseClass( NULL, NULL )
+ {
+ // parent is ignored, since we want look like we're steal focus from the parent (we'll become modal below)
+
+ SetTitle("#GameUI_ThirdPartyVideo_Title", true);
+ SetSize( 500, 200 );
+ LoadControlSettings( "resource/OptionsSubVideoThirdPartyDlg.res" );
+ MoveToCenterOfScreen();
+ SetSizeable( false );
+ SetDeleteSelfOnClose( true );
+ }
+
+ virtual void Activate()
+ {
+ BaseClass::Activate();
+
+ input()->SetAppModalSurface(GetVPanel());
+ }
+
+ void OnKeyCodeTyped(KeyCode code)
+ {
+ // force ourselves to be closed if the escape key it pressed
+ if (code == KEY_ESCAPE)
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Open third party audio credits dialog
+//-----------------------------------------------------------------------------
+void COptionsSubVideo::OpenThirdPartyVideoCreditsDialog()
+{
+ if (!m_OptionsSubVideoThirdPartyCreditsDlg.Get())
+ {
+ m_OptionsSubVideoThirdPartyCreditsDlg = new COptionsSubVideoThirdPartyCreditsDlg(GetVParent());
+ }
+ m_OptionsSubVideoThirdPartyCreditsDlg->Activate();
+}
diff --git a/gameui/OptionsSubVideo.h b/gameui/OptionsSubVideo.h
new file mode 100644
index 0000000..e832d27
--- /dev/null
+++ b/gameui/OptionsSubVideo.h
@@ -0,0 +1,80 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_VIDEO_H
+#define OPTIONS_SUB_VIDEO_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Panel.h>
+#include <vgui_controls/ComboBox.h>
+#include <vgui_controls/PropertyPage.h>
+#include "EngineInterface.h"
+#include "IGameUIFuncs.h"
+#include "URLButton.h"
+
+class CCvarSlider;
+
+//-----------------------------------------------------------------------------
+// Purpose: Video Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubVideo : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubVideo, vgui::PropertyPage );
+
+public:
+ COptionsSubVideo(vgui::Panel *parent);
+ ~COptionsSubVideo();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+ virtual void PerformLayout();
+
+ virtual bool RequiresRestart();
+
+private:
+ void SetCurrentResolutionComboItem();
+ void EnableOrDisableWindowedForVR();
+
+ MESSAGE_FUNC( OnDataChanged, "ControlModified" );
+ MESSAGE_FUNC_PTR_CHARPTR( OnTextChanged, "TextChanged", panel, text );
+ MESSAGE_FUNC( OpenAdvanced, "OpenAdvanced" );
+ MESSAGE_FUNC( LaunchBenchmark, "LaunchBenchmark" );
+ MESSAGE_FUNC( OpenGammaDialog, "OpenGammaDialog" );
+
+
+ void PrepareResolutionList();
+
+ bool BUseHDContent();
+ void SetUseHDContent( bool bUse );
+
+ int m_nSelectedMode; // -1 if we are running in a nonstandard mode
+
+ bool m_bDisplayedVRModeMessage;
+
+ vgui::ComboBox *m_pMode;
+ vgui::ComboBox *m_pWindowed;
+ vgui::ComboBox *m_pAspectRatio;
+ vgui::ComboBox *m_pVRMode;
+ vgui::Button *m_pGammaButton;
+ vgui::Button *m_pAdvanced;
+ vgui::Button *m_pBenchmark;
+ vgui::CheckButton *m_pHDContent;
+
+ vgui::DHANDLE<class COptionsSubVideoAdvancedDlg> m_hOptionsSubVideoAdvancedDlg;
+ vgui::DHANDLE<class CGammaDialog> m_hGammaDialog;
+
+ bool m_bRequireRestart;
+ MESSAGE_FUNC( OpenThirdPartyVideoCreditsDialog, "OpenThirdPartyVideoCreditsDialog" );
+ vgui::URLButton *m_pThirdPartyCredits;
+ vgui::DHANDLE<class COptionsSubVideoThirdPartyCreditsDlg> m_OptionsSubVideoThirdPartyCreditsDlg;
+};
+
+
+
+#endif // OPTIONS_SUB_VIDEO_H \ No newline at end of file
diff --git a/gameui/OptionsSubVoice.cpp b/gameui/OptionsSubVoice.cpp
new file mode 100644
index 0000000..6e08c0a
--- /dev/null
+++ b/gameui/OptionsSubVoice.cpp
@@ -0,0 +1,334 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "OptionsSubVoice.h"
+#include "cvarslider.h"
+#include <vgui/IVGui.h>
+#include <vgui_controls/ImagePanel.h>
+#include <vgui_controls/CheckButton.h>
+#include <vgui_controls/Slider.h>
+#include "EngineInterface.h"
+#include "ivoicetweak.h"
+#include "CvarToggleCheckButton.h"
+#include "tier1/KeyValues.h"
+#include "tier1/convar.h"
+#include <steam/steam_api.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubVoice::COptionsSubVoice(vgui::Panel *parent) : PropertyPage(parent, NULL)
+{
+#if !defined( NO_VOICE ) //#ifndef _XBOX
+ m_pVoiceTweak = engine->GetVoiceTweakAPI();
+#endif
+ m_pMicMeter = new ImagePanel(this, "MicMeter");
+ m_pMicMeter2 = new ImagePanel(this, "MicMeter2");
+
+ m_pReceiveSliderLabel = new Label(this, "ReceiveLabel", "#GameUI_VoiceReceiveVolume");
+ m_pReceiveVolume = new CCvarSlider( this, "VoiceReceive", "#GameUI_ReceiveVolume",
+ 0.0f, 1.0f, "voice_scale" );
+
+ m_pMicrophoneSliderLabel = new Label(this, "MicrophoneLabel", "#GameUI_VoiceTransmitVolume");
+ m_pMicrophoneVolume = new Slider( this, "#GameUI_MicrophoneVolume" );
+ m_pMicrophoneVolume->SetRange( 0, 100 );
+ m_pMicrophoneVolume->AddActionSignalTarget( this );
+
+ m_pVoiceEnableCheckButton = new CCvarToggleCheckButton( this, "voice_modenable", "#GameUI_EnableVoice", "voice_modenable" );
+
+ m_pMicBoost = new CheckButton(this, "MicBoost", "#GameUI_BoostMicrophone" );
+ m_pMicBoost->AddActionSignalTarget( this );
+
+ m_pTestMicrophoneButton = new Button(this, "TestMicrophone", "#GameUI_TestMicrophone");
+
+ LoadControlSettings("Resource\\OptionsSubVoice.res");
+
+ m_bVoiceOn = false;
+ m_pMicMeter2->SetVisible(false);
+ // no voice tweak - then disable all buttons
+ if (!m_pVoiceTweak)
+ {
+ m_pReceiveVolume->SetEnabled(false);
+ m_pMicrophoneVolume->SetEnabled(false);
+ m_pVoiceEnableCheckButton->SetEnabled(false);
+ m_pMicBoost->SetEnabled(false);
+ m_pTestMicrophoneButton->SetEnabled(false);
+ }
+ else
+ {
+ OnResetData();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+COptionsSubVoice::~COptionsSubVoice()
+{
+ // turn off voice if it was on, since we're leaving this page
+ if (m_bVoiceOn)
+ {
+ EndTestMicrophone();
+ }
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnResetData()
+{
+ if (!m_pVoiceTweak)
+ return;
+
+ float micVolume = m_pVoiceTweak->GetControlFloat( MicrophoneVolume );
+ m_pMicrophoneVolume->SetValue( (int)( 100.0f * micVolume ) );
+ m_nMicVolumeValue = m_pMicrophoneVolume->GetValue();
+
+ float fMicBoost = m_pVoiceTweak->GetControlFloat( MicBoost );
+ m_pMicBoost->SetSelected( fMicBoost != 0.0f );
+ m_bMicBoostSelected = m_pMicBoost->IsSelected();
+
+ m_pReceiveVolume->Reset();
+ m_fReceiveVolume = m_pReceiveVolume->GetSliderValue();
+
+ m_pVoiceEnableCheckButton->Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnSliderMoved( int position )
+{
+ if (m_pVoiceTweak)
+ {
+ if (m_pMicrophoneVolume->GetValue() != m_nMicVolumeValue)
+ {
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnCheckButtonChecked( int state )
+{
+ if (m_pVoiceTweak)
+ {
+ // if our state is different
+ if ( m_pMicBoost->IsSelected() != m_bMicBoostSelected)
+ {
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnApplyChanges()
+{
+ if (!m_pVoiceTweak)
+ return;
+
+ m_nMicVolumeValue = m_pMicrophoneVolume->GetValue();
+ float fMicVolume = (float) m_nMicVolumeValue / 100.0f;
+ m_pVoiceTweak->SetControlFloat( MicrophoneVolume, fMicVolume );
+
+ m_bMicBoostSelected = m_pMicBoost->IsSelected();
+ m_pVoiceTweak->SetControlFloat( MicBoost, m_bMicBoostSelected ? 1.0f : 0.0f );
+
+ m_pReceiveVolume->ApplyChanges();
+ m_fReceiveVolume = m_pReceiveVolume->GetSliderValue();
+
+ m_pVoiceEnableCheckButton->ApplyChanges();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::StartTestMicrophone()
+{
+ if (!m_pVoiceTweak || m_bVoiceOn)
+ return;
+
+ m_bVoiceOn = true;
+
+ UseCurrentVoiceParameters();
+
+ if (m_pVoiceTweak->StartVoiceTweakMode())
+ {
+ m_pTestMicrophoneButton->SetText("#GameUI_StopTestMicrophone");
+
+ m_pReceiveVolume->SetEnabled(false);
+ m_pMicrophoneVolume->SetEnabled(false);
+ m_pVoiceEnableCheckButton->SetEnabled(false);
+ m_pMicBoost->SetEnabled(false);
+ m_pMicrophoneSliderLabel->SetEnabled(false);
+ m_pReceiveSliderLabel->SetEnabled(false);
+
+ m_pMicMeter2->SetVisible(true);
+ }
+ else
+ {
+ ResetVoiceParameters();
+
+ // we couldn't start it
+ m_bVoiceOn = false;
+ return;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::UseCurrentVoiceParameters()
+{
+ int nVal = m_pMicrophoneVolume->GetValue();
+ float val = (float) nVal / 100.0f;
+ m_pVoiceTweak->SetControlFloat( MicrophoneVolume, val );
+
+ bool bSelected = m_pMicBoost->IsSelected();
+ val = bSelected ? 1.0f : 0.0f;
+ m_pVoiceTweak->SetControlFloat( MicBoost, val );
+
+ // get where the current slider is
+ m_nReceiveSliderValue = m_pReceiveVolume->GetValue();
+ m_pReceiveVolume->ApplyChanges();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::ResetVoiceParameters()
+{
+ float fMicVolume = (float) m_nMicVolumeValue / 100.0f;
+ m_pVoiceTweak->SetControlFloat( MicrophoneVolume, fMicVolume );
+ m_pVoiceTweak->SetControlFloat( MicBoost, m_bMicBoostSelected ? 1.0f : 0.0f );
+
+ // restore the old value
+ ConVarRef voice_scale( "voice_scale" );
+ voice_scale.SetValue( m_fReceiveVolume );
+
+ m_pReceiveVolume->Reset();
+ // set the slider to 'new' value, but we've reset the 'start' value where it was
+ m_pReceiveVolume->SetValue(m_nReceiveSliderValue);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::EndTestMicrophone()
+{
+ if (!m_pVoiceTweak || !m_bVoiceOn)
+ return;
+
+ if ( m_pVoiceTweak->IsStillTweaking() )
+ {
+ m_pVoiceTweak->EndVoiceTweakMode();
+ }
+ ResetVoiceParameters();
+ m_pTestMicrophoneButton->SetText("#GameUI_TestMicrophone");
+ m_bVoiceOn = false;
+
+ m_pReceiveVolume->SetEnabled(true);
+ m_pMicrophoneVolume->SetEnabled(true);
+ m_pVoiceEnableCheckButton->SetEnabled(true);
+ m_pMicBoost->SetEnabled(true);
+ m_pMicrophoneSliderLabel->SetEnabled(true);
+ m_pReceiveSliderLabel->SetEnabled(true);
+ m_pMicMeter2->SetVisible(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnCommand( const char *command)
+{
+ if (!stricmp(command, "TestMicrophone"))
+ {
+ if (!m_bVoiceOn)
+ {
+ StartTestMicrophone();
+ }
+ else
+ {
+ EndTestMicrophone();
+ }
+ }
+ else if (!stricmp(command, "SteamVoiceSettings"))
+ {
+ if ( steamapicontext && steamapicontext->SteamFriends() )
+ {
+ steamapicontext->SteamFriends()->ActivateGameOverlay( "voicesettings" );
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnPageHide()
+{
+ // turn off voice if it was on, since we're leaving this page
+ if (m_bVoiceOn)
+ {
+ EndTestMicrophone();
+ }
+ BaseClass::OnPageHide();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnControlModified()
+{
+ PostActionSignal(new KeyValues("ApplyButtonEnable"));
+}
+
+#define BAR_WIDTH 160
+#define BAR_INCREMENT 8
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void COptionsSubVoice::OnThink()
+{
+ BaseClass::OnThink();
+ if (m_bVoiceOn)
+ {
+ if ( !m_pVoiceTweak->IsStillTweaking() )
+ {
+ DevMsg( 1, "Lost Voice Tweak channels, resetting\n" );
+ EndTestMicrophone();
+ }
+ else
+ {
+ float val = m_pVoiceTweak->GetControlFloat( SpeakingVolume );
+ int nValue = static_cast<int>( val*32768.0f + 0.5f );
+
+ int width = (BAR_WIDTH * nValue) / 32768;
+ width = ((width + (BAR_INCREMENT-1)) / BAR_INCREMENT) * BAR_INCREMENT; // round to nearest BAR_INCREMENT
+
+ int wide, tall;
+ m_pMicMeter2->GetSize(wide, tall);
+ m_pMicMeter2->SetSize(width, tall);
+ m_pMicMeter2->Repaint();
+ }
+ }
+}
diff --git a/gameui/OptionsSubVoice.h b/gameui/OptionsSubVoice.h
new file mode 100644
index 0000000..945d9a6
--- /dev/null
+++ b/gameui/OptionsSubVoice.h
@@ -0,0 +1,73 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef OPTIONS_SUB_VOICE_H
+#define OPTIONS_SUB_VOICE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/PropertyPage.h>
+
+typedef struct IVoiceTweak_s IVoiceTweak;
+
+class CCvarSlider;
+class CCvarToggleCheckButton;
+//-----------------------------------------------------------------------------
+// Purpose: Voice Details, Part of OptionsDialog
+//-----------------------------------------------------------------------------
+class COptionsSubVoice : public vgui::PropertyPage
+{
+ DECLARE_CLASS_SIMPLE( COptionsSubVoice, vgui::PropertyPage );
+
+public:
+ COptionsSubVoice(vgui::Panel *parent);
+ ~COptionsSubVoice();
+
+ virtual void OnResetData();
+ virtual void OnApplyChanges();
+
+protected:
+ virtual void OnThink(); // called every frame before painting, but only if panel is visible
+
+private:
+ virtual void OnCommand( const char *command );
+
+ MESSAGE_FUNC( OnPageHide, "PageHide" );
+ MESSAGE_FUNC_INT( OnSliderMoved, "SliderMoved", position );
+ MESSAGE_FUNC_INT( OnCheckButtonChecked, "CheckButtonChecked", state );
+ MESSAGE_FUNC( OnControlModified, "ControlModified" );
+
+ void StartTestMicrophone();
+ void EndTestMicrophone();
+
+ void UseCurrentVoiceParameters();
+ void ResetVoiceParameters();
+
+ IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API.
+ vgui::CheckButton *m_pMicBoost;
+
+ vgui::ImagePanel *m_pMicMeter;
+ vgui::ImagePanel *m_pMicMeter2;
+ vgui::Button *m_pTestMicrophoneButton;
+ vgui::Label *m_pMicrophoneSliderLabel;
+ vgui::Slider *m_pMicrophoneVolume;
+ vgui::Label *m_pReceiveSliderLabel;
+ CCvarSlider *m_pReceiveVolume;
+ CCvarToggleCheckButton *m_pVoiceEnableCheckButton;
+
+ int m_nMicVolumeValue;
+ bool m_bMicBoostSelected;
+ float m_fReceiveVolume;
+ int m_nReceiveSliderValue;
+
+ bool m_bVoiceOn;
+};
+
+
+
+#endif // OPTIONS_SUB_VOICE_H \ No newline at end of file
diff --git a/gameui/PanelListPanel.cpp b/gameui/PanelListPanel.cpp
new file mode 100644
index 0000000..8ea327f
--- /dev/null
+++ b/gameui/PanelListPanel.cpp
@@ -0,0 +1,306 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include <assert.h>
+#include <vgui_controls/ScrollBar.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+
+#include <KeyValues.h>
+#include <vgui/MouseCode.h>
+#include <vgui/KeyCode.h>
+#include <vgui/IInput.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include "PanelListPanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+class VScrollBarReversedButtons : public ScrollBar
+{
+public:
+ VScrollBarReversedButtons( Panel *parent, const char *panelName, bool vertical );
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+};
+
+VScrollBarReversedButtons::VScrollBarReversedButtons( Panel *parent, const char *panelName, bool vertical ) : ScrollBar( parent, panelName, vertical )
+{
+}
+
+void VScrollBarReversedButtons::ApplySchemeSettings( IScheme *pScheme )
+{
+ ScrollBar::ApplySchemeSettings( pScheme );
+
+ Button *pButton;
+ pButton = GetButton( 0 );
+ pButton->SetArmedColor( pButton->GetSchemeColor("DimBaseText", pScheme), pButton->GetBgColor());
+ pButton->SetDepressedColor( pButton->GetSchemeColor("DimBaseText", pScheme), pButton->GetBgColor());
+ pButton->SetDefaultColor( pButton->GetFgColor(), pButton->GetBgColor());
+
+ pButton = GetButton( 1 );
+ pButton->SetArmedColor( pButton->GetSchemeColor("DimBaseText", pScheme), pButton->GetBgColor());
+ pButton->SetDepressedColor( pButton->GetSchemeColor("DimBaseText", pScheme), pButton->GetBgColor());
+ pButton->SetDefaultColor( pButton->GetFgColor(), pButton->GetBgColor());
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x -
+// y -
+// wide -
+// tall -
+// Output :
+//-----------------------------------------------------------------------------
+CPanelListPanel::CPanelListPanel( vgui::Panel *parent, char const *panelName, bool inverseButtons ) : Panel( parent, panelName )
+{
+ SetBounds( 0, 0, 100, 100 );
+ _sliderYOffset = 0;
+
+ if (inverseButtons)
+ {
+ _vbar = new VScrollBarReversedButtons(this, "CPanelListPanelVScroll", true );
+ }
+ else
+ {
+ _vbar = new ScrollBar(this, "CPanelListPanelVScroll", true );
+ }
+ _vbar->SetBounds( 0, 0, 20, 20 );
+ _vbar->SetVisible(false);
+ _vbar->AddActionSignalTarget( this );
+
+ _embedded = new Panel( this, "PanelListEmbedded" );
+ _embedded->SetBounds( 0, 0, 20, 20 );
+ _embedded->SetPaintBackgroundEnabled( false );
+ _embedded->SetPaintBorderEnabled( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CPanelListPanel::~CPanelListPanel()
+{
+ // free data from table
+ DeleteAllItems();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CPanelListPanel::computeVPixelsNeeded( void )
+{
+ int pixels =0;
+ DATAITEM *item;
+ Panel *panel;
+ for ( int i = 0; i < _dataItems.GetCount(); i++ )
+ {
+ item = _dataItems[ i ];
+ if ( !item )
+ continue;
+
+ panel = item->panel;
+ if ( !panel )
+ continue;
+
+ int w, h;
+ panel->GetSize( w, h );
+
+ pixels += h;
+ }
+ pixels+=5; // add a buffer after the last item
+
+ return pixels;
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns the panel to use to render a cell
+// Input : column -
+// row -
+// Output : Panel
+//-----------------------------------------------------------------------------
+Panel *CPanelListPanel::GetCellRenderer( int row )
+{
+ DATAITEM *item = _dataItems[ row ];
+ if ( item )
+ {
+ Panel *panel = item->panel;
+ return panel;
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: adds an item to the view
+// data->GetName() is used to uniquely identify an item
+// data sub items are matched against column header name to be used in the table
+// Input : *item -
+//-----------------------------------------------------------------------------
+int CPanelListPanel::AddItem( Panel *panel )
+{
+ InvalidateLayout();
+
+ DATAITEM *newitem = new DATAITEM;
+ newitem->panel = panel;
+ panel->SetParent( _embedded );
+ return _dataItems.PutElement( newitem );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output :
+//-----------------------------------------------------------------------------
+int CPanelListPanel::GetItemCount( void )
+{
+ return _dataItems.GetCount();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns pointer to data the row holds
+// Input : itemIndex -
+// Output : KeyValues
+//-----------------------------------------------------------------------------
+Panel *CPanelListPanel::GetItem(int itemIndex)
+{
+ if ( itemIndex < 0 || itemIndex >= _dataItems.GetCount() )
+ return NULL;
+
+ return _dataItems[itemIndex]->panel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : itemIndex -
+// Output : DATAITEM
+//-----------------------------------------------------------------------------
+CPanelListPanel::DATAITEM *CPanelListPanel::GetDataItem( int itemIndex )
+{
+ if ( itemIndex < 0 || itemIndex >= _dataItems.GetCount() )
+ return NULL;
+
+ return _dataItems[ itemIndex ];
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+//-----------------------------------------------------------------------------
+void CPanelListPanel::RemoveItem(int itemIndex)
+{
+ DATAITEM *item = _dataItems[ itemIndex ];
+ delete item->panel;
+ delete item;
+ _dataItems.RemoveElementAt(itemIndex);
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: clears and deletes all the memory used by the data items
+//-----------------------------------------------------------------------------
+void CPanelListPanel::DeleteAllItems()
+{
+ for (int i = 0; i < _dataItems.GetCount(); i++)
+ {
+ if ( _dataItems[i] )
+ {
+ delete _dataItems[i]->panel;
+ }
+ delete _dataItems[i];
+ }
+ _dataItems.RemoveAll();
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelListPanel::OnMouseWheeled(int delta)
+{
+ int val = _vbar->GetValue();
+ val -= (delta * 3 * 5);
+ _vbar->SetValue(val);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: relayouts out the panel after any internal changes
+//-----------------------------------------------------------------------------
+void CPanelListPanel::PerformLayout()
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ int vpixels = computeVPixelsNeeded();
+
+ //!! need to make it recalculate scroll positions
+ _vbar->SetVisible(true);
+ _vbar->SetEnabled(false);
+ _vbar->SetRange( 0, vpixels - tall + 24);
+ _vbar->SetRangeWindow( 24 /*vpixels / 10*/ );
+ _vbar->SetButtonPressedScrollValue( 24 );
+ _vbar->SetPos(wide - 20, _sliderYOffset);
+ _vbar->SetSize(18, tall - 2 - _sliderYOffset);
+ _vbar->InvalidateLayout();
+
+ int top = _vbar->GetValue();
+
+ _embedded->SetPos( 0, -top );
+ _embedded->SetSize( wide-20, vpixels );
+
+ // Now lay out the controls on the embedded panel
+ int y = 0;
+ int h = 0;
+ for ( int i = 0; i < _dataItems.GetCount(); i++, y += h )
+ {
+ DATAITEM *item = _dataItems[ i ];
+ if ( !item || !item->panel )
+ continue;
+
+ h = item->panel->GetTall();
+ item->panel->SetBounds( 8, y, wide-36, h );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPanelListPanel::PaintBackground()
+{
+ Panel::PaintBackground();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *inResourceData -
+//-----------------------------------------------------------------------------
+void CPanelListPanel::ApplySchemeSettings(IScheme *pScheme)
+{
+ Panel::ApplySchemeSettings(pScheme);
+
+ SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
+ SetBgColor(GetSchemeColor("Label.BgColor", GetBgColor(), pScheme));
+
+
+// _labelFgColor = GetSchemeColor("WindowFgColor");
+// _selectionFgColor = GetSchemeColor("ListSelectionFgColor", _labelFgColor);
+}
+
+void CPanelListPanel::OnSliderMoved( int position )
+{
+ InvalidateLayout();
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CPanelListPanel::SetSliderYOffset( int pixels )
+{
+ _sliderYOffset = pixels;
+}
diff --git a/gameui/PanelListPanel.h b/gameui/PanelListPanel.h
new file mode 100644
index 0000000..9baeccf
--- /dev/null
+++ b/gameui/PanelListPanel.h
@@ -0,0 +1,79 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( PANELLISTPANEL_H )
+#define PANELLISTPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui_controls/Panel.h>
+
+class KeyValues;
+
+
+//-----------------------------------------------------------------------------
+// Purpose: A list of variable height child panels
+//-----------------------------------------------------------------------------
+class CPanelListPanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CPanelListPanel, vgui::Panel );
+
+public:
+ typedef struct dataitem_s
+ {
+ // Always store a panel pointer
+ vgui::Panel *panel;
+ } DATAITEM;
+
+ CPanelListPanel( vgui::Panel *parent, char const *panelName, bool inverseButtons = false );
+ ~CPanelListPanel();
+
+ // DATA & ROW HANDLING
+ // The list now owns the panel
+ virtual int computeVPixelsNeeded( void );
+ virtual int AddItem( vgui::Panel *panel );
+ virtual int GetItemCount( void );
+ virtual vgui::Panel *GetItem(int itemIndex); // returns pointer to data the row holds
+ virtual void RemoveItem(int itemIndex); // removes an item from the table (changing the indices of all following items)
+ virtual void DeleteAllItems(); // clears and deletes all the memory used by the data items
+
+ // career-mode UI wants to nudge sub-controls around
+ void SetSliderYOffset(int pixels);
+
+ // PAINTING
+ virtual vgui::Panel *GetCellRenderer( int row );
+
+ MESSAGE_FUNC_INT( OnSliderMoved, "ScrollBarSliderMoved", position );
+
+ virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
+
+ vgui::Panel *GetEmbedded()
+ {
+ return _embedded;
+ }
+
+protected:
+
+ DATAITEM *GetDataItem( int itemIndex );
+
+ virtual void PerformLayout();
+ virtual void PaintBackground();
+ virtual void OnMouseWheeled(int delta);
+
+private:
+ // list of the column headers
+ vgui::Dar<DATAITEM *> _dataItems;
+ vgui::ScrollBar *_vbar;
+ vgui::Panel *_embedded;
+
+ int _tableStartX;
+ int _tableStartY;
+ int _sliderYOffset;
+};
+
+#endif // PANELLISTPANEL_H \ No newline at end of file
diff --git a/gameui/PlayerListDialog.cpp b/gameui/PlayerListDialog.cpp
new file mode 100644
index 0000000..85b1267
--- /dev/null
+++ b/gameui/PlayerListDialog.cpp
@@ -0,0 +1,250 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "PlayerListDialog.h"
+
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.h>
+#include <vgui_controls/ListPanel.h>
+#include <KeyValues.h>
+#include <vgui_controls/Label.h>
+#include <vgui_controls/Button.h>
+#include <vgui_controls/MessageBox.h>
+#include <vgui_controls/ComboBox.h>
+
+#include "EngineInterface.h"
+#include "game/client/IGameClientExports.h"
+#include "GameUI_Interface.h"
+#include "steam/steam_api.h"
+#include "fmtstr.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CPlayerListDialog::CPlayerListDialog(vgui::Panel *parent) : BaseClass(parent, "PlayerListDialog")
+{
+ SetSize(320, 240);
+ SetTitle("#GameUI_CurrentPlayers", true);
+
+ m_pMuteButton = new Button(this, "MuteButton", "");
+
+ m_pPlayerList = new ListPanel(this, "PlayerList");
+ m_pPlayerList->AddColumnHeader(0, "Name", "#GameUI_PlayerName", 180);
+ m_pPlayerList->AddColumnHeader(1, "Properties", "#GameUI_Properties", 80);
+
+ m_pPlayerList->SetEmptyListText("#GameUI_NoOtherPlayersInGame");
+
+ LoadControlSettings("Resource/PlayerListDialog.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CPlayerListDialog::~CPlayerListDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPlayerListDialog::Activate()
+{
+ BaseClass::Activate();
+
+ // refresh player list
+ m_pPlayerList->DeleteAllItems();
+ int maxClients = engine->GetMaxClients();
+ for (int i = 1; i <= maxClients; i++)
+ {
+ // get the player info from the engine
+ player_info_t pi;
+
+ if ( !engine->GetPlayerInfo(i, &pi) )
+ continue;
+
+ char szPlayerIndex[32];
+ Q_snprintf(szPlayerIndex, sizeof( szPlayerIndex ), "%d", i);
+
+ // collate user data then add it to the table
+ KeyValues *data = new KeyValues(szPlayerIndex);
+
+ data->SetString("Name", pi.name );
+ data->SetInt("index", i);
+
+ // add to the list
+ m_pPlayerList->AddItem(data, 0, false, false);
+ }
+
+ // refresh player properties info
+ RefreshPlayerProperties();
+
+ // select the first item by default
+ m_pPlayerList->SetSingleSelectedItem( m_pPlayerList->GetItemIDFromRow(0) );
+
+ // toggle button states
+ OnItemSelected();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: walks the players and sets their info display in the list
+//-----------------------------------------------------------------------------
+void CPlayerListDialog::RefreshPlayerProperties()
+{
+ for (int i = 0; i <= m_pPlayerList->GetItemCount(); i++)
+ {
+ KeyValues *data = m_pPlayerList->GetItem(i);
+ if (!data)
+ continue;
+
+ // assemble properties
+ int playerIndex = data->GetInt("index");
+ player_info_t pi;
+
+ if ( !engine->GetPlayerInfo( playerIndex, &pi) )
+ {
+ // disconnected
+ data->SetString("properties", "Disconnected");
+ continue;
+ }
+
+ data->SetString( "name", pi.name );
+
+ bool muted = false, friends = false, bot = false;
+
+ if ( GameClientExports() && GameClientExports()->IsPlayerGameVoiceMuted(playerIndex) )
+ {
+ muted = true;
+ }
+ if ( pi.fakeplayer )
+ {
+ bot = true;
+ }
+
+ if (bot)
+ {
+ data->SetString("properties", "CPU Player");
+ }
+ else if (muted && friends)
+ {
+ data->SetString("properties", "Friend; Muted");
+ }
+ else if (muted)
+ {
+ data->SetString("properties", "Muted");
+ }
+ else if (friends)
+ {
+ data->SetString("properties", "Friend");
+ }
+ else
+ {
+ data->SetString("properties", "");
+ }
+ }
+ m_pPlayerList->RereadAllItems();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles the AddFriend command
+//-----------------------------------------------------------------------------
+void CPlayerListDialog::OnCommand(const char *command)
+{
+ if (!stricmp(command, "Mute"))
+ {
+ ToggleMuteStateOfSelectedUser();
+ }
+ else
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: toggles whether a user is muted or not
+//-----------------------------------------------------------------------------
+void CPlayerListDialog::ToggleMuteStateOfSelectedUser()
+{
+ if (!GameClientExports())
+ return;
+
+ for ( int iSelectedItem = 0; iSelectedItem < m_pPlayerList->GetSelectedItemsCount(); iSelectedItem++ )
+ {
+ KeyValues *data = m_pPlayerList->GetItem( m_pPlayerList->GetSelectedItem( iSelectedItem ) );
+ if (!data)
+ return;
+ int playerIndex = data->GetInt("index");
+ Assert(playerIndex);
+
+ if (GameClientExports()->IsPlayerGameVoiceMuted(playerIndex))
+ {
+ GameClientExports()->UnmutePlayerGameVoice(playerIndex);
+ }
+ else
+ {
+ GameClientExports()->MutePlayerGameVoice(playerIndex);
+ }
+ }
+
+ RefreshPlayerProperties();
+ OnItemSelected();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CPlayerListDialog::OnItemSelected()
+{
+ // make sure the data is up-to-date
+ RefreshPlayerProperties();
+
+ // set the button state based on the selected item
+ bool bMuteButtonEnabled = false;
+ if (m_pPlayerList->GetSelectedItemsCount() > 0)
+ {
+ KeyValues *data = m_pPlayerList->GetItem(m_pPlayerList->GetSelectedItem(0));
+
+ player_info_t pi;
+
+ int iLocalPlayer = engine->GetLocalPlayer();
+
+ int iPlayerIndex = data->GetInt("index");
+ bool isValidPlayer = engine->GetPlayerInfo( iPlayerIndex, &pi );
+
+ // make sure the player is not a bot, or the user
+ // Matt - changed this check to see if player indeces match, instead of using friends ID
+ if ( pi.fakeplayer || iPlayerIndex == iLocalPlayer ) // || pi.friendsID == g_pFriendsUser->GetFriendsID() )
+ {
+ // invalid player,
+ isValidPlayer = false;
+ }
+
+ if (data && isValidPlayer && GameClientExports() && GameClientExports()->IsPlayerGameVoiceMuted(data->GetInt("index")))
+ {
+ m_pMuteButton->SetText("#GameUI_UnmuteIngameVoice");
+ }
+ else
+ {
+ m_pMuteButton->SetText("#GameUI_MuteIngameVoice");
+ }
+
+ if (GameClientExports() && isValidPlayer)
+ {
+ bMuteButtonEnabled = true;
+ }
+ }
+ else
+ {
+ m_pMuteButton->SetText("#GameUI_MuteIngameVoice");
+ }
+
+ m_pMuteButton->SetEnabled( bMuteButtonEnabled );
+}
diff --git a/gameui/PlayerListDialog.h b/gameui/PlayerListDialog.h
new file mode 100644
index 0000000..638a4e7
--- /dev/null
+++ b/gameui/PlayerListDialog.h
@@ -0,0 +1,53 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef PLAYERLISTDIALOG_H
+#define PLAYERLISTDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/Frame.h>
+#include "steam/steamclientpublic.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: List of players, their ingame-name and their friends-name
+//-----------------------------------------------------------------------------
+class CPlayerListDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CPlayerListDialog, vgui::Frame );
+
+public:
+ CPlayerListDialog(vgui::Panel *parent);
+ ~CPlayerListDialog();
+
+ virtual void Activate();
+
+private:
+ MESSAGE_FUNC( OnItemSelected, "ItemSelected" );
+ virtual void OnCommand(const char *command);
+
+ void ToggleMuteStateOfSelectedUser();
+ void RefreshPlayerProperties();
+
+ void OnKeyCodePressed( vgui::KeyCode code )
+ {
+ if ( code == KEY_XBUTTON_B )
+ {
+ Close();
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed(code);
+ }
+ }
+
+ vgui::ListPanel *m_pPlayerList;
+ vgui::Button *m_pMuteButton;
+};
+
+#endif // PLAYERLISTDIALOG_H
diff --git a/gameui/RunGameEngine.cpp b/gameui/RunGameEngine.cpp
new file mode 100644
index 0000000..b0ecd0f
--- /dev/null
+++ b/gameui/RunGameEngine.cpp
@@ -0,0 +1,205 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+
+#include "IRunGameEngine.h"
+#include "EngineInterface.h"
+#include "tier1/strtools.h"
+#include "IGameUIFuncs.h"
+#include "tier1/convar.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface to running the engine from the UI dlls
+//-----------------------------------------------------------------------------
+class CRunGameEngine : public IRunGameEngine
+{
+public:
+ // Returns true if the engine is running, false otherwise.
+ virtual bool IsRunning()
+ {
+ return true;
+ }
+
+ // Adds text to the engine command buffer. Only works if IsRunning()
+ // returns true on success, false on failure
+ virtual bool AddTextCommand(const char *text)
+ {
+ engine->ClientCmd_Unrestricted((char *)text);
+ return true;
+ }
+
+ // runs the engine with the specified command line parameters. Only works if !IsRunning()
+ // returns true on success, false on failure
+ virtual bool RunEngine(const char *gameName, const char *commandLineParams)
+ {
+ return false;
+ }
+
+ virtual bool RunEngine2(const char *gameDir, const char *commandLineParams, bool isSourceGame)
+ {
+ return false;
+ }
+
+ virtual ERunResult RunEngine( int iAppID, const char *gameDir, const char *commandLineParams )
+ {
+ return k_ERunResultOkay;
+ }
+
+ // returns true if the player is currently connected to a game server
+ virtual bool IsInGame()
+ {
+ return engine->GetLevelName() && strlen(engine->GetLevelName()) > 0;
+ }
+
+ // gets information about the server the engine is currently connected to
+ // returns true on success, false on failure
+ virtual bool GetGameInfo(char *infoBuffer, int bufferSize)
+ {
+ //!! need to implement
+ return false;
+ }
+
+ virtual void SetTrackerUserID(int trackerID, const char *trackerName)
+ {
+ gameuifuncs->SetFriendsID(trackerID, trackerName);
+
+ // update the player's name if necessary
+ ConVarRef name( "name" );
+ if ( name.IsValid() && trackerName && *trackerName && !Q_strcmp( name.GetString(), "unnamed" ) )
+ {
+ name.SetValue(trackerName);
+ }
+ }
+
+ // iterates users
+ // returns the number of user
+ virtual int GetPlayerCount()
+ {
+ return engine->GetMaxClients();
+ }
+
+ // returns a playerID for a player
+ // playerIndex is in the range [0, GetPlayerCount)
+ virtual unsigned int GetPlayerFriendsID(int playerIndex)
+ {
+ player_info_t pi;
+
+ if ( engine->GetPlayerInfo(playerIndex, &pi ) )
+ return pi.friendsID;
+
+ return 0;
+ }
+
+ // gets the in-game name of another user, returns NULL if that user doesn't exists
+ virtual const char *GetPlayerName(int trackerID, char *name, int namelen)
+ {
+ // find the player by their friendsID
+ player_info_t pi;
+ for (int i = 0; i < engine->GetMaxClients(); i++)
+ {
+ if (engine->GetPlayerInfo(i, &pi ))
+ {
+ if (pi.friendsID == (uint)trackerID)
+ {
+ Q_strncpy( name, pi.name, namelen );
+ return name;
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+ virtual const char *GetPlayerFriendsName(int trackerID, char *name, int namelen)
+ {
+ // find the player by their friendsID
+ player_info_t pi;
+ for (int i = 0; i < engine->GetMaxClients(); i++)
+ {
+ if (engine->GetPlayerInfo(i, &pi ))
+ {
+ if (pi.friendsID == (uint)trackerID)
+ {
+ Q_strncpy( name, pi.friendsName, namelen );
+ return name;
+ }
+ }
+ }
+
+ return NULL;
+ }
+
+ // return the build number of the engine
+ virtual unsigned int GetEngineBuildNumber()
+ {
+ return engine->GetEngineBuildNumber();
+ }
+
+ // return the product version of the mod being played (comes from steam.inf)
+ virtual const char *GetProductVersionString()
+ {
+ return engine->GetProductVersionString();
+ }
+};
+
+EXPOSE_SINGLE_INTERFACE(CRunGameEngine, IRunGameEngine, RUNGAMEENGINE_INTERFACE_VERSION);
+
+//namespace
+//{
+////-----------------------------------------------------------------------------
+//// Purpose: Interface to running the game engine
+////-----------------------------------------------------------------------------
+//abstract_class IRunGameEngine_Old : public IBaseInterface
+//{
+//public:
+// // Returns true if the engine is running, false otherwise.
+// virtual bool IsRunning() = 0;
+//
+// // Adds text to the engine command buffer. Only works if IsRunning()
+// // returns true on success, false on failure
+// virtual bool AddTextCommand(const char *text) = 0;
+//
+// // runs the engine with the specified command line parameters. Only works if !IsRunning()
+// // returns true on success, false on failure
+// virtual bool RunEngine(const char *gameDir, const char *commandLineParams) = 0;
+//
+// // returns true if the player is currently connected to a game server
+// virtual bool IsInGame() = 0;
+//
+// // gets information about the server the engine is currently ctrue on success, false on failure
+// virtual bool GetGameInfo(char *infoBuffer, int bufferSize) = 0;
+//
+// // tells the engine our userID
+// virtual void SetTrackerUserID(int trackerID, const char *trackerName) = 0;
+//
+// // this next section could probably moved to another interface
+// // iterates users
+// // returns the number of user
+// virtual int GetPlayerCount() = 0;
+//
+// // returns a playerID for a player
+// // playerIndex is in the range [0, GetPlayerCount)
+// virtual unsigned int GetPlayerFriendsID(int playerIndex) = 0;
+//
+// // gets the in-game name of another user, returns NULL if that user doesn't exists
+// virtual const char *GetPlayerName(int friendsID) = 0;
+//
+// // gets the friends name of a player
+// virtual const char *GetPlayerFriendsName(int friendsID) = 0;
+//};
+//
+//#define RUNGAMEENGINE_INTERFACE_VERSION_OLD "RunGameEngine004"
+//
+//#ifndef _XBOX
+//EXPOSE_SINGLE_INTERFACE(CRunGameEngine, IRunGameEngine_Old, RUNGAMEENGINE_INTERFACE_VERSION_OLD);
+//#endif
+//}
+
diff --git a/gameui/RunGameEngine.h b/gameui/RunGameEngine.h
new file mode 100644
index 0000000..db4f992
--- /dev/null
+++ b/gameui/RunGameEngine.h
@@ -0,0 +1 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
diff --git a/gameui/SaveGameBrowserDialog.cpp b/gameui/SaveGameBrowserDialog.cpp
new file mode 100644
index 0000000..ac894ff
--- /dev/null
+++ b/gameui/SaveGameBrowserDialog.cpp
@@ -0,0 +1,1423 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "SaveGameDialog.h"
+
+#include "winlite.h" // FILETIME
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+
+#include "vgui_controls/AnimationController.h"
+#include "vgui_controls/ImagePanel.h"
+#include "filesystem.h"
+#include "KeyValues.h"
+#include "ModInfo.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "vstdlib/random.h"
+
+#include "SaveGameBrowserDialog.h"
+
+extern const char *COM_GetModDirectory( void );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CGameSavePanel::CGameSavePanel( CSaveGameBrowserDialog *parent, SaveGameDescription_t *pSaveDesc, bool bCommandPanel )
+: BaseClass( parent, "SaveGamePanel" )
+{
+ // Store our save description internally for reference later by our parent
+ m_SaveInfo = (*pSaveDesc);
+ m_bNewSavePanel = bCommandPanel;
+
+ // Setup our main graphical elements
+ m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) );
+ m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) );
+
+ // Setup our various labels
+ m_pChapterTitle = new Label( this, "ChapterLabel", m_SaveInfo.szComment );
+ m_pTime = new Label( this, "TimeLabel", m_SaveInfo.szFileTime );
+ m_pElapsedTime = new Label( this, "ElapsedLabel", m_SaveInfo.szElapsedTime );
+ m_pType = new Label( this, "TypeLabel", m_SaveInfo.szType );
+
+ // Make sure we have a chapter description
+ char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" );
+ if ( pchChapterName )
+ {
+ char szChapterImage[ 256 ];
+ Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) );
+ char *ext = Q_strrchr( szChapterImage, '_' );
+ if ( ext )
+ {
+ *ext = '\0';
+ }
+ m_pLevelPic->SetImage( szChapterImage );
+ }
+ else
+ {
+ m_pLevelPic->SetImage( "ui_logo" );
+ }
+
+ // Setup our basic settings
+ KeyValues *pKeys = NULL;
+ if ( GameUI().IsConsoleUI() )
+ {
+ pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGamePanel.res" );
+ }
+ LoadControlSettings( "Resource/SaveGamePanel.res", NULL, pKeys );
+
+ int px, py;
+ m_pLevelPicBorder->GetPos( px, py );
+ SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() + ( m_pType->GetTall() + 16 ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CGameSavePanel::~CGameSavePanel( void )
+{
+ if ( m_pLevelPicBorder )
+ delete m_pLevelPicBorder;
+
+ if ( m_pLevelPic )
+ delete m_pLevelPic;
+
+ if ( m_pChapterTitle )
+ delete m_pChapterTitle;
+
+ if ( m_pTime )
+ delete m_pTime;
+
+ if ( m_pElapsedTime )
+ delete m_pElapsedTime;
+
+ if ( m_pType )
+ delete m_pType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CGameSavePanel::ApplySchemeSettings( IScheme *pScheme )
+{
+ m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
+ m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) );
+ m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 4) );
+ m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+
+ // Turn various labels off if we're the "stubbed" panel
+ if ( m_bNewSavePanel )
+ {
+ m_pTime->SetVisible( false );
+ m_pElapsedTime->SetVisible( false );
+ m_pType->SetVisible( false );
+ }
+
+ // Setup our initial state
+ m_pChapterTitle->SetFgColor( m_TextColor );
+ m_pTime->SetFgColor( m_TextColor );
+ m_pElapsedTime->SetFgColor( m_TextColor );
+
+ m_pLevelPic->SetFillColor( Color( 0, 0, 0, 255 ) );
+ m_pLevelPicBorder->SetFillColor( Color( 0, 0, 0, 255 ) );
+
+ if ( m_bNewSavePanel )
+ {
+ float flScaleAmount = m_pLevelPic->GetScaleAmount();
+ if ( flScaleAmount <= 0.0f )
+ flScaleAmount = 1.0f;
+
+ // TBD: Draw the game logo here!
+ int picWide = 64.0f * flScaleAmount;
+ int picTall = 64.0f * flScaleAmount;
+ int borderWide = m_pLevelPicBorder->GetWide();
+ int borderTall = m_pLevelPicBorder->GetTall();
+ int borderX, borderY;
+ m_pLevelPicBorder->GetPos( borderX, borderY );
+ m_pLevelPic->SetPos( borderX + ( ( borderWide - picWide ) / 2 ), borderY + ( ( borderTall - picTall ) / 2 ) );
+ m_pLevelPic->SetFillColor( Color( 0, 0, 0, 0 ) );
+ }
+
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Overwrite the level description
+// Input : *pDesc - Description to use
+//-----------------------------------------------------------------------------
+void CGameSavePanel::SetDescription( SaveGameDescription_t *pDesc )
+{
+ // Store our save description internally for reference later by our parent
+ m_SaveInfo = (*pDesc);
+
+ // Setup our main graphical elements
+ m_pChapterTitle->SetText( m_SaveInfo.szComment );
+ m_pTime->SetText( m_SaveInfo.szFileTime );
+ m_pElapsedTime->SetText( m_SaveInfo.szElapsedTime );
+ m_pType->SetText( m_SaveInfo.szType );
+
+ // Make sure we have a chapter description
+ char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" );
+ if ( pchChapterName )
+ {
+ char szChapterImage[ 256 ];
+ Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) );
+ char *ext = Q_strrchr( szChapterImage, '_' );
+ if ( ext )
+ {
+ *ext = '\0';
+ }
+ m_pLevelPic->SetImage( szChapterImage );
+ }
+}
+
+//
+//
+//
+//
+//
+
+//-----------------------------------------------------------------------------
+// Purpose: new game chapter selection
+//-----------------------------------------------------------------------------
+CSaveGameBrowserDialog::CSaveGameBrowserDialog( vgui::Panel *parent )
+: BaseClass( parent, "SaveGameDialog" ),
+ m_bFilterAutosaves( false ),
+ m_iSelectedSave( -1 ),
+ m_bScrolling( false ),
+ m_ScrollCt( 0 ),
+ m_ScrollSpeed( 0.0f ),
+ m_ButtonPressed( SCROLL_NONE ),
+ m_ScrollDirection( SCROLL_NONE ),
+ m_nDeletedPanel( INVALID_INDEX ),
+ m_nAddedPanel( INVALID_INDEX ),
+ m_nUsedStorageSpace( 0 ),
+ m_bControlDisabled( false )
+{
+ // Setup basic attributes
+ SetDeleteSelfOnClose( true );
+ SetSizeable( false );
+
+ // Create the backer that highlights the currently selected save
+ m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) );
+ m_pCenterBg->SetPaintBackgroundType( 2 );
+ m_pCenterBg->SetVisible( true );
+
+ // Create our button footer
+ m_pFooter = new CFooterPanel( parent, "SaveGameFooter" );
+
+ // Load our res files from the keyvalue we're holding
+ KeyValues *pKeys = NULL;
+ if ( GameUI().IsConsoleUI() )
+ {
+ pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGameDialog.res" );
+ }
+
+ LoadControlSettings( "Resource/SaveGameDialog.res", NULL, pKeys );
+}
+
+//-----------------------------------------------------------------------------
+// Destructor
+//-----------------------------------------------------------------------------
+CSaveGameBrowserDialog::~CSaveGameBrowserDialog( void )
+{
+ // Release all elements
+ m_SavePanels.PurgeAndDeleteElements();
+
+ // Kill the footer
+ if ( m_pFooter )
+ {
+ delete m_pFooter;
+ m_pFooter = NULL;
+ }
+
+ if ( m_pCenterBg )
+ {
+ delete m_pCenterBg;
+ m_pCenterBg = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Show the "No save games to display" indication label and hide all browsing UI
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ShowNoSaveGameUI( void )
+{
+ // Show the "no save games" text
+ vgui::Label *pNoSavesLabel = dynamic_cast<vgui::Label *>(FindChildByName( "NoSavesLabel" ));
+ if ( pNoSavesLabel )
+ {
+ if ( m_bSaveGameIsCorrupt )
+ {
+ pNoSavesLabel->SetText("#GameUI_SaveGame_CorruptFile");
+ }
+ else
+ {
+ pNoSavesLabel->SetText("#GameUI_NoSaveGamesToDisplay");
+ }
+ pNoSavesLabel->SetVisible( true );
+ }
+
+ if ( m_pCenterBg )
+ m_pCenterBg->SetVisible( false );
+
+ vgui::Panel *pLeftArrow = FindChildByName( "LeftArrow" );
+ if ( pLeftArrow )
+ pLeftArrow->SetVisible( false );
+
+ vgui::Panel *pRightArrow = FindChildByName( "RightArrow" );
+ if ( pRightArrow )
+ pRightArrow->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hide all "No save games" UI
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::HideNoSaveGameUI( void )
+{
+ // Show the "no save games" text
+ vgui::Panel *pNoSavesLabel = FindChildByName( "NoSavesLabel" );
+ if ( pNoSavesLabel )
+ pNoSavesLabel->SetVisible( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::LayoutPanels( void )
+{
+ // Setup our panels depending on the mode we're in
+ if ( HasActivePanels() )
+ {
+ // Hide any indicators about no save games
+ HideNoSaveGameUI();
+
+ // Layout panel positions relative to the dialog center.
+ int panelWidth = m_SavePanels[0]->GetWide() + 16;
+ int dialogWidth = GetWide();
+ m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + 8;
+ m_PanelXPos[1] = m_PanelXPos[2] - panelWidth;
+ m_PanelXPos[0] = m_PanelXPos[1];
+ m_PanelXPos[3] = m_PanelXPos[2] + panelWidth;
+ m_PanelXPos[4] = m_PanelXPos[3];
+
+ m_PanelAlpha[0] = 0;
+ m_PanelAlpha[1] = 64;
+ m_PanelAlpha[2] = 255;
+ m_PanelAlpha[3] = 64;
+ m_PanelAlpha[4] = 0;
+
+ int panelHeight;
+ m_SavePanels[0]->GetSize( panelWidth, panelHeight );
+ m_pCenterBg->SetVisible( true );
+ m_pCenterBg->SetWide( panelWidth + 16 );
+ m_pCenterBg->SetPos( m_PanelXPos[2] - 8, m_PanelYPos[2] - (panelHeight - m_nCenterBgTallDefault) + 8 );
+ m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) );
+ }
+ else
+ {
+ // Hide anything to do with browsing the saves
+ ShowNoSaveGameUI();
+
+ }
+
+ // Do internal cleanup to make sure we present a correct state to the user
+ UpdateMenuComponents( SCROLL_NONE );
+ UpdateFooterOptions();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Do a fancy slide-out when we're first displayed
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::AnimateDialogStart( void )
+{
+ const float flAnimInTime = 0.5f;
+ const float flOffset = 0.1f;
+
+ for ( int i = 0; i < NUM_SLOTS; i++ )
+ {
+ if ( m_PanelIndex[i] == INVALID_INDEX )
+ continue;
+
+ // Start us at the "opening" position
+ CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[i] ];
+ if ( panel )
+ {
+ panel->SetPos( m_PanelXPos[0], m_PanelYPos[0] );
+ panel->SetAlpha( m_PanelAlpha[0] );
+ panel->SetVisible( true );
+ panel->SetEnabled( true );
+ panel->SetZPos( NUM_SLOTS - i );
+ }
+
+ // Now make them slide out where they're going
+ GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ }
+
+ // Move and fade the back label
+ m_pCenterBg->SetAlpha( 0 );
+ int nX, nY;
+ m_pCenterBg->GetPos( nX, nY );
+ m_pCenterBg->SetPos( nX-m_pCenterBg->GetWide(), nY );
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "xpos", nX, 0, flAnimInTime + (flOffset*2), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, (flAnimInTime+ (flOffset*2))*2.0f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ CGameSavePanel *selectedPanel = GetActivePanel();
+ if ( selectedPanel && selectedPanel->IsAutoSaveType() )
+ {
+ m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 );
+ }
+ else
+ {
+ m_pCenterBg->SetTall( m_nCenterBgTallDefault );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Do our initial layout
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::Activate( void )
+{
+ // Start scanning for saved games
+ ScanSavedGames( m_bFilterAutosaves );
+
+ // Finish our layout depending on what the result of the scan was
+ LayoutPanels();
+
+ // Animate the opening animation
+ AnimateDialogStart();
+
+ BaseClass::Activate();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Apply special properties of the menu
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ int ypos = inResourceData->GetInt( "chapterypos", 20 );
+ for ( int i = 0; i < NUM_SLOTS; ++i )
+ {
+ m_PanelYPos[i] = ypos;
+ }
+
+ m_nCenterBgTallDefault = inResourceData->GetInt( "centerbgtall", 0 );
+ m_pCenterBg->SetTall( m_nCenterBgTallDefault );
+
+ m_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f );
+ m_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f );
+ SetFastScroll( false );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Apply scheme settings
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ UpdateMenuComponents( SCROLL_NONE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the correct properties for visible components
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::UpdateMenuComponents( EScrollDirection dir )
+{
+ // This is called prior to any scrolling, so we need to look ahead to the post-scroll state
+ int centerIdx = SLOT_CENTER;
+
+ // Scroll given our direction of travel
+ if ( dir == SCROLL_LEFT )
+ {
+ ++centerIdx;
+ }
+ else if ( dir == SCROLL_RIGHT )
+ {
+ --centerIdx;
+ }
+
+ int leftIdx = centerIdx - 1;
+ int rightIdx = centerIdx + 1;
+
+ // Update the state of the side arrows depending on whether or not we can scroll that direction
+ vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" );
+ vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" );
+ if ( leftArrow )
+ {
+ leftArrow->SetVisible( true );
+ if ( m_PanelIndex[leftIdx] != INVALID_INDEX )
+ {
+ leftArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ }
+ else
+ {
+ leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
+ }
+ }
+ if ( rightArrow )
+ {
+ rightArrow->SetVisible( true );
+ if ( m_PanelIndex[rightIdx] != INVALID_INDEX )
+ {
+ rightArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
+ }
+ else
+ {
+ rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets a chapter as selected
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::SetSelectedSaveIndex( int index )
+{
+ m_iSelectedSave = index;
+
+ // If we have no panels, there's nothing to update
+ if ( HasActivePanels() == false )
+ return;
+
+ // Setup panels to the left of the selected panel
+ int currIdx = index;
+ for ( int i = SLOT_CENTER; i >= 0 && currIdx >= 0; --i )
+ {
+ m_PanelIndex[i] = currIdx;
+ --currIdx;
+ InitPanelIndexForDisplay( i );
+ }
+
+ // Setup panels to the right of the selected panel
+ currIdx = index + 1;
+ for ( int i = SLOT_CENTER + 1; i < NUM_SLOTS && currIdx < m_SavePanels.Count(); ++i )
+ {
+ m_PanelIndex[i] = currIdx;
+ ++currIdx;
+ InitPanelIndexForDisplay( i );
+ }
+
+ UpdateMenuComponents( SCROLL_NONE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove the currently selected animation from the list with proper animations
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::RemoveActivePanel( void )
+{
+ // Kill the current panel
+ m_nDeletedPanel = m_PanelIndex[SLOT_CENTER];
+
+ // Start our current panel fading
+ CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ];
+ GetAnimationController()->RunAnimationCommand( pPanel, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL );
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL );
+ PostMessage( this, new KeyValues( "FinishDelete" ), m_ScrollSpeed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::CloseAfterSave( void )
+{
+ OnCommand( "CloseAndSelectResume" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::FinishInsert( void )
+{
+ CGameSavePanel *panel = m_SavePanels[ m_nAddedPanel ];
+
+ const float flScrollSpeed = 0.75f;
+
+ // Run the actual movement
+ GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ PostMessage( this, new KeyValues( "CloseAfterSave" ), flScrollSpeed*2.0f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Insert a new panel at the desired location
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::AnimateInsertNewPanel( const SaveGameDescription_t *pDesc )
+{
+ // This is the panel that's going to move
+ CGameSavePanel *pNewPanel = SETUP_PANEL( new CGameSavePanel( this, (SaveGameDescription_t *) pDesc ) );
+ pNewPanel->SetVisible( false );
+
+ // Tack this onto the list
+ m_nAddedPanel = m_SavePanels.InsertAfter( 0, pNewPanel );
+
+ // Set it up but turn it off immediately
+ pNewPanel->SetPos( m_PanelXPos[SLOT_CENTER], m_PanelYPos[SLOT_CENTER] );
+ pNewPanel->SetVisible( true );
+ pNewPanel->SetEnabled( true );
+ pNewPanel->SetZPos( 0 );
+ pNewPanel->SetAlpha( 0.0f );
+
+ // Increment our indices to reflect the change
+ for ( int i = 0; i < NUM_SLOTS; i++ )
+ {
+ if ( m_PanelIndex[i] == INVALID_INDEX )
+ continue;
+
+ if ( m_PanelIndex[i] > 0 )
+ {
+ m_PanelIndex[i]++;
+ }
+ }
+
+ // Fade the right panel away
+ if ( IsValidPanel( m_PanelIndex[ SLOT_RIGHT ] ) )
+ {
+ CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ SLOT_RIGHT ] ];
+
+ // Run the actual movement
+ GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ PostMessage( this, new KeyValues( "FinishInsert" ), m_ScrollSpeed );
+ }
+ else
+ {
+ PostMessage( this, new KeyValues( "FinishInsert" ), 0.1f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Pop in the new description
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::FinishOverwriteFadeDown( void )
+{
+ const float flFadeInTime = 0.25f;
+
+ // Fade the right panel away
+ CGameSavePanel *pActivePanel = GetActivePanel();
+ if ( pActivePanel )
+ {
+ pActivePanel->SetDescription( &m_NewSaveGameDesc );
+
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", m_PanelAlpha[SLOT_CENTER], 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ }
+
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ PostMessage( this, new KeyValues( "CloseAfterSave" ), flFadeInTime + 0.1f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Animate an overwrite event by fading out the old panel and bringing it back with a new description
+// Input : *pNewDesc - The new description to display
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::AnimateOverwriteActivePanel( const SaveGameDescription_t *pNewDesc )
+{
+ // Save a copy of this description
+ m_NewSaveGameDesc = (*pNewDesc);
+
+ // Fade the right panel away
+ CGameSavePanel *pActivePanel = GetActivePanel();
+ if ( pActivePanel )
+ {
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ }
+
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ PostMessage( this, new KeyValues( "FinishOverwriteFadeDown" ), 0.75f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called before a panel scroll starts.
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PreScroll( EScrollDirection dir )
+{
+ int hideIdx = INVALID_INDEX;
+ if ( m_nDeletedPanel != INVALID_INDEX )
+ {
+ hideIdx = m_nDeletedPanel;
+ }
+ else if ( dir == SCROLL_LEFT )
+ {
+ hideIdx = m_PanelIndex[SLOT_LEFT];
+ }
+ else if ( dir == SCROLL_RIGHT )
+ {
+ hideIdx = m_PanelIndex[SLOT_RIGHT];
+ }
+
+ if ( hideIdx != INVALID_INDEX )
+ {
+ // Push back the panel that's about to be hidden
+ // so the next panel scrolls over the top of it.
+ m_SavePanels[hideIdx]->SetZPos( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called after a panel scroll finishes.
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PostScroll( EScrollDirection dir )
+{
+ // FIXME: Nothing to do here...
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initiates a panel scroll and starts the animation.
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ScrollSelectionPanels( EScrollDirection dir )
+{
+ // Only initiate a scroll if panels aren't currently scrolling
+ if ( !m_bScrolling )
+ {
+ // Handle any pre-scroll setup
+ PreScroll( dir );
+
+ if ( dir == SCROLL_LEFT)
+ {
+ m_ScrollCt += SCROLL_LEFT;
+ }
+ else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 )
+ {
+ m_ScrollCt += SCROLL_RIGHT;
+ }
+
+ m_bScrolling = true;
+ AnimateSelectionPanels();
+
+ // Update the arrow colors, help text, and buttons. Doing it here looks better than having
+ // the components change after the entire scroll animation has finished.
+ UpdateMenuComponents( m_ScrollDirection );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Do all slide animation work here
+// Input : nPanelIndex - Panel we're currently operating on
+// nNextPanelIndex - Panel we're going to be moving over
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PerformSlideAction( int nPanelIndex, int nNextPanelIndex )
+{
+ CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ nPanelIndex ] ];
+
+ // Run the actual movement
+ GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+ GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ // Panel alpha
+ GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Initiates the scripted scroll and fade effects of all five slotted panels
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::AnimateSelectionPanels( void )
+{
+ int idxOffset = 0;
+ int startIdx = SLOT_LEFT;
+ int endIdx = SLOT_RIGHT;
+
+ // Don't scroll outside the bounds of the panel list
+ if ( m_ScrollCt >= SCROLL_LEFT && m_PanelIndex[SLOT_CENTER] < m_SavePanels.Count() - 1 )
+ {
+ if ( m_nDeletedPanel != INVALID_INDEX )
+ {
+ startIdx = SLOT_RIGHT;
+ }
+
+ idxOffset = -1;
+ endIdx = SLOT_OFFRIGHT;
+ m_ScrollDirection = SCROLL_LEFT;
+ }
+ else if ( m_ScrollCt <= SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] > 0 )
+ {
+ idxOffset = 1;
+ startIdx = SLOT_OFFLEFT;
+ m_ScrollDirection = SCROLL_RIGHT;
+ }
+
+ if ( 0 == idxOffset )
+ {
+ // Kill the scroll, it's outside the bounds
+ m_ScrollCt = 0;
+ m_bScrolling = false;
+ m_ScrollDirection = SCROLL_NONE;
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ return;
+ }
+
+ // Should never happen
+ if ( startIdx > endIdx )
+ return;
+
+ for ( int i = startIdx; i <= endIdx; ++i )
+ {
+ // Don't animate the special panel, just skip it
+ if ( m_PanelIndex[i] == m_nDeletedPanel )
+ continue;
+
+ int nNextIdx = i+idxOffset;
+ if ( m_PanelIndex[i] != INVALID_INDEX )
+ {
+ PerformSlideAction( i, nNextIdx );
+ }
+ }
+
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+
+ // Animate the center background panel
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
+
+ // Scrolling up through chapters, offset is negative
+ m_iSelectedSave -= idxOffset;
+
+ UpdateFooterOptions();
+
+ PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: After a scroll, each panel slot holds the index of a panel that has
+// scrolled to an adjacent slot. This function updates each slot so
+// it holds the index of the panel that is actually in that slot's position.
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ShiftPanelIndices( int offset )
+{
+ // Shift all the elements over one slot, then calculate what the last slot's index should be.
+ int lastSlot = NUM_SLOTS - 1;
+
+ // Handle the deletion case
+ if ( m_nDeletedPanel != INVALID_INDEX )
+ {
+ // Scroll panels in from the right
+ Q_memmove( &m_PanelIndex[SLOT_CENTER], &m_PanelIndex[SLOT_RIGHT], 2* sizeof( m_PanelIndex[SLOT_CENTER] ) );
+
+ if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
+ {
+ int num = m_PanelIndex[ lastSlot ] + 1;
+ if ( IsValidPanel( num ) )
+ {
+ m_PanelIndex[lastSlot] = num;
+ InitPanelIndexForDisplay( lastSlot );
+ }
+ else
+ {
+ m_PanelIndex[lastSlot] = INVALID_INDEX;
+ }
+ }
+ }
+ else if ( offset > 0 )
+ {
+ // Hide the panel that's dropping out of the slots
+ if ( IsValidPanel( m_PanelIndex[0] ) )
+ {
+ m_SavePanels[ m_PanelIndex[0] ]->SetVisible( false );
+ }
+
+ // Scrolled panels to the right, so shift the indices one slot to the left
+ Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) );
+ if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
+ {
+ int num = m_PanelIndex[ lastSlot ] + 1;
+ if ( IsValidPanel( num ) )
+ {
+ m_PanelIndex[lastSlot] = num;
+ InitPanelIndexForDisplay( lastSlot );
+ }
+ else
+ {
+ m_PanelIndex[lastSlot] = INVALID_INDEX;
+ }
+ }
+ }
+ else
+ {
+ // Hide the panel that's dropping out of the slots
+ if ( IsValidPanel( m_PanelIndex[lastSlot] ) )
+ {
+ m_SavePanels[ m_PanelIndex[lastSlot] ]->SetVisible( false );
+ }
+
+ // Scrolled panels to the left, so shift the indices one slot to the right
+ Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) );
+ if ( m_PanelIndex[0] != INVALID_INDEX )
+ {
+ int num = m_PanelIndex[0] - 1;
+ if ( IsValidPanel( num ) )
+ {
+ m_PanelIndex[0] = num;
+ InitPanelIndexForDisplay( 0 );
+ }
+ else
+ {
+ m_PanelIndex[0] = INVALID_INDEX;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Validates an index into the selection panels vector
+//-----------------------------------------------------------------------------
+bool CSaveGameBrowserDialog::IsValidPanel( const int idx )
+{
+ if ( idx < 0 || idx >= m_SavePanels.Count() )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets up a panel's properties before it is displayed
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::InitPanelIndexForDisplay( const int idx )
+{
+ CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[idx] ];
+ if ( panel )
+ {
+ panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] );
+ panel->SetAlpha( m_PanelAlpha[idx] );
+ panel->SetVisible( true );
+ panel->SetEnabled( true );
+ if ( m_PanelAlpha[idx] )
+ {
+ panel->SetZPos( NUM_SLOTS );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets which scroll speed should be used
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::SetFastScroll( bool fast )
+{
+ m_ScrollSpeed = fast ? m_ScrollSpeedFast : m_ScrollSpeedSlow;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Checks if a button is being held down, and speeds up the scroll
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ContinueScrolling( void )
+{
+ if ( !GameUI().IsConsoleUI() )
+ {
+ if ( m_PanelIndex[SLOT_CENTER-1] % 3 )
+ {
+ ScrollSelectionPanels( m_ScrollDirection );
+ }
+ return;
+ }
+
+ if ( m_ButtonPressed == m_ScrollDirection )
+ {
+ SetFastScroll( true );
+ ScrollSelectionPanels( m_ScrollDirection );
+ }
+ else if ( m_ButtonPressed != SCROLL_NONE )
+ {
+ // The other direction has been pressed - start a slow scroll
+ SetFastScroll( false );
+ ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed );
+ }
+ else
+ {
+ SetFastScroll( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fade animation has finished, now slide or be done
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::FinishDelete( void )
+{
+ // Catch the case where all saves are now gone!
+ if ( m_SavePanels.Count() == 1 )
+ {
+ m_nDeletedPanel = INVALID_INDEX;
+ m_SavePanels.PurgeAndDeleteElements();
+
+ for ( int i = 0; i < NUM_SLOTS; i++ )
+ {
+ m_PanelIndex[i] = INVALID_INDEX;
+ }
+
+ LayoutPanels();
+ return;
+ }
+
+ EScrollDirection nDirection = ( IsValidPanel( m_nDeletedPanel + 1 ) ) ? SCROLL_LEFT : SCROLL_RIGHT;
+ ScrollSelectionPanels( nDirection );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when a scroll distance of one slot has been completed
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::FinishScroll( void )
+{
+ // Fade the center bg panel back in
+ GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ ShiftPanelIndices( m_ScrollDirection );
+ m_bScrolling = false;
+ m_ScrollCt = 0;
+
+ // End of scroll step
+ PostScroll( m_ScrollDirection );
+
+ if ( m_nDeletedPanel != INVALID_INDEX )
+ {
+ // Find where we're going next
+ int newSave = m_nDeletedPanel;
+ if ( m_SavePanels.IsValidIndex( m_nDeletedPanel + 1 ) == false )
+ {
+ newSave = m_nDeletedPanel - 1;
+ }
+
+ // Remove it from our list
+ CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ];
+ m_SavePanels.Remove( m_nDeletedPanel );
+ delete pPanel;
+
+ // Decrement all the indices to reflect the change
+ for ( int i = 0; i < NUM_SLOTS; i++ )
+ {
+ if ( m_PanelIndex[i] > m_nDeletedPanel )
+ m_PanelIndex[i]--;
+ }
+
+ // Clear the spot and be done with it
+ SetSelectedSaveIndex( newSave );
+ m_nDeletedPanel = INVALID_INDEX;
+ UpdateMenuComponents( SCROLL_NONE );
+ }
+
+ // Size the "autosave" blade if need-be
+ CGameSavePanel *selectedPanel = GetActivePanel();
+ if ( selectedPanel && selectedPanel->IsAutoSaveType() )
+ {
+ m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 );
+ }
+ else
+ {
+ m_pCenterBg->SetTall( m_nCenterBgTallDefault );
+ }
+
+ // Continue scrolling if necessary
+ ContinueScrolling();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::OnClose( void )
+{
+ SetControlDisabled( true );
+
+ m_KeyRepeat.Reset();
+ BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" );
+
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Our save games have changed, so layout our panel again
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::RefreshSaveGames( void )
+{
+ // Close any pending messages
+ BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
+
+ // Don't leave us in a locked state
+ SetControlDisabled( false );
+
+ // Re-scan the saved games
+ ScanSavedGames( m_bFilterAutosaves );
+
+ // Re-layout the panels
+ LayoutPanels();
+
+ // Run our animation again
+ AnimateDialogStart();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PerformSelectedAction( void )
+{
+ // By default, do nothing
+ m_KeyRepeat.Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PerformDeletion( void )
+{
+ // By default, do nothing
+ m_KeyRepeat.Reset();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Release our key repeater
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::OnKeyCodeReleased( vgui::KeyCode code )
+{
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update our keypress repeater
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::OnThink( void )
+{
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ OnKeyCodePressed( code );
+ }
+
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // If the console has UI up, then ignore it
+ if ( BasePanel()->IsWaitingForConsoleUI() )
+ return;
+
+ // Inhibit key activity during transitions
+ if ( GetAlpha() != 255 || m_bControlDisabled )
+ return;
+
+ m_KeyRepeat.KeyDown( code );
+
+ switch( code )
+ {
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+ PerformSelectedAction();
+ break;
+
+ case KEY_XBUTTON_B:
+ case STEAMCONTROLLER_B:
+ OnClose();
+ break;
+
+ case KEY_XBUTTON_X:
+ case STEAMCONTROLLER_X:
+ PerformDeletion();
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ BasePanel()->OnChangeStorageDevice();
+ break;
+
+ // Move the selection up and down
+ case KEY_XSTICK1_LEFT:
+ case KEY_XBUTTON_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ ScrollSelectionPanels( SCROLL_RIGHT );
+ break;
+
+ case KEY_XSTICK1_RIGHT:
+ case KEY_XBUTTON_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ ScrollSelectionPanels( SCROLL_LEFT );
+ break;
+
+ default:
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::PaintBackground( void )
+{
+ int wide, tall;
+ GetSize( wide, tall );
+
+ Color col = GetBgColor();
+ DrawBox( 0, 0, wide, tall, col, 1.0f );
+
+ int y = 32;
+
+ // draw an inset
+ Color darkColor;
+ darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() );
+ vgui::surface()->DrawSetColor( darkColor );
+ vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parses the save game info out of the .sav file header
+//-----------------------------------------------------------------------------
+bool CSaveGameBrowserDialog::ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t *save )
+{
+ char szMapName[SAVEGAME_MAPNAME_LEN];
+ char szComment[SAVEGAME_COMMENT_LEN];
+ char szElapsedTime[SAVEGAME_ELAPSED_LEN];
+
+ if ( !pszFileName || !pszShortName )
+ return false;
+
+ Q_strncpy( save->szShortName, pszShortName, sizeof(save->szShortName) );
+ Q_strncpy( save->szFileName, pszFileName, sizeof(save->szFileName) );
+
+ FileHandle_t fh = g_pFullFileSystem->Open( pszFileName, "rb", "MOD" );
+ if (fh == FILESYSTEM_INVALID_HANDLE)
+ return false;
+
+ save->iSize = g_pFullFileSystem->Size( fh );
+
+ int readok = SaveReadNameAndComment( fh, szMapName, sizeof(szMapName), szComment, sizeof(szComment) );
+ g_pFullFileSystem->Close(fh);
+
+ if ( !readok )
+ {
+ return false;
+ }
+
+ Q_strncpy( save->szMapName, szMapName, sizeof(save->szMapName) );
+
+ // Elapsed time is the last 6 characters in comment. (mmm:ss)
+ int i;
+ i = strlen( szComment );
+ Q_strncpy( szElapsedTime, "??", sizeof( szElapsedTime ) );
+ if (i >= 6)
+ {
+ Q_strncpy( szElapsedTime, (char *)&szComment[i - 6], 7 );
+ szElapsedTime[6] = '\0';
+
+ // parse out
+ int minutes = atoi( szElapsedTime );
+ int seconds = atoi( szElapsedTime + 4);
+ int hours = minutes / 60;
+ minutes %= 60;
+
+ wchar_t wzHours[6];
+ wchar_t wzMins[4];
+ wchar_t wzSecs[4];
+
+ _snwprintf( wzHours, ARRAYSIZE(wzHours), L"%d", hours );
+ _snwprintf( wzMins, ARRAYSIZE(wzMins), L"%d", minutes );
+ _snwprintf( wzSecs, ARRAYSIZE(wzSecs), L"%d", seconds );
+
+ wchar_t buf[20];
+
+ // reformat
+ if ( hours )
+ {
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Hr_Min" ), 2, wzHours, wzMins );
+ }
+ else if ( minutes )
+ {
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Min_Sec" ), 2, wzMins, wzSecs );
+ }
+ else
+ {
+ g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Sec" ), 1, wzSecs );
+ }
+
+ g_pVGuiLocalize->ConvertUnicodeToANSI( buf, szElapsedTime, sizeof(szElapsedTime) );
+
+ // Chop elapsed out of comment.
+ char *pChop = Q_stristr( szComment, " " );
+ if ( pChop != NULL )
+ {
+ (*pChop) = '\0';
+ }
+ }
+
+ // calculate the file name to print
+ const char *pszType = "";
+ if (strstr(pszFileName, "quick"))
+ {
+ pszType = "#GameUI_QuickSave";
+ }
+ else if (strstr(pszFileName, "autosave"))
+ {
+ pszType = "#GameUI_AutoSave";
+ }
+
+ Q_strncpy( save->szType, pszType, sizeof(save->szType) );
+ Q_strncpy( save->szComment, szComment, sizeof(save->szComment) );
+ Q_strncpy( save->szElapsedTime, szElapsedTime, sizeof(save->szElapsedTime) );
+
+ // Now get file time stamp.
+ long fileTime = g_pFullFileSystem->GetFileTime(pszFileName);
+ char szFileTime[32];
+ g_pFullFileSystem->FileTimeToString(szFileTime, sizeof(szFileTime), fileTime);
+ char *newline = strstr(szFileTime, "\n");
+ if (newline)
+ {
+ *newline = 0;
+ }
+ Q_strncpy( save->szFileTime, szFileTime, sizeof(save->szFileTime) );
+ save->iTimestamp = fileTime;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update our footer options depending on what we've selected
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::UpdateFooterOptions( void )
+{
+ // Do nothing
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sort our games by time
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::SortSaveGames( SaveGameDescription_t *pSaves, unsigned int nNumSaves )
+{
+ qsort( pSaves, nNumSaves, sizeof(SaveGameDescription_t), &CBaseSaveGameDialog::SaveGameSortFunc );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: builds save game list from directory
+//-----------------------------------------------------------------------------
+void CSaveGameBrowserDialog::ScanSavedGames( bool bIgnoreAutosave )
+{
+ // Start with a clean slate
+ m_nUsedStorageSpace = 0;
+ m_bSaveGameIsCorrupt = false;
+
+ // Clear all known panels I'm holding now
+ m_SavePanels.PurgeAndDeleteElements();
+
+ // Reset all indices
+ for ( int i = 0; i < NUM_SLOTS; ++i )
+ {
+ m_PanelIndex[i] = INVALID_INDEX;
+ }
+
+ // Clear our list
+ CUtlVector<SaveGameDescription_t> saveGames;
+
+ // Get the search path
+ char szDirectory[_MAX_PATH];
+
+ if ( IsX360() )
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s:/*", COM_GetModDirectory() );
+ else
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "save/*" );
+
+ Q_DefaultExtension( szDirectory, IsX360() ? ".360.sav" : ".sav", sizeof( szDirectory ) );
+ Q_FixSlashes( szDirectory );
+
+ // iterate the saved files
+ FileFindHandle_t handle;
+ const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle );
+ while (pFileName)
+ {
+ if ( !Q_strnicmp(pFileName, "HLSave", strlen( "HLSave" ) ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ char szFileName[_MAX_PATH];
+
+ if ( IsX360() )
+ Q_snprintf(szFileName, sizeof( szFileName ), "%s:/%s", COM_GetModDirectory(), pFileName );
+ else
+ Q_snprintf(szFileName, sizeof( szFileName ), "save/%s", pFileName);
+
+ Q_FixSlashes( szFileName );
+
+ // Only load save games from the current mod's save dir
+ if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ SaveGameDescription_t save;
+ if ( ParseSaveData( szFileName, pFileName, &save ) )
+ {
+ // Add on this file's size to the count
+ m_nUsedStorageSpace += save.iSize;
+
+ // Always ignore autosave dangerous (they're not considered safe until committed)
+ if ( Q_stristr( save.szShortName, "dangerous" ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+
+ // If we're ignoring autosaves, skip it here
+ if ( bIgnoreAutosave )
+ {
+ if ( !Q_stricmp( save.szType, "#GameUI_Autosave" ) )
+ {
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ continue;
+ }
+ }
+
+ saveGames.AddToTail( save );
+ }
+
+ pFileName = g_pFullFileSystem->FindNext( handle );
+ }
+
+ g_pFullFileSystem->FindClose( handle );
+
+ // Sort the save list
+ SortSaveGames( saveGames.Base(), saveGames.Count() );
+
+ // Now add them in order
+ for ( int i = 0; i < saveGames.Count(); i++ )
+ {
+ CGameSavePanel *savePanel = SETUP_PANEL( new CGameSavePanel( this, &saveGames[i] ) );
+
+ savePanel->SetVisible( false );
+ m_SavePanels.AddToTail( savePanel );
+ }
+
+ // Notify derived classes that save games are done being scanned
+ OnDoneScanningSaveGames();
+
+ // Always start with the first panel (as we're sorted in a specific order)
+ SetSelectedSaveIndex( 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Return the currently selected panel
+//-----------------------------------------------------------------------------
+CGameSavePanel *CSaveGameBrowserDialog::GetActivePanel( void )
+{
+ if ( IsValidPanel( m_iSelectedSave ) == false )
+ return NULL;
+
+ return m_SavePanels[ m_iSelectedSave ];
+}
diff --git a/gameui/SaveGameBrowserDialog.h b/gameui/SaveGameBrowserDialog.h
new file mode 100644
index 0000000..1e66f26
--- /dev/null
+++ b/gameui/SaveGameBrowserDialog.h
@@ -0,0 +1,193 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SAVEGAMEBROWSERDIALOG_H
+#define SAVEGAMEBROWSERDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui/IScheme.h"
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/KeyRepeat.h"
+
+#include "BasePanel.h"
+
+class CSaveGameBrowserDialog;
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: selectable item with screenshot for an individual chapter in the dialog
+//-----------------------------------------------------------------------------
+class CGameSavePanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CGameSavePanel, vgui::EditablePanel );
+
+public:
+
+ CGameSavePanel( CSaveGameBrowserDialog *parent, SaveGameDescription_t *pSaveDesc, bool bCommandPanel = false );
+ ~CGameSavePanel( void );
+
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+
+ bool IsAutoSaveType( void ) { return ( Q_stristr( m_SaveInfo.szType, "autosave" ) != 0 ); }
+
+ const SaveGameDescription_t *GetSaveInfo( void ) { return ( const SaveGameDescription_t * ) &m_SaveInfo; }
+ void SetDescription( SaveGameDescription_t *pDesc );
+
+protected:
+
+ SaveGameDescription_t m_SaveInfo; // Stored internally for easy access
+
+ ImagePanel *m_pLevelPicBorder;
+ ImagePanel *m_pLevelPic;
+ ImagePanel *m_pCommentaryIcon;
+ Label *m_pChapterTitle;
+ Label *m_pTime;
+ Label *m_pElapsedTime;
+ Label *m_pType;
+
+ Color m_TextColor;
+ Color m_DisabledColor;
+ Color m_SelectedColor;
+ Color m_FillColor;
+
+ bool m_bNewSavePanel;
+};
+
+// Slot indices in new game menu
+#define INVALID_INDEX -1
+#define SLOT_OFFLEFT 0
+#define SLOT_LEFT 1
+#define SLOT_CENTER 2
+#define SLOT_RIGHT 3
+#define SLOT_OFFRIGHT 4
+#define NUM_SLOTS 5
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles starting a new game, skill and chapter selection
+//-----------------------------------------------------------------------------
+class CSaveGameBrowserDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CSaveGameBrowserDialog, vgui::Frame );
+
+public:
+ MESSAGE_FUNC( FinishScroll, "FinishScroll" );
+ MESSAGE_FUNC( FinishDelete, "FinishDelete" );
+ MESSAGE_FUNC( FinishInsert, "FinishInsert" );
+ MESSAGE_FUNC( FinishOverwriteFadeDown, "FinishOverwriteFadeDown" );
+ MESSAGE_FUNC( CloseAfterSave, "CloseAfterSave" );
+
+ CSaveGameBrowserDialog(vgui::Panel *parent );
+ ~CSaveGameBrowserDialog();
+
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+ virtual void Activate( void );
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnClose( void );
+ virtual void PaintBackground();
+ virtual void PerformSelectedAction( void );
+ virtual void PerformDeletion( void );
+ virtual void UpdateFooterOptions( void );
+ virtual void SortSaveGames( SaveGameDescription_t *pSaves, unsigned int nNumSaves );
+ virtual void OnThink( void );
+ virtual void OnKeyCodeReleased( vgui::KeyCode code );
+ virtual void OnDoneScanningSaveGames( void ) {}
+ virtual void RefreshSaveGames( void );
+
+ unsigned int GetNumPanels( void ) { return m_SavePanels.Count(); }
+ bool HasActivePanels( void ) { return ( m_SavePanels.Count() != 0 ); }
+ CGameSavePanel *GetActivePanel( void );
+ int GetActivePanelIndex( void ) { return m_iSelectedSave; }
+ CFooterPanel *GetFooterPanel( void ) { return m_pFooter; }
+ const SaveGameDescription_t *GetPanelSaveDecription( int idx ) { return ( IsValidPanel(idx) ? m_SavePanels[idx]->GetSaveInfo() : NULL ); }
+ const SaveGameDescription_t *GetActivePanelSaveDescription( void ) { return GetPanelSaveDecription( m_iSelectedSave ); }
+
+ uint GetStorageSpaceUsed( void ) { return m_nUsedStorageSpace; }
+
+ void SetSelectedSaveIndex( int index );
+ void SetSelectedSave( const char *chapter );
+ void AddPanel( CGameSavePanel *pPanel ) { m_SavePanels.AddToHead( pPanel ); }
+
+ void RemoveActivePanel( void );
+ void AnimateInsertNewPanel( const SaveGameDescription_t *pDesc );
+ void AnimateOverwriteActivePanel( const SaveGameDescription_t *pNewDesc );
+
+ void SetControlDisabled( bool bState ) { m_bControlDisabled = bState; }
+
+ // Xbox: Defined values are also used to shift the slot indices
+ enum EScrollDirection
+ {
+ SCROLL_RIGHT = -1,
+ SCROLL_NONE = 0,
+ SCROLL_LEFT = 1
+ };
+ EScrollDirection m_ScrollDirection;
+
+protected:
+
+ bool m_bFilterAutosaves;
+ CKeyRepeatHandler m_KeyRepeat;
+
+ bool ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t *save );
+
+private:
+
+ CUtlVector<CGameSavePanel *> m_SavePanels;
+ int m_iSelectedSave;
+ float m_ScrollSpeedSlow;
+ float m_ScrollSpeedFast;
+ int m_nDeletedPanel; // Panel being subtracted
+ int m_nAddedPanel; // Panel being added
+ SaveGameDescription_t m_NewSaveGameDesc; // Held for panel animations
+ uint m_nUsedStorageSpace; // Amount of disk space used by save games
+
+ vgui::Panel *m_pCenterBg;
+ CFooterPanel *m_pFooter;
+
+ // Xbox
+ void ScrollSelectionPanels( EScrollDirection dir );
+ void PreScroll( EScrollDirection dir );
+ void PostScroll( EScrollDirection dir );
+ void SetFastScroll( bool fast );
+ void ContinueScrolling( void );
+ void AnimateSelectionPanels( void );
+ void ShiftPanelIndices( int offset );
+ bool IsValidPanel( const int idx );
+ void InitPanelIndexForDisplay( const int idx );
+ void UpdateMenuComponents( EScrollDirection dir );
+ void ScanSavedGames( bool bIgnoreAutosave );
+ void LayoutPanels( void );
+
+ // "No Save Games" label
+ void ShowNoSaveGameUI( void );
+ void HideNoSaveGameUI( void );
+ void PerformSlideAction( int nPanelIndex, int nNextPanelIndex );
+ void AnimateDialogStart( void );
+
+ int m_nCenterBgTallDefault;
+ int m_PanelXPos[ NUM_SLOTS ];
+ int m_PanelYPos[ NUM_SLOTS ];
+ float m_PanelAlpha[ NUM_SLOTS ];
+ int m_PanelIndex[ NUM_SLOTS ];
+ float m_ScrollSpeed;
+ int m_ButtonPressed;
+ int m_ScrollCt;
+ bool m_bScrolling : 1;
+ bool m_bSaveGameIsCorrupt : 1;
+ bool m_bControlDisabled : 1;
+};
+
+
+#endif // SAVEGAMEBROWSERDIALOG_H \ No newline at end of file
diff --git a/gameui/SaveGameDialog.cpp b/gameui/SaveGameDialog.cpp
new file mode 100644
index 0000000..7a572b4
--- /dev/null
+++ b/gameui/SaveGameDialog.cpp
@@ -0,0 +1,163 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "SaveGameDialog.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+
+#include "vgui/ISystem.h"
+#include "vgui/ISurface.h"
+#include "vgui/IVGui.h"
+
+#include "vgui_controls/Button.h"
+#include "vgui_controls/ListPanel.h"
+#include "vgui_controls/QueryBox.h"
+
+#include "KeyValues.h"
+#include "filesystem.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define NEW_SAVE_GAME_TIMESTAMP 0xFFFFFFFF
+
+//-----------------------------------------------------------------------------
+// Purpose:Constructor
+//-----------------------------------------------------------------------------
+CSaveGameDialog::CSaveGameDialog(vgui::Panel *parent) : BaseClass(parent, "SaveGameDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 512, 384);
+ SetSizeable( true );
+
+ SetTitle("#GameUI_SaveGame", true);
+
+ vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
+ cancel->SetCommand( "Close" );
+
+ LoadControlSettings("Resource\\SaveGameDialog.res");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CSaveGameDialog::~CSaveGameDialog()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Saves game
+//-----------------------------------------------------------------------------
+void CSaveGameDialog::OnCommand( const char *command )
+{
+ if ( !stricmp( command, "loadsave" ) )
+ {
+ int saveIndex = GetSelectedItemSaveIndex();
+ if ( m_SaveGames.IsValidIndex(saveIndex) )
+ {
+ // see if we're overwriting
+ if ( m_SaveGames[saveIndex].iTimestamp == NEW_SAVE_GAME_TIMESTAMP )
+ {
+ // new save game, proceed
+ OnCommand( "SaveOverwriteConfirmed" );
+ }
+ else
+ {
+ // open confirmation dialog
+ QueryBox *box = new QueryBox( "#GameUI_ConfirmOverwriteSaveGame_Title", "#GameUI_ConfirmOverwriteSaveGame_Info" );
+ box->AddActionSignalTarget(this);
+ box->SetOKButtonText("#GameUI_ConfirmOverwriteSaveGame_OK");
+ box->SetOKCommand(new KeyValues("Command", "command", "SaveOverwriteConfirmed"));
+ box->DoModal();
+ }
+ }
+ }
+ else if ( !stricmp( command, "SaveOverwriteConfirmed" ) )
+ {
+ int saveIndex = GetSelectedItemSaveIndex();
+ if ( m_SaveGames.IsValidIndex(saveIndex) )
+ {
+ // delete any existing save
+ DeleteSaveGame( m_SaveGames[saveIndex].szFileName );
+
+ // save to a new name
+ char saveName[128];
+ FindSaveSlot( saveName, sizeof(saveName) );
+ if ( saveName[ 0 ] )
+ {
+ // Load the game, return to top and switch to engine
+ char sz[ 256 ];
+ Q_snprintf(sz, sizeof( sz ), "save %s\n", saveName );
+
+ engine->ClientCmd_Unrestricted( sz );
+
+ // Close this dialog
+ Close();
+
+ // hide the UI
+ GameUI().HideGameUI();
+ }
+ }
+ }
+ else
+ {
+ BaseClass::OnCommand( command );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Opens the dialog and rebuilds the save list
+//-----------------------------------------------------------------------------
+void CSaveGameDialog::Activate()
+{
+ BaseClass::Activate();
+ ScanSavedGames();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: scans for save games
+//-----------------------------------------------------------------------------
+void CSaveGameDialog::OnScanningSaveGames()
+{
+ // create dummy item for current saved game
+ SaveGameDescription_t save = { "NewSavedGame", "", "", "#GameUI_NewSaveGame", "", "", "Current", NEW_SAVE_GAME_TIMESTAMP };
+ m_SaveGames.AddToTail(save);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: generates a new save game name
+//-----------------------------------------------------------------------------
+void CSaveGameDialog::FindSaveSlot( char *buffer, int bufsize )
+{
+ buffer[0] = 0;
+ char szFileName[512];
+ for (int i = 0; i < 1000; i++)
+ {
+ Q_snprintf(szFileName, sizeof( szFileName ), "save/half-life-%03i.sav", i );
+
+ FileHandle_t fp = g_pFullFileSystem->Open( szFileName, "rb" );
+ if (!fp)
+ {
+ // clean up name
+ Q_strncpy( buffer, szFileName + 5, bufsize );
+ char *ext = strstr( buffer, ".sav" );
+ if ( ext )
+ {
+ *ext = 0;
+ }
+ return;
+ }
+ g_pFullFileSystem->Close(fp);
+ }
+
+ Assert(!("Could not generate new save game file"));
+} \ No newline at end of file
diff --git a/gameui/SaveGameDialog.h b/gameui/SaveGameDialog.h
new file mode 100644
index 0000000..9557d42
--- /dev/null
+++ b/gameui/SaveGameDialog.h
@@ -0,0 +1,66 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SAVEGAMEDIALOG_H
+#define SAVEGAMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "BaseSaveGameDialog.h"
+#include "SaveGameBrowserDialog.h"
+#include "vgui_controls/KeyRepeat.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Save game dialog
+//-----------------------------------------------------------------------------
+class CSaveGameDialog : public CBaseSaveGameDialog
+{
+ DECLARE_CLASS_SIMPLE( CSaveGameDialog, CBaseSaveGameDialog );
+
+public:
+ CSaveGameDialog( vgui::Panel *parent );
+ ~CSaveGameDialog();
+
+ virtual void Activate();
+ static void FindSaveSlot( char *buffer, int bufsize );
+
+protected:
+ virtual void OnCommand( const char *command );
+ virtual void OnScanningSaveGames();
+};
+
+#define SAVE_NUM_ITEMS 4
+
+//
+//
+//
+class CAsyncCtxSaveGame;
+
+class CSaveGameDialogXbox : public CSaveGameBrowserDialog
+{
+ DECLARE_CLASS_SIMPLE( CSaveGameDialogXbox, CSaveGameBrowserDialog );
+
+public:
+ CSaveGameDialogXbox( vgui::Panel *parent );
+ virtual void PerformSelectedAction( void );
+ virtual void UpdateFooterOptions( void );
+ virtual void OnCommand( const char *command );
+ virtual void OnDoneScanningSaveGames( void );
+
+private:
+ friend class CAsyncCtxSaveGame;
+ void InitiateSaving();
+ void SaveCompleted( CAsyncCtxSaveGame *pCtx );
+
+private:
+ bool m_bGameSaving;
+ bool m_bNewSaveAvailable;
+ SaveGameDescription_t m_NewSaveDesc;
+};
+
+#endif // SAVEGAMEDIALOG_H
diff --git a/gameui/SaveGameDialog_Xbox.cpp b/gameui/SaveGameDialog_Xbox.cpp
new file mode 100644
index 0000000..610c0a0
--- /dev/null
+++ b/gameui/SaveGameDialog_Xbox.cpp
@@ -0,0 +1,295 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "BasePanel.h"
+#include "SaveGameDialog.h"
+
+#include "winlite.h" // FILETIME
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "vgui/ISystem.h"
+#include "vgui/IVGui.h"
+
+#include "vgui_controls/AnimationController.h"
+#include "vgui_controls/ImagePanel.h"
+#include "filesystem.h"
+#include "KeyValues.h"
+#include "ModInfo.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "vstdlib/random.h"
+
+#include "BaseSaveGameDialog.h"
+#include "SaveGameBrowserDialog.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#include "vgui_controls/Frame.h"
+#include "utlvector.h"
+
+extern const char *COM_GetModDirectory();
+
+using namespace vgui;
+
+CSaveGameDialogXbox::CSaveGameDialogXbox( vgui::Panel *parent )
+: BaseClass( parent ),
+ m_bGameSaving ( false ),
+ m_bNewSaveAvailable( false )
+{
+ m_bFilterAutosaves = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::PerformSelectedAction( void )
+{
+ BaseClass::PerformSelectedAction();
+
+ // If there are no panels, don't allow this
+ if ( GetNumPanels() == 0 )
+ return;
+
+ SetControlDisabled( true );
+
+ // Decide if this is an overwrite or a new save game
+ bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
+ if ( bNewSave )
+ {
+ OnCommand( "SaveGame" );
+ }
+ else
+ {
+ BasePanel()->ShowMessageDialog( MD_SAVE_OVERWRITE, this );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : bNewSaveSelected -
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::UpdateFooterOptions( void )
+{
+ CFooterPanel *pFooter = GetFooterPanel();
+
+ // Show available buttons
+ pFooter->ClearButtons();
+
+ bool bSavePanelsActive = ( GetNumPanels() != 0 );
+ if ( bSavePanelsActive )
+ {
+ bool bNewSaveSelected = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
+ if ( bNewSaveSelected )
+ {
+ pFooter->AddNewButtonLabel( "#GameUI_SaveGame_NewSave", "#GameUI_Icons_A_BUTTON" );
+ }
+ else
+ {
+ pFooter->AddNewButtonLabel( "#GameUI_SaveGame_Overwrite", "#GameUI_Icons_A_BUTTON" );
+ }
+ }
+
+ // Always available
+ pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
+ pFooter->AddNewButtonLabel( "#GameUI_Console_StorageChange", "#GameUI_Icons_Y_BUTTON" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: perfrom the save on a separate thread
+//-----------------------------------------------------------------------------
+class CAsyncCtxSaveGame : public CBasePanel::CAsyncJobContext
+{
+public:
+ explicit CAsyncCtxSaveGame( CSaveGameDialogXbox *pDlg );
+ ~CAsyncCtxSaveGame() {}
+
+public:
+ virtual void ExecuteAsync();
+ virtual void Completed();
+
+public:
+ char m_szFilename[MAX_PATH];
+ CSaveGameDialogXbox *m_pSaveGameDlg;
+};
+
+CAsyncCtxSaveGame::CAsyncCtxSaveGame( CSaveGameDialogXbox *pDlg ) :
+ CBasePanel::CAsyncJobContext( 3.0f ), // Storage device info for at least 3 seconds
+ m_pSaveGameDlg( pDlg )
+{
+ NULL;
+}
+
+void CAsyncCtxSaveGame::ExecuteAsync()
+{
+ // Sit and wait for the async save to finish
+ for ( ; ; )
+ {
+ if ( !engine->IsSaveInProgress() )
+ // Save operation is no longer in progress
+ break;
+ else
+ ThreadSleep( 50 );
+ }
+}
+
+void CAsyncCtxSaveGame::Completed()
+{
+ m_pSaveGameDlg->SaveCompleted( this );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: kicks off the async save (called on the main thread)
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::InitiateSaving()
+{
+ // Determine whether this is a new save or overwrite
+ bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
+
+ // Allocate the async context for saving
+ CAsyncCtxSaveGame *pAsyncCtx = new CAsyncCtxSaveGame( this );
+
+ // If this is an overwrite then there was an overwrite warning displayed
+ if ( !bNewSave )
+ BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
+ // Now display the saving warning
+ BasePanel()->ShowMessageDialog( MD_SAVING_WARNING, this );
+
+ // Kick off saving
+ char *szFilename = pAsyncCtx->m_szFilename;
+ const int maxFilenameLen = sizeof( pAsyncCtx->m_szFilename );
+ char szCmd[MAX_PATH];
+
+ // See if this is the "new save game" slot
+ if ( bNewSave )
+ {
+ // Create a new save game (name is created from the current time, which should be pretty unique)
+#ifdef WIN32
+ FILETIME currentTime;
+ GetSystemTimeAsFileTime( &currentTime );
+ Q_snprintf( szFilename, maxFilenameLen, "%s_%u", COM_GetModDirectory(), currentTime.dwLowDateTime );
+#else
+ time_t currentTime = time( NULL );
+ Q_snprintf( szFilename, maxFilenameLen, "%s_%u", COM_GetModDirectory(), (unsigned)currentTime );
+#endif
+ Q_snprintf( szCmd, sizeof( szCmd ), "xsave %s", szFilename );
+ engine->ExecuteClientCmd( szCmd );
+ Q_strncat( szFilename, ".360.sav", maxFilenameLen );
+ }
+ else
+ {
+ const SaveGameDescription_t *pDesc = GetActivePanelSaveDescription();
+ Q_strncpy( szFilename, pDesc->szShortName, maxFilenameLen );
+ Q_snprintf( szCmd, sizeof( szCmd ), "xsave %s", szFilename );
+ engine->ExecuteClientCmd( szCmd );
+ }
+
+ // Enqueue waiting
+ BasePanel()->ExecuteAsync( pAsyncCtx );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles the end of async save (called on the main thread)
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::SaveCompleted( CAsyncCtxSaveGame *pCtx )
+{
+ char const *szFilename = pCtx->m_szFilename;
+
+ // We should now be saved so get the new desciption back from the file
+ char szDirectory[MAX_PATH];
+ Q_snprintf( szDirectory, sizeof( szDirectory ), "%s:/%s", COM_GetModDirectory(), szFilename );
+
+ ParseSaveData( szDirectory, szFilename, &m_NewSaveDesc );
+
+ // Close the progress dialog
+ BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
+
+ bool bNewSave = ( GetActivePanelIndex() == 0 ) && m_bNewSaveAvailable;
+ if ( bNewSave )
+ {
+ AnimateInsertNewPanel( &m_NewSaveDesc );
+ }
+ else
+ {
+ AnimateOverwriteActivePanel( &m_NewSaveDesc );
+ }
+
+ m_bGameSaving = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: handles button commands
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::OnCommand( const char *command )
+{
+ m_KeyRepeat.Reset();
+
+ if ( !Q_stricmp( command, "SaveGame" ) )
+ {
+ if ( m_bGameSaving )
+ return;
+ m_bGameSaving = true;
+
+ SetControlDisabled( true );
+
+ // Initiate the saving operation
+ InitiateSaving();
+ }
+ else if ( !Q_stricmp( command, "SaveSuccess" ) )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+ GameUI().SetSavedThisMenuSession( true );
+ }
+ else if ( !Q_stricmp( command, "CloseAndSelectResume" ) )
+ {
+ BasePanel()->ArmFirstMenuItem();
+ OnCommand( "Close" );
+ }
+ else if ( !Q_stricmp( command, "OverwriteGameCancelled" ) )
+ {
+ SetControlDisabled( false );
+ }
+ else if ( !Q_stricmp( command, "RefreshSaveGames" ) )
+ {
+ RefreshSaveGames();
+ }
+ else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
+ {
+ vgui::surface()->RestrictPaintToSinglePanel( NULL );
+ }
+ else if ( !m_bGameSaving )
+ {
+ BaseClass::OnCommand(command);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: On completion of scanning, prepend a utility slot on the stack
+//-----------------------------------------------------------------------------
+void CSaveGameDialogXbox::OnDoneScanningSaveGames( void )
+{
+ ConVarRef save_history_count("save_history_count" );
+
+ m_bNewSaveAvailable = false;
+#ifdef _X360
+ if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED )
+ return;
+
+ // We only allow 10 save games minus the number of autosaves, autosavedangerous, and autosave0?'s at once
+ if ( GetNumPanels() >= 10 - ( 2 + (unsigned)save_history_count.GetInt() ) )
+ return;
+
+ if ( GetStorageSpaceUsed() + XBX_SAVEGAME_BYTES > XBX_PERSISTENT_BYTES_NEEDED )
+ return;
+
+ m_bNewSaveAvailable = true;
+ SaveGameDescription_t bogusDesc = { "#GameUI_SaveGame_NewSavedGame", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", "#GameUI_SaveGame_NewSave", 0, 0 };
+ CGameSavePanel *newSavePanel = SETUP_PANEL( new CGameSavePanel( this, &bogusDesc, true ) );
+ AddPanel( newSavePanel );
+#endif // _X360
+}
diff --git a/gameui/Sys_Utils.cpp b/gameui/Sys_Utils.cpp
new file mode 100644
index 0000000..44f77fe
--- /dev/null
+++ b/gameui/Sys_Utils.cpp
@@ -0,0 +1,180 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "winlite.h"
+#include "Sys_Utils.h"
+#include "EngineInterface.h"
+#include "tier0/vcrmode.h"
+
+#if defined( _X360 )
+#include "xbox/xbox_win32stubs.h"
+#endif
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+#ifdef WIN32
+const unsigned int SYS_NO_ERROR = NO_ERROR;
+const unsigned int SYS_ERROR_INVALID_HANDLE = ERROR_INVALID_HANDLE;
+
+void Sys_SetLastError(unsigned long error)
+{
+ ::SetLastError(error);
+}
+
+unsigned long Sys_GetLastError()
+{
+ return ::GetLastError();
+}
+
+
+WHANDLE Sys_CreateMutex(const char *mutexName)
+{
+ return (WHANDLE)::CreateMutex(NULL, FALSE, TEXT(mutexName));
+}
+
+void Sys_ReleaseMutex(WHANDLE mutexHandle)
+{
+ ::ReleaseMutex((HANDLE)mutexHandle);
+}
+
+
+const unsigned int SYS_WAIT_OBJECT_0 = WAIT_OBJECT_0;
+const unsigned int SYS_WAIT_ABANDONED = WAIT_ABANDONED;
+
+unsigned int Sys_WaitForSingleObject(WHANDLE mutexHandle, int milliseconds)
+{
+ return VCRHook_WaitForSingleObject((HANDLE)mutexHandle, milliseconds);
+}
+
+unsigned int Sys_RegisterWindowMessage(const char *msgName)
+{
+ return ::RegisterWindowMessage(msgName);
+}
+
+WHANDLE Sys_FindWindow(const char *className, const char *windowName)
+{
+ return (WHANDLE)::FindWindow(className, windowName);
+}
+
+void Sys_EnumWindows(void *callbackFunction, int lparam)
+{
+ ::EnumWindows((WNDENUMPROC)callbackFunction, lparam);
+}
+
+#ifndef _XBOX
+void Sys_GetWindowText(WHANDLE wnd, char *buffer, int bufferSize)
+{
+ ::GetWindowText((HWND)wnd, buffer, bufferSize - 1);
+}
+#endif
+
+void Sys_PostMessage(WHANDLE wnd, unsigned int msg, unsigned int wParam, unsigned int lParam)
+{
+ ::PostMessageA((HWND)wnd, msg, wParam, lParam);
+}
+
+#ifndef _XBOX
+void Sys_SetCursorPos(int x, int y)
+{
+ ::SetCursorPos(x, y);
+// engine->SetCursorPos(x,y); // SRC version
+}
+#endif
+
+#ifndef _XBOX
+static ATOM staticWndclassAtom = 0;
+static WNDCLASS staticWndclass = { NULL };
+#endif
+
+static LRESULT CALLBACK staticProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
+{
+ return DefWindowProc(hwnd,msg,wparam,lparam);
+}
+
+WHANDLE Sys_CreateWindowEx(const char *windowName)
+{
+ /*
+ if (!staticWndclassAtom)
+ {
+ memset( &staticWndclass,0,sizeof(staticWndclass) );
+ staticWndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;
+ staticWndclass.lpfnWndProc = staticProc;
+ staticWndclass.hInstance = GetModuleHandle(NULL);
+ staticWndclass.hIcon = 0;
+ staticWndclass.lpszClassName = windowName;
+ staticWndclassAtom = ::RegisterClass( &staticWndclass );
+
+ DWORD error = ::GetLastError();
+ }
+
+ return (WHANDLE)::CreateWindow(windowName, windowName, 0, 0, 0, 0, 0, 0, 0, GetModuleHandle(NULL), 0);
+ */
+ return (WHANDLE)1;
+}
+
+void Sys_DestroyWindow(WHANDLE wnd)
+{
+ //::DestroyWindow((HWND)wnd);
+}
+
+#elif defined( POSIX )
+const unsigned int SYS_NO_ERROR = 0;
+const unsigned int SYS_ERROR_INVALID_HANDLE = 0;
+const unsigned int SYS_WAIT_OBJECT_0 = 0;
+const unsigned int SYS_WAIT_ABANDONED = 0;
+
+
+void Sys_SetLastError(unsigned long error)
+{
+ errno = error;
+}
+
+unsigned long Sys_GetLastError()
+{
+ return errno;
+}
+
+
+WHANDLE Sys_CreateMutex(const char *mutexName)
+{
+ Assert( !"Implement me" );
+ return 0;
+}
+
+void Sys_ReleaseMutex(WHANDLE mutexHandle)
+{
+ Assert( !"Implement me" );
+}
+
+void Sys_PostMessage(WHANDLE wnd, unsigned int msg, unsigned int wParam, unsigned int lParam)
+{
+ Assert( !"Implement me" );
+}
+
+unsigned int Sys_RegisterWindowMessage(const char *msgName)
+{
+ Assert( !"Implement me" );
+ return 0;
+}
+
+unsigned int Sys_WaitForSingleObject(WHANDLE mutexHandle, int milliseconds)
+{
+ return SYS_WAIT_ABANDONED;
+}
+
+void Sys_EnumWindows(void *callbackFunction, int lparam)
+{
+ Assert( !"Implement me" );
+}
+
+
+#else
+#error
+#endif
+
diff --git a/gameui/Sys_Utils.h b/gameui/Sys_Utils.h
new file mode 100644
index 0000000..5880f73
--- /dev/null
+++ b/gameui/Sys_Utils.h
@@ -0,0 +1,49 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SYS_UTILS_H
+#define SYS_UTILS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+typedef int WHANDLE;
+
+// ERROR HANDLING
+extern const unsigned int SYS_NO_ERROR;
+extern const unsigned int SYS_ERROR_INVALID_HANDLE;
+
+void Sys_SetLastError(unsigned long error);
+unsigned long Sys_GetLastError();
+
+// MUTEX HANDLING
+WHANDLE Sys_CreateMutex(const char *mutexName);
+void Sys_ReleaseMutex(WHANDLE mutexHandle);
+
+// MUTEX SYNCHRONIZATION
+extern const unsigned int SYS_WAIT_OBJECT_0;
+extern const unsigned int SYS_WAIT_ABANDONED;
+unsigned int Sys_WaitForSingleObject(WHANDLE mutexHandle, int milliseconds);
+
+// window handling
+unsigned int Sys_RegisterWindowMessage(const char *msgName);
+WHANDLE Sys_FindWindow(const char *className, const char *windowName);
+void Sys_EnumWindows(void *callbackFunction, int lparam);
+void Sys_GetWindowText(WHANDLE wnd, char *buffer, int bufferSize);
+void Sys_PostMessage(WHANDLE wnd, unsigned int msg, unsigned int wParam, unsigned int lParam);
+WHANDLE Sys_CreateWindowEx(const char *windowName);
+void Sys_DestroyWindow(WHANDLE wnd);
+
+// mouse
+void Sys_SetCursorPos(int x, int y);
+
+
+
+
+
+
+#endif // SYS_UTILS_H
diff --git a/gameui/TGAImagePanel.cpp b/gameui/TGAImagePanel.cpp
new file mode 100644
index 0000000..927b401
--- /dev/null
+++ b/gameui/TGAImagePanel.cpp
@@ -0,0 +1,92 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "TGAImagePanel.h"
+#include "bitmap/tgaloader.h"
+#include "vgui/ISurface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+using namespace vgui;
+
+CTGAImagePanel::CTGAImagePanel( vgui::Panel *parent, const char *name ) : BaseClass( parent, name )
+{
+ m_iTextureID = -1;
+ m_bHasValidTexture = false;
+ m_bLoadedTexture = false;
+ m_szTGAName[0] = 0;
+
+ SetPaintBackgroundEnabled( false );
+}
+
+CTGAImagePanel::~CTGAImagePanel()
+{
+ // release the texture memory
+ if ( vgui::surface() && m_iTextureID != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iTextureID );
+ m_iTextureID = -1;
+ }
+}
+
+void CTGAImagePanel::SetTGA( const char *filename )
+{
+ Q_snprintf( m_szTGAName, sizeof(m_szTGAName), "//MOD/%s", filename );
+}
+
+void CTGAImagePanel::SetTGANonMod( const char *filename )
+{
+ V_strcpy_safe( m_szTGAName, filename );
+}
+
+void CTGAImagePanel::Paint()
+{
+ if ( !m_bLoadedTexture )
+ {
+ m_bLoadedTexture = true;
+ // get a texture id, if we haven't already
+ if ( m_iTextureID == -1 )
+ {
+ m_iTextureID = vgui::surface()->CreateNewTextureID( true );
+ SetSize( 180, 100 );
+ }
+
+ // load the file
+ CUtlMemory<unsigned char> tga;
+#ifndef _XBOX
+ if ( TGALoader::LoadRGBA8888( m_szTGAName, tga, m_iImageWidth, m_iImageHeight ) )
+ {
+ // set the textureID
+ surface()->DrawSetTextureRGBA( m_iTextureID, tga.Base(), m_iImageWidth, m_iImageHeight, false, true );
+ m_bHasValidTexture = true;
+ // set our size to be the size of the tga
+ SetSize( m_iImageWidth, m_iImageHeight );
+ }
+ else
+#endif
+ {
+ m_bHasValidTexture = false;
+ }
+ }
+
+ // draw the image
+ int wide, tall;
+ if ( m_bHasValidTexture )
+ {
+ surface()->DrawGetTextureSize( m_iTextureID, wide, tall );
+ surface()->DrawSetTexture( m_iTextureID );
+ surface()->DrawSetColor( 255, 255, 255, 255 );
+ surface()->DrawTexturedRect( 0, 0, wide, tall );
+ }
+ else
+ {
+ // draw a black fill instead
+ wide = 180, tall = 100;
+ surface()->DrawSetColor( 0, 0, 0, 255 );
+ surface()->DrawFilledRect( 0, 0, wide, tall );
+ }
+}
diff --git a/gameui/TGAImagePanel.h b/gameui/TGAImagePanel.h
new file mode 100644
index 0000000..1c8d36e
--- /dev/null
+++ b/gameui/TGAImagePanel.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef TGAIMAGEPANEL_H
+#define TGAIMAGEPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/Panel.h"
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: Displays a tga image
+//-----------------------------------------------------------------------------
+class CTGAImagePanel : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CTGAImagePanel, vgui::Panel );
+
+public:
+ CTGAImagePanel( vgui::Panel *parent, const char *name );
+
+ ~CTGAImagePanel();
+
+ void SetTGA( const char *filename );
+ void SetTGANonMod( const char *filename );
+
+ virtual void Paint( void );
+
+private:
+ int m_iTextureID;
+ int m_iImageWidth, m_iImageHeight;
+ bool m_bHasValidTexture, m_bLoadedTexture;
+ char m_szTGAName[256];
+};
+
+#endif //TGAIMAGEPANEL_H
diff --git a/gameui/TextEntryBox.cpp b/gameui/TextEntryBox.cpp
new file mode 100644
index 0000000..a78b48c
--- /dev/null
+++ b/gameui/TextEntryBox.cpp
@@ -0,0 +1,120 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+// Author: Matthew D. Campbell ([email protected]), 2003
+
+#include <vgui/KeyCode.h>
+
+#include "CvarTextEntry.h"
+#include "TextEntryBox.h"
+#include <vgui_controls/TextEntry.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+using namespace vgui;
+
+//--------------------------------------------------------------------------------------------------------------
+CTextEntryBox::CTextEntryBox(const char *title, const char *queryText, const char *entryText, bool isCvar, vgui::Panel *parent) : QueryBox(title, queryText,parent)
+{
+ if (isCvar)
+ {
+ m_pEntry = m_pCvarEntry = new CCvarTextEntry( this, "TextEntry", entryText );
+ }
+ else
+ {
+ m_pEntry = new TextEntry( this, "TextEntry" );
+ m_pCvarEntry = NULL;
+ }
+ m_pEntry->SetTabPosition(3);
+ m_pEntry->RequestFocus();
+ m_pEntry->GotoTextEnd();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+CTextEntryBox::~CTextEntryBox()
+{
+ delete m_pEntry;
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CTextEntryBox::ShowWindow(Frame *pFrameOver)
+{
+ BaseClass::ShowWindow( pFrameOver );
+
+ m_pEntry->RequestFocus();
+
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CTextEntryBox::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, wide, tall;
+ GetClientArea(x, y, wide, tall);
+ wide += x;
+ tall += y;
+
+ const int borderW = 10;
+
+ int labelW, labelH;
+ int entryW, entryH;
+ m_pMessageLabel->GetSize( labelW, labelH );
+
+ entryW = max(120, wide - borderW - borderW - borderW - labelW);
+ entryH = max(24, labelH);
+ m_pEntry->SetSize( entryW, entryH );
+
+ int boxWidth, boxTall;
+ GetSize(boxWidth, boxTall);
+ if (boxWidth < labelW + entryW + borderW*3)
+ SetSize( labelW + entryW + borderW*3, boxTall );
+
+ m_pMessageLabel->GetPos( x, y );
+ m_pMessageLabel->SetPos( borderW, y - (entryH - labelH)/2 );
+
+ m_pEntry->SetPos( borderW + m_pMessageLabel->GetWide() + borderW, y - (entryH - labelH) );
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CTextEntryBox::OnCommand(const char *command)
+{
+ if (!stricmp(command, "Ok"))
+ {
+ if (m_pCvarEntry)
+ {
+ m_pCvarEntry->ApplyChanges( true );
+ }
+ }
+
+ BaseClass::OnCommand(command);
+
+}
+
+//--------------------------------------------------------------------------------------------------------------
+void CTextEntryBox::OnKeyCodeTyped(KeyCode code)
+{
+ if (code == KEY_ESCAPE)
+ {
+ OnCommand("Cancel");
+ }
+ if (code == KEY_ENTER)
+ {
+ OnCommand("Ok");
+ }
+ else
+ {
+ BaseClass::OnKeyCodeTyped(code);
+ }
+}
+
diff --git a/gameui/TextEntryBox.h b/gameui/TextEntryBox.h
new file mode 100644
index 0000000..71626e0
--- /dev/null
+++ b/gameui/TextEntryBox.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+// Author: Matthew D. Campbell ([email protected]), 2003
+
+#ifndef TEXTENTRYBOX_H
+#define TEXTENTRYBOX_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "KeyValues.h"
+#include <vgui_controls/QueryBox.h>
+
+class CCvarTextEntry;
+
+//--------------------------------------------------------------------------------------------------------------
+/**
+ * Popup dialog with a text entry, extending the QueryBox, which extends the MessageBox
+ */
+class CTextEntryBox : public vgui::QueryBox
+{
+public:
+ CTextEntryBox(const char *title, const char *labelText, const char *entryText, bool isCvar, vgui::Panel *parent = NULL);
+
+ virtual ~CTextEntryBox();
+
+ virtual void PerformLayout(); ///< Layout override to position the label and text entry
+ virtual void ShowWindow(vgui::Frame *pFrameOver); ///< Show window override to give focus to text entry
+
+private:
+ typedef vgui::QueryBox BaseClass;
+
+protected:
+ CCvarTextEntry *m_pCvarEntry;
+ vgui::TextEntry *m_pEntry;
+
+ virtual void OnKeyCodeTyped(vgui::KeyCode code);
+ void OnCommand( const char *command); ///< Handle button presses
+};
+
+#endif // CVARTEXTENTRYBOX_H
diff --git a/gameui/URLButton.cpp b/gameui/URLButton.cpp
new file mode 100644
index 0000000..7ef031f
--- /dev/null
+++ b/gameui/URLButton.cpp
@@ -0,0 +1,622 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Basic button control
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdio.h>
+#include <utlsymbol.h>
+
+#include <vgui/IBorder.h>
+#include <vgui/IInput.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui/ISystem.h>
+#include <vgui/IVGui.h>
+#include <vgui/MouseCode.h>
+#include <vgui/KeyCode.h>
+#include <KeyValues.h>
+
+#include "URLButton.h"
+#include <vgui_controls/FocusNavGroup.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+DECLARE_BUILD_FACTORY_DEFAULT_TEXT( URLButton, URLButton );
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+URLButton::URLButton(Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, text)
+{
+ Init();
+ if ( pActionSignalTarget && pCmd )
+ {
+ AddActionSignalTarget( pActionSignalTarget );
+ SetCommand( pCmd );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+URLButton::URLButton(Panel *parent, const char *panelName, const wchar_t *wszText, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, wszText)
+{
+ Init();
+ if ( pActionSignalTarget && pCmd )
+ {
+ AddActionSignalTarget( pActionSignalTarget );
+ SetCommand( pCmd );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::Init()
+{
+ _buttonFlags.SetFlag( USE_CAPTURE_MOUSE | BUTTON_BORDER_ENABLED );
+
+ _mouseClickMask = 0;
+ _actionMessage = NULL;
+ m_bSelectionStateSaved = false;
+ SetTextInset(0, 0);
+ SetMouseClickEnabled( MOUSE_LEFT, true );
+ SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED);
+
+ // labels have this off by default, but we need it on
+ SetPaintBackgroundEnabled( true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+URLButton::~URLButton()
+{
+ if (_actionMessage)
+ {
+ _actionMessage->deleteThis();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::SetButtonActivationType(ActivationType_t activationType)
+{
+ _activationType = activationType;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set button border attribute enabled.
+//-----------------------------------------------------------------------------
+void URLButton::SetButtonBorderEnabled( bool state )
+{
+ if ( state != _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) )
+ {
+ _buttonFlags.SetFlag( BUTTON_BORDER_ENABLED, state );
+ InvalidateLayout(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set button selected state.
+//-----------------------------------------------------------------------------
+void URLButton::SetSelected( bool state )
+{
+ if ( _buttonFlags.IsFlagSet( SELECTED ) != state )
+ {
+ _buttonFlags.SetFlag( SELECTED, state );
+ RecalculateDepressedState();
+ InvalidateLayout(false);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set button force depressed state.
+//-----------------------------------------------------------------------------
+void URLButton::ForceDepressed(bool state)
+{
+ if ( _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) != state )
+ {
+ _buttonFlags.SetFlag( FORCE_DEPRESSED, state );
+ RecalculateDepressedState();
+ InvalidateLayout(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set button depressed state with respect to the force depressed state.
+//-----------------------------------------------------------------------------
+void URLButton::RecalculateDepressedState( void )
+{
+ bool newState;
+ if (!IsEnabled())
+ {
+ newState = false;
+ }
+ else
+ {
+ newState = _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) ? true : (_buttonFlags.IsFlagSet(ARMED) && _buttonFlags.IsFlagSet( SELECTED ) );
+ }
+
+ _buttonFlags.SetFlag( DEPRESSED, newState );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets whether or not the button captures all mouse input when depressed
+// Defaults to true
+// Should be set to false for things like menu items where there is a higher-level mouse capture
+//-----------------------------------------------------------------------------
+void URLButton::SetUseCaptureMouse( bool state )
+{
+ _buttonFlags.SetFlag( USE_CAPTURE_MOUSE, state );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check if mouse capture is enabled.
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool URLButton::IsUseCaptureMouseEnabled( void )
+{
+ return _buttonFlags.IsFlagSet( USE_CAPTURE_MOUSE );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set armed state.
+//-----------------------------------------------------------------------------
+void URLButton::SetArmed(bool state)
+{
+ if ( _buttonFlags.IsFlagSet( ARMED ) != state )
+ {
+ _buttonFlags.SetFlag( ARMED, state );
+ RecalculateDepressedState();
+ InvalidateLayout(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check armed state
+//-----------------------------------------------------------------------------
+bool URLButton::IsArmed()
+{
+ return _buttonFlags.IsFlagSet( ARMED );
+}
+
+
+KeyValues *URLButton::GetActionMessage()
+{
+ return _actionMessage->MakeCopy();
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Activate a button click.
+//-----------------------------------------------------------------------------
+void URLButton::DoClick()
+{
+ SetSelected(true);
+ FireActionSignal();
+ SetSelected(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check selected state
+//-----------------------------------------------------------------------------
+bool URLButton::IsSelected()
+{
+ return _buttonFlags.IsFlagSet( SELECTED );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check depressed state
+//-----------------------------------------------------------------------------
+bool URLButton::IsDepressed()
+{
+ return _buttonFlags.IsFlagSet( DEPRESSED );
+}
+
+
+//-----------------------------------------------------------------------------
+// Drawing focus box?
+//-----------------------------------------------------------------------------
+bool URLButton::IsDrawingFocusBox()
+{
+ return _buttonFlags.IsFlagSet( DRAW_FOCUS_BOX );
+}
+
+void URLButton::DrawFocusBox( bool bEnable )
+{
+ _buttonFlags.SetFlag( DRAW_FOCUS_BOX, bEnable );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Paint button on screen
+//-----------------------------------------------------------------------------
+void URLButton::Paint(void)
+{
+ BaseClass::Paint();
+
+ int x, y;
+ int controlWidth, controlHeight, textWidth, textHeight;
+ GetSize(controlWidth, controlHeight);
+ GetContentSize(textWidth, textHeight);
+ x = textWidth;
+ y = controlHeight - 4;
+
+ surface()->DrawSetColor(GetButtonFgColor());
+ surface()->DrawLine(0, y, x, y);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Perform graphical layout of button.
+//-----------------------------------------------------------------------------
+void URLButton::PerformLayout()
+{
+ // set our color
+ SetFgColor(GetButtonFgColor());
+ SetBgColor(GetButtonBgColor());
+
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get button foreground color
+// Output : Color
+//-----------------------------------------------------------------------------
+Color URLButton::GetButtonFgColor()
+{
+ return _defaultFgColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get button background color
+//-----------------------------------------------------------------------------
+Color URLButton::GetButtonBgColor()
+{
+ return _defaultBgColor;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called when key focus is received
+//-----------------------------------------------------------------------------
+void URLButton::OnSetFocus()
+{
+ InvalidateLayout(false);
+ BaseClass::OnSetFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Respond when focus is killed
+//-----------------------------------------------------------------------------
+void URLButton::OnKillFocus()
+{
+ InvalidateLayout(false);
+ BaseClass::OnKillFocus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::ApplySchemeSettings(IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings(pScheme);
+
+ _defaultFgColor = GetSchemeColor("Button.TextColor", Color(255, 255, 255, 255), pScheme);
+ _defaultBgColor = GetSchemeColor("Button.BgColor", Color(0, 0, 0, 255), pScheme);
+
+ InvalidateLayout();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Set button to be mouse clickable or not.
+//-----------------------------------------------------------------------------
+void URLButton::SetMouseClickEnabled(MouseCode code,bool state)
+{
+ if(state)
+ {
+ //set bit to 1
+ _mouseClickMask|=1<<((int)(code+1));
+ }
+ else
+ {
+ //set bit to 0
+ _mouseClickMask&=~(1<<((int)(code+1)));
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the command to send when the button is pressed
+//-----------------------------------------------------------------------------
+void URLButton::SetCommand( const char *command )
+{
+ SetCommand(new KeyValues("Command", "command", command));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the message to send when the button is pressed
+//-----------------------------------------------------------------------------
+void URLButton::SetCommand( KeyValues *message )
+{
+ // delete the old message
+ if (_actionMessage)
+ {
+ _actionMessage->deleteThis();
+ }
+
+ _actionMessage = message;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Peeks at the message to send when button is pressed
+// Input : -
+// Output : KeyValues
+//-----------------------------------------------------------------------------
+KeyValues *URLButton::GetCommand()
+{
+ return _actionMessage;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Message targets that the button has been pressed
+//-----------------------------------------------------------------------------
+void URLButton::FireActionSignal()
+{
+ // message-based action signal
+ if (_actionMessage)
+ {
+ // see if it's a url
+ if (!stricmp(_actionMessage->GetName(), "command")
+ && !strnicmp(_actionMessage->GetString("command", ""), "url ", strlen("url "))
+ && strstr(_actionMessage->GetString("command", ""), "://"))
+ {
+ // it's a command to launch a url, run it
+ system()->ShellExecute("open", _actionMessage->GetString("command", " ") + 4);
+ }
+ PostActionSignal(_actionMessage->MakeCopy());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gets info about the button
+//-----------------------------------------------------------------------------
+bool URLButton::RequestInfo(KeyValues *outputData)
+{
+ if (!stricmp(outputData->GetName(), "GetState"))
+ {
+ outputData->SetInt("state", IsSelected());
+ return true;
+ }
+ else if ( !stricmp( outputData->GetName(), "GetCommand" ))
+ {
+ if ( _actionMessage )
+ {
+ outputData->SetString( "command", _actionMessage->GetString( "command", "" ) );
+ }
+ else
+ {
+ outputData->SetString( "command", "" );
+ }
+ return true;
+ }
+
+
+ return BaseClass::RequestInfo(outputData);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get control settings for editing
+//-----------------------------------------------------------------------------
+void URLButton::GetSettings( KeyValues *outResourceData )
+{
+ BaseClass::GetSettings(outResourceData);
+
+ if (_actionMessage)
+ {
+ outResourceData->SetString("command", _actionMessage->GetString("command", ""));
+ }
+ outResourceData->SetInt("default", _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) );
+ if ( m_bSelectionStateSaved )
+ {
+ outResourceData->SetInt( "selected", IsSelected() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings(inResourceData);
+
+ const char *cmd = inResourceData->GetString("command", "");
+ if (*cmd)
+ {
+ // add in the command
+ SetCommand(cmd);
+ }
+
+ // saved selection state
+ int iSelected = inResourceData->GetInt( "selected", -1 );
+ if ( iSelected != -1 )
+ {
+ SetSelected( iSelected != 0 );
+ m_bSelectionStateSaved = true;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Describes editing details
+//-----------------------------------------------------------------------------
+const char *URLButton::GetDescription( void )
+{
+ static char buf[1024];
+ Q_snprintf(buf, sizeof(buf), "%s, string command, int default", BaseClass::GetDescription());
+ return buf;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnSetState(int state)
+{
+ SetSelected((bool)state);
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnCursorEntered()
+{
+ if (IsEnabled())
+ {
+ SetArmed(true);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnCursorExited()
+{
+ if ( !_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) )
+ {
+ SetArmed(false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnMousePressed(MouseCode code)
+{
+ if (!IsEnabled())
+ return;
+
+ if (_activationType == ACTIVATE_ONPRESSED)
+ {
+ if ( IsKeyBoardInputEnabled() )
+ {
+ RequestFocus();
+ }
+ DoClick();
+ return;
+ }
+
+
+ if (IsUseCaptureMouseEnabled() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
+ {
+ {
+ if ( IsKeyBoardInputEnabled() )
+ {
+ RequestFocus();
+ }
+ SetSelected(true);
+ Repaint();
+ }
+
+ // lock mouse input to going to this button
+ input()->SetMouseCapture(GetVPanel());
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnMouseDoublePressed(MouseCode code)
+{
+ OnMousePressed(code);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnMouseReleased(MouseCode code)
+{
+ // ensure mouse capture gets released
+ if (IsUseCaptureMouseEnabled())
+ {
+ input()->SetMouseCapture(NULL);
+ }
+
+ if (_activationType == ACTIVATE_ONPRESSED)
+ return;
+
+
+ if (!IsSelected() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
+ return;
+
+ // it has to be both enabled and (mouse over the button or using a key) to fire
+ if ( IsEnabled() && ( GetVPanel() == input()->GetMouseOver() || _buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) ) )
+ {
+ DoClick();
+ }
+ else
+ {
+ SetSelected(false);
+ }
+
+ // make sure the button gets unselected
+ Repaint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnKeyCodePressed(KeyCode code)
+{
+ if (code == KEY_SPACE || code == KEY_ENTER)
+ {
+ SetArmed(true);
+ _buttonFlags.SetFlag( BUTTON_KEY_DOWN );
+ OnMousePressed(MOUSE_LEFT);
+ if (IsUseCaptureMouseEnabled()) // undo the mouse capture since its a fake mouse click!
+ {
+ input()->SetMouseCapture(NULL);
+ }
+ }
+ else
+ {
+ _buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
+ BaseClass::OnKeyCodePressed(code);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void URLButton::OnKeyCodeReleased(KeyCode code)
+{
+ if (_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && (code == KEY_SPACE || code == KEY_ENTER))
+ {
+ SetArmed(true);
+ OnMouseReleased(MOUSE_LEFT);
+ }
+ else
+ {
+ BaseClass::OnKeyCodeReleased(code);
+ }
+ _buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
+ SetArmed(false);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Size the object to its button and text. - only works from in ApplySchemeSettings or PerformLayout()
+//-----------------------------------------------------------------------------
+void URLButton::SizeToContents()
+{
+ int wide, tall;
+ GetContentSize(wide, tall);
+ SetSize(wide + Label::Content, tall + Label::Content);
+}
+
diff --git a/gameui/URLButton.h b/gameui/URLButton.h
new file mode 100644
index 0000000..32f88a1
--- /dev/null
+++ b/gameui/URLButton.h
@@ -0,0 +1,171 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//===========================================================================//
+
+#ifndef URLBUTTON_H
+#define URLBUTTON_H
+
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui/VGUI.h>
+#include <vgui/Dar.h>
+#include <Color.h>
+#include <vgui_controls/Label.h>
+#include "vgui/MouseCode.h"
+
+namespace vgui
+{
+
+//-----------------------------------------------------------------------------
+// Purpose: A control that looks like a hyperlink, but behaves like a button.
+//-----------------------------------------------------------------------------
+class URLButton : public Label
+{
+ DECLARE_CLASS_SIMPLE( URLButton, Label );
+
+public:
+ // You can optionally pass in the panel to send the click message to and the name of the command to send to that panel.
+ URLButton(Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget=NULL, const char *pCmd=NULL);
+ URLButton(Panel *parent, const char *panelName, const wchar_t *text, Panel *pActionSignalTarget=NULL, const char *pCmd=NULL);
+ ~URLButton();
+private:
+ void Init();
+public:
+ // Set armed state.
+ virtual void SetArmed(bool state);
+ // Check armed state
+ virtual bool IsArmed( void );
+
+ // Check depressed state
+ virtual bool IsDepressed();
+ // Set button force depressed state.
+ virtual void ForceDepressed(bool state);
+ // Set button depressed state with respect to the force depressed state.
+ virtual void RecalculateDepressedState( void );
+
+ // Set button selected state.
+ virtual void SetSelected(bool state);
+ // Check selected state
+ virtual bool IsSelected( void );
+
+ //Set whether or not the button captures all mouse input when depressed.
+ virtual void SetUseCaptureMouse( bool state );
+ // Check if mouse capture is enabled.
+ virtual bool IsUseCaptureMouseEnabled( void );
+
+ // Activate a button click.
+ MESSAGE_FUNC( DoClick, "PressButton" );
+ MESSAGE_FUNC( OnHotkey, "Hotkey" )
+ {
+ DoClick();
+ }
+
+ // Set button to be mouse clickable or not.
+ virtual void SetMouseClickEnabled( MouseCode code, bool state );
+
+ // sets the how this button activates
+ enum ActivationType_t
+ {
+ ACTIVATE_ONPRESSEDANDRELEASED, // normal button behaviour
+ ACTIVATE_ONPRESSED, // menu buttons, toggle buttons
+ ACTIVATE_ONRELEASED, // menu items
+ };
+ virtual void SetButtonActivationType(ActivationType_t activationType);
+
+ // Message targets that the button has been pressed
+ virtual void FireActionSignal( void );
+ // Perform graphical layout of button
+ virtual void PerformLayout();
+
+ virtual bool RequestInfo(KeyValues *data);
+
+ // Respond when key focus is received
+ virtual void OnSetFocus();
+ // Respond when focus is killed
+ virtual void OnKillFocus();
+
+ // Set button border attribute enabled, controls display of button.
+ virtual void SetButtonBorderEnabled( bool state );
+
+ // Get button foreground color
+ virtual Color GetButtonFgColor();
+ // Get button background color
+ virtual Color GetButtonBgColor();
+
+ // Set the command to send when the button is pressed
+ // Set the panel to send the command to with AddActionSignalTarget()
+ virtual void SetCommand( const char *command );
+ // Set the message to send when the button is pressed
+ virtual void SetCommand( KeyValues *message );
+
+ /* CUSTOM MESSAGE HANDLING
+ "PressButton" - makes the button act as if it had just been pressed by the user (just like DoClick())
+ input: none
+ */
+
+ virtual void OnCursorEntered();
+ virtual void OnCursorExited();
+ virtual void SizeToContents();
+
+ virtual KeyValues *GetCommand();
+
+ bool IsDrawingFocusBox();
+ void DrawFocusBox( bool bEnable );
+
+protected:
+
+ // Paint button on screen
+ virtual void Paint(void);
+ // Get button border attributes.
+
+ virtual void ApplySchemeSettings(IScheme *pScheme);
+ MESSAGE_FUNC_INT( OnSetState, "SetState", state );
+
+ virtual void OnMousePressed(MouseCode code);
+ virtual void OnMouseDoublePressed(MouseCode code);
+ virtual void OnMouseReleased(MouseCode code);
+ virtual void OnKeyCodePressed(KeyCode code);
+ virtual void OnKeyCodeReleased(KeyCode code);
+
+ // Get control settings for editing
+ virtual void GetSettings( KeyValues *outResourceData );
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual const char *GetDescription( void );
+
+ KeyValues *GetActionMessage();
+
+private:
+ enum ButtonFlags_t
+ {
+ ARMED = 0x0001,
+ DEPRESSED = 0x0002,
+ FORCE_DEPRESSED = 0x0004,
+ BUTTON_BORDER_ENABLED = 0x0008,
+ USE_CAPTURE_MOUSE = 0x0010,
+ BUTTON_KEY_DOWN = 0x0020,
+ DEFAULT_BUTTON = 0x0040,
+ SELECTED = 0x0080,
+ DRAW_FOCUS_BOX = 0x0100,
+ BLINK = 0x0200,
+ ALL_FLAGS = 0xFFFF,
+ };
+
+ CUtlFlags< unsigned short > _buttonFlags; // see ButtonFlags_t
+ int _mouseClickMask;
+ KeyValues *_actionMessage;
+ ActivationType_t _activationType;
+
+
+ Color _defaultFgColor, _defaultBgColor;
+
+ bool m_bSelectionStateSaved;
+};
+
+} // namespace vgui
+
+#endif // URLBUTTON_H
diff --git a/gameui/VGuiSystemModuleLoader.cpp b/gameui/VGuiSystemModuleLoader.cpp
new file mode 100644
index 0000000..8078100
--- /dev/null
+++ b/gameui/VGuiSystemModuleLoader.cpp
@@ -0,0 +1,384 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include <stdio.h>
+
+#include "VGuiSystemModuleLoader.h"
+#include "Sys_Utils.h"
+#include "IVguiModule.h"
+#include "ServerBrowser/IServerBrowser.h"
+
+#include <vgui/IPanel.h>
+#include <vgui/ISystem.h>
+#include <vgui/IVGui.h>
+#include <vgui/ILocalize.h>
+#include <KeyValues.h>
+
+#include <vgui_controls/Controls.h>
+#include <vgui_controls/Panel.h>
+
+#include "filesystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+// instance of class
+CVGuiSystemModuleLoader g_VModuleLoader;
+
+#ifdef GAMEUI_EXPORTS
+extern vgui::VPANEL GetGameUIBasePanel();
+#else
+#include "../SteamUI/PlatformMainPanel.h"
+extern CPlatformMainPanel *g_pMainPanel;
+#endif
+
+bool bSteamCommunityFriendsVersion = false;
+
+#include <tier0/dbg.h>
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CVGuiSystemModuleLoader, IVGuiModuleLoader, VGUIMODULELOADER_INTERFACE_VERSION, g_VModuleLoader);
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CVGuiSystemModuleLoader::CVGuiSystemModuleLoader()
+{
+ m_bModulesInitialized = false;
+ m_bPlatformShouldRestartAfterExit = false;
+ m_pPlatformModuleData = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+CVGuiSystemModuleLoader::~CVGuiSystemModuleLoader()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if the module loader has acquired the platform mutex and loaded the modules
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::IsPlatformReady()
+{
+ return m_bModulesInitialized;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets up all the modules for use
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::InitializeAllModules(CreateInterfaceFn *factorylist, int factorycount)
+{
+ if ( IsX360() )
+ {
+ // not valid for 360
+ return false;
+ }
+
+ bool bSuccess = true;
+
+ // Init vgui in the modules
+ int i;
+ for ( i = 0; i < m_Modules.Count(); i++ )
+ {
+ if (!m_Modules[i].moduleInterface->Initialize(factorylist, factorycount))
+ {
+ bSuccess = false;
+ Error("Platform Error: module failed to initialize\n");
+ }
+ }
+
+ // create a table of all the loaded modules
+ CreateInterfaceFn *moduleFactories = (CreateInterfaceFn *)_alloca(sizeof(CreateInterfaceFn) * m_Modules.Count());
+ for ( i = 0; i < m_Modules.Count(); i++ )
+ {
+ moduleFactories[i] = Sys_GetFactory(m_Modules[i].module);
+ }
+
+ // give the modules a chance to link themselves together
+ for (i = 0; i < m_Modules.Count(); i++)
+ {
+ if (!m_Modules[i].moduleInterface->PostInitialize(moduleFactories, m_Modules.Count()))
+ {
+ bSuccess = false;
+ Error("Platform Error: module failed to initialize\n");
+ }
+
+#ifdef GAMEUI_EXPORTS
+ m_Modules[i].moduleInterface->SetParent(GetGameUIBasePanel());
+#else
+ m_Modules[i].moduleInterface->SetParent(g_pMainPanel->GetVPanel());
+#endif
+ }
+
+ m_bModulesInitialized = true;
+ return bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads and initializes all the modules specified in the platform file
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::LoadPlatformModules(CreateInterfaceFn *factorylist, int factorycount, bool useSteamModules)
+{
+ if ( IsX360() )
+ {
+ // not valid for 360
+ return false;
+ }
+
+ bool bSuccess = true;
+
+ // load platform menu
+ KeyValues *kv = new KeyValues("Platform");
+ if (!kv->LoadFromFile(g_pFullFileSystem, "steam/games/PlatformMenu.vdf", "PLATFORM"))
+ {
+ kv->deleteThis();
+ return false;
+ }
+
+ // walk the platform menu loading all the interfaces
+ KeyValues *menuKeys = kv->FindKey("Menu", true);
+ for (KeyValues *it = menuKeys->GetFirstSubKey(); it != NULL; it = it->GetNextKey())
+ {
+ // see if we should skip steam modules
+ if (!useSteamModules && it->GetInt("SteamApp"))
+ continue;
+
+ const char *pchInterface = it->GetString("interface");
+
+ // don't load friends if we are using Steam Community
+ if ( !Q_stricmp( pchInterface, "VGuiModuleTracker001" ) && bSteamCommunityFriendsVersion )
+ continue;
+
+ // get copy out of steam cache
+ const char *dllPath = NULL;
+ if ( IsOSX() )
+ {
+ dllPath = it->GetString("dll_osx");
+ }
+ else if ( IsLinux() )
+ {
+ dllPath = it->GetString("dll_linux");
+ }
+ else
+ {
+ dllPath = it->GetString("dll");
+ }
+
+
+ // load the module (LoadModule calls GetLocalCopy() under steam)
+ CSysModule *mod = g_pFullFileSystem->LoadModule(dllPath, "EXECUTABLE_PATH");
+ if (!mod)
+ {
+ Error("Platform Error: bad module '%s', not loading\n", it->GetString("dll"));
+ bSuccess = false;
+ continue;
+ }
+
+ // make sure we get the right version
+ IVGuiModule *moduleInterface = (IVGuiModule *)Sys_GetFactory(mod)(pchInterface, NULL);
+ if (!moduleInterface)
+ {
+ Warning("Platform Error: module version ('%s, %s) invalid, not loading\n", it->GetString("dll"), it->GetString("interface"));
+ bSuccess = false;
+ continue;
+ }
+
+ // store off the module
+ int newIndex = m_Modules.AddToTail();
+ m_Modules[newIndex].module = mod;
+ m_Modules[newIndex].moduleInterface = moduleInterface;
+ m_Modules[newIndex].data = it;
+ }
+
+ m_pPlatformModuleData = kv;
+ return InitializeAllModules(factorylist, factorycount) && bSuccess;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: gives all platform modules a chance to Shutdown gracefully
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::ShutdownPlatformModules()
+{
+ if ( IsX360() )
+ {
+ // not valid for 360
+ return;
+ }
+
+ // static include guard to prevent recursive calls
+ static bool runningFunction = false;
+ if (runningFunction)
+ return;
+
+ runningFunction = true;
+
+ // deactivate all the modules first
+ DeactivatePlatformModules();
+
+ // give all the modules notice of quit
+ int i;
+ for ( i = 0; i < m_Modules.Count(); i++ )
+ {
+ vgui::ivgui()->PostMessage(m_Modules[i].moduleInterface->GetPanel(), new KeyValues("Command", "command", "Quit"), NULL);
+ }
+
+ for ( i = 0; i < m_Modules.Count(); i++ )
+ {
+ m_Modules[i].moduleInterface->Shutdown();
+ }
+
+ runningFunction = false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Deactivates all the modules (puts them into in inactive but recoverable state)
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::DeactivatePlatformModules()
+{
+ for (int i = 0; i < m_Modules.Count(); i++)
+ {
+ m_Modules[i].moduleInterface->Deactivate();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Reenables all the deactivated platform modules
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::ReactivatePlatformModules()
+{
+ for (int i = 0; i < m_Modules.Count(); i++)
+ {
+ m_Modules[i].moduleInterface->Reactivate();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Disables and unloads platform
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::UnloadPlatformModules()
+{
+ for (int i = 0; i < m_Modules.Count(); i++)
+ {
+ g_pFullFileSystem->UnloadModule(m_Modules[i].module);
+ }
+
+ m_Modules.RemoveAll();
+
+ if (m_pPlatformModuleData)
+ {
+ m_pPlatformModuleData->deleteThis();
+ m_pPlatformModuleData = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Called every frame
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::RunFrame()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns number of modules loaded
+//-----------------------------------------------------------------------------
+int CVGuiSystemModuleLoader::GetModuleCount()
+{
+ return m_Modules.Count();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns the string menu name (unlocalized) of a module
+// moduleIndex is of the range [0, GetModuleCount())
+//-----------------------------------------------------------------------------
+const char *CVGuiSystemModuleLoader::GetModuleLabel(int moduleIndex)
+{
+ return m_Modules[moduleIndex].data->GetString("MenuName", "< unknown >");
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::IsModuleVisible(int moduleIndex)
+{
+ return vgui::ipanel()->IsVisible( m_Modules[moduleIndex].moduleInterface->GetPanel() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: brings the specified module to the foreground
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::IsModuleHidden(int moduleIndex)
+{
+ return m_Modules[moduleIndex].data->GetInt("Hidden", 0);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: brings the specified module to the foreground
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::ActivateModule(int moduleIndex)
+{
+ if (!m_Modules.IsValidIndex(moduleIndex))
+ return false;
+
+ m_Modules[moduleIndex].moduleInterface->Activate();
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: activates a module by name
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::ActivateModule(const char *moduleName)
+{
+ for (int i = 0; i < GetModuleCount(); i++)
+ {
+ if (!stricmp(GetModuleLabel(i), moduleName) || !stricmp(m_Modules[i].data->GetName(), moduleName))
+ {
+ ActivateModule(i);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns a modules interface factory
+//-----------------------------------------------------------------------------
+CreateInterfaceFn CVGuiSystemModuleLoader::GetModuleFactory(int moduleIndex)
+{
+ return Sys_GetFactory(m_Modules[moduleIndex].module);
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::PostMessageToAllModules(KeyValues *message)
+{
+ for (int i = 0; i < m_Modules.Count(); i++)
+ {
+ vgui::ivgui()->PostMessage(m_Modules[i].moduleInterface->GetPanel(), message->MakeCopy(), NULL);
+ }
+ message->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: sets the the platform should update and restart when it quits
+//-----------------------------------------------------------------------------
+void CVGuiSystemModuleLoader::SetPlatformToRestart()
+{
+ m_bPlatformShouldRestartAfterExit = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: data accessor
+//-----------------------------------------------------------------------------
+bool CVGuiSystemModuleLoader::ShouldPlatformRestart()
+{
+ return m_bPlatformShouldRestartAfterExit;
+}
diff --git a/gameui/VGuiSystemModuleLoader.h b/gameui/VGuiSystemModuleLoader.h
new file mode 100644
index 0000000..76493db
--- /dev/null
+++ b/gameui/VGuiSystemModuleLoader.h
@@ -0,0 +1,97 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Handles loading/unloading of different vgui modules into a shared context
+//
+//=============================================================================//
+
+#ifndef VGUISYSTEMMODULELOADER_H
+#define VGUISYSTEMMODULELOADER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "vgui_controls/PHandle.h"
+#include "utlvector.h"
+#include "IVGuiModuleLoader.h"
+
+class IVGuiModule;
+
+class KeyValues;
+
+//-----------------------------------------------------------------------------
+// Purpose: Handles loading/unloading of different vgui modules into a shared context
+//-----------------------------------------------------------------------------
+class CVGuiSystemModuleLoader : public IVGuiModuleLoader
+{
+public:
+ CVGuiSystemModuleLoader();
+ ~CVGuiSystemModuleLoader();
+
+ // loads all the modules in the platform
+ bool LoadPlatformModules(CreateInterfaceFn *factorylist, int factorycount, bool useSteamModules);
+
+ // returns true if the module loader has loaded the modules
+ bool IsPlatformReady();
+
+ // needs to be called every frame - updates all the modules states
+ void RunFrame();
+
+ // returns number of modules loaded
+ int GetModuleCount();
+
+ // returns the string menu name (unlocalized) of a module
+ // moduleIndex is of the range [0, GetModuleCount())
+ const char *GetModuleLabel(int moduleIndex);
+
+ bool IsModuleHidden(int moduleIndex);
+ bool IsModuleVisible(int moduleIndex);
+
+ // returns a modules interface factory
+ CreateInterfaceFn GetModuleFactory(int moduleIndex);
+
+ // brings the specified module to the foreground
+ bool ActivateModule(int moduleIndex);
+ bool ActivateModule(const char *moduleName);
+
+ // Deactivates all the modules (puts them into in inactive but recoverable state)
+ void DeactivatePlatformModules();
+
+ // Reenables all the deactivated platform modules
+ void ReactivatePlatformModules();
+
+ // shuts down all the platform modules
+ void ShutdownPlatformModules();
+
+ // unload all active platform modules/dlls from memory
+ void UnloadPlatformModules();
+
+ // posts a message to all active modules
+ void PostMessageToAllModules(KeyValues *message);
+
+ // sets the the platform should update and restart when it quits
+ void SetPlatformToRestart();
+
+ // returns true if the platform should restart after exit
+ bool ShouldPlatformRestart();
+
+private:
+ // sets up all the modules for use
+ bool InitializeAllModules(CreateInterfaceFn *factorylist, int factorycount);
+
+ bool m_bModulesInitialized;
+ bool m_bPlatformShouldRestartAfterExit;
+
+ struct module_t
+ {
+ CSysModule *module;
+ IVGuiModule *moduleInterface;
+ KeyValues *data;
+ };
+
+ CUtlVector<module_t> m_Modules;
+ KeyValues *m_pPlatformModuleData;
+};
+
+extern CVGuiSystemModuleLoader g_VModuleLoader;
+
+#endif // VGUISYSTEMMODULELOADER_H
diff --git a/gameui/gameui_util.cpp b/gameui/gameui_util.cpp
new file mode 100644
index 0000000..0339460
--- /dev/null
+++ b/gameui/gameui_util.cpp
@@ -0,0 +1,32 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+
+#include <stdarg.h>
+#include "gameui_util.h"
+#include "strtools.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Performs a var args printf into a static return buffer
+// Input : *format -
+// ... -
+// Output : char
+//-----------------------------------------------------------------------------
+char *VarArgs( const char *format, ... )
+{
+ va_list argptr;
+ static char string[1024];
+
+ va_start (argptr, format);
+ Q_vsnprintf (string, sizeof( string ), format,argptr);
+ va_end (argptr);
+
+ return string;
+}
diff --git a/gameui/gameui_util.h b/gameui/gameui_util.h
new file mode 100644
index 0000000..482d3fc
--- /dev/null
+++ b/gameui/gameui_util.h
@@ -0,0 +1,15 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#ifndef GAMEUI_UTIL_H
+#define GAMEUI_UTIL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+char *VarArgs( char *format, ... );
+
+#endif // GAMEUI_UTIL_H
diff --git a/gameui/matchmaking/achievementsdialog.cpp b/gameui/matchmaking/achievementsdialog.cpp
new file mode 100644
index 0000000..82931b2
--- /dev/null
+++ b/gameui/matchmaking/achievementsdialog.cpp
@@ -0,0 +1,1075 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Display a list of achievements for the current game
+//
+//=============================================================================//
+
+#include "achievementsdialog.h"
+#include "vgui_controls/Button.h"
+#include "vgui/ILocalize.h"
+#include "ixboxsystem.h"
+#include "iachievementmgr.h"
+#include "EngineInterface.h"
+#include "GameUI_Interface.h"
+#include "MouseMessageForwardingPanel.h"
+#include "filesystem.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/ComboBox.h"
+#include "vgui_controls/CheckButton.h"
+#include "vgui_controls/ScrollBar.h"
+#include "BasePanel.h"
+#include "fmtstr.h"
+#include "UtlSortVector.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+KeyValues *g_pPreloadedAchievementItemLayout = NULL;
+
+#define NUM_COMBO_BOX_LINES_DEFAULT 10
+#define NUM_COMBO_BOX_LINES_MAX 16
+
+// Shared helper functions so xbox and pc can share as much code as possible while coming from different bases.
+
+//-----------------------------------------------------------------------------
+// Purpose: Sets the parameter pIconPanel to display the specified achievement's icon file.
+//-----------------------------------------------------------------------------
+bool LoadAchievementIcon( vgui::ImagePanel* pIconPanel, IAchievement *pAchievement, const char *pszExt /*= NULL*/ )
+{
+ char imagePath[_MAX_PATH];
+ Q_strncpy( imagePath, "achievements\\", sizeof(imagePath) );
+ Q_strncat( imagePath, pAchievement->GetName(), sizeof(imagePath), COPY_ALL_CHARACTERS );
+ if ( pszExt )
+ {
+ Q_strncat( imagePath, pszExt, sizeof(imagePath), COPY_ALL_CHARACTERS );
+ }
+ Q_strncat( imagePath, ".vtf", sizeof(imagePath), COPY_ALL_CHARACTERS );
+
+ char checkFile[_MAX_PATH];
+ Q_snprintf( checkFile, sizeof(checkFile), "materials\\vgui\\%s", imagePath );
+ if ( !g_pFullFileSystem->FileExists( checkFile ) )
+ {
+ Q_snprintf( imagePath, sizeof(imagePath), "hud\\icon_locked.vtf" );
+ }
+
+ pIconPanel->SetShouldScaleImage( true );
+ pIconPanel->SetImage( imagePath );
+ pIconPanel->SetVisible( true );
+
+ return pIconPanel->IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// The bias is to ensure the percentage bar gets plenty orange before it reaches the text,
+// as the white-on-grey is hard to read.
+//-----------------------------------------------------------------------------
+Color LerpColors ( Color cStart, Color cEnd, float flPercent )
+{
+ float r = (float)((float)(cStart.r()) + (float)(cEnd.r() - cStart.r()) * Bias( flPercent, 0.75 ) );
+ float g = (float)((float)(cStart.g()) + (float)(cEnd.g() - cStart.g()) * Bias( flPercent, 0.75 ) );
+ float b = (float)((float)(cStart.b()) + (float)(cEnd.b() - cStart.b()) * Bias( flPercent, 0.75 ) );
+ float a = (float)((float)(cStart.a()) + (float)(cEnd.a() - cStart.a()) * Bias( flPercent, 0.75 ) );
+ return Color( r, g, b, a );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Shares common percentage bar calculations/color settings between xbox and pc.
+// Not really intended for robustness or reuse across many panels.
+// Input : pFrame - assumed to have certain child panels (see below)
+// *pAchievement - source achievement to poll for progress. Non progress achievements will not show a percentage bar.
+//-----------------------------------------------------------------------------
+void UpdateProgressBar( vgui::EditablePanel* pPanel, IAchievement *pAchievement, Color clrProgressBar )
+{
+ if ( pAchievement->GetGoal() > 1 )
+ {
+ bool bShowProgress = true;
+
+ // if this achievement gets saved with game and we're not in a level and have not achieved it, then we do not have any state
+ // for this achievement, don't show progress
+ if ( ( pAchievement->GetFlags() & ACH_SAVE_WITH_GAME ) && !GameUI().IsInLevel() && !pAchievement->IsAchieved() )
+ {
+ bShowProgress = false;
+ }
+
+ float flCompletion = 0.0f;
+
+ // Once achieved, we can't rely on count. If they've completed the achievement just set to 100%.
+ int iCount = pAchievement->GetCount();
+ if ( pAchievement->IsAchieved() )
+ {
+ flCompletion = 1.0f;
+ iCount = pAchievement->GetGoal();
+ }
+ else if ( bShowProgress )
+ {
+ flCompletion = ( ((float)pAchievement->GetCount()) / ((float)pAchievement->GetGoal()) );
+ // In rare cases count can exceed goal and not be achieved (switch local storage on X360, take saved game from different user on PC).
+ // These will self-correct with continued play, but if we're in that state don't show more than 100% achieved.
+ flCompletion = min( flCompletion, 1.f );
+ }
+
+ char szPercentageText[ 256 ] = "";
+ if ( bShowProgress )
+ {
+ Q_snprintf( szPercentageText, 256, "%d/%d", iCount, pAchievement->GetGoal() );
+ }
+
+ pPanel->SetControlString( "PercentageText", szPercentageText );
+ pPanel->SetControlVisible( "PercentageText", true );
+ pPanel->SetControlVisible( "CompletionText", true );
+
+ vgui::ImagePanel *pPercentageBar = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBar" );
+ vgui::ImagePanel *pPercentageBarBkg = (vgui::ImagePanel*)pPanel->FindChildByName( "PercentageBarBackground" );
+
+ if ( pPercentageBar && pPercentageBarBkg )
+ {
+ pPercentageBar->SetFillColor( clrProgressBar );
+ pPercentageBar->SetWide( pPercentageBarBkg->GetWide() * flCompletion );
+
+ pPanel->SetControlVisible( "PercentageBarBackground", IsX360() ? bShowProgress : true );
+ pPanel->SetControlVisible( "PercentageBar", true );
+ }
+ }
+}
+
+// TODO: revisit this once other games are rebuilt using the updated IAchievement interface
+bool GameSupportsAchievementTracker()
+{
+ const char *pGame = Q_UnqualifiedFileName( engine->GetGameDirectory() );
+ if ( ( Q_stricmp( pGame, "tf" ) == 0 ) || ( Q_stricmp( pGame, "tf_beta" ) == 0 ) )
+ return true;
+
+ return false;
+}
+
+
+//----------------------------------------------------------
+// CAchievementsDialog_XBox
+//----------------------------------------------------------
+
+CAchievementsDialog_XBox::CAchievementsDialog_XBox( vgui::Panel *pParent ) : BaseClass( pParent, "AchievementsDialog" )
+{
+ m_nTotalAchievements = 0;
+ m_nUnlocked = 0;
+ m_iSelection = 0;
+ m_iScroll = 0;
+ m_iNumItems = 0;
+ m_bCenterOnScreen = true;
+
+ m_pProgressBg = new vgui::Panel( this, "ProgressBg" );
+ m_pProgressBar = new vgui::Panel( this, "ProgressBar" );
+ m_pProgressPercent = new vgui::Label( this, "ProgressPercent", "" );
+ m_pNumbering = new vgui::Label( this, "Numbering", "" );
+ m_pUpArrow = new vgui::Label( this, "UpArrow", "" );
+ m_pDownArrow = new vgui::Label( this, "DownArrow", "" );
+
+ SetDeleteSelfOnClose(true);
+ SetSizeable( false );
+
+ m_pFooter = new CFooterPanel( pParent, "AchievementsFooter" );
+}
+
+CAchievementsDialog_XBox::~CAchievementsDialog_XBox()
+{
+ delete m_pProgressBg;
+ delete m_pProgressBar;
+ delete m_pProgressPercent;
+ delete m_pNumbering;
+ delete m_pUpArrow;
+ delete m_pDownArrow;
+
+ delete m_pFooter;
+}
+
+//----------------------------------------------------------
+// Position the dialogs elements
+//----------------------------------------------------------
+void CAchievementsDialog_XBox::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ // Avoid division by zero if the achievements haven't been downloaded yet
+ if ( m_nTotalAchievements )
+ {
+ int x, y, wide, tall;
+ m_pProgressBg->GetBounds( x, y, wide, tall );
+ int iBarX = GetWide() - wide - m_nBorderWidth;
+ int iBarWide = wide * m_nUnlocked / m_nTotalAchievements;
+ m_pProgressBg->SetBounds( iBarX, y, wide, tall );
+ m_pProgressBar->SetBounds( iBarX, y, iBarWide, tall );
+
+ wchar_t wszProgressText[64];
+#ifdef WIN32
+ V_snwprintf( wszProgressText, ARRAYSIZE(wszProgressText), L"%d%% %s", (m_nUnlocked * 100) / m_nTotalAchievements, g_pVGuiLocalize->Find( "#GameUI_Achievement_Unlocked" ) );
+#else
+ V_snwprintf( wszProgressText, ARRAYSIZE(wszProgressText), L"%d%% %S", (m_nUnlocked * 100) / m_nTotalAchievements, g_pVGuiLocalize->Find( "#GameUI_Achievement_Unlocked" ) );
+#endif
+ m_pProgressPercent->SetText( wszProgressText );
+ m_pProgressPercent->SizeToContents();
+ m_pProgressPercent->SetPos( GetWide() - m_pProgressPercent->GetWide() - m_nBorderWidth, y + tall + 3 );
+
+ int menux, menuy;
+ m_Menu.GetPos( menux, menuy );
+
+ // Do a perform layout on the menu so we get the correct height now
+ m_Menu.InvalidateLayout( true, false );
+
+ int iBottomOfTable = menuy + m_Menu.GetTall() + 3;
+
+ m_pNumbering->SizeToContents();
+ m_pNumbering->SetPos( m_nBorderWidth, iBottomOfTable );
+
+ m_pUpArrow->GetPos( x, y );
+ m_pUpArrow->SetPos( x, iBottomOfTable );
+ m_pDownArrow->GetPos( x, y );
+ m_pDownArrow->SetPos( x, iBottomOfTable );
+
+ wchar_t wszNumbering[64];
+ wchar_t *wzNumberingFmt = g_pVGuiLocalize->Find( "#GameUI_Achievement_Menu_Range" );
+ wchar_t wzActiveItem[8];
+ wchar_t wzTotal[8];
+ V_snwprintf( wzActiveItem, ARRAYSIZE( wzActiveItem ), L"%d", m_Menu.GetActiveItemIndex()+1 );
+ V_snwprintf( wzTotal, ARRAYSIZE( wzTotal ), L"%d", m_nTotalAchievements );
+ g_pVGuiLocalize->ConstructString( wszNumbering, sizeof( wszNumbering ), wzNumberingFmt, 2, wzActiveItem, wzTotal );
+ m_pNumbering->SetText( wszNumbering );
+ m_pNumbering->SetWide( GetWide() );
+ }
+
+ if ( m_bCenterOnScreen )
+ {
+ MoveToCenterOfScreen();
+ }
+
+ // Set the footer
+ m_pFooter->ClearButtons();
+
+ if ( m_pFooterInfo && ( m_pFooterInfo->GetInt( "hide_regular_footer", 0 ) > 0 ) == false )
+ {
+ for ( KeyValues *pButton = m_pFooterInfo->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() )
+ {
+ if ( !Q_stricmp( pButton->GetName(), "button" ) )
+ {
+ // Add a button to the footer
+ const char *pText = pButton->GetString( "text", "NULL" );
+ const char *pIcon = pButton->GetString( "icon", "NULL" );
+ m_pFooter->AddNewButtonLabel( pText, pIcon );
+ }
+ }
+ }
+}
+
+//----------------------------------------------------------
+// Query the system interface for this game's list of achievements
+//----------------------------------------------------------
+void CAchievementsDialog_XBox::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ m_bCenterOnScreen = pResourceData->GetInt( "center", 1 ) == 1;
+
+ if ( !achievementmgr )
+ {
+ AssertOnce( 0 && "No achievement manager interface in GameUI.dll" );
+ return;
+ }
+
+ achievementmgr->EnsureGlobalStateLoaded();
+
+ int iAllAchievements = achievementmgr->GetAchievementCount();
+
+ for ( int i = 0; i < iAllAchievements; ++i )
+ {
+ IAchievement* pCurAchievement = (IAchievement*)achievementmgr->GetAchievementByIndex( i );
+ Assert ( pCurAchievement );
+
+ if ( pCurAchievement->IsAchieved() )
+ ++m_nUnlocked;
+
+ // don't show hidden achievements if not achieved
+ if ( pCurAchievement->ShouldHideUntilAchieved() && !pCurAchievement->IsAchieved() )
+ continue;
+
+ CAchievementItem *pItem = m_Menu.AddAchievementItem( ACHIEVEMENT_LOCALIZED_NAME( pCurAchievement ),
+ ACHIEVEMENT_LOCALIZED_DESC( pCurAchievement ),
+ pCurAchievement->GetPointValue(),
+ pCurAchievement->IsAchieved(),
+ pCurAchievement
+ );
+
+ SETUP_PANEL( pItem );
+ }
+
+ m_nTotalAchievements = m_Menu.GetItemCount();
+}
+
+//----------------------------------------------------------
+// Add the progress bar and update the dialog layout
+//----------------------------------------------------------
+void CAchievementsDialog_XBox::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pProgressBg->SetBgColor( Color( 200, 184, 151, 255 ) );
+ m_pProgressBar->SetBgColor( Color( 179, 82, 22, 255 ) );
+ m_pProgressPercent->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+ m_pNumbering->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Scrolling up and down with up/down, exit to main menu with back button
+//-----------------------------------------------------------------------------
+void CAchievementsDialog_XBox::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // Handle close here, CBasePanel parent doesn't support "DialogClosing" command
+ if ( GetBaseButtonCode( code ) == KEY_XBUTTON_B )
+ {
+ OnCommand( "AchievementsDialogClosing" );
+ SetDeleteSelfOnClose( true );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: catch key repeats
+//-----------------------------------------------------------------------------
+void CAchievementsDialog_XBox::HandleKeyRepeated( vgui::KeyCode code )
+{
+ BaseClass::HandleKeyRepeated( code );
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Fade main menu back in when this dialog closes.
+//-----------------------------------------------------------------------------
+void CAchievementsDialog_XBox::OnClose()
+{
+ BasePanel()->RunCloseAnimation( "CloseAchievementsDialog_OpenMainMenu" );
+ BaseClass::OnClose();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// PC Implementation
+//////////////////////////////////////////////////////////////////////////
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CAchievementsDialog::CAchievementsDialog(vgui::Panel *parent) : BaseClass(parent, "AchievementsDialog")
+{
+ SetDeleteSelfOnClose(true);
+ SetBounds(0, 0, 512, 384);
+ SetMinimumSize( 256, 300 );
+ SetSizeable( true );
+
+ m_nOldScrollItem = -1;
+ m_nScrollItem = -1;
+
+ m_nUnlocked = 0;
+ m_nTotalAchievements = 0;
+
+ m_pAchievementsList = new vgui::PanelListPanel( this, "listpanel_achievements" );
+ m_pAchievementsList->SetFirstColumnWidth( 0 );
+
+ m_pListBG = new vgui::ImagePanel( this, "listpanel_background" );
+
+ m_pPercentageBarBackground = SETUP_PANEL( new ImagePanel( this, "PercentageBarBackground" ) );
+ m_pPercentageBar = SETUP_PANEL( new ImagePanel( this, "PercentageBar" ) );
+
+ m_pSelectionHighlight = new ImagePanel( m_pAchievementsList->FindChildByName( "PanelListEmbedded" ), "SelectionHighlight" );
+ m_pSelectionHighlight->SetVisible( false );
+ m_pSelectionHighlight->SetZPos( 100 );
+
+ m_pAchievementPackCombo = new ComboBox(this, "achievement_pack_combo", NUM_COMBO_BOX_LINES_DEFAULT, false);
+ m_pHideAchievedCheck = new vgui::CheckButton( this, "HideAchieved", "" );
+
+ // int that holds the highest number achievement id we've found
+ int iHighestAchievementIDSeen = -1;
+ int iNextGroupBoundary = 1000;
+
+ Q_memset( m_AchievementGroups, 0, sizeof(m_AchievementGroups) );
+ m_iNumAchievementGroups = 0;
+
+ // Base groups
+// CreateNewAchievementGroup( 0, 16000 );
+ CreateNewAchievementGroup( 0, 999 );
+
+ Assert ( achievementmgr );
+ if ( achievementmgr )
+ {
+ int iCount = achievementmgr->GetAchievementCount();
+ for ( int i = 0; i < iCount; ++i )
+ {
+ IAchievement* pCur = achievementmgr->GetAchievementByIndex( i );
+
+ if ( !pCur )
+ continue;
+
+ int iAchievementID = pCur->GetAchievementID();
+
+ if ( iAchievementID > iHighestAchievementIDSeen )
+ {
+ // if its crossed the next group boundary, create a new group
+ if ( iAchievementID >= iNextGroupBoundary )
+ {
+ int iNewGroupBoundary = 100 * ( (int)( (float)iAchievementID / 100 ) );
+ CreateNewAchievementGroup( iNewGroupBoundary, iNewGroupBoundary+99 );
+
+ iNextGroupBoundary = iNewGroupBoundary + 100;
+ }
+
+ iHighestAchievementIDSeen = iAchievementID;
+ }
+
+ // don't show hidden achievements if not achieved
+ if ( pCur->ShouldHideUntilAchieved() && !pCur->IsAchieved() )
+ continue;
+
+ m_nTotalAchievements++;
+
+ if ( m_pHideAchievedCheck->IsSelected() && pCur->IsAchieved() )
+ continue;
+
+ bool bAchieved = pCur->IsAchieved();
+
+ if ( bAchieved )
+ {
+ ++m_nUnlocked;
+ }
+
+ for ( int j=0;j<m_iNumAchievementGroups;j++ )
+ {
+ if ( iAchievementID >= m_AchievementGroups[j].m_iMinRange &&
+ iAchievementID <= m_AchievementGroups[j].m_iMaxRange )
+ {
+ if ( bAchieved )
+ {
+ m_AchievementGroups[j].m_iNumUnlocked++;
+ }
+
+ m_AchievementGroups[j].m_iNumAchievements++;
+ }
+ }
+ }
+ }
+
+ CreateOrUpdateComboItems( true );
+
+ m_pAchievementPackCombo->ActivateItemByRow( 0 );
+}
+
+CAchievementsDialog::~CAchievementsDialog()
+{
+ if ( achievementmgr )
+ {
+ achievementmgr->SaveGlobalStateIfDirty( false ); // check for saving here to store achievements we want pinned to HUD
+ }
+
+ m_pAchievementsList->DeleteAllItems();
+ delete m_pAchievementsList;
+ delete m_pPercentageBarBackground;
+ delete m_pPercentageBar;
+}
+
+void CAchievementsDialog::OnCheckButtonChecked(Panel *panel)
+{
+ if ( panel == m_pHideAchievedCheck )
+ {
+ UpdateAchievementList();
+ }
+}
+
+void CAchievementsDialog::CreateNewAchievementGroup( int iMinRange, int iMaxRange )
+{
+ if ( m_iNumAchievementGroups < MAX_ACHIEVEMENT_GROUPS )
+ {
+ m_AchievementGroups[m_iNumAchievementGroups].m_iMinRange = iMinRange;
+ m_AchievementGroups[m_iNumAchievementGroups].m_iMaxRange = iMaxRange;
+ m_iNumAchievementGroups++;
+ }
+ else
+ {
+ AssertMsg( false, "CAchievementsDialog: Too many achievement groups" );
+ }
+}
+
+//----------------------------------------------------------
+// Get the width we're going to lock at
+//----------------------------------------------------------
+void CAchievementsDialog::ApplySettings( KeyValues *pResourceData )
+{
+ m_iFixedWidth = pResourceData->GetInt( "wide", 512 );
+
+ BaseClass::ApplySettings( pResourceData );
+}
+
+//----------------------------------------------------------
+// Preserve our width to the one in the .res file
+//----------------------------------------------------------
+void CAchievementsDialog::OnSizeChanged(int newWide, int newTall)
+{
+ // Lock the width, but allow height scaling
+ if ( newWide != m_iFixedWidth )
+ {
+ SetSize( m_iFixedWidth, newTall );
+ return;
+ }
+
+ BaseClass::OnSizeChanged(newWide, newTall);
+}
+
+//----------------------------------------------------------
+// New group was selected in the dropdown, recalc what achievements to show
+//----------------------------------------------------------
+void CAchievementsDialog::OnTextChanged(KeyValues *data)
+{
+ Panel *pPanel = (Panel *)data->GetPtr( "panel", NULL );
+
+ // first check which control had its text changed!
+ if ( pPanel == m_pAchievementPackCombo )
+ {
+ UpdateAchievementList();
+ }
+}
+
+class CAchievementsLess
+{
+public:
+ bool Less( const IAchievement* src1, const IAchievement* src2, void *pCtx )
+ {
+ IAchievement* _src1 = const_cast<IAchievement*>(src1);
+ IAchievement* _src2 = const_cast<IAchievement*>(src2);
+
+ if ( _src1->IsAchieved() && !_src2->IsAchieved() )
+ return false;
+ if ( !_src1->IsAchieved() && _src2->IsAchieved() )
+ return true;
+
+ const char* name1 = _src1->GetName();
+ const char* name2 = _src2->GetName();
+ if ( wcscoll( ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( name1 ), ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( name2 ) ) < 0 )
+ return true;
+ return false;
+ }
+};
+
+//----------------------------------------------------------
+// Re-populate the achievement list with the selected group
+//----------------------------------------------------------
+void CAchievementsDialog::UpdateAchievementList()
+{
+ m_pAchievementsList->DeleteAllItems();
+
+ KeyValues *pData = m_pAchievementPackCombo->GetActiveItemUserData();
+
+ if ( pData )
+ {
+ int iMinRange = pData->GetInt( "minrange" );
+ int iMaxRange = pData->GetInt( "maxrange" );
+
+ if ( achievementmgr )
+ {
+ CUtlSortVector<IAchievement*, CAchievementsLess> achievements;
+
+ int iCount = achievementmgr->GetAchievementCount();
+ for ( int i = 0; i < iCount; ++i )
+ {
+ IAchievement* pCur = achievementmgr->GetAchievementByIndex( i );
+
+ if ( !pCur )
+ continue;
+
+ int iAchievementID = pCur->GetAchievementID();
+
+ if ( iAchievementID < iMinRange || iAchievementID > iMaxRange )
+ continue;
+
+ // don't show hidden achievements if not achieved
+ if ( pCur->ShouldHideUntilAchieved() && !pCur->IsAchieved() )
+ continue;
+
+ if ( m_pHideAchievedCheck->IsSelected() && pCur->IsAchieved() )
+ continue;
+
+ // if we don't have a localized name, don't add it to the list
+ if ( pCur->GetName() == NULL || ACHIEVEMENT_LOCALIZED_NAME_FROM_STR( pCur->GetName() ) == NULL )
+ continue;
+
+ achievements.Insert( pCur );
+ }
+
+ for ( int i=0; i<achievements.Count(); i++ )
+ {
+ CAchievementDialogItemPanel *achievementItemPanel = new CAchievementDialogItemPanel( m_pAchievementsList, "AchievementDialogItemPanel", i );
+ achievementItemPanel->SetAchievementInfo( achievements[i] );
+ m_pAchievementsList->AddItem( NULL, achievementItemPanel );
+ }
+ }
+ }
+
+ if ( m_pAchievementsList->GetItemCount() > 0 )
+ {
+ m_nOldScrollItem = -1;
+ m_nScrollItem = -1;
+ m_pSelectionHighlight->SetVisible( false );
+ m_pAchievementsList->ScrollToItem( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from achievementsdialog.res in hl2/resource/ui/
+// Sets up progress bar displaying total achievement unlocking progress by the user.
+//-----------------------------------------------------------------------------
+void CAchievementsDialog::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ LoadControlSettings("resource/ui/AchievementsDialog.res");
+
+ if ( !achievementmgr )
+ {
+ AssertOnce( 0 && "No achievement manager interface in GameUI.dll" );
+ return;
+ }
+
+ // Set up total completion percentage bar
+ float flCompletion = 0.0f;
+ if ( achievementmgr->GetAchievementCount() > 0 )
+ {
+ flCompletion = (((float)m_nUnlocked) / ((float)m_nTotalAchievements));
+ }
+
+ char szPercentageText[64];
+ V_sprintf_safe( szPercentageText, "%d / %d ( %d%% )",
+ m_nUnlocked, m_nTotalAchievements, (int)( flCompletion * 100.0f ) );
+
+ SetControlString( "PercentageText", szPercentageText );
+ SetControlVisible( "PercentageText", true );
+ SetControlVisible( "CompletionText", true );
+
+ Color clrHighlight = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
+ Color clrWhite(255, 255, 255, 255);
+
+ Color cProgressBar = Color( static_cast<float>( clrHighlight.r() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.r() ) * flCompletion,
+ static_cast<float>( clrHighlight.g() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.g() ) * flCompletion,
+ static_cast<float>( clrHighlight.b() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.b() ) * flCompletion,
+ static_cast<float>( clrHighlight.a() ) * ( 1.0f - flCompletion ) + static_cast<float>( clrWhite.a() ) * flCompletion );
+
+ m_pPercentageBar->SetFgColor( cProgressBar );
+ m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion );
+
+ SetControlVisible( "PercentageBarBackground", true );
+ SetControlVisible( "PercentageBar", true );
+
+ m_pSelectionHighlight->SetFillColor( Color( clrHighlight.r(), clrHighlight.g(), clrHighlight.b(), 32 ) );
+
+ if ( m_iNumAchievementGroups <= 2 )
+ {
+ // we have no achievement packs. Hide the combo and bump the achievement list up a bit
+ m_pAchievementPackCombo->SetVisible( false );
+
+ // do some work to preserve the pincorner and resizing
+
+ int comboX, comboY;
+ m_pAchievementPackCombo->GetPos( comboX, comboY );
+
+ int x, y, w, h;
+ m_pAchievementsList->GetBounds( x, y, w, h );
+
+ PinCorner_e corner = m_pAchievementsList->GetPinCorner();
+ int pinX, pinY;
+ m_pAchievementsList->GetPinOffset( pinX, pinY );
+
+ int resizeOffsetX, resizeOffsetY;
+ m_pAchievementsList->GetResizeOffset( resizeOffsetX, resizeOffsetY );
+
+ m_pAchievementsList->SetAutoResize( corner, AUTORESIZE_DOWN, pinX, comboY, resizeOffsetX, resizeOffsetY );
+
+ m_pAchievementsList->SetBounds( x, comboY, w, h + ( y - comboY ) );
+
+ m_pListBG->SetAutoResize( corner, AUTORESIZE_DOWN, pinX, comboY, resizeOffsetX, resizeOffsetY );
+ m_pListBG->SetBounds( x, comboY, w, h + ( y - comboY ) );
+ }
+
+ MoveToCenterOfScreen();
+}
+
+void CAchievementsDialog::ScrollToItem( int nDirection )
+{
+ if ( m_pAchievementsList->GetItemCount() > 0 )
+ {
+ m_nScrollItem = clamp( m_nScrollItem + nDirection, 0, m_pAchievementsList->GetItemCount() - 1 );
+
+ if ( m_nOldScrollItem != m_nScrollItem )
+ {
+ m_nOldScrollItem = m_nScrollItem;
+ m_pAchievementsList->ScrollToItem( m_nScrollItem );
+
+ Panel *pItem = m_pAchievementsList->GetItemPanel( m_nScrollItem );
+ if ( pItem )
+ {
+ int nX, nY, nWide, nTall;
+ pItem->GetBounds( nX, nY, nWide, nTall );
+
+ m_pSelectionHighlight->SetVisible( true );
+ m_pSelectionHighlight->SetBounds( nX, nY, nWide, nTall );
+ }
+ }
+ }
+}
+
+void CAchievementsDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ // Handle close here, CBasePanel parent doesn't support "DialogClosing" command
+ ButtonCode_t nButtonCode = GetBaseButtonCode( code );
+
+ if ( nButtonCode == KEY_XBUTTON_B || nButtonCode == STEAMCONTROLLER_B )
+ {
+ OnCommand( "Close" );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_X || nButtonCode == STEAMCONTROLLER_X )
+ {
+ if ( m_pHideAchievedCheck && m_pHideAchievedCheck->IsVisible() )
+ {
+ m_pHideAchievedCheck->SetSelected( !m_pHideAchievedCheck->IsSelected() );
+ }
+ }
+ else if ( nButtonCode == KEY_XBUTTON_A || nButtonCode == STEAMCONTROLLER_A )
+ {
+ if ( GameSupportsAchievementTracker() && m_nScrollItem >= 0 && m_nScrollItem < m_pAchievementsList->GetItemCount() )
+ {
+ CAchievementDialogItemPanel *pItem = dynamic_cast< CAchievementDialogItemPanel* >( m_pAchievementsList->GetItemPanel( m_nScrollItem) );
+ if ( pItem && pItem->IsVisible() )
+ {
+ pItem->ToggleShowOnHUD();
+ }
+ }
+ }
+ else if ( nButtonCode == KEY_XBUTTON_UP ||
+ nButtonCode == KEY_XSTICK1_UP ||
+ nButtonCode == KEY_XSTICK2_UP ||
+ nButtonCode == STEAMCONTROLLER_DPAD_UP ||
+ nButtonCode == KEY_UP )
+ {
+ ScrollToItem( -1 );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_DOWN ||
+ nButtonCode == KEY_XSTICK1_DOWN ||
+ nButtonCode == KEY_XSTICK2_DOWN ||
+ nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
+ nButtonCode == KEY_DOWN )
+ {
+ ScrollToItem( 1 );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_LEFT ||
+ nButtonCode == KEY_XSTICK1_LEFT ||
+ nButtonCode == KEY_XSTICK2_LEFT ||
+ nButtonCode == STEAMCONTROLLER_DPAD_LEFT ||
+ nButtonCode == KEY_LEFT )
+ {
+ m_pAchievementPackCombo->ActivateItemByRow( m_pAchievementPackCombo->GetActiveItem() - 1 );
+ }
+ else if ( nButtonCode == KEY_XBUTTON_RIGHT ||
+ nButtonCode == KEY_XSTICK1_RIGHT ||
+ nButtonCode == KEY_XSTICK2_RIGHT ||
+ nButtonCode == STEAMCONTROLLER_DPAD_RIGHT ||
+ nButtonCode == KEY_RIGHT )
+ {
+ m_pAchievementPackCombo->ActivateItemByRow( m_pAchievementPackCombo->GetActiveItem() + 1 );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Each sub-panel gets its data updated
+//-----------------------------------------------------------------------------
+void CAchievementsDialog::UpdateAchievementDialogInfo( void )
+{
+ int iCount = m_pAchievementsList->GetItemCount();
+ IScheme *pScheme = scheme()->GetIScheme( GetScheme() );
+
+ for ( int i = 0; i < iCount; i++ )
+ {
+ CAchievementDialogItemPanel *pPanel = (CAchievementDialogItemPanel*)m_pAchievementsList->GetItemPanel(i);
+ if ( pPanel )
+ {
+ pPanel->UpdateAchievementInfo( pScheme );
+ }
+ }
+
+ // update the groups and overall progress bar
+ if ( achievementmgr )
+ {
+ int i;
+
+ // reset group completed counts
+ for ( i=0;i<m_iNumAchievementGroups;i++ )
+ {
+ m_AchievementGroups[i].m_iNumUnlocked = 0;
+ }
+
+ int iAchievementCount = achievementmgr->GetAchievementCount();
+
+ // update counts for each achieved achievement
+ for ( i=0;i<iAchievementCount;i++ )
+ {
+ IAchievement* pCurAchievement = achievementmgr->GetAchievementByIndex( i );
+
+ if ( !pCurAchievement || !pCurAchievement->IsAchieved() )
+ continue;
+
+ int iAchievementID = pCurAchievement->GetAchievementID();
+
+ for ( int j=0;j<m_iNumAchievementGroups;j++ )
+ {
+ if ( iAchievementID >= m_AchievementGroups[j].m_iMinRange &&
+ iAchievementID <= m_AchievementGroups[j].m_iMaxRange )
+ {
+ m_AchievementGroups[j].m_iNumUnlocked++;
+ }
+ }
+ }
+
+ // update the global progress bar label
+ char szPercentageText[64];
+ float flCompletion = (((float)m_AchievementGroups[0].m_iNumUnlocked) / ((float)iAchievementCount));
+ V_sprintf_safe( szPercentageText, "%d / %d ( %d%% )",
+ m_AchievementGroups[0].m_iNumUnlocked, m_nTotalAchievements, (int)( flCompletion * 100.0f ) );
+
+ // and the progress bar
+ m_pPercentageBar->SetWide( m_pPercentageBarBackground->GetWide() * flCompletion );
+
+ SetControlString( "PercentageText", szPercentageText );
+ }
+
+ CreateOrUpdateComboItems( false ); // update them with new achieved counts
+
+ m_pAchievementPackCombo->ActivateItemByRow( m_pAchievementPackCombo->GetActiveItem() );
+}
+
+void CAchievementsDialog::CreateOrUpdateComboItems( bool bCreate )
+{
+ for ( int i=0;i<m_iNumAchievementGroups;i++ )
+ {
+ char buf[128];
+
+ Q_snprintf( buf, sizeof(buf), "#Achievement_Group_%d", m_AchievementGroups[i].m_iMinRange );
+
+ const wchar_t *wzGroupName = g_pVGuiLocalize->Find( buf );
+
+ if ( !wzGroupName )
+ {
+ wzGroupName = L"Need Title ( %s1 of %s2 )";
+ }
+
+ wchar_t wzGroupTitle[128];
+
+ if ( wzGroupName )
+ {
+ wchar_t wzNumUnlocked[8];
+ V_snwprintf( wzNumUnlocked, ARRAYSIZE( wzNumUnlocked ), L"%d", m_AchievementGroups[i].m_iNumUnlocked );
+
+ wchar_t wzNumAchievements[8];
+ V_snwprintf( wzNumAchievements, ARRAYSIZE( wzNumAchievements ), L"%d", m_AchievementGroups[i].m_iNumAchievements );
+
+ g_pVGuiLocalize->ConstructString( wzGroupTitle, sizeof( wzGroupTitle ), wzGroupName, 2, wzNumUnlocked, wzNumAchievements );
+ }
+
+ KeyValues *pKV = new KeyValues( "grp" );
+ pKV->SetInt( "minrange", m_AchievementGroups[i].m_iMinRange );
+ pKV->SetInt( "maxrange", m_AchievementGroups[i].m_iMaxRange );
+
+ if ( bCreate )
+ m_AchievementGroups[i].m_iDropDownGroupID = m_pAchievementPackCombo->AddItem( wzGroupTitle, pKV );
+ else
+ m_pAchievementPackCombo->UpdateItem( m_AchievementGroups[i].m_iDropDownGroupID, wzGroupTitle, pKV );
+ }
+
+ if ( bCreate && ( m_iNumAchievementGroups > NUM_COMBO_BOX_LINES_DEFAULT ) )
+ {
+ if ( m_pAchievementPackCombo )
+ {
+ m_pAchievementPackCombo->SetNumberOfEditLines( ( m_iNumAchievementGroups <= NUM_COMBO_BOX_LINES_MAX ) ? m_iNumAchievementGroups : NUM_COMBO_BOX_LINES_MAX );
+ }
+ }
+}
+
+void CAchievementsDialog::OnCommand( const char *command )
+{
+ if ( !Q_strcasecmp( command, "ongameuiactivated" ) )
+ {
+ UpdateAchievementDialogInfo();
+ }
+
+ BaseClass::OnCommand( command );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: creates child panels, passes down name to pick up any settings from res files.
+//-----------------------------------------------------------------------------
+CAchievementDialogItemPanel::CAchievementDialogItemPanel( vgui::PanelListPanel *parent, const char* name, int iListItemID ) : BaseClass( parent, name )
+{
+ m_iListItemID = iListItemID;
+ m_pParent = parent;
+ m_pSchemeSettings = NULL;
+
+ SetMouseInputEnabled( true );
+ parent->SetMouseInputEnabled( true );
+
+ //CMouseMessageForwardingPanel *panel = new CMouseMessageForwardingPanel(this, NULL);
+ //panel->SetZPos(2);
+}
+
+CAchievementDialogItemPanel::~CAchievementDialogItemPanel()
+{
+ /*
+ delete m_pAchievementIcon;
+ delete m_pAchievementNameLabel;
+ delete m_pAchievementDescLabel;
+ delete m_pPercentageBar;
+ delete m_pPercentageText;
+ delete m_pShowOnHUDCheck;
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates displayed achievement data. In applyschemesettings, and when gameui activates.
+//-----------------------------------------------------------------------------
+void CAchievementDialogItemPanel::UpdateAchievementInfo( IScheme* pScheme )
+{
+ if ( m_pSourceAchievement && m_pSchemeSettings )
+ {
+ // Set name, description and unlocked state text
+ m_pAchievementNameLabel->SetText( ACHIEVEMENT_LOCALIZED_NAME( m_pSourceAchievement ) );
+ m_pAchievementDescLabel->SetText( ACHIEVEMENT_LOCALIZED_DESC( m_pSourceAchievement ) );
+
+ // Setup icon
+ // get the vtfFilename from the path.
+
+ // Display percentage completion for progressive achievements
+ // Set up total completion percentage bar. Goal > 1 means its a progress achievement.
+ UpdateProgressBar( this, m_pSourceAchievement, m_clrProgressBar );
+
+ if ( m_pSourceAchievement->IsAchieved() )
+ {
+ LoadAchievementIcon( m_pAchievementIcon, m_pSourceAchievement );
+
+ SetBgColor( pScheme->GetColor( "AchievementsLightGrey", Color(255, 0, 0, 255) ) );
+
+ m_pAchievementNameLabel->SetFgColor( pScheme->GetColor( "SteamLightGreen", Color(255, 255, 255, 255) ) );
+
+ Color fgColor = pScheme->GetColor( "Label.TextBrightColor", Color(255, 255, 255, 255) );
+ m_pAchievementDescLabel->SetFgColor( fgColor );
+ m_pPercentageText->SetFgColor( fgColor );
+ m_pShowOnHUDCheck->SetVisible( false );
+ m_pShowOnHUDCheck->SetSelected( false );
+ }
+ else
+ {
+ LoadAchievementIcon( m_pAchievementIcon, m_pSourceAchievement, "_bw" );
+
+ SetBgColor( pScheme->GetColor( "AchievementsDarkGrey", Color(255, 0, 0, 255) ) );
+
+ Color fgColor = pScheme->GetColor( "AchievementsInactiveFG", Color(255, 255, 255, 255) );
+ m_pAchievementNameLabel->SetFgColor( fgColor );
+ m_pAchievementDescLabel->SetFgColor( fgColor );
+ m_pPercentageText->SetFgColor( fgColor );
+ if ( GameSupportsAchievementTracker() )
+ {
+ m_pShowOnHUDCheck->SetVisible( !m_pSourceAchievement->ShouldHideUntilAchieved() ); // m_pSourceAchievement->GetGoal() > 1 &&
+ m_pShowOnHUDCheck->SetSelected( m_pSourceAchievement->ShouldShowOnHUD() );
+ }
+ else
+ {
+ m_pShowOnHUDCheck->SetVisible( false );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Makes a local copy of a pointer to the achievement entity stored on the client.
+//-----------------------------------------------------------------------------
+void CAchievementDialogItemPanel::SetAchievementInfo( IAchievement* pAchievement )
+{
+ if ( !pAchievement )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ m_pSourceAchievement = pAchievement;
+ m_iSourceAchievementIndex = pAchievement->GetAchievementID();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CAchievementDialogItemPanel::PreloadResourceFile( void )
+{
+ const char *controlResourceName = "resource/ui/AchievementItem.res";
+
+ g_pPreloadedAchievementItemLayout = new KeyValues(controlResourceName);
+ g_pPreloadedAchievementItemLayout->LoadFromFile(g_pFullFileSystem, controlResourceName);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Loads settings from hl2/resource/ui/achievementitem.res
+// Sets display info for this achievement item.
+//-----------------------------------------------------------------------------
+void CAchievementDialogItemPanel::ApplySchemeSettings( IScheme* pScheme )
+{
+ if ( !g_pPreloadedAchievementItemLayout )
+ {
+ PreloadResourceFile();
+ }
+
+ LoadControlSettings( "", NULL, g_pPreloadedAchievementItemLayout );
+
+ m_pSchemeSettings = pScheme;
+
+ if ( !m_pSourceAchievement )
+ {
+ return;
+ }
+
+ m_pAchievementIcon = SETUP_PANEL(dynamic_cast<vgui::ImagePanel*>(FindChildByName("AchievementIcon")));
+ m_pAchievementNameLabel = dynamic_cast<vgui::Label*>(FindChildByName("AchievementName"));
+ m_pAchievementDescLabel = dynamic_cast<vgui::Label*>(FindChildByName("AchievementDesc"));
+ m_pPercentageBar = SETUP_PANEL(dynamic_cast<vgui::ImagePanel*>(FindChildByName("PercentageBar")));
+ m_pPercentageText = dynamic_cast<vgui::Label*>(FindChildByName("PercentageText"));
+ m_pShowOnHUDCheck = dynamic_cast<vgui::CheckButton*>(FindChildByName("ShowOnHUD"));
+ m_pShowOnHUDCheck->SetMouseInputEnabled( true );
+ m_pShowOnHUDCheck->SetEnabled( true );
+ m_pShowOnHUDCheck->SetCheckButtonCheckable( true );
+ m_pShowOnHUDCheck->AddActionSignalTarget( this );
+
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // m_pSchemeSettings must be set for this.
+ UpdateAchievementInfo( pScheme );
+}
+
+void CAchievementDialogItemPanel::ToggleShowOnHUD( void )
+{
+ m_pShowOnHUDCheck->SetSelected( !m_pShowOnHUDCheck->IsSelected() );
+}
+
+void CAchievementDialogItemPanel::OnCheckButtonChecked(Panel *panel)
+{
+ if ( GameSupportsAchievementTracker() && panel == m_pShowOnHUDCheck && m_pSourceAchievement )
+ {
+ m_pSourceAchievement->SetShowOnHUD( m_pShowOnHUDCheck->IsSelected() );
+ }
+}
diff --git a/gameui/matchmaking/achievementsdialog.h b/gameui/matchmaking/achievementsdialog.h
new file mode 100644
index 0000000..b16d876
--- /dev/null
+++ b/gameui/matchmaking/achievementsdialog.h
@@ -0,0 +1,182 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef ACHIEVEMENTSDIALOG_H
+#define ACHIEVEMENTSDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+#include "vgui_controls/PanelListPanel.h"
+#include "vgui_controls/Label.h"
+#include "tier1/KeyValues.h"
+#include "TGAImagePanel.h"
+
+#define MAX_ACHIEVEMENT_GROUPS 25
+
+class IAchievement;
+
+#define ACHIEVED_ICON_PATH "hud/icon_check.vtf"
+#define LOCK_ICON_PATH "hud/icon_locked.vtf"
+
+// Loads an achievement's icon into a specified image panel, or turns the panel off if no achievement icon was found.
+bool LoadAchievementIcon( vgui::ImagePanel* pIconPanel, IAchievement *pAchievement, const char *pszExt = NULL );
+
+// Updates a listed achievement item's progress bar.
+void UpdateProgressBar( vgui::EditablePanel* pPanel, IAchievement *pAchievement, Color clrProgressBar );
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple menu to choose a matchmaking session type
+//-----------------------------------------------------------------------------
+class CAchievementsDialog_XBox : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CAchievementsDialog_XBox, CBaseDialog );
+
+public:
+ CAchievementsDialog_XBox(vgui::Panel *parent);
+ ~CAchievementsDialog_XBox();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void PerformLayout();
+
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void HandleKeyRepeated( vgui::KeyCode code );
+
+ virtual void OnClose();
+
+
+private:
+
+ vgui::Panel *m_pProgressBg;
+
+ vgui::Panel *m_pProgressBar;
+ vgui::Label *m_pProgressPercent;
+ vgui::Label *m_pNumbering;
+ vgui::Label *m_pUpArrow;
+ vgui::Label *m_pDownArrow;
+
+ KeyValues* m_pResourceData;
+
+ CFooterPanel *m_pFooter;
+
+ bool m_bCenterOnScreen;
+ int m_iNumItems;
+ int m_nTotalAchievements; // Total achievements for this title
+ int m_nUnlocked;
+ int m_iSelection;
+ int m_iScroll;
+};
+
+
+////////////////////////////////////////////////////////////////////////////
+// PC version
+//////////////////////////////////////////////////////////////////////////
+class CAchievementsDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE ( CAchievementsDialog, vgui::Frame );
+
+public:
+ CAchievementsDialog( vgui::Panel *parent );
+ ~CAchievementsDialog();
+
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+ void ScrollToItem( int nDirection );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void UpdateAchievementDialogInfo( void );
+ virtual void OnCommand( const char* command );
+
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void OnSizeChanged( int newWide, int newTall );
+
+ MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel );
+ MESSAGE_FUNC_PARAMS( OnTextChanged, "TextChanged", data );
+
+ void CreateNewAchievementGroup( int iMinRange, int iMaxRange );
+ void CreateOrUpdateComboItems( bool bCreate );
+ void UpdateAchievementList();
+
+ vgui::PanelListPanel *m_pAchievementsList;
+ vgui::ImagePanel *m_pListBG;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+
+ vgui::ImagePanel *m_pSelectionHighlight;
+
+ vgui::ComboBox *m_pAchievementPackCombo;
+ vgui::CheckButton *m_pHideAchievedCheck;
+
+ int m_nUnlocked;
+ int m_nTotalAchievements;
+
+ int m_iFixedWidth;
+
+ typedef struct
+ {
+ int m_iMinRange;
+ int m_iMaxRange;
+ int m_iNumAchievements;
+ int m_iNumUnlocked;
+ int m_iDropDownGroupID;
+ } achievement_group_t;
+
+ int m_iNumAchievementGroups;
+
+ achievement_group_t m_AchievementGroups[ MAX_ACHIEVEMENT_GROUPS ];
+
+ int m_nScrollItem;
+ int m_nOldScrollItem;
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Individual item panel, displaying stats for one achievement
+class CAchievementDialogItemPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CAchievementDialogItemPanel, vgui::EditablePanel );
+
+public:
+ CAchievementDialogItemPanel( vgui::PanelListPanel *parent, const char* name, int iListItemID );
+ ~CAchievementDialogItemPanel();
+
+ void SetAchievementInfo ( IAchievement* pAchievement );
+ IAchievement* GetAchievementInfo( void ) { return m_pSourceAchievement; }
+ void UpdateAchievementInfo( IScheme *pScheme );
+ virtual void ApplySchemeSettings( IScheme *pScheme );
+ void ToggleShowOnHUD( void );
+
+ MESSAGE_FUNC_PTR( OnCheckButtonChecked, "CheckButtonChecked", panel );
+
+private:
+ void PreloadResourceFile( void );
+
+ IAchievement* m_pSourceAchievement;
+ int m_iSourceAchievementIndex;
+
+ vgui::PanelListPanel *m_pParent;
+
+ vgui::Label *m_pAchievementNameLabel;
+ vgui::Label *m_pAchievementDescLabel;
+ vgui::Label *m_pPercentageText;
+
+ vgui::ImagePanel *m_pLockedIcon;
+ vgui::ImagePanel *m_pAchievementIcon;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+
+ vgui::CheckButton *m_pShowOnHUDCheck;
+
+ vgui::IScheme *m_pSchemeSettings;
+
+ CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" );
+
+ int m_iListItemID;
+};
+
+#endif // ACHIEVEMENTSDIALOG_H
diff --git a/gameui/matchmaking/basedialog.cpp b/gameui/matchmaking/basedialog.cpp
new file mode 100644
index 0000000..be65718
--- /dev/null
+++ b/gameui/matchmaking/basedialog.cpp
@@ -0,0 +1,295 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: All matchmaking dialogs inherit from this
+//
+//=============================================================================//
+
+#include "vgui_controls/Label.h"
+#include "GameUI_Interface.h"
+#include "KeyValues.h"
+#include "basedialog.h"
+#include "BasePanel.h"
+#include "matchmakingbasepanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//---------------------------------------------------------
+// CBaseDialog
+//---------------------------------------------------------
+CBaseDialog::CBaseDialog( vgui::Panel *pParent, const char *pName ) : BaseClass( pParent, pName )
+{
+ SetTitleBarVisible( false );
+ SetCloseButtonVisible( false );
+ SetSizeable( false );
+
+ m_pParent = pParent;
+ m_Menu.SetParent( this );
+
+ m_pTitle = new vgui::Label( this, "DialogTitle", "" );
+ m_pFooterInfo = NULL;
+
+ m_nBorderWidth = 0;
+ m_nButtonGap = -1;
+}
+
+CBaseDialog::~CBaseDialog()
+{
+ delete m_pTitle;
+
+ if ( m_pFooterInfo )
+ {
+ m_pFooterInfo->deleteThis();
+ }
+}
+
+//---------------------------------------------------------
+// Purpose: Activate the dialog
+//---------------------------------------------------------
+void CBaseDialog::Activate( void )
+{
+ BaseClass::Activate();
+
+ InvalidateLayout( false, false );
+}
+
+//---------------------------------------------------------
+// Purpose: Set the title and menu positions
+//---------------------------------------------------------
+void CBaseDialog::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ m_pTitle->SizeToContents();
+
+ int menux, menuy;
+ m_Menu.GetPos( menux, menuy );
+
+ int autoWide = m_Menu.GetWide() + m_nBorderWidth * 2;
+ int autoTall = menuy + m_Menu.GetTall() + m_nBorderWidth;
+ autoWide = max( autoWide, GetWide() );
+ autoTall = max( autoTall, GetTall() );
+
+ SetSize( autoWide, autoTall );
+
+ if ( m_pFooterInfo && m_pParent )
+ {
+ CMatchmakingBasePanel *pBasePanel = dynamic_cast< CMatchmakingBasePanel* >( m_pParent );
+ if ( pBasePanel )
+ {
+ // the base panel is our parent
+ pBasePanel->SetFooterButtons( this, m_pFooterInfo, m_nButtonGap );
+ }
+ }
+
+ if ( m_Menu.GetActiveItemIndex() == -1 )
+ {
+ m_Menu.SetFocus( 0 );
+ }
+}
+
+//---------------------------------------------------------
+// Purpose: Setup sizes and positions
+//---------------------------------------------------------
+void CBaseDialog::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ m_nBorderWidth = inResourceData->GetInt( "borderwidth", 0 );
+
+ KeyValues *pFooter = inResourceData->FindKey( "Footer" );
+ if ( pFooter )
+ {
+ m_pFooterInfo = pFooter->MakeCopy();
+ }
+
+ m_nButtonGap = inResourceData->GetInt( "footer_buttongap", -1 );
+}
+
+//---------------------------------------------------------
+// Purpose: Setup colors and fonts
+//---------------------------------------------------------
+void CBaseDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetPaintBackgroundType( 2 );
+
+ m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingDialogTitleColor", Color( 200, 184, 151, 255 ) ) );
+
+ char szResourceName[MAX_PATH];
+ Q_snprintf( szResourceName, sizeof( szResourceName ), "%s.res", GetName() );
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( szResourceName );
+ LoadControlSettings( "NULL", NULL, pKeys );
+}
+
+//-----------------------------------------------------------------
+// Purpose: Set the resource file to load this dialog's settings
+//-----------------------------------------------------------------
+void CBaseDialog::OnClose()
+{
+ // Hide the rather ugly fade out
+ SetAlpha( 0 );
+ BaseClass::OnClose();
+}
+
+//-----------------------------------------------------------------
+// Purpose: Change properties of a menu item
+//-----------------------------------------------------------------
+void CBaseDialog::OverrideMenuItem( KeyValues *pKeys )
+{
+ // Do nothing
+}
+
+//-----------------------------------------------------------------
+// Purpose: Swap the order of two menu items
+//-----------------------------------------------------------------
+void CBaseDialog::SwapMenuItems( int iOne, int iTwo )
+{
+ // Do nothing
+}
+
+//-----------------------------------------------------------------
+// Purpose: Send key presses to the dialog's menu
+//-----------------------------------------------------------------
+void CBaseDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_START )
+ {
+ m_KeyRepeat.Reset();
+ if ( GameUI().IsInLevel() )
+ {
+ m_pParent->OnCommand( "ResumeGame" );
+ }
+ return;
+ }
+
+ m_KeyRepeat.KeyDown( code );
+
+ // Send down to the menu
+ if ( !m_Menu.HandleKeyCode( code ) )
+ {
+ if ( code == KEY_XBUTTON_B )
+ {
+ OnCommand( "DialogClosing" );
+ SetDeleteSelfOnClose( true );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDialog::OnKeyCodeReleased( vgui::KeyCode code )
+{
+ m_KeyRepeat.KeyUp( code );
+
+ BaseClass::OnKeyCodeReleased( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDialog::HandleKeyRepeated( vgui::KeyCode code )
+{
+ m_Menu.HandleKeyCode( code );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CBaseDialog::OnThink()
+{
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ if ( HasFocus() )
+ {
+ HandleKeyRepeated( code );
+ }
+ else
+ {
+ // This can happen because of the slight delay after selecting a
+ // menu option and the resulting action. The selection caused the
+ // key repeater to be reset, but the player can press a movement
+ // key before the action occurs, leaving us with a key repeating
+ // on this dialog even though it no longer has focus.
+ m_KeyRepeat.Reset();
+ }
+ }
+
+ BaseClass::OnThink();
+}
+
+//-----------------------------------------------------------------
+// Purpose: Forward commands to the matchmaking base panel
+//-----------------------------------------------------------------
+void CBaseDialog::OnCommand( const char *pCommand )
+{
+ m_KeyRepeat.Reset();
+ m_pParent->OnCommand( pCommand );
+}
+
+
+//---------------------------------------------------------------------
+// Helper object to display the map picture and descriptive text
+//---------------------------------------------------------------------
+CScenarioInfoPanel::CScenarioInfoPanel( vgui::Panel *parent, const char *pName ) : BaseClass( parent, pName )
+{
+ m_pMapImage = new vgui::ImagePanel( this, "MapImage" );
+ m_pTitle = new CPropertyLabel( this, "Title", "" );
+ m_pSubtitle = new CPropertyLabel( this, "Subtitle", "" );
+
+ m_pDescOne = new CPropertyLabel( this, "DescOne", "" );
+ m_pDescTwo = new CPropertyLabel( this, "DescTwo", "" );
+ m_pDescThree = new CPropertyLabel( this, "DescThree", "" );
+
+ m_pValueTwo = new CPropertyLabel( this, "ValueTwo", "" );
+ m_pValueThree = new CPropertyLabel( this, "ValueThree", "" );
+}
+CScenarioInfoPanel::~CScenarioInfoPanel()
+{
+ delete m_pMapImage;
+ delete m_pTitle;
+ delete m_pSubtitle;
+ delete m_pDescOne;
+ delete m_pDescTwo;
+ delete m_pDescThree;
+ delete m_pValueTwo;
+ delete m_pValueThree;
+}
+
+void CScenarioInfoPanel::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+}
+
+void CScenarioInfoPanel::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+}
+
+void CScenarioInfoPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ Color fontColor = pScheme->GetColor( "MatchmakingDialogTitleColor", Color( 0, 0, 0, 255 ) );
+ m_pTitle->SetFgColor( fontColor );
+ m_pSubtitle->SetFgColor( fontColor );
+ m_pDescOne->SetFgColor( fontColor );
+ m_pDescTwo->SetFgColor( fontColor );
+ m_pDescThree->SetFgColor( fontColor );
+ m_pValueTwo->SetFgColor( fontColor );
+ m_pValueThree->SetFgColor( fontColor );
+
+ SetPaintBackgroundType( 2 );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "ScenarioInfoPanel.res" );
+ ApplySettings( pKeys );
+}
+
+DECLARE_BUILD_FACTORY( CScenarioInfoPanel );
diff --git a/gameui/matchmaking/basedialog.h b/gameui/matchmaking/basedialog.h
new file mode 100644
index 0000000..1501e1f
--- /dev/null
+++ b/gameui/matchmaking/basedialog.h
@@ -0,0 +1,120 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: All matchmaking dialogs inherit from this
+//
+//=============================================================================//
+
+#ifndef BASEDIALOG_H
+#define BASEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "dialogmenu.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/KeyRepeat.h"
+#include "KeyValues.h"
+#include "BasePanel.h"
+
+#if !defined( _X360 )
+#include "xbox/xboxstubs.h"
+#endif
+
+class CFooterPanel;
+
+//-----------------------------------------------------------------------------
+// Purpose: A Label with an extra string to hold a session property lookup key
+//-----------------------------------------------------------------------------
+class CPropertyLabel : public vgui::Label
+{
+ DECLARE_CLASS_SIMPLE( CPropertyLabel, vgui::Label );
+
+public:
+ CPropertyLabel( Panel *parent, const char *panelName, const char *text ) : BaseClass( parent, panelName, text )
+ {
+ }
+
+ virtual void ApplySettings( KeyValues *pResourceData )
+ {
+ BaseClass::ApplySettings( pResourceData );
+
+ m_szPropertyString[0] = 0;
+ const char *pString = pResourceData->GetString( "PropertyString", NULL );
+ if ( pString )
+ {
+ Q_strncpy( m_szPropertyString, pString, sizeof( m_szPropertyString ) );
+ }
+ }
+
+ char m_szPropertyString[ MAX_PATH ];
+};
+
+//--------------------------------
+// CBaseDialog
+//--------------------------------
+class CBaseDialog : public vgui::Frame
+{
+ DECLARE_CLASS_SIMPLE( CBaseDialog, vgui::Frame );
+
+public:
+ CBaseDialog( vgui::Panel *parent, const char *pName );
+ ~CBaseDialog();
+
+ // IPanel interface
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void PerformLayout();
+ virtual void Activate();
+
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnKeyCodeReleased( vgui::KeyCode code);
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnClose();
+ virtual void OnThink();
+
+ virtual void OverrideMenuItem( KeyValues *pKeys );
+ virtual void SwapMenuItems( int iOne, int iTwo );
+
+ virtual void HandleKeyRepeated( vgui::KeyCode code );
+
+protected:
+ int m_nBorderWidth;
+ int m_nMinWide;
+
+ CDialogMenu m_Menu;
+ vgui::Label *m_pTitle;
+ vgui::Panel *m_pParent;
+
+ KeyValues *m_pFooterInfo;
+ int m_nButtonGap;
+
+ vgui::CKeyRepeatHandler m_KeyRepeat;
+};
+
+
+//---------------------------------------------------------------------
+// Helper object to display the map picture and descriptive text
+//---------------------------------------------------------------------
+class CScenarioInfoPanel : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CScenarioInfoPanel, vgui::EditablePanel );
+
+public:
+ CScenarioInfoPanel( vgui::Panel *parent, const char *pName );
+ ~CScenarioInfoPanel();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ vgui::ImagePanel *m_pMapImage;
+ CPropertyLabel *m_pTitle;
+ CPropertyLabel *m_pSubtitle;
+ CPropertyLabel *m_pDescOne;
+ CPropertyLabel *m_pDescTwo;
+ CPropertyLabel *m_pDescThree;
+ CPropertyLabel *m_pValueTwo;
+ CPropertyLabel *m_pValueThree;
+};
+
+#endif // BASEDIALOG_H \ No newline at end of file
diff --git a/gameui/matchmaking/dialogmenu.cpp b/gameui/matchmaking/dialogmenu.cpp
new file mode 100644
index 0000000..e46888b
--- /dev/null
+++ b/gameui/matchmaking/dialogmenu.cpp
@@ -0,0 +1,1524 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Multi-purpose menu for matchmaking dialogs, navigable with the xbox controller.
+//
+//=============================================================================//
+
+#include "engine/imatchmaking.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui/ILocalize.h"
+#include "vgui/ISurface.h"
+#include "KeyValues.h"
+#include "dialogmenu.h"
+#include "BasePanel.h"
+#include "vgui_controls/ImagePanel.h"
+#include "iachievementmgr.h" // for iachievement abstract class in CAchievementItem
+#include "achievementsdialog.h" // for helper functions used by both pc and xbox achievements
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//-----------------------------------------------------------------------
+// Base class representing a generic menu item. Supports two text labels,
+// where the first label is the "action" text and the second is an optional
+// description of the action.
+//-----------------------------------------------------------------------
+CMenuItem::CMenuItem( CDialogMenu *pParent, const char *pTitle, const char *pDescription )
+ : BaseClass( pParent, "MenuItem" )
+{
+ // Quiet "parent not sized yet" spew
+ SetSize( 10, 10 );
+
+ m_pParent = pParent;
+
+ m_bEnabled = true;
+ m_nDisabledAlpha = 30;
+
+ m_pTitle = new vgui::Label( this, "MenuItemText", pTitle );
+ m_pDescription = NULL;
+ if ( pDescription )
+ {
+ m_pDescription = new vgui::Label( this, "MenuItemDesc", pDescription );
+ }
+}
+
+CMenuItem::~CMenuItem()
+{
+ delete m_pTitle;
+ delete m_pDescription;
+}
+
+//-----------------------------------------------------------------------
+// Update colors according to enabled/disabled state
+//-----------------------------------------------------------------------
+void CMenuItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------------
+// Setup margins and calculate the total menu item size
+//-----------------------------------------------------------------------
+void CMenuItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+
+ m_nBottomMargin = pSettings->GetInt( "bottommargin", 0 );
+ m_nRightMargin = pSettings->GetInt( "rightmargin", 0 );
+
+ int x, y;
+ m_pTitle->GetPos( x, y );
+ m_pTitle->SizeToContents();
+
+ int bgTall = y + m_pTitle->GetTall() + m_nBottomMargin;
+ int textWide = m_pTitle->GetWide();
+
+ if ( m_pDescription )
+ {
+ m_pDescription->SizeToContents();
+ m_pDescription->GetPos( x, y );
+ bgTall = y + m_pDescription->GetTall() + m_nBottomMargin;
+ textWide = max( textWide, m_pDescription->GetWide() );
+ }
+
+ int bgWide = x + textWide + m_nRightMargin;
+
+ SetSize( bgWide, bgTall );
+}
+
+//-----------------------------------------------------------------------
+// Setup colors and fonts
+//-----------------------------------------------------------------------
+void CMenuItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ SetPaintBackgroundType( 2 );
+
+ m_BgColor = pScheme->GetColor( "MatchmakingMenuItemBackground", Color( 46, 43, 42, 255 ) );
+ m_BgColorActive = pScheme->GetColor( "MatchmakingMenuItemBackgroundActive", Color( 150, 71, 0, 255 ) );
+
+ m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 0, 0, 0, 255 ) ) );
+
+ if ( m_pDescription )
+ {
+ m_pDescription->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 0, 0, 0, 255 ) ) );
+ }
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "MenuItem.res" );
+ ApplySettings( pKeys );
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetFocus( const bool bActive )
+{
+ if ( bActive )
+ {
+ SetBgColor( m_BgColorActive );
+ }
+ else
+ {
+ SetBgColor( m_BgColor );
+ }
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetEnabled( bool bEnabled )
+{
+ if ( bEnabled )
+ {
+ SetAlpha( 255 );
+ }
+ else
+ {
+ SetAlpha( m_nDisabledAlpha );
+ }
+ m_bEnabled = bEnabled;
+}
+
+//-----------------------------------------------------------------------
+// Set a column as having focus
+//-----------------------------------------------------------------------
+void CMenuItem::SetActiveColumn( int col )
+{
+ // do nothing
+}
+
+//-----------------------------------------------------------------------
+// Set an item as having input focus
+//-----------------------------------------------------------------------
+bool CMenuItem::IsEnabled()
+{
+ return m_bEnabled;
+}
+
+//-----------------------------------------------------------------------
+// Perform any special actions when an item is "clicked"
+//-----------------------------------------------------------------------
+void CMenuItem::OnClick()
+{
+ // do nothing - derived classes implement this
+}
+
+
+//-----------------------------------------------------------------------
+// CCommandItem
+//
+// Menu item that issues a command when clicked.
+//-----------------------------------------------------------------------
+CCommandItem::CCommandItem( CDialogMenu *pParent, const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
+ : BaseClass( pParent, pTitleLabel, pDescLabel )
+{
+ Q_strncpy( m_szCommand, pCommand, MAX_COMMAND_LEN );
+}
+
+CCommandItem::~CCommandItem()
+{
+ // do nothing
+}
+
+void CCommandItem::OnClick()
+{
+ GetParent()->OnCommand( m_szCommand );
+
+ vgui::surface()->PlaySound( "UI/buttonclick.wav" );
+}
+
+void CCommandItem::SetFocus(const bool bActive )
+{
+ BaseClass::SetFocus( bActive );
+
+ if ( bActive == true && m_bHasFocus == false )
+ {
+ vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
+ }
+
+ m_bHasFocus = bActive;
+}
+
+
+//-----------------------------------------------------------------------
+// CPlayerItem
+//
+// Menu item to display a player in the lobby.
+//-----------------------------------------------------------------------
+CPlayerItem::CPlayerItem( CDialogMenu *pParent, const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
+: BaseClass( pParent, pTitleLabel, NULL, "ShowGamerCard" )
+{
+ m_pVoiceIcon = new vgui::Label( this, "voiceicon", "" );
+ m_pReadyIcon = new vgui::Label( this, "readyicon", "" );
+
+ m_nId = nId;
+ m_bVoice = bVoice;
+ m_bReady = bReady;
+}
+
+CPlayerItem::~CPlayerItem()
+{
+ delete m_pVoiceIcon;
+ delete m_pReadyIcon;
+}
+
+void CPlayerItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ const char *pVoice = "";
+
+ if ( m_bVoice == 2 )
+ {
+ pVoice = "#TF_Icon_Voice";
+ }
+ else if ( m_bVoice == 1 )
+ {
+ pVoice = "#TF_Icon_Voice_Idle";
+ }
+
+ m_pVoiceIcon->SetText( pVoice );
+ m_pReadyIcon->SetText( m_bReady ? "#TF_Icon_Ready" : "#TF_Icon_NotReady" );
+
+ int x, y;
+ m_pReadyIcon->GetPos( x, y );
+ m_pReadyIcon->SetPos( GetWide() - m_pReadyIcon->GetWide() - m_nRightMargin, y );
+}
+
+void CPlayerItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "PlayerItem.res" );
+ ApplySettings( pKeys );
+}
+
+void CPlayerItem::OnClick()
+{
+ BaseClass::OnClick();
+}
+
+//-----------------------------------------------------------------------
+// CBrowserItem
+//
+// Menu item used to display session search results.
+//-----------------------------------------------------------------------
+CBrowserItem::CBrowserItem( CDialogMenu *pParent, const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
+ : BaseClass( pParent, pHost, NULL, "SelectSession" )
+{
+ m_pPlayers = new vgui::Label( this, "players", pPlayers );
+ m_pScenario = new vgui::Label( this, "scenario", pScenario );
+ m_pPing = new vgui::Label( this, "ping", pPing );
+}
+
+CBrowserItem::~CBrowserItem()
+{
+ delete m_pPlayers;
+ delete m_pScenario;
+ delete m_pPing;
+}
+
+void CBrowserItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y, wide, tall;
+ m_pPing->GetBounds( x, y, wide, tall );
+
+ m_pScenario->SizeToContents();
+ int sx, sy;
+ m_pScenario->GetPos( sx, sy );
+ m_pScenario->SetPos( x - m_pScenario->GetWide() - m_nRightMargin, sy );
+
+ SetSize( x + wide, GetTall() );
+}
+
+void CBrowserItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+}
+
+void CBrowserItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ Color fgcolor = pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) );
+ m_pPlayers->SetFgColor( fgcolor );
+ m_pScenario->SetFgColor( fgcolor );
+
+ m_pPing->SetContentAlignment( vgui::Label::a_center );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "BrowserItem.res" );
+ ApplySettings( pKeys );
+
+ SetFocus( false );
+}
+
+//-----------------------------------------------------------------------
+// COptionsItem
+//
+// Menu item used to present a list of options for the player to select
+// from, such as "choose a map" or "number of rounds".
+//-----------------------------------------------------------------------
+COptionsItem::COptionsItem( CDialogMenu *pParent, const char *pLabel )
+ : BaseClass( pParent, pLabel, NULL )
+{
+ m_nActiveOption = m_Options.InvalidIndex();
+ m_nOptionsXPos = 0;
+ m_nMaxOptionWidth = 0;
+
+ m_szOptionsFont[0] = '\0';
+ m_hOptionsFont = vgui::INVALID_FONT;
+
+ m_pLeftArrow = new vgui::Label( this, "LeftArrow", "" );
+ m_pRightArrow = new vgui::Label( this, "RightArrow", "" );
+}
+
+COptionsItem::~COptionsItem()
+{
+ m_OptionLabels.PurgeAndDeleteElements();
+
+ delete m_pLeftArrow;
+ delete m_pRightArrow;
+}
+
+void COptionsItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int optionWide = max( m_nOptionsMinWide, GetWide() - m_nOptionsXPos - m_pRightArrow->GetWide() - m_nOptionsLeftMargin );
+ int optionTall = GetTall();
+
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ vgui::Label *pOption = m_OptionLabels[i];
+
+ pOption->SetBounds( m_nOptionsXPos, 0, optionWide, optionTall );
+ }
+
+ int lx, ly;
+ m_pLeftArrow->GetPos( lx, ly );
+ m_pLeftArrow->SetPos( m_nOptionsXPos - m_nArrowGap - m_pLeftArrow->GetWide(), ly );
+
+ int rx, ry;
+ m_pRightArrow->GetPos( rx, ry );
+ m_pRightArrow->SetPos( m_nOptionsXPos + optionWide + m_nArrowGap, ry );
+
+ m_pLeftArrow->SetAlpha( 255 );
+ m_pRightArrow->SetAlpha( 255 );
+
+ if ( m_nActiveOption == 0 )
+ {
+ m_pLeftArrow->SetAlpha( 32 );
+ }
+ else if ( m_nActiveOption == m_OptionLabels.Count() - 1 )
+ {
+ m_pRightArrow->SetAlpha( 32 );
+ }
+}
+
+void COptionsItem::ApplySettings( KeyValues *pSettings )
+{
+ BaseClass::ApplySettings( pSettings );
+
+ m_nOptionsXPos = pSettings->GetInt( "optionsxpos", 0 );
+ m_nOptionsMinWide = pSettings->GetInt( "optionsminwide", 0 );
+ m_nOptionsLeftMargin = pSettings->GetInt( "optionsleftmargin", 0 );
+ m_nArrowGap = pSettings->GetInt( "arrowgap", 0 );
+
+ Q_strncpy( m_szOptionsFont, pSettings->GetString( "optionsfont", "Default" ), sizeof( m_szOptionsFont ) );
+}
+
+void COptionsItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ SetPaintBackgroundEnabled( false );
+
+ m_pTitle->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemTitleColor", Color( 200, 184, 151, 255 ) ) );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "OptionsItem.res" );
+ ApplySettings( pKeys );
+
+ m_hOptionsFont = pScheme->GetFont( m_szOptionsFont );
+}
+
+void COptionsItem::SetFocus( const bool bActive )
+{
+ if ( bActive )
+ {
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ m_OptionLabels[i]->SetBgColor( m_BgColorActive );
+ }
+ }
+ else
+ {
+ for ( int i = 0; i < m_OptionLabels.Count(); ++i )
+ {
+ m_OptionLabels[i]->SetBgColor( m_BgColor );
+ }
+ }
+}
+
+void COptionsItem::AddOption( const char *pLabelText, const sessionProperty_t& option )
+{
+ // Add a new option to this item's list of options
+ m_Options.AddToTail( option );
+
+ int idx = m_OptionLabels.AddToTail( new vgui::Label( this, "Option Value", pLabelText ) );
+ vgui::Label *pOption = m_OptionLabels[idx];
+
+ // Check for a format string
+ if ( Q_stristr( pLabelText, "Fmt" ) )
+ {
+ wchar_t wszString[64];
+ wchar_t wzNumber[8];
+ wchar_t *wzFmt = g_pVGuiLocalize->Find( pLabelText );
+ g_pVGuiLocalize->ConvertANSIToUnicode( option.szValue, wzNumber, sizeof( wzNumber ) );
+ g_pVGuiLocalize->ConstructString( wszString, sizeof( wszString ), wzFmt, 1, wzNumber );
+ pOption->SetText( wszString );
+ }
+
+ SETUP_PANEL( pOption );
+ pOption->SetPaintBackgroundType( 2 );
+
+ pOption->SetFont( m_hOptionsFont );
+ pOption->SetBgColor( Color( 46, 43, 42, 255 ) );
+ pOption->SetFgColor( m_pTitle ? m_pTitle->GetFgColor() : Color( 200, 184, 151, 255 ) );
+ pOption->SetTextInset( m_nOptionsLeftMargin, 0 );
+ pOption->SetContentAlignment( vgui::Label::a_southwest );
+ pOption->SizeToContents();
+
+ int wide = max( m_nOptionsMinWide, pOption->GetWide() );
+ pOption->SetBounds( m_nOptionsXPos, 0, wide, GetTall() );
+ m_nMaxOptionWidth = max( wide, m_nMaxOptionWidth );
+
+ SetWide( m_nOptionsXPos + m_nMaxOptionWidth + m_nOptionsLeftMargin * 2 + m_nArrowGap * 2 + m_pRightArrow->GetWide() );
+}
+
+//-----------------------------------------------------------------------
+// Return the session property associated with the current active option
+//-----------------------------------------------------------------------
+const sessionProperty_t &COptionsItem::GetActiveOption()
+{
+ return m_Options[m_nActiveOption];
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active option
+//-----------------------------------------------------------------------
+int COptionsItem::GetActiveOptionIndex()
+{
+ return m_nActiveOption;
+}
+
+//-----------------------------------------------------------------------
+// Sets which option currently has focus
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocus( unsigned int idx )
+{
+ unsigned int itemCt = (unsigned int)m_OptionLabels.Count();
+ if ( idx > itemCt )
+ return;
+
+ m_nActiveOption = idx;
+
+ for ( unsigned int i = 0; i < itemCt; ++i )
+ {
+ vgui::Label *pLabel = m_OptionLabels[i];
+
+ const bool bVisible = ( i == idx );
+ pLabel->SetVisible( bVisible );
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------
+// Move focus to the next option - does not wrap
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocusNext()
+{
+ if ( m_nActiveOption + 1 < m_OptionLabels.Count() )
+ {
+ SetOptionFocus( m_nActiveOption + 1 );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+}
+
+//-----------------------------------------------------------------------
+// Move focus to the previous option - does not wrap
+//-----------------------------------------------------------------------
+void COptionsItem::SetOptionFocusPrev()
+{
+ if ( m_nActiveOption > 0 )
+ {
+ SetOptionFocus( m_nActiveOption - 1 );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+}
+
+
+//-----------------------------------------------------------------------
+// CAchievementItem
+//
+// Menu item used to present an achievement - including image, title,
+// description, points and unlock date. Clicking the item opens another
+// dialog with additional information about the achievement.
+//-----------------------------------------------------------------------
+CAchievementItem::CAchievementItem( CDialogMenu *pParent, const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
+ : BaseClass( pParent, "", "" )
+{
+ // Title and description were returned as results of a system query,
+ // and are therefore already localized.
+ m_pTitle->SetText( pName );
+
+ if ( IsX360() )
+ {
+ wchar_t buf[120];
+
+ // Get the screen size
+ int wide, tall;
+ vgui::surface()->GetScreenSize(wide, tall);
+
+ unsigned int iWrapLen;
+
+ if ( tall <= 480 )
+ {
+ iWrapLen = 50;
+ }
+ else
+ {
+ iWrapLen = 65;
+ }
+
+ // let's do some wrapping on this label
+ wcsncpy( buf, pDesc, sizeof(buf) / sizeof( wchar_t ) );
+
+ if ( wcslen(buf) > iWrapLen )
+ {
+ int iPos = iWrapLen;
+
+ while ( iPos > 0 && buf[iPos] != L' ' )
+ {
+ iPos--;
+ }
+
+ if ( iPos > 0 && buf[iPos] == L' ' )
+ {
+ buf[iPos] = L'\n';
+ }
+ }
+
+ m_pDescription->SetText( buf );
+ }
+ else
+ {
+ m_pDescription->SetText( pDesc );
+ }
+
+ m_pSourceAchievement = pSourceAchievement;
+
+ m_pPercentageBarBackground = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBarBackground" ) );
+ m_pPercentageBar = SETUP_PANEL( new vgui::ImagePanel( this, "PercentageBar" ) );
+ m_pPercentageText = SETUP_PANEL( new vgui::Label( this, "PercentageText", "" ) );
+
+ // Set the status icons
+ m_pLockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "lockedicon" ) );
+ m_pUnlockedIcon = SETUP_PANEL( new vgui::ImagePanel( this, "unlockedicon" ) );
+
+ // Gamerscore number
+ if ( IsX360() )
+ {
+ wchar_t *wzFormat = g_pVGuiLocalize->Find( "#GameUI_Achievement_Points" ); // "%s1G"
+ wchar_t wzPoints[10];
+ V_snwprintf( wzPoints, ARRAYSIZE( wzPoints ), L"%d", points );
+ wchar_t wzPointsLayout[10];
+ g_pVGuiLocalize->ConstructString( wzPointsLayout, sizeof( wzPointsLayout ), wzFormat, 1, wzPoints );
+ m_pPoints = new vgui::Label( this, "Points", wzPointsLayout );
+ }
+
+ // Achievement image
+ m_pImage = new vgui::ImagePanel( this, "icon" );
+}
+
+CAchievementItem::~CAchievementItem()
+{
+ delete m_pImage;
+ delete m_pPoints;
+ delete m_pLockedIcon;
+ delete m_pUnlockedIcon;
+ delete m_pPercentageBarBackground;
+ delete m_pPercentageBar;
+ delete m_pPercentageText;
+}
+
+void CAchievementItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int x, y;
+
+ m_pPoints->SizeToContents();
+ m_pPoints->GetPos( x, y );
+ x = GetWide() - m_pPoints->GetWide() - m_nRightMargin;
+ m_pPoints->SetPos( x, y );
+
+}
+
+void CAchievementItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues*pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "AchievementItem.res" );
+ ApplySettings( pKeys );
+
+ m_pImage->SetBgColor( Color( 32, 32, 32, 255 ) );
+ m_pImage->SetFgColor( Color( 32, 32, 32, 255 ) );
+ m_pImage->SetPaintBackgroundEnabled( true );
+
+ m_pPoints->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+
+ // Set icon image
+ LoadAchievementIcon( m_pImage, m_pSourceAchievement );
+
+ // Percentage completion bar (for progressive achievements)
+ UpdateProgressBar( this, m_pSourceAchievement, m_clrProgressBar );
+
+ if ( m_pSourceAchievement && m_pSourceAchievement->IsAchieved() )
+ {
+ m_pLockedIcon->SetVisible( false );
+ m_pUnlockedIcon->SetVisible ( true );
+ m_pImage->SetVisible( true );
+ }
+ else
+ {
+ m_pLockedIcon->SetVisible( true );
+ m_pUnlockedIcon->SetVisible( false );
+ m_pImage->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------
+// CSectionedItem
+//
+// Menu item used to display some number of data entries, which are arranged
+// into columns. Supports scrolling through columns horizontally with the
+// ability to "lock" columns so they don't scroll
+//-----------------------------------------------------------------------
+CSectionedItem::CSectionedItem( CDialogMenu *pParent, const char **ppEntries, int ct )
+ : BaseClass( pParent, "", NULL, "SelectSession" )
+{
+ m_bHeader = false;
+ for ( int i = 0; i < ct; ++i )
+ {
+ AddSection( ppEntries[i], m_pParent->GetColumnAlignment( i ) );
+ }
+}
+
+CSectionedItem::~CSectionedItem()
+{
+ ClearSections();
+}
+
+void CSectionedItem::ClearSections()
+{
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ section_s &sec = m_Sections[i];
+ delete sec.pLabel;
+ }
+}
+
+void CSectionedItem::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ int tall = GetTall();
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ vgui::Label *pLabel = m_Sections[i].pLabel;
+ if ( !m_bHeader )
+ {
+ pLabel->SetFont( m_pParent->GetColumnFont(i) );
+ pLabel->SetFgColor( m_pParent->GetColumnColor(i) );
+ }
+ pLabel->SetBounds( m_pParent->GetColumnXPos(i), 0, m_pParent->GetColumnWide(i), tall );
+ pLabel->SetTextInset( 10, m_bHeader ? 5 : m_pParent->GetColumnYPos(i) ); // only use ypos for the y-inset if we're not a header
+ }
+}
+
+void CSectionedItem::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+}
+
+void CSectionedItem::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ KeyValues *pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SectionedItem.res" );
+ ApplySettings( pKeys );
+
+ int iLast = m_Sections.Count() -1;
+ SetWide( m_pParent->GetColumnXPos(iLast) + m_pParent->GetColumnWide(iLast) );
+}
+
+void CSectionedItem::AddSection( const char *pText, int align )
+{
+ section_s sec;
+ sec.pLabel = new vgui::Label( this, "Section", pText );
+ SETUP_PANEL( sec.pLabel );
+ sec.pLabel->SetContentAlignment( (vgui::Label::Alignment)align );
+ sec.pLabel->SetTextInset( 10, 0 );
+ sec.pLabel->SetBgColor( Color( 209, 112, 52, 128 ) );
+ m_Sections.AddToTail( sec );
+}
+
+void CSectionedItem::SetActiveColumn( int col )
+{
+ for ( int i = 0; i < m_Sections.Count(); ++i )
+ {
+ m_Sections[i].pLabel->SetPaintBackgroundEnabled( i == col );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Generic menu for Xbox 360 matchmaking dialogs. Contains a list of CMenuItems arranged
+// vertically. The user can navigate the list using the controller and click on any
+// item. A clicked item may send a command to the dialog and the dialog responds accordingly.
+//--------------------------------------------------------------------------------------
+CDialogMenu::CDialogMenu() : BaseClass( NULL, "DialogMenu" )
+{
+ // Quiet "parent not sized yet" spew
+ SetSize( 100, 100 );
+
+ m_pParent = NULL;
+ m_pHeader = NULL;
+ m_bUseFilter = false;
+ m_bHasHeader = false;
+ m_nItemSpacing = 0;
+ m_nMinWide = 0;
+ m_nActive = -1;
+ m_nActiveColumn = -1;
+ m_nBaseRowIdx = 0;
+ m_nBaseColumnIdx = 0;
+ m_iUnlocked = 0;
+ m_nMaxVisibleItems = 1000; // arbitrarily large
+ m_nMaxVisibleColumns = 1000;// arbitrarily large
+}
+
+CDialogMenu::~CDialogMenu()
+{
+ m_MenuItems.PurgeAndDeleteElements();
+ delete m_pHeader;
+}
+
+void CDialogMenu::SetParent( CBaseDialog *pParent )
+{
+ BaseClass::SetParent( pParent );
+ m_pParent = pParent;
+}
+
+//--------------------------------------------------------------------------------------
+// Set a filter to use when reading in menu item keyvalues
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFilter( const char *pFilter )
+{
+ if ( pFilter )
+ {
+ Q_strncpy( m_szFilter, pFilter, sizeof( m_szFilter ) );
+ m_bUseFilter = true;
+ }
+ else
+ {
+ m_bUseFilter = false;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Add a new menu item to the item array
+//--------------------------------------------------------------------------------------
+CMenuItem *CDialogMenu::AddItemInternal( CMenuItem *pItem )
+{
+ int idx = m_MenuItems.AddToTail( pItem );
+
+ SETUP_PANEL( pItem );
+
+ return m_MenuItems[idx];
+}
+
+//--------------------------------------------------------------------------------------
+// Add a new menu item of some type that derives from CMenuItem
+//--------------------------------------------------------------------------------------
+CCommandItem *CDialogMenu::AddCommandItem( const char *pTitleLabel, const char *pDescLabel, const char *pCommand )
+{
+ return (CCommandItem*)AddItemInternal( new CCommandItem( this, pTitleLabel, pDescLabel, pCommand ) );
+}
+
+CBrowserItem *CDialogMenu::AddBrowserItem( const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing )
+{
+ // Results are added to the menu at runtime, so the layout needs to be updated after each addition.
+ CBrowserItem *pItem = (CBrowserItem*)AddItemInternal( new CBrowserItem( this, pHost, pPlayers, pScenario, pPing ) );
+ PerformLayout();
+ return pItem;
+}
+
+COptionsItem *CDialogMenu::AddOptionsItem( const char *pLabel )
+{
+ return (COptionsItem*)AddItemInternal( new COptionsItem( this, pLabel ) );
+}
+
+CAchievementItem *CDialogMenu::AddAchievementItem( const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement )
+{
+ return (CAchievementItem*)AddItemInternal( new CAchievementItem( this, pName, pDesc, points, bUnlocked, pSourceAchievement ) );
+}
+
+CSectionedItem *CDialogMenu::AddSectionedItem( const char **ppEntries, int ct )
+{
+ CSectionedItem *pItem = (CSectionedItem*)AddItemInternal( new CSectionedItem( this, ppEntries, ct ) );
+ PerformLayout();
+ return pItem;
+}
+
+CPlayerItem *CDialogMenu::AddPlayerItem( const char *pTitleLabel, int64 nId, byte bVoice, bool bReady )
+{
+ // Players are added to the lobby at runtime, so the layout needs to be updated after each addition.
+ CPlayerItem *pItem = (CPlayerItem*)AddItemInternal( new CPlayerItem( this, pTitleLabel, nId, bVoice, bReady ) );
+ PerformLayout();
+ return pItem;
+}
+
+void CDialogMenu::RemovePlayerItem( int idx )
+{
+ delete m_MenuItems[idx];
+ m_MenuItems.Remove( idx );
+ PerformLayout();
+}
+
+void CDialogMenu::ClearItems()
+{
+ m_MenuItems.PurgeAndDeleteElements();
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------
+// Set the size an position of all the menu items
+//--------------------------------------------------------------------------------------
+void CDialogMenu::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Position the menu items and set their width
+ int yPos = 0;
+ int wide = GetWide();
+
+ if ( m_bHasHeader )
+ {
+ yPos = 40;
+ m_pHeader->SetPos( 0, 0 );
+ m_pHeader->SetWide( wide );
+ m_pHeader->PerformLayout();
+ }
+
+ for ( int i = 0; i < m_MenuItems.Count(); ++i )
+ {
+ CMenuItem *pItem = m_MenuItems[i];
+
+ pItem->SetPos( 0, yPos );
+ pItem->SetWide( wide );
+ pItem->SetActiveColumn( m_nActiveColumn );
+ pItem->PerformLayout();
+
+ if ( i < m_nBaseRowIdx || i > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
+ {
+ pItem->SetVisible( false );
+ }
+ else
+ {
+ pItem->SetVisible( true );
+ yPos += pItem->GetTall() + m_nItemSpacing;
+ }
+ }
+
+ // Reset the focus to update background colors of all menu items
+ SetFocus( m_nActive );
+
+
+ SetTall( yPos );
+}
+
+//--------------------------------------------------------------------------------------
+// Parse the res file for menu items to build out the dialog menu.
+//--------------------------------------------------------------------------------------
+void CDialogMenu::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ m_nItemSpacing = pResourceData->GetInt( "itemspacing", 2 );
+ m_nMinWide = pResourceData->GetInt( "minwide", 0 );
+ m_nActiveColumn = pResourceData->GetInt( "activecolumn", -1 );
+ m_nMaxVisibleItems = pResourceData->GetInt( "maxvisibleitems", 1000 ); // arbitrarily large
+ m_nMaxVisibleColumns = pResourceData->GetInt( "maxvisiblecolumns", 1000 ); // arbitrarily large
+
+ KeyValues *pColumnData = pResourceData->FindKey( "Columns" );
+ if ( pColumnData )
+ {
+ int xPos = 0;
+ int idx = 0;
+ const char *ppHeader[MAX_COLUMNS];
+ for ( KeyValues *pColumn = pColumnData->GetFirstSubKey(); pColumn != NULL; pColumn = pColumn->GetNextKey() )
+ {
+ if ( !Q_stricmp( pColumn->GetName(), "Column" ) )
+ {
+ columninfo_s col;
+ col.bSortDown = true;
+ col.xpos = pColumn->GetInt( "xpos", xPos );
+ col.ypos = pColumn->GetInt( "ypos", 0 );
+ col.wide = pColumn->GetInt( "wide", 0 );
+ col.align = pColumn->GetInt( "align", 3 ); // west by default
+ col.bLocked = pColumn->GetInt( "locked", 0 );
+ col.hFont = m_pScheme->GetFont( pColumn->GetString( "font", "default" ) );
+ col.color = m_pScheme->GetColor( pColumn->GetString( "fgcolor" ), Color( 0, 0, 0, 255 ) );
+
+ ppHeader[idx++] = pColumn->GetString( "header", "" );
+
+ xPos = col.xpos + col.wide;
+ m_Columns.AddToTail( col );
+
+ if ( col.bLocked )
+ {
+ m_nBaseColumnIdx = idx;
+ m_iUnlocked = idx;
+ }
+ }
+ }
+ m_bHasHeader = true;
+ m_pHeader = new CSectionedItem( this, ppHeader, idx );
+ m_pHeader->m_bHeader = true;
+ SETUP_PANEL( m_pHeader );
+
+ m_pHeader->SetPaintBackgroundEnabled( false );
+ vgui::HFont headerFont = m_pScheme->GetFont( pColumnData->GetString( "headerfont", "default" ) );
+ Color headerColor = m_pScheme->GetColor( pColumnData->GetString( "headerfgcolor" ), Color( 0, 0, 0, 255 ) );
+ for ( int i = 0; i < idx; ++i )
+ {
+ vgui::Label *pLabel = m_pHeader->m_Sections[i].pLabel;
+ pLabel->SetFont( headerFont );
+ pLabel->SetFgColor( headerColor );
+ pLabel->SetPaintBackgroundEnabled( false );
+ }
+ }
+
+ for ( KeyValues *pMenuData = pResourceData->GetFirstSubKey(); pMenuData != NULL; pMenuData = pMenuData->GetNextKey() )
+ {
+ // See if we should skip over this block
+ if ( m_bUseFilter )
+ {
+ if ( pMenuData->GetInt( m_szFilter, 0 ) == 0 )
+ continue;
+ }
+
+ // Give our parent a chance to change the properties of this item
+ m_pParent->OverrideMenuItem( pMenuData );
+
+ if ( !Q_stricmp( pMenuData->GetName(), "CommandItem" ) )
+ {
+ // New Command Item
+ const char *label = pMenuData->GetString( "label", "<unknown>" );
+ const char *description = pMenuData->GetString( "description", NULL );
+ const char *command = pMenuData->GetString( "command", "<unknown>" );
+
+ AddCommandItem( label, description, command );
+ }
+ else if ( !Q_stricmp( pMenuData->GetName(), "OptionsItem" ) )
+ {
+ // New Options Item
+ COptionsItem *pItem = AddOptionsItem( pMenuData->GetString( "label", "<unknown>" ) );
+
+ // ID and ValueType and the same for all option values
+ const char *pID = pMenuData->GetString( "id", "NULL" );
+ const char *pValueType = pMenuData->GetString( "valuetype", NULL );
+
+ // Add all the options
+ for ( KeyValues *pValue = pMenuData->GetFirstSubKey(); pValue != NULL; pValue = pValue->GetNextKey() )
+ {
+ if ( !Q_stricmp( pValue->GetName(), "Option" ) )
+ {
+ sessionProperty_t prop;
+ prop.nType = SESSION_CONTEXT;
+ Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
+ Q_strncpy( prop.szValue, pValue->GetString( "value", "NULL" ), sizeof( prop.szValue ) );
+
+ if ( pValueType )
+ {
+ // Only session properties have a type
+ prop.nType = SESSION_PROPERTY;
+ Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
+ }
+
+ const char *pLabel = pValue->GetString( "label", "<unknown>" );
+ pItem->AddOption( pLabel, prop );
+ }
+ }
+
+ // Add range items after the specified items
+ if ( pMenuData->GetInt( "userange" ) )
+ {
+ // Options are an implicit range of integers
+ int nStart = pMenuData->GetInt( "rangelow" );
+ int nEnd = pMenuData->GetInt( "rangehigh" );
+ int nInterval = pMenuData->GetInt( "interval", 1 );
+
+ // Prevent total destruction from a bad resource file
+ if ( nEnd < nStart )
+ {
+ nEnd = nStart;
+ }
+
+ for ( int i = nStart; i <= nEnd; i += nInterval )
+ {
+ sessionProperty_t prop;
+ prop.nType = SESSION_PROPERTY;
+ Q_strncpy( prop.szID, pID, sizeof( prop.szID ) );
+ Q_strncpy( prop.szValueType, pValueType, sizeof( prop.szValueType ) );
+ Q_snprintf( prop.szValue, sizeof(prop.szValue), "%d", i );
+
+ pItem->AddOption( prop.szValue, prop );
+ }
+ }
+
+ // Set the default active option
+ int active = pMenuData->GetInt( "activeoption", 0 );
+ pItem->SetOptionFocus( active );
+
+ // Notify our parent that each option has been set to its current setting
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", GetItemCount() - 1 );
+ PostActionSignal( kv );
+ }
+ }
+
+ // Calculate the final menu size according to the widest menu item
+ int wide = m_nMinWide;
+ for ( int i = 0; i < m_MenuItems.Count(); ++i )
+ {
+ wide = max( wide, m_MenuItems[i]->GetWide() );
+ }
+ SetWide( wide );
+}
+
+//--------------------------------------------------------------------------------------
+// Cache off the scheme
+//--------------------------------------------------------------------------------------
+void CDialogMenu::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pScheme = pScheme;
+}
+
+//--------------------------------------------------------------------------------------
+// Give focus (highlights) a particular menu item by index
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocus( int idx )
+{
+ int itemCt = (unsigned int)m_MenuItems.Count();
+ if ( idx >= itemCt )
+ return;
+
+ for ( int i = 0; i < itemCt; ++i )
+ {
+ m_MenuItems[i]->SetFocus( i == idx );
+ }
+ m_nActive = idx;
+
+ if ( m_nActive >= 0 && m_nActive < m_nBaseRowIdx )
+ {
+ m_nBaseRowIdx = m_nActive;
+ }
+ else if ( m_nActive > m_nBaseRowIdx + m_nMaxVisibleItems - 1 )
+ {
+ m_nBaseRowIdx = m_nActive - ( m_nMaxVisibleItems - 1 );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Sort the menu items according to the selected column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SortMenuItems()
+{
+ if ( !m_bHasHeader )
+ return;
+
+ // Simple bubble sort
+ char szBufferOne[32];
+ char szBufferTwo[32];
+ bool bSortDown = GetColumnSortType( m_nActiveColumn );
+ for ( int i = 1; i <= m_MenuItems.Count(); ++i )
+ {
+ for ( int j = 0; j < m_MenuItems.Count() - i; ++j )
+ {
+ ((CSectionedItem*)m_MenuItems[j])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferOne, sizeof( szBufferOne ) );
+ ((CSectionedItem*)m_MenuItems[j+1])->m_Sections[m_nActiveColumn].pLabel->GetText( szBufferTwo, sizeof( szBufferTwo ) );
+
+ int diff = Q_stricmp( szBufferOne, szBufferTwo );
+ bool bSwap = bSortDown ? diff > 0 : diff < 0;
+ if ( bSwap )
+ {
+ CMenuItem *pTemp = m_MenuItems[j+1];
+ m_MenuItems[j+1] = m_MenuItems[j];
+ m_MenuItems[j] = pTemp;
+
+ m_pParent->SwapMenuItems( j, j+1 );
+ }
+ }
+ }
+ InvalidateLayout();
+}
+
+//--------------------------------------------------------------------------------------
+// Move item focus to the next item in the menu - supports wrapping
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocusNext()
+{
+ if ( m_MenuItems.Count() )
+ {
+ int iNewIndex = ( m_nActive + 1 ) % m_MenuItems.Count();
+
+ int i = 0;
+ bool bSet = false;
+ while ( i < m_MenuItems.Count() )
+ {
+ if ( m_MenuItems[iNewIndex]->IsEnabled() )
+ {
+ SetFocus( iNewIndex );
+ bSet = true;
+ break;
+ }
+
+ iNewIndex = ( iNewIndex + 1 ) % m_MenuItems.Count();
+ i++;
+ }
+
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// Move item focus to the previous item in the menu - supports wrapping
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetFocusPrev()
+{
+ if ( m_MenuItems.Count() )
+ {
+ int iNewIndex = m_nActive - 1;
+ if ( iNewIndex < 0 )
+ iNewIndex = m_MenuItems.Count() - 1;
+
+ int i = 0;
+ bool bSet = false;
+ while ( i < m_MenuItems.Count() )
+ {
+ if ( m_MenuItems[iNewIndex]->IsEnabled() )
+ {
+ SetFocus( iNewIndex );
+ bSet = true;
+ break;
+ }
+
+ if ( --iNewIndex < 0 )
+ iNewIndex = m_MenuItems.Count() - 1;
+
+ i++;
+ }
+
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Move focus to the next option in the menu item - does not wrap
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetOptionFocusNext()
+{
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
+ if ( pItem )
+ {
+ pItem->SetOptionFocusNext();
+
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
+ PostActionSignal( kv );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Move focus to the previous option in the menu item - does not wrap
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetOptionFocusPrev()
+{
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( m_nActive ) );
+ if ( pItem )
+ {
+ pItem->SetOptionFocusPrev();
+
+ KeyValues *kv = new KeyValues( "MenuItemChanged", "item", m_nActive );
+ PostActionSignal( kv );
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Update the base index for the columns
+//--------------------------------------------------------------------------------------
+void CDialogMenu::UpdateBaseColumnIndex()
+{
+ if ( m_iUnlocked + m_nActiveColumn - m_nBaseColumnIdx >= m_nMaxVisibleColumns )
+ {
+ m_nBaseColumnIdx = m_iUnlocked + m_nActiveColumn - m_nMaxVisibleColumns + 1;
+ }
+ else if ( m_nActiveColumn - m_nBaseColumnIdx < 0 )
+ {
+ m_nBaseColumnIdx = m_nActiveColumn;
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For menus with sectioned columns - move focus to the next column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetColumnFocusNext()
+{
+ if ( m_nActiveColumn == -1 )
+ return;
+
+ if ( m_Columns.Count() )
+ {
+ int iNewColumn = m_nActiveColumn + 1;
+ if ( iNewColumn >= m_Columns.Count() )
+ return;
+
+ m_nActiveColumn = iNewColumn;
+ UpdateBaseColumnIndex();
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For menus with sectioned columns - move focus to the next column
+//--------------------------------------------------------------------------------------
+void CDialogMenu::SetColumnFocusPrev()
+{
+ if ( m_nActiveColumn == -1 )
+ return;
+
+ if ( m_Columns.Count() )
+ {
+ int iNewColumn = m_nActiveColumn - 1;
+ if ( iNewColumn < 0 || m_Columns[iNewColumn].bLocked )
+ return;
+
+ m_nActiveColumn = iNewColumn;
+ UpdateBaseColumnIndex();
+ InvalidateLayout();
+ }
+}
+
+//--------------------------------------------------------------------------------------
+// For OptionsItems: Lets the dialog find out which option is currently selected
+//--------------------------------------------------------------------------------------
+int CDialogMenu::GetActiveOptionIndex( int nMenuItemIdx )
+{
+ int retval = -1;
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( GetItem( nMenuItemIdx ) );
+ if ( pItem )
+ {
+ retval = pItem->GetActiveOptionIndex();
+ }
+ return retval;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active menu item
+//-----------------------------------------------------------------------
+int CDialogMenu::GetActiveItemIndex()
+{
+ return m_nActive;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the current active menu column
+//-----------------------------------------------------------------------
+int CDialogMenu::GetActiveColumnIndex()
+{
+ return m_nActiveColumn;
+}
+
+//-----------------------------------------------------------------------
+// Return the number of menu items
+//-----------------------------------------------------------------------
+int CDialogMenu::GetItemCount()
+{
+ return m_MenuItems.Count();
+}
+
+//-----------------------------------------------------------------------
+// Return the number of visible menu items
+//-----------------------------------------------------------------------
+int CDialogMenu::GetVisibleItemCount()
+{
+ return min( GetItemCount(), m_nMaxVisibleItems );
+}
+
+//-----------------------------------------------------------------------
+// Return the number of visible menu columns
+//-----------------------------------------------------------------------
+int CDialogMenu::GetVisibleColumnCount()
+{
+ return m_nMaxVisibleColumns;
+}
+
+//-----------------------------------------------------------------------
+// Return the index of the first unlocked column
+//-----------------------------------------------------------------------
+int CDialogMenu::GetFirstUnlockedColumnIndex()
+{
+ return m_iUnlocked;
+}
+
+//-----------------------------------------------------------------------
+// Return the first visible index in the menu
+//-----------------------------------------------------------------------
+int CDialogMenu::GetBaseRowIndex()
+{
+ return m_nBaseRowIdx;
+}
+
+//-----------------------------------------------------------------------
+// Set the first visible index in the menu
+//-----------------------------------------------------------------------
+void CDialogMenu::SetBaseRowIndex( int idx )
+{
+ m_nBaseRowIdx = idx;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified menu item
+//-----------------------------------------------------------------------
+CMenuItem *CDialogMenu::GetItem( int idx )
+{
+ if ( m_MenuItems.IsValidIndex( idx ) )
+ {
+ return m_MenuItems[idx];
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column xpos
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnXPos( int idx )
+{
+ // Compensate for scrolling offsets
+ columninfo_s &col = m_Columns[idx];
+
+ int xpos;
+ if ( col.bLocked )
+ {
+ xpos = m_Columns[idx].xpos;
+ }
+ else
+ {
+ int trueIdx = m_iUnlocked + idx - m_nBaseColumnIdx;
+ if ( trueIdx < m_iUnlocked )
+ {
+ // Put it offscreen
+ xpos = -100 - col.wide;
+ }
+ else
+ {
+ xpos = m_Columns[trueIdx].xpos;
+ }
+ }
+ return xpos;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column ypos
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnYPos( int idx )
+{
+ return m_Columns[idx].ypos;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column width
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnWide( int idx )
+{
+ return m_Columns[idx].wide;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column alignment
+//-----------------------------------------------------------------------
+int CDialogMenu::GetColumnAlignment( int idx )
+{
+ return m_Columns[idx].align;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column font
+//-----------------------------------------------------------------------
+HFont CDialogMenu::GetColumnFont( int idx )
+{
+ return m_Columns[idx].hFont;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column fgcolor
+//-----------------------------------------------------------------------
+Color CDialogMenu::GetColumnColor( int idx )
+{
+ return m_Columns[idx].color;
+}
+
+//-----------------------------------------------------------------------
+// Return the specified column fgcolor
+//-----------------------------------------------------------------------
+bool CDialogMenu::GetColumnSortType( int idx )
+{
+ bool bSortDown = m_Columns[idx].bSortDown;
+ m_Columns[idx].bSortDown = !bSortDown;
+ return bSortDown;
+}
+
+//--------------------------------------------------------------------------------------
+// Receive the command from a clicked menu item and forwards it to the parent dialog
+//--------------------------------------------------------------------------------------
+void CDialogMenu::OnCommand( const char *pCommand )
+{
+ GetParent()->OnCommand( pCommand );
+}
+
+//--------------------------------------------------------------------------------------
+// Update the menu state according to controller input.
+// Returns whether or not the keycode was handled by the menu.
+//--------------------------------------------------------------------------------------
+bool CDialogMenu::HandleKeyCode( vgui::KeyCode code )
+{
+ switch( code )
+ {
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ SetFocusNext();
+ break;
+
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ SetFocusPrev();
+ break;
+
+ case KEY_XBUTTON_LEFT:
+ case KEY_XSTICK1_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ SetOptionFocusPrev();
+ SetColumnFocusPrev();
+ break;
+
+ case KEY_XBUTTON_RIGHT:
+ case KEY_XSTICK1_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ SetOptionFocusNext();
+ SetColumnFocusNext();
+ break;
+
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+ if ( m_MenuItems.Count() && m_nActive >= 0 )
+ {
+ m_MenuItems[m_nActive]->OnClick();
+ }
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ SortMenuItems();
+ break;
+
+ default:
+ // Not handled
+ return false;
+ }
+
+ return true;
+}
+
diff --git a/gameui/matchmaking/dialogmenu.h b/gameui/matchmaking/dialogmenu.h
new file mode 100644
index 0000000..83940d9
--- /dev/null
+++ b/gameui/matchmaking/dialogmenu.h
@@ -0,0 +1,367 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef DIALOGMENU_H
+#define DIALOGMENU_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#if defined(_WIN32) && !defined(_X360)
+#include "winlite.h" // FILETIME
+#endif
+
+#include "vgui_controls/Panel.h"
+#include "vgui_controls/Frame.h"
+
+class IAchievement;
+
+#define MAX_COMMAND_LEN 256
+#define MAX_COLUMNS 32
+
+class CDialogMenu;
+class CBaseDialog;
+
+struct sessionProperty_t
+{
+ static const int MAX_KEY_LEN = 64;
+ byte nType;
+ char szID[MAX_KEY_LEN];
+ char szValue[MAX_KEY_LEN];
+ char szValueType[MAX_KEY_LEN];
+};
+
+//-----------------------------------------------------------------------
+// Base class representing a generic menu item. Supports two text labels,
+// where the first label is the "action" text and the second is an optional
+// description of the action.
+//-----------------------------------------------------------------------
+class CMenuItem : public vgui::EditablePanel
+{
+ DECLARE_CLASS_SIMPLE( CMenuItem, vgui::EditablePanel );
+
+public:
+ CMenuItem( CDialogMenu *pParent, const char *pTitle, const char *pDescription );
+ virtual ~CMenuItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *pSettings );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void SetFocus( const bool bActive );
+ virtual void SetEnabled( bool bEnabled );
+ virtual void SetActiveColumn( int col );
+ virtual bool IsEnabled();
+ virtual void OnClick();
+
+protected:
+ CDialogMenu *m_pParent;
+
+ vgui::Label *m_pTitle;
+ vgui::Label *m_pDescription;
+
+ Color m_BgColor;
+ Color m_BgColorActive;
+
+ int m_nDisabledAlpha;
+ int m_nBottomMargin;
+ int m_nRightMargin;
+
+ bool m_bEnabled;
+};
+
+//-----------------------------------------------------------------------
+// CCommandItem
+//
+// Menu item that issues a command when clicked.
+//-----------------------------------------------------------------------
+class CCommandItem : public CMenuItem
+{
+ DECLARE_CLASS_SIMPLE( CCommandItem, CMenuItem );
+
+public:
+ CCommandItem( CDialogMenu *pParent, const char *pTitle, const char *pDescription, const char *pCommand );
+ virtual ~CCommandItem();
+
+ virtual void OnClick();
+ virtual void SetFocus( const bool bActive );
+
+ bool m_bHasFocus;
+
+ char m_szCommand[MAX_PATH];
+};
+
+//-----------------------------------------------------------------------
+// CPlayerItem
+//
+// Menu item to display a player in the lobby.
+//-----------------------------------------------------------------------
+class CPlayerItem : public CCommandItem
+{
+ DECLARE_CLASS_SIMPLE( CMenuItem, CCommandItem );
+
+public:
+ CPlayerItem( CDialogMenu *pParent, const char *pTitle, int64 nId, byte bVoice, bool bReady );
+ virtual ~CPlayerItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual void OnClick();
+
+ vgui::Label *m_pVoiceIcon;
+ vgui::Label *m_pReadyIcon;
+
+ byte m_bVoice;
+ bool m_bReady;
+ uint64 m_nId;
+};
+
+//-----------------------------------------------------------------------
+// CBrowserItem
+//
+// Menu item used to display session search results, etc.
+//-----------------------------------------------------------------------
+class CBrowserItem : public CCommandItem
+{
+ DECLARE_CLASS_SIMPLE( CBrowserItem, CCommandItem );
+
+public:
+ CBrowserItem( CDialogMenu *pParent, const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing );
+ virtual ~CBrowserItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *pSettings );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+private:
+ vgui::Label *m_pPlayers;
+ vgui::Label *m_pScenario;
+ vgui::Label *m_pPing;
+};
+
+//-----------------------------------------------------------------------
+// COptionsItem
+//
+// Menu item used to present a list of options for the player to select
+// from, such as "choose a map" or "number of rounds".
+//-----------------------------------------------------------------------
+class COptionsItem : public CMenuItem
+{
+ DECLARE_CLASS_SIMPLE( COptionsItem, CMenuItem );
+
+public:
+ COptionsItem( CDialogMenu *pParent, const char *pLabel );
+ virtual ~COptionsItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *pSettings );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void SetFocus( const bool bActive );
+
+ void SetOptionFocus( unsigned int idx );
+ void SetOptionFocusNext();
+ void SetOptionFocusPrev();
+
+ void AddOption( const char *pLabelText, const sessionProperty_t &option );
+ int GetActiveOptionIndex();
+ const sessionProperty_t &GetActiveOption();
+
+ void DeleteAllOptions()
+ {
+ m_Options.RemoveAll();
+ m_OptionLabels.PurgeAndDeleteElements();
+ m_nActiveOption = m_Options.InvalidIndex();
+ }
+private:
+ int m_nActiveOption;
+ int m_nOptionsXPos;
+ int m_nOptionsMinWide;
+ int m_nOptionsLeftMargin;
+ int m_nMaxOptionWidth;
+ int m_nArrowGap;
+
+ CUtlVector< vgui::Label* > m_OptionLabels;
+ CUtlVector< sessionProperty_t > m_Options;
+
+ char m_szOptionsFont[64];
+ vgui::HFont m_hOptionsFont;
+
+ vgui::Label *m_pLeftArrow;
+ vgui::Label *m_pRightArrow;
+};
+
+//-----------------------------------------------------------------------
+// CAchievementItem
+//
+// Menu item used to present an achievement - including image, title,
+// description, points and unlock date. Clicking the item opens another
+// dialog with additional information about the achievement.
+//-----------------------------------------------------------------------
+class CAchievementItem : public CMenuItem
+{
+ DECLARE_CLASS_SIMPLE( CAchievementItem, CMenuItem );
+
+public:
+ CAchievementItem( CDialogMenu *pParent, const wchar_t *pName, const wchar_t *pDesc, uint points, bool bUnlocked, IAchievement* pSourceAchievement );
+ virtual ~CAchievementItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+private:
+ vgui::Label *m_pPoints;
+ vgui::ImagePanel *m_pLockedIcon;
+ vgui::ImagePanel *m_pUnlockedIcon;
+ vgui::ImagePanel *m_pImage;
+
+ vgui::ImagePanel *m_pPercentageBarBackground;
+ vgui::ImagePanel *m_pPercentageBar;
+ vgui::Label *m_pPercentageText;
+
+ IAchievement *m_pSourceAchievement;
+
+ Color m_AchievedBGColor;
+ Color m_UnachievedBGColor;
+
+ CPanelAnimationVar( Color, m_clrProgressBar, "ProgressBarColor", "140 140 140 255" );
+};
+
+//-----------------------------------------------------------------------
+// CSectionedItem
+//
+// Menu item used to display some number of data entries, which are arranged
+// into columns. Supports scrolling through columns horizontally with the
+// ability to "lock" columns so they don't scroll
+//-----------------------------------------------------------------------
+class CSectionedItem : public CCommandItem
+{
+ DECLARE_CLASS_SIMPLE( CSectionedItem, CCommandItem );
+
+public:
+ CSectionedItem( CDialogMenu *pParent, const char **ppEntries, int ct );
+ virtual ~CSectionedItem();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *pSettings );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual void SetActiveColumn( int col );
+
+ void ClearSections();
+ void AddSection( const char *pText, int wide );
+
+ struct section_s
+ {
+ int wide;
+ vgui::Label *pLabel;
+ };
+ CUtlVector< section_s >m_Sections;
+
+ bool m_bHeader;
+};
+
+//--------------------------------------------------------------------------------------
+// Generic menu for Xbox 360 matchmaking dialogs. Contains a list of CMenuItems arranged
+// vertically. The user can navigate the list using the controller and click on any
+// item. A clicked item may send a command to the dialog and the dialog responds accordingly.
+//--------------------------------------------------------------------------------------
+class CDialogMenu : public vgui::Panel
+{
+ DECLARE_CLASS_SIMPLE( CDialogMenu, vgui::Panel );
+
+public:
+ CDialogMenu();
+ ~CDialogMenu();
+
+ virtual void OnCommand( const char *pCommand );
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void PerformLayout();
+ void SetFilter( const char *pFilter );
+ virtual bool HandleKeyCode( vgui::KeyCode code );
+ void SetMaxVisibleItems( uint nMaxVisibleItems );
+ void SetParent( CBaseDialog *pParent );
+
+ // Menu items
+ CCommandItem *AddCommandItem( const char *pTitleLabel, const char *pDescLabel, const char *pCommand );
+ CPlayerItem *AddPlayerItem( const char *pTitleLabel, int64 nId, byte bVoice, bool bReady );
+ CBrowserItem *AddBrowserItem( const char *pHost, const char *pPlayers, const char *pScenario, const char *pPing );
+ COptionsItem *AddOptionsItem( const char *pLabel );
+ CSectionedItem *AddSectionedItem( const char **ppEntries, int ct );
+ CAchievementItem *AddAchievementItem( const wchar_t *pName, const wchar_t *pDesc, uint cred, bool bUnlocked, IAchievement* pSourceAchievement );
+ CMenuItem *AddItemInternal( CMenuItem *pItem );
+
+ void RemovePlayerItem( int idx );
+ void SortMenuItems();
+ void ClearItems();
+
+ // Navigation
+ void SetFocus( int idx );
+ void SetFocusNext();
+ void SetFocusPrev();
+ void SetOptionFocusNext();
+ void SetOptionFocusPrev();
+ void SetColumnFocusNext();
+ void SetColumnFocusPrev();
+ void UpdateBaseColumnIndex();
+
+ // Accessors
+ CMenuItem *GetItem( int idx);
+ int GetItemCount();
+ int GetActiveItemIndex();
+ int GetActiveColumnIndex();
+ int GetActiveOptionIndex( int idx );
+ int GetVisibleItemCount();
+ int GetVisibleColumnCount();
+ int GetFirstUnlockedColumnIndex();
+ int GetBaseRowIndex();
+ void SetBaseRowIndex( int idx );
+ int GetColumnXPos( int idx );
+ int GetColumnYPos( int idx );
+ int GetColumnWide( int idx );
+ int GetColumnAlignment( int idx );
+ vgui::HFont GetColumnFont( int idx );
+ Color GetColumnColor( int idx );
+ bool GetColumnSortType( int idx );
+
+private:
+ struct columninfo_s
+ {
+ int xpos;
+ int ypos;
+ int wide;
+ int align;
+ bool bLocked;
+ Color color;
+ vgui::HFont hFont;
+ bool bSortDown;
+ };
+ CUtlVector< columninfo_s >m_Columns;
+ CUtlVector< CMenuItem* > m_MenuItems;
+
+ CBaseDialog *m_pParent;
+ CSectionedItem *m_pHeader;
+ vgui::IScheme *m_pScheme;
+
+ char m_szFilter[MAX_COMMAND_LEN]; // string to use as a keyvalues filter when reading in menu items
+
+ int m_nItemSpacing; // gap between menu items
+ int m_nMinWide; // minimum width - final menu width will always be >= m_nMinWide
+
+ bool m_bInitialized;
+ bool m_bUseFilter;
+ bool m_bHasHeader;
+ int m_nMaxVisibleItems; // max number of items to display in the menu
+ int m_nMaxVisibleColumns; // max number of columns to display in the menu
+ int m_nActiveColumn; // index of the current active column
+ int m_nBaseColumnIdx; // array index of the first non-static column
+ int m_nBaseRowIdx; // array index of the first visible row
+ int m_nActive; // index of the current active item
+ int m_iUnlocked; // first unlocked column in the menu
+};
+
+#endif // DIALOGMENU_H
diff --git a/gameui/matchmaking/leaderboarddialog.cpp b/gameui/matchmaking/leaderboarddialog.cpp
new file mode 100644
index 0000000..93885db
--- /dev/null
+++ b/gameui/matchmaking/leaderboarddialog.cpp
@@ -0,0 +1,563 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Displays a leaderboard
+//
+//=============================================================================//
+
+#include "leaderboarddialog.h"
+#include "vgui_controls/Label.h"
+#include "vgui/ILocalize.h"
+#include "hl2orange.spa.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define NUM_ROWS_PER_QUERY 100
+
+CLeaderboardDialog *g_pLeaderboardDialog;
+
+//----------------------------------------------------------
+// CLeaderboardDialog
+//----------------------------------------------------------
+CLeaderboardDialog::CLeaderboardDialog( vgui::Panel *pParent ) : BaseClass( pParent, "LeaderboardDialog" )
+{
+ g_pLeaderboardDialog = this;
+ m_iBaseRank = 0;
+ m_iActiveRank = 0;
+ m_iMaxRank = 0;
+ m_cColumns = 0;
+ m_iRangeBase = 0;
+#if defined( _X360 )
+ m_pStats = NULL;
+#endif
+
+ m_pProgressBg = new vgui::Panel( this, "ProgressBg" );
+ m_pProgressBar = new vgui::Panel( this, "ProgressBar" );
+ m_pProgressPercent = new vgui::Label( this, "ProgressPercent", "" );
+ m_pNumbering = new vgui::Label( this, "Numbering", "" );
+ m_pUpArrow = new vgui::Label( this, "UpArrow", "" );
+ m_pDownArrow = new vgui::Label( this, "DownArrow", "" );
+ m_pBestMoments = new vgui::Label( this, "BestMoments", "" );
+}
+
+CLeaderboardDialog::~CLeaderboardDialog()
+{
+ CleanupStats();
+
+ delete m_pProgressBg;
+ delete m_pProgressBar;
+ delete m_pProgressPercent;
+ delete m_pNumbering;
+ delete m_pUpArrow;
+ delete m_pDownArrow;
+}
+
+//----------------------------------------------------------
+// Clean up the stats array
+//----------------------------------------------------------
+void CLeaderboardDialog::CleanupStats()
+{
+#if defined( _X360 )
+ if ( m_pStats )
+ {
+ delete [] m_pStats;
+ m_pStats = NULL;
+ }
+#endif
+}
+
+//----------------------------------------------------------
+// Position the dialogs elements
+//----------------------------------------------------------
+void CLeaderboardDialog::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ if ( m_cColumns )
+ {
+ int x, y, wide, tall;
+ m_pProgressBg->GetBounds( x, y, wide, tall );
+
+ int columnWide = wide / m_cColumns;
+ int lockedColumns = m_Menu.GetFirstUnlockedColumnIndex();
+ int visibleColumns = m_Menu.GetVisibleColumnCount() - lockedColumns;
+ int iColumn = m_Menu.GetActiveColumnIndex() - lockedColumns;
+
+ if ( iColumn < 0 )
+ {
+ iColumn = 0;
+ }
+ else if ( iColumn < m_iRangeBase )
+ {
+ m_iRangeBase = iColumn;
+ }
+ else if ( iColumn >= m_iRangeBase + visibleColumns )
+ {
+ m_iRangeBase = iColumn - visibleColumns + 1;
+ }
+
+ m_pProgressBg->SetBounds( x, y, columnWide * m_cColumns, tall );
+ m_pProgressBar->SetBounds( x + columnWide * m_iRangeBase, y, columnWide * visibleColumns, tall );
+ }
+ else
+ {
+ m_pProgressBg->SetVisible( false );
+ m_pProgressBar->SetVisible( false );
+ }
+
+ int menux, menuy;
+ m_Menu.GetPos( menux, menuy );
+
+ // Do a perform layout on the menu so we get the correct height now
+ m_Menu.InvalidateLayout( true, false );
+
+ m_pNumbering->SizeToContents();
+
+ wchar_t wszNumbering[64];
+ wchar_t *wzNumberingFmt = g_pVGuiLocalize->Find( "#GameUI_Achievement_Menu_Range" );
+ wchar_t wzActiveItem[8];
+ wchar_t wzTotal[8];
+
+ int iActive = m_iBaseRank + m_Menu.GetActiveItemIndex();
+ if ( iActive < 0 )
+ {
+ iActive = 0;
+ }
+ V_snwprintf( wzActiveItem, ARRAYSIZE( wzActiveItem ), L"%d", iActive );
+ V_snwprintf( wzTotal, ARRAYSIZE( wzTotal ), L"%d", m_iMaxRank );
+ g_pVGuiLocalize->ConstructString( wszNumbering, sizeof( wszNumbering ), wzNumberingFmt, 2, wzActiveItem, wzTotal );
+ m_pNumbering->SetText( wszNumbering );
+ m_pNumbering->SetWide( GetWide() );
+
+ MoveToCenterOfScreen();
+}
+
+//----------------------------------------------------------
+//
+//----------------------------------------------------------
+void CLeaderboardDialog::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XBUTTON_DOWN, 0.05f );
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XSTICK1_DOWN, 0.05f );
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XBUTTON_UP, 0.05f );
+ m_KeyRepeat.SetKeyRepeatTime( KEY_XSTICK1_UP, 0.05f );
+}
+
+//----------------------------------------------------------
+//
+//----------------------------------------------------------
+void CLeaderboardDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_pProgressBg->SetBgColor( Color( 200, 184, 151, 255 ) );
+ m_pProgressBar->SetBgColor( Color( 179, 82, 22, 255 ) );
+ m_pNumbering->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+ m_pBestMoments->SetFgColor( pScheme->GetColor( "MatchmakingMenuItemDescriptionColor", Color( 64, 64, 64, 255 ) ) );
+}
+
+//----------------------------------------------------------
+//
+//----------------------------------------------------------
+void CLeaderboardDialog::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "CenterOnPlayer" ) )
+ {
+ if ( GetPlayerStats( -1 ) == 0 )
+ {
+ // Player isn't on the board, just start at rank 1
+ GetPlayerStats( 1 );
+ }
+ }
+ else if ( !Q_stricmp( pCommand, "Friends" ) )
+ {
+ GetPlayerStats( -1, true );
+ }
+
+ BaseClass::OnCommand( pCommand );
+}
+
+//----------------------------------------------------------
+//
+//----------------------------------------------------------
+void CLeaderboardDialog::AddLeaderboardEntry( const char **ppEntries, int ct )
+{
+ m_Menu.AddSectionedItem( ppEntries, ct );
+}
+
+//----------------------------------------------------------
+// Get some portion of the leaderboard. This should ideally live
+// in the client, since it's very mod-specific
+//----------------------------------------------------------
+bool CLeaderboardDialog::GetPlayerStats( int rank, bool bFriends )
+{
+#if defined _X360
+ HANDLE handle;
+
+ // Retrieve the necessary buffer size
+ DWORD cbResults = 0;
+
+ bool bRanked = false;
+ const char *pName = GetName();
+ if ( !Q_stricmp( pName, "LeaderboardDialog_Ranked" ) )
+ {
+ bRanked = true;
+ }
+
+ XUSER_STATS_SPEC spec;
+ if ( !bRanked )
+ {
+ spec.dwViewId = STATS_VIEW_PLAYER_MAX_UNRANKED;
+ spec.dwNumColumnIds = 15;
+ spec.rgwColumnIds[0] = STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_SCORED;
+ spec.rgwColumnIds[1] = STATS_COLUMN_PLAYER_MAX_UNRANKED_KILLS;
+ spec.rgwColumnIds[2] = STATS_COLUMN_PLAYER_MAX_UNRANKED_POINTS_CAPPED;
+ spec.rgwColumnIds[3] = STATS_COLUMN_PLAYER_MAX_UNRANKED_POINT_DEFENSES;
+ spec.rgwColumnIds[4] = STATS_COLUMN_PLAYER_MAX_UNRANKED_DOMINATIONS;
+ spec.rgwColumnIds[5] = STATS_COLUMN_PLAYER_MAX_UNRANKED_REVENGE;
+ spec.rgwColumnIds[6] = STATS_COLUMN_PLAYER_MAX_UNRANKED_BUILDINGS_DESTROYED;
+ spec.rgwColumnIds[7] = STATS_COLUMN_PLAYER_MAX_UNRANKED_HEADSHOTS;
+ spec.rgwColumnIds[8] = STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_HEALED;
+ spec.rgwColumnIds[9] = STATS_COLUMN_PLAYER_MAX_UNRANKED_INVULNS;
+ spec.rgwColumnIds[10] = STATS_COLUMN_PLAYER_MAX_UNRANKED_KILL_ASSISTS;
+ spec.rgwColumnIds[11] = STATS_COLUMN_PLAYER_MAX_UNRANKED_BACKSTABS;
+ spec.rgwColumnIds[12] = STATS_COLUMN_PLAYER_MAX_UNRANKED_HEALTH_POINTS_LEACHED;
+ spec.rgwColumnIds[13] = STATS_COLUMN_PLAYER_MAX_UNRANKED_SENTRY_KILLS;
+ spec.rgwColumnIds[14] = STATS_COLUMN_PLAYER_MAX_UNRANKED_TELEPORTS;
+ m_cColumns = 15;
+ }
+ else
+ {
+ spec.dwViewId = STATS_VIEW_PLAYER_MAX_RANKED;
+ spec.dwNumColumnIds = 1;
+ spec.rgwColumnIds[ 0 ] = STATS_COLUMN_PLAYER_MAX_RANKED_POINTS_SCORED;
+
+ // set to zero to hide the progress bar
+ m_cColumns = 0;
+ }
+
+ DWORD ret;
+ XUID xuid = 0u;
+ XUID xuidFriends[NUM_ROWS_PER_QUERY];
+ int xuidCount = 1;
+
+ if ( !bFriends )
+ {
+ if ( rank == -1 )
+ {
+ // Center on the player's xuid
+ XUserGetXUID( XBX_GetPrimaryUserId(), &xuid );
+
+ ret = XUserCreateStatsEnumeratorByXuid(
+ 0,
+ xuid,
+ NUM_ROWS_PER_QUERY,
+ 1,
+ &spec,
+ &cbResults,
+ &handle );
+ }
+ else
+ {
+ // Start at the requested rank
+ ret = XUserCreateStatsEnumeratorByRank(
+ 0,
+ rank,
+ NUM_ROWS_PER_QUERY,
+ 1,
+ &spec,
+ &cbResults,
+ &handle );
+ }
+
+ if( ret != ERROR_SUCCESS )
+ {
+ Warning( "Error getting stats\n" );
+ return false;
+ }
+
+ // Allocate the buffer
+ CleanupStats();
+ m_pStats = ( XUSER_STATS_READ_RESULTS* ) new char[cbResults];
+
+ DWORD cpReturned;
+ ret = XEnumerate( handle, m_pStats, cbResults, &cpReturned, NULL );
+ }
+ else
+ {
+ // Get Friends leaderboard
+ int id = XBX_GetPrimaryUserId();
+ ret = XFriendsCreateEnumerator( id, 0, 5, &cbResults, &handle );
+
+ if ( ret != ERROR_SUCCESS )
+ {
+ Warning( "Error getting friends list\n" );
+ return false;
+ }
+
+ // Allocate the buffer
+ XONLINE_FRIEND *pFriends = ( XONLINE_FRIEND* ) new char[cbResults];
+
+ DWORD cpReturned;
+ ret = XEnumerate( handle, pFriends, cbResults, &cpReturned, NULL );
+ if( ret != ERROR_SUCCESS )
+ {
+ delete pFriends;
+ return false;
+ }
+
+ for ( uint i = 0; i < cpReturned; ++i )
+ {
+ xuidFriends[i] = pFriends[i].xuid;
+ }
+
+ // Allocate the buffer
+ CleanupStats();
+ m_pStats = ( XUSER_STATS_READ_RESULTS* ) new char[cbResults];
+
+ ret = XUserReadStats( 0, xuidCount, xuidFriends, 1, &spec, &cbResults, m_pStats, NULL );
+ }
+
+ if( ret == ERROR_SUCCESS )
+ {
+ const char *pEntries[32];
+ char pRowBuffer[MAX_PATH];
+ char pBuffers[32][MAX_PATH];
+
+ m_Menu.ClearItems();
+ m_iMaxRank = m_pStats->pViews[0].dwTotalViewRows;
+
+ // Did this search return any rows?
+ if ( m_pStats->pViews[0].dwNumRows == 0 )
+ return false;
+
+ for ( uint i = 0; i < m_pStats->pViews[0].dwNumRows; ++i )
+ {
+ XUSER_STATS_ROW &row = m_pStats->pViews[0].pRows[i];
+
+ // Save off the first rank in this set of entries
+ if ( i == 0 && m_iBaseRank == 0 )
+ {
+ m_iBaseRank = row.dwRank;
+ }
+
+ pEntries[0] = itoa( row.dwRank, pRowBuffer, 10 );
+ pEntries[1] = row.szGamertag;
+ for ( uint j = 0; j < row.dwNumColumns; ++j )
+ {
+ XUSER_STATS_COLUMN &col = m_pStats->pViews[0].pRows[i].pColumns[j];
+ pEntries[j+2] = itoa( col.Value.nData, pBuffers[j], 10 );
+ }
+
+ AddLeaderboardEntry( pEntries, row.dwNumColumns + 2 );
+
+ if ( rank == -1 && row.xuid == xuid )
+ {
+ m_Menu.SetFocus( i );
+ m_iActiveRank = row.dwRank;
+ }
+ }
+ }
+ else
+ {
+ Warning( "Error getting leaderboard stats\n" );
+ return false;
+ }
+
+ CloseHandle( handle );
+
+ return true;
+#endif
+
+ return false;
+}
+
+//----------------------------------------------------------
+// Determine if a new set of stats needs to be downloaded
+// Return true if the update has been handled, false otherwise
+//----------------------------------------------------------
+void CLeaderboardDialog::UpdateLeaderboard( int iNewRank )
+{
+ // Clamp the input
+ if ( iNewRank < 1 )
+ {
+ iNewRank = 1;
+ }
+ else if ( iNewRank > m_iMaxRank )
+ {
+ iNewRank = m_iMaxRank;
+ }
+
+ // No action necessary?
+ if ( iNewRank == m_iActiveRank )
+ return;
+
+ int nInterval = iNewRank - m_iActiveRank;
+ int iNewActiveItemIndex = m_Menu.GetActiveItemIndex() + nInterval;
+
+ // Set these "new" values to the current values - they will be conditionally updated.
+ int iNewBaseRank = m_iBaseRank;
+ int iNewBaseItemIndex = m_Menu.GetBaseRowIndex();
+ int nVisibleItems = m_Menu.GetVisibleItemCount();
+ int nHiddenItems = NUM_ROWS_PER_QUERY - nVisibleItems;
+
+ // Are we outside the visible range of the menu?
+ if ( iNewActiveItemIndex < iNewBaseItemIndex )
+ {
+ // Do we need to grab another set of columns?
+ if ( iNewRank < m_iBaseRank )
+ {
+ iNewBaseRank = iNewRank - nHiddenItems;
+ if ( iNewBaseRank < 1 )
+ {
+ iNewBaseRank = 1;
+ }
+
+ if ( !GetPlayerStats( iNewBaseRank ) )
+ {
+ // Failed to load player stats, don't change the current index
+ return;
+ }
+
+ m_iBaseRank = iNewBaseRank;
+ }
+
+ int nBaseToActiveInterval = iNewRank - m_iBaseRank;
+
+ // Since we shifted the menu down, both base and active item are at the first visible menu item
+ iNewActiveItemIndex = nBaseToActiveInterval;
+ iNewBaseItemIndex = nBaseToActiveInterval;
+ }
+ else if ( iNewActiveItemIndex >= m_Menu.GetBaseRowIndex() + nVisibleItems )
+ {
+ int nHiddenItems = NUM_ROWS_PER_QUERY - nVisibleItems;
+ int iTopRank = iNewRank + nHiddenItems;
+ if ( iTopRank > m_iMaxRank )
+ {
+ iTopRank = m_iMaxRank;
+ }
+
+
+ // Do we need to grab another set of columns?
+ if ( iNewRank >= m_iBaseRank + NUM_ROWS_PER_QUERY )
+ {
+ iNewBaseRank = iTopRank - NUM_ROWS_PER_QUERY + 1;
+ if ( !GetPlayerStats( iNewBaseRank ) )
+ {
+ // Failed to load player stats, don't change the current index
+ return;
+ }
+ m_iBaseRank = iNewBaseRank;
+ }
+
+ int nBaseToActiveInterval = iNewRank - m_iBaseRank;
+
+ iNewActiveItemIndex = nBaseToActiveInterval;
+ iNewBaseItemIndex = iNewActiveItemIndex - nVisibleItems + 1;
+ }
+
+ // Set all the new variables - must set base index before active index.
+ m_iActiveRank = iNewRank;
+ m_Menu.SetBaseRowIndex( iNewBaseItemIndex );
+ m_Menu.SetFocus( iNewActiveItemIndex );
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CLeaderboardDialog::HandleKeyRepeated( vgui::KeyCode code )
+{
+ OnKeyCodePressed( code );
+}
+
+//-----------------------------------------------------------------
+// Purpose: Send key presses to the dialog's menu
+//-----------------------------------------------------------------
+void CLeaderboardDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+
+ switch( code )
+ {
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+#ifdef _X360
+ {
+ int idx = m_Menu.GetActiveItemIndex();
+ if ( m_pStats && idx < (int)m_pStats->pViews[0].dwNumRows )
+ {
+ XUSER_STATS_ROW &row = m_pStats->pViews[0].pRows[idx];
+ XShowGamerCardUI( XBX_GetPrimaryUserId(), row.xuid );
+ }
+ }
+#endif
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ break;
+
+ case KEY_XSTICK1_DOWN:
+ case KEY_XBUTTON_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ m_KeyRepeat.KeyDown( code );
+ UpdateLeaderboard( m_iActiveRank + 1 );
+ break;
+
+ case KEY_XSTICK1_UP:
+ case KEY_XBUTTON_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ m_KeyRepeat.KeyDown( code );
+ UpdateLeaderboard( m_iActiveRank - 1 );
+ break;
+
+ case KEY_XBUTTON_LEFT_SHOULDER:
+ UpdateLeaderboard( 1 );
+ break;
+
+ case KEY_XBUTTON_RIGHT_SHOULDER:
+ OnCommand( "CenterOnPlayer" );
+ break;
+
+ // Disabled until friends enumeration works
+// case KEY_XBUTTON_RIGHT_SHOULDER:
+// OnCommand( "Friends" );
+// break;
+
+ default:
+ m_KeyRepeat.KeyDown( code );
+ BaseClass::OnKeyCodePressed( code );
+ break;
+ }
+
+ // Invalidate layout when scrolling through columns
+ switch( code )
+ {
+ case KEY_XSTICK1_LEFT:
+ case KEY_XBUTTON_LEFT:
+ case STEAMCONTROLLER_DPAD_LEFT:
+ case KEY_XSTICK1_RIGHT:
+ case KEY_XBUTTON_RIGHT:
+ case STEAMCONTROLLER_DPAD_RIGHT:
+ InvalidateLayout();
+ break;
+ }
+}
+
+
+CON_COMMAND( mm_add_item, "Add a stats item" )
+{
+ if ( args.ArgC() > 1 )
+ {
+ int ct = atoi( args[1] );
+ const char *pEntries[32];
+ for ( int i = 0; i < ct; ++i )
+ {
+ pEntries[i] = args[i+2];
+ }
+ g_pLeaderboardDialog->AddLeaderboardEntry( pEntries, ct );
+ }
+}
diff --git a/gameui/matchmaking/leaderboarddialog.h b/gameui/matchmaking/leaderboarddialog.h
new file mode 100644
index 0000000..6fd646f
--- /dev/null
+++ b/gameui/matchmaking/leaderboarddialog.h
@@ -0,0 +1,59 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Displays a leaderboard
+//
+//=============================================================================//
+
+#ifndef LEADERBOARDDIALOG_H
+#define LEADERBOARDDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Display player leaderboards
+//-----------------------------------------------------------------------------
+class CLeaderboardDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CLeaderboardDialog, CBaseDialog );
+
+public:
+ CLeaderboardDialog(vgui::Panel *parent);
+ ~CLeaderboardDialog();
+
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void PerformLayout( void );
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void HandleKeyRepeated( vgui::KeyCode code );
+
+ bool GetPlayerStats( int rank, bool bFriends = false );
+ void UpdateLeaderboard( int iNewRank );
+ void AddLeaderboardEntry( const char **pEntries, int ct );
+ void CleanupStats();
+
+private:
+ vgui::Panel *m_pProgressBg;
+ vgui::Panel *m_pProgressBar;
+ vgui::Label *m_pProgressPercent;
+ vgui::Label *m_pNumbering;
+ vgui::Label *m_pUpArrow;
+ vgui::Label *m_pDownArrow;
+ vgui::Label *m_pBestMoments;
+
+ int m_iBaseRank;
+ int m_iActiveRank;
+ int m_iMaxRank;
+ int m_cColumns;
+ int m_iRangeBase;
+
+#if defined( _X360 )
+ XUSER_STATS_READ_RESULTS *m_pStats;
+#endif
+};
+
+
+#endif // LEADERBOARDDIALOG_H
diff --git a/gameui/matchmaking/matchmakingbasepanel.cpp b/gameui/matchmaking/matchmakingbasepanel.cpp
new file mode 100644
index 0000000..403e476
--- /dev/null
+++ b/gameui/matchmaking/matchmakingbasepanel.cpp
@@ -0,0 +1,999 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Serves as the base panel for the entire matchmaking UI
+//
+//=============================================================================//
+
+#include "matchmakingbasepanel.h"
+#include "welcomedialog.h"
+#include "pausedialog.h"
+#include "leaderboarddialog.h"
+#include "achievementsdialog.h"
+#include "sessionoptionsdialog.h"
+#include "sessionlobbydialog.h"
+#include "sessionbrowserdialog.h"
+#include "vgui_controls/Label.h"
+#include "vgui_controls/MessageDialog.h"
+#include "vgui/ISurface.h"
+#include "EngineInterface.h"
+#include "game/client/IGameClientExports.h"
+#include "GameUI_Interface.h"
+#include "engine/imatchmaking.h"
+#include "KeyValues.h"
+#include "vstdlib/jobthread.h"
+#include "BasePanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//--------------------------------
+// CMatchmakingBasePanel
+//--------------------------------
+CMatchmakingBasePanel::CMatchmakingBasePanel( vgui::Panel *pParent ) : BaseClass( pParent, "MatchmakingBasePanel" )
+{
+ SetDeleteSelfOnClose( true );
+ SetPaintBackgroundEnabled( false );
+
+ vgui::scheme()->LoadSchemeFromFile( "Resource/ClientScheme.res", "ClientScheme" );
+ SetScheme( "ClientScheme" );
+
+ m_pFooter = new CFooterPanel( this, "MatchmakingFooterPanel" );
+
+ m_nGameType = GAMETYPE_STANDARD_MATCH;
+}
+
+CMatchmakingBasePanel::~CMatchmakingBasePanel()
+{
+ if ( m_pFooter )
+ {
+ delete m_pFooter;
+ m_pFooter = NULL;
+ }
+}
+
+void CMatchmakingBasePanel::SetFooterButtons( CBaseDialog *pOwner, KeyValues *pKeyValues, int nButtonGap /* = -1 */ )
+{
+ // Don't lay out the buttons if the dialog is not at the top of the stack
+ if ( m_DialogStack.Count() )
+ {
+ CBaseDialog *pDlg = m_DialogStack.Top();
+ if ( pDlg != pOwner )
+ return;
+ }
+
+ if ( m_pFooter )
+ {
+ m_pFooter->ClearButtons();
+
+ if ( pKeyValues )
+ {
+ for ( KeyValues *pButton = pKeyValues->GetFirstSubKey(); pButton != NULL; pButton = pButton->GetNextKey() )
+ {
+ if ( !Q_stricmp( pButton->GetName(), "button" ) )
+ {
+ // Add a button to the footer
+ const char *pText = pButton->GetString( "text", NULL );
+ const char *pIcon = pButton->GetString( "icon", NULL );
+
+ if ( pText && pIcon )
+ {
+ m_pFooter->AddNewButtonLabel( pText, pIcon );
+ }
+ }
+ }
+ }
+ else
+ {
+ // no data was passed so just setup the standard footer buttons
+ m_pFooter->SetStandardDialogButtons();
+ }
+
+ if ( nButtonGap > 0 )
+ {
+ m_pFooter->SetButtonGap( nButtonGap );
+ }
+ else
+ {
+ m_pFooter->UseDefaultButtonGap();
+ }
+ }
+}
+
+void CMatchmakingBasePanel::ShowFooter( bool bShown )
+{
+ m_pFooter->SetVisible( bShown );
+}
+
+void CMatchmakingBasePanel::SetFooterButtonVisible( const char *pszText, bool bVisible )
+{
+ if ( m_pFooter )
+ {
+ m_pFooter->ShowButtonLabel( pszText, bVisible );
+ }
+}
+
+void CMatchmakingBasePanel::Activate( void )
+{
+ BaseClass::Activate();
+
+ // Close animation may have set this to zero
+ SetAlpha( 255 );
+
+ if ( !GameUI().IsInLevel() )
+ {
+ OnOpenWelcomeDialog();
+ }
+ else
+ {
+ OnOpenPauseDialog();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle commands from all matchmaking dialogs
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( "OpenWelcomeDialog", pCommand ) )
+ {
+ OnOpenWelcomeDialog();
+ }
+ if ( !Q_stricmp( "OpenPauseDialog", pCommand ) )
+ {
+ OnOpenPauseDialog();
+ }
+ if ( !Q_stricmp( "OpenRankingsDialog", pCommand ) )
+ {
+ OnOpenRankingsDialog();
+ }
+ else if ( !Q_stricmp( "OpenSystemLinkDialog", pCommand ) )
+ {
+ OnOpenSystemLinkDialog();
+ }
+ else if ( !Q_stricmp( "OpenPlayerMatchDialog", pCommand ) )
+ {
+ OnOpenPlayerMatchDialog();
+ }
+ else if ( !Q_stricmp( "OpenRankedMatchDialog", pCommand ) )
+ {
+ OnOpenRankedMatchDialog();
+ }
+ else if ( !Q_stricmp( "OpenAchievementsDialog", pCommand ) )
+ {
+ OnOpenAchievementsDialog();
+ }
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Specific code for CS Achievements Display
+ //=============================================================================
+
+ else if ( !Q_stricmp( "OpenCSAchievementsDialog", pCommand ) )
+ {
+ OnOpenCSAchievementsDialog();
+ }
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ else if ( !Q_stricmp( "LevelLoadingStarted", pCommand ) )
+ {
+ OnLevelLoadingStarted();
+ }
+ else if ( !Q_stricmp( "LevelLoadingFinished", pCommand ) )
+ {
+ OnLevelLoadingFinished();
+ }
+ else if ( !Q_stricmp( "SessionOptions_Modify", pCommand ) )
+ {
+ OnOpenSessionOptionsDialog( pCommand );
+ }
+ else if ( !Q_stricmp( "ModifySession", pCommand ) )
+ {
+ matchmaking->ModifySession();
+ }
+ else if ( !Q_stricmp( "ChangeClass", pCommand ) )
+ {
+ engine->ClientCmd_Unrestricted( "changeclass" );
+ OnCommand( "ResumeGame" );
+ }
+ else if ( !Q_stricmp( "ChangeTeam", pCommand ) )
+ {
+ engine->ClientCmd_Unrestricted( "changeteam" );
+ OnCommand( "ResumeGame" );
+ }
+ else if ( !Q_stricmp( "ShowMapInfo", pCommand ) )
+ {
+ engine->ClientCmd_Unrestricted( "showmapinfo" );
+ OnCommand( "ResumeGame" );
+ }
+ else if ( !Q_stricmp( "StartHost", pCommand ) )
+ {
+ // Show progress dialog
+ GameUI().ShowMessageDialog( MD_CREATING_GAME, this );
+
+ // Send the host start command
+ matchmaking->StartHost();
+ }
+ else if ( !Q_stricmp( "StartSystemLinkHost", pCommand ) )
+ {
+ // Show progress dialog
+ GameUI().ShowMessageDialog( MD_CREATING_GAME, this );
+
+ m_nGameType = GAMETYPE_SYSTEMLINK_MATCH;
+ matchmaking->StartHost( true );
+ }
+ else if ( !Q_stricmp( "StartClient", pCommand ) )
+ {
+ // Show progress dialog
+ GameUI().ShowMessageDialog( MD_SEARCHING_FOR_GAMES, this );
+
+ // Tell matchmaking to start a client and search for games
+ matchmaking->StartClient( false );
+ }
+ else if ( !Q_stricmp( "StartSystemLinkClient", pCommand ) )
+ {
+ // Show progress dialog
+ GameUI().ShowMessageDialog( MD_SEARCHING_FOR_GAMES, this );
+
+ // Set the system link flag
+ matchmaking->AddSessionProperty( SESSION_FLAG, "SESSION_CREATE_SYSTEMLINK", NULL, NULL );
+
+ // Tell matchmaking to start a client and search for games
+ m_nGameType = GAMETYPE_SYSTEMLINK_MATCH;
+ matchmaking->StartClient( true );
+ }
+ else if ( Q_stristr( pCommand, "StartQuickMatchClient_" ) )
+ {
+ // Show progress dialog
+ GameUI().ShowMessageDialog( MD_SEARCHING_FOR_GAMES, this );
+
+ if ( Q_stristr( pCommand, "_Ranked" ) )
+ {
+ // Set the basic flags
+ matchmaking->AddSessionProperty( SESSION_CONTEXT, "CONTEXT_GAME_MODE", "CONTEXT_GAME_MODE_MULTIPLAYER", NULL );
+ matchmaking->AddSessionProperty( SESSION_CONTEXT, "CONTEXT_GAME_TYPE", "CONTEXT_GAME_TYPE_RANKED", NULL );
+ matchmaking->AddSessionProperty( SESSION_FLAG, "SESSION_CREATE_LIVE_MULTIPLAYER_RANKED", NULL, NULL );
+ m_nGameType = GAMETYPE_RANKED_MATCH;
+ }
+ else
+ {
+ // Set the standard match flag
+ matchmaking->AddSessionProperty( SESSION_CONTEXT, "CONTEXT_GAME_MODE", "CONTEXT_GAME_MODE_MULTIPLAYER", NULL );
+ matchmaking->AddSessionProperty( SESSION_CONTEXT, "CONTEXT_GAME_TYPE", "CONTEXT_GAME_TYPE_STANDARD", NULL );
+ matchmaking->AddSessionProperty( SESSION_FLAG, "SESSION_CREATE_LIVE_MULTIPLAYER_STANDARD", NULL, NULL );
+ m_nGameType = GAMETYPE_STANDARD_MATCH;
+ }
+
+ // Tell matchmaking to start a client and search for games
+ matchmaking->StartClient( false );
+ }
+ else if ( !Q_stricmp( "StartGame", pCommand ) )
+ {
+ // Tell matchmaking the host wants to start the game
+ matchmaking->StartGame();
+ }
+ else if ( Q_stristr( pCommand, "LeaderboardDialog_" ) )
+ {
+ // This covers LeaderboardDialog_[Ranked|Stats]
+ OnOpenLeaderboardDialog( pCommand );
+ }
+ else if ( Q_stristr( pCommand, "SessionOptions_" ) )
+ {
+ // This covers six command strings: *_Host[Standard|Ranked|Systemlink], *_Client[Standard|Ranked|Systemlink]
+ // Each command has a unique options menu - the command string is used as the name of the .res file.
+ OnOpenSessionOptionsDialog( pCommand );
+ }
+ else if ( !Q_stricmp( pCommand, "DialogClosing" ) )
+ {
+ PopDialog();
+ }
+ else if ( !Q_stricmp( pCommand, "AchievementsDialogClosing" ) )
+ {
+ PopDialog();
+ }
+ else if ( !Q_stricmp( pCommand, "show_achievements_dialog" ) )
+ {
+ OnOpenAchievementsDialog();
+ }
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Specific code for CS Achievements Display
+ //=============================================================================
+
+ else if ( !Q_stricmp( pCommand, "show_csachievements_dialog" ) )
+ {
+ OnOpenCSAchievementsDialog();
+ }
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ else if ( !Q_stricmp( pCommand, "ShowSessionOptionsDialog" ) )
+ {
+ // Need to close the client options dialog and open the host options equivalent
+ PopDialog();
+
+ switch( m_nGameType )
+ {
+ case GAMETYPE_STANDARD_MATCH:
+ OnOpenSessionOptionsDialog( "SessionOptions_HostStandard" );
+ break;
+
+ case GAMETYPE_RANKED_MATCH:
+ OnOpenSessionOptionsDialog( "SessionOptions_HostRanked" );
+ break;
+
+ case GAMETYPE_SYSTEMLINK_MATCH:
+ OnOpenSessionOptionsDialog( "SessionOptions_SystemLink" );
+ break;
+ }
+ }
+ else if ( !Q_stricmp( pCommand, "ReturnToMainMenu" ) )
+ {
+ CloseAllDialogs();
+ Activate();
+ }
+ else if ( !Q_stricmp( pCommand, "CancelOperation" ) )
+ {
+ GameUI().CloseMessageDialog();
+ PopDialog();
+ matchmaking->CancelCurrentOperation();
+ }
+ else if ( !Q_stricmp( pCommand, "StorageDeviceDenied" ) )
+ {
+ // Set us as declined
+ XBX_SetStorageDeviceId( XBX_STORAGE_DECLINED );
+ }
+ else
+ {
+ if ( !Q_stricmp( "ResumeGame", pCommand ) )
+ {
+ CloseAllDialogs();
+ }
+
+ CallParentFunction( new KeyValues( "Command", "command", pCommand ) );
+ }
+
+ // We should handle the case when user launched the game via invite,
+ // was prompted for a storage device and cancelled the picker.
+ // In this case whenever any command gets selected from the main menu
+ // we should cancel the wait for storage device selection.
+ BasePanel()->ValidateStorageDevice( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Handle notifications from matchmaking in the engine.
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::SessionNotification( const int notification, const int param )
+{
+ switch( notification )
+ {
+ case SESSION_NOTIFY_FAIL_SEARCH:
+ GameUI().CloseMessageDialog();
+ GameUI().ShowMessageDialog( MD_SESSION_SEARCH_FAILED, this );
+ break;
+
+ case SESSION_NOTIFY_CONNECT_NOTAVAILABLE:
+ CloseAllDialogs();
+ GameUI().ShowMessageDialog( MD_SESSION_CONNECT_NOTAVAILABLE, this );
+ break;
+
+ case SESSION_NOTIFY_CONNECT_SESSIONFULL:
+ CloseAllDialogs();
+ GameUI().ShowMessageDialog( MD_SESSION_CONNECT_SESSIONFULL, this );
+ break;
+
+ case SESSION_NOTIFY_CONNECT_FAILED:
+ CloseAllDialogs();
+ GameUI().ShowMessageDialog( MD_SESSION_CONNECT_FAILED, this );
+ break;
+
+ case SESSION_NOTIFY_FAIL_CREATE:
+ CloseAllDialogs();
+ GameUI().ShowMessageDialog( MD_SESSION_CREATE_FAILED, this );
+ break;
+
+ case SESSION_NOTIFY_CLIENT_KICKED:
+ CloseAllDialogs();
+ GameUI().ShowMessageDialog( MD_CLIENT_KICKED, this );
+ break;
+
+ case SESSION_NOTIFY_LOST_HOST:
+ CloseBaseDialogs();
+ GameUI().ShowMessageDialog( MD_LOST_HOST, this );
+ break;
+
+ case SESSION_NOTIFY_LOST_SERVER:
+ CloseBaseDialogs();
+ GameUI().ShowMessageDialog( MD_LOST_SERVER, this );
+ break;
+
+ case SESSION_NOFIFY_MODIFYING_SESSION:
+ GameUI().ShowMessageDialog( MD_MODIFYING_SESSION, this );
+ break;
+
+ case SESSION_NOTIFY_SEARCH_COMPLETED:
+ GameUI().CloseMessageDialog();
+
+ LoadSessionProperties();
+
+ // Switch to the session browser
+ switch( m_nGameType )
+ {
+ case GAMETYPE_STANDARD_MATCH:
+ case GAMETYPE_RANKED_MATCH:
+ OnOpenSessionBrowserDialog( "SessionBrowser_Live" );
+ break;
+
+ case GAMETYPE_SYSTEMLINK_MATCH:
+ OnOpenSessionBrowserDialog( "SessionBrowser_SystemLink" );
+ break;
+ }
+ break;
+
+ case SESSION_NOTIFY_CREATED_HOST:
+ case SESSION_NOTIFY_MODIFYING_COMPLETED_HOST:
+ GameUI().CloseMessageDialog();
+
+ LoadSessionProperties();
+
+ // Switch to the Lobby
+ switch( m_nGameType )
+ {
+ case GAMETYPE_STANDARD_MATCH:
+ case GAMETYPE_RANKED_MATCH:
+ case GAMETYPE_SYSTEMLINK_MATCH:
+ OnOpenSessionLobbyDialog( "SessionLobby_Host" );
+ break;
+ }
+ break;
+
+ case SESSION_NOTIFY_CREATED_CLIENT:
+ GameUI().ShowMessageDialog( MD_SESSION_CONNECTING, this );
+ break;
+
+ case SESSION_NOTIFY_CONNECTED_TOSESSION:
+ case SESSION_NOTIFY_MODIFYING_COMPLETED_CLIENT:
+ GameUI().CloseMessageDialog();
+
+ LoadSessionProperties();
+
+ // Switch to the Lobby
+ switch( m_nGameType )
+ {
+ case GAMETYPE_STANDARD_MATCH:
+ case GAMETYPE_RANKED_MATCH:
+ case GAMETYPE_SYSTEMLINK_MATCH:
+ OnOpenSessionLobbyDialog( "SessionLobby_Client" );
+ break;
+ }
+ break;
+
+ case SESSION_NOTIFY_CONNECTED_TOSERVER:
+ CloseAllDialogs( false );
+ break;
+
+ case SESSION_NOTIFY_ENDGAME_RANKED:
+ // Return to the main menu
+ CloseAllDialogs();
+ break;
+
+ case SESSION_NOTIFY_ENDGAME_HOST:
+ CloseBaseDialogs();
+ OnOpenSessionLobbyDialog( "SessionLobby_Host" );
+ break;
+
+ case SESSION_NOTIFY_ENDGAME_CLIENT:
+ CloseBaseDialogs();
+ OnOpenSessionLobbyDialog( "SessionLobby_Client" );
+ break;
+
+ case SESSION_NOTIFY_COUNTDOWN:
+ {
+ CSessionLobbyDialog *pDlg = (CSessionLobbyDialog*)m_hSessionLobbyDialog.Get();
+ if ( pDlg )
+ {
+ pDlg->UpdateCountdown( param );
+ }
+
+ if ( param == 0 )
+ {
+ BasePanel()->RunAnimationWithCallback( this, "CloseMatchmakingUI", new KeyValues( "LoadMap" ) );
+ }
+ }
+ break;
+
+ case SESSION_NOTIFY_DUMPSTATS:
+ Msg( "[MM] %d open dialogs\n", m_DialogStack.Count() );
+ for ( int i = 0; i < m_DialogStack.Count(); ++i )
+ {
+ const char *pString = "NULL";
+ bool bVisible = false;
+ float fAlpha = 0.f;
+ CBaseDialog *pDlg = m_DialogStack[i];
+ if ( pDlg )
+ {
+ pString = pDlg->GetName();
+ bVisible = pDlg->IsVisible();
+ fAlpha = pDlg->GetAlpha();
+ }
+ const char *pVisible = bVisible ? "YES" : "NO";
+ Msg( "[MM] Dialog %d: %s, Visible %s, Alpha %f\n", i, pString, pVisible, fAlpha );
+ }
+ break;
+
+ case SESSION_NOTIFY_WELCOME:
+ CloseGameDialogs( false );
+ Activate();
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: System Notification
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::SystemNotification( const int notification )
+{
+ switch( notification )
+ {
+ case SYSTEMNOTIFY_USER_SIGNEDOUT:
+ // See if this was us
+#if defined( _X360 )
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state == eXUserSigninState_NotSignedIn )
+ {
+ matchmaking->KickPlayerFromSession( 0 );
+ CloseAllDialogs();
+ }
+ else if ( state != eXUserSigninState_SignedInToLive )
+ {
+ // User was signed out of live
+ if ( m_bPlayingOnline )
+ {
+ matchmaking->KickPlayerFromSession( 0 );
+ CloseAllDialogs();
+ }
+ }
+#endif
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Check whether a player meets the signin requirements for a multiplayer game
+//-----------------------------------------------------------------------------
+bool CMatchmakingBasePanel::ValidateSigninAndStorage( bool bOnlineRequired, const char *pIssuingCommand )
+{
+ // Check the signin state of the primary user
+ bool bSignedIn = false;
+ bool bOnlineEnabled = false;
+ bool bOnlineSignedIn = false;
+
+#if defined( _X360 )
+ int userIdx = XBX_GetPrimaryUserId();
+ if ( userIdx != INVALID_USER_ID )
+ {
+ XUSER_SIGNIN_INFO info;
+ uint ret = XUserGetSigninInfo( userIdx, 0, &info );
+ if ( ret == ERROR_SUCCESS )
+ {
+ bSignedIn = true;
+ if ( info.dwInfoFlags & XUSER_INFO_FLAG_LIVE_ENABLED )
+ {
+ bOnlineEnabled = true;
+ uint state = XUserGetSigninState( XBX_GetPrimaryUserId() );
+ if ( state == eXUserSigninState_SignedInToLive )
+ {
+ bOnlineSignedIn = true;
+
+ // Check privileges
+ BOOL bPrivCheck = false;
+ DWORD dwPrivCheck = XUserCheckPrivilege( userIdx, XPRIVILEGE_MULTIPLAYER_SESSIONS, &bPrivCheck );
+ if ( ERROR_SUCCESS != dwPrivCheck ||
+ !bPrivCheck )
+ {
+ bOnlineEnabled = false;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ if ( bOnlineRequired && !bOnlineEnabled )
+ {
+ // Player must sign in an online account
+ GameUI().ShowMessageDialog( MD_NOT_ONLINE_ENABLED );
+ return false;
+ }
+ else if ( bOnlineRequired && !bOnlineSignedIn )
+ {
+ // Player's live account isn't signed in to live
+ GameUI().ShowMessageDialog( MD_NOT_ONLINE_SIGNEDIN );
+ return false;
+ }
+ else if ( !bSignedIn )
+ {
+ // Eat the input and make the user sign in
+ xboxsystem->ShowSigninUI( 1, 0 ); // One user, no special flags
+ return false;
+ }
+
+ // Handle the storage device selection
+ if ( !BasePanel()->HandleStorageDeviceRequest( pIssuingCommand ) )
+ return false;
+
+ // If we succeeded, clear the command out
+ BasePanel()->ClearPostPromptCommand( pIssuingCommand );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Update player information in the lobby
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost )
+{
+ CSessionLobbyDialog *pLobby = dynamic_cast< CSessionLobbyDialog* >( m_hSessionLobbyDialog.Get() );
+ if ( pLobby )
+ {
+ pLobby->UpdatePlayerInfo( nPlayerId, pName, nTeam, cVoiceState, nPlayersNeeded, bHost );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add a search result to the browser dialog
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping )
+{
+ CSessionBrowserDialog *pBrowser = dynamic_cast< CSessionBrowserDialog* >( m_hSessionBrowserDialog.Get() );
+ if ( pBrowser )
+ {
+ pBrowser->SessionSearchResult( searchIdx, pHostData, pResult, ping );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Pre level load ops
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::OnLevelLoadingStarted()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Post level load ops
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::OnLevelLoadingFinished()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Hide the current dialog, add a new one to the stack and activate it.
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::PushDialog( vgui::DHANDLE< CBaseDialog > &hDialog )
+{
+ if ( m_DialogStack.Count() )
+ {
+ if ( m_DialogStack.Top() )
+ {
+ m_DialogStack.Top()->Close();
+ }
+ else
+ {
+ m_DialogStack.Pop();
+ }
+ }
+ hDialog->Activate();
+ m_DialogStack.Push( hDialog );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Close the current dialog, pop it from the top of the stack, and activate the next one.
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::PopDialog( bool bActivateNext )
+{
+ if ( m_DialogStack.Count() > 1 )
+ {
+ if ( m_DialogStack.Top() )
+ {
+ m_DialogStack.Top()->SetDeleteSelfOnClose( true );
+ m_DialogStack.Top()->Close();
+ m_DialogStack.Pop();
+ }
+
+ // Drop down to the next available dialog
+ while ( m_DialogStack.Count() && !m_DialogStack.Top() )
+ {
+ m_DialogStack.Pop();
+ }
+
+ if ( bActivateNext && m_DialogStack.Count() && m_DialogStack.Top() )
+ {
+ m_DialogStack.Top()->Activate();
+ }
+ }
+
+ if ( m_DialogStack.Count() <= 1 )
+ {
+ // Back at the welcome menu
+ m_bPlayingOnline = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Close all open dialogs down to the main menu
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::CloseGameDialogs( bool bActivateNext )
+{
+ CloseBaseDialogs();
+ while ( m_DialogStack.Count() > 1 )
+ {
+ PopDialog( bActivateNext );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Close all open dialogs down to the main menu
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::CloseAllDialogs( bool bActivateNext )
+{
+ GameUI().CloseMessageDialog();
+ CloseGameDialogs( bActivateNext );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::CloseBaseDialogs( void )
+{
+ if ( BasePanel() )
+ {
+ BasePanel()->CloseBaseDialogs();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Get session property keyvalues from base panel and matchmaking
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::LoadSessionProperties()
+{
+ // Grab the session property keys from XboxDialogs.res and from matchmaking
+ m_pSessionKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "PropertyDisplayKeys" );
+ if ( m_pSessionKeys )
+ {
+ m_pSessionKeys->ChainKeyValue( matchmaking->GetSessionProperties() );
+ }
+
+ // Cache off the map name
+ const char *pDiskName = NULL;
+ KeyValues *pName = m_pSessionKeys->FindKey( "MapDiskNames" );
+ if ( pName )
+ {
+ KeyValues *pScenario = m_pSessionKeys->FindKey( "CONTEXT_SCENARIO" );
+ if ( pScenario )
+ {
+ pDiskName = pName->GetString( pScenario->GetString( "displaystring" ), NULL );
+ }
+ }
+
+ if ( pDiskName )
+ {
+ Q_strncpy( m_szMapLoadName, pDiskName, sizeof( m_szMapLoadName ) );
+ Msg( "Storing mapname %s\n", m_szMapLoadName );
+ if ( Q_strlen( m_szMapLoadName ) < 5 )
+ {
+ Warning( "Bad map name!\n" );
+ }
+ }
+ else
+ {
+ // X360TBD: Generate a create error
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Open dialog functions.
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::OnOpenWelcomeDialog()
+{
+ if ( !m_hWelcomeDialog.Get() )
+ {
+ m_hWelcomeDialog = new CWelcomeDialog( this );
+ m_DialogStack.Push( m_hWelcomeDialog );
+ }
+
+ m_hWelcomeDialog->Activate();
+ m_bPlayingOnline = false;
+}
+
+void CMatchmakingBasePanel::OnOpenPauseDialog()
+{
+ if ( !m_hPauseDialog.Get() )
+ {
+ m_hPauseDialog = new CPauseDialog( this );
+ }
+ PushDialog( m_hPauseDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenRankingsDialog()
+{
+ if ( !ValidateSigninAndStorage( true, "OpenRankingDialog" ) )
+ return;
+
+ if ( !m_hRankingsDialog.Get() )
+ {
+ m_hRankingsDialog = new CBaseDialog( this, "RankingsDialog" );
+ }
+ PushDialog( m_hRankingsDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenSystemLinkDialog()
+{
+ if ( !ValidateSigninAndStorage( false, "OpenSystemLinkDialog" ) )
+ return;
+
+ if ( !m_hSystemLinkDialog.Get() )
+ {
+ m_hSystemLinkDialog = new CBaseDialog( this, "SystemLinkDialog" );
+ }
+ PushDialog( m_hSystemLinkDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenPlayerMatchDialog()
+{
+ if ( !ValidateSigninAndStorage( true, "OpenPlayerMatchDialog" ) )
+ return;
+
+ if ( !m_hPlayerMatchDialog.Get() )
+ {
+ m_hPlayerMatchDialog = new CBaseDialog( this, "PlayerMatchDialog" );
+ }
+ PushDialog( m_hPlayerMatchDialog );
+ m_bPlayingOnline = true;
+}
+
+void CMatchmakingBasePanel::OnOpenRankedMatchDialog()
+{
+ if ( !ValidateSigninAndStorage( true, "OpenRankedMatchDialog" ) )
+ return;
+
+ if ( !m_hRankedMatchDialog.Get() )
+ {
+ m_hRankedMatchDialog = new CBaseDialog( this, "RankedMatchDialog" );
+ }
+ PushDialog( m_hRankedMatchDialog );
+ m_bPlayingOnline = true;
+}
+
+void CMatchmakingBasePanel::OnOpenAchievementsDialog()
+{
+ if ( !ValidateSigninAndStorage( false, "OpenAchievementsDialog" ) )
+ return;
+
+ if ( !m_hAchievementsDialog.Get() )
+ {
+ m_hAchievementsDialog = new CAchievementsDialog_XBox( this );
+ }
+ PushDialog( m_hAchievementsDialog );
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [dwenger] Specific code for CS Achievements Display
+//=============================================================================
+
+void CMatchmakingBasePanel::OnOpenCSAchievementsDialog()
+{
+ if ( !ValidateSigninAndStorage( false, "OpenCSAchievementsDialog" ) )
+ return;
+
+ if ( !m_hAchievementsDialog.Get() )
+ {
+ // $TODO(HPE): m_hAchievementsDialog = new CAchievementsDialog_XBox( this );
+ }
+ PushDialog( m_hAchievementsDialog );
+}
+
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+void CMatchmakingBasePanel::OnOpenSessionOptionsDialog( const char *pResourceName )
+{
+ if ( !m_hSessionOptionsDialog.Get() )
+ {
+ m_hSessionOptionsDialog = new CSessionOptionsDialog( this );
+ }
+
+ if ( Q_stristr( pResourceName, "Ranked" ) )
+ {
+ m_nGameType = GAMETYPE_RANKED_MATCH;
+ }
+ else if ( Q_stristr( pResourceName, "Standard" ) )
+ {
+ m_nGameType = GAMETYPE_STANDARD_MATCH;
+ }
+ else if ( Q_stristr( pResourceName, "SystemLink" ) )
+ {
+ m_nGameType = GAMETYPE_SYSTEMLINK_MATCH;
+ }
+
+ LoadSessionProperties();
+
+ CSessionOptionsDialog* pDlg = ((CSessionOptionsDialog*)m_hSessionOptionsDialog.Get());
+ pDlg->SetGameType( pResourceName );
+ pDlg->SetDialogKeys( m_pSessionKeys );
+
+ PushDialog( m_hSessionOptionsDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenSessionLobbyDialog( const char *pResourceName )
+{
+ if ( !m_hSessionLobbyDialog.Get() )
+ {
+ m_hSessionLobbyDialog = new CSessionLobbyDialog( this );
+ }
+ CSessionLobbyDialog *pDlg = (CSessionLobbyDialog*)m_hSessionLobbyDialog.Get();
+ pDlg->SetDialogKeys( m_pSessionKeys );
+
+ m_hSessionLobbyDialog->SetName( pResourceName );
+ PushDialog( m_hSessionLobbyDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenSessionBrowserDialog( const char *pResourceName )
+{
+ if ( !m_hSessionBrowserDialog.Get() )
+ {
+ m_hSessionBrowserDialog = new CSessionBrowserDialog( this, m_pSessionKeys );
+ m_hSessionBrowserDialog->SetName( pResourceName );
+
+ // Matchmaking will start adding results immediately, so prepare the dialog
+ SETUP_PANEL( m_hSessionBrowserDialog.Get() );
+ }
+ PushDialog( m_hSessionBrowserDialog );
+}
+
+void CMatchmakingBasePanel::OnOpenLeaderboardDialog( const char *pResourceName )
+{
+ if ( !m_hLeaderboardDialog.Get() )
+ {
+ m_hLeaderboardDialog = new CLeaderboardDialog( this );
+ m_hLeaderboardDialog->SetName( pResourceName );
+ SETUP_PANEL( m_hLeaderboardDialog.Get() );
+ }
+ PushDialog( m_hLeaderboardDialog );
+ m_hLeaderboardDialog->OnCommand( "CenterOnPlayer" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Callback function to start map load after ui fades out.
+//-----------------------------------------------------------------------------
+void CMatchmakingBasePanel::LoadMap( const char *mapname )
+{
+ CloseAllDialogs( false );
+
+ char cmd[MAX_PATH];
+ Q_snprintf( cmd, sizeof( cmd ), "map %s", m_szMapLoadName );
+ BasePanel()->FadeToBlackAndRunEngineCommand( cmd );
+}
+
+//-------------------------------------------------------
+// Keyboard input
+//-------------------------------------------------------
+void CMatchmakingBasePanel::OnKeyCodePressed( vgui::KeyCode code )
+{
+ switch( code )
+ {
+ case KEY_XBUTTON_B:
+ // Can't close the matchmaking base panel
+ break;
+
+ default:
+ BaseClass::OnKeyCodePressed( code );
+ break;
+ }
+}
diff --git a/gameui/matchmaking/matchmakingbasepanel.h b/gameui/matchmaking/matchmakingbasepanel.h
new file mode 100644
index 0000000..0be40ed
--- /dev/null
+++ b/gameui/matchmaking/matchmakingbasepanel.h
@@ -0,0 +1,114 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Serves as the base panel for the entire matchmaking UI
+//
+//=============================================================================//
+
+#ifndef MATCHMAKINGBASEPANEL_H
+#define MATCHMAKINGBASEPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+#include "utlstack.h"
+#include "const.h"
+
+enum EGameType
+{
+ GAMETYPE_RANKED_MATCH,
+ GAMETYPE_STANDARD_MATCH,
+ GAMETYPE_SYSTEMLINK_MATCH,
+};
+
+//----------------------------
+// CMatchmakingBasePanel
+//----------------------------
+class CMatchmakingBasePanel : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CMatchmakingBasePanel, CBaseDialog );
+
+public:
+ CMatchmakingBasePanel(vgui::Panel *parent);
+ ~CMatchmakingBasePanel();
+
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void Activate();
+
+ void SessionNotification( const int notification, const int param = 0 );
+ void SystemNotification( const int notification );
+ void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost );
+ void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping );
+
+ void OnLevelLoadingStarted();
+ void OnLevelLoadingFinished();
+ void CloseGameDialogs( bool bActivateNext = true );
+ void CloseAllDialogs( bool bActivateNext = true );
+ void CloseBaseDialogs( void );
+
+ void SetFooterButtons( CBaseDialog *pOwner, KeyValues *pData, int nButtonGap = -1 );
+ void ShowFooter( bool bShown );
+ void SetFooterButtonVisible( const char *pszText, bool bVisible );
+
+ uint GetGameType( void ) { return m_nGameType; }
+
+ MESSAGE_FUNC_CHARPTR( LoadMap, "LoadMap", mapname );
+private:
+ void OnOpenWelcomeDialog();
+ void OnOpenPauseDialog();
+ void OnOpenRankingsDialog();
+ void OnOpenSystemLinkDialog();
+ void OnOpenPlayerMatchDialog();
+ void OnOpenRankedMatchDialog();
+ void OnOpenAchievementsDialog();
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [dwenger] Specific code for CS Achievements Display
+ //=============================================================================
+
+ // $TODO(HPE): Move this to a game-specific location
+ void OnOpenCSAchievementsDialog();
+
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ void OnOpenLeaderboardDialog( const char *pResourceName );
+ void OnOpenSessionOptionsDialog( const char *pResourceName );
+ void OnOpenSessionLobbyDialog( const char *pResourceName );
+ void OnOpenSessionBrowserDialog( const char *pResourceName );
+
+ void LoadSessionProperties();
+ bool ValidateSigninAndStorage( bool bOnlineRequired, const char *pIssuingCommand );
+ void CenterDialog( vgui::PHandle dlg );
+ void PushDialog( vgui::DHANDLE< CBaseDialog > &hDialog );
+ void PopDialog( bool bActivateNext = true );
+
+ vgui::DHANDLE< CBaseDialog > m_hWelcomeDialog;
+ vgui::DHANDLE< CBaseDialog > m_hPauseDialog;
+ vgui::DHANDLE< CBaseDialog > m_hStatsDialog;
+ vgui::DHANDLE< CBaseDialog > m_hRankingsDialog;
+ vgui::DHANDLE< CBaseDialog > m_hLeaderboardDialog;
+ vgui::DHANDLE< CBaseDialog > m_hSystemLinkDialog;
+ vgui::DHANDLE< CBaseDialog > m_hPlayerMatchDialog;
+ vgui::DHANDLE< CBaseDialog > m_hRankedMatchDialog;
+ vgui::DHANDLE< CBaseDialog > m_hAchievementsDialog;
+ vgui::DHANDLE< CBaseDialog > m_hSessionOptionsDialog;
+ vgui::DHANDLE< CBaseDialog > m_hSessionLobbyDialog;
+ vgui::DHANDLE< CBaseDialog > m_hSessionBrowserDialog;
+
+ CUtlStack< vgui::DHANDLE< CBaseDialog > > m_DialogStack;
+
+ uint m_nSessionType;
+ uint m_nGameType;
+ bool m_bPlayingOnline;
+ char m_szMapLoadName[MAX_MAP_NAME];
+ KeyValues *m_pSessionKeys;
+
+ CFooterPanel *m_pFooter;
+};
+
+
+#endif // MATCHMAKINGBASEPANEL_H
diff --git a/gameui/matchmaking/pausedialog.cpp b/gameui/matchmaking/pausedialog.cpp
new file mode 100644
index 0000000..f158583
--- /dev/null
+++ b/gameui/matchmaking/pausedialog.cpp
@@ -0,0 +1,47 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Multiplayer pause menu
+//
+//=============================================================================//
+
+#include "pausedialog.h"
+#include "GameUI_Interface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//--------------------------------
+// CPauseDialog
+//--------------------------------
+CPauseDialog::CPauseDialog( vgui::Panel *pParent ) : BaseClass( pParent, "PauseDialog" )
+{
+ // do nothing
+}
+
+void CPauseDialog::Activate( void )
+{
+ BaseClass::Activate();
+
+ SetDeleteSelfOnClose( false );
+ m_Menu.SetFocus( 0 );
+}
+
+//-------------------------------------------------------
+// Keyboard input
+//-------------------------------------------------------
+void CPauseDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ switch( code )
+ {
+ case KEY_XBUTTON_B:
+ if ( GameUI().IsInLevel() )
+ {
+ m_pParent->OnCommand( "ResumeGame" );
+ }
+ break;
+
+ default:
+ BaseClass::OnKeyCodePressed( code );
+ break;
+ }
+} \ No newline at end of file
diff --git a/gameui/matchmaking/pausedialog.h b/gameui/matchmaking/pausedialog.h
new file mode 100644
index 0000000..3d580d8
--- /dev/null
+++ b/gameui/matchmaking/pausedialog.h
@@ -0,0 +1,30 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Multiplayer pause menu
+//
+//=============================================================================//
+
+#ifndef PAUSEDIALOG_H
+#define PAUSEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Multiplayer pause menu
+//-----------------------------------------------------------------------------
+class CPauseDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CPauseDialog, CBaseDialog );
+
+public:
+ CPauseDialog( vgui::Panel *parent );
+
+ virtual void Activate( void );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+};
+
+
+#endif // PAUSEDIALOG_H
diff --git a/gameui/matchmaking/sessionbrowserdialog.cpp b/gameui/matchmaking/sessionbrowserdialog.cpp
new file mode 100644
index 0000000..f29b177
--- /dev/null
+++ b/gameui/matchmaking/sessionbrowserdialog.cpp
@@ -0,0 +1,323 @@
+//========= 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();
+}
diff --git a/gameui/matchmaking/sessionbrowserdialog.h b/gameui/matchmaking/sessionbrowserdialog.h
new file mode 100644
index 0000000..ea77b9b
--- /dev/null
+++ b/gameui/matchmaking/sessionbrowserdialog.h
@@ -0,0 +1,46 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Present a list of sessions from which the player can choose a game to join.
+//
+//=====================================================================================//
+
+#ifndef SESSIONBROWSERDIALOG_H
+#define SESSIONBROWSERDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+class CSessionBrowserDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CSessionBrowserDialog, CBaseDialog );
+
+public:
+ CSessionBrowserDialog( vgui::Panel *parent, KeyValues *pDialogKeys );
+ ~CSessionBrowserDialog();
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnThink();
+
+ virtual void SwapMenuItems( int iOne, int iTwo );
+
+ void UpdateScenarioDisplay( void );
+ void SessionSearchResult( int searchIdx, void *pHostData, XSESSION_SEARCHRESULT *pResult, int ping );
+
+ KeyValues *m_pDialogKeys;
+
+ CUtlVector< CScenarioInfoPanel* > m_pScenarioInfos;
+ CUtlVector< int > m_ScenarioIndices;
+ CUtlVector< int > m_SearchIndices;
+ CUtlVector< int > m_GameStates;
+ CUtlVector< int > m_GameTimes;
+ CUtlVector< XUID > m_XUIDs;
+};
+
+
+#endif // SESSIONBROWSERDIALOG_H
diff --git a/gameui/matchmaking/sessionlobbydialog.cpp b/gameui/matchmaking/sessionlobbydialog.cpp
new file mode 100644
index 0000000..6f4e808
--- /dev/null
+++ b/gameui/matchmaking/sessionlobbydialog.cpp
@@ -0,0 +1,739 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "sessionlobbydialog.h"
+#include "engine/imatchmaking.h"
+#include "GameUI_Interface.h"
+#include "EngineInterface.h"
+#include "vgui/ISurface.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui/ILocalize.h"
+#include "BasePanel.h"
+#include "matchmakingbasepanel.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+CSessionLobbyDialog *g_pLobbyDialog;
+
+//--------------------------------
+// CSessionLobbyDialog
+//--------------------------------
+CSessionLobbyDialog::CSessionLobbyDialog( vgui::Panel *pParent ) : BaseClass( pParent, "SessionLobbyDialog" )
+{
+ m_Menus[0].SetParent( this );
+ m_Menus[0].SetName( "BluePlayers" );
+ m_Menus[1].SetParent( this );
+ m_Menus[1].SetName( "RedPlayers" );
+
+ m_iLocalTeam = -1;
+ m_iActiveMenu = -1;
+ m_nHostId = 0;
+ m_bHostLobby = false;
+ m_bCenterOnScreen = true;
+
+ m_pLobbyStateBg = new vgui::Panel( this, "LobbyStateBg" );
+ m_pLobbyStateLabel = new CPropertyLabel( this, "LobbyStateLabel", "" );
+ m_pLobbyStateIcon = new CPropertyLabel( this, "LobbyStateIcon", "" );
+ m_pHostLabel = new CPropertyLabel( this, "HostLabel", "" );
+ m_pHostOptionsPanel = new vgui::EditablePanel( this, "HostOptions" );
+
+ m_pScenarioInfo = new CScenarioInfoPanel( this, "GameScenario" );
+ m_pTeamInfos[BLUE_TEAM_LOBBY] = new CScenarioInfoPanel( this, "BlueTeamDescription" );
+ m_pTeamInfos[RED_TEAM_LOBBY] = new CScenarioInfoPanel( this, "RedTeamDescription" );
+
+ m_pDialogKeys = NULL;
+
+ g_pLobbyDialog = this;
+
+ m_bStartingGame = false;
+ m_nLastPlayersNeeded = 0;
+
+ m_nMinInfoHeight[BLUE_TEAM_LOBBY] = 0;
+ m_nMinInfoHeight[RED_TEAM_LOBBY] = 0;
+}
+
+CSessionLobbyDialog::~CSessionLobbyDialog()
+{
+ delete m_pLobbyStateBg;
+ delete m_pLobbyStateLabel;
+ delete m_pLobbyStateIcon;
+ delete m_pHostLabel;
+ delete m_pHostOptionsPanel;
+
+ delete m_pScenarioInfo;
+ for ( int i = 0; i < TOTAL_LOBBY_TEAMS; ++i )
+ {
+ delete m_pTeamInfos[i];
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Dialog keys contain session contexts and properties
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::SetDialogKeys( KeyValues *pKeys )
+{
+ m_pDialogKeys = pKeys;
+ InvalidateLayout();
+}
+
+//---------------------------------------------------------------------
+// Purpose: Helper to set label text from keyvalues
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::SetTextFromKeyvalues( CPropertyLabel *pLabel )
+{
+ KeyValues *pKey = m_pDialogKeys->FindKey( pLabel->m_szPropertyString );
+ if ( pKey )
+ {
+ const char *pString = pKey->GetString( "displaystring", NULL );
+ if ( pString )
+ {
+ pLabel->SetText( pString );
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Center the dialog on the screen
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ if ( !m_pDialogKeys )
+ return;
+
+ // Set the label strings according to the keyvalues passed in
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pTitle );
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pDescOne );
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pDescTwo );
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pDescThree );
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pValueTwo );
+ SetTextFromKeyvalues( m_pScenarioInfo->m_pValueThree );
+
+ const char *pDiskName = "unknown";
+ KeyValues *pName = m_pDialogKeys->FindKey( "MapDiskNames" );
+ if ( pName )
+ {
+ KeyValues *pScenario = m_pDialogKeys->FindKey( "CONTEXT_SCENARIO" );
+ if ( pScenario )
+ {
+ pDiskName = pName->GetString( pScenario->GetString( "displaystring" ), "unknown" );
+ }
+ }
+
+ // find the scenario type
+ KeyValues *pType = m_pDialogKeys->FindKey( "ScenarioTypes" );
+ if ( pType )
+ {
+ const char *pString = pType->GetString( pDiskName, NULL );
+ if ( pString )
+ {
+ m_pScenarioInfo->m_pSubtitle->SetText( pString );
+ }
+ }
+
+ // Set the team goals
+ KeyValues *pGoals = m_pDialogKeys->FindKey( "TeamGoals" );
+ if ( pGoals )
+ {
+ KeyValues *pTeam = pGoals->FindKey( "Blue" );
+ if ( pTeam )
+ {
+ m_pTeamInfos[BLUE_TEAM_LOBBY]->m_pDescOne->SetText( pTeam->GetString( pDiskName, "" ) );
+ }
+ pTeam = pGoals->FindKey( "Red" );
+ if ( pTeam )
+ {
+ m_pTeamInfos[RED_TEAM_LOBBY]->m_pDescOne->SetText( pTeam->GetString( pDiskName, "" ) );
+ }
+ }
+
+ for ( int i = 0; i < TOTAL_LOBBY_TEAMS; ++i )
+ {
+ UpdatePlayerCountDisplay( i );
+ }
+
+ if ( m_bCenterOnScreen )
+ {
+ MoveToCenterOfScreen();
+ }
+
+ // Don't allow player reviews in system link games
+ CMatchmakingBasePanel *pBase = dynamic_cast< CMatchmakingBasePanel* >( m_pParent );
+ if ( pBase )
+ {
+ pBase->SetFooterButtonVisible( "#GameUI_PlayerReview", pBase->GetGameType() != GAMETYPE_SYSTEMLINK_MATCH );
+
+ // hide the settings changing if we're in a ranked game
+ if ( m_pHostOptionsPanel )
+ {
+ bool bVisible = pBase->GetGameType() != GAMETYPE_RANKED_MATCH;
+ vgui::Label *pSettingsLabel = (vgui::Label *)m_pHostOptionsPanel->FindChildByName("ChangeSettingsButton",true);
+ if ( pSettingsLabel )
+ {
+ pSettingsLabel->SetVisible( bVisible );
+ }
+ pSettingsLabel = (vgui::Label *)m_pHostOptionsPanel->FindChildByName("ChangeSettingsText",true);
+ if ( pSettingsLabel )
+ {
+ pSettingsLabel->SetVisible( bVisible );
+ }
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Parse session properties and contexts from the resource file
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ m_nImageBorderWidth = pResourceData->GetInt( "imageborderwidth", 15 );
+ m_nTeamspacing = pResourceData->GetInt( "teamspacing", 0 );
+ m_bHostLobby = pResourceData->GetInt( "hostlobby", 0 ) != 0;
+ m_bCenterOnScreen = pResourceData->GetInt( "center", 1 ) == 1;
+
+ Q_strncpy( m_szCommand, pResourceData->GetString( "commandstring", "NULL" ), sizeof( m_szCommand ) );
+}
+
+//---------------------------------------------------------------------
+// Purpose: Set up colors and other such stuff
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ Color cLabelColor = pScheme->GetColor( "MatchmakingDialogTitleColor", Color( 0, 0, 0, 255 ) );
+
+ m_pLobbyStateLabel->SetFgColor( cLabelColor );
+ m_pHostLabel->SetFgColor( cLabelColor );
+
+ m_pLobbyStateBg->SetBgColor( pScheme->GetColor( "TanDarker", Color( 0, 0, 0, 255 ) ) );
+ m_pLobbyStateBg->SetPaintBackgroundType( 2 );
+
+ m_pHostOptionsPanel->SetBgColor( pScheme->GetColor( "TanDarker", Color( 0, 0, 0, 255 ) ) );
+ m_pHostOptionsPanel->SetPaintBackgroundType( 2 );
+
+ m_pScenarioInfo->SetBgColor( pScheme->GetColor( "TanDarker", Color( 0, 0, 0, 255 ) ) );
+ m_pTeamInfos[BLUE_TEAM_LOBBY]->SetBgColor( pScheme->GetColor( "HudBlueTeam", Color( 0, 0, 0, 255 ) ) );
+ m_pTeamInfos[RED_TEAM_LOBBY]->SetBgColor( pScheme->GetColor( "HudRedTeam", Color( 0, 0, 0, 255 ) ) );
+
+ // Cache of these heights so we never go below them when resizing
+ m_nMinInfoHeight[BLUE_TEAM_LOBBY] = m_pTeamInfos[BLUE_TEAM_LOBBY]->GetTall();
+ m_nMinInfoHeight[RED_TEAM_LOBBY] = m_pTeamInfos[RED_TEAM_LOBBY]->GetTall();
+
+ //Lets set all the labels this panel owns to be the right fgcolor. hooray vgui!
+ int iChildren = m_pHostOptionsPanel->GetChildCount();
+
+ for ( int i=0;i<iChildren;i++ )
+ {
+ vgui::Label *pLabel = dynamic_cast< vgui::Label * >( m_pHostOptionsPanel->GetChild(i) );
+ if ( pLabel )
+ {
+ SETUP_PANEL( pLabel );
+ pLabel->SetFgColor( cLabelColor );
+ }
+ }
+
+ vgui::Label *pPlayerReviewLabel = (vgui::Label *)FindChildByName("PlayerReviewLabel" );
+ if ( pPlayerReviewLabel )
+ {
+ SETUP_PANEL( pPlayerReviewLabel );
+ pPlayerReviewLabel->SetFgColor( cLabelColor );
+ }
+
+ SetLobbyReadyState( m_nLastPlayersNeeded );
+}
+
+void CSessionLobbyDialog::PositionTeamInfos()
+{
+ // Line up the team info panels and menus
+ int x, y;
+ int menux, menuy;
+ m_pTeamInfos[0]->GetPos( x, y );
+ m_Menus[0].GetPos( menux, menuy );
+
+ for ( int i = 1; i < TOTAL_LOBBY_TEAMS; ++i )
+ {
+ y += m_pTeamInfos[i - 1]->GetTall() + m_nTeamspacing;
+ m_pTeamInfos[i]->SetPos( x, y );
+ m_Menus[i].SetPos( menux, y );
+ }
+}
+
+void CSessionLobbyDialog::ActivateNextMenu()
+{
+ int startIndex = m_iActiveMenu;
+ m_Menus[m_iActiveMenu].SetFocus( -1 );
+ do
+ {
+ m_iActiveMenu = (m_iActiveMenu + 1) % TOTAL_LOBBY_TEAMS;
+ } while ( m_Menus[m_iActiveMenu].GetItemCount() == 0 && m_iActiveMenu != startIndex );
+
+ m_Menus[m_iActiveMenu].SetFocus( 0 );
+}
+
+void CSessionLobbyDialog::ActivatePreviousMenu()
+{
+ int startIndex = m_iActiveMenu;
+ m_Menus[m_iActiveMenu].SetFocus( -1 );
+ do
+ {
+ m_iActiveMenu = m_iActiveMenu ? m_iActiveMenu - 1 : TOTAL_LOBBY_TEAMS - 1;
+ } while ( m_Menus[m_iActiveMenu].GetItemCount() == 0 && m_iActiveMenu != startIndex );
+
+ m_Menus[m_iActiveMenu].SetFocus( m_Menus[m_iActiveMenu].GetItemCount() - 1 );
+}
+
+void CSessionLobbyDialog::UpdatePlayerCountDisplay( int iTeam )
+{
+ int ct = m_Menus[iTeam].GetItemCount();
+ wchar_t wszString[32];
+ wchar_t *wzPlayersFmt = g_pVGuiLocalize->Find( ct != 1 ? "#TF_ScoreBoard_Players" : "#TF_ScoreBoard_Player" );
+ wchar_t wzPlayerCt[8];
+ V_snwprintf( wzPlayerCt, ARRAYSIZE( wzPlayerCt ), L"%d", ct );
+ g_pVGuiLocalize->ConstructString( wszString, sizeof( wszString ), wzPlayersFmt, 1, wzPlayerCt );
+
+ m_pTeamInfos[iTeam]->m_pSubtitle->SetText( wszString );
+
+ if ( m_nMinInfoHeight[iTeam] == 0 )
+ {
+ m_nMinInfoHeight[iTeam] = m_pTeamInfos[iTeam]->GetTall();
+ }
+
+ int height = max( m_nMinInfoHeight[iTeam], m_Menus[iTeam].GetTall() );
+ m_pTeamInfos[iTeam]->SetTall( height );
+
+ PositionTeamInfos();
+}
+
+void CSessionLobbyDialog::UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int iTeam, byte cVoiceState, int nPlayersNeeded, bool bHost )
+{
+ if ( m_iLocalTeam == -1 )
+ {
+ m_iLocalTeam = iTeam;
+ }
+
+ bool bReady = ( nPlayersNeeded == 0 );
+
+ // Look for the player
+ int iFoundTeam = -1;
+ int iFoundItem = -1;
+ CPlayerItem *pFound = NULL;
+ for ( int iMenu = 0; iMenu < TOTAL_LOBBY_TEAMS && !pFound; ++iMenu )
+ {
+ CDialogMenu &menu = m_Menus[iMenu];
+
+ if ( menu.GetItemCount() == 0 )
+ continue;
+
+ for ( int idx = 0; idx < menu.GetItemCount(); ++idx )
+ {
+ CPlayerItem *pPlayerItem = dynamic_cast< CPlayerItem* >( menu.GetItem( idx ) );
+ if ( pPlayerItem && pPlayerItem->m_nId == nPlayerId )
+ {
+ pFound = pPlayerItem;
+ iFoundTeam = iMenu;
+ iFoundItem = idx;
+ break;
+ }
+ }
+ }
+
+ // Update menu and item focus if the player changed teams
+ if ( iFoundTeam != iTeam )
+ {
+ if ( pFound )
+ {
+ // Remove the player from the current team
+ m_Menus[iFoundTeam].RemovePlayerItem( iFoundItem );
+ UpdatePlayerCountDisplay( iFoundTeam );
+ }
+
+ if ( 0 <= iTeam && iTeam < TOTAL_LOBBY_TEAMS )
+ {
+ // Add the player to the new team
+ m_Menus[iTeam].AddPlayerItem( pName, nPlayerId, cVoiceState, bReady );
+ UpdatePlayerCountDisplay( iTeam );
+ }
+
+ // if the player joined an empty lobby, set the active team
+ if ( m_iActiveMenu == -1 )
+ {
+ m_iActiveMenu = iTeam;
+ m_Menus[m_iActiveMenu].SetFocus( 0 );
+ }
+
+ // update the highlight position
+ if ( iFoundTeam == m_iActiveMenu )
+ {
+ CDialogMenu &activeMenu = m_Menus[m_iActiveMenu];
+ int iActive = activeMenu.GetActiveItemIndex();
+
+ if ( iActive == iFoundItem )
+ {
+ // The changed player was also the highlighted player
+ if ( iTeam >= 0 )
+ {
+ // Move the highlight to the player's new position
+ activeMenu.SetFocus( -1 );
+ m_iActiveMenu = iTeam;
+ m_Menus[m_iActiveMenu].SetFocus( m_Menus[m_iActiveMenu].GetItemCount() - 1 );
+ }
+ else
+ {
+ // player left the game, move the highlight to the next filled slot
+ if ( iActive >= activeMenu.GetItemCount() )
+ {
+ ActivateNextMenu();
+ }
+ }
+ }
+ else if ( iActive > iFoundItem )
+ {
+ // Need to drop the highlighted index one slot
+ m_Menus[m_iActiveMenu].SetFocus( iActive - 1 );
+ }
+ }
+ }
+ else
+ {
+ if ( pFound )
+ {
+ if ( pFound->m_bVoice != cVoiceState )
+ {
+ pFound->m_bVoice = cVoiceState;
+ pFound->InvalidateLayout();
+ }
+ }
+ }
+
+ if ( bHost )
+ {
+ wchar_t wszString[MAX_PATH];
+ wchar_t wszHostname[MAX_PATH];
+ wchar_t *wzHostFmt = g_pVGuiLocalize->Find( "#TF_Lobby_Host" );
+ g_pVGuiLocalize->ConvertANSIToUnicode( pName, wszHostname, sizeof( wszHostname ) );
+
+ V_snwprintf( wszString, ARRAYSIZE(wszString), L"%s\n%s", wzHostFmt, wszHostname );
+
+ m_pHostLabel->SetText( wszString );
+ m_nHostId = nPlayerId;
+ }
+
+ int iPlayersNeeded = ( bReady ) ? 0 : nPlayersNeeded;
+ SetLobbyReadyState( iPlayersNeeded );
+ m_nLastPlayersNeeded = iPlayersNeeded;
+
+ InvalidateLayout( true, false );
+}
+
+void CSessionLobbyDialog::SetLobbyReadyState( int nPlayersNeeded )
+{
+ // check if the host is allowed to start the game
+ if ( nPlayersNeeded <= 0 )
+ {
+ if ( m_bHostLobby )
+ {
+ m_pLobbyStateLabel->SetText( "#TF_PressStart" );
+ m_pLobbyStateIcon->SetText( "#GameUI_Icons_START" );
+ }
+ else
+ {
+ m_pLobbyStateLabel->SetText( "#TF_WaitingForHost" );
+ m_pLobbyStateIcon->SetText( "#TF_Icon_Alert" );
+
+ m_bStartingGame = false; // client guesses that they can change teams
+ }
+ }
+ else
+ {
+ wchar_t wszWaiting[64];
+ wchar_t *wzWaitingFmt;
+ if ( nPlayersNeeded == 1 )
+ {
+ wzWaitingFmt = g_pVGuiLocalize->Find( "#TF_WaitingForPlayerFmt" );
+ }
+ else
+ {
+ wzWaitingFmt = g_pVGuiLocalize->Find( "#TF_WaitingForPlayersFmt" );
+ }
+ wchar_t wzPlayers[8];
+ V_snwprintf( wzPlayers, ARRAYSIZE( wzPlayers ), L"%d", nPlayersNeeded );
+ g_pVGuiLocalize->ConstructString( wszWaiting, sizeof( wszWaiting ), wzWaitingFmt, 1, wzPlayers );
+ m_pLobbyStateLabel->SetText( wszWaiting );
+ m_pLobbyStateIcon->SetText( "#TF_Icon_Alert" );
+
+ // If we were starting and dropped below min players, cancel
+ SetStartGame( false );
+ }
+}
+
+void CSessionLobbyDialog::UpdateCountdown( int seconds )
+{
+ if ( seconds == -1 )
+ {
+ // countdown was canceled
+ SetLobbyReadyState( 0 );
+ return;
+ }
+
+ // Set the text in the countdown label
+ wchar_t wszCountdown[MAX_PATH];
+ wchar_t wszSeconds[MAX_PATH];
+ wchar_t *wzCountdownFmt;
+ if ( seconds != 1 )
+ {
+ wzCountdownFmt = g_pVGuiLocalize->Find( "#TF_StartingInSecs" );
+ }
+ else
+ {
+ wzCountdownFmt = g_pVGuiLocalize->Find( "#TF_StartingInSec" );
+ }
+ V_snwprintf( wszSeconds, ARRAYSIZE( wszSeconds ), L"%d", seconds );
+ g_pVGuiLocalize->ConstructString( wszCountdown, sizeof( wszCountdown ), wzCountdownFmt, 1, wszSeconds );
+
+ m_pLobbyStateLabel->SetText( wszCountdown );
+
+ if ( !m_bHostLobby )
+ {
+ m_bStartingGame = true; // client guesses that they can't change teams
+ }
+}
+
+//-----------------------------------------------------------------
+// Purpose: Send key presses to the dialog's menu
+//-----------------------------------------------------------------
+void CSessionLobbyDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ CDialogMenu *pMenu = &m_Menus[m_iActiveMenu];
+ if ( !pMenu )
+ return;
+
+ int idx = pMenu->GetActiveItemIndex();
+ int itemCt = pMenu->GetItemCount();
+
+ CPlayerItem *pItem = dynamic_cast< CPlayerItem* >( pMenu->GetItem( idx ) );
+ if ( !pItem )
+ return;
+
+ SetDeleteSelfOnClose( true );
+
+ switch( code )
+ {
+ case KEY_XBUTTON_DOWN:
+ case KEY_XSTICK1_DOWN:
+ case STEAMCONTROLLER_DPAD_DOWN:
+ if ( idx >= itemCt - 1 )
+ {
+ ActivateNextMenu();
+ }
+ else
+ {
+ pMenu->HandleKeyCode( code );
+ }
+ break;
+
+ case KEY_XBUTTON_UP:
+ case KEY_XSTICK1_UP:
+ case STEAMCONTROLLER_DPAD_UP:
+ if ( idx <= 0 )
+ {
+ ActivatePreviousMenu();
+ }
+ else
+ {
+ pMenu->HandleKeyCode( code );
+ }
+ break;
+
+ case KEY_XBUTTON_A:
+ case STEAMCONTROLLER_A:
+#ifdef _X360
+ XShowGamerCardUI( XBX_GetPrimaryUserId(), pItem->m_nId );
+#endif
+ break;
+
+ case KEY_XBUTTON_RIGHT_SHOULDER:
+#ifdef _X360
+ {
+ // Don't allow player reviews in system link games
+ CMatchmakingBasePanel *pBase = dynamic_cast< CMatchmakingBasePanel* >( m_pParent );
+ if ( pBase && pBase->GetGameType() == GAMETYPE_SYSTEMLINK_MATCH )
+ break;
+ }
+
+ XShowPlayerReviewUI( XBX_GetPrimaryUserId(), pItem->m_nId );
+#endif
+ break;
+
+ case KEY_XBUTTON_LEFT_SHOULDER:
+ {
+ // Don't kick ourselves
+ if ( m_bHostLobby )
+ {
+ if ( pItem && ((CPlayerItem*)pItem)->m_nId != m_nHostId )
+ {
+ GameUI().ShowMessageDialog( MD_KICK_CONFIRMATION, this );
+ }
+ else
+ {
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+ }
+ }
+ break;
+
+ case KEY_XBUTTON_B:
+ case STEAMCONTROLLER_B:
+ GameUI().ShowMessageDialog( MD_EXIT_SESSION_CONFIRMATION, this );
+
+ if ( m_bHostLobby )
+ {
+ SetStartGame( false );
+ }
+ break;
+
+ case KEY_XBUTTON_X:
+ case STEAMCONTROLLER_X:
+ if ( m_bStartingGame )
+ {
+ // We think we're loading the game, so play deny sound
+ vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
+ }
+ else
+ {
+ matchmaking->ChangeTeam( NULL );
+ }
+ break;
+
+ case KEY_XBUTTON_Y:
+ case STEAMCONTROLLER_Y:
+ if ( m_bHostLobby )
+ {
+ // Don't allow settings changes in ranked games
+ CMatchmakingBasePanel *pBase = dynamic_cast< CMatchmakingBasePanel* >( m_pParent );
+ if ( pBase && pBase->GetGameType() == GAMETYPE_RANKED_MATCH )
+ break;
+
+ SetDeleteSelfOnClose( false );
+ OnCommand( "SessionOptions_Modify" );
+ SetStartGame( false );
+ }
+ break;
+
+ case KEY_XBUTTON_START:
+ SetStartGame( !m_bStartingGame );
+ break;
+
+ default:
+ pMenu->HandleKeyCode( code );
+ break;
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: start and stop the countdown
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::SetStartGame( bool bStartGame )
+{
+ if ( !m_bHostLobby )
+ return;
+
+ bool bCanStart = true;
+ if ( m_bStartingGame != bStartGame )
+ {
+ if ( bStartGame )
+ {
+ m_bStartingGame = matchmaking->StartGame();
+ bCanStart = m_bStartingGame;
+ }
+ else
+ {
+ if ( matchmaking->CancelStartGame() )
+ {
+ m_bStartingGame = false;
+ }
+ }
+
+ // If we can start the game but haven't started yet, show the "Start Game" label
+ bool bShowStartGame = bCanStart && !m_bStartingGame;
+
+ // show/hide the "start game" and countdown hint label based on state
+ vgui::Label *pStartGame = (vgui::Label *)m_pHostOptionsPanel->FindChildByName("StartGameText" );
+ if ( pStartGame )
+ {
+ pStartGame->SetVisible( m_bStartingGame == false );
+ }
+
+ vgui::Label *pCancelCountdown = (vgui::Label *)m_pHostOptionsPanel->FindChildByName("CancelGameText" );
+ if ( pCancelCountdown )
+ {
+ pCancelCountdown->SetVisible( m_bStartingGame == true );
+ }
+
+ if ( bShowStartGame )
+ {
+ m_pLobbyStateLabel->SetText( "#TF_PressStart" );
+ m_pLobbyStateIcon->SetText( "#GameUI_Icons_START" );
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Handle menu commands
+//---------------------------------------------------------------------
+void CSessionLobbyDialog::OnCommand( const char *pCommand )
+{
+ if ( !Q_stricmp( pCommand, "ReturnToMainMenu" ) )
+ {
+ matchmaking->KickPlayerFromSession( 0 );
+ }
+ else if ( !Q_stricmp( pCommand, "KickPlayer" ) )
+ {
+ CDialogMenu *pMenu = &m_Menus[m_iActiveMenu];
+ CPlayerItem *pItem = (CPlayerItem*)pMenu->GetItem( pMenu->GetActiveItemIndex() );
+ if ( pItem )
+ {
+ matchmaking->KickPlayerFromSession( pItem->m_nId );
+ }
+ }
+
+ GetParent()->OnCommand( pCommand );
+}
+
+static int pnum = 1;
+
+CON_COMMAND( mm_add_player, "Add a player" )
+{
+ if ( args.ArgC() >= 5 )
+ {
+ int team = atoi( args[1] );
+ const char *pName = args[2];
+ uint32 id = atoi( args[3] );
+ byte cVoiceState = atoi( args[4] ) != 0;
+ int nPlayersNeeded = atoi( args[5] );
+ g_pLobbyDialog->UpdatePlayerInfo( id, pName, team, cVoiceState, nPlayersNeeded, false );
+ }
+ else if ( args.ArgC() >= 1 )
+ {
+ char name[ 32 ];
+ int team = pnum & 0x1;
+ int id = pnum++;
+ if ( args.ArgC() >= 2 )
+ {
+ team = atoi( args[ 1 ] );
+ if ( args.ArgC() >= 3 )
+ {
+ id = atoi( args[2] );
+ }
+ }
+ Q_snprintf( name, sizeof( name ), "Player%d", pnum );
+ g_pLobbyDialog->UpdatePlayerInfo( id, name, team, true, 0, false );
+ }
+} \ No newline at end of file
diff --git a/gameui/matchmaking/sessionlobbydialog.h b/gameui/matchmaking/sessionlobbydialog.h
new file mode 100644
index 0000000..9049333
--- /dev/null
+++ b/gameui/matchmaking/sessionlobbydialog.h
@@ -0,0 +1,85 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SESSIONLOBBYDIALOG_H
+#define SESSIONLOBBYDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple menu to choose a matchmaking session type
+//-----------------------------------------------------------------------------
+class CSessionLobbyDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CSessionLobbyDialog, CBaseDialog );
+
+public:
+ CSessionLobbyDialog( vgui::Panel *parent );
+ ~CSessionLobbyDialog();
+
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+ virtual void PerformLayout();
+ virtual void ApplySettings( KeyValues *inResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ void SetDialogKeys( KeyValues *pKeys );
+ void UpdatePlayerInfo( uint64 nPlayerId, const char *pName, int nTeam, byte cVoiceState, int nPlayersNeeded, bool bHost );
+ void UpdateCountdown( int seconds );
+
+private:
+ void ActivateNextMenu();
+ void ActivatePreviousMenu();
+ void UpdatePlayerCountDisplay( int iTeam );
+ void SetLobbyReadyState( int nPlayersNeeded );
+ void PositionTeamInfos();
+
+ void SetTextFromKeyvalues( CPropertyLabel *pLabel );
+
+ void SetStartGame( bool bStartGame );
+
+ enum
+ {
+ BLUE_TEAM_LOBBY,
+ RED_TEAM_LOBBY,
+ TOTAL_LOBBY_TEAMS,
+ };
+
+ CDialogMenu m_Menus[TOTAL_LOBBY_TEAMS];
+
+ vgui::Panel *m_pLobbyStateBg;
+ CPropertyLabel *m_pLobbyStateLabel;
+ CPropertyLabel *m_pLobbyStateIcon;
+ CPropertyLabel *m_pHostLabel;
+ vgui::EditablePanel *m_pHostOptionsPanel;
+
+ KeyValues *m_pDialogKeys;
+
+ CScenarioInfoPanel *m_pScenarioInfo;
+ CScenarioInfoPanel *m_pTeamInfos[TOTAL_LOBBY_TEAMS];
+
+ int m_nMinInfoHeight[TOTAL_LOBBY_TEAMS];
+
+ uint64 m_nHostId;
+ bool m_bReady;
+ bool m_bHostLobby;
+ bool m_bCenterOnScreen;
+ int m_iLocalTeam;
+ int m_iActiveMenu;
+ int m_nImageBorderWidth;
+ int m_nTeamspacing;
+ char m_szCommand[MAX_COMMAND_LEN];
+
+ bool m_bStartingGame;
+ int m_nLastPlayersNeeded;
+};
+
+
+#endif // SESSIONLOBBYDIALOG_H
diff --git a/gameui/matchmaking/sessionoptionsdialog.cpp b/gameui/matchmaking/sessionoptionsdialog.cpp
new file mode 100644
index 0000000..fba64d8
--- /dev/null
+++ b/gameui/matchmaking/sessionoptionsdialog.cpp
@@ -0,0 +1,420 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Dialog for setting customizable game options
+//
+//=============================================================================//
+
+#include "sessionoptionsdialog.h"
+#include "engine/imatchmaking.h"
+#include "EngineInterface.h"
+#include "vgui_controls/ImagePanel.h"
+#include "vgui_controls/Label.h"
+#include "KeyValues.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//---------------------------------------------------------------------
+// CSessionOptionsDialog
+//---------------------------------------------------------------------
+CSessionOptionsDialog::CSessionOptionsDialog( vgui::Panel *pParent ) : BaseClass( pParent, "SessionOptions" )
+{
+ SetDeleteSelfOnClose( true );
+
+ m_pDialogKeys = NULL;
+ m_bModifySession = false;
+}
+
+CSessionOptionsDialog::~CSessionOptionsDialog()
+{
+ m_pScenarioInfos.PurgeAndDeleteElements();
+}
+
+//---------------------------------------------------------------------
+// Purpose: Dialog keys contain session contexts and properties
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::SetDialogKeys( KeyValues *pKeys )
+{
+ m_pDialogKeys = pKeys;
+}
+
+
+//---------------------------------------------------------------------
+// Purpose: Strip off the game type from the resource name
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::SetGameType( const char *pString )
+{
+ // Get the full gametype from the resource name
+ const char *pGametype = Q_stristr( pString, "_" );
+ if ( !pGametype )
+ return;
+
+ Q_strncpy( m_szGametype, pGametype + 1, sizeof( m_szGametype ) );
+
+ // set the menu filter
+ m_Menu.SetFilter( m_szGametype );
+}
+
+//---------------------------------------------------------------------
+// Purpose: Center the dialog on the screen
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ UpdateScenarioDisplay();
+
+ MoveToCenterOfScreen();
+
+ if ( m_pRecommendedLabel )
+ {
+ bool bHosting = ( Q_stristr( m_szGametype, "Host" ) );
+ m_pRecommendedLabel->SetVisible( bHosting );
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Apply common properties and contexts
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::ApplyCommonProperties( KeyValues *pKeys )
+{
+ for ( KeyValues *pProperty = pKeys->GetFirstSubKey(); pProperty != NULL; pProperty = pProperty->GetNextKey() )
+ {
+ const char *pName = pProperty->GetName();
+
+ if ( !Q_stricmp( pName, "SessionContext" ) )
+ {
+ // Create a new session context
+ sessionProperty_t ctx;
+ ctx.nType = SESSION_CONTEXT;
+ Q_strncpy( ctx.szID, pProperty->GetString( "id", "NULL" ), sizeof( ctx.szID ) );
+ Q_strncpy( ctx.szValue, pProperty->GetString( "value", "NULL" ), sizeof( ctx.szValue ) );
+ // ctx.szValueType not used
+
+ m_SessionProperties.AddToTail( ctx );
+ }
+ else if ( !Q_stricmp( pName, "SessionProperty" ) )
+ {
+ // Create a new session property
+ sessionProperty_t prop;
+ prop.nType = SESSION_PROPERTY;
+ Q_strncpy( prop.szID, pProperty->GetString( "id", "NULL" ), sizeof( prop.szID ) );
+ Q_strncpy( prop.szValue, pProperty->GetString( "value", "NULL" ), sizeof( prop.szValue ) );
+ Q_strncpy( prop.szValueType, pProperty->GetString( "valuetype", "NULL" ), sizeof( prop.szValueType ) );
+
+ m_SessionProperties.AddToTail( prop );
+ }
+ else if ( !Q_stricmp( pName, "SessionFlag" ) )
+ {
+ sessionProperty_t flag;
+ flag.nType = SESSION_FLAG;
+ Q_strncpy( flag.szID, pProperty->GetString(), sizeof( flag.szID ) );
+
+ m_SessionProperties.AddToTail( flag );
+ }
+ }
+}
+
+//---------------------------------------------------------------------
+// Purpose: Parse session properties and contexts from the resource file
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::ApplySettings( KeyValues *pResourceData )
+{
+ BaseClass::ApplySettings( pResourceData );
+
+ // Apply settings common to all game types
+ ApplyCommonProperties( pResourceData );
+
+ // Apply settings specific to this game type
+ KeyValues *pSettings = pResourceData->FindKey( m_szGametype );
+ if ( pSettings )
+ {
+ Q_strncpy( m_szCommand, pSettings->GetString( "commandstring", "NULL" ), sizeof( m_szCommand ) );
+ m_pTitle->SetText( pSettings->GetString( "title", "Unknown" ) );
+
+ ApplyCommonProperties( pSettings );
+ }
+
+ 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 );
+ }
+
+ m_pScenarioInfos.AddToTail( pScenarioInfo );
+ }
+ }
+
+ if ( Q_stristr( m_szGametype, "Modify" ) )
+ {
+ m_bModifySession = true;
+ }
+}
+
+int CSessionOptionsDialog::GetMaxPlayersRecommendedOption( void )
+{
+ MM_QOS_t qos = matchmaking->GetQosWithLIVE();
+
+ // Conservatively assume that every player needs ~ 7 kBytes/s
+ // plus one for the hosting player.
+ int numPlayersCanService = 1 + int( qos.flBwUpKbs / 7.0f );
+
+ // Determine the option that suits our B/W bests
+ int options[] = { 8, 12, 16 };
+
+ for ( int k = 1; k < ARRAYSIZE( options ); ++ k )
+ {
+ if ( options[k] > numPlayersCanService )
+ {
+ Msg( "[SessionOptionsDialog] Defaulting number of players to %d (upstream b/w = %.1f kB/s ~ %d players).\n",
+ options[k - 1], qos.flBwUpKbs, numPlayersCanService );
+ return k - 1;
+ }
+ }
+
+ return ARRAYSIZE( options ) - 1;
+}
+
+//---------------------------------------------------------------------
+// Purpose: Set up colors and other such stuff
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::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 ) ) );
+ }
+
+ m_pRecommendedLabel = dynamic_cast<vgui::Label *>(FindChildByName( "RecommendedLabel" ));
+}
+
+//---------------------------------------------------------------------
+// Purpose: Send all properties and contexts to the matchmaking session
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::SetupSession( void )
+{
+ KeyValues *pKeys = new KeyValues( "SessionKeys" );
+
+ // Send user-selected properties and contexts
+ for ( int i = 0; i < m_Menu.GetItemCount(); ++i )
+ {
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( m_Menu.GetItem( i ) );
+ if ( !pItem )
+ {
+ continue;
+ }
+
+ const sessionProperty_t &prop = pItem->GetActiveOption();
+
+ KeyValues *pProperty = pKeys->CreateNewKey();
+ pProperty->SetName( prop.szID );
+ pProperty->SetInt( "type", prop.nType );
+ pProperty->SetString( "valuestring", prop.szValue );
+ pProperty->SetString( "valuetype", prop.szValueType );
+ pProperty->SetInt( "optionindex", pItem->GetActiveOptionIndex() );
+ }
+
+ // Send contexts and properties parsed from the resource file
+ for ( int i = 0; i < m_SessionProperties.Count(); ++i )
+ {
+ const sessionProperty_t &prop = m_SessionProperties[i];
+
+ KeyValues *pProperty = pKeys->CreateNewKey();
+ pProperty->SetName( prop.szID );
+ pProperty->SetInt( "type", prop.nType );
+ pProperty->SetString( "valuestring", prop.szValue );
+ pProperty->SetString( "valuetype", prop.szValueType );
+ }
+
+ // Matchmaking will make a copy of these keys
+ matchmaking->SetSessionProperties( pKeys );
+ pKeys->deleteThis();
+}
+
+//-----------------------------------------------------------------
+// Purpose: Show the correct scenario image and text
+//-----------------------------------------------------------------
+void CSessionOptionsDialog::UpdateScenarioDisplay( void )
+{
+ // Check if the selected map has changed (first menu item)
+ int idx = m_Menu.GetActiveOptionIndex( 0 );
+ for ( int i = 0; i < m_pScenarioInfos.Count(); ++i )
+ {
+ m_pScenarioInfos[i]->SetVisible( i == idx );
+ }
+}
+
+//-----------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------
+void CSessionOptionsDialog::OnMenuItemChanged( KeyValues *pData )
+{
+ // which item changed
+ int iItem = pData->GetInt( "item", -1 );
+
+ if ( iItem >= 0 && iItem < m_Menu.GetItemCount() )
+ {
+ COptionsItem *pActiveOption = dynamic_cast< COptionsItem* >( m_Menu.GetItem( iItem ) );
+ if ( pActiveOption )
+ {
+ const sessionProperty_t &activeOption = pActiveOption->GetActiveOption();
+
+ if ( !Q_strncmp( activeOption.szID, "PROPERTY_GAME_SIZE", sessionProperty_t::MAX_KEY_LEN ) )
+ {
+ // make sure the private slots is less than prop.szValue
+
+ int iMaxPlayers = atoi(activeOption.szValue);
+ bool bShouldWarnMaxPlayers = ( pActiveOption->GetActiveOptionIndex() > GetMaxPlayersRecommendedOption() );
+ m_pRecommendedLabel->SetVisible( bShouldWarnMaxPlayers );
+
+ // find the private slots option and repopulate it
+ for ( int iMenu = 0; iMenu < m_Menu.GetItemCount(); ++iMenu )
+ {
+ COptionsItem *pItem = dynamic_cast< COptionsItem* >( m_Menu.GetItem( iMenu ) );
+ if ( !pItem )
+ {
+ continue;
+ }
+
+ const sessionProperty_t &prop = pItem->GetActiveOption();
+
+ if ( !Q_strncmp( prop.szID, "PROPERTY_PRIVATE_SLOTS", sessionProperty_t::MAX_KEY_LEN ) )
+ {
+ const sessionProperty_t baseProp = pItem->GetActiveOption();
+
+ // preserve the selection
+ int iActiveItem = pItem->GetActiveOptionIndex();
+
+ // clear all options
+ pItem->DeleteAllOptions();
+
+ // re-add the items 0 - maxplayers
+ int nStart = 0;
+ int nEnd = iMaxPlayers;
+ int nInterval = 1;
+
+ for ( int i = nStart; i <= nEnd; i += nInterval )
+ {
+ sessionProperty_t propNew;
+ propNew.nType = SESSION_PROPERTY;
+ Q_strncpy( propNew.szID, baseProp.szID, sizeof( propNew.szID ) );
+ Q_strncpy( propNew.szValueType, baseProp.szValueType, sizeof( propNew.szValueType ) );
+ Q_snprintf( propNew.szValue, sizeof( propNew.szValue), "%d", i );
+ pItem->AddOption( propNew.szValue, propNew );
+ }
+
+ // re-set the focus
+ pItem->SetOptionFocus( min( iActiveItem, iMaxPlayers ) );
+
+ // fixup the option sizes
+ m_Menu.InvalidateLayout();
+ }
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------
+// Purpose: Change properties of a menu item
+//-----------------------------------------------------------------
+void CSessionOptionsDialog::OverrideMenuItem( KeyValues *pItemKeys )
+{
+ if ( m_bModifySession && m_pDialogKeys )
+ {
+ if ( !Q_stricmp( pItemKeys->GetName(), "OptionsItem" ) )
+ {
+ const char *pID = pItemKeys->GetString( "id", "NULL" );
+
+ KeyValues *pKey = m_pDialogKeys->FindKey( pID );
+ if ( pKey )
+ {
+ pItemKeys->SetInt( "activeoption", pKey->GetInt( "optionindex" ) );
+ }
+ }
+ }
+
+ //
+ // When hosting a new session on LIVE:
+ // - restrict max number of players to bandwidth allowed
+ //
+ if ( !m_bModifySession &&
+ ( !Q_stricmp( m_szGametype, "hoststandard" ) || !Q_stricmp( m_szGametype, "hostranked" ) )
+ )
+ {
+ if ( !Q_stricmp( pItemKeys->GetName(), "OptionsItem" ) )
+ {
+ const char *pID = pItemKeys->GetString( "id", "NULL" );
+ if ( !Q_stricmp( pID, "PROPERTY_GAME_SIZE" ) )
+ {
+ pItemKeys->SetInt( "activeoption", GetMaxPlayersRecommendedOption() );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------
+// Purpose: Send key presses to the dialog's menu
+//-----------------------------------------------------------------
+void CSessionOptionsDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ if ( code == KEY_XBUTTON_A || code == STEAMCONTROLLER_A )
+ {
+ OnCommand( m_szCommand );
+ }
+ else if ( (code == KEY_XBUTTON_B || code == STEAMCONTROLLER_B) && m_bModifySession )
+ {
+ // Return to the session lobby without making any changes
+ OnCommand( "DialogClosing" );
+ }
+ else
+ {
+ BaseClass::OnKeyCodePressed( code );
+ }
+
+ UpdateScenarioDisplay();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSessionOptionsDialog::OnThink()
+{
+ vgui::KeyCode code = m_KeyRepeat.KeyRepeated();
+ if ( code )
+ {
+ m_Menu.HandleKeyCode( code );
+ UpdateScenarioDisplay();
+ }
+
+ BaseClass::OnThink();
+}
+
+//---------------------------------------------------------------------
+// Purpose: Handle menu commands
+//---------------------------------------------------------------------
+void CSessionOptionsDialog::OnCommand( const char *pCommand )
+{
+ // Don't set up the session if the dialog is just closing
+ if ( Q_stricmp( pCommand, "DialogClosing" ) )
+ {
+ SetupSession();
+ OnClose();
+ }
+
+ GetParent()->OnCommand( pCommand );
+}
+
diff --git a/gameui/matchmaking/sessionoptionsdialog.h b/gameui/matchmaking/sessionoptionsdialog.h
new file mode 100644
index 0000000..69de2b3
--- /dev/null
+++ b/gameui/matchmaking/sessionoptionsdialog.h
@@ -0,0 +1,61 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Dialog for setting customizable game options
+//
+//=============================================================================//
+
+#ifndef SESSIONOPTIONSDIALOG_H
+#define SESSIONOPTIONSDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple menu to choose a matchmaking session type
+//-----------------------------------------------------------------------------
+class CSessionOptionsDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CSessionOptionsDialog, CBaseDialog );
+
+public:
+ CSessionOptionsDialog( vgui::Panel *parent );
+ ~CSessionOptionsDialog();
+
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+ virtual void OnThink();
+
+ virtual void PerformLayout( void );
+ virtual void ApplySettings( KeyValues *pResourceData );
+ virtual void ApplySchemeSettings( vgui::IScheme *pScheme );
+
+ virtual void OverrideMenuItem( KeyValues *pKeys );
+
+ void SetGameType( const char *pGametype );
+ void SetDialogKeys( KeyValues *pKeys );
+ void ApplyCommonProperties( KeyValues *pKeys );
+
+ MESSAGE_FUNC_PARAMS( OnMenuItemChanged, "MenuItemChanged", data );
+
+private:
+ void SetupSession( void );
+ void UpdateScenarioDisplay( void );
+
+ int GetMaxPlayersRecommendedOption( void );
+
+ char m_szCommand[MAX_COMMAND_LEN];
+ char m_szGametype[MAX_COMMAND_LEN];
+ bool m_bModifySession;
+
+ KeyValues *m_pDialogKeys;
+
+ CUtlVector< sessionProperty_t > m_SessionProperties;
+ CUtlVector< CScenarioInfoPanel* > m_pScenarioInfos;
+
+ vgui::Label *m_pRecommendedLabel;
+};
+
+
+#endif // SESSIONOPTIONSDIALOG_H
diff --git a/gameui/matchmaking/welcomedialog.cpp b/gameui/matchmaking/welcomedialog.cpp
new file mode 100644
index 0000000..7249c70
--- /dev/null
+++ b/gameui/matchmaking/welcomedialog.cpp
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Matchmaking's "main menu"
+//
+//=============================================================================//
+
+#include "welcomedialog.h"
+#include "GameUI_Interface.h"
+#include "vgui_controls/MessageDialog.h"
+#include "ixboxsystem.h"
+#include "EngineInterface.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//--------------------------------
+// CPlayerMatchDialog
+//--------------------------------
+CWelcomeDialog::CWelcomeDialog( vgui::Panel *pParent ) : BaseClass( pParent, "WelcomeDialog" )
+{
+ // do nothing
+}
+
+//---------------------------------------------------------
+// Purpose: Set the title and menu positions
+//---------------------------------------------------------
+void CWelcomeDialog::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+}
+
+//-----------------------------------------------------------------
+// Purpose: Forward commands to the matchmaking base panel
+//-----------------------------------------------------------------
+void CWelcomeDialog::OnCommand( const char *pCommand )
+{
+ BaseClass::OnCommand( pCommand );
+}
+
+//-------------------------------------------------------
+// Keyboard input
+//-------------------------------------------------------
+void CWelcomeDialog::OnKeyCodePressed( vgui::KeyCode code )
+{
+ switch( code )
+ {
+ case KEY_XBUTTON_B:
+ if ( GameUI().IsInLevel() )
+ {
+ m_pParent->OnCommand( "ResumeGame" );
+ }
+ break;
+
+ default:
+ BaseClass::OnKeyCodePressed( code );
+ break;
+ }
+} \ No newline at end of file
diff --git a/gameui/matchmaking/welcomedialog.h b/gameui/matchmaking/welcomedialog.h
new file mode 100644
index 0000000..dbef44d
--- /dev/null
+++ b/gameui/matchmaking/welcomedialog.h
@@ -0,0 +1,34 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Matchmaking's "main menu"
+//
+//=============================================================================//
+
+#ifndef WELCOMEDIALOG_H
+#define WELCOMEDIALOG_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialog.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Main matchmaking menu
+//-----------------------------------------------------------------------------
+class CWelcomeDialog : public CBaseDialog
+{
+ DECLARE_CLASS_SIMPLE( CWelcomeDialog, CBaseDialog );
+
+public:
+ CWelcomeDialog(vgui::Panel *parent);
+
+ virtual void PerformLayout( void );
+ virtual void OnCommand( const char *pCommand );
+ virtual void OnKeyCodePressed( vgui::KeyCode code );
+
+private:
+ bool m_bOnlineEnabled;
+};
+
+
+#endif // WELCOMEDIALOG_H
diff --git a/gameui/vcontrolslistpanel.cpp b/gameui/vcontrolslistpanel.cpp
new file mode 100644
index 0000000..f644d3e
--- /dev/null
+++ b/gameui/vcontrolslistpanel.cpp
@@ -0,0 +1,207 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "vcontrolslistpanel.h"
+#include "GameUI_Interface.h"
+#include "EngineInterface.h"
+
+#include <vgui/IInput.h>
+#include <vgui/IScheme.h>
+#include <vgui/ISurface.h>
+#include <vgui/IVGui.h>
+#include <vgui/Cursor.h>
+#include <KeyValues.h>
+
+// NVNT including for input system access
+#include "tier2/tier2.h"
+#include "inputsystem/iinputsystem.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include <tier0/memdbgon.h>
+
+using namespace vgui;
+
+//-----------------------------------------------------------------------------
+// Purpose: panel used for inline editing of key bindings
+//-----------------------------------------------------------------------------
+class CInlineEditPanel : public vgui::Panel
+{
+public:
+ CInlineEditPanel() : vgui::Panel(NULL, "InlineEditPanel")
+ {
+ }
+
+ virtual void Paint()
+ {
+ int x = 0, y = 0, wide, tall;
+ GetSize(wide, tall);
+
+ // Draw a white rectangle around that cell
+ vgui::surface()->DrawSetColor( 255, 165, 0, 255 );
+ vgui::surface()->DrawFilledRect( x, y, x + wide, y + tall );
+ }
+
+ virtual void OnKeyCodeTyped(KeyCode code)
+ {
+ // forward up
+ if (GetParent())
+ {
+ GetParent()->OnKeyCodeTyped(code);
+ }
+ }
+
+ virtual void ApplySchemeSettings(IScheme *pScheme)
+ {
+ Panel::ApplySchemeSettings(pScheme);
+ SetBorder(pScheme->GetBorder("DepressedButtonBorder"));
+ }
+
+ void OnMousePressed(vgui::MouseCode code)
+ {
+ // forward up mouse pressed messages to be handled by the key options
+ if (GetParent())
+ {
+ GetParent()->OnMousePressed(code);
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Construction
+//-----------------------------------------------------------------------------
+VControlsListPanel::VControlsListPanel( vgui::Panel *parent, const char *listName ) : vgui::SectionedListPanel( parent, listName )
+{
+ m_bCaptureMode = false;
+ m_nClickRow = 0;
+ m_pInlineEditPanel = new CInlineEditPanel();
+ m_hFont = INVALID_FONT;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Destructor
+//-----------------------------------------------------------------------------
+VControlsListPanel::~VControlsListPanel()
+{
+ m_pInlineEditPanel->MarkForDeletion();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void VControlsListPanel::ApplySchemeSettings(IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+ m_hFont = pScheme->GetFont("Default", IsProportional() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Start capture prompt display
+//-----------------------------------------------------------------------------
+void VControlsListPanel::StartCaptureMode( HCursor hCursor )
+{
+ m_bCaptureMode = true;
+ EnterEditMode(m_nClickRow, 1, m_pInlineEditPanel);
+ input()->SetMouseFocus(m_pInlineEditPanel->GetVPanel());
+ input()->SetMouseCapture(m_pInlineEditPanel->GetVPanel());
+ // NVNT tell the input system that novint devices
+ // should be set unable to do menu mouse emulation.
+ g_pInputSystem->SetNovintPure(true);
+
+ engine->StartKeyTrapMode();
+
+ if (hCursor)
+ {
+ m_pInlineEditPanel->SetCursor(hCursor);
+
+ // save off the cursor position so we can restore it
+ vgui::input()->GetCursorPos( m_iMouseX, m_iMouseY );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finish capture prompt display
+//-----------------------------------------------------------------------------
+void VControlsListPanel::EndCaptureMode( HCursor hCursor )
+{
+ m_bCaptureMode = false;
+ input()->SetMouseCapture(NULL);
+ LeaveEditMode();
+ RequestFocus();
+ input()->SetMouseFocus(GetVPanel());
+ // NVNT tell the input system that novint devices
+ // should be allowed to do menu mouse emulation.
+ g_pInputSystem->SetNovintPure(false);
+ if (hCursor)
+ {
+ m_pInlineEditPanel->SetCursor(hCursor);
+ surface()->SetCursor(hCursor);
+ if ( hCursor != dc_none )
+ {
+ vgui::input()->SetCursorPos ( m_iMouseX, m_iMouseY );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Set active row column
+//-----------------------------------------------------------------------------
+void VControlsListPanel::SetItemOfInterest(int itemID)
+{
+ m_nClickRow = itemID;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Retrieve row, column of interest
+//-----------------------------------------------------------------------------
+int VControlsListPanel::GetItemOfInterest()
+{
+ return m_nClickRow;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: returns true if we're currently waiting to capture a key
+//-----------------------------------------------------------------------------
+bool VControlsListPanel::IsCapturing( void )
+{
+ return m_bCaptureMode;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Forwards mouse pressed message up to keyboard page when in capture
+//-----------------------------------------------------------------------------
+void VControlsListPanel::OnMousePressed(vgui::MouseCode code)
+{
+ if (IsCapturing())
+ {
+ // forward up mouse pressed messages to be handled by the key options
+ if (GetParent())
+ {
+ GetParent()->OnMousePressed(code);
+ }
+ }
+ else
+ {
+ BaseClass::OnMousePressed(code);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: input handler
+//-----------------------------------------------------------------------------
+void VControlsListPanel::OnMouseDoublePressed( vgui::MouseCode code )
+{
+ if (IsItemIDValid(GetSelectedItem()))
+ {
+ // enter capture mode
+ OnKeyCodePressed(KEY_ENTER);
+ }
+ else
+ {
+ BaseClass::OnMouseDoublePressed(code);
+ }
+}
diff --git a/gameui/vcontrolslistpanel.h b/gameui/vcontrolslistpanel.h
new file mode 100644
index 0000000..d468fa4
--- /dev/null
+++ b/gameui/vcontrolslistpanel.h
@@ -0,0 +1,54 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#if !defined( VCONTROLSLISTPANEL_H )
+#define VCONTROLSLISTPANEL_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <vgui_controls/SectionedListPanel.h>
+
+//-----------------------------------------------------------------------------
+// Purpose: Special list subclass to handle drawing of trap mode prompt on top of
+// lists client area
+//-----------------------------------------------------------------------------
+class VControlsListPanel : public vgui::SectionedListPanel
+{
+public:
+ // Construction
+ VControlsListPanel( vgui::Panel *parent, const char *listName );
+ virtual ~VControlsListPanel();
+
+ // Start/end capturing
+ virtual void StartCaptureMode(vgui::HCursor hCursor = NULL);
+ virtual void EndCaptureMode(vgui::HCursor hCursor = NULL);
+ virtual bool IsCapturing();
+
+ // Set which item should be associated with the prompt
+ virtual void SetItemOfInterest(int itemID);
+ virtual int GetItemOfInterest();
+
+ virtual void OnMousePressed(vgui::MouseCode code);
+ virtual void OnMouseDoublePressed(vgui::MouseCode code);
+
+private:
+ void ApplySchemeSettings(vgui::IScheme *pScheme );
+
+ // Are we showing the prompt?
+ bool m_bCaptureMode;
+ // If so, where?
+ int m_nClickRow;
+ // Font to use for showing the prompt
+ vgui::HFont m_hFont;
+ // panel used to edit
+ class CInlineEditPanel *m_pInlineEditPanel;
+ int m_iMouseX, m_iMouseY;
+
+ typedef vgui::SectionedListPanel BaseClass;
+};
+
+#endif // VCONTROLSLISTPANEL_H \ No newline at end of file
diff --git a/gameui/xbox/xbox.def b/gameui/xbox/xbox.def
new file mode 100644
index 0000000..444ddb1
--- /dev/null
+++ b/gameui/xbox/xbox.def
@@ -0,0 +1,3 @@
+LIBRARY gameui_360.dll
+EXPORTS
+ CreateInterface @1