You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1741 lines
49 KiB
1741 lines
49 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "BasePanel.h" |
|
#include "NewGameDialog.h" |
|
#include "EngineInterface.h" |
|
#include "vgui_controls/Button.h" |
|
#include "vgui_controls/CheckButton.h" |
|
#include "KeyValues.h" |
|
#include "vgui/ISurface.h" |
|
#include "vgui/IInput.h" |
|
#include "vgui/ILocalize.h" |
|
#include <vgui/ISystem.h> |
|
#include "vgui_controls/RadioButton.h" |
|
#include "vgui_controls/ComboBox.h" |
|
#include "vgui_controls/ImagePanel.h" |
|
#include "vgui_controls/Frame.h" |
|
#include "vgui_controls/ControllerMap.h" |
|
#include "filesystem.h" |
|
#include "ModInfo.h" |
|
#include "tier1/convar.h" |
|
#include "GameUI_Interface.h" |
|
#include "tier0/icommandline.h" |
|
#include "vgui_controls/AnimationController.h" |
|
#include "CommentaryExplanationDialog.h" |
|
#include "vgui_controls/BitmapImagePanel.h" |
|
#include "BonusMapsDatabase.h" |
|
|
|
#include <stdio.h> |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
using namespace vgui; |
|
|
|
static float g_ScrollSpeedSlow; |
|
static float g_ScrollSpeedFast; |
|
|
|
// sort function used in displaying chapter list |
|
struct chapter_t |
|
{ |
|
char filename[32]; |
|
}; |
|
static int __cdecl ChapterSortFunc(const void *elem1, const void *elem2) |
|
{ |
|
chapter_t *c1 = (chapter_t *)elem1; |
|
chapter_t *c2 = (chapter_t *)elem2; |
|
|
|
// compare chapter number first |
|
static int chapterlen = strlen("chapter"); |
|
if (atoi(c1->filename + chapterlen) > atoi(c2->filename + chapterlen)) |
|
return 1; |
|
else if (atoi(c1->filename + chapterlen) < atoi(c2->filename + chapterlen)) |
|
return -1; |
|
|
|
// compare length second (longer string show up later in the list, eg. chapter9 before chapter9a) |
|
if (strlen(c1->filename) > strlen(c2->filename)) |
|
return 1; |
|
else if (strlen(c1->filename) < strlen(c2->filename)) |
|
return -1; |
|
|
|
// compare strings third |
|
return strcmp(c1->filename, c2->filename); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: invisible panel used for selecting a chapter panel |
|
//----------------------------------------------------------------------------- |
|
class CSelectionOverlayPanel : public vgui::Panel |
|
{ |
|
DECLARE_CLASS_SIMPLE( CSelectionOverlayPanel, Panel ); |
|
int m_iChapterIndex; |
|
CNewGameDialog *m_pSelectionTarget; |
|
public: |
|
CSelectionOverlayPanel( Panel *parent, CNewGameDialog *selectionTarget, int chapterIndex ) : BaseClass( parent, NULL ) |
|
{ |
|
m_iChapterIndex = chapterIndex; |
|
m_pSelectionTarget = selectionTarget; |
|
SetPaintEnabled(false); |
|
SetPaintBackgroundEnabled(false); |
|
} |
|
|
|
virtual void OnMousePressed( vgui::MouseCode code ) |
|
{ |
|
if (GetParent()->IsEnabled()) |
|
{ |
|
m_pSelectionTarget->SetSelectedChapterIndex( m_iChapterIndex ); |
|
} |
|
} |
|
|
|
virtual void OnMouseDoublePressed( vgui::MouseCode code ) |
|
{ |
|
// call the panel |
|
OnMousePressed( code ); |
|
if (GetParent()->IsEnabled()) |
|
{ |
|
PostMessage( m_pSelectionTarget, new KeyValues("Command", "command", "play") ); |
|
} |
|
} |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: selectable item with screenshot for an individual chapter in the dialog |
|
//----------------------------------------------------------------------------- |
|
class CGameChapterPanel : public vgui::EditablePanel |
|
{ |
|
DECLARE_CLASS_SIMPLE( CGameChapterPanel, vgui::EditablePanel ); |
|
|
|
ImagePanel *m_pLevelPicBorder; |
|
ImagePanel *m_pLevelPic; |
|
ImagePanel *m_pCommentaryIcon; |
|
Label *m_pChapterLabel; |
|
Label *m_pChapterNameLabel; |
|
|
|
Color m_TextColor; |
|
Color m_DisabledColor; |
|
Color m_SelectedColor; |
|
Color m_FillColor; |
|
|
|
char m_szConfigFile[_MAX_PATH]; |
|
char m_szChapter[32]; |
|
|
|
bool m_bTeaserChapter; |
|
bool m_bHasBonus; |
|
bool m_bCommentaryMode; |
|
|
|
bool m_bIsSelected; |
|
|
|
public: |
|
CGameChapterPanel( CNewGameDialog *parent, const char *name, const char *chapterName, int chapterIndex, const char *chapterNumber, const char *chapterConfigFile, bool bCommentary ) : BaseClass( parent, name ) |
|
{ |
|
Q_strncpy( m_szConfigFile, chapterConfigFile, sizeof(m_szConfigFile) ); |
|
Q_strncpy( m_szChapter, chapterNumber, sizeof(m_szChapter) ); |
|
|
|
m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) ); |
|
m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) ); |
|
m_pCommentaryIcon = NULL; |
|
m_bCommentaryMode = bCommentary; |
|
m_bIsSelected = false; |
|
|
|
wchar_t text[32]; |
|
wchar_t num[32]; |
|
wchar_t *chapter = g_pVGuiLocalize->Find("#GameUI_Chapter"); |
|
g_pVGuiLocalize->ConvertANSIToUnicode( chapterNumber, num, sizeof(num) ); |
|
_snwprintf( text, ARRAYSIZE(text), L"%ls %ls", chapter ? chapter : L"CHAPTER", num ); |
|
|
|
if ( ModInfo().IsSinglePlayerOnly() ) |
|
{ |
|
m_pChapterLabel = new Label( this, "ChapterLabel", text ); |
|
m_pChapterNameLabel = new Label( this, "ChapterNameLabel", chapterName ); |
|
} |
|
else |
|
{ |
|
m_pChapterLabel = new Label( this, "ChapterLabel", chapterName ); |
|
m_pChapterNameLabel = new Label( this, "ChapterNameLabel", "#GameUI_LoadCommentary" ); |
|
} |
|
|
|
SetPaintBackgroundEnabled( false ); |
|
|
|
KeyValues *pKeys = NULL; |
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameChapterPanel.res" ); |
|
} |
|
LoadControlSettings( "Resource/NewGameChapterPanel.res", NULL, pKeys ); |
|
|
|
// the image has the same name as the config file |
|
char szMaterial[MAX_PATH]; |
|
Q_snprintf(szMaterial, sizeof(szMaterial), "chapters/%s", chapterConfigFile); |
|
char* ext = strstr(szMaterial, "."); |
|
if (ext) |
|
{ |
|
*ext = 0; |
|
} |
|
m_pLevelPic->SetImage(szMaterial); |
|
|
|
int px, py; |
|
m_pLevelPicBorder->GetPos( px, py ); |
|
SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() ); |
|
|
|
// create a selection panel the size of the page |
|
CSelectionOverlayPanel *overlay = new CSelectionOverlayPanel( this, parent, chapterIndex ); |
|
overlay->SetBounds(0, 0, GetWide(), GetTall()); |
|
overlay->MoveToFront(); |
|
|
|
// HACK: Detect new episode teasers by the "Coming Soon" text |
|
wchar_t w_szStrTemp[256]; |
|
m_pChapterNameLabel->GetText( w_szStrTemp, sizeof(w_szStrTemp) ); |
|
m_bTeaserChapter = !wcscmp(w_szStrTemp, L"Coming Soon"); |
|
m_bHasBonus = false; |
|
} |
|
|
|
virtual void ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) ); |
|
m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) ); |
|
m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 255) ); |
|
m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) ); |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
// Hide chapter numbers for new episode teasers |
|
if ( m_bTeaserChapter ) |
|
{ |
|
m_pChapterLabel->SetVisible( false ); |
|
} |
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
m_pChapterNameLabel->SetVisible( false ); |
|
} |
|
|
|
m_pCommentaryIcon = dynamic_cast<ImagePanel*>( FindChildByName( "CommentaryIcon" ) ); |
|
if ( m_pCommentaryIcon ) |
|
m_pCommentaryIcon->SetVisible( m_bCommentaryMode ); |
|
} |
|
|
|
bool IsSelected( void ) const { return m_bIsSelected; } |
|
|
|
void SetSelected( bool state ) |
|
{ |
|
m_bIsSelected = state; |
|
|
|
// update the text/border colors |
|
if ( !IsEnabled() ) |
|
{ |
|
m_pChapterLabel->SetFgColor( m_DisabledColor ); |
|
m_pChapterNameLabel->SetFgColor( Color(0, 0, 0, 0) ); |
|
m_pLevelPicBorder->SetFillColor( m_DisabledColor ); |
|
m_pLevelPic->SetAlpha( GameUI().IsConsoleUI() ? 64 : 128 ); |
|
return; |
|
} |
|
|
|
if ( state ) |
|
{ |
|
if ( !GameUI().IsConsoleUI() ) |
|
{ |
|
m_pChapterLabel->SetFgColor( m_SelectedColor ); |
|
m_pChapterNameLabel->SetFgColor( m_SelectedColor ); |
|
} |
|
m_pLevelPicBorder->SetFillColor( m_SelectedColor ); |
|
} |
|
else |
|
{ |
|
m_pChapterLabel->SetFgColor( m_TextColor ); |
|
m_pChapterNameLabel->SetFgColor( m_TextColor ); |
|
m_pLevelPicBorder->SetFillColor( m_FillColor ); |
|
} |
|
m_pLevelPic->SetAlpha( 255 ); |
|
} |
|
|
|
const char *GetConfigFile() |
|
{ |
|
return m_szConfigFile; |
|
} |
|
|
|
const char *GetChapter() |
|
{ |
|
return m_szChapter; |
|
} |
|
|
|
bool IsTeaserChapter() |
|
{ |
|
return m_bTeaserChapter; |
|
} |
|
|
|
bool HasBonus() |
|
{ |
|
return m_bHasBonus; |
|
} |
|
|
|
void SetCommentaryMode( bool bCommentaryMode ) |
|
{ |
|
m_bCommentaryMode = bCommentaryMode; |
|
if ( m_pCommentaryIcon ) |
|
m_pCommentaryIcon->SetVisible( m_bCommentaryMode ); |
|
} |
|
}; |
|
|
|
const char *COM_GetModDirectory() |
|
{ |
|
static char modDir[MAX_PATH]; |
|
if ( Q_strlen( modDir ) == 0 ) |
|
{ |
|
const char *gamedir = CommandLine()->ParmValue("-game", CommandLine()->ParmValue( "-defaultgamedir", "hl2" ) ); |
|
Q_strncpy( modDir, gamedir, sizeof(modDir) ); |
|
if ( strchr( modDir, '/' ) || strchr( modDir, '\\' ) ) |
|
{ |
|
Q_StripLastDir( modDir, sizeof(modDir) ); |
|
int dirlen = Q_strlen( modDir ); |
|
Q_strncpy( modDir, gamedir + dirlen, sizeof(modDir) - dirlen ); |
|
} |
|
} |
|
|
|
return modDir; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: new game chapter selection |
|
//----------------------------------------------------------------------------- |
|
CNewGameDialog::CNewGameDialog(vgui::Panel *parent, bool bCommentaryMode) : BaseClass(parent, "NewGameDialog") |
|
{ |
|
SetDeleteSelfOnClose(true); |
|
SetBounds(0, 0, 372, 160); |
|
SetSizeable( false ); |
|
m_iSelectedChapter = -1; |
|
m_ActiveTitleIdx = 0; |
|
|
|
m_bCommentaryMode = bCommentaryMode; |
|
m_bMapStarting = false; |
|
m_bScrolling = false; |
|
m_ScrollCt = 0; |
|
m_ScrollSpeed = 0.f; |
|
m_ButtonPressed = SCROLL_NONE; |
|
m_ScrollDirection = SCROLL_NONE; |
|
m_pCommentaryLabel = NULL; |
|
|
|
m_iBonusSelection = 0; |
|
m_bScrollToFirstBonusMap = false; |
|
|
|
SetTitle("#GameUI_NewGame", true); |
|
|
|
m_pNextButton = new Button( this, "Next", "#gameui_next" ); |
|
m_pPrevButton = new Button( this, "Prev", "#gameui_prev" ); |
|
m_pPlayButton = new CNewGamePlayButton( this, "Play", "#GameUI_Play" ); |
|
m_pPlayButton->SetCommand( "Play" ); |
|
|
|
vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" ); |
|
cancel->SetCommand( "Close" ); |
|
|
|
m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) ); |
|
m_pCenterBg->SetVisible( false ); |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
m_pNextButton->SetVisible( false ); |
|
m_pPrevButton->SetVisible( false ); |
|
m_pPlayButton->SetVisible( false ); |
|
cancel->SetVisible( false ); |
|
|
|
m_pCenterBg->SetPaintBackgroundType( 2 ); |
|
m_pCenterBg->SetVisible( true ); |
|
|
|
m_pChapterTitleLabels[0] = SETUP_PANEL( new Label( this, "ChapterTitleLabel", "" ) ); |
|
m_pChapterTitleLabels[0]->SetVisible( true ); |
|
m_pChapterTitleLabels[0]->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
|
|
m_pChapterTitleLabels[1] = SETUP_PANEL( new Label( this, "ChapterTitleLabel2", "" ) ); |
|
m_pChapterTitleLabels[1]->SetVisible( true ); |
|
m_pChapterTitleLabels[1]->SetAlpha( 0 ); |
|
m_pChapterTitleLabels[1]->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
|
|
m_pBonusSelection = SETUP_PANEL( new Label( this, "BonusSelectionLabel", "#GameUI_BonusMapsStandard" ) ); |
|
m_pBonusSelectionBorder = SETUP_PANEL( new ImagePanel( this, "BonusSelectionBorder" ) ); |
|
|
|
m_pFooter = new CFooterPanel( parent, "NewGameFooter" ); |
|
m_pFooter->AddNewButtonLabel( "#GameUI_Play", "#GameUI_Icons_A_BUTTON" ); |
|
m_pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" ); |
|
} |
|
else |
|
{ |
|
m_pFooter = NULL; |
|
} |
|
|
|
// parse out the chapters off disk |
|
static const int MAX_CHAPTERS = 32; |
|
chapter_t chapters[MAX_CHAPTERS]; |
|
|
|
char szFullFileName[MAX_PATH]; |
|
int chapterIndex = 0; |
|
|
|
if ( IsPC() || !IsX360() ) |
|
{ |
|
FileFindHandle_t findHandle = FILESYSTEM_INVALID_FIND_HANDLE; |
|
const char *fileName = "cfg/chapter*.cfg"; |
|
fileName = g_pFullFileSystem->FindFirst( fileName, &findHandle ); |
|
while ( fileName && chapterIndex < MAX_CHAPTERS ) |
|
{ |
|
if ( fileName[0] ) |
|
{ |
|
// Only load chapter configs from the current mod's cfg dir |
|
// or else chapters appear that we don't want! |
|
Q_snprintf( szFullFileName, sizeof(szFullFileName), "cfg/%s", fileName ); |
|
FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" ); |
|
if ( f ) |
|
{ |
|
// don't load chapter files that are empty, used in the demo |
|
if ( g_pFullFileSystem->Size(f) > 0 ) |
|
{ |
|
Q_strncpy(chapters[chapterIndex].filename, fileName, sizeof(chapters[chapterIndex].filename)); |
|
++chapterIndex; |
|
} |
|
g_pFullFileSystem->Close( f ); |
|
} |
|
} |
|
fileName = g_pFullFileSystem->FindNext(findHandle); |
|
} |
|
} |
|
else if ( IsX360() ) |
|
{ |
|
int ChapterStringIndex = 0; |
|
bool bExists = true; |
|
while ( bExists && chapterIndex < MAX_CHAPTERS ) |
|
{ |
|
Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter%d.cfg", ChapterStringIndex+1 ); |
|
|
|
FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" ); |
|
if ( f ) |
|
{ |
|
Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename)); |
|
++chapterIndex; |
|
++ChapterStringIndex; |
|
g_pFullFileSystem->Close( f ); |
|
} |
|
else |
|
{ |
|
bExists = false; |
|
} |
|
//Hack to account for xbox360 missing chapter9a |
|
if ( ChapterStringIndex == 10 ) |
|
{ |
|
Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter9a.cfg" ); |
|
FileHandle_t fChap = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" ); |
|
if ( fChap ) |
|
{ |
|
Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename)); |
|
++chapterIndex; |
|
g_pFullFileSystem->Close( fChap ); |
|
} |
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
bool bBonusesUnlocked = false; |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
if ( !m_bCommentaryMode ) |
|
{ |
|
// Scan to see if the bonus maps have been unlocked |
|
bBonusesUnlocked = BonusMapsDatabase()->BonusesUnlocked(); |
|
} |
|
} |
|
|
|
// sort the chapters |
|
qsort(chapters, chapterIndex, sizeof(chapter_t), &ChapterSortFunc); |
|
|
|
// work out which chapters are unlocked |
|
ConVarRef var( "sv_unlockedchapters" ); |
|
|
|
if ( bBonusesUnlocked ) |
|
{ |
|
// Bonuses are unlocked so we need to unlock all the chapters too |
|
var.SetValue( 15 ); |
|
} |
|
|
|
const char *unlockedChapter = var.IsValid() ? var.GetString() : "1"; |
|
int iUnlockedChapter = atoi(unlockedChapter); |
|
|
|
// add chapters to combobox |
|
for (int i = 0; i < chapterIndex; i++) |
|
{ |
|
const char *fileName = chapters[i].filename; |
|
char chapterID[32] = { 0 }; |
|
sscanf(fileName, "chapter%s", chapterID); |
|
// strip the extension |
|
char *ext = V_stristr(chapterID, ".cfg"); |
|
if (ext) |
|
{ |
|
*ext = 0; |
|
} |
|
|
|
const char *pGameDir = COM_GetModDirectory(); |
|
|
|
char chapterName[64]; |
|
Q_snprintf(chapterName, sizeof(chapterName), "#%s_Chapter%s_Title", pGameDir, chapterID); |
|
|
|
Q_snprintf( szFullFileName, sizeof( szFullFileName ), "%s", fileName ); |
|
CGameChapterPanel *chapterPanel = SETUP_PANEL( new CGameChapterPanel( this, NULL, chapterName, i, chapterID, szFullFileName, m_bCommentaryMode ) ); |
|
chapterPanel->SetVisible( false ); |
|
|
|
UpdatePanelLockedStatus( iUnlockedChapter, i + 1, chapterPanel ); |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
if ( bBonusesUnlocked ) |
|
{ |
|
// check to see if it has associated challenges |
|
for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap ) |
|
{ |
|
BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap ); |
|
if ( Q_stricmp( pMap->szChapterName, szFullFileName ) == 0 && !pMap->bLocked ) |
|
{ |
|
chapterPanel->m_bHasBonus = true; |
|
chapterPanel->SetControlVisible( "HasBonusLabel", true ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
m_ChapterPanels.AddToTail( chapterPanel ); |
|
} |
|
|
|
KeyValues *pKeys = NULL; |
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameDialog.res" ); |
|
} |
|
LoadControlSettings( "Resource/NewGameDialog.res", NULL, pKeys ); |
|
|
|
// Reset all properties |
|
for ( int i = 0; i < NUM_SLOTS; ++i ) |
|
{ |
|
m_PanelIndex[i] = INVALID_INDEX; |
|
} |
|
|
|
if ( !m_ChapterPanels.Count() ) |
|
{ |
|
UpdateMenuComponents( SCROLL_NONE ); |
|
return; |
|
} |
|
|
|
int indent = 8; |
|
if ( IsProportional() ) |
|
{ |
|
indent = scheme()->GetProportionalScaledValueEx( GetScheme(), indent ); |
|
} |
|
|
|
int wide = 16; |
|
if ( IsProportional() ) |
|
{ |
|
wide = scheme()->GetProportionalScaledValueEx( GetScheme(), wide ); |
|
} |
|
|
|
// Layout panel positions relative to the dialog center. |
|
int panelWidth = m_ChapterPanels[0]->GetWide() + wide; |
|
int dialogWidth = GetWide(); |
|
|
|
m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + indent; |
|
|
|
if (m_ChapterPanels.Count() > 1) |
|
{ |
|
m_PanelXPos[1] = m_PanelXPos[2] - panelWidth; |
|
m_PanelXPos[0] = m_PanelXPos[1]; |
|
m_PanelXPos[3] = m_PanelXPos[2] + panelWidth; |
|
m_PanelXPos[4] = m_PanelXPos[3]; |
|
} |
|
else |
|
{ |
|
m_PanelXPos[0] = m_PanelXPos[1] = m_PanelXPos[3] = |
|
m_PanelXPos[4] = m_PanelXPos[2]; |
|
} |
|
|
|
|
|
m_PanelAlpha[0] = 0; |
|
m_PanelAlpha[1] = 255; |
|
m_PanelAlpha[2] = 255; |
|
m_PanelAlpha[3] = 255; |
|
m_PanelAlpha[4] = 0; |
|
|
|
int panelHeight; |
|
m_ChapterPanels[0]->GetSize( panelWidth, panelHeight ); |
|
m_pCenterBg->SetWide( panelWidth + wide); |
|
m_pCenterBg->SetPos( m_PanelXPos[2] - indent, m_PanelYPos[2] - (m_pCenterBg->GetTall() - panelHeight) + indent ); |
|
m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) ); |
|
|
|
// start the first item selected |
|
SetSelectedChapterIndex( 0 ); |
|
} |
|
|
|
CNewGameDialog::~CNewGameDialog() |
|
{ |
|
delete m_pFooter; |
|
m_pFooter = NULL; |
|
} |
|
|
|
void CNewGameDialog::Activate( void ) |
|
{ |
|
m_bMapStarting = false; |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
// Stop blinking the menu item now that we've seen the unlocked stuff |
|
CBasePanel *pBasePanel = BasePanel(); |
|
if ( pBasePanel ) |
|
pBasePanel->SetMenuItemBlinkingState( "OpenNewGameDialog", false ); |
|
|
|
BonusMapsDatabase()->SetBlink( false ); |
|
} |
|
|
|
// Commentary stuff is set up on activate because in XBox the new game menu is never deleted |
|
SetTitle( ( ( m_bCommentaryMode ) ? ( "#GameUI_LoadCommentary" ) : ( "#GameUI_NewGame") ), true); |
|
|
|
if ( m_pCommentaryLabel ) |
|
m_pCommentaryLabel->SetVisible( m_bCommentaryMode ); |
|
|
|
// work out which chapters are unlocked |
|
ConVarRef var( "sv_unlockedchapters" ); |
|
const char *unlockedChapter = var.IsValid() ? var.GetString() : "1"; |
|
int iUnlockedChapter = atoi(unlockedChapter); |
|
|
|
for ( int i = 0; i < m_ChapterPanels.Count(); i++) |
|
{ |
|
CGameChapterPanel *pChapterPanel = m_ChapterPanels[ i ]; |
|
|
|
if ( pChapterPanel ) |
|
{ |
|
pChapterPanel->SetCommentaryMode( m_bCommentaryMode ); |
|
|
|
UpdatePanelLockedStatus( iUnlockedChapter, i + 1, pChapterPanel ); |
|
} |
|
} |
|
|
|
BaseClass::Activate(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Apply special properties of the menu |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::ApplySettings( KeyValues *inResourceData ) |
|
{ |
|
BaseClass::ApplySettings( inResourceData ); |
|
|
|
int ypos = inResourceData->GetInt( "chapterypos", 40 ); |
|
if ( IsProportional() ) |
|
{ |
|
ypos = scheme()->GetProportionalScaledValueEx( GetScheme(), ypos ); |
|
} |
|
|
|
for ( int i = 0; i < NUM_SLOTS; ++i ) |
|
{ |
|
m_PanelYPos[i] = ypos; |
|
} |
|
|
|
m_pCenterBg->SetTall( inResourceData->GetInt( "centerbgtall", 0 ) ); |
|
|
|
g_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f ); |
|
g_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f ); |
|
SetFastScroll( false ); |
|
} |
|
|
|
void CNewGameDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
if ( m_pFooter ) |
|
{ |
|
KeyValues *pFooterControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameFooter.res" ); |
|
m_pFooter->LoadControlSettings( "null", NULL, pFooterControlSettings ); |
|
} |
|
|
|
UpdateMenuComponents( SCROLL_NONE ); |
|
|
|
m_pCommentaryLabel = dynamic_cast<vgui::Label*>( FindChildByName( "CommentaryUnlock" ) ); |
|
if ( m_pCommentaryLabel ) |
|
m_pCommentaryLabel->SetVisible( m_bCommentaryMode ); |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
if ( !m_bCommentaryMode && BonusMapsDatabase()->BonusesUnlocked() && !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() ) |
|
{ |
|
// Find the first bonus |
|
ScrollSelectionPanels( SCROLL_LEFT ); |
|
m_bScrollToFirstBonusMap = true; |
|
} |
|
} |
|
} |
|
|
|
static float GetArrowAlpha( void ) |
|
{ |
|
// X360TBD: Pulsing arrows |
|
return 255.f; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets the correct properties for visible components |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::UpdateMenuComponents( EScrollDirection dir ) |
|
{ |
|
// This is called prior to any scrolling, |
|
// so we need to look ahead to the post-scroll state |
|
int centerIdx = SLOT_CENTER; |
|
if ( dir == SCROLL_LEFT ) |
|
{ |
|
++centerIdx; |
|
} |
|
else if ( dir == SCROLL_RIGHT ) |
|
{ |
|
--centerIdx; |
|
} |
|
int leftIdx = centerIdx - 1; |
|
int rightIdx = centerIdx + 1; |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
bool bHasBonus = false; |
|
if ( m_PanelIndex[centerIdx] != INVALID_INDEX ) |
|
{ |
|
wchar_t buffer[ MAX_PATH ]; |
|
m_ChapterPanels[ m_PanelIndex[centerIdx] ]->m_pChapterNameLabel->GetText( buffer, sizeof(buffer) ); |
|
m_pChapterTitleLabels[(unsigned)m_ActiveTitleIdx]->SetText( buffer ); |
|
|
|
// If it has bonuses show the scroll up and down arrows |
|
bHasBonus = m_ChapterPanels[ m_PanelIndex[centerIdx] ]->HasBonus(); |
|
} |
|
|
|
vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" ); |
|
vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" ); |
|
if ( leftArrow ) |
|
{ |
|
if ( m_PanelIndex[leftIdx] != INVALID_INDEX ) |
|
{ |
|
leftArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) ); |
|
} |
|
else |
|
{ |
|
leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) ); |
|
} |
|
} |
|
if ( rightArrow ) |
|
{ |
|
if ( m_PanelIndex[rightIdx] != INVALID_INDEX ) |
|
{ |
|
rightArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) ); |
|
} |
|
else |
|
{ |
|
rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) ); |
|
} |
|
} |
|
|
|
if ( bHasBonus ) |
|
{ |
|
// Find the bonus description for this panel |
|
for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus ) |
|
{ |
|
m_pBonusMapDescription = BonusMapsDatabase()->GetBonusData( iBonus ); |
|
if ( Q_stricmp( m_pBonusMapDescription->szChapterName, m_ChapterPanels[ m_PanelIndex[centerIdx] ]->GetConfigFile() ) == 0 ) |
|
break; |
|
} |
|
} |
|
else |
|
{ |
|
m_pBonusMapDescription = NULL; |
|
} |
|
|
|
vgui::Panel *upArrow = this->FindChildByName( "UpArrow" ); |
|
vgui::Panel *downArrow = this->FindChildByName( "DownArrow" ); |
|
|
|
if ( upArrow ) |
|
upArrow->SetVisible( bHasBonus ); |
|
if ( downArrow ) |
|
downArrow->SetVisible( bHasBonus ); |
|
|
|
m_pBonusSelection->SetVisible( bHasBonus ); |
|
m_pBonusSelectionBorder->SetVisible( bHasBonus ); |
|
|
|
UpdateBonusSelection(); |
|
} |
|
|
|
// No buttons in the xbox ui |
|
if ( !GameUI().IsConsoleUI() ) |
|
{ |
|
if ( m_PanelIndex[leftIdx] == INVALID_INDEX || m_PanelIndex[leftIdx] == 0 ) |
|
{ |
|
m_pPrevButton->SetVisible( false ); |
|
m_pPrevButton->SetEnabled( false ); |
|
} |
|
else |
|
{ |
|
m_pPrevButton->SetVisible( true ); |
|
m_pPrevButton->SetEnabled( true ); |
|
} |
|
|
|
if ( m_ChapterPanels.Count() < 4 ) // if there are less than 4 chapters show the next button but disabled |
|
{ |
|
m_pNextButton->SetVisible( true ); |
|
m_pNextButton->SetEnabled( false ); |
|
} |
|
else if ( m_PanelIndex[rightIdx] == INVALID_INDEX || m_PanelIndex[rightIdx] == m_ChapterPanels.Count()-1 ) |
|
{ |
|
m_pNextButton->SetVisible( false ); |
|
m_pNextButton->SetEnabled( false ); |
|
} |
|
else |
|
{ |
|
m_pNextButton->SetVisible( true ); |
|
m_pNextButton->SetEnabled( true ); |
|
} |
|
} |
|
} |
|
|
|
void CNewGameDialog::UpdateBonusSelection( void ) |
|
{ |
|
int iNumChallenges = 0; |
|
if ( m_pBonusMapDescription ) |
|
{ |
|
if ( m_pBonusMapDescription->m_pChallenges ) |
|
iNumChallenges = m_pBonusMapDescription->m_pChallenges->Count(); |
|
|
|
// Wrap challenge selection to fit number of possible selections |
|
if ( m_iBonusSelection < 0 ) |
|
m_iBonusSelection = iNumChallenges + 1; |
|
else if ( m_iBonusSelection >= iNumChallenges + 2 ) |
|
m_iBonusSelection = 0; |
|
} |
|
else |
|
{ |
|
// No medals to show |
|
SetControlVisible( "ChallengeEarnedMedal", false ); |
|
SetControlVisible( "ChallengeBestLabel", false ); |
|
SetControlVisible( "ChallengeNextMedal", false ); |
|
SetControlVisible( "ChallengeNextLabel", false ); |
|
return; |
|
} |
|
|
|
if ( m_iBonusSelection == 0 ) |
|
{ |
|
m_pBonusSelection->SetText( "#GameUI_BonusMapsStandard" ); |
|
SetControlVisible( "ChallengeEarnedMedal", false ); |
|
SetControlVisible( "ChallengeBestLabel", false ); |
|
SetControlVisible( "ChallengeNextMedal", false ); |
|
SetControlVisible( "ChallengeNextLabel", false ); |
|
} |
|
else if ( m_iBonusSelection == 1 ) |
|
{ |
|
m_pBonusSelection->SetText( "#GameUI_BonusMapsAdvanced" ); |
|
SetControlVisible( "ChallengeEarnedMedal", false ); |
|
SetControlVisible( "ChallengeBestLabel", false ); |
|
SetControlVisible( "ChallengeNextMedal", false ); |
|
SetControlVisible( "ChallengeNextLabel", false ); |
|
|
|
char szMapAdvancedName[ 256 ] = ""; |
|
if ( m_pBonusMapDescription ) |
|
{ |
|
Q_snprintf( szMapAdvancedName, sizeof( szMapAdvancedName ), "%s_advanced", m_pBonusMapDescription->szMapFileName ); |
|
} |
|
|
|
BonusMapDescription_t *pAdvancedDescription = NULL; |
|
|
|
// Find the bonus description for this panel |
|
for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus ) |
|
{ |
|
pAdvancedDescription = BonusMapsDatabase()->GetBonusData( iBonus ); |
|
if ( Q_stricmp( szMapAdvancedName, pAdvancedDescription->szMapFileName ) == 0 ) |
|
break; |
|
} |
|
|
|
if ( pAdvancedDescription && pAdvancedDescription->bComplete ) |
|
{ |
|
CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) ); |
|
pBitmap->SetVisible( true ); |
|
pBitmap->setTexture( "hud/icon_complete" ); |
|
} |
|
} |
|
else |
|
{ |
|
int iChallenge = m_iBonusSelection - 2; |
|
ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge ]); |
|
|
|
// Set the display text for the selected challenge |
|
m_pBonusSelection->SetText( pChallengeDescription->szName ); |
|
|
|
int iBest, iEarnedMedal, iNext, iNextMedal; |
|
GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal ); |
|
|
|
char szBuff[ 512 ]; |
|
|
|
// Set earned medal |
|
if ( iEarnedMedal > -1 && iBest != -1 ) |
|
{ |
|
if ( iChallenge < 10 ) |
|
Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] ); |
|
else |
|
Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] ); |
|
|
|
CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) ); |
|
pBitmap->SetVisible( true ); |
|
pBitmap->setTexture( szBuff ); |
|
} |
|
else |
|
{ |
|
CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) ); |
|
pBitmap->SetVisible( false ); |
|
} |
|
|
|
// Set next medal |
|
if ( iNextMedal > 0 ) |
|
{ |
|
if ( iChallenge < 10 ) |
|
Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] ); |
|
else |
|
Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] ); |
|
|
|
CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeNextMedal" ) ); |
|
pBitmap->SetVisible( true ); |
|
pBitmap->setTexture( szBuff ); |
|
} |
|
else |
|
{ |
|
SetControlVisible( "ChallengeNextMedal", false ); |
|
} |
|
|
|
wchar_t szWideBuff[ 64 ]; |
|
wchar_t szWideBuff2[ 64 ]; |
|
|
|
// Best label |
|
if ( iBest != -1 ) |
|
{ |
|
Q_snprintf( szBuff, sizeof( szBuff ), "%i", iBest ); |
|
g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) ); |
|
g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsBest" ), 1, szWideBuff2 ); |
|
g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) ); |
|
|
|
SetControlString( "ChallengeBestLabel", szBuff ); |
|
SetControlVisible( "ChallengeBestLabel", true ); |
|
} |
|
else |
|
{ |
|
SetControlVisible( "ChallengeBestLabel", false ); |
|
} |
|
|
|
// Next label |
|
if ( iNext != -1 ) |
|
{ |
|
Q_snprintf( szBuff, sizeof( szBuff ), "%i", iNext ); |
|
g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) ); |
|
g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsGoal" ), 1, szWideBuff2 ); |
|
g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) ); |
|
|
|
SetControlString( "ChallengeNextLabel", szBuff ); |
|
SetControlVisible( "ChallengeNextLabel", true ); |
|
} |
|
else |
|
{ |
|
SetControlVisible( "ChallengeNextLabel", false ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets a chapter as selected |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::SetSelectedChapterIndex( int index ) |
|
{ |
|
m_iSelectedChapter = index; |
|
|
|
for (int i = 0; i < m_ChapterPanels.Count(); i++) |
|
{ |
|
if ( i == index ) |
|
{ |
|
m_ChapterPanels[i]->SetSelected( true ); |
|
} |
|
else |
|
{ |
|
m_ChapterPanels[i]->SetSelected( false ); |
|
} |
|
} |
|
|
|
if ( m_pPlayButton ) |
|
{ |
|
m_pPlayButton->SetEnabled( true ); |
|
} |
|
|
|
// Setup panels to the left of the selected panel |
|
int selectedSlot = GameUI().IsConsoleUI() ? SLOT_CENTER : index % 3 + 1; |
|
int currIdx = index; |
|
for ( int i = selectedSlot; i >= 0 && currIdx >= 0; --i ) |
|
{ |
|
m_PanelIndex[i] = currIdx; |
|
--currIdx; |
|
InitPanelIndexForDisplay( i ); |
|
} |
|
|
|
// Setup panels to the right of the selected panel |
|
currIdx = index + 1; |
|
for ( int i = selectedSlot + 1; i < NUM_SLOTS && currIdx < m_ChapterPanels.Count(); ++i ) |
|
{ |
|
m_PanelIndex[i] = currIdx; |
|
++currIdx; |
|
InitPanelIndexForDisplay( i ); |
|
} |
|
|
|
UpdateMenuComponents( SCROLL_NONE ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets a chapter as selected |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::SetSelectedChapter( const char *chapter ) |
|
{ |
|
Assert( chapter ); |
|
for (int i = 0; i < m_ChapterPanels.Count(); i++) |
|
{ |
|
if ( chapter && !Q_stricmp(m_ChapterPanels[i]->GetChapter(), chapter) ) |
|
{ |
|
m_iSelectedChapter = i; |
|
m_ChapterPanels[m_iSelectedChapter]->SetSelected( true ); |
|
} |
|
else |
|
{ |
|
m_ChapterPanels[i]->SetSelected( false ); |
|
} |
|
} |
|
|
|
if ( m_pPlayButton ) |
|
{ |
|
m_pPlayButton->SetEnabled( true ); |
|
} |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// iUnlockedChapter - the value of sv_unlockedchapters, 1-based. A value of 0 |
|
// is treated as a 1, since at least one chapter must be unlocked. |
|
// |
|
// i - the 1-based index of the chapter we're considering. |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::UpdatePanelLockedStatus( int iUnlockedChapter, int i, CGameChapterPanel *pChapterPanel ) |
|
{ |
|
if ( iUnlockedChapter <= 0 ) |
|
{ |
|
iUnlockedChapter = 1; |
|
} |
|
|
|
// Commentary mode requires chapters to be finished before they can be chosen |
|
bool bLocked = false; |
|
|
|
if ( m_bCommentaryMode ) |
|
{ |
|
bLocked = ( iUnlockedChapter <= i ); |
|
} |
|
else |
|
{ |
|
if ( iUnlockedChapter < i ) |
|
{ |
|
// Never lock the first chapter |
|
bLocked = ( i != 0 ); |
|
} |
|
} |
|
|
|
pChapterPanel->SetEnabled( !bLocked ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called before a panel scroll starts. |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::PreScroll( EScrollDirection dir ) |
|
{ |
|
int hideIdx = INVALID_INDEX; |
|
if ( dir == SCROLL_LEFT ) |
|
{ |
|
hideIdx = m_PanelIndex[SLOT_LEFT]; |
|
} |
|
else if ( dir == SCROLL_RIGHT ) |
|
{ |
|
hideIdx = m_PanelIndex[SLOT_RIGHT]; |
|
} |
|
if ( hideIdx != INVALID_INDEX ) |
|
{ |
|
// Push back the panel that's about to be hidden |
|
// so the next panel scrolls over the top of it. |
|
m_ChapterPanels[hideIdx]->SetZPos( 0 ); |
|
} |
|
|
|
// Flip the active title label prior to the crossfade |
|
m_ActiveTitleIdx ^= 0x01; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called after a panel scroll finishes. |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::PostScroll( EScrollDirection dir ) |
|
{ |
|
int index = INVALID_INDEX; |
|
if ( dir == SCROLL_LEFT ) |
|
{ |
|
index = m_PanelIndex[SLOT_RIGHT]; |
|
} |
|
else if ( dir == SCROLL_RIGHT ) |
|
{ |
|
index = m_PanelIndex[SLOT_LEFT]; |
|
} |
|
|
|
// Fade in the revealed panel |
|
if ( index != INVALID_INDEX ) |
|
{ |
|
CGameChapterPanel *panel = m_ChapterPanels[index]; |
|
panel->SetZPos( 50 ); |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
} |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
if ( BonusMapsDatabase()->BonusesUnlocked() && m_bScrollToFirstBonusMap ) |
|
{ |
|
if ( !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() ) |
|
{ |
|
// Find the first bonus |
|
ScrollSelectionPanels( SCROLL_LEFT ); |
|
} |
|
else |
|
{ |
|
// Found a bonus, stop scrolling |
|
m_bScrollToFirstBonusMap = false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initiates a panel scroll and starts the animation. |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::ScrollSelectionPanels( EScrollDirection dir ) |
|
{ |
|
// Only initiate a scroll if panels aren't currently scrolling |
|
if ( !m_bScrolling ) |
|
{ |
|
// Handle any pre-scroll setup |
|
PreScroll( dir ); |
|
|
|
if ( dir == SCROLL_LEFT) |
|
{ |
|
m_ScrollCt += SCROLL_LEFT; |
|
} |
|
else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 ) |
|
{ |
|
m_ScrollCt += SCROLL_RIGHT; |
|
} |
|
|
|
m_bScrolling = true; |
|
AnimateSelectionPanels(); |
|
|
|
// Update the arrow colors, help text, and buttons. Doing it here looks better than having |
|
// the components change after the entire scroll animation has finished. |
|
UpdateMenuComponents( m_ScrollDirection ); |
|
} |
|
} |
|
|
|
void CNewGameDialog::ScrollBonusSelection( EScrollDirection dir ) |
|
{ |
|
// Don't scroll if there's no bonuses for this panel |
|
if ( !m_pBonusMapDescription ) |
|
return; |
|
|
|
m_iBonusSelection += dir; |
|
|
|
vgui::surface()->PlaySound( "UI/buttonclick.wav" ); |
|
|
|
UpdateBonusSelection(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initiates the scripted scroll and fade effects of all five slotted panels |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::AnimateSelectionPanels( void ) |
|
{ |
|
int idxOffset = 0; |
|
int startIdx = SLOT_LEFT; |
|
int endIdx = SLOT_RIGHT; |
|
|
|
// Don't scroll outside the bounds of the panel list |
|
if ( m_ScrollCt >= SCROLL_LEFT && (m_PanelIndex[SLOT_CENTER] < m_ChapterPanels.Count() - 1 || !GameUI().IsConsoleUI()) ) |
|
{ |
|
idxOffset = -1; |
|
endIdx = SLOT_OFFRIGHT; |
|
m_ScrollDirection = SCROLL_LEFT; |
|
} |
|
else if ( m_ScrollCt <= SCROLL_RIGHT && (m_PanelIndex[SLOT_CENTER] > 0 || !GameUI().IsConsoleUI()) ) |
|
{ |
|
idxOffset = 1; |
|
startIdx = SLOT_OFFLEFT; |
|
m_ScrollDirection = SCROLL_RIGHT; |
|
} |
|
|
|
if ( 0 == idxOffset ) |
|
{ |
|
// Kill the scroll, it's outside the bounds |
|
m_ScrollCt = 0; |
|
m_bScrolling = false; |
|
m_ScrollDirection = SCROLL_NONE; |
|
vgui::surface()->PlaySound( "player/suit_denydevice.wav" ); |
|
return; |
|
} |
|
|
|
// Should never happen |
|
if ( startIdx > endIdx ) |
|
return; |
|
|
|
for ( int i = startIdx; i <= endIdx; ++i ) |
|
{ |
|
if ( m_PanelIndex[i] != INVALID_INDEX ) |
|
{ |
|
int nextIdx = i + idxOffset; |
|
CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[i] ]; |
|
GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
} |
|
} |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
vgui::surface()->PlaySound( "UI/buttonclick.wav" ); |
|
|
|
// Animate the center background panel |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
|
|
// Crossfade the chapter title labels |
|
int inactiveTitleIdx = m_ActiveTitleIdx ^ 0x01; |
|
GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[(unsigned)m_ActiveTitleIdx], "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[inactiveTitleIdx], "alpha", 0, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
|
|
// Scrolling up through chapters, offset is negative |
|
m_iSelectedChapter -= idxOffset; |
|
} |
|
|
|
PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: After a scroll, each panel slot holds the index of a panel that has |
|
// scrolled to an adjacent slot. This function updates each slot so |
|
// it holds the index of the panel that is actually in that slot's position. |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::ShiftPanelIndices( int offset ) |
|
{ |
|
// Shift all the elements over one slot, then calculate what the last slot's index should be. |
|
int lastSlot = NUM_SLOTS - 1; |
|
if ( offset > 0 ) |
|
{ |
|
// Hide the panel that's dropping out of the slots |
|
if ( IsValidPanel( m_PanelIndex[0] ) ) |
|
{ |
|
m_ChapterPanels[ m_PanelIndex[0] ]->SetVisible( false ); |
|
} |
|
|
|
// Scrolled panels to the right, so shift the indices one slot to the left |
|
Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) ); |
|
if ( m_PanelIndex[lastSlot] != INVALID_INDEX ) |
|
{ |
|
int num = m_PanelIndex[ lastSlot ] + 1; |
|
if ( IsValidPanel( num ) ) |
|
{ |
|
m_PanelIndex[lastSlot] = num; |
|
InitPanelIndexForDisplay( lastSlot ); |
|
} |
|
else |
|
{ |
|
m_PanelIndex[lastSlot] = INVALID_INDEX; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// Hide the panel that's dropping out of the slots |
|
if ( IsValidPanel( m_PanelIndex[lastSlot] ) ) |
|
{ |
|
m_ChapterPanels[ m_PanelIndex[lastSlot] ]->SetVisible( false ); |
|
} |
|
|
|
// Scrolled panels to the left, so shift the indices one slot to the right |
|
Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) ); |
|
if ( m_PanelIndex[0] != INVALID_INDEX ) |
|
{ |
|
int num = m_PanelIndex[0] - 1; |
|
if ( IsValidPanel( num ) ) |
|
{ |
|
m_PanelIndex[0] = num; |
|
InitPanelIndexForDisplay( 0 ); |
|
} |
|
else |
|
{ |
|
m_PanelIndex[0] = INVALID_INDEX; |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Validates an index into the selection panels vector |
|
//----------------------------------------------------------------------------- |
|
bool CNewGameDialog::IsValidPanel( const int idx ) |
|
{ |
|
if ( idx < 0 || idx >= m_ChapterPanels.Count() ) |
|
return false; |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets up a panel's properties before it is displayed |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::InitPanelIndexForDisplay( const int idx ) |
|
{ |
|
CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[idx] ]; |
|
if ( panel ) |
|
{ |
|
panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] ); |
|
panel->SetAlpha( m_PanelAlpha[idx] ); |
|
panel->SetVisible( true ); |
|
if ( m_PanelAlpha[idx] ) |
|
{ |
|
panel->SetZPos( 50 ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets which scroll speed should be used |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::SetFastScroll( bool fast ) |
|
{ |
|
m_ScrollSpeed = fast ? g_ScrollSpeedFast : g_ScrollSpeedSlow; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Checks if a button is being held down, and speeds up the scroll |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::ContinueScrolling( void ) |
|
{ |
|
if ( !GameUI().IsConsoleUI() ) |
|
{ |
|
if ( m_PanelIndex[SLOT_CENTER-1] % 3 ) |
|
{ |
|
// m_ButtonPressed = m_ScrollDirection; |
|
ScrollSelectionPanels( m_ScrollDirection ); |
|
} |
|
return; |
|
} |
|
|
|
if ( m_ButtonPressed == m_ScrollDirection ) |
|
{ |
|
SetFastScroll( true ); |
|
ScrollSelectionPanels( m_ScrollDirection ); |
|
} |
|
else if ( m_ButtonPressed != SCROLL_NONE ) |
|
{ |
|
// The other direction has been pressed - start a slow scroll |
|
SetFastScroll( false ); |
|
ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed ); |
|
} |
|
else |
|
{ |
|
SetFastScroll( false ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when a scroll distance of one slot has been completed |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::FinishScroll( void ) |
|
{ |
|
// Fade the center bg panel back in |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
|
|
ShiftPanelIndices( m_ScrollDirection ); |
|
m_bScrolling = false; |
|
m_ScrollCt = 0; |
|
|
|
// End of scroll step |
|
PostScroll( m_ScrollDirection ); |
|
|
|
// Continue scrolling if necessary |
|
ContinueScrolling(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: starts the game at the specified skill level |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::StartGame( void ) |
|
{ |
|
if ( m_ChapterPanels.IsValidIndex( m_iSelectedChapter ) ) |
|
{ |
|
char mapcommand[512]; |
|
mapcommand[0] = 0; |
|
Q_snprintf( mapcommand, sizeof( mapcommand ), "disconnect\ndeathmatch 0\nprogress_enable\nexec %s\n", m_ChapterPanels[m_iSelectedChapter]->GetConfigFile() ); |
|
|
|
// Set commentary |
|
ConVarRef commentary( "commentary" ); |
|
commentary.SetValue( m_bCommentaryMode ); |
|
|
|
ConVarRef sv_cheats( "sv_cheats" ); |
|
sv_cheats.SetValue( m_bCommentaryMode ); |
|
|
|
if ( IsPC() ) |
|
{ |
|
// If commentary is on, we go to the explanation dialog (but not for teaser trailers) |
|
if ( m_bCommentaryMode && !m_ChapterPanels[m_iSelectedChapter]->IsTeaserChapter() ) |
|
{ |
|
// Check our current state and disconnect us from any multiplayer server we're connected to. |
|
// This fixes an exploit where players would click "start" on the commentary dialog to enable |
|
// sv_cheats on the client (via the code above) and then hit <esc> to get out of the explanation dialog. |
|
if ( GameUI().IsInMultiplayer() ) |
|
{ |
|
engine->ExecuteClientCmd( "disconnect" ); |
|
} |
|
|
|
DHANDLE<CCommentaryExplanationDialog> hCommentaryExplanationDialog; |
|
if ( !hCommentaryExplanationDialog.Get() ) |
|
{ |
|
hCommentaryExplanationDialog = new CCommentaryExplanationDialog( BasePanel(), mapcommand ); |
|
} |
|
hCommentaryExplanationDialog->Activate(); |
|
} |
|
else |
|
{ |
|
// start map |
|
BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand ); |
|
} |
|
} |
|
else if ( IsX360() ) |
|
{ |
|
if ( m_ChapterPanels[m_iSelectedChapter]->HasBonus() && m_iBonusSelection > 0 ) |
|
{ |
|
if ( m_iBonusSelection == 1 ) |
|
{ |
|
// Run the advanced chamber instead of the config file |
|
char *pLastSpace = Q_strrchr( mapcommand, '\n' ); |
|
pLastSpace[ 0 ] = '\0'; |
|
pLastSpace = Q_strrchr( mapcommand, '\n' ); |
|
|
|
Q_snprintf( pLastSpace, sizeof( mapcommand ) - Q_strlen( mapcommand ), "\nmap %s_advanced\n", m_pBonusMapDescription->szMapFileName ); |
|
} |
|
else |
|
{ |
|
char sz[ 256 ]; |
|
|
|
int iChallenge = m_iBonusSelection - 1; |
|
|
|
// Set up the challenge mode |
|
Q_snprintf( sz, sizeof( sz ), "sv_bonus_challenge %i\n", iChallenge ); |
|
engine->ClientCmd_Unrestricted( sz ); |
|
|
|
ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge - 1 ]); |
|
|
|
// Set up medal goals |
|
BonusMapsDatabase()->SetCurrentChallengeObjectives( pChallengeDescription->iBronze, pChallengeDescription->iSilver, pChallengeDescription->iGold ); |
|
BonusMapsDatabase()->SetCurrentChallengeNames( m_pBonusMapDescription->szFileName, m_pBonusMapDescription->szMapName, pChallengeDescription->szName ); |
|
} |
|
} |
|
|
|
m_bMapStarting = true; |
|
BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand ); |
|
} |
|
|
|
OnClose(); |
|
} |
|
} |
|
|
|
void CNewGameDialog::OnClose( void ) |
|
{ |
|
m_KeyRepeat.Reset(); |
|
|
|
if ( GameUI().IsConsoleUI() && !m_bMapStarting ) |
|
{ |
|
BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" ); |
|
BonusMapsDatabase()->WriteSaveData(); // Closing this dialog is a good time to save |
|
} |
|
BaseClass::OnClose(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: handles button commands |
|
//----------------------------------------------------------------------------- |
|
void CNewGameDialog::OnCommand( const char *command ) |
|
{ |
|
bool bReset = true; |
|
|
|
if ( !stricmp( command, "Play" ) ) |
|
{ |
|
if ( m_bMapStarting ) |
|
return; |
|
|
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
if ( m_ChapterPanels[m_iSelectedChapter]->IsEnabled() ) |
|
{ |
|
if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 ) |
|
{ |
|
vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" ); |
|
BasePanel()->ShowMessageDialog( MD_SAVE_BEFORE_NEW_GAME, this ); |
|
} |
|
else |
|
{ |
|
OnCommand( "StartNewGame" ); |
|
} |
|
} |
|
else |
|
{ |
|
// This chapter isn't unlocked! |
|
m_bMapStarting = false; |
|
vgui::surface()->PlaySound( "player/suit_denydevice.wav" ); |
|
|
|
if ( m_bCommentaryMode ) |
|
{ |
|
BasePanel()->ShowMessageDialog( MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION, this ); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
StartGame(); |
|
} |
|
} |
|
|
|
#ifdef _X360 |
|
else if ( !stricmp( command, "StartNewGame" ) ) |
|
{ |
|
ConVarRef commentary( "commentary" ); |
|
|
|
if ( m_bCommentaryMode && !commentary.GetBool() ) |
|
{ |
|
// Using the commentary menu, but not already in commentary mode, explain the rules |
|
PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithCommentaryExplanation" ), 0.2f ); |
|
} |
|
else |
|
{ |
|
if ( XBX_GetStorageDeviceId() == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId() == XBX_STORAGE_DECLINED || |
|
!ModInfo().IsSinglePlayerOnly() ) |
|
{ |
|
// Multiplayer or no storage device so don't bore them with autosave details |
|
m_bMapStarting = true; |
|
OnCommand( "StartNewGameNoCommentaryExplanation" ); |
|
} |
|
else |
|
{ |
|
// Don't allow other inputs |
|
m_bMapStarting = true; |
|
|
|
// Remind them how autosaves work |
|
PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithAutosaveExplanation" ), 0.2f ); |
|
} |
|
} |
|
} |
|
else if ( !stricmp( command, "StartNewGameWithAutosaveExplanation" ) ) |
|
{ |
|
BasePanel()->ShowMessageDialog( MD_AUTOSAVE_EXPLANATION, this ); |
|
} |
|
else if ( !stricmp( command, "StartNewGameWithCommentaryExplanation" ) ) |
|
{ |
|
if ( ModInfo().IsSinglePlayerOnly() ) |
|
{ |
|
// Don't allow other inputs |
|
m_bMapStarting = true; |
|
BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION, this ); |
|
} |
|
else |
|
{ |
|
// Don't allow other inputs |
|
m_bMapStarting = true; |
|
BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION_MULTI, this ); |
|
} |
|
} |
|
else if ( !stricmp( command, "StartNewGameNoCommentaryExplanation" ) ) |
|
{ |
|
vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" ); |
|
BasePanel()->RunAnimationWithCallback( this, "CloseNewGameDialog", new KeyValues( "StartGame" ) ); |
|
} |
|
#endif |
|
|
|
else if ( !stricmp( command, "Next" ) ) |
|
{ |
|
if ( m_bMapStarting ) |
|
return; |
|
|
|
ScrollSelectionPanels( SCROLL_LEFT ); |
|
bReset = false; |
|
} |
|
else if ( !stricmp( command, "Prev" ) ) |
|
{ |
|
if ( m_bMapStarting ) |
|
return; |
|
|
|
ScrollSelectionPanels( SCROLL_RIGHT ); |
|
bReset = false; |
|
} |
|
else if ( !stricmp( command, "Mode_Next" ) ) |
|
{ |
|
if ( m_bMapStarting ) |
|
return; |
|
|
|
ScrollBonusSelection( SCROLL_LEFT ); |
|
bReset = false; |
|
} |
|
else if ( !stricmp( command, "Mode_Prev" ) ) |
|
{ |
|
if ( m_bMapStarting ) |
|
return; |
|
|
|
ScrollBonusSelection( SCROLL_RIGHT ); |
|
bReset = false; |
|
} |
|
else if ( !Q_stricmp( command, "ReleaseModalWindow" ) ) |
|
{ |
|
vgui::surface()->RestrictPaintToSinglePanel(NULL); |
|
} |
|
else |
|
{ |
|
BaseClass::OnCommand( command ); |
|
} |
|
|
|
if ( bReset ) |
|
{ |
|
m_KeyRepeat.Reset(); |
|
} |
|
} |
|
|
|
void CNewGameDialog::PaintBackground() |
|
{ |
|
if ( !GameUI().IsConsoleUI() ) |
|
{ |
|
BaseClass::PaintBackground(); |
|
return; |
|
} |
|
|
|
int wide, tall; |
|
GetSize( wide, tall ); |
|
|
|
Color col = GetBgColor(); |
|
DrawBox( 0, 0, wide, tall, col, 1.0f ); |
|
|
|
int y = 0; |
|
if ( m_pChapterTitleLabels[0] ) |
|
{ |
|
// offset by title |
|
int titleX, titleY, titleWide, titleTall; |
|
m_pChapterTitleLabels[0]->GetBounds( titleX, titleY, titleWide, titleTall ); |
|
y += titleY + titleTall; |
|
} |
|
else |
|
{ |
|
y = 8; |
|
} |
|
|
|
// draw an inset |
|
Color darkColor; |
|
darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() ); |
|
vgui::surface()->DrawSetColor( darkColor ); |
|
vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 ); |
|
} |
|
|
|
void CNewGameDialog::OnKeyCodePressed( KeyCode code ) |
|
{ |
|
switch ( code ) |
|
{ |
|
case KEY_XBUTTON_LEFT: |
|
case KEY_XSTICK1_LEFT: |
|
case KEY_XSTICK2_LEFT: |
|
case KEY_LEFT: |
|
case STEAMCONTROLLER_DPAD_LEFT: |
|
if ( !m_bScrolling ) |
|
{ |
|
for ( int i = 0; i < m_ChapterPanels.Count(); ++i ) |
|
{ |
|
if ( m_ChapterPanels[ i ]->IsSelected() ) |
|
{ |
|
int nNewChapter = i - 1; |
|
if ( nNewChapter >= 0 ) |
|
{ |
|
if ( nNewChapter < m_PanelIndex[ SLOT_LEFT ] && m_PanelIndex[ SLOT_LEFT ] != -1 ) |
|
{ |
|
ScrollSelectionPanels( SCROLL_RIGHT ); |
|
} |
|
else if ( m_ChapterPanels[ nNewChapter ]->IsEnabled() ) |
|
{ |
|
SetSelectedChapterIndex( nNewChapter ); |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
return; |
|
|
|
case KEY_XBUTTON_RIGHT: |
|
case KEY_XSTICK1_RIGHT: |
|
case KEY_XSTICK2_RIGHT: |
|
case KEY_RIGHT: |
|
case STEAMCONTROLLER_DPAD_RIGHT: |
|
if ( !m_bScrolling ) |
|
{ |
|
for ( int i = 0; i < m_ChapterPanels.Count(); ++i ) |
|
{ |
|
if ( m_ChapterPanels[ i ]->IsSelected() ) |
|
{ |
|
int nNewChapter = i + 1; |
|
if ( nNewChapter < m_ChapterPanels.Count() ) |
|
{ |
|
if ( nNewChapter > m_PanelIndex[ SLOT_RIGHT ] && m_PanelIndex[ SLOT_RIGHT ] != -1 ) |
|
{ |
|
ScrollSelectionPanels( SCROLL_LEFT ); |
|
} |
|
else if ( m_ChapterPanels[ nNewChapter ]->IsEnabled() ) |
|
{ |
|
SetSelectedChapterIndex( nNewChapter ); |
|
} |
|
} |
|
break; |
|
} |
|
} |
|
} |
|
return; |
|
|
|
case KEY_XBUTTON_B: |
|
case STEAMCONTROLLER_B: |
|
OnCommand( "Close" ); |
|
return; |
|
|
|
case KEY_XBUTTON_A: |
|
case STEAMCONTROLLER_A: |
|
OnCommand( "Play" ); |
|
return; |
|
} |
|
|
|
m_KeyRepeat.KeyDown( code ); |
|
|
|
BaseClass::OnKeyCodePressed( code ); |
|
} |
|
|
|
void CNewGameDialog::OnKeyCodeReleased( vgui::KeyCode code ) |
|
{ |
|
m_KeyRepeat.KeyUp( code ); |
|
|
|
BaseClass::OnKeyCodeReleased( code ); |
|
} |
|
|
|
void CNewGameDialog::OnThink() |
|
{ |
|
vgui::KeyCode code = m_KeyRepeat.KeyRepeated(); |
|
if ( code ) |
|
{ |
|
OnKeyCodeTyped( code ); |
|
} |
|
|
|
BaseClass::OnThink(); |
|
}
|
|
|