Counter Strike : Global Offensive Source Code
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.

1574 lines
46 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "basepanel.h"
  8. #include "newgamedialog.h"
  9. #include "engineinterface.h"
  10. #include "vgui_controls/Button.h"
  11. #include "vgui_controls/CheckButton.h"
  12. #include "keyvalues.h"
  13. #include "vgui/ISurface.h"
  14. #include "vgui/IInput.h"
  15. #include "vgui/ILocalize.h"
  16. #include <vgui/ISystem.h>
  17. #include "vgui_controls/RadioButton.h"
  18. #include "vgui_controls/ComboBox.h"
  19. #include "vgui_controls/ImagePanel.h"
  20. #include "vgui_controls/Frame.h"
  21. #include "vgui_controls/ControllerMap.h"
  22. #include "filesystem.h"
  23. #include "modinfo.h"
  24. #include "tier1/convar.h"
  25. #include "gameui_interface.h"
  26. #include "tier0/icommandline.h"
  27. #include "vgui_controls/AnimationController.h"
  28. #include "commentaryexplanationdialog.h"
  29. #include "vgui_controls/BitmapImagePanel.h"
  30. #include "bonusmapsdatabase.h"
  31. #include <stdio.h>
  32. // memdbgon must be the last include file in a .cpp file!!!
  33. #include "tier0/memdbgon.h"
  34. using namespace vgui;
  35. extern const char *COM_GetModDirectory();
  36. static float g_ScrollSpeedSlow;
  37. static float g_ScrollSpeedFast;
  38. // sort function used in displaying chapter list
  39. struct chapter_t
  40. {
  41. char filename[32];
  42. };
  43. static int __cdecl ChapterSortFunc(const void *elem1, const void *elem2)
  44. {
  45. chapter_t *c1 = (chapter_t *)elem1;
  46. chapter_t *c2 = (chapter_t *)elem2;
  47. // compare chapter number first
  48. static int chapterlen = strlen("chapter");
  49. if (atoi(c1->filename + chapterlen) > atoi(c2->filename + chapterlen))
  50. return 1;
  51. else if (atoi(c1->filename + chapterlen) < atoi(c2->filename + chapterlen))
  52. return -1;
  53. // compare length second (longer string show up later in the list, eg. chapter9 before chapter9a)
  54. if (strlen(c1->filename) > strlen(c2->filename))
  55. return 1;
  56. else if (strlen(c1->filename) < strlen(c2->filename))
  57. return -1;
  58. // compare strings third
  59. return strcmp(c1->filename, c2->filename);
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: invisible panel used for selecting a chapter panel
  63. //-----------------------------------------------------------------------------
  64. class CSelectionOverlayPanel : public vgui::Panel
  65. {
  66. DECLARE_CLASS_SIMPLE( CSelectionOverlayPanel, Panel );
  67. int m_iChapterIndex;
  68. CNewGameDialog *m_pSelectionTarget;
  69. public:
  70. CSelectionOverlayPanel( Panel *parent, CNewGameDialog *selectionTarget, int chapterIndex ) : BaseClass( parent, NULL )
  71. {
  72. m_iChapterIndex = chapterIndex;
  73. m_pSelectionTarget = selectionTarget;
  74. SetPaintEnabled(false);
  75. SetPaintBackgroundEnabled(false);
  76. }
  77. virtual void OnMousePressed( vgui::MouseCode code )
  78. {
  79. if (GetParent()->IsEnabled())
  80. {
  81. m_pSelectionTarget->SetSelectedChapterIndex( m_iChapterIndex );
  82. }
  83. }
  84. virtual void OnMouseDoublePressed( vgui::MouseCode code )
  85. {
  86. // call the panel
  87. OnMousePressed( code );
  88. if (GetParent()->IsEnabled())
  89. {
  90. PostMessage( m_pSelectionTarget, new KeyValues("Command", "command", "play") );
  91. }
  92. }
  93. };
  94. //-----------------------------------------------------------------------------
  95. // Purpose: selectable item with screenshot for an individual chapter in the dialog
  96. //-----------------------------------------------------------------------------
  97. class CGameChapterPanel : public vgui::EditablePanel
  98. {
  99. DECLARE_CLASS_SIMPLE( CGameChapterPanel, vgui::EditablePanel );
  100. ImagePanel *m_pLevelPicBorder;
  101. ImagePanel *m_pLevelPic;
  102. ImagePanel *m_pCommentaryIcon;
  103. Label *m_pChapterLabel;
  104. Label *m_pChapterNameLabel;
  105. Color m_TextColor;
  106. Color m_DisabledColor;
  107. Color m_SelectedColor;
  108. Color m_FillColor;
  109. char m_szConfigFile[_MAX_PATH];
  110. char m_szChapter[32];
  111. bool m_bTeaserChapter;
  112. bool m_bHasBonus;
  113. bool m_bCommentaryMode;
  114. public:
  115. CGameChapterPanel( CNewGameDialog *parent, const char *name, const char *chapterName, int chapterIndex, const char *chapterNumber, const char *chapterConfigFile, bool bCommentary ) : BaseClass( parent, name )
  116. {
  117. Q_strncpy( m_szConfigFile, chapterConfigFile, sizeof(m_szConfigFile) );
  118. Q_strncpy( m_szChapter, chapterNumber, sizeof(m_szChapter) );
  119. m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) );
  120. m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) );
  121. m_pCommentaryIcon = NULL;
  122. m_bCommentaryMode = bCommentary;
  123. wchar_t text[32];
  124. wchar_t num[32];
  125. wchar_t *chapter = g_pVGuiLocalize->Find("#GameUI_Chapter");
  126. g_pVGuiLocalize->ConvertANSIToUnicode( chapterNumber, num, sizeof(num) );
  127. _snwprintf( text, ARRAYSIZE(text), L"%s %s", chapter ? chapter : L"CHAPTER", num );
  128. if ( ModInfo().IsSinglePlayerOnly() )
  129. {
  130. m_pChapterLabel = new Label( this, "ChapterLabel", text );
  131. m_pChapterNameLabel = new Label( this, "ChapterNameLabel", chapterName );
  132. }
  133. else
  134. {
  135. m_pChapterLabel = new Label( this, "ChapterLabel", chapterName );
  136. m_pChapterNameLabel = new Label( this, "ChapterNameLabel", "#GameUI_LoadCommentary" );
  137. }
  138. SetPaintBackgroundEnabled( false );
  139. // the image has the same name as the config file
  140. char szMaterial[ MAX_PATH ];
  141. Q_snprintf( szMaterial, sizeof(szMaterial), "chapters/%s", chapterConfigFile );
  142. char *ext = strstr( szMaterial, "." );
  143. if ( ext )
  144. {
  145. *ext = 0;
  146. }
  147. m_pLevelPic->SetImage( szMaterial );
  148. KeyValues *pKeys = NULL;
  149. if ( GameUI().IsConsoleUI() )
  150. {
  151. // JDW FIXME: Cannot call BasePanel() at this time!
  152. // pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameChapterPanel.res" );
  153. }
  154. LoadControlSettings( "Resource/NewGameChapterPanel.res", NULL, pKeys );
  155. int px, py;
  156. m_pLevelPicBorder->GetPos( px, py );
  157. SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() );
  158. // create a selection panel the size of the page
  159. CSelectionOverlayPanel *overlay = new CSelectionOverlayPanel( this, parent, chapterIndex );
  160. overlay->SetBounds(0, 0, GetWide(), GetTall());
  161. overlay->MoveToFront();
  162. // HACK: Detect new episode teasers by the "Coming Soon" text
  163. wchar_t w_szStrTemp[256];
  164. m_pChapterNameLabel->GetText( w_szStrTemp, sizeof(w_szStrTemp) );
  165. m_bTeaserChapter = !wcscmp(w_szStrTemp, L"Coming Soon");
  166. m_bHasBonus = false;
  167. }
  168. virtual void ApplySchemeSettings( IScheme *pScheme )
  169. {
  170. m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
  171. m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) );
  172. m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 255) );
  173. m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
  174. BaseClass::ApplySchemeSettings( pScheme );
  175. // Hide chapter numbers for new episode teasers
  176. if ( m_bTeaserChapter )
  177. {
  178. m_pChapterLabel->SetVisible( false );
  179. }
  180. if ( GameUI().IsConsoleUI() )
  181. {
  182. m_pChapterNameLabel->SetVisible( false );
  183. }
  184. m_pCommentaryIcon = dynamic_cast<ImagePanel*>( FindChildByName( "CommentaryIcon" ) );
  185. if ( m_pCommentaryIcon )
  186. m_pCommentaryIcon->SetVisible( m_bCommentaryMode );
  187. }
  188. void SetSelected( bool state )
  189. {
  190. // update the text/border colors
  191. if ( !IsEnabled() )
  192. {
  193. m_pChapterLabel->SetFgColor( m_DisabledColor );
  194. m_pChapterNameLabel->SetFgColor( Color(0, 0, 0, 0) );
  195. m_pLevelPicBorder->SetFillColor( m_DisabledColor );
  196. m_pLevelPic->SetAlpha( GameUI().IsConsoleUI() ? 64 : 128 );
  197. return;
  198. }
  199. if ( state )
  200. {
  201. if ( !GameUI().IsConsoleUI() )
  202. {
  203. m_pChapterLabel->SetFgColor( m_SelectedColor );
  204. m_pChapterNameLabel->SetFgColor( m_SelectedColor );
  205. }
  206. m_pLevelPicBorder->SetFillColor( m_SelectedColor );
  207. }
  208. else
  209. {
  210. m_pChapterLabel->SetFgColor( m_TextColor );
  211. m_pChapterNameLabel->SetFgColor( m_TextColor );
  212. m_pLevelPicBorder->SetFillColor( m_FillColor );
  213. }
  214. m_pLevelPic->SetAlpha( 255 );
  215. }
  216. const char *GetConfigFile()
  217. {
  218. return m_szConfigFile;
  219. }
  220. const char *GetChapter()
  221. {
  222. return m_szChapter;
  223. }
  224. bool IsTeaserChapter()
  225. {
  226. return m_bTeaserChapter;
  227. }
  228. bool HasBonus()
  229. {
  230. return m_bHasBonus;
  231. }
  232. void SetCommentaryMode( bool bCommentaryMode )
  233. {
  234. m_bCommentaryMode = bCommentaryMode;
  235. if ( m_pCommentaryIcon )
  236. m_pCommentaryIcon->SetVisible( m_bCommentaryMode );
  237. }
  238. };
  239. //-----------------------------------------------------------------------------
  240. // Purpose: new game chapter selection
  241. //-----------------------------------------------------------------------------
  242. CNewGameDialog::CNewGameDialog(vgui::Panel *parent, bool bCommentaryMode) : BaseClass(parent, "NewGameDialog")
  243. {
  244. SetDeleteSelfOnClose(true);
  245. SetBounds(0, 0, 372, 160);
  246. SetSizeable( false );
  247. m_iSelectedChapter = -1;
  248. m_ActiveTitleIdx = 0;
  249. m_bCommentaryMode = bCommentaryMode;
  250. m_bMapStarting = false;
  251. m_bScrolling = false;
  252. m_ScrollCt = 0;
  253. m_ScrollSpeed = 0.f;
  254. m_ButtonPressed = SCROLL_NONE;
  255. m_ScrollDirection = SCROLL_NONE;
  256. m_pCommentaryLabel = NULL;
  257. m_iBonusSelection = 0;
  258. m_bScrollToFirstBonusMap = false;
  259. SetTitle("#GameUI_NewGame", true);
  260. m_pNextButton = new Button( this, "Next", "#gameui_next" );
  261. m_pPrevButton = new Button( this, "Prev", "#gameui_prev" );
  262. m_pPlayButton = new vgui::Button( this, "Play", "#GameUI_Play" );
  263. m_pPlayButton->SetCommand( "Play" );
  264. vgui::Button *cancel = new vgui::Button( this, "Cancel", "#GameUI_Cancel" );
  265. cancel->SetCommand( "Close" );
  266. m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) );
  267. m_pCenterBg->SetVisible( false );
  268. if ( GameUI().IsConsoleUI() )
  269. {
  270. m_pNextButton->SetVisible( false );
  271. m_pPrevButton->SetVisible( false );
  272. m_pPlayButton->SetVisible( false );
  273. cancel->SetVisible( false );
  274. m_pCenterBg->SetPaintBackgroundType( 2 );
  275. m_pCenterBg->SetVisible( true );
  276. m_pChapterTitleLabels[0] = SETUP_PANEL( new Label( this, "ChapterTitleLabel", "" ) );
  277. m_pChapterTitleLabels[0]->SetVisible( true );
  278. m_pChapterTitleLabels[0]->SetFgColor( Color( 255, 255, 255, 255 ) );
  279. m_pChapterTitleLabels[1] = SETUP_PANEL( new Label( this, "ChapterTitleLabel2", "" ) );
  280. m_pChapterTitleLabels[1]->SetVisible( true );
  281. m_pChapterTitleLabels[1]->SetAlpha( 0 );
  282. m_pChapterTitleLabels[1]->SetFgColor( Color( 255, 255, 255, 255 ) );
  283. m_pBonusSelection = SETUP_PANEL( new Label( this, "BonusSelectionLabel", "#GameUI_BonusMapsStandard" ) );
  284. m_pBonusSelectionBorder = SETUP_PANEL( new ImagePanel( this, "BonusSelectionBorder" ) );
  285. m_pFooter = new CFooterPanel( parent, "NewGameFooter" );
  286. m_pFooter->AddNewButtonLabel( "#GameUI_Play", "#GameUI_Icons_A_BUTTON" );
  287. m_pFooter->AddNewButtonLabel( "#GameUI_Close", "#GameUI_Icons_B_BUTTON" );
  288. }
  289. else
  290. {
  291. m_pFooter = NULL;
  292. }
  293. // parse out the chapters off disk
  294. static const int MAX_CHAPTERS = 32;
  295. chapter_t chapters[MAX_CHAPTERS];
  296. char szFullFileName[MAX_PATH];
  297. int chapterIndex = 0;
  298. if ( IsPC() || !IsGameConsole() )
  299. {
  300. FileFindHandle_t findHandle = FILESYSTEM_INVALID_FIND_HANDLE;
  301. const char *fileName = "cfg/chapter*.cfg";
  302. fileName = g_pFullFileSystem->FindFirst( fileName, &findHandle );
  303. while ( fileName && chapterIndex < MAX_CHAPTERS )
  304. {
  305. // Only load chapter configs from the current mod's cfg dir
  306. // or else chapters appear that we don't want!
  307. Q_snprintf( szFullFileName, sizeof(szFullFileName), "cfg/%s", fileName );
  308. FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
  309. if ( f )
  310. {
  311. // don't load chapter files that are empty, used in the demo
  312. if ( g_pFullFileSystem->Size(f) > 0 )
  313. {
  314. Q_strncpy(chapters[chapterIndex].filename, fileName, sizeof(chapters[chapterIndex].filename));
  315. ++chapterIndex;
  316. }
  317. g_pFullFileSystem->Close( f );
  318. }
  319. fileName = g_pFullFileSystem->FindNext(findHandle);
  320. }
  321. }
  322. else if ( IsGameConsole() )
  323. {
  324. int ChapterStringIndex = 0;
  325. bool bExists = true;
  326. while ( bExists && chapterIndex < MAX_CHAPTERS )
  327. {
  328. Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter%d.cfg", ChapterStringIndex+1 );
  329. FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
  330. if ( f )
  331. {
  332. Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename));
  333. ++chapterIndex;
  334. ++ChapterStringIndex;
  335. g_pFullFileSystem->Close( f );
  336. }
  337. else
  338. {
  339. bExists = false;
  340. }
  341. //Hack to account for xbox360 missing chapter9a
  342. if ( ChapterStringIndex == 10 )
  343. {
  344. Q_snprintf( szFullFileName, sizeof( szFullFileName ), "cfg/chapter9a.cfg" );
  345. FileHandle_t f = g_pFullFileSystem->Open( szFullFileName, "rb", "MOD" );
  346. if ( f )
  347. {
  348. Q_strncpy(chapters[chapterIndex].filename, szFullFileName + 4, sizeof(chapters[chapterIndex].filename));
  349. ++chapterIndex;
  350. g_pFullFileSystem->Close( f );
  351. }
  352. }
  353. }
  354. }
  355. bool bBonusesUnlocked = false;
  356. if ( GameUI().IsConsoleUI() )
  357. {
  358. if ( !m_bCommentaryMode )
  359. {
  360. // Scan to see if the bonus maps have been unlocked
  361. bBonusesUnlocked = BonusMapsDatabase()->BonusesUnlocked();
  362. }
  363. }
  364. // sort the chapters
  365. qsort(chapters, chapterIndex, sizeof(chapter_t), &ChapterSortFunc);
  366. // work out which chapters are unlocked
  367. ConVarRef var( "sv_unlockedchapters" );
  368. if ( bBonusesUnlocked )
  369. {
  370. // Bonuses are unlocked so we need to unlock all the chapters too
  371. var.SetValue( 15 );
  372. }
  373. const char *unlockedChapter = var.IsValid() ? var.GetString() : "1";
  374. int iUnlockedChapter = atoi(unlockedChapter);
  375. // add chapters to combobox
  376. for (int i = 0; i < chapterIndex; i++)
  377. {
  378. const char *fileName = chapters[i].filename;
  379. char chapterID[32] = { 0 };
  380. sscanf(fileName, "chapter%s", chapterID);
  381. // strip the extension
  382. char *ext = V_stristr(chapterID, ".cfg");
  383. if (ext)
  384. {
  385. *ext = 0;
  386. }
  387. const char *pGameDir = COM_GetModDirectory();
  388. char chapterName[64];
  389. Q_snprintf(chapterName, sizeof(chapterName), "#%s_Chapter%s_Title", pGameDir, chapterID);
  390. Q_snprintf( szFullFileName, sizeof( szFullFileName ), "%s", fileName );
  391. CGameChapterPanel *chapterPanel = SETUP_PANEL( new CGameChapterPanel( this, NULL, chapterName, i, chapterID, szFullFileName, m_bCommentaryMode ) );
  392. chapterPanel->SetVisible( false );
  393. UpdatePanelLockedStatus( iUnlockedChapter, i + 1, chapterPanel );
  394. if ( GameUI().IsConsoleUI() )
  395. {
  396. if ( bBonusesUnlocked )
  397. {
  398. // check to see if it has associated challenges
  399. for ( int iBonusMap = 0; iBonusMap < BonusMapsDatabase()->BonusCount(); ++iBonusMap )
  400. {
  401. BonusMapDescription_t *pMap = BonusMapsDatabase()->GetBonusData( iBonusMap );
  402. if ( Q_stricmp( pMap->szChapterName, szFullFileName ) == 0 && !pMap->bLocked )
  403. {
  404. chapterPanel->m_bHasBonus = true;
  405. chapterPanel->SetControlVisible( "HasBonusLabel", true );
  406. }
  407. }
  408. }
  409. }
  410. m_ChapterPanels.AddToTail( chapterPanel );
  411. }
  412. KeyValues *pKeys = NULL;
  413. if ( GameUI().IsConsoleUI() )
  414. {
  415. // JDW FIXME: Cannot call BasePanel() at this point
  416. // pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameDialog.res" );
  417. }
  418. LoadControlSettings( "Resource/NewGameDialog.res", NULL, pKeys );
  419. // Reset all properties
  420. for ( int i = 0; i < NUM_SLOTS; ++i )
  421. {
  422. m_PanelIndex[i] = INVALID_INDEX;
  423. }
  424. if ( !m_ChapterPanels.Count() )
  425. {
  426. UpdateMenuComponents( SCROLL_NONE );
  427. return;
  428. }
  429. // Layout panel positions relative to the dialog center.
  430. int panelWidth = m_ChapterPanels[0]->GetWide() + 16;
  431. int dialogWidth = GetWide();
  432. m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + 8;
  433. m_PanelXPos[1] = m_PanelXPos[2] - panelWidth;
  434. m_PanelXPos[0] = m_PanelXPos[1];
  435. m_PanelXPos[3] = m_PanelXPos[2] + panelWidth;
  436. m_PanelXPos[4] = m_PanelXPos[3];
  437. m_PanelAlpha[0] = 0;
  438. m_PanelAlpha[1] = 255;
  439. m_PanelAlpha[2] = 255;
  440. m_PanelAlpha[3] = 255;
  441. m_PanelAlpha[4] = 0;
  442. int panelHeight;
  443. m_ChapterPanels[0]->GetSize( panelWidth, panelHeight );
  444. m_pCenterBg->SetWide( panelWidth + 16 );
  445. m_pCenterBg->SetPos( m_PanelXPos[2] - 8, m_PanelYPos[2] - (m_pCenterBg->GetTall() - panelHeight) + 8 );
  446. m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) );
  447. // start the first item selected
  448. SetSelectedChapterIndex( 0 );
  449. }
  450. CNewGameDialog::~CNewGameDialog()
  451. {
  452. delete m_pFooter;
  453. m_pFooter = NULL;
  454. }
  455. void CNewGameDialog::Activate( void )
  456. {
  457. m_bMapStarting = false;
  458. if ( GameUI().IsConsoleUI() )
  459. {
  460. // Stop blinking the menu item now that we've seen the unlocked stuff
  461. CBaseModPanel *pBasePanel = BasePanel();
  462. if ( pBasePanel )
  463. pBasePanel->SetMenuItemBlinkingState( "OpenNewGameDialog", false );
  464. BonusMapsDatabase()->SetBlink( false );
  465. }
  466. // Commentary stuff is set up on activate because in XBox the new game menu is never deleted
  467. SetTitle( ( ( m_bCommentaryMode ) ? ( "#GameUI_LoadCommentary" ) : ( "#GameUI_NewGame") ), true);
  468. if ( m_pCommentaryLabel )
  469. m_pCommentaryLabel->SetVisible( m_bCommentaryMode );
  470. // work out which chapters are unlocked
  471. ConVarRef var( "sv_unlockedchapters" );
  472. const char *unlockedChapter = var.IsValid() ? var.GetString() : "1";
  473. int iUnlockedChapter = atoi(unlockedChapter);
  474. for ( int i = 0; i < m_ChapterPanels.Count(); i++)
  475. {
  476. CGameChapterPanel *pChapterPanel = m_ChapterPanels[ i ];
  477. if ( pChapterPanel )
  478. {
  479. pChapterPanel->SetCommentaryMode( m_bCommentaryMode );
  480. UpdatePanelLockedStatus( iUnlockedChapter, i + 1, pChapterPanel );
  481. }
  482. }
  483. BaseClass::Activate();
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose: Apply special properties of the menu
  487. //-----------------------------------------------------------------------------
  488. void CNewGameDialog::ApplySettings( KeyValues *inResourceData )
  489. {
  490. BaseClass::ApplySettings( inResourceData );
  491. int ypos = inResourceData->GetInt( "chapterypos", 40 );
  492. for ( int i = 0; i < NUM_SLOTS; ++i )
  493. {
  494. m_PanelYPos[i] = ypos;
  495. }
  496. m_pCenterBg->SetTall( inResourceData->GetInt( "centerbgtall", 0 ) );
  497. g_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f );
  498. g_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f );
  499. SetFastScroll( false );
  500. }
  501. void CNewGameDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  502. {
  503. BaseClass::ApplySchemeSettings( pScheme );
  504. if ( m_pFooter )
  505. {
  506. KeyValues *pFooterControlSettings = BasePanel()->GetConsoleControlSettings()->FindKey( "NewGameFooter.res" );
  507. m_pFooter->LoadControlSettings( "null", NULL, pFooterControlSettings );
  508. }
  509. UpdateMenuComponents( SCROLL_NONE );
  510. m_pCommentaryLabel = dynamic_cast<vgui::Label*>( FindChildByName( "CommentaryUnlock" ) );
  511. if ( m_pCommentaryLabel )
  512. m_pCommentaryLabel->SetVisible( m_bCommentaryMode );
  513. if ( GameUI().IsConsoleUI() )
  514. {
  515. if ( !m_bCommentaryMode && BonusMapsDatabase()->BonusesUnlocked() && !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() )
  516. {
  517. // Find the first bonus
  518. ScrollSelectionPanels( SCROLL_LEFT );
  519. m_bScrollToFirstBonusMap = true;
  520. }
  521. }
  522. }
  523. static float GetArrowAlpha( void )
  524. {
  525. // X360TBD: Pulsing arrows
  526. return 255.f;
  527. }
  528. //-----------------------------------------------------------------------------
  529. // Purpose: sets the correct properties for visible components
  530. //-----------------------------------------------------------------------------
  531. void CNewGameDialog::UpdateMenuComponents( EScrollDirection dir )
  532. {
  533. // This is called prior to any scrolling,
  534. // so we need to look ahead to the post-scroll state
  535. int centerIdx = SLOT_CENTER;
  536. if ( dir == SCROLL_LEFT )
  537. {
  538. ++centerIdx;
  539. }
  540. else if ( dir == SCROLL_RIGHT )
  541. {
  542. --centerIdx;
  543. }
  544. int leftIdx = centerIdx - 1;
  545. int rightIdx = centerIdx + 1;
  546. if ( GameUI().IsConsoleUI() )
  547. {
  548. bool bHasBonus = false;
  549. if ( m_PanelIndex[centerIdx] != INVALID_INDEX )
  550. {
  551. wchar_t buffer[ MAX_PATH ];
  552. m_ChapterPanels[ m_PanelIndex[centerIdx] ]->m_pChapterNameLabel->GetText( buffer, sizeof(buffer) );
  553. m_pChapterTitleLabels[m_ActiveTitleIdx]->SetText( buffer );
  554. // If it has bonuses show the scroll up and down arrows
  555. bHasBonus = m_ChapterPanels[ m_PanelIndex[centerIdx] ]->HasBonus();
  556. }
  557. vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" );
  558. vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" );
  559. if ( leftArrow )
  560. {
  561. if ( m_PanelIndex[leftIdx] != INVALID_INDEX )
  562. {
  563. leftArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) );
  564. }
  565. else
  566. {
  567. leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
  568. }
  569. }
  570. if ( rightArrow )
  571. {
  572. if ( m_PanelIndex[rightIdx] != INVALID_INDEX )
  573. {
  574. rightArrow->SetFgColor( Color( 255, 255, 255, GetArrowAlpha() ) );
  575. }
  576. else
  577. {
  578. rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
  579. }
  580. }
  581. if ( bHasBonus )
  582. {
  583. // Find the bonus description for this panel
  584. for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus )
  585. {
  586. m_pBonusMapDescription = BonusMapsDatabase()->GetBonusData( iBonus );
  587. if ( Q_stricmp( m_pBonusMapDescription->szChapterName, m_ChapterPanels[ m_PanelIndex[centerIdx] ]->GetConfigFile() ) == 0 )
  588. break;
  589. }
  590. }
  591. else
  592. {
  593. m_pBonusMapDescription = NULL;
  594. }
  595. vgui::Panel *upArrow = this->FindChildByName( "UpArrow" );
  596. vgui::Panel *downArrow = this->FindChildByName( "DownArrow" );
  597. if ( upArrow )
  598. upArrow->SetVisible( bHasBonus );
  599. if ( downArrow )
  600. downArrow->SetVisible( bHasBonus );
  601. m_pBonusSelection->SetVisible( bHasBonus );
  602. m_pBonusSelectionBorder->SetVisible( bHasBonus );
  603. UpdateBonusSelection();
  604. }
  605. // No buttons in the xbox ui
  606. if ( !GameUI().IsConsoleUI() )
  607. {
  608. if ( m_PanelIndex[leftIdx] == INVALID_INDEX || m_PanelIndex[leftIdx] == 0 )
  609. {
  610. m_pPrevButton->SetVisible( false );
  611. m_pPrevButton->SetEnabled( false );
  612. }
  613. else
  614. {
  615. m_pPrevButton->SetVisible( true );
  616. m_pPrevButton->SetEnabled( true );
  617. }
  618. if ( m_ChapterPanels.Count() < 4 ) // if there are less than 4 chapters show the next button but disabled
  619. {
  620. m_pNextButton->SetVisible( true );
  621. m_pNextButton->SetEnabled( false );
  622. }
  623. else if ( m_PanelIndex[rightIdx] == INVALID_INDEX || m_PanelIndex[rightIdx] == m_ChapterPanels.Count()-1 )
  624. {
  625. m_pNextButton->SetVisible( false );
  626. m_pNextButton->SetEnabled( false );
  627. }
  628. else
  629. {
  630. m_pNextButton->SetVisible( true );
  631. m_pNextButton->SetEnabled( true );
  632. }
  633. }
  634. }
  635. void CNewGameDialog::UpdateBonusSelection( void )
  636. {
  637. int iNumChallenges = 0;
  638. if ( m_pBonusMapDescription )
  639. {
  640. if ( m_pBonusMapDescription->m_pChallenges )
  641. iNumChallenges = m_pBonusMapDescription->m_pChallenges->Count();
  642. // Wrap challenge selection to fit number of possible selections
  643. if ( m_iBonusSelection < 0 )
  644. m_iBonusSelection = iNumChallenges + 1;
  645. else if ( m_iBonusSelection >= iNumChallenges + 2 )
  646. m_iBonusSelection = 0;
  647. }
  648. else
  649. {
  650. // No medals to show
  651. SetControlVisible( "ChallengeEarnedMedal", false );
  652. SetControlVisible( "ChallengeBestLabel", false );
  653. SetControlVisible( "ChallengeNextMedal", false );
  654. SetControlVisible( "ChallengeNextLabel", false );
  655. return;
  656. }
  657. if ( m_iBonusSelection == 0 )
  658. {
  659. m_pBonusSelection->SetText( "#GameUI_BonusMapsStandard" );
  660. SetControlVisible( "ChallengeEarnedMedal", false );
  661. SetControlVisible( "ChallengeBestLabel", false );
  662. SetControlVisible( "ChallengeNextMedal", false );
  663. SetControlVisible( "ChallengeNextLabel", false );
  664. }
  665. else if ( m_iBonusSelection == 1 )
  666. {
  667. m_pBonusSelection->SetText( "#GameUI_BonusMapsAdvanced" );
  668. SetControlVisible( "ChallengeEarnedMedal", false );
  669. SetControlVisible( "ChallengeBestLabel", false );
  670. SetControlVisible( "ChallengeNextMedal", false );
  671. SetControlVisible( "ChallengeNextLabel", false );
  672. char szMapAdvancedName[ 256 ] = "";
  673. if ( m_pBonusMapDescription )
  674. {
  675. Q_snprintf( szMapAdvancedName, sizeof( szMapAdvancedName ), "%s_advanced", m_pBonusMapDescription->szMapFileName );
  676. }
  677. BonusMapDescription_t *pAdvancedDescription = NULL;
  678. // Find the bonus description for this panel
  679. for ( int iBonus = 0; iBonus < BonusMapsDatabase()->BonusCount(); ++iBonus )
  680. {
  681. pAdvancedDescription = BonusMapsDatabase()->GetBonusData( iBonus );
  682. if ( Q_stricmp( szMapAdvancedName, pAdvancedDescription->szMapFileName ) == 0 )
  683. break;
  684. }
  685. if ( pAdvancedDescription && pAdvancedDescription->bComplete )
  686. {
  687. CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
  688. pBitmap->SetVisible( true );
  689. pBitmap->setTexture( "hud/icon_complete" );
  690. }
  691. }
  692. else
  693. {
  694. int iChallenge = m_iBonusSelection - 2;
  695. ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge ]);
  696. // Set the display text for the selected challenge
  697. m_pBonusSelection->SetText( pChallengeDescription->szName );
  698. int iBest, iEarnedMedal, iNext, iNextMedal;
  699. GetChallengeMedals( pChallengeDescription, iBest, iEarnedMedal, iNext, iNextMedal );
  700. char szBuff[ 512 ];
  701. // Set earned medal
  702. if ( iEarnedMedal > -1 && iBest != -1 )
  703. {
  704. if ( iChallenge < 10 )
  705. Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
  706. else
  707. Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iEarnedMedal ] );
  708. CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
  709. pBitmap->SetVisible( true );
  710. pBitmap->setTexture( szBuff );
  711. }
  712. else
  713. {
  714. CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeEarnedMedal" ) );
  715. pBitmap->SetVisible( false );
  716. }
  717. // Set next medal
  718. if ( iNextMedal > 0 )
  719. {
  720. if ( iChallenge < 10 )
  721. Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_0%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
  722. else
  723. Q_snprintf( szBuff, sizeof( szBuff ), "medals/medal_%i_%s", iChallenge, g_pszMedalNames[ iNextMedal ] );
  724. CBitmapImagePanel *pBitmap = dynamic_cast<CBitmapImagePanel*>( FindChildByName( "ChallengeNextMedal" ) );
  725. pBitmap->SetVisible( true );
  726. pBitmap->setTexture( szBuff );
  727. }
  728. else
  729. {
  730. SetControlVisible( "ChallengeNextMedal", false );
  731. }
  732. wchar_t szWideBuff[ 64 ];
  733. wchar_t szWideBuff2[ 64 ];
  734. // Best label
  735. if ( iBest != -1 )
  736. {
  737. Q_snprintf( szBuff, sizeof( szBuff ), "%i", iBest );
  738. g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
  739. g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsBest" ), 1, szWideBuff2 );
  740. g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
  741. SetControlString( "ChallengeBestLabel", szBuff );
  742. SetControlVisible( "ChallengeBestLabel", true );
  743. }
  744. else
  745. {
  746. SetControlVisible( "ChallengeBestLabel", false );
  747. }
  748. // Next label
  749. if ( iNext != -1 )
  750. {
  751. Q_snprintf( szBuff, sizeof( szBuff ), "%i", iNext );
  752. g_pVGuiLocalize->ConvertANSIToUnicode( szBuff, szWideBuff2, sizeof( szWideBuff2 ) );
  753. g_pVGuiLocalize->ConstructString( szWideBuff, sizeof( szWideBuff ), g_pVGuiLocalize->Find( "#GameUI_BonusMapsGoal" ), 1, szWideBuff2 );
  754. g_pVGuiLocalize->ConvertUnicodeToANSI( szWideBuff, szBuff, sizeof( szBuff ) );
  755. SetControlString( "ChallengeNextLabel", szBuff );
  756. SetControlVisible( "ChallengeNextLabel", true );
  757. }
  758. else
  759. {
  760. SetControlVisible( "ChallengeNextLabel", false );
  761. }
  762. }
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Purpose: sets a chapter as selected
  766. //-----------------------------------------------------------------------------
  767. void CNewGameDialog::SetSelectedChapterIndex( int index )
  768. {
  769. m_iSelectedChapter = index;
  770. for (int i = 0; i < m_ChapterPanels.Count(); i++)
  771. {
  772. if ( i == index )
  773. {
  774. m_ChapterPanels[i]->SetSelected( true );
  775. }
  776. else
  777. {
  778. m_ChapterPanels[i]->SetSelected( false );
  779. }
  780. }
  781. if ( m_pPlayButton )
  782. {
  783. m_pPlayButton->SetEnabled( true );
  784. }
  785. // Setup panels to the left of the selected panel
  786. int selectedSlot = GameUI().IsConsoleUI() ? SLOT_CENTER : index % 3 + 1;
  787. int currIdx = index;
  788. for ( int i = selectedSlot; i >= 0 && currIdx >= 0; --i )
  789. {
  790. m_PanelIndex[i] = currIdx;
  791. --currIdx;
  792. InitPanelIndexForDisplay( i );
  793. }
  794. // Setup panels to the right of the selected panel
  795. currIdx = index + 1;
  796. for ( int i = selectedSlot + 1; i < NUM_SLOTS && currIdx < m_ChapterPanels.Count(); ++i )
  797. {
  798. m_PanelIndex[i] = currIdx;
  799. ++currIdx;
  800. InitPanelIndexForDisplay( i );
  801. }
  802. UpdateMenuComponents( SCROLL_NONE );
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Purpose: sets a chapter as selected
  806. //-----------------------------------------------------------------------------
  807. void CNewGameDialog::SetSelectedChapter( const char *chapter )
  808. {
  809. Assert( chapter );
  810. for (int i = 0; i < m_ChapterPanels.Count(); i++)
  811. {
  812. if ( chapter && !Q_stricmp(m_ChapterPanels[i]->GetChapter(), chapter) )
  813. {
  814. m_iSelectedChapter = i;
  815. m_ChapterPanels[m_iSelectedChapter]->SetSelected( true );
  816. }
  817. else
  818. {
  819. m_ChapterPanels[i]->SetSelected( false );
  820. }
  821. }
  822. if ( m_pPlayButton )
  823. {
  824. m_pPlayButton->SetEnabled( true );
  825. }
  826. }
  827. //-----------------------------------------------------------------------------
  828. // iUnlockedChapter - the value of sv_unlockedchapters, 1-based. A value of 0
  829. // is treated as a 1, since at least one chapter must be unlocked.
  830. //
  831. // i - the 1-based index of the chapter we're considering.
  832. //-----------------------------------------------------------------------------
  833. void CNewGameDialog::UpdatePanelLockedStatus( int iUnlockedChapter, int i, CGameChapterPanel *pChapterPanel )
  834. {
  835. if ( iUnlockedChapter <= 0 )
  836. {
  837. iUnlockedChapter = 1;
  838. }
  839. // Commentary mode requires chapters to be finished before they can be chosen
  840. bool bLocked = false;
  841. if ( m_bCommentaryMode )
  842. {
  843. bLocked = ( iUnlockedChapter <= i );
  844. }
  845. else
  846. {
  847. if ( iUnlockedChapter < i )
  848. {
  849. // Never lock the first chapter
  850. bLocked = ( i != 0 );
  851. }
  852. }
  853. pChapterPanel->SetEnabled( !bLocked );
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Purpose: Called before a panel scroll starts.
  857. //-----------------------------------------------------------------------------
  858. void CNewGameDialog::PreScroll( EScrollDirection dir )
  859. {
  860. int hideIdx = INVALID_INDEX;
  861. if ( dir == SCROLL_LEFT )
  862. {
  863. hideIdx = m_PanelIndex[SLOT_LEFT];
  864. }
  865. else if ( dir == SCROLL_RIGHT )
  866. {
  867. hideIdx = m_PanelIndex[SLOT_RIGHT];
  868. }
  869. if ( hideIdx != INVALID_INDEX )
  870. {
  871. // Push back the panel that's about to be hidden
  872. // so the next panel scrolls over the top of it.
  873. m_ChapterPanels[hideIdx]->SetZPos( 0 );
  874. }
  875. // Flip the active title label prior to the crossfade
  876. m_ActiveTitleIdx ^= 0x01;
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Purpose: Called after a panel scroll finishes.
  880. //-----------------------------------------------------------------------------
  881. void CNewGameDialog::PostScroll( EScrollDirection dir )
  882. {
  883. int index = INVALID_INDEX;
  884. if ( dir == SCROLL_LEFT )
  885. {
  886. index = m_PanelIndex[SLOT_RIGHT];
  887. }
  888. else if ( dir == SCROLL_RIGHT )
  889. {
  890. index = m_PanelIndex[SLOT_LEFT];
  891. }
  892. // Fade in the revealed panel
  893. if ( index != INVALID_INDEX )
  894. {
  895. CGameChapterPanel *panel = m_ChapterPanels[index];
  896. panel->SetZPos( 50 );
  897. GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  898. }
  899. if ( GameUI().IsConsoleUI() )
  900. {
  901. if ( BonusMapsDatabase()->BonusesUnlocked() && m_bScrollToFirstBonusMap )
  902. {
  903. if ( !m_ChapterPanels[ m_PanelIndex[SLOT_CENTER] ]->HasBonus() )
  904. {
  905. // Find the first bonus
  906. ScrollSelectionPanels( SCROLL_LEFT );
  907. }
  908. else
  909. {
  910. // Found a bonus, stop scrolling
  911. m_bScrollToFirstBonusMap = false;
  912. }
  913. }
  914. }
  915. }
  916. //-----------------------------------------------------------------------------
  917. // Purpose: Initiates a panel scroll and starts the animation.
  918. //-----------------------------------------------------------------------------
  919. void CNewGameDialog::ScrollSelectionPanels( EScrollDirection dir )
  920. {
  921. // Only initiate a scroll if panels aren't currently scrolling
  922. if ( !m_bScrolling )
  923. {
  924. // Handle any pre-scroll setup
  925. PreScroll( dir );
  926. if ( dir == SCROLL_LEFT)
  927. {
  928. m_ScrollCt += SCROLL_LEFT;
  929. }
  930. else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 )
  931. {
  932. m_ScrollCt += SCROLL_RIGHT;
  933. }
  934. m_bScrolling = true;
  935. AnimateSelectionPanels();
  936. // Update the arrow colors, help text, and buttons. Doing it here looks better than having
  937. // the components change after the entire scroll animation has finished.
  938. UpdateMenuComponents( m_ScrollDirection );
  939. }
  940. }
  941. void CNewGameDialog::ScrollBonusSelection( EScrollDirection dir )
  942. {
  943. // Don't scroll if there's no bonuses for this panel
  944. if ( !m_pBonusMapDescription )
  945. return;
  946. m_iBonusSelection += dir;
  947. vgui::surface()->PlaySound( "UI/buttonclick.wav" );
  948. UpdateBonusSelection();
  949. }
  950. //-----------------------------------------------------------------------------
  951. // Purpose: Initiates the scripted scroll and fade effects of all five slotted panels
  952. //-----------------------------------------------------------------------------
  953. void CNewGameDialog::AnimateSelectionPanels( void )
  954. {
  955. int idxOffset = 0;
  956. int startIdx = SLOT_LEFT;
  957. int endIdx = SLOT_RIGHT;
  958. // Don't scroll outside the bounds of the panel list
  959. if ( m_ScrollCt >= SCROLL_LEFT && (m_PanelIndex[SLOT_CENTER] < m_ChapterPanels.Count() - 1 || !GameUI().IsConsoleUI()) )
  960. {
  961. idxOffset = -1;
  962. endIdx = SLOT_OFFRIGHT;
  963. m_ScrollDirection = SCROLL_LEFT;
  964. }
  965. else if ( m_ScrollCt <= SCROLL_RIGHT && (m_PanelIndex[SLOT_CENTER] > 0 || !GameUI().IsConsoleUI()) )
  966. {
  967. idxOffset = 1;
  968. startIdx = SLOT_OFFLEFT;
  969. m_ScrollDirection = SCROLL_RIGHT;
  970. }
  971. if ( 0 == idxOffset )
  972. {
  973. // Kill the scroll, it's outside the bounds
  974. m_ScrollCt = 0;
  975. m_bScrolling = false;
  976. m_ScrollDirection = SCROLL_NONE;
  977. vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
  978. return;
  979. }
  980. // Should never happen
  981. if ( startIdx > endIdx )
  982. return;
  983. for ( int i = startIdx; i <= endIdx; ++i )
  984. {
  985. if ( m_PanelIndex[i] != INVALID_INDEX )
  986. {
  987. int nextIdx = i + idxOffset;
  988. CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[i] ];
  989. GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  990. GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  991. GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nextIdx], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  992. }
  993. }
  994. if ( GameUI().IsConsoleUI() )
  995. {
  996. vgui::surface()->PlaySound( "UI/buttonclick.wav" );
  997. // Animate the center background panel
  998. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  999. // Crossfade the chapter title labels
  1000. int inactiveTitleIdx = m_ActiveTitleIdx ^ 0x01;
  1001. GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[m_ActiveTitleIdx], "alpha", 255, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  1002. GetAnimationController()->RunAnimationCommand( m_pChapterTitleLabels[inactiveTitleIdx], "alpha", 0, 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_LINEAR );
  1003. // Scrolling up through chapters, offset is negative
  1004. m_iSelectedChapter -= idxOffset;
  1005. }
  1006. PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed );
  1007. }
  1008. //-----------------------------------------------------------------------------
  1009. // Purpose: After a scroll, each panel slot holds the index of a panel that has
  1010. // scrolled to an adjacent slot. This function updates each slot so
  1011. // it holds the index of the panel that is actually in that slot's position.
  1012. //-----------------------------------------------------------------------------
  1013. void CNewGameDialog::ShiftPanelIndices( int offset )
  1014. {
  1015. // Shift all the elements over one slot, then calculate what the last slot's index should be.
  1016. int lastSlot = NUM_SLOTS - 1;
  1017. if ( offset > 0 )
  1018. {
  1019. // Hide the panel that's dropping out of the slots
  1020. if ( IsValidPanel( m_PanelIndex[0] ) )
  1021. {
  1022. m_ChapterPanels[ m_PanelIndex[0] ]->SetVisible( false );
  1023. }
  1024. // Scrolled panels to the right, so shift the indices one slot to the left
  1025. Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) );
  1026. if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
  1027. {
  1028. int num = m_PanelIndex[ lastSlot ] + 1;
  1029. if ( IsValidPanel( num ) )
  1030. {
  1031. m_PanelIndex[lastSlot] = num;
  1032. InitPanelIndexForDisplay( lastSlot );
  1033. }
  1034. else
  1035. {
  1036. m_PanelIndex[lastSlot] = INVALID_INDEX;
  1037. }
  1038. }
  1039. }
  1040. else
  1041. {
  1042. // Hide the panel that's dropping out of the slots
  1043. if ( IsValidPanel( m_PanelIndex[lastSlot] ) )
  1044. {
  1045. m_ChapterPanels[ m_PanelIndex[lastSlot] ]->SetVisible( false );
  1046. }
  1047. // Scrolled panels to the left, so shift the indices one slot to the right
  1048. Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) );
  1049. if ( m_PanelIndex[0] != INVALID_INDEX )
  1050. {
  1051. int num = m_PanelIndex[0] - 1;
  1052. if ( IsValidPanel( num ) )
  1053. {
  1054. m_PanelIndex[0] = num;
  1055. InitPanelIndexForDisplay( 0 );
  1056. }
  1057. else
  1058. {
  1059. m_PanelIndex[0] = INVALID_INDEX;
  1060. }
  1061. }
  1062. }
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. // Purpose: Validates an index into the selection panels vector
  1066. //-----------------------------------------------------------------------------
  1067. bool CNewGameDialog::IsValidPanel( const int idx )
  1068. {
  1069. if ( idx < 0 || idx >= m_ChapterPanels.Count() )
  1070. return false;
  1071. return true;
  1072. }
  1073. //-----------------------------------------------------------------------------
  1074. // Purpose: Sets up a panel's properties before it is displayed
  1075. //-----------------------------------------------------------------------------
  1076. void CNewGameDialog::InitPanelIndexForDisplay( const int idx )
  1077. {
  1078. CGameChapterPanel *panel = m_ChapterPanels[ m_PanelIndex[idx] ];
  1079. if ( panel )
  1080. {
  1081. panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] );
  1082. panel->SetAlpha( m_PanelAlpha[idx] );
  1083. panel->SetVisible( true );
  1084. if ( m_PanelAlpha[idx] )
  1085. {
  1086. panel->SetZPos( 50 );
  1087. }
  1088. }
  1089. }
  1090. //-----------------------------------------------------------------------------
  1091. // Purpose: Sets which scroll speed should be used
  1092. //-----------------------------------------------------------------------------
  1093. void CNewGameDialog::SetFastScroll( bool fast )
  1094. {
  1095. m_ScrollSpeed = fast ? g_ScrollSpeedFast : g_ScrollSpeedSlow;
  1096. }
  1097. //-----------------------------------------------------------------------------
  1098. // Purpose: Checks if a button is being held down, and speeds up the scroll
  1099. //-----------------------------------------------------------------------------
  1100. void CNewGameDialog::ContinueScrolling( void )
  1101. {
  1102. if ( !GameUI().IsConsoleUI() )
  1103. {
  1104. if ( m_PanelIndex[SLOT_CENTER-1] % 3 )
  1105. {
  1106. // m_ButtonPressed = m_ScrollDirection;
  1107. ScrollSelectionPanels( m_ScrollDirection );
  1108. }
  1109. return;
  1110. }
  1111. if ( m_ButtonPressed == m_ScrollDirection )
  1112. {
  1113. SetFastScroll( true );
  1114. ScrollSelectionPanels( m_ScrollDirection );
  1115. }
  1116. else if ( m_ButtonPressed != SCROLL_NONE )
  1117. {
  1118. // The other direction has been pressed - start a slow scroll
  1119. SetFastScroll( false );
  1120. ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed );
  1121. }
  1122. else
  1123. {
  1124. SetFastScroll( false );
  1125. }
  1126. }
  1127. //-----------------------------------------------------------------------------
  1128. // Purpose: Called when a scroll distance of one slot has been completed
  1129. //-----------------------------------------------------------------------------
  1130. void CNewGameDialog::FinishScroll( void )
  1131. {
  1132. // Fade the center bg panel back in
  1133. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  1134. ShiftPanelIndices( m_ScrollDirection );
  1135. m_bScrolling = false;
  1136. m_ScrollCt = 0;
  1137. // End of scroll step
  1138. PostScroll( m_ScrollDirection );
  1139. // Continue scrolling if necessary
  1140. ContinueScrolling();
  1141. }
  1142. //-----------------------------------------------------------------------------
  1143. // Purpose: starts the game at the specified skill level
  1144. //-----------------------------------------------------------------------------
  1145. void CNewGameDialog::StartGame( void )
  1146. {
  1147. if ( m_ChapterPanels.IsValidIndex( m_iSelectedChapter ) )
  1148. {
  1149. char mapcommand[512];
  1150. mapcommand[0] = 0;
  1151. Q_snprintf( mapcommand, sizeof( mapcommand ), "disconnect\ndeathmatch 0\nprogress_enable\nexec %s\n", m_ChapterPanels[m_iSelectedChapter]->GetConfigFile() );
  1152. // Set commentary
  1153. ConVarRef commentary( "commentary" );
  1154. commentary.SetValue( m_bCommentaryMode );
  1155. ConVarRef sv_cheats( "sv_cheats" );
  1156. sv_cheats.SetValue( m_bCommentaryMode );
  1157. if ( IsPC() )
  1158. {
  1159. // If commentary is on, we go to the explanation dialog (but not for teaser trailers)
  1160. if ( m_bCommentaryMode && !m_ChapterPanels[m_iSelectedChapter]->IsTeaserChapter() )
  1161. {
  1162. DHANDLE<CCommentaryExplanationDialog> hCommentaryExplanationDialog;
  1163. if ( !hCommentaryExplanationDialog.Get() )
  1164. {
  1165. hCommentaryExplanationDialog = new CCommentaryExplanationDialog( BasePanel(), mapcommand );
  1166. }
  1167. hCommentaryExplanationDialog->Activate();
  1168. }
  1169. else
  1170. {
  1171. // start map
  1172. BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand );
  1173. }
  1174. }
  1175. else if ( IsGameConsole() )
  1176. {
  1177. if ( m_ChapterPanels[m_iSelectedChapter]->HasBonus() && m_iBonusSelection > 0 )
  1178. {
  1179. if ( m_iBonusSelection == 1 )
  1180. {
  1181. // Run the advanced chamber instead of the config file
  1182. char *pLastSpace = Q_strrchr( mapcommand, '\n' );
  1183. pLastSpace[ 0 ] = '\0';
  1184. pLastSpace = Q_strrchr( mapcommand, '\n' );
  1185. Q_snprintf( pLastSpace, sizeof( mapcommand ) - Q_strlen( mapcommand ), "\nmap %s_advanced\n", m_pBonusMapDescription->szMapFileName );
  1186. }
  1187. else
  1188. {
  1189. char sz[ 256 ];
  1190. int iChallenge = m_iBonusSelection - 1;
  1191. // Set up the challenge mode
  1192. Q_snprintf( sz, sizeof( sz ), "sv_bonus_challenge %i\n", iChallenge );
  1193. engine->ClientCmd_Unrestricted( sz );
  1194. ChallengeDescription_t *pChallengeDescription = &((*m_pBonusMapDescription->m_pChallenges)[ iChallenge - 1 ]);
  1195. // Set up medal goals
  1196. BonusMapsDatabase()->SetCurrentChallengeObjectives( pChallengeDescription->iBronze, pChallengeDescription->iSilver, pChallengeDescription->iGold );
  1197. BonusMapsDatabase()->SetCurrentChallengeNames( m_pBonusMapDescription->szFileName, m_pBonusMapDescription->szMapName, pChallengeDescription->szName );
  1198. }
  1199. }
  1200. m_bMapStarting = true;
  1201. BasePanel()->FadeToBlackAndRunEngineCommand( mapcommand );
  1202. }
  1203. OnClose();
  1204. }
  1205. }
  1206. void CNewGameDialog::OnClose( void )
  1207. {
  1208. if ( GameUI().IsConsoleUI() && !m_bMapStarting )
  1209. {
  1210. BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" );
  1211. BonusMapsDatabase()->WriteSaveData(); // Closing this dialog is a good time to save
  1212. }
  1213. BaseClass::OnClose();
  1214. }
  1215. //-----------------------------------------------------------------------------
  1216. // Purpose: handles button commands
  1217. //-----------------------------------------------------------------------------
  1218. void CNewGameDialog::OnCommand( const char *command )
  1219. {
  1220. if ( !stricmp( command, "Play" ) )
  1221. {
  1222. if ( m_bMapStarting )
  1223. return;
  1224. if ( GameUI().IsConsoleUI() )
  1225. {
  1226. if ( m_ChapterPanels[m_iSelectedChapter]->IsEnabled() )
  1227. {
  1228. if ( !GameUI().HasSavedThisMenuSession() && GameUI().IsInLevel() && engine->GetMaxClients() == 1 )
  1229. {
  1230. vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
  1231. BasePanel()->ShowMessageDialog( MD_SAVE_BEFORE_NEW_GAME, this );
  1232. }
  1233. else
  1234. {
  1235. OnCommand( "StartNewGame" );
  1236. }
  1237. }
  1238. else
  1239. {
  1240. // This chapter isn't unlocked!
  1241. m_bMapStarting = false;
  1242. vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
  1243. if ( m_bCommentaryMode )
  1244. {
  1245. BasePanel()->ShowMessageDialog( MD_COMMENTARY_CHAPTER_UNLOCK_EXPLANATION, this );
  1246. }
  1247. }
  1248. }
  1249. else
  1250. {
  1251. StartGame();
  1252. }
  1253. }
  1254. #ifdef _GAMECONSOLE
  1255. else if ( !stricmp( command, "StartNewGame" ) )
  1256. {
  1257. ConVarRef commentary( "commentary" );
  1258. if ( m_bCommentaryMode && !commentary.GetBool() )
  1259. {
  1260. // Using the commentary menu, but not already in commentary mode, explain the rules
  1261. PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithCommentaryExplanation" ), 0.2f );
  1262. }
  1263. else
  1264. {
  1265. #pragma message( __FILE__ "(" __LINE__AS_STRING ") : warning custom: Slamming controller for xbox storage id to 0" )
  1266. if ( XBX_GetStorageDeviceId( 0 ) == XBX_INVALID_STORAGE_ID || XBX_GetStorageDeviceId( 0 ) == XBX_STORAGE_DECLINED ||
  1267. !ModInfo().IsSinglePlayerOnly() )
  1268. {
  1269. // Multiplayer or no storage device so don't bore them with autosave details
  1270. m_bMapStarting = true;
  1271. OnCommand( "StartNewGameNoCommentaryExplanation" );
  1272. }
  1273. else
  1274. {
  1275. // Don't allow other inputs
  1276. m_bMapStarting = true;
  1277. // Remind them how autosaves work
  1278. PostMessage( (vgui::Panel*)this, new KeyValues( "command", "command", "StartNewGameWithAutosaveExplanation" ), 0.2f );
  1279. }
  1280. }
  1281. }
  1282. else if ( !stricmp( command, "StartNewGameWithAutosaveExplanation" ) )
  1283. {
  1284. BasePanel()->ShowMessageDialog( MD_AUTOSAVE_EXPLANATION, this );
  1285. }
  1286. else if ( !stricmp( command, "StartNewGameWithCommentaryExplanation" ) )
  1287. {
  1288. if ( ModInfo().IsSinglePlayerOnly() )
  1289. {
  1290. // Don't allow other inputs
  1291. m_bMapStarting = true;
  1292. BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION, this );
  1293. }
  1294. else
  1295. {
  1296. // Don't allow other inputs
  1297. m_bMapStarting = true;
  1298. BasePanel()->ShowMessageDialog( MD_COMMENTARY_EXPLANATION_MULTI, this );
  1299. }
  1300. }
  1301. else if ( !stricmp( command, "StartNewGameNoCommentaryExplanation" ) )
  1302. {
  1303. vgui::surface()->PlaySound( "UI/buttonclickrelease.wav" );
  1304. BasePanel()->RunAnimationWithCallback( this, "CloseNewGameDialog", new KeyValues( "StartGame" ) );
  1305. }
  1306. #endif
  1307. else if ( !stricmp( command, "Next" ) )
  1308. {
  1309. if ( m_bMapStarting )
  1310. return;
  1311. ScrollSelectionPanels( SCROLL_LEFT );
  1312. }
  1313. else if ( !stricmp( command, "Prev" ) )
  1314. {
  1315. if ( m_bMapStarting )
  1316. return;
  1317. ScrollSelectionPanels( SCROLL_RIGHT );
  1318. }
  1319. else if ( !stricmp( command, "Mode_Next" ) )
  1320. {
  1321. if ( m_bMapStarting )
  1322. return;
  1323. ScrollBonusSelection( SCROLL_LEFT );
  1324. }
  1325. else if ( !stricmp( command, "Mode_Prev" ) )
  1326. {
  1327. if ( m_bMapStarting )
  1328. return;
  1329. ScrollBonusSelection( SCROLL_RIGHT );
  1330. }
  1331. else if ( !Q_stricmp( command, "ReleaseModalWindow" ) )
  1332. {
  1333. vgui::surface()->RestrictPaintToSinglePanel(NULL);
  1334. }
  1335. else
  1336. {
  1337. BaseClass::OnCommand( command );
  1338. }
  1339. }
  1340. void CNewGameDialog::PaintBackground()
  1341. {
  1342. if ( !GameUI().IsConsoleUI() )
  1343. {
  1344. BaseClass::PaintBackground();
  1345. return;
  1346. }
  1347. int wide, tall;
  1348. GetSize( wide, tall );
  1349. Color col = GetBgColor();
  1350. DrawBox( 0, 0, wide, tall, col, 1.0f );
  1351. int y = 0;
  1352. if ( m_pChapterTitleLabels[0] )
  1353. {
  1354. // offset by title
  1355. int titleX, titleY, titleWide, titleTall;
  1356. m_pChapterTitleLabels[0]->GetBounds( titleX, titleY, titleWide, titleTall );
  1357. y += titleY + titleTall;
  1358. }
  1359. else
  1360. {
  1361. y = 8;
  1362. }
  1363. // draw an inset
  1364. Color darkColor;
  1365. darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() );
  1366. vgui::surface()->DrawSetColor( darkColor );
  1367. vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 );
  1368. }