This commit is contained in:
FluorescentCIAAfricanAmerican
2020-04-22 12:56:21 -04:00
commit 3bf9df6b27
15370 changed files with 5489726 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 );

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 );
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 );
}
}

View File

@@ -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

View File

@@ -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 );
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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