ASYLUM: implement saving/loading via the GMM

This commit is contained in:
alxpnv 2021-09-16 15:47:25 +03:00
parent 1dcf364a00
commit 0d1e2da0b0
5 changed files with 176 additions and 97 deletions

View file

@ -113,10 +113,6 @@ AsylumEngine::~AsylumEngine() {
_gameDescription = NULL; _gameDescription = NULL;
} }
bool AsylumEngine::hasFeature(EngineFeature f) const {
return (f == kSupportsReturnToLauncher);
}
Common::Error AsylumEngine::run() { Common::Error AsylumEngine::run() {
// Initialize the graphics // Initialize the graphics
initGraphics(640, 480); initGraphics(640, 480);
@ -641,6 +637,34 @@ void AsylumEngine::checkAchievements() {
} }
} }
//////////////////////////////////////////////////////////////////////////
// Save/Load
//////////////////////////////////////////////////////////////////////////
bool AsylumEngine::canLoadGameStateCurrently() {
return _handler == _scene || _handler == _menu;
}
bool AsylumEngine::canSaveGameStateCurrently() {
return _handler == _scene;
}
Common::Error AsylumEngine::loadGameState(int slot) {
savegame()->loadList();
savegame()->setIndex(slot);
startGame(savegame()->getScenePack(), AsylumEngine::kStartGameLoad);
return Common::kNoError;
}
Common::Error AsylumEngine::saveGameState(int slot, const Common::String &desc, bool isAutosave) {
savegame()->loadList();
savegame()->setIndex(slot);
savegame()->setName(slot, desc);
savegame()->save(true);
return Common::kNoError;
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Misc // Misc
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View file

@ -194,6 +194,12 @@ public:
bool isAltDemo() { return Common::File::exists("asylum.dat"); } bool isAltDemo() { return Common::File::exists("asylum.dat"); }
Common::Language getLanguage() { return _gameDescription->language; } Common::Language getLanguage() { return _gameDescription->language; }
// Save/Load
bool canLoadGameStateCurrently();
Common::Error loadGameState(int slot);
bool canSaveGameStateCurrently();
Common::Error saveGameState(int slot, const Common::String &desc, bool isAutosave = false);
private: private:
const ADGameDescription *_gameDescription; const ADGameDescription *_gameDescription;

View file

@ -20,15 +20,19 @@
* *
*/ */
#include "engines/advancedDetector.h"
#include "base/plugins.h" #include "base/plugins.h"
#include "backends/keymapper/action.h" #include "backends/keymapper/action.h"
#include "backends/keymapper/keymap.h" #include "backends/keymapper/keymap.h"
#include "common/achievements.h" #include "common/achievements.h"
#include "common/savefile.h"
#include "common/translation.h" #include "common/translation.h"
#include "engines/advancedDetector.h"
#include "asylum/system/savegame.h"
#include "asylum/asylum.h" #include "asylum/asylum.h"
#include "asylum/shared.h" #include "asylum/shared.h"
@ -42,14 +46,50 @@ public:
return "Sanitarium (c) ASC Games"; return "Sanitarium (c) ASC Games";
} }
bool hasFeature(MetaEngineFeature f) const override; int getMaximumSaveSlot() const override { return 25; }
SaveStateList listSaves(const char *target) const override;
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const override; Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const override;
Common::KeymapArray initKeymaps(const char *target) const override; Common::KeymapArray initKeymaps(const char *target) const override;
const Common::AchievementDescriptionList *getAchievementDescriptionList() const override; const Common::AchievementDescriptionList *getAchievementDescriptionList() const override;
}; };
bool AsylumMetaEngine::hasFeature(MetaEngineFeature f) const { bool Asylum::AsylumEngine::hasFeature(EngineFeature f) const {
return false; return
(f == kSupportsReturnToLauncher) ||
(f == kSupportsLoadingDuringRuntime) ||
(f == kSupportsSavingDuringRuntime);
}
SaveStateList AsylumMetaEngine::listSaves(const char *target) const {
Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
Common::StringArray filenames;
Common::String pattern(getSavegameFilePattern(target));
filenames = saveFileMan->listSavefiles(pattern);
SaveStateList saveList;
for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
// Obtain the last 3 digits of the filename, since they correspond to the save slot
int slotNum = atoi(file->c_str() + file->size() - 3);
if (slotNum >= 0 && slotNum <= getMaximumSaveSlot()) {
SaveStateDescriptor desc = querySaveMetaInfos(target, slotNum);
if (desc.getSaveSlot() == -1) {
Common::InSaveFile *in(saveFileMan->openForLoading(*file));
if (in && in->size()) {
(void)(uint32)Asylum::Savegame::read(in, "Chapter");
desc.setSaveSlot(slotNum);
desc.setDescription(Asylum::Savegame::read(in, 45, "Game Name"));
}
}
saveList.push_back(desc);
}
}
// Sort saves based on slot number.
Common::sort(saveList.begin(), saveList.end(), SaveStateDescriptorSlotComparator());
return saveList;
} }
Common::Error AsylumMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { Common::Error AsylumMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {

View file

@ -45,8 +45,6 @@ namespace Asylum {
#define SAVEGAME_VERSION_SIZE 11 #define SAVEGAME_VERSION_SIZE 11
#define SAVEGAME_NAME_SIZE 45 #define SAVEGAME_NAME_SIZE 45
#define SAVEGAME_NAME "asylum"
#define SAVEGAME_QUICKSLOT 24 #define SAVEGAME_QUICKSLOT 24
#define SAVEGAME_MOVIES "asylum.movies" #define SAVEGAME_MOVIES "asylum.movies"
@ -134,11 +132,11 @@ bool Savegame::quickLoad() {
return true; return true;
} }
void Savegame::save() { void Savegame::save(bool appendExtended) {
// Original creates a folder to hold saved games and checks for disk space, we can skip that // Original creates a folder to hold saved games and checks for disk space, we can skip that
getCursor()->hide(); getCursor()->hide();
if (saveData(getFilename(_index), _names[_index], getWorld()->chapter)) { if (saveData(getFilename(_index), _names[_index], getWorld()->chapter, appendExtended)) {
_savegames[_index] = true; _savegames[_index] = true;
getMenu()->setDword455C78(true); getMenu()->setDword455C78(true);
@ -216,7 +214,7 @@ Common::String Savegame::getFilename(uint32 index) const {
if (index > SAVEGAME_COUNT - 1) if (index > SAVEGAME_COUNT - 1)
error("[Savegame::getFilename] Invalid savegame index (was:%d, valid: [0-24])", index); error("[Savegame::getFilename] Invalid savegame index (was:%d, valid: [0-24])", index);
return Common::String::format("%s%02d.sav", SAVEGAME_NAME, index); return _vm->getSaveStateName(index);
} }
bool Savegame::isSavegamePresent(Common::String filename) const { bool Savegame::isSavegamePresent(Common::String filename) const {
@ -296,7 +294,7 @@ bool Savegame::loadData(Common::String filename) {
return true; return true;
} }
bool Savegame::saveData(Common::String filename, Common::String name, ChapterIndex chapter) { bool Savegame::saveData(Common::String filename, Common::String name, ChapterIndex chapter, bool appendExtended) {
Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(filename); Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(filename);
if (!file) if (!file)
return false; return false;
@ -315,12 +313,17 @@ bool Savegame::saveData(Common::String filename, Common::String name, ChapterInd
write(file, _vm->getTick(), "Time"); write(file, _vm->getTick(), "Time");
if (appendExtended)
_vm->getMetaEngine()->appendExtendedSaveToStream(file, _vm->getTotalPlayTime() / 1000, name, false);
else
file->writeUint32LE(0);
delete file; delete file;
return true; return true;
} }
void Savegame::seek(Common::InSaveFile *file, uint32 offset, Common::String description) const { void Savegame::seek(Common::InSaveFile *file, uint32 offset, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Seeking to offset: %s", description.c_str()); debugC(kDebugLevelSavegame, "[Savegame] Seeking to offset: %s", description.c_str());
if (offset == 0) if (offset == 0)
@ -337,7 +340,7 @@ void Savegame::seek(Common::InSaveFile *file, uint32 offset, Common::String desc
} }
} }
uint32 Savegame::read(Common::InSaveFile *file, Common::String description) const { uint32 Savegame::read(Common::InSaveFile *file, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Reading %s", description.c_str()); debugC(kDebugLevelSavegame, "[Savegame] Reading %s", description.c_str());
uint32 size = file->readUint32LE(); uint32 size = file->readUint32LE();
@ -349,7 +352,7 @@ uint32 Savegame::read(Common::InSaveFile *file, Common::String description) cons
return file->readUint32LE(); return file->readUint32LE();
} }
Common::String Savegame::read(Common::InSaveFile *file, uint32 strLength, Common::String description) const { Common::String Savegame::read(Common::InSaveFile *file, uint32 strLength, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Reading %s (of length %d)", description.c_str(), strLength); debugC(kDebugLevelSavegame, "[Savegame] Reading %s (of length %d)", description.c_str(), strLength);
/*uint32 size =*/ file->readUint32LE(); /*uint32 size =*/ file->readUint32LE();
@ -369,7 +372,7 @@ Common::String Savegame::read(Common::InSaveFile *file, uint32 strLength, Common
return ret; return ret;
} }
void Savegame::read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) const { void Savegame::read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Reading %s (%d block(s) of size %d)", description.c_str(), size, count); debugC(kDebugLevelSavegame, "[Savegame] Reading %s (%d block(s) of size %d)", description.c_str(), size, count);
uint32 fileSize = file->readUint32LE(); uint32 fileSize = file->readUint32LE();
@ -387,7 +390,7 @@ void Savegame::read(Common::InSaveFile *file, Common::Serializable *data, uint32
data->saveLoadWithSerializer(ser); data->saveLoadWithSerializer(ser);
} }
void Savegame::write(Common::OutSaveFile *file, uint32 val, Common::String description) const { void Savegame::write(Common::OutSaveFile *file, uint32 val, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Writing %s: %d", description.c_str(), val); debugC(kDebugLevelSavegame, "[Savegame] Writing %s: %d", description.c_str(), val);
file->writeUint32LE(4); file->writeUint32LE(4);
@ -396,7 +399,7 @@ void Savegame::write(Common::OutSaveFile *file, uint32 val, Common::String descr
file->writeUint32LE(val); file->writeUint32LE(val);
} }
void Savegame::write(Common::OutSaveFile *file, Common::String val, uint32 strLength, Common::String description) const { void Savegame::write(Common::OutSaveFile *file, Common::String val, uint32 strLength, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Writing %s (of length %d): %s", description.c_str(), strLength, val.c_str()); debugC(kDebugLevelSavegame, "[Savegame] Writing %s (of length %d): %s", description.c_str(), strLength, val.c_str());
if (val.size() > strLength) if (val.size() > strLength)
@ -414,7 +417,7 @@ void Savegame::write(Common::OutSaveFile *file, Common::String val, uint32 strLe
} }
} }
void Savegame::write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) const { void Savegame::write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) {
debugC(kDebugLevelSavegame, "[Savegame] Writing %s (%d block(s) of size %d)", description.c_str(), size, count); debugC(kDebugLevelSavegame, "[Savegame] Writing %s (%d block(s) of size %d)", description.c_str(), size, count);
file->writeUint32LE(size); file->writeUint32LE(size);

View file

@ -69,9 +69,11 @@ public:
/** /**
* Saves a game * Saves a game
* *
* @param appendExtended Append the extended savegame header to the stream.
*
* @return true if it succeeds, false if it fails. * @return true if it succeeds, false if it fails.
*/ */
void save(); void save(bool appendExtended = false);
/** /**
* Quick saves a game * Quick saves a game
@ -85,6 +87,80 @@ public:
*/ */
void remove(); void remove();
//////////////////////////////////////////////////////////////////////////
// Static methods
//////////////////////////////////////////////////////////////////////////
/**
* Seeks to a specific place in the file
*
* @param [in,out] file If non-null, the file.
* @param offset Offset index of the info into the file
* @param description The description.
*/
static void seek(Common::InSaveFile *file, uint32 offset, Common::String description);
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param description The description.
*
* @return the value
*/
static uint32 read(Common::InSaveFile *file, Common::String description);
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param strLength Length of the string.
* @param description The description.
*
* @return the string
*/
static Common::String read(Common::InSaveFile *file, uint32 strLength, Common::String description);
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param [in,out] data If non-null, the data.
* @param size The size.
* @param count Number of.
* @param description The description.
*/
static void read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description);
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param val The value
* @param description The description.
*/
static void write(Common::OutSaveFile *file, uint32 val, Common::String description);
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param val The string
* @param strLength The size of the string.
* @param description The description.
*/
static void write(Common::OutSaveFile *file, Common::String val, uint32 strLength, Common::String description);
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param [in,out] data If non-null, the data.
* @param size The size.
* @param count Number of.
* @param description The description.
*/
static void write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description);
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
// Movies // Movies
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
@ -176,84 +252,14 @@ private:
/** /**
* Save savegame data. * Save savegame data.
* *
* @param filename Filename of the file. * @param filename Filename of the file.
* @param name The name. * @param name The name.
* @param chapter The chapter. * @param chapter The chapter.
* @param appendExtended Append the extended savegame header to the stream.
* *
* @return true if it succeeds, false if it fails. * @return true if it succeeds, false if it fails.
*/ */
bool saveData(Common::String filename, Common::String name, ChapterIndex chapter); bool saveData(Common::String filename, Common::String name, ChapterIndex chapter, bool appendExtended = false);
/**
* Seeks to a specific place in the file
*
* @param [in,out] file If non-null, the file.
* @param offset Offset index of the info into the file
* @param description The description.
*/
void seek(Common::InSaveFile *file, uint32 offset, Common::String description) const;
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param description The description.
*
* @return the value
*/
uint32 read(Common::InSaveFile *file, Common::String description) const;
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param strLength Length of the string.
* @param description The description.
*
* @return the string
*/
Common::String read(Common::InSaveFile *file, uint32 strLength, Common::String description) const;
/**
* Reads data from a file.
*
* @param [in,out] file If non-null, the file.
* @param [in,out] data If non-null, the data.
* @param size The size.
* @param count Number of.
* @param description The description.
*/
void read(Common::InSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) const;
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param val The value
* @param description The description.
*/
void write(Common::OutSaveFile *file, uint32 val, Common::String description) const;
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param val The string
* @param strLength The size of the string.
* @param description The description.
*/
void write(Common::OutSaveFile *file, Common::String val, uint32 strLength, Common::String description) const;
/**
* Writes data to a file.
*
* @param [in,out] file If non-null, the file.
* @param [in,out] data If non-null, the data.
* @param size The size.
* @param count Number of.
* @param description The description.
*/
void write(Common::OutSaveFile *file, Common::Serializable *data, uint32 size, uint32 count, Common::String description) const;
}; };
} // End of namespace Asylum } // End of namespace Asylum