Files
GTASource/game/SaveLoad/savegame_frontend.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1343 lines
46 KiB
C++

// Game headers
#include "SaveLoad/savegame_frontend.h"
#include "audio/frontendaudioentity.h"
#include "camera/viewports/ViewportManager.h"
#include "frontend/PauseMenu.h"
#include "SaveLoad/GenericGameStorage.h"
#include "SaveLoad/savegame_channel.h"
#include "SaveLoad/savegame_filenames.h"
#include "SaveLoad/savegame_initial_checks.h"
#include "SaveLoad/savegame_list.h"
#include "SaveLoad/savegame_messages.h"
#include "SaveLoad/savegame_save.h"
#include "SaveLoad/savegame_users_and_devices.h"
#include "Text/Messages.h"
#include "Text/TextConversion.h"
SAVEGAME_OPTIMISATIONS()
s32 CSavegameFrontEnd::ms_SaveGameSlotToLoad = -1;
s32 CSavegameFrontEnd::ms_SaveGameSlotToDelete = -1;
CSavegameFrontEnd::eSavegameMenuFunction CSavegameFrontEnd::ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_LOAD;
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
s32 CSavegameFrontEnd::ms_SaveGameSlotToExport = -1;
char CSavegameFrontEnd::sm_MigrationInfoTextBuffer[MAX_CHARS_IN_EXTENDED_MESSAGE];
bool CSavegameFrontEnd::sm_bAllowAcceptButtonOnMigrationInfoScreen = true;
CSaveGameExport::eNetworkProblemsForSavegameExport CSavegameFrontEnd::sm_NetworkProblemForSavegameExport = CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_NONE;
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
#if __ALLOW_IMPORT_OF_SP_SAVEGAMES
s32 CSavegameFrontEnd::ms_SaveGameSlotToImport = -1;
#endif // __ALLOW_IMPORT_OF_SP_SAVEGAMES
#define MAX_SAVEGAMES_PER_FRONTEND_PAGE (TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES)
const int NumberOfMenuItemsBeforeSavegameList = 1; // The first menu item displays the current and maximum number of saves. In the Save menu, it can be selected to create a new save.
// If NumberOfMenuItemsBeforeSavegameList gets set to 0 then I'll still need to
// deal with problems with displaying the Save menu when there are no saves.
void CSavegameFrontEnd::SetLoadMenuContext(eLoadMenuInstructionalButtonContexts loadMenuContext)
{
s8 ColumnForSpinner = CPauseMenu::GetColumnForSpinner();
switch (loadMenuContext)
{
case BUTTON_CONTEXT_WAITING_FOR_SIGN_IN :
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(false, ColumnForSpinner);
break;
case BUTTON_CONTEXT_WAITING_FOR_DEVICE_SELECT :
SUIContexts::Activate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(false, ColumnForSpinner);
break;
case BUTTON_CONTEXT_LOAD_GAME_MENU :
SUIContexts::Activate("SELECT_STORAGE_DEVICE");
if (CPauseMenu::IsInLoadGamePanel())
{
SUIContexts::Activate(DELETE_SAVEGAME_CONTEXT);
}
else
{
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
}
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(true, ColumnForSpinner);
break;
case BUTTON_CONTEXT_LOAD_GAME_MENU_DELETE_IN_PROGRESS :
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
break;
case BUTTON_CONTEXT_SAVE_GAME_MENU_WAITING_FOR_MENU_TO_DISPLAY :
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
break;
case BUTTON_CONTEXT_SAVE_GAME_MENU_IS_DISPLAYING :
SUIContexts::Activate("SELECT_STORAGE_DEVICE");
if (ms_CurrentlyHighlightedSlot < 1 || // There will never be a valid save file above slot 1 - don't show delete
ms_CurrentlyHighlightedSlot > ms_SavegameSlotsArrangedByTime.GetCount()) // When a save is deleted, ms_CurrentlyHighlighted slot won't update right away. This check fixes the edge case of deleting the last save - otherwise delete will show over "create new save"
{
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
}
else
{
SUIContexts::Activate(DELETE_SAVEGAME_CONTEXT);
}
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
break;
case BUTTON_CONTEXT_SAVE_GAME_MENU_DELETE_IN_PROGRESS :
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
break;
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
case BUTTON_CONTEXT_UPLOAD_MENU_IS_DISPLAYING :
{
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
// Copied these two from BUTTON_CONTEXT_LOAD_GAME_MENU
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(true, ColumnForSpinner);
}
break;
case BUTTON_CONTEXT_MIGRATION_INFO_SCREEN :
{
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Deactivate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(false, ColumnForSpinner);
}
break;
case BUTTON_CONTEXT_MIGRATION_INFO_SCREEN_NO_ACCEPT :
{
SUIContexts::Deactivate("SELECT_STORAGE_DEVICE");
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
SUIContexts::Activate("HIDE_ACCEPTBUTTON");
CPauseMenu::SetBusySpinner(false, ColumnForSpinner);
}
break;
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
}
CPauseMenu::RedrawInstructionalButtons();
}
CSavegameFrontEnd::CSavegameFrontEnd(CMenuScreen& owner)
: CMenuBase(owner)
{
}
CSavegameFrontEnd::~CSavegameFrontEnd()
{
}
void CSavegameFrontEnd::LayoutChanged( MenuScreenId OUTPUT_ONLY(iPreviousLayout), MenuScreenId OUTPUT_ONLY(iNewLayout), s32 iUniqueId, eLAYOUT_CHANGED_DIR OUTPUT_ONLY(eDir))
{
uiDebugf3("CSavegameFrontEnd::LayoutChanged - Prev: %i, New: %i, Unique: %i, Dir: %i", iPreviousLayout.GetValue(), iNewLayout.GetValue(), iUniqueId, eDir);
SetHighlightedMenuItem(iUniqueId);
if (CPauseMenu::IsInSaveGameMenus())
{
bool hasDeleteButtonVisibilityChanged = false;
if (iUniqueId == 0)
{
// Make sure the Delete button is hidden when the "Create new save" element is highlighted
if (SUIContexts::IsActive(DELETE_SAVEGAME_CONTEXT))
{
SUIContexts::Deactivate(DELETE_SAVEGAME_CONTEXT);
hasDeleteButtonVisibilityChanged = true;
}
}
else
{
if (!SUIContexts::IsActive(DELETE_SAVEGAME_CONTEXT))
{
SUIContexts::Activate(DELETE_SAVEGAME_CONTEXT);
hasDeleteButtonVisibilityChanged = true;
}
}
if (hasDeleteButtonVisibilityChanged)
{
CPauseMenu::RedrawInstructionalButtons();
}
CPauseMenu::SetPlayerWantsToSaveASavegame();
}
}
void CSavegameFrontEnd::SetHighlightedMenuItem( s32 iMenuItem )
{
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
if ( CPauseMenu::IsInSaveGameOrLoadGameMenus()
|| CPauseMenu::IsUploadSavegameOptionHighlighted()
|| CPauseMenu::IsInUploadSavegamePanel() )
#else // __ALLOW_EXPORT_OF_SP_SAVEGAMES
if ( CPauseMenu::IsInSaveGameOrLoadGameMenus() )
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
{
ms_CurrentlyHighlightedSlot = iMenuItem;
}
}
s32 CSavegameFrontEnd::GetNumberOfLinesToDisplayInSavegameList(bool /*bSaveMenu*/)
{
return (MAX_SAVEGAMES_PER_FRONTEND_PAGE + 1);
}
bool CSavegameFrontEnd::BeginSaveGameList()
{
if (SaveGameListScreenSetup(true, false, false) == MEM_CARD_ERROR)
{
return false;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////////////
// NAME: SaveGameMenuCheck
// PURPOSE: checks for input and handles the new input into the menu list
/////////////////////////////////////////////////////////////////////////////////////
MemoryCardError CSavegameFrontEnd::SaveGameMenuCheck(bool bQuitAsSoonAsNoSavegameOperationsAreRunning)
{
MemoryCardError ScanStatus = SaveGameListScreenSetup(false, false, bQuitAsSoonAsNoSavegameOperationsAreRunning);
switch (ScanStatus)
{
case MEM_CARD_COMPLETE :
// list of save games has been displayed so just carry on
break;
case MEM_CARD_BUSY :
return MEM_CARD_BUSY; // still scanning the memory card
case MEM_CARD_ERROR :
{
if (bQuitAsSoonAsNoSavegameOperationsAreRunning)
{
savegameDisplayf("CSavegameFrontEnd::SaveGameMenuCheck - backed out of savegame list after SaveGameListScreenSetup() returned MEM_CARD_ERROR");
CPauseMenu::ResetMenuItemTriggered();
}
return MEM_CARD_ERROR;
}
default :
Assertf(0, "CSavegameFrontEnd::SaveGameMenuCheck - unexpected return value from SaveGameListScreenSetup");
return MEM_CARD_ERROR;
}
ePlayerConfirmationReturn PlayerConfirmationResult = NO_PLAYER_CONFIRMATION_CHECK_IN_PROGRESS;
if (CPauseMenu::IsInSaveGameMenus())
{
Assertf(!CLoadConfirmationMessage::IsThereAMessageToProcess(), "CSavegameFrontEnd::SaveGameMenuCheck - there shouldn't be a load confirmation message to process within the save menu");
PlayerConfirmationResult = CSaveConfirmationMessage::Process();
}
else
{ // GraemeSW - would it be better to have a new CUploadSavegameConfirmationMessage class instead of shoe-horning the Upload code into CLoadConfirmationMessage?
Assertf(!CSaveConfirmationMessage::IsThereAMessageToProcess(), "CSavegameFrontEnd::SaveGameMenuCheck - there shouldn't be a save confirmation message to process within the load menu");
PlayerConfirmationResult = CLoadConfirmationMessage::Process();
}
switch (PlayerConfirmationResult)
{
case NO_PLAYER_CONFIRMATION_CHECK_IN_PROGRESS :
break;
case PLAYER_CONFIRMATION_CHECK_IN_PROGRESS :
return MEM_CARD_BUSY;
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_LOADING :
CPauseMenu::CloseAndLoadSavedGame();
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_LOAD;
ms_SaveGameSlotToLoad = CLoadConfirmationMessage::GetSlotIndex();
CSavegameList::SetEpisodeNumberForTheSaveGameToBeLoadedToThisSlot(ms_SaveGameSlotToLoad);
return MEM_CARD_COMPLETE;
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_DELETING_FROM_LOAD_MENU :
SetLoadMenuContext(BUTTON_CONTEXT_LOAD_GAME_MENU_DELETE_IN_PROGRESS);
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_DELETE;
#if RSG_ORBIS
ms_SaveGameSlotToDelete = CSavegameList::ConvertBackupSlotToSavegameSlot(CLoadConfirmationMessage::GetSlotIndex());
#else
ms_SaveGameSlotToDelete = CLoadConfirmationMessage::GetSlotIndex();
#endif
return MEM_CARD_COMPLETE;
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_DELETING_FROM_SAVE_MENU :
SetLoadMenuContext(BUTTON_CONTEXT_SAVE_GAME_MENU_DELETE_IN_PROGRESS);
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_DELETE;
#if RSG_ORBIS
ms_SaveGameSlotToDelete = CSavegameList::ConvertBackupSlotToSavegameSlot(CSaveConfirmationMessage::GetSlotIndex());
#else
ms_SaveGameSlotToDelete = CSaveConfirmationMessage::GetSlotIndex();
#endif
return MEM_CARD_COMPLETE;
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_EXPORTING :
{
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_EXPORT;
ms_SaveGameSlotToExport = CLoadConfirmationMessage::GetSlotIndex();
return MEM_CARD_COMPLETE;
}
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_SAVING :
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_SAVE;
#if RSG_ORBIS
CSavegameSave::BeginGameSave(CSavegameList::ConvertBackupSlotToSavegameSlot(CSaveConfirmationMessage::GetSlotIndex()), SAVEGAME_SINGLE_PLAYER);
#else
CSavegameSave::BeginGameSave(CSaveConfirmationMessage::GetSlotIndex(), SAVEGAME_SINGLE_PLAYER);
#endif
//CPauseMenu::LockMenuControl();
return MEM_CARD_COMPLETE;
#if __ALLOW_IMPORT_OF_SP_SAVEGAMES
case PLAYER_CONFIRMATION_CHECK_FINISHED_BEGIN_IMPORTING :
{
ms_SavegameMenuFunction = SAVEGAME_MENU_FUNCTION_IMPORT;
#if RSG_ORBIS
ms_SaveGameSlotToImport = CSavegameList::ConvertBackupSlotToSavegameSlot(CSaveConfirmationMessage::GetSlotIndex());
#else
ms_SaveGameSlotToImport = CSaveConfirmationMessage::GetSlotIndex();
#endif
return MEM_CARD_COMPLETE;
}
#endif // __ALLOW_IMPORT_OF_SP_SAVEGAMES
case PLAYER_CONFIRMATION_CHECK_INTERRUPTED_NEED_TO_RESCAN :
if (SaveGameListScreenSetup(true, false, false) == MEM_CARD_ERROR)
{
Assertf(0, "CSavegameFrontEnd::SaveGameMenuCheck - error occurred in the first call to SaveGameListScreenSetup");
return MEM_CARD_ERROR;
}
return MEM_CARD_BUSY;
case PLAYER_CONFIRMATION_CHECK_INTERRUPTED_PLAYER_HAS_SIGNED_OUT :
return MEM_CARD_ERROR;
default :
Assertf(0, "CSavegameFrontEnd::SaveGameMenuCheck - unexpected return value from ConfirmationMessage::Process()");
return MEM_CARD_ERROR;
}
// This function might get called for one extra frame after FRONTEND_MENU_SAVEGAME_LIST has been disabled
// by the player cancelling the menu so return before anything attempts to access the menu
if (CPauseMenu::IsPauseMenuControlDisabled())
return MEM_CARD_ERROR; // not sure what should be returned here yet
// item has been accepted:
bool bItemTriggered = CPauseMenu::HasMenuItemBeenTriggered();
if (bItemTriggered || bQuitAsSoonAsNoSavegameOperationsAreRunning)
{
s32 menu_item = CPauseMenu::GetMenuItemTriggered();
CPauseMenu::ResetMenuItemTriggered(); // maybe rework this?
if (bQuitAsSoonAsNoSavegameOperationsAreRunning)
{
savegameDisplayf("CSavegameFrontEnd::SaveGameMenuCheck - backed out of savegame list");
return MEM_CARD_ERROR;
}
else
{
if ( menu_item == 0 ) // && (NumberOfMenuItemsBeforeSavegameList == 1) )
{
// If there are only damaged saves in this screen of the Load menu then the first item will be
// highlighted. Don't do anything if the player selects it though.
if (CPauseMenu::IsInSaveGameMenus())
{
s32 FreeSaveSlot = CSavegameList::FindFreeManualSaveSlot();
if (savegameVerifyf(FreeSaveSlot >= 0, "CSavegameFrontEnd::SaveGameMenuCheck - failed to find a free manual save slot"))
{
#if __ALLOW_IMPORT_OF_SP_SAVEGAMES
if (CPauseMenu::PlayerHasChosenToImportASavegame())
{
CSaveConfirmationMessage::Begin(FreeSaveSlot, CSaveConfirmationMessage::SAVE_MESSAGE_IMPORT);
}
else
#endif // __ALLOW_IMPORT_OF_SP_SAVEGAMES
{
CSaveConfirmationMessage::Begin(FreeSaveSlot, CSaveConfirmationMessage::SAVE_MESSAGE_SAVE);
}
}
}
}
else
{
if (CPauseMenu::IsInSaveGameMenus())
{
if (CPauseMenu::PlayerHasChosenToDeleteASavegame())
{
CSaveConfirmationMessage::Begin(ConvertMenuItemToSlotIndex(menu_item), CSaveConfirmationMessage::SAVE_MESSAGE_DELETE);
}
else
{
#if __ALLOW_IMPORT_OF_SP_SAVEGAMES
if (CPauseMenu::PlayerHasChosenToImportASavegame())
{
CSaveConfirmationMessage::Begin(ConvertMenuItemToSlotIndex(menu_item), CSaveConfirmationMessage::SAVE_MESSAGE_IMPORT);
}
else
#endif // __ALLOW_IMPORT_OF_SP_SAVEGAMES
{
CSaveConfirmationMessage::Begin(ConvertMenuItemToSlotIndex(menu_item), CSaveConfirmationMessage::SAVE_MESSAGE_SAVE);
}
}
}
else
{
if (CPauseMenu::PlayerHasChosenToDeleteASavegame())
{
CLoadConfirmationMessage::Begin(ConvertMenuItemToSlotIndex(menu_item), CLoadConfirmationMessage::LOAD_MESSAGE_DELETE);
}
else
{
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
if (CPauseMenu::PlayerHasChosenToExportASavegame())
{
CLoadConfirmationMessage::Begin(ConvertMenuItemToSlotIndex(menu_item), CLoadConfirmationMessage::LOAD_MESSAGE_EXPORT);
}
else
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
{
s32 slotToLoad = ConvertMenuItemToSlotIndex(menu_item);
#if __BANK && RSG_ORBIS
if (CGenericGameStorage::ms_bAlwaysLoadBackupSaves)
{
if (slotToLoad < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES)
{
if (!CSavegameList::IsSaveGameSlotEmpty(slotToLoad + TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES))
{
slotToLoad += TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES;
}
}
else
{
savegameAssertf( (slotToLoad >= TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES) && (slotToLoad < (TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES + NUM_BACKUPSAVE_SLOTS) ), "CSavegameFrontEnd::SaveGameMenuCheck - expected slot to be between 0 and %u", (TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES + NUM_BACKUPSAVE_SLOTS));
}
}
#endif // __BANK && RSG_ORBIS
CLoadConfirmationMessage::Begin(slotToLoad, CLoadConfirmationMessage::LOAD_MESSAGE_LOAD);
}
}
}
}
}
}
return MEM_CARD_BUSY;
}
atFixedArray<s32, TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES> CSavegameFrontEnd::ms_SavegameSlotsArrangedByTime;
s32 CSavegameFrontEnd::ms_BaseMenuItem = 0;
s32 CSavegameFrontEnd::ms_CurrentlyHighlightedSlot = 0;
bool CSavegameFrontEnd::ms_bNeedToRestartDamagedCheck = true;
// CSavegameFrontEnd::CreateListSortedByDate - returns false if we're in the Load menu and no valid saves were found to display
bool CSavegameFrontEnd::CreateListSortedByDate()
{
ms_SavegameSlotsArrangedByTime.Reset();
ms_bNeedToRestartDamagedCheck = true;
// We could have an array of flags to remember which files we'd already checked for damage
// so that the damaged check doesn't need to be run again if the same page of the list is displayed again.
// This array could be reset here.
s32 MaxSlotsToSort = TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES;
if (CPauseMenu::IsInSaveGameMenus())
{ // Ignore the autosave slots in the save menu
MaxSlotsToSort = NUM_MANUAL_SAVE_SLOTS;
}
const u8 ALREADY_ADDED_TO_SORTED_ARRAY = 1 << 0; // Originally I thought I might flag damaged slots too
u8 FlagsForSlots[TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES]; // so I thought I'd make FlagsForSlots an array of bit-fields instead of an array of bools
sysMemSet(FlagsForSlots, 0, TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES);
CDate MostRecentSaveDate;
s32 MostRecentSaveSlot = -1;
bool bFinished = false;
// Add slot indices of saves to array ordered by time with most recent save in array index 0
while (!bFinished)
{
MostRecentSaveDate.Initialise();
MostRecentSaveSlot = -1;
s32 slot_loop = 0;
while (slot_loop < MaxSlotsToSort)
{
if ( (FlagsForSlots[slot_loop] & ALREADY_ADDED_TO_SORTED_ARRAY) == 0)
{
if (!CSavegameList::IsSaveGameSlotEmpty(slot_loop)
#if RSG_ORBIS
|| !CSavegameList::IsSaveGameSlotEmpty(slot_loop + INDEX_OF_BACKUPSAVE_SLOT)
#endif
)
{
//possible that only a backup save exists if the main save was corrupt and deleted
//in that case, use the backup slot
s32 activeSlot = slot_loop;
bool bConsiderThisSlot = true;
#if RSG_ORBIS
if(CSavegameList::IsSaveGameSlotEmpty(activeSlot))
{
#if USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
if (CSavegameList::IsThisAnAutosaveSlot(activeSlot))
{ // Ignore download0 backups of autosaves if the main autosave doesn't exist
savegameDisplayf("CSavegameFrontEnd::CreateListSortedByDate - autosave slot %d is empty so don't consider the download0 backup", activeSlot);
bConsiderThisSlot = false;
}
else
#endif // USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
{
activeSlot += INDEX_OF_BACKUPSAVE_SLOT;
}
}
#endif
if (bConsiderThisSlot)
{
// if (!CSavegameList::GetIsDamaged(slot_loop)) no point checking this since I've not checked if the slot is damaged yet
{
if (CSavegameList::GetSaveTime(activeSlot) > MostRecentSaveDate)
{
MostRecentSaveDate = CSavegameList::GetSaveTime(activeSlot);
MostRecentSaveSlot = activeSlot;
}
}
}
}
}
slot_loop++;
}
bFinished = true;
if (MostRecentSaveSlot >= 0)
{
bFinished = false;
ms_SavegameSlotsArrangedByTime.Push(MostRecentSaveSlot);
#if RSG_ORBIS
FlagsForSlots[CSavegameList::ConvertBackupSlotToSavegameSlot(MostRecentSaveSlot)] |= ALREADY_ADDED_TO_SORTED_ARRAY;
#else
FlagsForSlots[MostRecentSaveSlot] |= ALREADY_ADDED_TO_SORTED_ARRAY;
#endif
}
}
if (!CPauseMenu::IsInSaveGameMenus())
{ // We are in the Load menu or the Upload Savegame menu
if (ms_SavegameSlotsArrangedByTime.GetCount() == 0)
{ // haven't found any good saves so display the error
CPauseMenu::SetNoValidSaveGameFiles(true);
//CPauseMenu::Close();
// CFrontEnd::DisplayNoSaveGamesMessageInMilliseconds = 5000;
g_FrontendAudioEntity.PlaySound("ERROR","HUD_FRONTEND_DEFAULT_SOUNDSET");
CSavegameDevices::SetAllowDeviceHasBeenRemovedMessageToBeDisplayed(false);
CSavegameDevices::SetDeviceIsInvalid(false);
return false;
}
// else
// {
// CFrontEnd::DisplayNoSaveGamesMessageInMilliseconds = 0;
// }
}
return true;
}
bool CSavegameFrontEnd::AddOneItemToSaveGameList(s32 MenuItem)
{
bool bFoundValidData = false;
bool SlotIsEmpty = false;
bool SlotIsDamaged = false;
char cSaveGameName[SAVE_GAME_MAX_DISPLAY_NAME_LENGTH];
char cSaveGameDate[MAX_MENU_ITEM_CHAR_LENGTH];
if ( (MenuItem < NumberOfMenuItemsBeforeSavegameList) || (MenuItem > (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) ) )
{
savegameAssertf(0, "CSavegameFrontEnd::AddOneItemToSaveGameList should be called with an int in the range %d to %d", NumberOfMenuItemsBeforeSavegameList, (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) );
return false;
}
s32 SlotIndex = ConvertMenuItemToSlotIndex(MenuItem);
CSavegameList::GetDisplayNameAndDateForThisSaveGameItem(SlotIndex, cSaveGameName, cSaveGameDate, &SlotIsEmpty, &SlotIsDamaged);
if (savegameVerifyf(!SlotIsEmpty, "CSavegameFrontEnd::AddOneItemToSaveGameList - sorting by time should ignore empty slots so shouldn't find any at this stage"))
{
if (SlotIsDamaged)
{
char gxtSlotIsDamagedText[MAX_MENU_ITEM_CHAR_LENGTH];
char *pGxtFromTextFile = TheText.Get("SG_DAM");
CNumberWithinMessage NumbersArray[1];
NumbersArray[0].Set((ms_BaseMenuItem + MenuItem + (1 - NumberOfMenuItemsBeforeSavegameList) ));
CMessages::InsertNumbersAndSubStringsIntoString(pGxtFromTextFile,
NumbersArray, 1,
NULL, 0,
gxtSlotIsDamagedText, NELEM(gxtSlotIsDamagedText));
bool bActivated = true;
// Bug 2006658 - The Load menu now has a Delete button. Don't grey out damaged savegames so that they can be selected for deletion.
// If the player attempts to load a damaged save, they'll get a "The selected save game data cannot be loaded because it is damaged." warning message.
// if (!CPauseMenu::IsInSaveGameMenus())
// { // damaged slots should be greyed out in the load menu but not in the save menu
// bActivated = false;
// }
CPauseMenu::InsertSaveGameIntoMenu(MenuItem, gxtSlotIsDamagedText, NULL, bActivated);
}
else
{
bFoundValidData = true;
// lets cap the amount of characters at run time:
s32 MaxCharactersToDisplay = 64;
char cSaveGameNameWithMenuItemNumber[SAVE_GAME_MAX_DISPLAY_NAME_LENGTH];
sprintf(cSaveGameNameWithMenuItemNumber, "%02d - ", (MenuItem + ms_BaseMenuItem) );
s32 numberOfCharactersInMenuItemNumber = CountUtf8Characters(cSaveGameNameWithMenuItemNumber);
s32 numberOfBytesInMenuItemNumber = istrlen(cSaveGameNameWithMenuItemNumber); // There shouldn't be any multi-byte characters in this part so numberOfBytesInMenuItemNumber should equal numberOfCharactersInMenuItemNumber
s32 numberOfCharactersInSaveGameName = CountUtf8Characters(cSaveGameName);
s32 numberOfBytesInSaveGameName = istrlen(cSaveGameName);
bool bStringDoesntFit = false;
if ((numberOfCharactersInMenuItemNumber + numberOfCharactersInSaveGameName) > MaxCharactersToDisplay)
{
bStringDoesntFit = true;
}
if ((numberOfBytesInMenuItemNumber + numberOfBytesInSaveGameName) >= NELEM(cSaveGameNameWithMenuItemNumber))
{
bStringDoesntFit = true;
}
s32 maxBytesToCopy = NELEM(cSaveGameNameWithMenuItemNumber) - numberOfBytesInMenuItemNumber;
if (bStringDoesntFit)
{
maxBytesToCopy -= 3; // for the three '.' characters
}
s32 maxCharactersToCopy = (MaxCharactersToDisplay - numberOfCharactersInMenuItemNumber);
if ( (maxCharactersToCopy > 0) && (maxBytesToCopy > 0) )
{
CTextConversion::StrcpyWithCharacterAndByteLimits(&cSaveGameNameWithMenuItemNumber[numberOfBytesInMenuItemNumber], cSaveGameName, maxCharactersToCopy, maxBytesToCopy);
}
if (bStringDoesntFit)
{
s32 numberOfBytesInFullString = istrlen(cSaveGameNameWithMenuItemNumber);
if (Verifyf(numberOfBytesInFullString < (NELEM(cSaveGameNameWithMenuItemNumber)-3),
"CSavegameFrontEnd::AddOneItemToSaveGameList - expected there to still be space to append three dot characters at the end of this string. Current length is %d. Maximum length is %d",
numberOfBytesInFullString, NELEM(cSaveGameNameWithMenuItemNumber)))
{
strcat(cSaveGameNameWithMenuItemNumber, "...");
}
}
// CMenuSystem::InsertOneMenuItem(CFrontEnd::GetMenuID(FRONTEND_MENU_SAVEGAME_LIST), 0, MenuItem, cSaveGameNameWithMenuItemNumber, false);
// CMenuSystem::InsertOneMenuItem(CFrontEnd::GetMenuID(FRONTEND_MENU_SAVEGAME_LIST), 1, MenuItem, cSaveGameDate, false);
CPauseMenu::InsertSaveGameIntoMenu(MenuItem, cSaveGameNameWithMenuItemNumber, cSaveGameDate, true);
}
}
return bFoundValidData;
}
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
#if __NO_OUTPUT
#define SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS(textLabel)
#else
#define SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS(textLabel) \
if (!TheText.DoesTextLabelExist(textLabel))\
{\
savegameErrorf("Can't find Key %s in the text file", textLabel);\
savegameAssertf(0, "Can't find Key %s in the text file", textLabel);\
}
#endif
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
/////////////////////////////////////////////////////////////////////////////////////
// NAME: SaveGameListScreenSetup
// PURPOSE: sets up the savegame list menu
/////////////////////////////////////////////////////////////////////////////////////
MemoryCardError CSavegameFrontEnd::SaveGameListScreenSetup(bool bRescanMemoryCard, bool bForceDeviceSelection, bool bForceCloseWhenSafe)
{
enum eScreenSetupProgress
{
SCREEN_SETUP_PROGRESS_DO_NOTHING,
#if RSG_PC || RSG_DURANGO
SCREEN_SETUP_PROGRESS_WAIT_FOR_USER_TO_PRESS_A_BUTTON,
#endif // RSG_PC || RSG_DURANGO
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
SCREEN_SETUP_PROGRESS_DISPLAY_MIGRATION_INFO_SCREEN,
SCREEN_SETUP_PROGRESS_WAIT_ON_MIGRATION_INFO_SCREEN,
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING,
SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS,
SCREEN_SETUP_PROGRESS_SCAN_FOR_DAMAGES,
SCREEN_SETUP_PROGRESS_HANDLE_ERRORS
};
static eScreenSetupProgress SetupProgress = SCREEN_SETUP_PROGRESS_DO_NOTHING;
MemoryCardError returnStatus = MEM_CARD_BUSY;
if (bRescanMemoryCard)
{
if (!bForceCloseWhenSafe)
{
if (ms_SavegameSlotsArrangedByTime.GetCount() > 0)
{
// Only notify the pause menu that there are valid save games if that is the case. Otherwise, a flicker will occur in the instructional buttons when selecting
// load game, as CPauseMenu::SetNoValidSaveGameFiles now updates the SUIContexts/instructional buttons to reflect not having save games.
CPauseMenu::SetNoValidSaveGameFiles(false);
}
CSavegameList::ClearSlotData();
CSavegameList::ClearNumberOfSaveGameSlots();
CSavegameList::ResetFileTimeScan();
CPauseMenu::ClearSaveGameMenu();
CLoadConfirmationMessage::Clear();
CSaveConfirmationMessage::Clear();
if (CPauseMenu::IsInSaveGameMenus())
{
CGenericGameStorage::SetSaveOperation(OPERATION_SCANNING_CONSOLE_FOR_SAVING_SAVEGAMES);
SetLoadMenuContext(BUTTON_CONTEXT_SAVE_GAME_MENU_WAITING_FOR_MENU_TO_DISPLAY);
CSavegameInitialChecks::BeginInitialChecks(bForceDeviceSelection);
SetupProgress = SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS;
}
else
{
CGenericGameStorage::SetSaveOperation(OPERATION_SCANNING_CONSOLE_FOR_LOADING_SAVEGAMES);
bool bPlayerIsSignedIn = false;
#if RSG_PC || RSG_DURANGO
if (CSavegameUsers::GetSignedInUser())
{
bPlayerIsSignedIn = true;
}
else
{
SetLoadMenuContext(BUTTON_CONTEXT_WAITING_FOR_SIGN_IN);
CScaleformMenuHelper::SHOW_WARNING_MESSAGE(PM_COLUMN_MIDDLE, 2, TheText.Get("PM_SIGN_IN"), TheText.Get("PM_PANE_LOA"));
SetupProgress = SCREEN_SETUP_PROGRESS_WAIT_FOR_USER_TO_PRESS_A_BUTTON;
}
#else // do the following if not RSG_PC or RSG_DURANGO
bPlayerIsSignedIn = true;
#endif // RSG_PC || RSG_DURANGO
if (bPlayerIsSignedIn)
{
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
if (CPauseMenu::IsUploadSavegameOptionHighlighted() || CPauseMenu::IsInUploadSavegamePanel())
{
SetupProgress = SCREEN_SETUP_PROGRESS_DISPLAY_MIGRATION_INFO_SCREEN;
}
else
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
{
SetupProgress = SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING;
}
}
}
}
}
else
{
switch (SetupProgress)
{
case SCREEN_SETUP_PROGRESS_DO_NOTHING :
return MEM_CARD_COMPLETE; // Don't set returnStatus to MEM_CARD_COMPLETE. Just return here to avoid any of the extra code that is done at the bottom of this function when it has just completed.
break;
#if RSG_PC || RSG_DURANGO
case SCREEN_SETUP_PROGRESS_WAIT_FOR_USER_TO_PRESS_A_BUTTON :
if ( (CSavegameUsers::GetSignedInUser())
|| (CPauseMenu::CheckInput(FRONTEND_INPUT_ACCEPT, true, (CHECK_INPUT_OVERRIDE_FLAG_WARNING_MESSAGE | CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE | CHECK_INPUT_OVERRIDE_FLAG_RESTART_SAVED_GAME_STATE) )) )
{
CScaleformMenuHelper::SET_WARNING_MESSAGE_VISIBILITY(false);
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
if (CPauseMenu::IsUploadSavegameOptionHighlighted() || CPauseMenu::IsInUploadSavegamePanel())
{
SetupProgress = SCREEN_SETUP_PROGRESS_DISPLAY_MIGRATION_INFO_SCREEN;
}
else
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
{
SetupProgress = SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING;
}
}
break;
#endif // RSG_PC || RSG_DURANGO
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
case SCREEN_SETUP_PROGRESS_DISPLAY_MIGRATION_INFO_SCREEN :
{
bool bDisplayInfoMessage = true;
sm_bAllowAcceptButtonOnMigrationInfoScreen = true;
sm_NetworkProblemForSavegameExport = CSaveGameExport::CheckForNetworkProblems();
if (sm_NetworkProblemForSavegameExport != CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_NONE)
{
savegameDebugf1("SaveGameListScreenSetup - DISPLAY_MIGRATION_INFO_SCREEN - network problem is %s",
CSaveGameExport::GetNetworkProblemName(sm_NetworkProblemForSavegameExport));
switch (sm_NetworkProblemForSavegameExport)
{
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_NONE :
// Can't reach this state
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_SIGNED_OUT_LOCALLY :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_1")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_1", 0x1AF4BAA2), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_NO_NETWORK_CONNECTION :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_2")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_2", 0x29850C), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_AGE_RESTRICTED :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_3")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_3", 0x2DE1607B), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_SIGNED_OUT_ONLINE :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_4")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_4", 0x240F4CD7), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_SOCIAL_CLUB_UNAVAILABLE :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_5")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_5", 0xD7F734A8), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_NOT_SIGNED_IN_TO_SOCIAL_CLUB :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_6")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_6", 0xC5C59045), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
case CSaveGameExport::SAVEGAME_EXPORT_NETWORK_PROBLEM_SOCIAL_CLUB_POLICIES_OUT_OF_DATE :
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_NET_7")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_NET_7", 0xFC9CFDF3), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
break;
}
}
else if (CSaveGameExport::GetTransferAlreadyCompleted())
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_INTRO3")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_INTRO3", 0xD04E3B52), ""));
sm_bAllowAcceptButtonOnMigrationInfoScreen = false;
}
else if (CSaveGameExport::GetHaveCheckedForPreviousUpload())
{
if (CSaveGameExport::GetHasASavegameBeenPreviouslyUploaded())
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_INTRO2")
char *pMainString = TheText.Get(ATSTRINGHASH("SG_PROC_INTRO2", 0x12F8C0A6), "");
CSubStringWithinMessage SubStringArray[2];
u32 NumberOfSubStringsToInsert = 2;
SubStringArray[0].SetCharPointer(CSaveGameExport::GetMissionNameOfPreviousUpload());
SubStringArray[1].SetCharPointer(CSaveGameExport::GetSaveTimeStringOfPreviousUpload());
CMessages::InsertNumbersAndSubStringsIntoString(pMainString,
NULL, 0, // no numbers to insert
SubStringArray, NumberOfSubStringsToInsert,
sm_MigrationInfoTextBuffer, MAX_CHARS_IN_EXTENDED_MESSAGE);
}
else
{
SAVEGAME_FRONTEND_CHECK_TEXT_LABEL_EXISTS("SG_PROC_INTRO1")
safecpy(sm_MigrationInfoTextBuffer, TheText.Get(ATSTRINGHASH("SG_PROC_INTRO1", 0x28C2EC3A), ""));
}
}
else
{ // If we haven't yet checked for a previously-uploaded savegame then don't display any info message.
// Should I instead display SG_PROC_INTRO1 as if there is no previous upload?
// Or should I run the check now?
bDisplayInfoMessage = false;
}
if (bDisplayInfoMessage)
{
if (sm_bAllowAcceptButtonOnMigrationInfoScreen)
{
SetLoadMenuContext(BUTTON_CONTEXT_MIGRATION_INFO_SCREEN);
}
else
{
SetLoadMenuContext(BUTTON_CONTEXT_MIGRATION_INFO_SCREEN_NO_ACCEPT);
}
u32 hashOfTitleTextKey = ATSTRINGHASH("PM_PANE_PROC", 0x92FB6209);
CScaleformMenuHelper::SHOW_WARNING_MESSAGE(PM_COLUMN_MIDDLE, 2, sm_MigrationInfoTextBuffer, TheText.Get(hashOfTitleTextKey, ""));
SetupProgress = SCREEN_SETUP_PROGRESS_WAIT_ON_MIGRATION_INFO_SCREEN;
}
else
{
SetupProgress = SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING;
}
}
break;
case SCREEN_SETUP_PROGRESS_WAIT_ON_MIGRATION_INFO_SCREEN :
{
CSaveGameExport::eNetworkProblemsForSavegameExport currentNetworkProblem = CSaveGameExport::CheckForNetworkProblems();
if (currentNetworkProblem != sm_NetworkProblemForSavegameExport)
{
savegameDebugf1("SaveGameListScreenSetup - WAIT_ON_MIGRATION_INFO_SCREEN - network problem was %s. Now it's %s. Return to DISPLAY_MIGRATION_INFO_SCREEN",
CSaveGameExport::GetNetworkProblemName(sm_NetworkProblemForSavegameExport), CSaveGameExport::GetNetworkProblemName(currentNetworkProblem));
CScaleformMenuHelper::SET_WARNING_MESSAGE_VISIBILITY(false);
SetupProgress = SCREEN_SETUP_PROGRESS_DISPLAY_MIGRATION_INFO_SCREEN;
}
else
{
if (sm_bAllowAcceptButtonOnMigrationInfoScreen)
{
if (CPauseMenu::CheckInput(FRONTEND_INPUT_ACCEPT, true, (CHECK_INPUT_OVERRIDE_FLAG_WARNING_MESSAGE | CHECK_INPUT_OVERRIDE_FLAG_STORAGE_DEVICE) )) // | CHECK_INPUT_OVERRIDE_FLAG_RESTART_SAVED_GAME_STATE
{
CScaleformMenuHelper::SET_WARNING_MESSAGE_VISIBILITY(false);
SetupProgress = SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING;
}
}
}
}
break;
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
case SCREEN_SETUP_PROGRESS_BEGIN_INITIAL_CHECKS_FOR_LOADING :
{
#if __ALLOW_EXPORT_OF_SP_SAVEGAMES
if (CPauseMenu::IsUploadSavegameOptionHighlighted() || CPauseMenu::IsInUploadSavegamePanel())
{
SetLoadMenuContext(BUTTON_CONTEXT_UPLOAD_MENU_IS_DISPLAYING);
}
else
#endif // __ALLOW_EXPORT_OF_SP_SAVEGAMES
{
SetLoadMenuContext(BUTTON_CONTEXT_LOAD_GAME_MENU);
}
CSavegameInitialChecks::BeginInitialChecks(bForceDeviceSelection);
SetupProgress = SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS;
}
// break; // Deliberately fall through to SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS
case SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS :
{
MemoryCardError InitialChecksReturnStatus = CSavegameInitialChecks::InitialChecks();
switch (InitialChecksReturnStatus)
{
case MEM_CARD_BUSY :
bForceCloseWhenSafe = false; // This can't be interrupted
break;
case MEM_CARD_COMPLETE :
if (CreateListSortedByDate())
{
ms_BaseMenuItem = 0;
}
SetupProgress = SCREEN_SETUP_PROGRESS_SCAN_FOR_DAMAGES;
break;
case MEM_CARD_ERROR :
if (SAVE_GAME_DIALOG_PLAYER_HAS_SIGNED_OUT == CSavegameDialogScreens::GetMostRecentErrorCode())
{
returnStatus = MEM_CARD_ERROR;
}
else
{
SetupProgress = SCREEN_SETUP_PROGRESS_HANDLE_ERRORS;
}
break;
} // switch (InitialChecksReturnStatus)
}
break; // case SCREEN_SETUP_PROGRESS_DO_INITIAL_CHECKS
case SCREEN_SETUP_PROGRESS_SCAN_FOR_DAMAGES :
{
MemoryCardError ScanStatus = CheckVisibleFilesForDamage(bForceCloseWhenSafe);
switch (ScanStatus)
{
case MEM_CARD_COMPLETE :
if (CPauseMenu::IsInSaveGameMenus())
{
SetLoadMenuContext(BUTTON_CONTEXT_SAVE_GAME_MENU_IS_DISPLAYING);
}
returnStatus = MEM_CARD_COMPLETE;
break;
case MEM_CARD_BUSY :
bForceCloseWhenSafe = false; // This can't be interrupted
break;
case MEM_CARD_ERROR :
returnStatus = MEM_CARD_ERROR;
break;
}
}
break;
case SCREEN_SETUP_PROGRESS_HANDLE_ERRORS :
if (CSavegameDialogScreens::HandleSaveGameErrorCode())
{
returnStatus = MEM_CARD_ERROR;
}
break;
} // switch (SetupProgress)
} // end of else for if (bRescanMemoryCard)
if ( (returnStatus != MEM_CARD_BUSY) || bForceCloseWhenSafe)
{
SetupProgress = SCREEN_SETUP_PROGRESS_DO_NOTHING;
CGenericGameStorage::SetSaveOperation(OPERATION_NONE);
CSavegameDialogScreens::SetMessageAsProcessing(false);
}
if (bForceCloseWhenSafe)
{
savegameDisplayf("CSavegameFrontEnd::SaveGameListScreenSetup - bForceCloseWhenSafe is set so returning MEM_CARD_ERROR");
returnStatus = MEM_CARD_ERROR;
}
return returnStatus;
}
s32 CSavegameFrontEnd::ConvertMenuItemToSlotIndex(s32 menu_item)
{
if (savegameVerifyf( (menu_item >= NumberOfMenuItemsBeforeSavegameList) && (menu_item < (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) ), "CSavegameFrontEnd::ConvertMenuItemToSlotIndex - expected menu_item to be between %d and %d", NumberOfMenuItemsBeforeSavegameList, (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) ) )
{
menu_item -= NumberOfMenuItemsBeforeSavegameList;
if ((ms_BaseMenuItem + menu_item) < ms_SavegameSlotsArrangedByTime.GetCount())
{
return ms_SavegameSlotsArrangedByTime[ms_BaseMenuItem + menu_item];
}
}
return -1;
}
#if RSG_ORBIS
void CSavegameFrontEnd::ReplaceMenuItemWithSlotIndex(s32 menu_item, s32 slotIndex)
{
if (savegameVerifyf( (menu_item >= NumberOfMenuItemsBeforeSavegameList) && (menu_item < (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) ), "CSavegameFrontEnd::ReplaceMenuItemWithSlotIndex - expected menu_item to be between %d and %d", NumberOfMenuItemsBeforeSavegameList, (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList) ) )
{
menu_item -= NumberOfMenuItemsBeforeSavegameList;
if ((ms_BaseMenuItem + menu_item) < ms_SavegameSlotsArrangedByTime.GetCount())
{
ms_SavegameSlotsArrangedByTime[ms_BaseMenuItem + menu_item] = slotIndex;
}
}
}
#endif
MemoryCardError CSavegameFrontEnd::CheckVisibleFilesForDamage(bool bForceCloseWhenSafe)
{
static s32 sMenuItemToHighlight = 0;
static s32 ms_MenuItemForDamagedCheck = NumberOfMenuItemsBeforeSavegameList;
static bool s_bFinishedCheckingMenuItems = false;
if (ms_bNeedToRestartDamagedCheck)
{
if (bForceCloseWhenSafe)
{
savegameDisplayf("CSavegameFrontEnd::CheckVisibleFilesForDamage - ms_bNeedToRestartDamagedCheck is TRUE but returning MEM_CARD_ERROR because bForceCloseWhenSafe is set");
return MEM_CARD_ERROR;
}
else
{
sMenuItemToHighlight = -1;
if (NumberOfMenuItemsBeforeSavegameList == 1)
{
// Menu item 0 displays the current and maximum number of savegames
// In the save menu it can be selected to create a new save file if the maximum number of saves hasn't already been reached
char gxtNumberOfSavesText[MAX_MENU_ITEM_CHAR_LENGTH];
char *pGxtFromTextFile = TheText.Get("MO_NUM_SAVES");
bool bActivated = false;
int currentNumberOfSaveGames = ms_SavegameSlotsArrangedByTime.GetCount();
int maximumNumberOfSaveGames = TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES;
CNumberWithinMessage NumbersArray[2];
int numberOfStringArgument = 1;
if (CPauseMenu::IsInSaveGameMenus())
{
maximumNumberOfSaveGames = NUM_MANUAL_SAVE_SLOTS;
if (ms_SavegameSlotsArrangedByTime.GetCount() < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES - 1)
{
pGxtFromTextFile = TheText.Get("MO_NEW_SAVE");
currentNumberOfSaveGames = ms_SavegameSlotsArrangedByTime.GetCount()+1;
numberOfStringArgument = 2;
bActivated = true;
}
}
NumbersArray[0].Set(currentNumberOfSaveGames);
NumbersArray[1].Set(maximumNumberOfSaveGames);
if(ms_SavegameSlotsArrangedByTime.GetCount() == 0 && !CPauseMenu::IsInSaveGameMenus())
{
pGxtFromTextFile = TheText.Get("MO_NO_SAVES");
strcpy(gxtNumberOfSavesText, pGxtFromTextFile);
}
else
{
CMessages::InsertNumbersAndSubStringsIntoString(pGxtFromTextFile,
NumbersArray, numberOfStringArgument,
NULL, 0,
gxtNumberOfSavesText, NELEM(gxtNumberOfSavesText));
}
CPauseMenu::InsertSaveGameIntoMenu(0, gxtNumberOfSavesText, NULL, bActivated);
}
ms_MenuItemForDamagedCheck = NumberOfMenuItemsBeforeSavegameList;
s_bFinishedCheckingMenuItems = false;
ms_bNeedToRestartDamagedCheck = false;
} // end of else for if (bForceCloseWhenSafe)
} // if (ms_bNeedToRestartDamagedCheck)
if (s_bFinishedCheckingMenuItems)
{
return MEM_CARD_COMPLETE;
}
bool bAllMenuItemsDisplayed = false;
s32 SlotIndex = ConvertMenuItemToSlotIndex(ms_MenuItemForDamagedCheck);
if (SlotIndex >= 0)
{
#if USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
if (CSavegameList::IsThisAnAutosaveSlot(SlotIndex))
{
const s32 slotIndexOfBackupSave = SlotIndex + INDEX_OF_BACKUPSAVE_SLOT;
if (!CSavegameList::IsSaveGameSlotEmpty(slotIndexOfBackupSave) && !CSavegameList::HasBeenCheckedForDamage(slotIndexOfBackupSave))
{
switch (CSavegameList::CheckIfSlotIsDamaged(slotIndexOfBackupSave))
{
case MEM_CARD_COMPLETE :
{
if (bForceCloseWhenSafe)
{
savegameDisplayf("CSavegameFrontEnd::CheckVisibleFilesForDamage - damaged check for autosave backup slot %d has just finished. Returning MEM_CARD_ERROR because bForceCloseWhenSafe is set", slotIndexOfBackupSave);
return MEM_CARD_ERROR;
}
else
{
savegameDisplayf("CSavegameFrontEnd::CheckVisibleFilesForDamage - finished checking autosave backup slot %d for damage. Damaged = %s. I'll move on to checking the main autosave slot now", slotIndexOfBackupSave, CSavegameList::GetIsDamaged(slotIndexOfBackupSave)?"true":"false");
}
}
break;
case MEM_CARD_BUSY :
return MEM_CARD_BUSY;
// break;
case MEM_CARD_ERROR :
return MEM_CARD_ERROR;
}
}
}
#endif // USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
switch (CSavegameList::CheckIfSlotIsDamaged(SlotIndex))
{
case MEM_CARD_COMPLETE :
if (bForceCloseWhenSafe)
{
savegameDisplayf("CSavegameFrontEnd::CheckVisibleFilesForDamage - damaged check for slot %d has just finished. Returning MEM_CARD_ERROR because bForceCloseWhenSafe is set", SlotIndex);
return MEM_CARD_ERROR;
}
else
{
#if RSG_ORBIS
bool bAddCurrentItemToList = true;
//if main slot and is damaged, check backup
if(SlotIndex < TOTAL_NUMBER_OF_SLOTS_FOR_SAVEGAMES && CSavegameList::GetIsDamaged(SlotIndex) && !CSavegameList::IsSaveGameSlotEmpty(SlotIndex + INDEX_OF_BACKUPSAVE_SLOT))
{
ReplaceMenuItemWithSlotIndex(ms_MenuItemForDamagedCheck, SlotIndex + INDEX_OF_BACKUPSAVE_SLOT);
bAddCurrentItemToList = false;
}
#if USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
else if (CSavegameList::IsThisAnAutosaveSlot(SlotIndex))
{
if (!CSavegameList::IsSaveGameSlotEmpty(SlotIndex) && !CSavegameList::GetIsDamaged(SlotIndex))
{
const s32 backupSlotIndex = SlotIndex + INDEX_OF_BACKUPSAVE_SLOT;
if (!CSavegameList::IsSaveGameSlotEmpty(backupSlotIndex) && !CSavegameList::GetIsDamaged(backupSlotIndex))
{
if (CSavegameList::GetSaveTime(backupSlotIndex) > CSavegameList::GetSaveTime(SlotIndex))
{
savegameDisplayf("CSavegameFrontEnd::CheckVisibleFilesForDamage - backup slot %d is more recent than main slot %d so display the backup", backupSlotIndex, SlotIndex);
ReplaceMenuItemWithSlotIndex(ms_MenuItemForDamagedCheck, backupSlotIndex);
bAddCurrentItemToList = false;
}
}
}
}
#endif // USE_SAVE_DATA_MEMORY || USE_DOWNLOAD0_FOR_AUTOSAVE_BACKUP
if (!bAddCurrentItemToList)
{
return MEM_CARD_BUSY;
}
#endif
AddOneItemToSaveGameList(ms_MenuItemForDamagedCheck);
int iNumSavegameSlots = ms_SavegameSlotsArrangedByTime.GetCount();
if (ms_CurrentlyHighlightedSlot > iNumSavegameSlots)
{
// The end slot has been removed - move the highlight to the last save
ms_CurrentlyHighlightedSlot = iNumSavegameSlots;
}
sMenuItemToHighlight = ms_CurrentlyHighlightedSlot;
ms_MenuItemForDamagedCheck++;
if (ms_MenuItemForDamagedCheck == (MAX_SAVEGAMES_PER_FRONTEND_PAGE + NumberOfMenuItemsBeforeSavegameList))
{
bAllMenuItemsDisplayed = true;
}
}
break;
case MEM_CARD_BUSY :
break;
case MEM_CARD_ERROR :
return MEM_CARD_ERROR;
}
}
else
{
bAllMenuItemsDisplayed = true;
}
if (bAllMenuItemsDisplayed)
{
// CMenuSystem::SetSelectedMenuItem(CFrontEnd::GetMenuID(FRONTEND_MENU_SAVEGAME_LIST), sMenuItemToHighlight);
// CMenuSystem::HighlightOneItem(CFrontEnd::GetMenuID(FRONTEND_MENU_SAVEGAME_LIST), sMenuItemToHighlight, true);
// CMenuSystem::Enable(CFrontEnd::GetMenuID(FRONTEND_MENU_SAVEGAME_LIST));
// Do I need to return MEM_CARD_ERROR here if bForceCloseWhenSafe is true?
CPauseMenu::FlagSaveGameMenuAsFinished(sMenuItemToHighlight);
s8 ColumnForSpinner = CPauseMenu::GetColumnForSpinner();
CPauseMenu::SetBusySpinner(false, ColumnForSpinner);
s_bFinishedCheckingMenuItems = true;
return MEM_CARD_COMPLETE;
}
return MEM_CARD_BUSY;
}