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.

1388 lines
43 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "basepanel.h"
  7. #include "savegamedialog.h"
  8. #include "winlite.h" // FILETIME
  9. #include "vgui/ILocalize.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui/ISystem.h"
  12. #include "vgui/IVGui.h"
  13. #include "vgui_controls/AnimationController.h"
  14. #include "vgui_controls/ImagePanel.h"
  15. #include "filesystem.h"
  16. #include "keyvalues.h"
  17. #include "modinfo.h"
  18. #include "engineinterface.h"
  19. #include "gameui_interface.h"
  20. #include "vstdlib/random.h"
  21. #include "savegamebrowserdialog.h"
  22. extern const char *COM_GetModDirectory( void );
  23. //-----------------------------------------------------------------------------
  24. // Purpose:
  25. //-----------------------------------------------------------------------------
  26. CGameSavePanel::CGameSavePanel( CSaveGameBrowserDialog *parent, SaveGameDescription_t *pSaveDesc, bool bCommandPanel )
  27. : BaseClass( parent, "SaveGamePanel" )
  28. {
  29. // Store our save description internally for reference later by our parent
  30. m_SaveInfo = (*pSaveDesc);
  31. m_bNewSavePanel = bCommandPanel;
  32. // Setup our main graphical elements
  33. m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) );
  34. m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) );
  35. // Setup our various labels
  36. m_pChapterTitle = new Label( this, "ChapterLabel", m_SaveInfo.szComment );
  37. m_pTime = new Label( this, "TimeLabel", m_SaveInfo.szFileTime );
  38. m_pElapsedTime = new Label( this, "ElapsedLabel", m_SaveInfo.szElapsedTime );
  39. m_pType = new Label( this, "TypeLabel", m_SaveInfo.szType );
  40. // Make sure we have a chapter description
  41. char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" );
  42. if ( pchChapterName )
  43. {
  44. char szChapterImage[ 256 ];
  45. Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) );
  46. char *ext = Q_strrchr( szChapterImage, '_' );
  47. if ( ext )
  48. {
  49. *ext = '\0';
  50. }
  51. m_pLevelPic->SetImage( szChapterImage );
  52. }
  53. else
  54. {
  55. m_pLevelPic->SetImage( "ui_logo" );
  56. }
  57. // Setup our basic settings
  58. KeyValues *pKeys = NULL;
  59. if ( GameUI().IsConsoleUI() )
  60. {
  61. pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGamePanel.res" );
  62. }
  63. LoadControlSettings( "Resource/SaveGamePanel.res", NULL, pKeys );
  64. int px, py;
  65. m_pLevelPicBorder->GetPos( px, py );
  66. SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() + ( m_pType->GetTall() + 16 ) );
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. CGameSavePanel::~CGameSavePanel( void )
  72. {
  73. if ( m_pLevelPicBorder )
  74. delete m_pLevelPicBorder;
  75. if ( m_pLevelPic )
  76. delete m_pLevelPic;
  77. if ( m_pChapterTitle )
  78. delete m_pChapterTitle;
  79. if ( m_pTime )
  80. delete m_pTime;
  81. if ( m_pElapsedTime )
  82. delete m_pElapsedTime;
  83. if ( m_pType )
  84. delete m_pType;
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. //-----------------------------------------------------------------------------
  89. void CGameSavePanel::ApplySchemeSettings( IScheme *pScheme )
  90. {
  91. m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) );
  92. m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) );
  93. m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 4) );
  94. m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) );
  95. // Turn various labels off if we're the "stubbed" panel
  96. if ( m_bNewSavePanel )
  97. {
  98. m_pTime->SetVisible( false );
  99. m_pElapsedTime->SetVisible( false );
  100. m_pType->SetVisible( false );
  101. }
  102. // Setup our initial state
  103. m_pChapterTitle->SetFgColor( m_TextColor );
  104. m_pTime->SetFgColor( m_TextColor );
  105. m_pElapsedTime->SetFgColor( m_TextColor );
  106. m_pLevelPic->SetFillColor( Color( 0, 0, 0, 255 ) );
  107. m_pLevelPicBorder->SetFillColor( Color( 0, 0, 0, 255 ) );
  108. if ( m_bNewSavePanel )
  109. {
  110. float flScaleAmount = m_pLevelPic->GetScaleAmount();
  111. if ( flScaleAmount <= 0.0f )
  112. flScaleAmount = 1.0f;
  113. // TBD: Draw the game logo here!
  114. int picWide = 64.0f * flScaleAmount;
  115. int picTall = 64.0f * flScaleAmount;
  116. int borderWide = m_pLevelPicBorder->GetWide();
  117. int borderTall = m_pLevelPicBorder->GetTall();
  118. int borderX, borderY;
  119. m_pLevelPicBorder->GetPos( borderX, borderY );
  120. m_pLevelPic->SetPos( borderX + ( ( borderWide - picWide ) / 2 ), borderY + ( ( borderTall - picTall ) / 2 ) );
  121. m_pLevelPic->SetFillColor( Color( 0, 0, 0, 0 ) );
  122. }
  123. BaseClass::ApplySchemeSettings( pScheme );
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose: Overwrite the level description
  127. // Input : *pDesc - Description to use
  128. //-----------------------------------------------------------------------------
  129. void CGameSavePanel::SetDescription( SaveGameDescription_t *pDesc )
  130. {
  131. // Store our save description internally for reference later by our parent
  132. m_SaveInfo = (*pDesc);
  133. // Setup our main graphical elements
  134. m_pChapterTitle->SetText( m_SaveInfo.szComment );
  135. m_pTime->SetText( m_SaveInfo.szFileTime );
  136. m_pElapsedTime->SetText( m_SaveInfo.szElapsedTime );
  137. m_pType->SetText( m_SaveInfo.szType );
  138. // Make sure we have a chapter description
  139. char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" );
  140. if ( pchChapterName )
  141. {
  142. char szChapterImage[ 256 ];
  143. Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) );
  144. char *ext = Q_strrchr( szChapterImage, '_' );
  145. if ( ext )
  146. {
  147. *ext = '\0';
  148. }
  149. m_pLevelPic->SetImage( szChapterImage );
  150. }
  151. }
  152. //
  153. //
  154. //
  155. //
  156. //
  157. //-----------------------------------------------------------------------------
  158. // Purpose: new game chapter selection
  159. //-----------------------------------------------------------------------------
  160. CSaveGameBrowserDialog::CSaveGameBrowserDialog( vgui::Panel *parent )
  161. : BaseClass( parent, "SaveGameDialog" ),
  162. m_bFilterAutosaves( false ),
  163. m_iSelectedSave( -1 ),
  164. m_bScrolling( false ),
  165. m_ScrollCt( 0 ),
  166. m_ScrollSpeed( 0.0f ),
  167. m_ButtonPressed( SCROLL_NONE ),
  168. m_ScrollDirection( SCROLL_NONE ),
  169. m_nDeletedPanel( INVALID_INDEX ),
  170. m_nAddedPanel( INVALID_INDEX ),
  171. m_nUsedStorageSpace( 0 ),
  172. m_bControlDisabled( false )
  173. {
  174. // Setup basic attributes
  175. SetDeleteSelfOnClose( true );
  176. SetSizeable( false );
  177. // Create the backer that highlights the currently selected save
  178. m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) );
  179. m_pCenterBg->SetPaintBackgroundType( 2 );
  180. m_pCenterBg->SetVisible( true );
  181. // Create our button footer
  182. m_pFooter = new vgui::CFooterPanel( parent, "SaveGameFooter" );
  183. // Load our res files from the keyvalue we're holding
  184. KeyValues *pKeys = NULL;
  185. if ( GameUI().IsConsoleUI() )
  186. {
  187. pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGameDialog.res" );
  188. }
  189. LoadControlSettings( "Resource/SaveGameDialog.res", NULL, pKeys );
  190. }
  191. //-----------------------------------------------------------------------------
  192. // Destructor
  193. //-----------------------------------------------------------------------------
  194. CSaveGameBrowserDialog::~CSaveGameBrowserDialog( void )
  195. {
  196. // Release all elements
  197. m_SavePanels.PurgeAndDeleteElements();
  198. // Kill the footer
  199. if ( m_pFooter )
  200. {
  201. delete m_pFooter;
  202. m_pFooter = NULL;
  203. }
  204. if ( m_pCenterBg )
  205. {
  206. delete m_pCenterBg;
  207. m_pCenterBg = NULL;
  208. }
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose: Show the "No save games to display" indication label and hide all browsing UI
  212. //-----------------------------------------------------------------------------
  213. void CSaveGameBrowserDialog::ShowNoSaveGameUI( void )
  214. {
  215. // Show the "no save games" text
  216. vgui::Label *pNoSavesLabel = dynamic_cast<vgui::Label *>(FindChildByName( "NoSavesLabel" ));
  217. if ( pNoSavesLabel )
  218. {
  219. if ( m_bSaveGameIsCorrupt )
  220. {
  221. pNoSavesLabel->SetText("#GameUI_SaveGame_CorruptFile");
  222. }
  223. else
  224. {
  225. pNoSavesLabel->SetText("#GameUI_NoSaveGamesToDisplay");
  226. }
  227. pNoSavesLabel->SetVisible( true );
  228. }
  229. if ( m_pCenterBg )
  230. m_pCenterBg->SetVisible( false );
  231. vgui::Panel *pLeftArrow = FindChildByName( "LeftArrow" );
  232. if ( pLeftArrow )
  233. pLeftArrow->SetVisible( false );
  234. vgui::Panel *pRightArrow = FindChildByName( "RightArrow" );
  235. if ( pRightArrow )
  236. pRightArrow->SetVisible( false );
  237. }
  238. //-----------------------------------------------------------------------------
  239. // Purpose: Hide all "No save games" UI
  240. //-----------------------------------------------------------------------------
  241. void CSaveGameBrowserDialog::HideNoSaveGameUI( void )
  242. {
  243. // Show the "no save games" text
  244. vgui::Panel *pNoSavesLabel = FindChildByName( "NoSavesLabel" );
  245. if ( pNoSavesLabel )
  246. pNoSavesLabel->SetVisible( false );
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose:
  250. //-----------------------------------------------------------------------------
  251. void CSaveGameBrowserDialog::LayoutPanels( void )
  252. {
  253. // Setup our panels depending on the mode we're in
  254. if ( HasActivePanels() )
  255. {
  256. // Hide any indicators about no save games
  257. HideNoSaveGameUI();
  258. // Layout panel positions relative to the dialog center.
  259. int panelWidth = m_SavePanels[0]->GetWide() + 16;
  260. int dialogWidth = GetWide();
  261. m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + 8;
  262. m_PanelXPos[1] = m_PanelXPos[2] - panelWidth;
  263. m_PanelXPos[0] = m_PanelXPos[1];
  264. m_PanelXPos[3] = m_PanelXPos[2] + panelWidth;
  265. m_PanelXPos[4] = m_PanelXPos[3];
  266. m_PanelAlpha[0] = 0;
  267. m_PanelAlpha[1] = 64;
  268. m_PanelAlpha[2] = 255;
  269. m_PanelAlpha[3] = 64;
  270. m_PanelAlpha[4] = 0;
  271. int panelHeight;
  272. m_SavePanels[0]->GetSize( panelWidth, panelHeight );
  273. m_pCenterBg->SetVisible( true );
  274. m_pCenterBg->SetWide( panelWidth + 16 );
  275. m_pCenterBg->SetPos( m_PanelXPos[2] - 8, m_PanelYPos[2] - (panelHeight - m_nCenterBgTallDefault) + 8 );
  276. m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) );
  277. }
  278. else
  279. {
  280. // Hide anything to do with browsing the saves
  281. ShowNoSaveGameUI();
  282. }
  283. // Do internal cleanup to make sure we present a correct state to the user
  284. UpdateMenuComponents( SCROLL_NONE );
  285. UpdateFooterOptions();
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Purpose: Do a fancy slide-out when we're first displayed
  289. //-----------------------------------------------------------------------------
  290. void CSaveGameBrowserDialog::AnimateDialogStart( void )
  291. {
  292. const float flAnimInTime = 0.5f;
  293. const float flOffset = 0.1f;
  294. for ( int i = 0; i < NUM_SLOTS; i++ )
  295. {
  296. if ( m_PanelIndex[i] == INVALID_INDEX )
  297. continue;
  298. // Start us at the "opening" position
  299. CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[i] ];
  300. if ( panel )
  301. {
  302. panel->SetPos( m_PanelXPos[0], m_PanelYPos[0] );
  303. panel->SetAlpha( m_PanelAlpha[0] );
  304. panel->SetVisible( true );
  305. panel->SetEnabled( true );
  306. panel->SetZPos( NUM_SLOTS - i );
  307. }
  308. // Now make them slide out where they're going
  309. GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  310. GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  311. // Panel alpha
  312. GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  313. }
  314. // Move and fade the back label
  315. m_pCenterBg->SetAlpha( 0 );
  316. int nX, nY;
  317. m_pCenterBg->GetPos( nX, nY );
  318. m_pCenterBg->SetPos( nX-m_pCenterBg->GetWide(), nY );
  319. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "xpos", nX, 0, flAnimInTime + (flOffset*2), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  320. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, (flAnimInTime+ (flOffset*2))*2.0f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  321. CGameSavePanel *selectedPanel = GetActivePanel();
  322. if ( selectedPanel && selectedPanel->IsAutoSaveType() )
  323. {
  324. m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 );
  325. }
  326. else
  327. {
  328. m_pCenterBg->SetTall( m_nCenterBgTallDefault );
  329. }
  330. }
  331. //-----------------------------------------------------------------------------
  332. // Purpose: Do our initial layout
  333. //-----------------------------------------------------------------------------
  334. void CSaveGameBrowserDialog::Activate( void )
  335. {
  336. // Start scanning for saved games
  337. ScanSavedGames( m_bFilterAutosaves );
  338. // Finish our layout depending on what the result of the scan was
  339. LayoutPanels();
  340. // Animate the opening animation
  341. AnimateDialogStart();
  342. BaseClass::Activate();
  343. }
  344. //-----------------------------------------------------------------------------
  345. // Purpose: Apply special properties of the menu
  346. //-----------------------------------------------------------------------------
  347. void CSaveGameBrowserDialog::ApplySettings( KeyValues *inResourceData )
  348. {
  349. BaseClass::ApplySettings( inResourceData );
  350. int ypos = inResourceData->GetInt( "chapterypos", 20 );
  351. for ( int i = 0; i < NUM_SLOTS; ++i )
  352. {
  353. m_PanelYPos[i] = ypos;
  354. }
  355. m_nCenterBgTallDefault = inResourceData->GetInt( "centerbgtall", 0 );
  356. m_pCenterBg->SetTall( m_nCenterBgTallDefault );
  357. m_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f );
  358. m_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f );
  359. SetFastScroll( false );
  360. }
  361. //-----------------------------------------------------------------------------
  362. // Purpose: Apply scheme settings
  363. //-----------------------------------------------------------------------------
  364. void CSaveGameBrowserDialog::ApplySchemeSettings( vgui::IScheme *pScheme )
  365. {
  366. BaseClass::ApplySchemeSettings( pScheme );
  367. UpdateMenuComponents( SCROLL_NONE );
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose: sets the correct properties for visible components
  371. //-----------------------------------------------------------------------------
  372. void CSaveGameBrowserDialog::UpdateMenuComponents( EScrollDirection dir )
  373. {
  374. // This is called prior to any scrolling, so we need to look ahead to the post-scroll state
  375. int centerIdx = SLOT_CENTER;
  376. // Scroll given our direction of travel
  377. if ( dir == SCROLL_LEFT )
  378. {
  379. ++centerIdx;
  380. }
  381. else if ( dir == SCROLL_RIGHT )
  382. {
  383. --centerIdx;
  384. }
  385. int leftIdx = centerIdx - 1;
  386. int rightIdx = centerIdx + 1;
  387. // Update the state of the side arrows depending on whether or not we can scroll that direction
  388. vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" );
  389. vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" );
  390. if ( leftArrow )
  391. {
  392. leftArrow->SetVisible( true );
  393. if ( m_PanelIndex[leftIdx] != INVALID_INDEX )
  394. {
  395. leftArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  396. }
  397. else
  398. {
  399. leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
  400. }
  401. }
  402. if ( rightArrow )
  403. {
  404. rightArrow->SetVisible( true );
  405. if ( m_PanelIndex[rightIdx] != INVALID_INDEX )
  406. {
  407. rightArrow->SetFgColor( Color( 255, 255, 255, 255 ) );
  408. }
  409. else
  410. {
  411. rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) );
  412. }
  413. }
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Purpose: sets a chapter as selected
  417. //-----------------------------------------------------------------------------
  418. void CSaveGameBrowserDialog::SetSelectedSaveIndex( int index )
  419. {
  420. m_iSelectedSave = index;
  421. // If we have no panels, there's nothing to update
  422. if ( HasActivePanels() == false )
  423. return;
  424. // Setup panels to the left of the selected panel
  425. int currIdx = index;
  426. for ( int i = SLOT_CENTER; i >= 0 && currIdx >= 0; --i )
  427. {
  428. m_PanelIndex[i] = currIdx;
  429. --currIdx;
  430. InitPanelIndexForDisplay( i );
  431. }
  432. // Setup panels to the right of the selected panel
  433. currIdx = index + 1;
  434. for ( int i = SLOT_CENTER + 1; i < NUM_SLOTS && currIdx < m_SavePanels.Count(); ++i )
  435. {
  436. m_PanelIndex[i] = currIdx;
  437. ++currIdx;
  438. InitPanelIndexForDisplay( i );
  439. }
  440. UpdateMenuComponents( SCROLL_NONE );
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose: Remove the currently selected animation from the list with proper animations
  444. //-----------------------------------------------------------------------------
  445. void CSaveGameBrowserDialog::RemoveActivePanel( void )
  446. {
  447. // Kill the current panel
  448. m_nDeletedPanel = m_PanelIndex[SLOT_CENTER];
  449. // Start our current panel fading
  450. CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ];
  451. GetAnimationController()->RunAnimationCommand( pPanel, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL );
  452. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL );
  453. PostMessage( this, new KeyValues( "FinishDelete" ), m_ScrollSpeed );
  454. }
  455. //-----------------------------------------------------------------------------
  456. // Purpose:
  457. //-----------------------------------------------------------------------------
  458. void CSaveGameBrowserDialog::CloseAfterSave( void )
  459. {
  460. OnCommand( "CloseAndSelectResume" );
  461. }
  462. //-----------------------------------------------------------------------------
  463. // Purpose:
  464. //-----------------------------------------------------------------------------
  465. void CSaveGameBrowserDialog::FinishInsert( void )
  466. {
  467. CGameSavePanel *panel = m_SavePanels[ m_nAddedPanel ];
  468. const float flScrollSpeed = 0.75f;
  469. // Run the actual movement
  470. GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  471. GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  472. // Panel alpha
  473. GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  474. PostMessage( this, new KeyValues( "CloseAfterSave" ), flScrollSpeed*2.0f );
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose: Insert a new panel at the desired location
  478. //-----------------------------------------------------------------------------
  479. void CSaveGameBrowserDialog::AnimateInsertNewPanel( const SaveGameDescription_t *pDesc )
  480. {
  481. // This is the panel that's going to move
  482. CGameSavePanel *pNewPanel = SETUP_PANEL( new CGameSavePanel( this, (SaveGameDescription_t *) pDesc ) );
  483. pNewPanel->SetVisible( false );
  484. // Tack this onto the list
  485. m_nAddedPanel = m_SavePanels.InsertAfter( 0, pNewPanel );
  486. // Set it up but turn it off immediately
  487. pNewPanel->SetPos( m_PanelXPos[SLOT_CENTER], m_PanelYPos[SLOT_CENTER] );
  488. pNewPanel->SetVisible( true );
  489. pNewPanel->SetEnabled( true );
  490. pNewPanel->SetZPos( 0 );
  491. pNewPanel->SetAlpha( 0.0f );
  492. // Increment our indices to reflect the change
  493. for ( int i = 0; i < NUM_SLOTS; i++ )
  494. {
  495. if ( m_PanelIndex[i] == INVALID_INDEX )
  496. continue;
  497. if ( m_PanelIndex[i] > 0 )
  498. {
  499. m_PanelIndex[i]++;
  500. }
  501. }
  502. // Fade the right panel away
  503. if ( IsValidPanel( m_PanelIndex[ SLOT_RIGHT ] ) )
  504. {
  505. CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ SLOT_RIGHT ] ];
  506. // Run the actual movement
  507. GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  508. GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  509. // Panel alpha
  510. GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  511. PostMessage( this, new KeyValues( "FinishInsert" ), m_ScrollSpeed );
  512. }
  513. else
  514. {
  515. PostMessage( this, new KeyValues( "FinishInsert" ), 0.1f );
  516. }
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Purpose: Pop in the new description
  520. //-----------------------------------------------------------------------------
  521. void CSaveGameBrowserDialog::FinishOverwriteFadeDown( void )
  522. {
  523. const float flFadeInTime = 0.25f;
  524. // Fade the right panel away
  525. CGameSavePanel *pActivePanel = GetActivePanel();
  526. if ( pActivePanel )
  527. {
  528. pActivePanel->SetDescription( &m_NewSaveGameDesc );
  529. // Panel alpha
  530. GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", m_PanelAlpha[SLOT_CENTER], 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  531. }
  532. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  533. PostMessage( this, new KeyValues( "CloseAfterSave" ), flFadeInTime + 0.1f );
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose: Animate an overwrite event by fading out the old panel and bringing it back with a new description
  537. // Input : *pNewDesc - The new description to display
  538. //-----------------------------------------------------------------------------
  539. void CSaveGameBrowserDialog::AnimateOverwriteActivePanel( const SaveGameDescription_t *pNewDesc )
  540. {
  541. // Save a copy of this description
  542. m_NewSaveGameDesc = (*pNewDesc);
  543. // Fade the right panel away
  544. CGameSavePanel *pActivePanel = GetActivePanel();
  545. if ( pActivePanel )
  546. {
  547. // Panel alpha
  548. GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  549. }
  550. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  551. PostMessage( this, new KeyValues( "FinishOverwriteFadeDown" ), 0.75f );
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose: Called before a panel scroll starts.
  555. //-----------------------------------------------------------------------------
  556. void CSaveGameBrowserDialog::PreScroll( EScrollDirection dir )
  557. {
  558. int hideIdx = INVALID_INDEX;
  559. if ( m_nDeletedPanel != INVALID_INDEX )
  560. {
  561. hideIdx = m_nDeletedPanel;
  562. }
  563. else if ( dir == SCROLL_LEFT )
  564. {
  565. hideIdx = m_PanelIndex[SLOT_LEFT];
  566. }
  567. else if ( dir == SCROLL_RIGHT )
  568. {
  569. hideIdx = m_PanelIndex[SLOT_RIGHT];
  570. }
  571. if ( hideIdx != INVALID_INDEX )
  572. {
  573. // Push back the panel that's about to be hidden
  574. // so the next panel scrolls over the top of it.
  575. m_SavePanels[hideIdx]->SetZPos( 0 );
  576. }
  577. }
  578. //-----------------------------------------------------------------------------
  579. // Purpose: Called after a panel scroll finishes.
  580. //-----------------------------------------------------------------------------
  581. void CSaveGameBrowserDialog::PostScroll( EScrollDirection dir )
  582. {
  583. // FIXME: Nothing to do here...
  584. }
  585. //-----------------------------------------------------------------------------
  586. // Purpose: Initiates a panel scroll and starts the animation.
  587. //-----------------------------------------------------------------------------
  588. void CSaveGameBrowserDialog::ScrollSelectionPanels( EScrollDirection dir )
  589. {
  590. // Only initiate a scroll if panels aren't currently scrolling
  591. if ( !m_bScrolling )
  592. {
  593. // Handle any pre-scroll setup
  594. PreScroll( dir );
  595. if ( dir == SCROLL_LEFT)
  596. {
  597. m_ScrollCt += SCROLL_LEFT;
  598. }
  599. else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 )
  600. {
  601. m_ScrollCt += SCROLL_RIGHT;
  602. }
  603. m_bScrolling = true;
  604. AnimateSelectionPanels();
  605. // Update the arrow colors, help text, and buttons. Doing it here looks better than having
  606. // the components change after the entire scroll animation has finished.
  607. UpdateMenuComponents( m_ScrollDirection );
  608. }
  609. }
  610. //-----------------------------------------------------------------------------
  611. // Purpose: Do all slide animation work here
  612. // Input : nPanelIndex - Panel we're currently operating on
  613. // nNextPanelIndex - Panel we're going to be moving over
  614. //-----------------------------------------------------------------------------
  615. void CSaveGameBrowserDialog::PerformSlideAction( int nPanelIndex, int nNextPanelIndex )
  616. {
  617. CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ nPanelIndex ] ];
  618. // Run the actual movement
  619. GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  620. GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  621. // Panel alpha
  622. GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  623. }
  624. //-----------------------------------------------------------------------------
  625. // Purpose: Initiates the scripted scroll and fade effects of all five slotted panels
  626. //-----------------------------------------------------------------------------
  627. void CSaveGameBrowserDialog::AnimateSelectionPanels( void )
  628. {
  629. int idxOffset = 0;
  630. int startIdx = SLOT_LEFT;
  631. int endIdx = SLOT_RIGHT;
  632. // Don't scroll outside the bounds of the panel list
  633. if ( m_ScrollCt >= SCROLL_LEFT && m_PanelIndex[SLOT_CENTER] < m_SavePanels.Count() - 1 )
  634. {
  635. if ( m_nDeletedPanel != INVALID_INDEX )
  636. {
  637. startIdx = SLOT_RIGHT;
  638. }
  639. idxOffset = -1;
  640. endIdx = SLOT_OFFRIGHT;
  641. m_ScrollDirection = SCROLL_LEFT;
  642. }
  643. else if ( m_ScrollCt <= SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] > 0 )
  644. {
  645. idxOffset = 1;
  646. startIdx = SLOT_OFFLEFT;
  647. m_ScrollDirection = SCROLL_RIGHT;
  648. }
  649. if ( 0 == idxOffset )
  650. {
  651. // Kill the scroll, it's outside the bounds
  652. m_ScrollCt = 0;
  653. m_bScrolling = false;
  654. m_ScrollDirection = SCROLL_NONE;
  655. vgui::surface()->PlaySound( "player/suit_denydevice.wav" );
  656. return;
  657. }
  658. // Should never happen
  659. if ( startIdx > endIdx )
  660. return;
  661. for ( int i = startIdx; i <= endIdx; ++i )
  662. {
  663. // Don't animate the special panel, just skip it
  664. if ( m_PanelIndex[i] == m_nDeletedPanel )
  665. continue;
  666. int nNextIdx = i+idxOffset;
  667. if ( m_PanelIndex[i] != INVALID_INDEX )
  668. {
  669. PerformSlideAction( i, nNextIdx );
  670. }
  671. }
  672. vgui::surface()->PlaySound( "UI/buttonclick.wav" );
  673. // Animate the center background panel
  674. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE );
  675. // Scrolling up through chapters, offset is negative
  676. m_iSelectedSave -= idxOffset;
  677. UpdateFooterOptions();
  678. PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed );
  679. }
  680. //-----------------------------------------------------------------------------
  681. // Purpose: After a scroll, each panel slot holds the index of a panel that has
  682. // scrolled to an adjacent slot. This function updates each slot so
  683. // it holds the index of the panel that is actually in that slot's position.
  684. //-----------------------------------------------------------------------------
  685. void CSaveGameBrowserDialog::ShiftPanelIndices( int offset )
  686. {
  687. // Shift all the elements over one slot, then calculate what the last slot's index should be.
  688. int lastSlot = NUM_SLOTS - 1;
  689. // Handle the deletion case
  690. if ( m_nDeletedPanel != INVALID_INDEX )
  691. {
  692. // Scroll panels in from the right
  693. Q_memmove( &m_PanelIndex[SLOT_CENTER], &m_PanelIndex[SLOT_RIGHT], 2* sizeof( m_PanelIndex[SLOT_CENTER] ) );
  694. if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
  695. {
  696. int num = m_PanelIndex[ lastSlot ] + 1;
  697. if ( IsValidPanel( num ) )
  698. {
  699. m_PanelIndex[lastSlot] = num;
  700. InitPanelIndexForDisplay( lastSlot );
  701. }
  702. else
  703. {
  704. m_PanelIndex[lastSlot] = INVALID_INDEX;
  705. }
  706. }
  707. }
  708. else if ( offset > 0 )
  709. {
  710. // Hide the panel that's dropping out of the slots
  711. if ( IsValidPanel( m_PanelIndex[0] ) )
  712. {
  713. m_SavePanels[ m_PanelIndex[0] ]->SetVisible( false );
  714. }
  715. // Scrolled panels to the right, so shift the indices one slot to the left
  716. Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) );
  717. if ( m_PanelIndex[lastSlot] != INVALID_INDEX )
  718. {
  719. int num = m_PanelIndex[ lastSlot ] + 1;
  720. if ( IsValidPanel( num ) )
  721. {
  722. m_PanelIndex[lastSlot] = num;
  723. InitPanelIndexForDisplay( lastSlot );
  724. }
  725. else
  726. {
  727. m_PanelIndex[lastSlot] = INVALID_INDEX;
  728. }
  729. }
  730. }
  731. else
  732. {
  733. // Hide the panel that's dropping out of the slots
  734. if ( IsValidPanel( m_PanelIndex[lastSlot] ) )
  735. {
  736. m_SavePanels[ m_PanelIndex[lastSlot] ]->SetVisible( false );
  737. }
  738. // Scrolled panels to the left, so shift the indices one slot to the right
  739. Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) );
  740. if ( m_PanelIndex[0] != INVALID_INDEX )
  741. {
  742. int num = m_PanelIndex[0] - 1;
  743. if ( IsValidPanel( num ) )
  744. {
  745. m_PanelIndex[0] = num;
  746. InitPanelIndexForDisplay( 0 );
  747. }
  748. else
  749. {
  750. m_PanelIndex[0] = INVALID_INDEX;
  751. }
  752. }
  753. }
  754. }
  755. //-----------------------------------------------------------------------------
  756. // Purpose: Validates an index into the selection panels vector
  757. //-----------------------------------------------------------------------------
  758. bool CSaveGameBrowserDialog::IsValidPanel( const int idx )
  759. {
  760. if ( idx < 0 || idx >= m_SavePanels.Count() )
  761. return false;
  762. return true;
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Purpose: Sets up a panel's properties before it is displayed
  766. //-----------------------------------------------------------------------------
  767. void CSaveGameBrowserDialog::InitPanelIndexForDisplay( const int idx )
  768. {
  769. CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[idx] ];
  770. if ( panel )
  771. {
  772. panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] );
  773. panel->SetAlpha( m_PanelAlpha[idx] );
  774. panel->SetVisible( true );
  775. panel->SetEnabled( true );
  776. if ( m_PanelAlpha[idx] )
  777. {
  778. panel->SetZPos( NUM_SLOTS );
  779. }
  780. }
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Purpose: Sets which scroll speed should be used
  784. //-----------------------------------------------------------------------------
  785. void CSaveGameBrowserDialog::SetFastScroll( bool fast )
  786. {
  787. m_ScrollSpeed = fast ? m_ScrollSpeedFast : m_ScrollSpeedSlow;
  788. }
  789. //-----------------------------------------------------------------------------
  790. // Purpose: Checks if a button is being held down, and speeds up the scroll
  791. //-----------------------------------------------------------------------------
  792. void CSaveGameBrowserDialog::ContinueScrolling( void )
  793. {
  794. if ( !GameUI().IsConsoleUI() )
  795. {
  796. if ( m_PanelIndex[SLOT_CENTER-1] % 3 )
  797. {
  798. ScrollSelectionPanels( m_ScrollDirection );
  799. }
  800. return;
  801. }
  802. if ( m_ButtonPressed == m_ScrollDirection )
  803. {
  804. SetFastScroll( true );
  805. ScrollSelectionPanels( m_ScrollDirection );
  806. }
  807. else if ( m_ButtonPressed != SCROLL_NONE )
  808. {
  809. // The other direction has been pressed - start a slow scroll
  810. SetFastScroll( false );
  811. ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed );
  812. }
  813. else
  814. {
  815. SetFastScroll( false );
  816. }
  817. }
  818. //-----------------------------------------------------------------------------
  819. // Purpose: Fade animation has finished, now slide or be done
  820. //-----------------------------------------------------------------------------
  821. void CSaveGameBrowserDialog::FinishDelete( void )
  822. {
  823. // Catch the case where all saves are now gone!
  824. if ( m_SavePanels.Count() == 1 )
  825. {
  826. m_nDeletedPanel = INVALID_INDEX;
  827. m_SavePanels.PurgeAndDeleteElements();
  828. for ( int i = 0; i < NUM_SLOTS; i++ )
  829. {
  830. m_PanelIndex[i] = INVALID_INDEX;
  831. }
  832. LayoutPanels();
  833. return;
  834. }
  835. EScrollDirection nDirection = ( IsValidPanel( m_nDeletedPanel + 1 ) ) ? SCROLL_LEFT : SCROLL_RIGHT;
  836. ScrollSelectionPanels( nDirection );
  837. }
  838. //-----------------------------------------------------------------------------
  839. // Purpose: Called when a scroll distance of one slot has been completed
  840. //-----------------------------------------------------------------------------
  841. void CSaveGameBrowserDialog::FinishScroll( void )
  842. {
  843. // Fade the center bg panel back in
  844. GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR );
  845. ShiftPanelIndices( m_ScrollDirection );
  846. m_bScrolling = false;
  847. m_ScrollCt = 0;
  848. // End of scroll step
  849. PostScroll( m_ScrollDirection );
  850. if ( m_nDeletedPanel != INVALID_INDEX )
  851. {
  852. // Find where we're going next
  853. int newSave = m_nDeletedPanel;
  854. if ( m_SavePanels.IsValidIndex( m_nDeletedPanel + 1 ) == false )
  855. {
  856. newSave = m_nDeletedPanel - 1;
  857. }
  858. // Remove it from our list
  859. CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ];
  860. m_SavePanels.Remove( m_nDeletedPanel );
  861. delete pPanel;
  862. // Decrement all the indices to reflect the change
  863. for ( int i = 0; i < NUM_SLOTS; i++ )
  864. {
  865. if ( m_PanelIndex[i] > m_nDeletedPanel )
  866. m_PanelIndex[i]--;
  867. }
  868. // Clear the spot and be done with it
  869. SetSelectedSaveIndex( newSave );
  870. m_nDeletedPanel = INVALID_INDEX;
  871. UpdateMenuComponents( SCROLL_NONE );
  872. }
  873. // Size the "autosave" blade if need-be
  874. CGameSavePanel *selectedPanel = GetActivePanel();
  875. if ( selectedPanel && selectedPanel->IsAutoSaveType() )
  876. {
  877. m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 );
  878. }
  879. else
  880. {
  881. m_pCenterBg->SetTall( m_nCenterBgTallDefault );
  882. }
  883. // Continue scrolling if necessary
  884. ContinueScrolling();
  885. }
  886. //-----------------------------------------------------------------------------
  887. // Purpose:
  888. //-----------------------------------------------------------------------------
  889. void CSaveGameBrowserDialog::OnClose( void )
  890. {
  891. SetControlDisabled( true );
  892. BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" );
  893. BaseClass::OnClose();
  894. }
  895. //-----------------------------------------------------------------------------
  896. // Purpose: Our save games have changed, so layout our panel again
  897. //-----------------------------------------------------------------------------
  898. void CSaveGameBrowserDialog::RefreshSaveGames( void )
  899. {
  900. // Close any pending messages
  901. BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING );
  902. // Don't leave us in a locked state
  903. SetControlDisabled( false );
  904. // Re-scan the saved games
  905. ScanSavedGames( m_bFilterAutosaves );
  906. // Re-layout the panels
  907. LayoutPanels();
  908. // Run our animation again
  909. AnimateDialogStart();
  910. }
  911. //-----------------------------------------------------------------------------
  912. // Purpose:
  913. //-----------------------------------------------------------------------------
  914. void CSaveGameBrowserDialog::PerformSelectedAction( void )
  915. {
  916. // By default, do nothing
  917. }
  918. //-----------------------------------------------------------------------------
  919. // Purpose:
  920. //-----------------------------------------------------------------------------
  921. void CSaveGameBrowserDialog::PerformDeletion( void )
  922. {
  923. // By default, do nothing
  924. }
  925. //-----------------------------------------------------------------------------
  926. // Purpose:
  927. //-----------------------------------------------------------------------------
  928. void CSaveGameBrowserDialog::OnKeyCodePressed( vgui::KeyCode code )
  929. {
  930. // If the console has UI up, then ignore it
  931. if ( BasePanel()->IsWaitingForConsoleUI() )
  932. return;
  933. // Inhibit key activity during transitions
  934. if ( GetAlpha() != 255 || m_bControlDisabled )
  935. return;
  936. switch( code )
  937. {
  938. case KEY_XBUTTON_A:
  939. PerformSelectedAction();
  940. break;
  941. case KEY_XBUTTON_B:
  942. OnClose();
  943. break;
  944. case KEY_XBUTTON_X:
  945. PerformDeletion();
  946. break;
  947. case KEY_XBUTTON_Y:
  948. BasePanel()->OnChangeStorageDevice();
  949. break;
  950. // Move the selection up and down
  951. case KEY_XSTICK1_LEFT:
  952. case KEY_XBUTTON_LEFT:
  953. ScrollSelectionPanels( SCROLL_RIGHT );
  954. break;
  955. case KEY_XSTICK1_RIGHT:
  956. case KEY_XBUTTON_RIGHT:
  957. ScrollSelectionPanels( SCROLL_LEFT );
  958. break;
  959. default:
  960. break;
  961. }
  962. }
  963. //-----------------------------------------------------------------------------
  964. // Purpose:
  965. //-----------------------------------------------------------------------------
  966. void CSaveGameBrowserDialog::PaintBackground( void )
  967. {
  968. int wide, tall;
  969. GetSize( wide, tall );
  970. Color col = GetBgColor();
  971. DrawBox( 0, 0, wide, tall, col, 1.0f );
  972. int y = 32;
  973. // draw an inset
  974. Color darkColor;
  975. darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() );
  976. vgui::surface()->DrawSetColor( darkColor );
  977. vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 );
  978. }
  979. //-----------------------------------------------------------------------------
  980. // Purpose: Parses the save game info out of the .sav file header
  981. //-----------------------------------------------------------------------------
  982. bool CSaveGameBrowserDialog::ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t *save )
  983. {
  984. char szMapName[SAVEGAME_MAPNAME_LEN];
  985. char szComment[SAVEGAME_COMMENT_LEN];
  986. char szElapsedTime[SAVEGAME_ELAPSED_LEN];
  987. if ( !pszFileName || !pszShortName )
  988. return false;
  989. Q_strncpy( save->szShortName, pszShortName, sizeof(save->szShortName) );
  990. Q_strncpy( save->szFileName, pszFileName, sizeof(save->szFileName) );
  991. FileHandle_t fh = g_pFullFileSystem->Open( pszFileName, "rb", "MOD" );
  992. if (fh == FILESYSTEM_INVALID_HANDLE)
  993. return false;
  994. save->iSize = g_pFullFileSystem->Size( fh );
  995. int readok = SaveReadNameAndComment( fh, szMapName, szComment );
  996. g_pFullFileSystem->Close(fh);
  997. if ( !readok )
  998. {
  999. return false;
  1000. }
  1001. Q_strncpy( save->szMapName, szMapName, sizeof(save->szMapName) );
  1002. // Elapsed time is the last 6 characters in comment. (mmm:ss)
  1003. int i;
  1004. i = strlen( szComment );
  1005. Q_strncpy( szElapsedTime, "??", sizeof( szElapsedTime ) );
  1006. if (i >= 6)
  1007. {
  1008. Q_strncpy( szElapsedTime, (char *)&szComment[i - 6], 7 );
  1009. szElapsedTime[6] = '\0';
  1010. // parse out
  1011. int minutes = atoi( szElapsedTime );
  1012. int seconds = atoi( szElapsedTime + 4);
  1013. int hours = minutes / 60;
  1014. minutes %= 60;
  1015. wchar_t wzHours[6];
  1016. wchar_t wzMins[4];
  1017. wchar_t wzSecs[4];
  1018. _snwprintf( wzHours, ARRAYSIZE(wzHours), L"%d", hours );
  1019. _snwprintf( wzMins, ARRAYSIZE(wzMins), L"%d", minutes );
  1020. _snwprintf( wzSecs, ARRAYSIZE(wzSecs), L"%d", seconds );
  1021. wchar_t buf[20];
  1022. // reformat
  1023. if ( hours )
  1024. {
  1025. g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Hr_Min" ), 2, wzHours, wzMins );
  1026. }
  1027. else if ( minutes )
  1028. {
  1029. g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Min_Sec" ), 2, wzMins, wzSecs );
  1030. }
  1031. else
  1032. {
  1033. g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Sec" ), 1, wzSecs );
  1034. }
  1035. g_pVGuiLocalize->ConvertUnicodeToANSI( buf, szElapsedTime, sizeof(szElapsedTime) );
  1036. // Chop elapsed out of comment.
  1037. char *pChop = Q_stristr( szComment, " " );
  1038. if ( pChop != NULL )
  1039. {
  1040. (*pChop) = '\0';
  1041. }
  1042. }
  1043. // calculate the file name to print
  1044. const char *pszType = "";
  1045. if (strstr(pszFileName, "quick"))
  1046. {
  1047. pszType = "#GameUI_QuickSave";
  1048. }
  1049. else if (strstr(pszFileName, "autosave"))
  1050. {
  1051. pszType = "#GameUI_AutoSave";
  1052. }
  1053. Q_strncpy( save->szType, pszType, sizeof(save->szType) );
  1054. Q_strncpy( save->szComment, szComment, sizeof(save->szComment) );
  1055. Q_strncpy( save->szElapsedTime, szElapsedTime, sizeof(save->szElapsedTime) );
  1056. // Now get file time stamp.
  1057. long fileTime = g_pFullFileSystem->GetFileTime(pszFileName);
  1058. char szFileTime[32];
  1059. g_pFullFileSystem->FileTimeToString(szFileTime, sizeof(szFileTime), fileTime);
  1060. char *newline = strstr(szFileTime, "\n");
  1061. if (newline)
  1062. {
  1063. *newline = 0;
  1064. }
  1065. Q_strncpy( save->szFileTime, szFileTime, sizeof(save->szFileTime) );
  1066. save->iTimestamp = fileTime;
  1067. return true;
  1068. }
  1069. //-----------------------------------------------------------------------------
  1070. // Purpose: Update our footer options depending on what we've selected
  1071. //-----------------------------------------------------------------------------
  1072. void CSaveGameBrowserDialog::UpdateFooterOptions( void )
  1073. {
  1074. // Do nothing
  1075. }
  1076. //-----------------------------------------------------------------------------
  1077. // Purpose: Sort our games by time
  1078. //-----------------------------------------------------------------------------
  1079. void CSaveGameBrowserDialog::SortSaveGames( SaveGameDescription_t *pSaves, unsigned int nNumSaves )
  1080. {
  1081. qsort( pSaves, nNumSaves, sizeof(SaveGameDescription_t), &CBaseSaveGameDialog::SaveGameSortFunc );
  1082. }
  1083. //-----------------------------------------------------------------------------
  1084. // Purpose: builds save game list from directory
  1085. //-----------------------------------------------------------------------------
  1086. void CSaveGameBrowserDialog::ScanSavedGames( bool bIgnoreAutosave )
  1087. {
  1088. // Start with a clean slate
  1089. m_nUsedStorageSpace = 0;
  1090. m_bSaveGameIsCorrupt = false;
  1091. // Clear all known panels I'm holding now
  1092. m_SavePanels.PurgeAndDeleteElements();
  1093. // Reset all indices
  1094. for ( int i = 0; i < NUM_SLOTS; ++i )
  1095. {
  1096. m_PanelIndex[i] = INVALID_INDEX;
  1097. }
  1098. // Clear our list
  1099. CUtlVector<SaveGameDescription_t> saveGames;
  1100. // Get the search path
  1101. char szDirectory[_MAX_PATH];
  1102. if ( IsGameConsole() )
  1103. Q_snprintf( szDirectory, sizeof( szDirectory ), "%s:/*", COM_GetModDirectory() );
  1104. else
  1105. Q_snprintf( szDirectory, sizeof( szDirectory ), "save/*" );
  1106. Q_DefaultExtension( szDirectory, IsGameConsole() ? ".360.sav" : ".sav", sizeof( szDirectory ) );
  1107. Q_FixSlashes( szDirectory );
  1108. // iterate the saved files
  1109. FileFindHandle_t handle;
  1110. const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle );
  1111. while (pFileName)
  1112. {
  1113. if ( StringHasPrefix(pFileName, "HLSave" ) )
  1114. {
  1115. pFileName = g_pFullFileSystem->FindNext( handle );
  1116. continue;
  1117. }
  1118. char szFileName[_MAX_PATH];
  1119. if ( IsGameConsole() )
  1120. Q_snprintf(szFileName, sizeof( szFileName ), "%s:/%s", COM_GetModDirectory(), pFileName );
  1121. else
  1122. Q_snprintf(szFileName, sizeof( szFileName ), "save/%s", pFileName);
  1123. Q_FixSlashes( szFileName );
  1124. // Only load save games from the current mod's save dir
  1125. if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) )
  1126. {
  1127. pFileName = g_pFullFileSystem->FindNext( handle );
  1128. continue;
  1129. }
  1130. SaveGameDescription_t save;
  1131. if ( ParseSaveData( szFileName, pFileName, &save ) )
  1132. {
  1133. // Add on this file's size to the count
  1134. m_nUsedStorageSpace += save.iSize;
  1135. // Always ignore autosave dangerous (they're not considered safe until committed)
  1136. if ( Q_stristr( save.szShortName, "dangerous" ) )
  1137. {
  1138. pFileName = g_pFullFileSystem->FindNext( handle );
  1139. continue;
  1140. }
  1141. // If we're ignoring autosaves, skip it here
  1142. if ( bIgnoreAutosave )
  1143. {
  1144. if ( !Q_stricmp( save.szType, "#GameUI_Autosave" ) )
  1145. {
  1146. pFileName = g_pFullFileSystem->FindNext( handle );
  1147. continue;
  1148. }
  1149. }
  1150. saveGames.AddToTail( save );
  1151. }
  1152. pFileName = g_pFullFileSystem->FindNext( handle );
  1153. }
  1154. g_pFullFileSystem->FindClose( handle );
  1155. // Sort the save list
  1156. SortSaveGames( saveGames.Base(), saveGames.Count() );
  1157. // Now add them in order
  1158. for ( int i = 0; i < saveGames.Count(); i++ )
  1159. {
  1160. CGameSavePanel *savePanel = SETUP_PANEL( new CGameSavePanel( this, &saveGames[i] ) );
  1161. savePanel->SetVisible( false );
  1162. m_SavePanels.AddToTail( savePanel );
  1163. }
  1164. // Notify derived classes that save games are done being scanned
  1165. OnDoneScanningSaveGames();
  1166. // Always start with the first panel (as we're sorted in a specific order)
  1167. SetSelectedSaveIndex( 0 );
  1168. }
  1169. //-----------------------------------------------------------------------------
  1170. // Purpose: Return the currently selected panel
  1171. //-----------------------------------------------------------------------------
  1172. CGameSavePanel *CSaveGameBrowserDialog::GetActivePanel( void )
  1173. {
  1174. if ( IsValidPanel( m_iSelectedSave ) == false )
  1175. return NULL;
  1176. return m_SavePanels[ m_iSelectedSave ];
  1177. }