mirror of
https://github.com/nillerusr/source-engine.git
synced 2025-02-04 19:24:13 +00:00
1236 lines
36 KiB
C++
1236 lines
36 KiB
C++
#include "gamepadui_interface.h"
|
|
#include "gamepadui_image.h"
|
|
#include "gamepadui_util.h"
|
|
#include "gamepadui_genericconfirmation.h"
|
|
#include "gamepadui_scrollbar.h"
|
|
|
|
#include "ienginevgui.h"
|
|
#include "vgui/ILocalize.h"
|
|
#include "vgui/ISurface.h"
|
|
#include "vgui/IVGui.h"
|
|
#include "GameUI/IGameUI.h"
|
|
|
|
#include "vgui_controls/ComboBox.h"
|
|
#include "vgui_controls/ImagePanel.h"
|
|
#include "vgui_controls/ScrollBar.h"
|
|
#include "savegame_version.h"
|
|
|
|
#include "KeyValues.h"
|
|
#include "filesystem.h"
|
|
|
|
#include "tier0/memdbgon.h"
|
|
|
|
ConVar gamepadui_savegame_use_delete_mode( "gamepadui_savegame_use_delete_mode", "1", FCVAR_NONE, "Causes the save game panel to use a \"delete mode\" when not using a controller, showing X buttons next to each save game" );
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
ConVar gamepadui_savegame_wilson_thumb( "gamepadui_savegame_wilson_thumb", "1", FCVAR_NONE, "Shows a Wilson icon on save games that have Wilson" );
|
|
#endif
|
|
|
|
class GamepadUISaveButton;
|
|
struct SaveGameDescription_t;
|
|
|
|
class GamepadUISaveGamePanel : public GamepadUIFrame
|
|
{
|
|
DECLARE_CLASS_SIMPLE( GamepadUISaveGamePanel, GamepadUIFrame );
|
|
|
|
public:
|
|
GamepadUISaveGamePanel( vgui::Panel *pParent, const char* pPanelName, bool bIsSave );
|
|
~GamepadUISaveGamePanel();
|
|
|
|
void UpdateGradients();
|
|
|
|
void ApplySchemeSettings( vgui::IScheme *pScheme ) OVERRIDE;
|
|
void OnThink() OVERRIDE;
|
|
void Paint() OVERRIDE;
|
|
void OnCommand( char const* pCommand ) OVERRIDE;
|
|
void OnMouseWheeled( int nDelta ) OVERRIDE;
|
|
|
|
bool InDeleteMode() { return m_pDeletePanels.Count() > 0; }
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
int IsSaveSuspect( const char *pszEZ2Version, const char *pszMapName, int nMapVersion, const char **ppszIncompatibleVersion, const char **ppszLastCompatibleBranch );
|
|
|
|
GamepadUIImage &GetWilsonThumb( float &flSize, float &flOffsetX, float &flOffsetY )
|
|
{
|
|
flSize = m_flThumbSize; flOffsetX = m_flThumbOffsetX; flOffsetY = m_flThumbOffsetY;
|
|
return m_WilsonThumb;
|
|
}
|
|
#endif
|
|
|
|
MESSAGE_FUNC_HANDLE( OnGamepadUIButtonNavigatedTo, "OnGamepadUIButtonNavigatedTo", button );
|
|
|
|
private:
|
|
void ScanSavedGames();
|
|
void LayoutSaveButtons();
|
|
bool ParseSaveData( char const* pFileName, char const* pShortName, SaveGameDescription_t& save );
|
|
static int SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP( nameSize ) char* name, int nameSize, OUT_Z_CAP( commentSize ) char* comment, int commentSize );
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
static int SaveReadCustomMetadata( const char *pSaveName, char *ez2version, int ez2versionSize, char *platform, int platformSize, int &nMapVersion, bool &bDeck, bool &bWilson );
|
|
|
|
void LoadVersionHistory();
|
|
void UnloadVersionHistory();
|
|
#endif
|
|
void FindSaveSlot( OUT_Z_CAP( bufsize ) char* buffer, int bufsize );
|
|
void DeleteSaveGame( const char* pFileName );
|
|
|
|
void LoadGame( const SaveGameDescription_t* pSave );
|
|
void SaveGame( const SaveGameDescription_t *pSave );
|
|
|
|
GamepadUIString m_strNoSaveString;
|
|
|
|
CUtlVector<GamepadUISaveButton*> m_pSavePanels;
|
|
CUtlVector<SaveGameDescription_t> m_Saves;
|
|
|
|
CUtlVector<GamepadUIButton*> m_pDeletePanels;
|
|
|
|
GamepadUIScrollState m_ScrollState;
|
|
|
|
GamepadUIScrollBar *m_pScrollBar = NULL;
|
|
|
|
bool m_bIsSave;
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
KeyValues *m_pVersionHistory;
|
|
|
|
GamepadUIImage m_WilsonThumb;
|
|
#endif
|
|
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flSavesFade, "Saves.Fade", "0", SchemeValueTypes::ProportionalFloat );
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flSavesOffsetX, "Saves.OffsetX", "0", SchemeValueTypes::ProportionalFloat );
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flSavesOffsetY, "Saves.OffsetY", "0", SchemeValueTypes::ProportionalFloat );
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flSavesSpacing, "Saves.Spacing", "0", SchemeValueTypes::ProportionalFloat );
|
|
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flThumbSize, "Saves.Thumb.Size", "16", SchemeValueTypes::ProportionalFloat );
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flThumbOffsetX, "Saves.Thumb.OffsetX", "4", SchemeValueTypes::ProportionalFloat );
|
|
GAMEPADUI_PANEL_PROPERTY( float, m_flThumbOffsetY, "Saves.Thumb.OffsetY", "4", SchemeValueTypes::ProportionalFloat );
|
|
};
|
|
|
|
/* From GameUI */
|
|
struct SaveGameDescription_t;
|
|
#define SAVEGAME_MAPNAME_LEN 32
|
|
#define SAVEGAME_COMMENT_LEN 80
|
|
#define SAVEGAME_ELAPSED_LEN 32
|
|
|
|
#define TGA_IMAGE_PANEL_WIDTH 180
|
|
#define TGA_IMAGE_PANEL_HEIGHT 100
|
|
#define MAX_LISTED_SAVE_GAMES 128
|
|
#define NEW_SAVE_GAME_TIMESTAMP 0xFFFFFFFF
|
|
|
|
struct SaveGameDescription_t
|
|
{
|
|
char szShortName[64];
|
|
char szFileName[128];
|
|
char szMapName[SAVEGAME_MAPNAME_LEN];
|
|
char szComment[SAVEGAME_COMMENT_LEN];
|
|
char szType[64];
|
|
char szElapsedTime[SAVEGAME_ELAPSED_LEN];
|
|
char szFileTime[32];
|
|
unsigned int iTimestamp;
|
|
unsigned int iSize;
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
char szEZ2Version[8];
|
|
char szPlatform[16];
|
|
int nMapVersion;
|
|
bool bDeck;
|
|
bool bWilson;
|
|
#endif
|
|
};
|
|
/* End from GameUI */
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
enum
|
|
{
|
|
SaveSuspectLevel_None,
|
|
SaveSuspectLevel_Mismatch, // Save is from a different version
|
|
SaveSuspectLevel_Incompatible, // Save is from an explicitly incompatible version
|
|
};
|
|
#endif
|
|
|
|
class GamepadUISaveButton : public GamepadUIButton
|
|
{
|
|
public:
|
|
DECLARE_CLASS_SIMPLE( GamepadUISaveButton, GamepadUIButton );
|
|
|
|
GamepadUISaveButton( vgui::Panel* pParent, vgui::Panel* pActionSignalTarget, const char *pSchemeFile, const char* pCommand, const SaveGameDescription_t *pSaveGame )
|
|
: BaseClass( pParent, pActionSignalTarget, pSchemeFile, pCommand, pSaveGame->szComment, pSaveGame->szFileTime )
|
|
, m_Image()
|
|
, m_pSaveGame( pSaveGame )
|
|
{
|
|
char tga[_MAX_PATH];
|
|
Q_strncpy( tga, pSaveGame->szFileName, sizeof( tga ) );
|
|
char *ext = strstr( tga, ".sav" );
|
|
if ( ext )
|
|
strcpy( ext, ".tga" );
|
|
|
|
char tga2[_MAX_PATH];
|
|
Q_snprintf( tga2, sizeof( tga2 ), "//MOD/%s", tga );
|
|
|
|
if ( g_pFullFileSystem->FileExists( tga2 ) )
|
|
{
|
|
m_Image.SetTGAImage( tga2 );
|
|
m_bUseTGAImage = true;
|
|
}
|
|
else
|
|
{
|
|
m_Image.SetImage( "gamepadui/save_game.vmt" );
|
|
}
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
m_strEZ2Version = GamepadUIString( pSaveGame->szEZ2Version );
|
|
#endif
|
|
}
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
void RunAnimations( ButtonState state )
|
|
{
|
|
BaseClass::RunAnimations( state );
|
|
|
|
GAMEPADUI_RUN_ANIMATION_COMMAND( m_colVersion, vgui::AnimationController::INTERPOLATOR_LINEAR );
|
|
}
|
|
|
|
void ApplySchemeSettings( vgui::IScheme *pScheme ) OVERRIDE
|
|
{
|
|
BaseClass::ApplySchemeSettings( pScheme );
|
|
|
|
char szVersion[8];
|
|
V_UnicodeToUTF8( m_strEZ2Version.String(), szVersion, sizeof( szVersion ) );
|
|
m_iSaveSuspectLevel = static_cast<GamepadUISaveGamePanel *>(GetParent())->IsSaveSuspect( szVersion, m_pSaveGame->szMapName, m_pSaveGame->nMapVersion, &m_pIncompatibleVersion, &m_pLastCompatibleBranch );
|
|
|
|
if ( m_iSaveSuspectLevel != SaveSuspectLevel_None )
|
|
{
|
|
switch (m_iSaveSuspectLevel)
|
|
{
|
|
case SaveSuspectLevel_Mismatch:
|
|
m_colVersionAnimationValue[ButtonStates::Out] = m_colVersionMismatch;
|
|
break;
|
|
|
|
case SaveSuspectLevel_Incompatible:
|
|
{
|
|
// For now, correspond suspect colors to over and out states
|
|
m_colBackgroundColorAnimationValue[ButtonStates::Over] = m_colVersionIncompatible;
|
|
m_colTextColorAnimationValue[ButtonStates::Out] = m_colVersionIncompatible;
|
|
m_colDescriptionColorAnimationValue[ButtonStates::Out] = m_colVersionIncompatible;
|
|
m_colVersionAnimationValue[ButtonStates::Out] = m_colVersionIncompatible;
|
|
break;
|
|
}
|
|
}
|
|
|
|
DoAnimations( true );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void Paint() OVERRIDE
|
|
{
|
|
int x, y, w, t;
|
|
GetBounds( x, y, w, t );
|
|
|
|
PaintButton();
|
|
|
|
// Save game icons are 180x100
|
|
int imgW = (t * 180) / 100;
|
|
|
|
if ( m_Image.IsValid() )
|
|
{
|
|
vgui::surface()->DrawSetColor( Color( 255, 255, 255, 255 ) );
|
|
vgui::surface()->DrawSetTexture( m_Image );
|
|
int imgH = t;
|
|
// Half pixel offset to avoid leaking into pink + black
|
|
if ( m_bUseTGAImage )
|
|
{
|
|
const float flHalfPixelX = ( 0.5f / 180.0f );
|
|
const float flHalfPixelY = ( 0.5f / 100.0f );
|
|
vgui::surface()->DrawTexturedSubRect( 0, 0, imgW, imgH, 0.0f, 0.0f, 1.0f - flHalfPixelX, 1.0f - flHalfPixelY );
|
|
}
|
|
else
|
|
{
|
|
vgui::surface()->DrawTexturedRect( 0, 0, imgW, imgH );
|
|
}
|
|
vgui::surface()->DrawSetTexture( 0 );
|
|
}
|
|
else
|
|
{
|
|
vgui::surface()->DrawSetColor( Color( 0, 0, 0, 255 ) );
|
|
imgW = ( t * 180 ) / 100;
|
|
int imgH = t;
|
|
vgui::surface()->DrawFilledRect( 0, 0, imgW, imgH );
|
|
}
|
|
|
|
PaintText();
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
if ( m_pSaveGame->iTimestamp != NEW_SAVE_GAME_TIMESTAMP )
|
|
{
|
|
const wchar_t *pwszEZ2Version = m_strEZ2Version.String();
|
|
int nEZ2VerLen = m_strEZ2Version.Length();
|
|
if (m_strEZ2Version.IsEmpty())
|
|
{
|
|
// Display a question mark for unknown versions
|
|
pwszEZ2Version = L"?";
|
|
nEZ2VerLen = 1;
|
|
}
|
|
|
|
int nTextW, nTextH;
|
|
vgui::surface()->GetTextSize( m_hDescriptionFont, pwszEZ2Version, nTextW, nTextH );
|
|
|
|
int nTextX = m_flWidth - m_flTextOffsetX - nTextW + imgW;
|
|
int nTextY = m_flHeight + m_flTextOffsetY - nTextH;
|
|
|
|
vgui::surface()->DrawSetTextFont( m_hTextFont );
|
|
vgui::surface()->DrawSetTextPos( nTextX, nTextY );
|
|
vgui::surface()->DrawSetTextColor( m_colVersion );
|
|
vgui::surface()->DrawPrintText( pwszEZ2Version, nEZ2VerLen );
|
|
}
|
|
|
|
if ( m_pSaveGame->bWilson && gamepadui_savegame_wilson_thumb.GetBool() )
|
|
{
|
|
float flSize, flOffsetX, flOffsetY;
|
|
vgui::surface()->DrawSetColor( m_colDescriptionColor );
|
|
vgui::surface()->DrawSetTexture( static_cast<GamepadUISaveGamePanel*>(GetParent())->GetWilsonThumb( flSize, flOffsetX, flOffsetY ) );
|
|
//vgui::surface()->DrawTexturedSubRect( m_flWidth - flOffsetX - flSize, flOffsetY, m_flWidth - flOffsetX, flOffsetY + flSize, 0.28125f, 0.1875f, 0.703125f, 0.703125f );
|
|
vgui::surface()->DrawTexturedSubRect( flOffsetX, flOffsetY, flOffsetX + flSize, flOffsetY + flSize, 0.28125f, 0.1875f, 0.703125f, 0.703125f );
|
|
vgui::surface()->DrawSetTexture( 0 );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
const SaveGameDescription_t* GetSaveGame() const
|
|
{
|
|
return m_pSaveGame;
|
|
}
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
int GetSaveSuspectLevel() const
|
|
{
|
|
return m_iSaveSuspectLevel;
|
|
}
|
|
|
|
const char *GetIncompatibleVersion() const
|
|
{
|
|
return m_pIncompatibleVersion;
|
|
}
|
|
|
|
const char *GetLastCompatibleBranch() const
|
|
{
|
|
return m_pLastCompatibleBranch;
|
|
}
|
|
#endif
|
|
|
|
private:
|
|
bool m_bUseTGAImage = false;
|
|
GamepadUIImage m_Image;
|
|
const SaveGameDescription_t *m_pSaveGame;
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
GamepadUIString m_strEZ2Version;
|
|
|
|
int m_iSaveSuspectLevel;
|
|
const char *m_pIncompatibleVersion = NULL;
|
|
const char *m_pLastCompatibleBranch = NULL;
|
|
|
|
GAMEPADUI_BUTTON_ANIMATED_PROPERTY( Color, m_colVersion, "Button.Version", "255 255 255 255", SchemeValueTypes::Color );
|
|
GAMEPADUI_PANEL_PROPERTY( Color, m_colVersionMismatch, "Button.Version.Mismatch", "255 224 0 255", SchemeValueTypes::Color );
|
|
GAMEPADUI_PANEL_PROPERTY( Color, m_colVersionIncompatible, "Button.Version.Incompatible", "255 128 0 255", SchemeValueTypes::Color );
|
|
#endif
|
|
};
|
|
|
|
GamepadUISaveGamePanel::GamepadUISaveGamePanel( vgui::Panel* pParent, const char* pPanelName, bool bIsSave )
|
|
: BaseClass( pParent, pPanelName )
|
|
, m_bIsSave( bIsSave )
|
|
{
|
|
vgui::HScheme Scheme = vgui::scheme()->LoadSchemeFromFileEx( GamepadUI::GetInstance().GetSizingVPanel(), GAMEPADUI_DEFAULT_PANEL_SCHEME, "SchemePanel" );
|
|
SetScheme( Scheme );
|
|
|
|
GetFrameTitle() = GamepadUIString(m_bIsSave ? "#GameUI_SaveGame" : "#GameUI_LoadGame");
|
|
|
|
Activate();
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
m_WilsonThumb.SetImage( "vgui/icons/icon_wilson" );
|
|
|
|
LoadVersionHistory();
|
|
#endif
|
|
ScanSavedGames();
|
|
|
|
if ( m_pSavePanels.Count() )
|
|
m_pSavePanels[0]->NavigateTo();
|
|
|
|
UpdateGradients();
|
|
}
|
|
|
|
GamepadUISaveGamePanel::~GamepadUISaveGamePanel()
|
|
{
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
UnloadVersionHistory();
|
|
#endif
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::UpdateGradients()
|
|
{
|
|
const float flTime = GamepadUI::GetInstance().GetTime();
|
|
GamepadUI::GetInstance().GetGradientHelper()->ResetTargets( flTime );
|
|
GamepadUI::GetInstance().GetGradientHelper()->SetTargetGradient( GradientSide::Up, { 1.0f, 1.0f }, flTime );
|
|
GamepadUI::GetInstance().GetGradientHelper()->SetTargetGradient( GradientSide::Down, { 1.0f, 1.0f }, flTime );
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::ApplySchemeSettings( vgui::IScheme *pScheme )
|
|
{
|
|
BaseClass::ApplySchemeSettings( pScheme );
|
|
|
|
m_bFooterButtonsStack = true;
|
|
|
|
float flX, flY;
|
|
if (GamepadUI::GetInstance().GetScreenRatio( flX, flY ))
|
|
{
|
|
m_flSavesOffsetX *= (flX);
|
|
}
|
|
|
|
int nX, nY;
|
|
GamepadUI::GetInstance().GetSizingPanelOffset( nX, nY );
|
|
if (nX > 0)
|
|
{
|
|
GamepadUI::GetInstance().GetSizingPanelScale( flX, flY );
|
|
flX *= 0.4f;
|
|
|
|
m_flSavesOffsetX += ((float)nX) * flX;
|
|
m_flSavesFade += ((float)nX) * flX;
|
|
}
|
|
|
|
if ( m_pScrollBar )
|
|
{
|
|
m_pScrollBar->InitScrollBar( &m_ScrollState, m_flSavesOffsetX + m_pSavePanels[0]->GetWide() + m_flSavesSpacing, m_flSavesOffsetY );
|
|
}
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::OnThink()
|
|
{
|
|
BaseClass::OnThink();
|
|
|
|
LayoutSaveButtons();
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::Paint()
|
|
{
|
|
BaseClass::Paint();
|
|
|
|
if ( !m_strNoSaveString.IsEmpty() )
|
|
{
|
|
int nParentW, nParentH;
|
|
GetParent()->GetSize( nParentW, nParentH );
|
|
|
|
vgui::surface()->DrawSetTextFont( m_hGenericFont );
|
|
vgui::surface()->DrawSetTextColor( Color( 255, 255, 255, 255 ) );
|
|
int nTextW, nTextH;
|
|
vgui::surface()->GetTextSize( m_hGenericFont, m_strNoSaveString.String(), nTextW, nTextH );
|
|
vgui::surface()->DrawSetTextPos( nParentW / 2 - nTextW / 2, m_flSavesOffsetY + nTextH );
|
|
vgui::surface()->DrawPrintText( m_strNoSaveString.String(), m_strNoSaveString.Length() );
|
|
}
|
|
}
|
|
|
|
/* Mostly from GameUI */
|
|
void GamepadUISaveGamePanel::ScanSavedGames()
|
|
{
|
|
m_Saves.Purge();
|
|
m_pSavePanels.PurgeAndDeleteElements();
|
|
m_pDeletePanels.PurgeAndDeleteElements();
|
|
|
|
if ( m_bIsSave )
|
|
m_Saves.AddToTail( SaveGameDescription_t{ "NewSavedGame", "", "", "#GameUI_NewSaveGame", "", "", "Current", NEW_SAVE_GAME_TIMESTAMP } );
|
|
|
|
// populate list box with all saved games on record:
|
|
char szDirectory[_MAX_PATH];
|
|
Q_snprintf( szDirectory, sizeof( szDirectory ), "save/*.sav" );
|
|
|
|
// 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];
|
|
Q_snprintf( szFileName, sizeof( szFileName ), "save/%s", pFileName );
|
|
|
|
// 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 ) )
|
|
{
|
|
m_Saves.AddToTail( save );
|
|
}
|
|
|
|
pFileName = g_pFullFileSystem->FindNext( handle );
|
|
}
|
|
|
|
g_pFullFileSystem->FindClose( handle );
|
|
|
|
// sort the save list
|
|
qsort( m_Saves.Base(), m_Saves.Count(), sizeof( SaveGameDescription_t ), []( const void* lhs, const void* rhs ) {
|
|
const SaveGameDescription_t *s1 = ( const SaveGameDescription_t * )lhs;
|
|
const SaveGameDescription_t *s2 = ( const SaveGameDescription_t * )rhs;
|
|
|
|
if ( s1->iTimestamp < s2->iTimestamp )
|
|
return 1;
|
|
else if ( s1->iTimestamp > s2->iTimestamp )
|
|
return -1;
|
|
|
|
// timestamps are equal, so just sort by filename
|
|
return strcmp( s1->szFileName, s2->szFileName );
|
|
} );
|
|
|
|
// add to the list
|
|
for ( int saveIndex = 0; saveIndex < m_Saves.Count() && saveIndex < MAX_LISTED_SAVE_GAMES; saveIndex++ )
|
|
{
|
|
GamepadUISaveButton *button = new GamepadUISaveButton( this, this, GAMEPADUI_RESOURCE_FOLDER "schemesavebutton.res", "load_save", &m_Saves[saveIndex] );
|
|
button->SetPriority( saveIndex );
|
|
button->SetForwardToParent( true );
|
|
m_pSavePanels.AddToTail( button );
|
|
}
|
|
|
|
// display a message if there are no save games
|
|
if ( !m_Saves.Count() )
|
|
{
|
|
m_strNoSaveString = GamepadUIString( "#GameUI_NoSaveGamesToDisplay" );
|
|
SetFooterButtons( FooterButtons::Back );
|
|
}
|
|
else
|
|
{
|
|
if ( m_bIsSave )
|
|
{
|
|
SetFooterButtons( FooterButtons::Back | FooterButtons::Select, FooterButtons::Select );
|
|
}
|
|
else
|
|
{
|
|
SetFooterButtons( FooterButtons::Back | FooterButtons::Delete | FooterButtons::Select, FooterButtons::Select );
|
|
}
|
|
}
|
|
|
|
SetControlEnabled( "loadsave", false );
|
|
SetControlEnabled( "delete", false );
|
|
|
|
if ( m_pSavePanels.Count() )
|
|
{
|
|
if ( !m_pScrollBar )
|
|
{
|
|
m_pScrollBar = new GamepadUIScrollBar(
|
|
this, this,
|
|
GAMEPADUI_RESOURCE_FOLDER "schemescrollbar.res",
|
|
NULL, false );
|
|
|
|
m_pScrollBar->SetNavLeft( m_pSavePanels[0] );
|
|
}
|
|
}
|
|
else if ( m_pScrollBar )
|
|
{
|
|
m_pScrollBar->MarkForDeletion();
|
|
m_pScrollBar = NULL;
|
|
}
|
|
|
|
for ( int i = 1; i < m_pSavePanels.Count(); i++ )
|
|
{
|
|
m_pSavePanels[i]->SetNavUp( m_pSavePanels[i - 1] );
|
|
m_pSavePanels[i - 1]->SetNavDown( m_pSavePanels[i] );
|
|
}
|
|
}
|
|
|
|
bool GamepadUISaveGamePanel::ParseSaveData( char const* pFileName, char const* pShortName, SaveGameDescription_t& save )
|
|
{
|
|
char szMapName[SAVEGAME_MAPNAME_LEN];
|
|
char szComment[SAVEGAME_COMMENT_LEN];
|
|
char szElapsedTime[SAVEGAME_ELAPSED_LEN];
|
|
|
|
if ( !pFileName || !pShortName )
|
|
return false;
|
|
|
|
Q_strncpy( save.szShortName, pShortName, sizeof( save.szShortName ) );
|
|
Q_strncpy( save.szFileName, pFileName, sizeof( save.szFileName ) );
|
|
|
|
FileHandle_t fh = g_pFullFileSystem->Open( pFileName, "rb", "MOD" );
|
|
if ( fh == FILESYSTEM_INVALID_HANDLE )
|
|
return false;
|
|
|
|
int readok = SaveReadNameAndComment( fh, szMapName, ARRAYSIZE( szMapName ), szComment, ARRAYSIZE( szComment ) );
|
|
g_pFullFileSystem->Close( fh );
|
|
|
|
if ( !readok )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
char szEZ2Version[8];
|
|
char szPlatform[16];
|
|
int nMapVersion = 0;
|
|
bool bDeck = false;
|
|
bool bWilson = false;
|
|
SaveReadCustomMetadata( pFileName, szEZ2Version, sizeof(szEZ2Version), szPlatform, sizeof(szPlatform), nMapVersion, bDeck, bWilson );
|
|
#endif
|
|
|
|
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 );
|
|
|
|
// reformat
|
|
if ( minutes )
|
|
{
|
|
Q_snprintf( szElapsedTime, sizeof( szElapsedTime ), "%d %s %d seconds", minutes, minutes > 1 ? "minutes" : "minute", seconds );
|
|
}
|
|
else
|
|
{
|
|
Q_snprintf( szElapsedTime, sizeof( szElapsedTime ), "%d seconds", seconds );
|
|
}
|
|
|
|
// Chop elapsed out of comment.
|
|
int n;
|
|
|
|
n = i - 6;
|
|
szComment[n] = '\0';
|
|
|
|
n--;
|
|
|
|
// Strip back the spaces at the end.
|
|
while ( ( n >= 1 ) &&
|
|
szComment[n] &&
|
|
szComment[n] == ' ' )
|
|
{
|
|
szComment[n--] = '\0';
|
|
}
|
|
}
|
|
|
|
// calculate the file name to print
|
|
const char* pszType = "";
|
|
if ( strstr( pFileName, "quick" ) )
|
|
{
|
|
pszType = "#GameUI_QuickSave";
|
|
}
|
|
else if ( strstr( pFileName, "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.
|
|
long fileTime = g_pFullFileSystem->GetFileTime( pFileName );
|
|
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;
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
Q_strncpy( save.szEZ2Version, szEZ2Version, sizeof( save.szEZ2Version ) );
|
|
Q_strncpy( save.szPlatform, szPlatform, sizeof( save.szPlatform ) );
|
|
save.nMapVersion = nMapVersion;
|
|
save.bDeck = bDeck;
|
|
save.bWilson = bWilson;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
int GamepadUISaveGamePanel::SaveReadNameAndComment( FileHandle_t f, OUT_Z_CAP( nameSize ) char* name, int nameSize, OUT_Z_CAP( commentSize ) char* comment, int commentSize )
|
|
{
|
|
int i, tag, size, tokenSize, tokenCount;
|
|
char* pSaveData, * pFieldName, ** pTokenList;
|
|
|
|
name[0] = '\0';
|
|
comment[0] = '\0';
|
|
|
|
g_pFullFileSystem->Read( &tag, sizeof( int ), f );
|
|
if ( tag != MAKEID( 'J', 'S', 'A', 'V' ) )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
g_pFullFileSystem->Read( &tag, sizeof( int ), f );
|
|
if ( tag != SAVEGAME_VERSION ) // Enforce version for now
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
g_pFullFileSystem->Read( &size, sizeof( int ), f );
|
|
|
|
g_pFullFileSystem->Read( &tokenCount, sizeof( int ), f ); // These two ints are the token list
|
|
g_pFullFileSystem->Read( &tokenSize, sizeof( int ), f );
|
|
size += tokenSize;
|
|
|
|
// Sanity Check.
|
|
if ( tokenCount < 0 || tokenCount > 1024 * 1024 * 32 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if ( tokenSize < 0 || tokenSize > 1024 * 1024 * 32 )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
pSaveData = ( char* )new char[size];
|
|
g_pFullFileSystem->Read( pSaveData, size, f );
|
|
|
|
int nNumberOfFields;
|
|
|
|
char* pData;
|
|
int nFieldSize;
|
|
|
|
pData = pSaveData;
|
|
|
|
// Allocate a table for the strings, and parse the table
|
|
if ( tokenSize > 0 )
|
|
{
|
|
pTokenList = new char* [tokenCount];
|
|
|
|
// Make sure the token strings pointed to by the pToken hashtable.
|
|
for ( i = 0; i < tokenCount; i++ )
|
|
{
|
|
pTokenList[i] = *pData ? pData : NULL; // Point to each string in the pToken table
|
|
while ( *pData++ ); // Find next token ( after next null )
|
|
}
|
|
}
|
|
else
|
|
pTokenList = NULL;
|
|
|
|
// short, short ( size, index of field name )
|
|
nFieldSize = *( short* )pData;
|
|
pData += sizeof( short );
|
|
pFieldName = pTokenList[*( short* )pData];
|
|
|
|
if ( stricmp( pFieldName, "GameHeader" ) )
|
|
{
|
|
delete[] pSaveData;
|
|
return 0;
|
|
};
|
|
|
|
// int ( fieldcount )
|
|
pData += sizeof( short );
|
|
nNumberOfFields = *( int* )pData;
|
|
pData += nFieldSize;
|
|
|
|
// Each field is a short ( size ), short ( index of name ), binary string of "size" bytes ( data )
|
|
for ( i = 0; i < nNumberOfFields; i++ )
|
|
{
|
|
// Data order is:
|
|
// Size
|
|
// szName
|
|
// Actual Data
|
|
|
|
nFieldSize = *( short* )pData;
|
|
pData += sizeof( short );
|
|
|
|
pFieldName = pTokenList[*( short* )pData];
|
|
pData += sizeof( short );
|
|
|
|
if ( !stricmp( pFieldName, "comment" ) )
|
|
{
|
|
int copySize = MAX( commentSize, nFieldSize );
|
|
Q_strncpy( comment, pData, copySize );
|
|
}
|
|
else if ( !stricmp( pFieldName, "mapName" ) )
|
|
{
|
|
int copySize = MAX( nameSize, nFieldSize );
|
|
Q_strncpy( name, pData, copySize );
|
|
};
|
|
|
|
// Move to Start of next field.
|
|
pData += nFieldSize;
|
|
};
|
|
|
|
// Delete the string table we allocated
|
|
delete[] pTokenList;
|
|
delete[] pSaveData;
|
|
|
|
if ( strlen( name ) > 0 && strlen( comment ) > 0 )
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
int GamepadUISaveGamePanel::SaveReadCustomMetadata( const char *pSaveName, char *ez2version, int ez2versionSize, char *platform, int platformSize, int &nMapVersion, bool &bDeck, bool &bWilson )
|
|
{
|
|
char name[MAX_PATH];
|
|
Q_strncpy( name, pSaveName, sizeof( name ) );
|
|
Q_SetExtension( name, ".txt", sizeof( name ) );
|
|
|
|
KeyValues *pCustomSaveMetadata = new KeyValues( "CustomSaveMetadata" );
|
|
if (pCustomSaveMetadata->LoadFromFile( g_pFullFileSystem, name, "MOD" ))
|
|
{
|
|
Q_strncpy( ez2version, pCustomSaveMetadata->GetString( "ez2_version" ), ez2versionSize );
|
|
Q_strncpy( platform, pCustomSaveMetadata->GetString( "platform" ), platformSize );
|
|
nMapVersion = pCustomSaveMetadata->GetInt( "mapversion" );
|
|
bDeck = pCustomSaveMetadata->GetBool( "is_deck" );
|
|
bWilson = pCustomSaveMetadata->GetBool( "wilson" );
|
|
|
|
pCustomSaveMetadata->deleteThis();
|
|
return 1;
|
|
}
|
|
|
|
pCustomSaveMetadata->deleteThis();
|
|
return 0;
|
|
}
|
|
|
|
// 0 = equal, negative = version 1 greater, positive = version 2 greater
|
|
//
|
|
// Actual return number is based on which version place is greater/less
|
|
// For example:
|
|
// - '1' would mean version 1 is a major version greater than version 2
|
|
// - '-2' would mean version 2 is a minor version greater than version 1
|
|
static int CompareVersions( const char *pszVersion1, const char *pszVersion2 )
|
|
{
|
|
if (!(pszVersion1 || *pszVersion1))
|
|
return 1;
|
|
if (!(pszVersion2 || *pszVersion2))
|
|
return -1;
|
|
|
|
// If the first character isn't a number, it's not a valid version
|
|
if (pszVersion1[0] < '0' || pszVersion1[0] > '9')
|
|
return 1;
|
|
if (pszVersion2[0] < '0' || pszVersion2[0] > '9')
|
|
return -1;
|
|
|
|
CUtlStringList szVersionNums1;
|
|
V_SplitString( pszVersion1, ".", szVersionNums1 );
|
|
|
|
CUtlStringList szVersionNums2;
|
|
V_SplitString( pszVersion2, ".", szVersionNums2 );
|
|
|
|
Assert( szVersionNums1.Count() >= szVersionNums2.Count() );
|
|
|
|
int nReturn = 0;
|
|
for (int i = 0; i < szVersionNums1.Count(); i++)
|
|
{
|
|
int nV1 = atoi( szVersionNums1[i] );
|
|
int nV2 = atoi( szVersionNums2[i] );
|
|
if (nV1 > nV2)
|
|
{
|
|
nReturn = -(i+1);
|
|
break;
|
|
}
|
|
else if (nV1 < nV2)
|
|
{
|
|
nReturn = i+1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
szVersionNums1.PurgeAndDeleteElements();
|
|
szVersionNums2.PurgeAndDeleteElements();
|
|
|
|
return nReturn;
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::LoadVersionHistory()
|
|
{
|
|
m_pVersionHistory = new KeyValues( "VersionHistory" );
|
|
m_pVersionHistory->LoadFromFile( g_pFullFileSystem, "scripts/ez2_version_history.txt", "MOD" );
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::UnloadVersionHistory()
|
|
{
|
|
m_pVersionHistory->deleteThis();
|
|
}
|
|
|
|
int GamepadUISaveGamePanel::IsSaveSuspect( const char *pszEZ2Version, const char *pszMapName, int nMapVersion, const char **ppszIncompatibleVersion, const char **ppszLastCompatibleBranch )
|
|
{
|
|
if (!(pszEZ2Version && *pszEZ2Version))
|
|
{
|
|
// Placeholder version for updates which predate this system
|
|
pszEZ2Version = "0.0.0";
|
|
*ppszLastCompatibleBranch = "release-1.5";
|
|
}
|
|
|
|
if (m_pVersionHistory)
|
|
{
|
|
bool bNewerVersionExists = false;
|
|
KeyValues *pVersionKey = m_pVersionHistory->GetFirstSubKey();
|
|
while (pVersionKey)
|
|
{
|
|
int iVerCompare = CompareVersions( pVersionKey->GetName(), pszEZ2Version );
|
|
if (iVerCompare <= -1)
|
|
{
|
|
// Newer version of E:Z2 than the save game's
|
|
|
|
// Each major/minor version
|
|
bNewerVersionExists = (iVerCompare >= -2);
|
|
|
|
// Check if this version breaks all previous versions
|
|
if (pVersionKey->GetBool( "universal" ))
|
|
{
|
|
*ppszIncompatibleVersion = pVersionKey->GetName();
|
|
return SaveSuspectLevel_Incompatible;
|
|
}
|
|
|
|
// Check for incompatible maps
|
|
KeyValues *pMaps = pVersionKey->FindKey( "maps" );
|
|
if (pMaps)
|
|
{
|
|
KeyValues *pMapKey = pMaps->FindKey( pszMapName );
|
|
if (pMapKey)
|
|
{
|
|
*ppszIncompatibleVersion = pVersionKey->GetName();
|
|
return SaveSuspectLevel_Incompatible;
|
|
}
|
|
}
|
|
}
|
|
else if (iVerCompare == 0)
|
|
{
|
|
// Matching version of E:Z2
|
|
*ppszLastCompatibleBranch = pVersionKey->GetString( "branch", *ppszLastCompatibleBranch );
|
|
}
|
|
|
|
pVersionKey = pVersionKey->GetNextKey();
|
|
}
|
|
|
|
if (bNewerVersionExists)
|
|
return SaveSuspectLevel_Mismatch;
|
|
}
|
|
|
|
return SaveSuspectLevel_None;
|
|
}
|
|
#endif
|
|
|
|
void GamepadUISaveGamePanel::FindSaveSlot( OUT_Z_CAP( bufsize ) char* buffer, int bufsize )
|
|
{
|
|
buffer[0] = 0;
|
|
char szFileName[_MAX_PATH];
|
|
for ( int i = 0; i < 1000; i++ )
|
|
{
|
|
Q_snprintf( szFileName, sizeof( szFileName ), "save/half-life-%03i.sav", i );
|
|
|
|
FileHandle_t fp = g_pFullFileSystem->Open( szFileName, "rb" );
|
|
if ( !fp )
|
|
{
|
|
// clean up name
|
|
Q_strncpy( buffer, szFileName + 5, bufsize );
|
|
char* ext = strstr( buffer, ".sav" );
|
|
if ( ext )
|
|
{
|
|
*ext = 0;
|
|
}
|
|
return;
|
|
}
|
|
g_pFullFileSystem->Close( fp );
|
|
}
|
|
|
|
AssertMsg( false, "Could not generate new save game file" );
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::DeleteSaveGame( const char* pFileName )
|
|
{
|
|
if ( !pFileName || !pFileName[0] )
|
|
return;
|
|
|
|
// delete the save game file
|
|
g_pFullFileSystem->RemoveFile( pFileName, "MOD" );
|
|
|
|
// delete the associated tga
|
|
char tga[_MAX_PATH];
|
|
Q_strncpy( tga, pFileName, sizeof( tga ) );
|
|
char* ext = strstr( tga, ".sav" );
|
|
if ( ext )
|
|
{
|
|
strcpy( ext, ".tga" );
|
|
}
|
|
g_pFullFileSystem->RemoveFile( tga, "MOD" );
|
|
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
// delete the associated txt
|
|
Q_SetExtension( tga, ".txt", sizeof( tga ) );
|
|
g_pFullFileSystem->RemoveFile( tga, "MOD" );
|
|
#endif
|
|
}
|
|
/* End Mostly from GameUI */
|
|
|
|
void GamepadUISaveGamePanel::OnGamepadUIButtonNavigatedTo( vgui::VPANEL button )
|
|
{
|
|
GamepadUIButton *pButton = dynamic_cast< GamepadUIButton * >( vgui::ipanel()->GetPanel( button, GetModuleName() ) );
|
|
if ( pButton )
|
|
{
|
|
if ( pButton->GetAlpha() != 255 )
|
|
{
|
|
int nParentW, nParentH;
|
|
GetParent()->GetSize( nParentW, nParentH );
|
|
|
|
int nX, nY;
|
|
pButton->GetPos( nX, nY );
|
|
|
|
int nTargetY = pButton->GetPriority() * ( pButton->m_flHeightAnimationValue[ButtonStates::Out] + m_flSavesSpacing );
|
|
|
|
if ( nY < nParentH / 2 )
|
|
{
|
|
nTargetY += nParentH - m_flSavesOffsetY;
|
|
// Add a bit of spacing to make this more visually appealing :)
|
|
nTargetY -= m_flSavesSpacing;
|
|
}
|
|
else
|
|
{
|
|
nTargetY += pButton->m_flHeightAnimationValue[ButtonStates::Over];
|
|
// Add a bit of spacing to make this more visually appealing :)
|
|
nTargetY += (pButton->m_flHeightAnimationValue[ButtonStates::Over] / 2) + m_flSavesSpacing;
|
|
}
|
|
|
|
|
|
m_ScrollState.SetScrollTarget( nTargetY - ( nParentH - m_flSavesOffsetY), GamepadUI::GetInstance().GetTime() );
|
|
}
|
|
}
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::LayoutSaveButtons()
|
|
{
|
|
int nParentW, nParentH;
|
|
GetParent()->GetSize( nParentW, nParentH );
|
|
|
|
float scrollClamp = 0.0f;
|
|
for ( int i = 0; i < ( int )m_pSavePanels.Count(); i++ )
|
|
{
|
|
int size = ( m_pSavePanels[i]->GetTall() + m_flSavesSpacing );
|
|
|
|
if ( i < ( ( int )m_pSavePanels.Count() ) - 3 )
|
|
scrollClamp += size;
|
|
}
|
|
|
|
m_ScrollState.UpdateScrollBounds( 0.0f, scrollClamp );
|
|
|
|
if (m_pSavePanels.Count() > 0)
|
|
{
|
|
m_pScrollBar->UpdateScrollBounds( 0.0f, scrollClamp,
|
|
((m_pSavePanels[0]->GetTall() + m_flSavesSpacing) * 3), nParentH - m_flFooterButtonsOffsetY - m_nFooterButtonHeight - m_flSavesOffsetY );
|
|
}
|
|
|
|
int previousSizes = 0;
|
|
for ( int i = 0; i < ( int )m_pSavePanels.Count(); i++ )
|
|
{
|
|
int tall = m_pSavePanels[i]->GetTall();
|
|
int size = ( tall + m_flSavesSpacing );
|
|
|
|
int y = m_flSavesOffsetY + previousSizes - m_ScrollState.GetScrollProgress();
|
|
int fade = 255;
|
|
if ( y < m_flSavesOffsetY )
|
|
fade = ( 1.0f - clamp( -( y - m_flSavesOffsetY ) / m_flSavesFade, 0.0f, 1.0f ) ) * 255.0f;
|
|
if ( y > nParentH - m_flSavesFade )
|
|
fade = ( 1.0f - clamp( ( y - ( nParentH - m_flSavesFade - size ) ) / m_flSavesFade, 0.0f, 1.0f ) ) * 255.0f;
|
|
if ( m_pSavePanels[i]->HasFocus() && fade != 0 )
|
|
fade = 255;
|
|
m_pSavePanels[i]->SetAlpha( fade );
|
|
m_pSavePanels[i]->SetPos( m_flSavesOffsetX, y );
|
|
m_pSavePanels[i]->SetVisible( true );
|
|
previousSizes += size;
|
|
|
|
if (m_pDeletePanels.Count() > i)
|
|
{
|
|
m_pDeletePanels[i]->SetPos( m_flSavesOffsetX - m_pDeletePanels[i]->GetWide() - m_flSavesSpacing, y );
|
|
m_pDeletePanels[i]->SetAlpha( fade );
|
|
m_pDeletePanels[i]->SetVisible( true );
|
|
}
|
|
}
|
|
|
|
m_ScrollState.UpdateScrolling( 2.0f, GamepadUI::GetInstance().GetTime() );
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::LoadGame( const SaveGameDescription_t* pSave )
|
|
{
|
|
const char* shortName = pSave->szShortName;
|
|
if ( shortName && shortName[0] )
|
|
{
|
|
// Load the game, return to top and switch to engine
|
|
char sz[256];
|
|
Q_snprintf( sz, sizeof( sz ), "progress_enable\nload %s\n", shortName );
|
|
|
|
GamepadUI::GetInstance().GetEngineClient()->ClientCmd_Unrestricted( sz );
|
|
|
|
// Close this dialog
|
|
Close();
|
|
}
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::SaveGame( const SaveGameDescription_t* pSave )
|
|
{
|
|
// delete any existing save
|
|
DeleteSaveGame( pSave->szFileName );
|
|
|
|
// save to a new name
|
|
char saveName[128];
|
|
FindSaveSlot( saveName, sizeof( saveName ) );
|
|
if ( saveName && saveName[0] )
|
|
{
|
|
// Load the game, return to top and switch to engine
|
|
char sz[256];
|
|
Q_snprintf( sz, sizeof( sz ), "save %s\n", saveName );
|
|
|
|
GamepadUI::GetInstance().GetEngineClient()->ClientCmd_Unrestricted( sz );
|
|
Close();
|
|
GamepadUI::GetInstance().GetGameUI()->SendMainMenuCommand( "resumegame" );
|
|
}
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::OnCommand( char const* pCommand )
|
|
{
|
|
if ( !V_strcmp( pCommand, "action_back" ) )
|
|
{
|
|
Close();
|
|
}
|
|
else if ( !V_strcmp( pCommand, "action_delete_mode_button" ) )
|
|
{
|
|
for ( auto& panel : m_pDeletePanels )
|
|
{
|
|
if ( panel->HasFocus() )
|
|
{
|
|
new GamepadUIGenericConfirmationPanel( this, "SaveDeleteConfirmationPanel", "#GameUI_ConfirmDeleteSaveGame_Title", "#GameUI_ConfirmDeleteSaveGame_Info",
|
|
[this, panel]()
|
|
{
|
|
DeleteSaveGame( panel->GetName() );
|
|
ScanSavedGames();
|
|
} );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if ( !V_strcmp( pCommand, "action_delete" ) )
|
|
{
|
|
#ifdef STEAM_INPUT
|
|
const bool bController = GamepadUI::GetInstance().GetSteamInput()->IsEnabled();
|
|
#elif defined(HL2_RETAIL) // Steam input and Steam Controller are not supported in SDK2013 (Madi)
|
|
const bool bController = g_pInputSystem->IsSteamControllerActive();
|
|
#else
|
|
const bool bController = ( g_pInputSystem->GetJoystickCount() >= 1 );
|
|
#endif
|
|
if (InDeleteMode())
|
|
{
|
|
m_pDeletePanels.PurgeAndDeleteElements();
|
|
}
|
|
else if (!bController && gamepadui_savegame_use_delete_mode.GetBool())
|
|
{
|
|
// Add delete panels
|
|
for (int i = 0; i < m_pSavePanels.Count(); i++)
|
|
{
|
|
GamepadUIButton *button = new GamepadUIButton( this, this, GAMEPADUI_RESOURCE_FOLDER "schemedeletesavebutton.res", "action_delete_mode_button", "X", "");
|
|
button->SetName( m_pSavePanels[i]->GetSaveGame()->szFileName );
|
|
button->SetPriority( m_pSavePanels[i]->GetPriority() );
|
|
button->SetForwardToParent( true );
|
|
m_pDeletePanels.AddToTail( button );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Delete directly if using a controller
|
|
for ( auto& panel : m_pSavePanels )
|
|
{
|
|
if ( panel->HasFocus() )
|
|
{
|
|
new GamepadUIGenericConfirmationPanel( this, "SaveDeleteConfirmationPanel", "#GameUI_ConfirmDeleteSaveGame_Title", "#GameUI_ConfirmDeleteSaveGame_Info",
|
|
[this, panel]()
|
|
{
|
|
int i = m_pSavePanels.Find( panel );
|
|
DeleteSaveGame( panel->GetSaveGame()->szFileName );
|
|
ScanSavedGames();
|
|
|
|
if ( i > 0 && m_pSavePanels.Count() >= i )
|
|
m_pSavePanels[i-1]->NavigateTo();
|
|
else if ( m_pSavePanels.Count() )
|
|
m_pSavePanels[0]->NavigateTo();
|
|
} );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( !V_strcmp( pCommand, "load_save" ) )
|
|
{
|
|
for ( auto& panel : m_pSavePanels )
|
|
{
|
|
if ( panel->HasFocus() )
|
|
{
|
|
auto* pSave = panel->GetSaveGame();
|
|
if ( m_bIsSave )
|
|
{
|
|
if ( panel->GetSaveGame()->iTimestamp != NEW_SAVE_GAME_TIMESTAMP )
|
|
{
|
|
new GamepadUIGenericConfirmationPanel( this, "SaveOverwriteConfirmationPanel", "#GameUI_ConfirmOverwriteSaveGame_Title", "#GameUI_ConfirmOverwriteSaveGame_Info",
|
|
[this, pSave]()
|
|
{
|
|
SaveGame( pSave );
|
|
} );
|
|
}
|
|
else
|
|
SaveGame( pSave );
|
|
}
|
|
else
|
|
{
|
|
#ifdef GAMEPADUI_GAME_EZ2
|
|
if (panel->GetSaveSuspectLevel() != SaveSuspectLevel_None)
|
|
{
|
|
wchar_t wszLastCompatibleBranch[ 16 ];
|
|
V_UTF8ToUnicode( panel->GetLastCompatibleBranch(), wszLastCompatibleBranch, sizeof( wszLastCompatibleBranch ) );
|
|
|
|
const char *pszFrameTitle = NULL;
|
|
wchar_t buf[ 512 ];
|
|
switch (panel->GetSaveSuspectLevel())
|
|
{
|
|
case SaveSuspectLevel_Mismatch:
|
|
g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_DifferentVersion_Info" ), 1, wszLastCompatibleBranch );
|
|
pszFrameTitle = "#GameUI_DifferentVersion_Title";
|
|
break;
|
|
case SaveSuspectLevel_Incompatible:
|
|
g_pVGuiLocalize->ConstructString( buf, sizeof( buf ), g_pVGuiLocalize->Find( "#GameUI_IncompatibleVersion_Info" ), 1, wszLastCompatibleBranch );
|
|
pszFrameTitle = "#GameUI_IncompatibleVersion_Title";
|
|
break;
|
|
}
|
|
|
|
new GamepadUIGenericConfirmationPanel( this, "IncompatibleVersionConfirmationPanel", g_pVGuiLocalize->Find( pszFrameTitle ), buf,
|
|
[this, pSave]()
|
|
{
|
|
LoadGame( pSave );
|
|
}, true );
|
|
}
|
|
else
|
|
#endif
|
|
LoadGame( pSave );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BaseClass::OnCommand( pCommand );
|
|
}
|
|
}
|
|
|
|
void GamepadUISaveGamePanel::OnMouseWheeled( int delta )
|
|
{
|
|
m_ScrollState.OnMouseWheeled( delta * 200.0f, GamepadUI::GetInstance().GetTime() );
|
|
}
|
|
|
|
CON_COMMAND( gamepadui_opensavegamedialog, "" )
|
|
{
|
|
new GamepadUISaveGamePanel( GamepadUI::GetInstance().GetBasePanel(), "", true );
|
|
}
|
|
|
|
CON_COMMAND( gamepadui_openloadgamedialog, "" )
|
|
{
|
|
new GamepadUISaveGamePanel( GamepadUI::GetInstance().GetBasePanel(), "", false );
|
|
}
|