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.
1425 lines
44 KiB
1425 lines
44 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
//=============================================================================// |
|
|
|
#include "BasePanel.h" |
|
#include "SaveGameDialog.h" |
|
|
|
#include "winlite.h" // FILETIME |
|
#include "vgui/ILocalize.h" |
|
#include "vgui/ISurface.h" |
|
#include "vgui/ISystem.h" |
|
#include "vgui/IVGui.h" |
|
|
|
#include "vgui_controls/AnimationController.h" |
|
#include "vgui_controls/ImagePanel.h" |
|
#include "filesystem.h" |
|
#include "KeyValues.h" |
|
#include "ModInfo.h" |
|
#include "EngineInterface.h" |
|
#include "GameUI_Interface.h" |
|
#include "vstdlib/random.h" |
|
|
|
#include <time.h> |
|
|
|
#include "SaveGameBrowserDialog.h" |
|
|
|
extern const char *COM_GetModDirectory( void ); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CGameSavePanel::CGameSavePanel( CSaveGameBrowserDialog *parent, SaveGameDescription_t *pSaveDesc, bool bCommandPanel ) |
|
: BaseClass( parent, "SaveGamePanel" ) |
|
{ |
|
// Store our save description internally for reference later by our parent |
|
m_SaveInfo = (*pSaveDesc); |
|
m_bNewSavePanel = bCommandPanel; |
|
|
|
// Setup our main graphical elements |
|
m_pLevelPicBorder = SETUP_PANEL( new ImagePanel( this, "LevelPicBorder" ) ); |
|
m_pLevelPic = SETUP_PANEL( new ImagePanel( this, "LevelPic" ) ); |
|
|
|
// Setup our various labels |
|
m_pChapterTitle = new Label( this, "ChapterLabel", m_SaveInfo.szComment ); |
|
m_pTime = new Label( this, "TimeLabel", m_SaveInfo.szFileTime ); |
|
m_pElapsedTime = new Label( this, "ElapsedLabel", m_SaveInfo.szElapsedTime ); |
|
m_pType = new Label( this, "TypeLabel", m_SaveInfo.szType ); |
|
|
|
// Make sure we have a chapter description |
|
char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" ); |
|
if ( pchChapterName ) |
|
{ |
|
char szChapterImage[ 256 ]; |
|
Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) ); |
|
char *ext = Q_strrchr( szChapterImage, '_' ); |
|
if ( ext ) |
|
{ |
|
*ext = '\0'; |
|
} |
|
m_pLevelPic->SetImage( szChapterImage ); |
|
} |
|
else |
|
{ |
|
m_pLevelPic->SetImage( "ui_logo" ); |
|
} |
|
|
|
// Setup our basic settings |
|
KeyValues *pKeys = NULL; |
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGamePanel.res" ); |
|
} |
|
LoadControlSettings( "Resource/SaveGamePanel.res", NULL, pKeys ); |
|
|
|
int px, py; |
|
m_pLevelPicBorder->GetPos( px, py ); |
|
SetSize( m_pLevelPicBorder->GetWide(), py + m_pLevelPicBorder->GetTall() + ( m_pType->GetTall() + 16 ) ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
CGameSavePanel::~CGameSavePanel( void ) |
|
{ |
|
if ( m_pLevelPicBorder ) |
|
delete m_pLevelPicBorder; |
|
|
|
if ( m_pLevelPic ) |
|
delete m_pLevelPic; |
|
|
|
if ( m_pChapterTitle ) |
|
delete m_pChapterTitle; |
|
|
|
if ( m_pTime ) |
|
delete m_pTime; |
|
|
|
if ( m_pElapsedTime ) |
|
delete m_pElapsedTime; |
|
|
|
if ( m_pType ) |
|
delete m_pType; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CGameSavePanel::ApplySchemeSettings( IScheme *pScheme ) |
|
{ |
|
m_TextColor = pScheme->GetColor( "NewGame.TextColor", Color(255, 255, 255, 255) ); |
|
m_FillColor = pScheme->GetColor( "NewGame.FillColor", Color(255, 255, 255, 255) ); |
|
m_DisabledColor = pScheme->GetColor( "NewGame.DisabledColor", Color(255, 255, 255, 4) ); |
|
m_SelectedColor = pScheme->GetColor( "NewGame.SelectionColor", Color(255, 255, 255, 255) ); |
|
|
|
// Turn various labels off if we're the "stubbed" panel |
|
if ( m_bNewSavePanel ) |
|
{ |
|
m_pTime->SetVisible( false ); |
|
m_pElapsedTime->SetVisible( false ); |
|
m_pType->SetVisible( false ); |
|
} |
|
|
|
// Setup our initial state |
|
m_pChapterTitle->SetFgColor( m_TextColor ); |
|
m_pTime->SetFgColor( m_TextColor ); |
|
m_pElapsedTime->SetFgColor( m_TextColor ); |
|
|
|
m_pLevelPic->SetFillColor( Color( 0, 0, 0, 255 ) ); |
|
m_pLevelPicBorder->SetFillColor( Color( 0, 0, 0, 255 ) ); |
|
|
|
if ( m_bNewSavePanel ) |
|
{ |
|
float flScaleAmount = m_pLevelPic->GetScaleAmount(); |
|
if ( flScaleAmount <= 0.0f ) |
|
flScaleAmount = 1.0f; |
|
|
|
// TBD: Draw the game logo here! |
|
int picWide = 64.0f * flScaleAmount; |
|
int picTall = 64.0f * flScaleAmount; |
|
int borderWide = m_pLevelPicBorder->GetWide(); |
|
int borderTall = m_pLevelPicBorder->GetTall(); |
|
int borderX, borderY; |
|
m_pLevelPicBorder->GetPos( borderX, borderY ); |
|
m_pLevelPic->SetPos( borderX + ( ( borderWide - picWide ) / 2 ), borderY + ( ( borderTall - picTall ) / 2 ) ); |
|
m_pLevelPic->SetFillColor( Color( 0, 0, 0, 0 ) ); |
|
} |
|
|
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Overwrite the level description |
|
// Input : *pDesc - Description to use |
|
//----------------------------------------------------------------------------- |
|
void CGameSavePanel::SetDescription( SaveGameDescription_t *pDesc ) |
|
{ |
|
// Store our save description internally for reference later by our parent |
|
m_SaveInfo = (*pDesc); |
|
|
|
// Setup our main graphical elements |
|
m_pChapterTitle->SetText( m_SaveInfo.szComment ); |
|
m_pTime->SetText( m_SaveInfo.szFileTime ); |
|
m_pElapsedTime->SetText( m_SaveInfo.szElapsedTime ); |
|
m_pType->SetText( m_SaveInfo.szType ); |
|
|
|
// Make sure we have a chapter description |
|
char *pchChapterName = Q_stristr( m_SaveInfo.szComment, "chapter" ); |
|
if ( pchChapterName ) |
|
{ |
|
char szChapterImage[ 256 ]; |
|
Q_snprintf( szChapterImage, sizeof(szChapterImage), "chapters/%s", Q_strlower( pchChapterName ) ); |
|
char *ext = Q_strrchr( szChapterImage, '_' ); |
|
if ( ext ) |
|
{ |
|
*ext = '\0'; |
|
} |
|
m_pLevelPic->SetImage( szChapterImage ); |
|
} |
|
} |
|
|
|
// |
|
// |
|
// |
|
// |
|
// |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: new game chapter selection |
|
//----------------------------------------------------------------------------- |
|
CSaveGameBrowserDialog::CSaveGameBrowserDialog( vgui::Panel *parent ) |
|
: BaseClass( parent, "SaveGameDialog" ), |
|
m_bFilterAutosaves( false ), |
|
m_iSelectedSave( -1 ), |
|
m_bScrolling( false ), |
|
m_ScrollCt( 0 ), |
|
m_ScrollSpeed( 0.0f ), |
|
m_ButtonPressed( SCROLL_NONE ), |
|
m_ScrollDirection( SCROLL_NONE ), |
|
m_nDeletedPanel( INVALID_INDEX ), |
|
m_nAddedPanel( INVALID_INDEX ), |
|
m_nUsedStorageSpace( 0 ), |
|
m_bControlDisabled( false ) |
|
{ |
|
// Setup basic attributes |
|
SetDeleteSelfOnClose( true ); |
|
SetSizeable( false ); |
|
|
|
// Create the backer that highlights the currently selected save |
|
m_pCenterBg = SETUP_PANEL( new Panel( this, "CenterBG" ) ); |
|
m_pCenterBg->SetPaintBackgroundType( 2 ); |
|
m_pCenterBg->SetVisible( true ); |
|
|
|
// Create our button footer |
|
m_pFooter = new CFooterPanel( parent, "SaveGameFooter" ); |
|
|
|
// Load our res files from the keyvalue we're holding |
|
KeyValues *pKeys = NULL; |
|
if ( GameUI().IsConsoleUI() ) |
|
{ |
|
pKeys = BasePanel()->GetConsoleControlSettings()->FindKey( "SaveGameDialog.res" ); |
|
} |
|
|
|
LoadControlSettings( "Resource/SaveGameDialog.res", NULL, pKeys ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Destructor |
|
//----------------------------------------------------------------------------- |
|
CSaveGameBrowserDialog::~CSaveGameBrowserDialog( void ) |
|
{ |
|
// Release all elements |
|
m_SavePanels.PurgeAndDeleteElements(); |
|
|
|
// Kill the footer |
|
if ( m_pFooter ) |
|
{ |
|
delete m_pFooter; |
|
m_pFooter = NULL; |
|
} |
|
|
|
if ( m_pCenterBg ) |
|
{ |
|
delete m_pCenterBg; |
|
m_pCenterBg = NULL; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Show the "No save games to display" indication label and hide all browsing UI |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ShowNoSaveGameUI( void ) |
|
{ |
|
// Show the "no save games" text |
|
vgui::Label *pNoSavesLabel = dynamic_cast<vgui::Label *>(FindChildByName( "NoSavesLabel" )); |
|
if ( pNoSavesLabel ) |
|
{ |
|
if ( m_bSaveGameIsCorrupt ) |
|
{ |
|
pNoSavesLabel->SetText("#GameUI_SaveGame_CorruptFile"); |
|
} |
|
else |
|
{ |
|
pNoSavesLabel->SetText("#GameUI_NoSaveGamesToDisplay"); |
|
} |
|
pNoSavesLabel->SetVisible( true ); |
|
} |
|
|
|
if ( m_pCenterBg ) |
|
m_pCenterBg->SetVisible( false ); |
|
|
|
vgui::Panel *pLeftArrow = FindChildByName( "LeftArrow" ); |
|
if ( pLeftArrow ) |
|
pLeftArrow->SetVisible( false ); |
|
|
|
vgui::Panel *pRightArrow = FindChildByName( "RightArrow" ); |
|
if ( pRightArrow ) |
|
pRightArrow->SetVisible( false ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Hide all "No save games" UI |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::HideNoSaveGameUI( void ) |
|
{ |
|
// Show the "no save games" text |
|
vgui::Panel *pNoSavesLabel = FindChildByName( "NoSavesLabel" ); |
|
if ( pNoSavesLabel ) |
|
pNoSavesLabel->SetVisible( false ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::LayoutPanels( void ) |
|
{ |
|
// Setup our panels depending on the mode we're in |
|
if ( HasActivePanels() ) |
|
{ |
|
// Hide any indicators about no save games |
|
HideNoSaveGameUI(); |
|
|
|
// Layout panel positions relative to the dialog center. |
|
int panelWidth = m_SavePanels[0]->GetWide() + 16; |
|
int dialogWidth = GetWide(); |
|
m_PanelXPos[2] = ( dialogWidth - panelWidth ) / 2 + 8; |
|
m_PanelXPos[1] = m_PanelXPos[2] - panelWidth; |
|
m_PanelXPos[0] = m_PanelXPos[1]; |
|
m_PanelXPos[3] = m_PanelXPos[2] + panelWidth; |
|
m_PanelXPos[4] = m_PanelXPos[3]; |
|
|
|
m_PanelAlpha[0] = 0; |
|
m_PanelAlpha[1] = 64; |
|
m_PanelAlpha[2] = 255; |
|
m_PanelAlpha[3] = 64; |
|
m_PanelAlpha[4] = 0; |
|
|
|
int panelHeight; |
|
m_SavePanels[0]->GetSize( panelWidth, panelHeight ); |
|
m_pCenterBg->SetVisible( true ); |
|
m_pCenterBg->SetWide( panelWidth + 16 ); |
|
m_pCenterBg->SetPos( m_PanelXPos[2] - 8, m_PanelYPos[2] - (panelHeight - m_nCenterBgTallDefault) + 8 ); |
|
m_pCenterBg->SetBgColor( Color( 190, 115, 0, 255 ) ); |
|
} |
|
else |
|
{ |
|
// Hide anything to do with browsing the saves |
|
ShowNoSaveGameUI(); |
|
|
|
} |
|
|
|
// Do internal cleanup to make sure we present a correct state to the user |
|
UpdateMenuComponents( SCROLL_NONE ); |
|
UpdateFooterOptions(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Do a fancy slide-out when we're first displayed |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::AnimateDialogStart( void ) |
|
{ |
|
const float flAnimInTime = 0.5f; |
|
const float flOffset = 0.1f; |
|
|
|
for ( int i = 0; i < NUM_SLOTS; i++ ) |
|
{ |
|
if ( m_PanelIndex[i] == INVALID_INDEX ) |
|
continue; |
|
|
|
// Start us at the "opening" position |
|
CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[i] ]; |
|
if ( panel ) |
|
{ |
|
panel->SetPos( m_PanelXPos[0], m_PanelYPos[0] ); |
|
panel->SetAlpha( m_PanelAlpha[0] ); |
|
panel->SetVisible( true ); |
|
panel->SetEnabled( true ); |
|
panel->SetZPos( NUM_SLOTS - i ); |
|
} |
|
|
|
// Now make them slide out where they're going |
|
GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[i], 0, flAnimInTime + (flOffset*i), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
} |
|
|
|
// Move and fade the back label |
|
m_pCenterBg->SetAlpha( 0 ); |
|
int nX, nY; |
|
m_pCenterBg->GetPos( nX, nY ); |
|
m_pCenterBg->SetPos( nX-m_pCenterBg->GetWide(), nY ); |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "xpos", nX, 0, flAnimInTime + (flOffset*2), vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, (flAnimInTime+ (flOffset*2))*2.0f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
CGameSavePanel *selectedPanel = GetActivePanel(); |
|
if ( selectedPanel && selectedPanel->IsAutoSaveType() ) |
|
{ |
|
m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 ); |
|
} |
|
else |
|
{ |
|
m_pCenterBg->SetTall( m_nCenterBgTallDefault ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Do our initial layout |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::Activate( void ) |
|
{ |
|
// Start scanning for saved games |
|
ScanSavedGames( m_bFilterAutosaves ); |
|
|
|
// Finish our layout depending on what the result of the scan was |
|
LayoutPanels(); |
|
|
|
// Animate the opening animation |
|
AnimateDialogStart(); |
|
|
|
BaseClass::Activate(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Apply special properties of the menu |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ApplySettings( KeyValues *inResourceData ) |
|
{ |
|
BaseClass::ApplySettings( inResourceData ); |
|
|
|
int ypos = inResourceData->GetInt( "chapterypos", 20 ); |
|
for ( int i = 0; i < NUM_SLOTS; ++i ) |
|
{ |
|
m_PanelYPos[i] = ypos; |
|
} |
|
|
|
m_nCenterBgTallDefault = inResourceData->GetInt( "centerbgtall", 0 ); |
|
m_pCenterBg->SetTall( m_nCenterBgTallDefault ); |
|
|
|
m_ScrollSpeedSlow = inResourceData->GetFloat( "scrollslow", 0.0f ); |
|
m_ScrollSpeedFast = inResourceData->GetFloat( "scrollfast", 0.0f ); |
|
SetFastScroll( false ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Apply scheme settings |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ApplySchemeSettings( vgui::IScheme *pScheme ) |
|
{ |
|
BaseClass::ApplySchemeSettings( pScheme ); |
|
|
|
UpdateMenuComponents( SCROLL_NONE ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets the correct properties for visible components |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::UpdateMenuComponents( EScrollDirection dir ) |
|
{ |
|
// This is called prior to any scrolling, so we need to look ahead to the post-scroll state |
|
int centerIdx = SLOT_CENTER; |
|
|
|
// Scroll given our direction of travel |
|
if ( dir == SCROLL_LEFT ) |
|
{ |
|
++centerIdx; |
|
} |
|
else if ( dir == SCROLL_RIGHT ) |
|
{ |
|
--centerIdx; |
|
} |
|
|
|
int leftIdx = centerIdx - 1; |
|
int rightIdx = centerIdx + 1; |
|
|
|
// Update the state of the side arrows depending on whether or not we can scroll that direction |
|
vgui::Panel *leftArrow = this->FindChildByName( "LeftArrow" ); |
|
vgui::Panel *rightArrow = this->FindChildByName( "RightArrow" ); |
|
if ( leftArrow ) |
|
{ |
|
leftArrow->SetVisible( true ); |
|
if ( m_PanelIndex[leftIdx] != INVALID_INDEX ) |
|
{ |
|
leftArrow->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
} |
|
else |
|
{ |
|
leftArrow->SetFgColor( Color( 128, 128, 128, 64 ) ); |
|
} |
|
} |
|
if ( rightArrow ) |
|
{ |
|
rightArrow->SetVisible( true ); |
|
if ( m_PanelIndex[rightIdx] != INVALID_INDEX ) |
|
{ |
|
rightArrow->SetFgColor( Color( 255, 255, 255, 255 ) ); |
|
} |
|
else |
|
{ |
|
rightArrow->SetFgColor( Color( 128, 128, 128, 64 ) ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: sets a chapter as selected |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::SetSelectedSaveIndex( int index ) |
|
{ |
|
m_iSelectedSave = index; |
|
|
|
// If we have no panels, there's nothing to update |
|
if ( HasActivePanels() == false ) |
|
return; |
|
|
|
// Setup panels to the left of the selected panel |
|
int currIdx = index; |
|
for ( int i = SLOT_CENTER; i >= 0 && currIdx >= 0; --i ) |
|
{ |
|
m_PanelIndex[i] = currIdx; |
|
--currIdx; |
|
InitPanelIndexForDisplay( i ); |
|
} |
|
|
|
// Setup panels to the right of the selected panel |
|
currIdx = index + 1; |
|
for ( int i = SLOT_CENTER + 1; i < NUM_SLOTS && currIdx < m_SavePanels.Count(); ++i ) |
|
{ |
|
m_PanelIndex[i] = currIdx; |
|
++currIdx; |
|
InitPanelIndexForDisplay( i ); |
|
} |
|
|
|
UpdateMenuComponents( SCROLL_NONE ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Remove the currently selected animation from the list with proper animations |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::RemoveActivePanel( void ) |
|
{ |
|
// Kill the current panel |
|
m_nDeletedPanel = m_PanelIndex[SLOT_CENTER]; |
|
|
|
// Start our current panel fading |
|
CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ]; |
|
GetAnimationController()->RunAnimationCommand( pPanel, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL ); |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeedFast, vgui::AnimationController::INTERPOLATOR_ACCEL ); |
|
PostMessage( this, new KeyValues( "FinishDelete" ), m_ScrollSpeed ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::CloseAfterSave( void ) |
|
{ |
|
OnCommand( "CloseAndSelectResume" ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::FinishInsert( void ) |
|
{ |
|
CGameSavePanel *panel = m_SavePanels[ m_nAddedPanel ]; |
|
|
|
const float flScrollSpeed = 0.75f; |
|
|
|
// Run the actual movement |
|
GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_RIGHT], 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", 255, 0, flScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
PostMessage( this, new KeyValues( "CloseAfterSave" ), flScrollSpeed*2.0f ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Insert a new panel at the desired location |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::AnimateInsertNewPanel( const SaveGameDescription_t *pDesc ) |
|
{ |
|
// This is the panel that's going to move |
|
CGameSavePanel *pNewPanel = SETUP_PANEL( new CGameSavePanel( this, (SaveGameDescription_t *) pDesc ) ); |
|
pNewPanel->SetVisible( false ); |
|
|
|
// Tack this onto the list |
|
m_nAddedPanel = m_SavePanels.InsertAfter( 0, pNewPanel ); |
|
|
|
// Set it up but turn it off immediately |
|
pNewPanel->SetPos( m_PanelXPos[SLOT_CENTER], m_PanelYPos[SLOT_CENTER] ); |
|
pNewPanel->SetVisible( true ); |
|
pNewPanel->SetEnabled( true ); |
|
pNewPanel->SetZPos( 0 ); |
|
pNewPanel->SetAlpha( 0.0f ); |
|
|
|
// Increment our indices to reflect the change |
|
for ( int i = 0; i < NUM_SLOTS; i++ ) |
|
{ |
|
if ( m_PanelIndex[i] == INVALID_INDEX ) |
|
continue; |
|
|
|
if ( m_PanelIndex[i] > 0 ) |
|
{ |
|
m_PanelIndex[i]++; |
|
} |
|
} |
|
|
|
// Fade the right panel away |
|
if ( IsValidPanel( m_PanelIndex[ SLOT_RIGHT ] ) ) |
|
{ |
|
CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ SLOT_RIGHT ] ]; |
|
|
|
// Run the actual movement |
|
GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[SLOT_OFFRIGHT], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
PostMessage( this, new KeyValues( "FinishInsert" ), m_ScrollSpeed ); |
|
} |
|
else |
|
{ |
|
PostMessage( this, new KeyValues( "FinishInsert" ), 0.1f ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Pop in the new description |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::FinishOverwriteFadeDown( void ) |
|
{ |
|
const float flFadeInTime = 0.25f; |
|
|
|
// Fade the right panel away |
|
CGameSavePanel *pActivePanel = GetActivePanel(); |
|
if ( pActivePanel ) |
|
{ |
|
pActivePanel->SetDescription( &m_NewSaveGameDesc ); |
|
|
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", m_PanelAlpha[SLOT_CENTER], 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
} |
|
|
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, flFadeInTime, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
PostMessage( this, new KeyValues( "CloseAfterSave" ), flFadeInTime + 0.1f ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Animate an overwrite event by fading out the old panel and bringing it back with a new description |
|
// Input : *pNewDesc - The new description to display |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::AnimateOverwriteActivePanel( const SaveGameDescription_t *pNewDesc ) |
|
{ |
|
// Save a copy of this description |
|
m_NewSaveGameDesc = (*pNewDesc); |
|
|
|
// Fade the right panel away |
|
CGameSavePanel *pActivePanel = GetActivePanel(); |
|
if ( pActivePanel ) |
|
{ |
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( pActivePanel, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
} |
|
|
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, 0.5f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
PostMessage( this, new KeyValues( "FinishOverwriteFadeDown" ), 0.75f ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called before a panel scroll starts. |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PreScroll( EScrollDirection dir ) |
|
{ |
|
int hideIdx = INVALID_INDEX; |
|
if ( m_nDeletedPanel != INVALID_INDEX ) |
|
{ |
|
hideIdx = m_nDeletedPanel; |
|
} |
|
else if ( dir == SCROLL_LEFT ) |
|
{ |
|
hideIdx = m_PanelIndex[SLOT_LEFT]; |
|
} |
|
else if ( dir == SCROLL_RIGHT ) |
|
{ |
|
hideIdx = m_PanelIndex[SLOT_RIGHT]; |
|
} |
|
|
|
if ( hideIdx != INVALID_INDEX ) |
|
{ |
|
// Push back the panel that's about to be hidden |
|
// so the next panel scrolls over the top of it. |
|
m_SavePanels[hideIdx]->SetZPos( 0 ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called after a panel scroll finishes. |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PostScroll( EScrollDirection dir ) |
|
{ |
|
// FIXME: Nothing to do here... |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initiates a panel scroll and starts the animation. |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ScrollSelectionPanels( EScrollDirection dir ) |
|
{ |
|
// Only initiate a scroll if panels aren't currently scrolling |
|
if ( !m_bScrolling ) |
|
{ |
|
// Handle any pre-scroll setup |
|
PreScroll( dir ); |
|
|
|
if ( dir == SCROLL_LEFT) |
|
{ |
|
m_ScrollCt += SCROLL_LEFT; |
|
} |
|
else if ( dir == SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] != 0 ) |
|
{ |
|
m_ScrollCt += SCROLL_RIGHT; |
|
} |
|
|
|
m_bScrolling = true; |
|
AnimateSelectionPanels(); |
|
|
|
// Update the arrow colors, help text, and buttons. Doing it here looks better than having |
|
// the components change after the entire scroll animation has finished. |
|
UpdateMenuComponents( m_ScrollDirection ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Do all slide animation work here |
|
// Input : nPanelIndex - Panel we're currently operating on |
|
// nNextPanelIndex - Panel we're going to be moving over |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PerformSlideAction( int nPanelIndex, int nNextPanelIndex ) |
|
{ |
|
CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[ nPanelIndex ] ]; |
|
|
|
// Run the actual movement |
|
GetAnimationController()->RunAnimationCommand( panel, "xpos", m_PanelXPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
GetAnimationController()->RunAnimationCommand( panel, "ypos", m_PanelYPos[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
// Panel alpha |
|
GetAnimationController()->RunAnimationCommand( panel, "alpha", m_PanelAlpha[nNextPanelIndex], 0, m_ScrollSpeed, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Initiates the scripted scroll and fade effects of all five slotted panels |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::AnimateSelectionPanels( void ) |
|
{ |
|
int idxOffset = 0; |
|
int startIdx = SLOT_LEFT; |
|
int endIdx = SLOT_RIGHT; |
|
|
|
// Don't scroll outside the bounds of the panel list |
|
if ( m_ScrollCt >= SCROLL_LEFT && m_PanelIndex[SLOT_CENTER] < m_SavePanels.Count() - 1 ) |
|
{ |
|
if ( m_nDeletedPanel != INVALID_INDEX ) |
|
{ |
|
startIdx = SLOT_RIGHT; |
|
} |
|
|
|
idxOffset = -1; |
|
endIdx = SLOT_OFFRIGHT; |
|
m_ScrollDirection = SCROLL_LEFT; |
|
} |
|
else if ( m_ScrollCt <= SCROLL_RIGHT && m_PanelIndex[SLOT_CENTER] > 0 ) |
|
{ |
|
idxOffset = 1; |
|
startIdx = SLOT_OFFLEFT; |
|
m_ScrollDirection = SCROLL_RIGHT; |
|
} |
|
|
|
if ( 0 == idxOffset ) |
|
{ |
|
// Kill the scroll, it's outside the bounds |
|
m_ScrollCt = 0; |
|
m_bScrolling = false; |
|
m_ScrollDirection = SCROLL_NONE; |
|
vgui::surface()->PlaySound( "player/suit_denydevice.wav" ); |
|
return; |
|
} |
|
|
|
// Should never happen |
|
if ( startIdx > endIdx ) |
|
return; |
|
|
|
for ( int i = startIdx; i <= endIdx; ++i ) |
|
{ |
|
// Don't animate the special panel, just skip it |
|
if ( m_PanelIndex[i] == m_nDeletedPanel ) |
|
continue; |
|
|
|
int nNextIdx = i+idxOffset; |
|
if ( m_PanelIndex[i] != INVALID_INDEX ) |
|
{ |
|
PerformSlideAction( i, nNextIdx ); |
|
} |
|
} |
|
|
|
vgui::surface()->PlaySound( "UI/buttonclick.wav" ); |
|
|
|
// Animate the center background panel |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 0, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_SIMPLESPLINE ); |
|
|
|
// Scrolling up through chapters, offset is negative |
|
m_iSelectedSave -= idxOffset; |
|
|
|
UpdateFooterOptions(); |
|
|
|
PostMessage( this, new KeyValues( "FinishScroll" ), m_ScrollSpeed ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: After a scroll, each panel slot holds the index of a panel that has |
|
// scrolled to an adjacent slot. This function updates each slot so |
|
// it holds the index of the panel that is actually in that slot's position. |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ShiftPanelIndices( int offset ) |
|
{ |
|
// Shift all the elements over one slot, then calculate what the last slot's index should be. |
|
int lastSlot = NUM_SLOTS - 1; |
|
|
|
// Handle the deletion case |
|
if ( m_nDeletedPanel != INVALID_INDEX ) |
|
{ |
|
// Scroll panels in from the right |
|
Q_memmove( &m_PanelIndex[SLOT_CENTER], &m_PanelIndex[SLOT_RIGHT], 2* sizeof( m_PanelIndex[SLOT_CENTER] ) ); |
|
|
|
if ( m_PanelIndex[lastSlot] != INVALID_INDEX ) |
|
{ |
|
int num = m_PanelIndex[ lastSlot ] + 1; |
|
if ( IsValidPanel( num ) ) |
|
{ |
|
m_PanelIndex[lastSlot] = num; |
|
InitPanelIndexForDisplay( lastSlot ); |
|
} |
|
else |
|
{ |
|
m_PanelIndex[lastSlot] = INVALID_INDEX; |
|
} |
|
} |
|
} |
|
else if ( offset > 0 ) |
|
{ |
|
// Hide the panel that's dropping out of the slots |
|
if ( IsValidPanel( m_PanelIndex[0] ) ) |
|
{ |
|
m_SavePanels[ m_PanelIndex[0] ]->SetVisible( false ); |
|
} |
|
|
|
// Scrolled panels to the right, so shift the indices one slot to the left |
|
Q_memmove( &m_PanelIndex[0], &m_PanelIndex[1], lastSlot * sizeof( m_PanelIndex[0] ) ); |
|
if ( m_PanelIndex[lastSlot] != INVALID_INDEX ) |
|
{ |
|
int num = m_PanelIndex[ lastSlot ] + 1; |
|
if ( IsValidPanel( num ) ) |
|
{ |
|
m_PanelIndex[lastSlot] = num; |
|
InitPanelIndexForDisplay( lastSlot ); |
|
} |
|
else |
|
{ |
|
m_PanelIndex[lastSlot] = INVALID_INDEX; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// Hide the panel that's dropping out of the slots |
|
if ( IsValidPanel( m_PanelIndex[lastSlot] ) ) |
|
{ |
|
m_SavePanels[ m_PanelIndex[lastSlot] ]->SetVisible( false ); |
|
} |
|
|
|
// Scrolled panels to the left, so shift the indices one slot to the right |
|
Q_memmove( &m_PanelIndex[1], &m_PanelIndex[0], lastSlot * sizeof( m_PanelIndex[0] ) ); |
|
if ( m_PanelIndex[0] != INVALID_INDEX ) |
|
{ |
|
int num = m_PanelIndex[0] - 1; |
|
if ( IsValidPanel( num ) ) |
|
{ |
|
m_PanelIndex[0] = num; |
|
InitPanelIndexForDisplay( 0 ); |
|
} |
|
else |
|
{ |
|
m_PanelIndex[0] = INVALID_INDEX; |
|
} |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Validates an index into the selection panels vector |
|
//----------------------------------------------------------------------------- |
|
bool CSaveGameBrowserDialog::IsValidPanel( const int idx ) |
|
{ |
|
if ( idx < 0 || idx >= m_SavePanels.Count() ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets up a panel's properties before it is displayed |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::InitPanelIndexForDisplay( const int idx ) |
|
{ |
|
CGameSavePanel *panel = m_SavePanels[ m_PanelIndex[idx] ]; |
|
if ( panel ) |
|
{ |
|
panel->SetPos( m_PanelXPos[idx], m_PanelYPos[idx] ); |
|
panel->SetAlpha( m_PanelAlpha[idx] ); |
|
panel->SetVisible( true ); |
|
panel->SetEnabled( true ); |
|
if ( m_PanelAlpha[idx] ) |
|
{ |
|
panel->SetZPos( NUM_SLOTS ); |
|
} |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sets which scroll speed should be used |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::SetFastScroll( bool fast ) |
|
{ |
|
m_ScrollSpeed = fast ? m_ScrollSpeedFast : m_ScrollSpeedSlow; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Checks if a button is being held down, and speeds up the scroll |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ContinueScrolling( void ) |
|
{ |
|
if ( !GameUI().IsConsoleUI() ) |
|
{ |
|
if ( m_PanelIndex[SLOT_CENTER-1] % 3 ) |
|
{ |
|
ScrollSelectionPanels( m_ScrollDirection ); |
|
} |
|
return; |
|
} |
|
|
|
if ( m_ButtonPressed == m_ScrollDirection ) |
|
{ |
|
SetFastScroll( true ); |
|
ScrollSelectionPanels( m_ScrollDirection ); |
|
} |
|
else if ( m_ButtonPressed != SCROLL_NONE ) |
|
{ |
|
// The other direction has been pressed - start a slow scroll |
|
SetFastScroll( false ); |
|
ScrollSelectionPanels( (EScrollDirection)m_ButtonPressed ); |
|
} |
|
else |
|
{ |
|
SetFastScroll( false ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Fade animation has finished, now slide or be done |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::FinishDelete( void ) |
|
{ |
|
// Catch the case where all saves are now gone! |
|
if ( m_SavePanels.Count() == 1 ) |
|
{ |
|
m_nDeletedPanel = INVALID_INDEX; |
|
m_SavePanels.PurgeAndDeleteElements(); |
|
|
|
for ( int i = 0; i < NUM_SLOTS; i++ ) |
|
{ |
|
m_PanelIndex[i] = INVALID_INDEX; |
|
} |
|
|
|
LayoutPanels(); |
|
return; |
|
} |
|
|
|
EScrollDirection nDirection = ( IsValidPanel( m_nDeletedPanel + 1 ) ) ? SCROLL_LEFT : SCROLL_RIGHT; |
|
ScrollSelectionPanels( nDirection ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Called when a scroll distance of one slot has been completed |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::FinishScroll( void ) |
|
{ |
|
// Fade the center bg panel back in |
|
GetAnimationController()->RunAnimationCommand( m_pCenterBg, "alpha", 255, 0, m_ScrollSpeed * 0.25f, vgui::AnimationController::INTERPOLATOR_LINEAR ); |
|
|
|
ShiftPanelIndices( m_ScrollDirection ); |
|
m_bScrolling = false; |
|
m_ScrollCt = 0; |
|
|
|
// End of scroll step |
|
PostScroll( m_ScrollDirection ); |
|
|
|
if ( m_nDeletedPanel != INVALID_INDEX ) |
|
{ |
|
// Find where we're going next |
|
int newSave = m_nDeletedPanel; |
|
if ( m_SavePanels.IsValidIndex( m_nDeletedPanel + 1 ) == false ) |
|
{ |
|
newSave = m_nDeletedPanel - 1; |
|
} |
|
|
|
// Remove it from our list |
|
CGameSavePanel *pPanel = m_SavePanels[ m_nDeletedPanel ]; |
|
m_SavePanels.Remove( m_nDeletedPanel ); |
|
delete pPanel; |
|
|
|
// Decrement all the indices to reflect the change |
|
for ( int i = 0; i < NUM_SLOTS; i++ ) |
|
{ |
|
if ( m_PanelIndex[i] > m_nDeletedPanel ) |
|
m_PanelIndex[i]--; |
|
} |
|
|
|
// Clear the spot and be done with it |
|
SetSelectedSaveIndex( newSave ); |
|
m_nDeletedPanel = INVALID_INDEX; |
|
UpdateMenuComponents( SCROLL_NONE ); |
|
} |
|
|
|
// Size the "autosave" blade if need-be |
|
CGameSavePanel *selectedPanel = GetActivePanel(); |
|
if ( selectedPanel && selectedPanel->IsAutoSaveType() ) |
|
{ |
|
m_pCenterBg->SetTall( m_nCenterBgTallDefault + 20 ); |
|
} |
|
else |
|
{ |
|
m_pCenterBg->SetTall( m_nCenterBgTallDefault ); |
|
} |
|
|
|
// Continue scrolling if necessary |
|
ContinueScrolling(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::OnClose( void ) |
|
{ |
|
SetControlDisabled( true ); |
|
|
|
m_KeyRepeat.Reset(); |
|
BasePanel()->RunCloseAnimation( "CloseNewGameDialog_OpenMainMenu" ); |
|
|
|
BaseClass::OnClose(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Our save games have changed, so layout our panel again |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::RefreshSaveGames( void ) |
|
{ |
|
// Close any pending messages |
|
BasePanel()->CloseMessageDialog( DIALOG_STACK_IDX_WARNING ); |
|
|
|
// Don't leave us in a locked state |
|
SetControlDisabled( false ); |
|
|
|
// Re-scan the saved games |
|
ScanSavedGames( m_bFilterAutosaves ); |
|
|
|
// Re-layout the panels |
|
LayoutPanels(); |
|
|
|
// Run our animation again |
|
AnimateDialogStart(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PerformSelectedAction( void ) |
|
{ |
|
// By default, do nothing |
|
m_KeyRepeat.Reset(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PerformDeletion( void ) |
|
{ |
|
// By default, do nothing |
|
m_KeyRepeat.Reset(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Release our key repeater |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::OnKeyCodeReleased( vgui::KeyCode code ) |
|
{ |
|
m_KeyRepeat.KeyUp( code ); |
|
|
|
BaseClass::OnKeyCodeReleased( code ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Update our keypress repeater |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::OnThink( void ) |
|
{ |
|
vgui::KeyCode code = m_KeyRepeat.KeyRepeated(); |
|
if ( code ) |
|
{ |
|
OnKeyCodePressed( code ); |
|
} |
|
|
|
BaseClass::OnThink(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::OnKeyCodePressed( vgui::KeyCode code ) |
|
{ |
|
// If the console has UI up, then ignore it |
|
if ( BasePanel()->IsWaitingForConsoleUI() ) |
|
return; |
|
|
|
// Inhibit key activity during transitions |
|
if ( GetAlpha() != 255 || m_bControlDisabled ) |
|
return; |
|
|
|
m_KeyRepeat.KeyDown( code ); |
|
|
|
switch( code ) |
|
{ |
|
case KEY_XBUTTON_A: |
|
case STEAMCONTROLLER_A: |
|
PerformSelectedAction(); |
|
break; |
|
|
|
case KEY_XBUTTON_B: |
|
case STEAMCONTROLLER_B: |
|
OnClose(); |
|
break; |
|
|
|
case KEY_XBUTTON_X: |
|
case STEAMCONTROLLER_X: |
|
PerformDeletion(); |
|
break; |
|
|
|
case KEY_XBUTTON_Y: |
|
case STEAMCONTROLLER_Y: |
|
BasePanel()->OnChangeStorageDevice(); |
|
break; |
|
|
|
// Move the selection up and down |
|
case KEY_XSTICK1_LEFT: |
|
case KEY_XBUTTON_LEFT: |
|
case STEAMCONTROLLER_DPAD_LEFT: |
|
ScrollSelectionPanels( SCROLL_RIGHT ); |
|
break; |
|
|
|
case KEY_XSTICK1_RIGHT: |
|
case KEY_XBUTTON_RIGHT: |
|
case STEAMCONTROLLER_DPAD_RIGHT: |
|
ScrollSelectionPanels( SCROLL_LEFT ); |
|
break; |
|
|
|
default: |
|
break; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::PaintBackground( void ) |
|
{ |
|
int wide, tall; |
|
GetSize( wide, tall ); |
|
|
|
Color col = GetBgColor(); |
|
DrawBox( 0, 0, wide, tall, col, 1.0f ); |
|
|
|
int y = 32; |
|
|
|
// draw an inset |
|
Color darkColor; |
|
darkColor.SetColor( 0.70f * (float)col.r(), 0.70f * (float)col.g(), 0.70f * (float)col.b(), col.a() ); |
|
vgui::surface()->DrawSetColor( darkColor ); |
|
vgui::surface()->DrawFilledRect( 8, y, wide - 8, tall - 8 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Parses the save game info out of the .sav file header |
|
//----------------------------------------------------------------------------- |
|
bool CSaveGameBrowserDialog::ParseSaveData( char const *pszFileName, char const *pszShortName, SaveGameDescription_t *save ) |
|
{ |
|
char szMapName[SAVEGAME_MAPNAME_LEN]; |
|
char szComment[SAVEGAME_COMMENT_LEN]; |
|
char szElapsedTime[SAVEGAME_ELAPSED_LEN]; |
|
|
|
if ( !pszFileName || !pszShortName ) |
|
return false; |
|
|
|
Q_strncpy( save->szShortName, pszShortName, sizeof(save->szShortName) ); |
|
Q_strncpy( save->szFileName, pszFileName, sizeof(save->szFileName) ); |
|
|
|
FileHandle_t fh = g_pFullFileSystem->Open( pszFileName, "rb", "MOD" ); |
|
if (fh == FILESYSTEM_INVALID_HANDLE) |
|
return false; |
|
|
|
save->iSize = g_pFullFileSystem->Size( fh ); |
|
|
|
int readok = SaveReadNameAndComment( fh, szMapName, sizeof(szMapName), szComment, sizeof(szComment) ); |
|
g_pFullFileSystem->Close(fh); |
|
|
|
if ( !readok ) |
|
{ |
|
return false; |
|
} |
|
|
|
Q_strncpy( save->szMapName, szMapName, sizeof(save->szMapName) ); |
|
|
|
// Elapsed time is the last 6 characters in comment. (mmm:ss) |
|
int i; |
|
i = strlen( szComment ); |
|
Q_strncpy( szElapsedTime, "??", sizeof( szElapsedTime ) ); |
|
if (i >= 6) |
|
{ |
|
Q_strncpy( szElapsedTime, (char *)&szComment[i - 6], 7 ); |
|
szElapsedTime[6] = '\0'; |
|
|
|
// parse out |
|
int minutes = atoi( szElapsedTime ); |
|
int seconds = atoi( szElapsedTime + 4); |
|
int hours = minutes / 60; |
|
minutes %= 60; |
|
|
|
wchar_t wzHours[6]; |
|
wchar_t wzMins[4]; |
|
wchar_t wzSecs[4]; |
|
|
|
_snwprintf( wzHours, ARRAYSIZE(wzHours), L"%d", hours ); |
|
_snwprintf( wzMins, ARRAYSIZE(wzMins), L"%d", minutes ); |
|
_snwprintf( wzSecs, ARRAYSIZE(wzSecs), L"%d", seconds ); |
|
|
|
wchar_t buf[20]; |
|
|
|
// reformat |
|
if ( hours ) |
|
{ |
|
g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Hr_Min" ), 2, wzHours, wzMins ); |
|
} |
|
else if ( minutes ) |
|
{ |
|
g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Min_Sec" ), 2, wzMins, wzSecs ); |
|
} |
|
else |
|
{ |
|
g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_LoadDialog_Sec" ), 1, wzSecs ); |
|
} |
|
|
|
g_pVGuiLocalize->ConvertUnicodeToANSI( buf, szElapsedTime, sizeof(szElapsedTime) ); |
|
|
|
// Chop elapsed out of comment. |
|
char *pChop = Q_stristr( szComment, " " ); |
|
if ( pChop != NULL ) |
|
{ |
|
(*pChop) = '\0'; |
|
} |
|
} |
|
|
|
// calculate the file name to print |
|
const char *pszType = ""; |
|
if (strstr(pszFileName, "quick")) |
|
{ |
|
pszType = "#GameUI_QuickSave"; |
|
} |
|
else if (strstr(pszFileName, "autosave")) |
|
{ |
|
pszType = "#GameUI_AutoSave"; |
|
} |
|
|
|
Q_strncpy( save->szType, pszType, sizeof(save->szType) ); |
|
Q_strncpy( save->szComment, szComment, sizeof(save->szComment) ); |
|
Q_strncpy( save->szElapsedTime, szElapsedTime, sizeof(save->szElapsedTime) ); |
|
|
|
// Now get file time stamp. |
|
time_t fileTime = g_pFullFileSystem->GetFileTime(pszFileName); |
|
char szFileTime[32]; |
|
g_pFullFileSystem->FileTimeToString(szFileTime, sizeof(szFileTime), fileTime); |
|
char *newline = strstr(szFileTime, "\n"); |
|
if (newline) |
|
{ |
|
*newline = 0; |
|
} |
|
Q_strncpy( save->szFileTime, szFileTime, sizeof(save->szFileTime) ); |
|
save->iTimestamp = fileTime; |
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Update our footer options depending on what we've selected |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::UpdateFooterOptions( void ) |
|
{ |
|
// Do nothing |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Sort our games by time |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::SortSaveGames( SaveGameDescription_t *pSaves, unsigned int nNumSaves ) |
|
{ |
|
qsort( pSaves, nNumSaves, sizeof(SaveGameDescription_t), &CBaseSaveGameDialog::SaveGameSortFunc ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: builds save game list from directory |
|
//----------------------------------------------------------------------------- |
|
void CSaveGameBrowserDialog::ScanSavedGames( bool bIgnoreAutosave ) |
|
{ |
|
// Start with a clean slate |
|
m_nUsedStorageSpace = 0; |
|
m_bSaveGameIsCorrupt = false; |
|
|
|
// Clear all known panels I'm holding now |
|
m_SavePanels.PurgeAndDeleteElements(); |
|
|
|
// Reset all indices |
|
for ( int i = 0; i < NUM_SLOTS; ++i ) |
|
{ |
|
m_PanelIndex[i] = INVALID_INDEX; |
|
} |
|
|
|
// Clear our list |
|
CUtlVector<SaveGameDescription_t> saveGames; |
|
|
|
// Get the search path |
|
char szDirectory[_MAX_PATH]; |
|
|
|
if ( IsX360() ) |
|
Q_snprintf( szDirectory, sizeof( szDirectory ), "%s:/*", COM_GetModDirectory() ); |
|
else |
|
Q_snprintf( szDirectory, sizeof( szDirectory ), "save/*" ); |
|
|
|
Q_DefaultExtension( szDirectory, IsX360() ? ".360.sav" : ".sav", sizeof( szDirectory ) ); |
|
Q_FixSlashes( szDirectory ); |
|
|
|
// iterate the saved files |
|
FileFindHandle_t handle; |
|
const char *pFileName = g_pFullFileSystem->FindFirst( szDirectory, &handle ); |
|
while (pFileName) |
|
{ |
|
if ( !Q_strnicmp(pFileName, "HLSave", strlen( "HLSave" ) ) ) |
|
{ |
|
pFileName = g_pFullFileSystem->FindNext( handle ); |
|
continue; |
|
} |
|
|
|
char szFileName[_MAX_PATH]; |
|
|
|
if ( IsX360() ) |
|
Q_snprintf(szFileName, sizeof( szFileName ), "%s:/%s", COM_GetModDirectory(), pFileName ); |
|
else |
|
Q_snprintf(szFileName, sizeof( szFileName ), "save/%s", pFileName); |
|
|
|
Q_FixSlashes( szFileName ); |
|
|
|
// Only load save games from the current mod's save dir |
|
if( !g_pFullFileSystem->FileExists( szFileName, "MOD" ) ) |
|
{ |
|
pFileName = g_pFullFileSystem->FindNext( handle ); |
|
continue; |
|
} |
|
|
|
SaveGameDescription_t save; |
|
if ( ParseSaveData( szFileName, pFileName, &save ) ) |
|
{ |
|
// Add on this file's size to the count |
|
m_nUsedStorageSpace += save.iSize; |
|
|
|
// Always ignore autosave dangerous (they're not considered safe until committed) |
|
if ( Q_stristr( save.szShortName, "dangerous" ) ) |
|
{ |
|
pFileName = g_pFullFileSystem->FindNext( handle ); |
|
continue; |
|
} |
|
|
|
// If we're ignoring autosaves, skip it here |
|
if ( bIgnoreAutosave ) |
|
{ |
|
if ( !Q_stricmp( save.szType, "#GameUI_Autosave" ) ) |
|
{ |
|
pFileName = g_pFullFileSystem->FindNext( handle ); |
|
continue; |
|
} |
|
} |
|
|
|
saveGames.AddToTail( save ); |
|
} |
|
|
|
pFileName = g_pFullFileSystem->FindNext( handle ); |
|
} |
|
|
|
g_pFullFileSystem->FindClose( handle ); |
|
|
|
// Sort the save list |
|
SortSaveGames( saveGames.Base(), saveGames.Count() ); |
|
|
|
// Now add them in order |
|
for ( int i = 0; i < saveGames.Count(); i++ ) |
|
{ |
|
CGameSavePanel *savePanel = SETUP_PANEL( new CGameSavePanel( this, &saveGames[i] ) ); |
|
|
|
savePanel->SetVisible( false ); |
|
m_SavePanels.AddToTail( savePanel ); |
|
} |
|
|
|
// Notify derived classes that save games are done being scanned |
|
OnDoneScanningSaveGames(); |
|
|
|
// Always start with the first panel (as we're sorted in a specific order) |
|
SetSelectedSaveIndex( 0 ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Return the currently selected panel |
|
//----------------------------------------------------------------------------- |
|
CGameSavePanel *CSaveGameBrowserDialog::GetActivePanel( void ) |
|
{ |
|
if ( IsValidPanel( m_iSelectedSave ) == false ) |
|
return NULL; |
|
|
|
return m_SavePanels[ m_iSelectedSave ]; |
|
}
|
|
|