aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sci/console.cpp11
-rw-r--r--engines/sci/detection.cpp168
-rw-r--r--engines/sci/engine/savegame.cpp11
-rw-r--r--engines/sci/engine/savegame.h2
-rw-r--r--engines/sci/sci.h5
5 files changed, 191 insertions, 6 deletions
diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp
index 04d9eaf475..eceac555de 100644
--- a/engines/sci/console.cpp
+++ b/engines/sci/console.cpp
@@ -768,14 +768,15 @@ bool Console::cmdSaveGame(int argc, const char **argv) {
DebugPrintf("Note: Game state has %d open file handles.\n", result);
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
- Common::OutSaveFile *out;
- if (!(out = saveFileMan->openForSaving(argv[1]))) {
+ Common::OutSaveFile *out = saveFileMan->openForSaving(argv[1]);
+ const char *version = "";
+ if (!out) {
DebugPrintf("Error opening savegame \"%s\" for writing\n", argv[1]);
return true;
}
// TODO: enable custom descriptions? force filename into a specific format?
- if (gamestate_save(_vm->_gamestate, out, "debugging", 0)) {
+ if (gamestate_save(_vm->_gamestate, out, "debugging", version)) {
DebugPrintf("Saving the game state to '%s' failed\n", argv[1]);
}
@@ -792,8 +793,8 @@ bool Console::cmdRestoreGame(int argc, const char **argv) {
EngineState *newstate = NULL;
Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
- Common::SeekableReadStream *in;
- if (!(in = saveFileMan->openForLoading(argv[1]))) {
+ Common::SeekableReadStream *in = saveFileMan->openForLoading(argv[1]);
+ if (in) {
// found a savegame file
newstate = gamestate_restore(_vm->_gamestate, in);
delete in;
diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp
index 90be90b156..c4aad4e5f7 100644
--- a/engines/sci/detection.cpp
+++ b/engines/sci/detection.cpp
@@ -25,10 +25,14 @@
#include "engines/advancedDetector.h"
#include "base/plugins.h"
+#include "common/savefile.h"
+#include "graphics/thumbnail.h"
#include "sci/sci.h"
#include "sci/engine/kernel.h"
+#include "sci/engine/savegame.h"
#include "sci/engine/seg_manager.h"
+#include "sci/engine/state.h"
#include "sci/engine/vm.h" // for convertSierraGameId
namespace Sci {
@@ -161,6 +165,11 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
const ADGameDescription *fallbackDetect(const Common::FSList &fslist) const;
+ virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual void removeSaveState(const char *target, int slot) const;
+ SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
Common::Language charToScummVMLanguage(const char c) {
@@ -373,6 +382,165 @@ bool SciMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
return true;
}
+bool SciMetaEngine::hasFeature(MetaEngineFeature f) const {
+ return
+ (f == kSupportsListSaves) ||
+ //(f == kSupportsLoadingDuringStartup) ||
+ (f == kSupportsDeleteSave) ||
+ (f == kSavesSupportMetaInfo) ||
+ (f == kSavesSupportThumbnail) ||
+ (f == kSavesSupportCreationDate);
+}
+
+bool SciEngine::hasFeature(EngineFeature f) const {
+ return
+ //(f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime);
+ //(f == kSupportsSavingDuringRuntime);
+}
+
+SaveStateList SciMetaEngine::listSaves(const char *target) const {
+ Common::SaveFileManager *saveFileMan = g_system->getSavefileManager();
+ Common::StringList filenames;
+ Common::String pattern = target;
+ pattern += ".???";
+
+ filenames = saveFileMan->listSavefiles(pattern);
+ sort(filenames.begin(), filenames.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ int slotNum = 0;
+ for (Common::StringList::const_iterator file = filenames.begin(); file != filenames.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ slotNum = atoi(file->c_str() + file->size() - 3);
+
+ if (slotNum >= 0 && slotNum < 999) {
+ Common::InSaveFile *in = saveFileMan->openForLoading(*file);
+ if (in) {
+ SavegameMetadata meta;
+ if (!get_savegame_metadata(in, &meta)) {
+ // invalid
+ delete in;
+ continue;
+ }
+ saveList.push_back(SaveStateDescriptor(slotNum, meta.savegame_name));
+ delete in;
+ }
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor SciMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (in) {
+ SavegameMetadata meta;
+ if (!get_savegame_metadata(in, &meta)) {
+ // invalid
+ delete in;
+
+ SaveStateDescriptor desc(slot, "Invalid");
+ return desc;
+ }
+
+ SaveStateDescriptor desc(slot, meta.savegame_name);
+
+ Graphics::Surface *thumbnail = new Graphics::Surface();
+ assert(thumbnail);
+ if (!Graphics::loadThumbnail(*in, *thumbnail)) {
+ delete thumbnail;
+ thumbnail = 0;
+ }
+
+ desc.setThumbnail(thumbnail);
+
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+
+ int day = (meta.savegame_date >> 24) & 0xFF;
+ int month = (meta.savegame_date >> 16) & 0xFF;
+ int year = meta.savegame_date & 0xFFFF;
+
+ desc.setSaveDate(year, month, day);
+
+ int hour = (meta.savegame_time >> 16) & 0xFF;
+ int minutes = (meta.savegame_time >> 8) & 0xFF;
+
+ desc.setSaveTime(hour, minutes);
+
+ // TODO: played time
+
+ delete in;
+
+ return desc;
+ }
+
+ return SaveStateDescriptor();
+}
+
+int SciMetaEngine::getMaximumSaveSlot() const { return 999; }
+
+void SciMetaEngine::removeSaveState(const char *target, int slot) const {
+ Common::String fileName = Common::String::printf("%s.%03d", target, slot);
+ g_system->getSavefileManager()->removeSavefile(fileName);
+}
+
+Common::Error SciEngine::loadGameState(int slot) {
+ EngineState *newstate = NULL;
+ Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
+ Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+ Common::SeekableReadStream *in = saveFileMan->openForLoading(fileName);
+
+ if (in) {
+ // found a savegame file
+ newstate = gamestate_restore(_gamestate, in);
+ delete in;
+ }
+
+ if (newstate) {
+ _gamestate->successor = newstate; // Set successor
+
+ script_abort_flag = 2; // Abort current game with replay
+
+ shrink_execution_stack(_gamestate, _gamestate->execution_stack_base + 1);
+ return Common::kNoError;
+ } else {
+ warning("Restoring gamestate '%s' failed.\n", fileName);
+ return Common::kUnknownError;
+ }
+}
+
+Common::Error SciEngine::saveGameState(int slot, const char *desc) {
+ // TODO: Savegames created from the GMM are still problematic
+#if 0
+ Common::String fileName = Common::String::printf("%s.%03d", _targetName.c_str(), slot);
+ Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager();
+ Common::OutSaveFile *out = saveFileMan->openForSaving(fileName);
+ const char *version = "";
+ if (!out) {
+ warning("Error opening savegame \"%s\" for writing\n", fileName);
+ return Common::kWritingFailed;
+ }
+
+ if (gamestate_save(_gamestate, out, desc, version)) {
+ warning("Saving the game state to '%s' failed\n", fileName);
+ return Common::kUnknownError;
+ }
+#endif
+ return Common::kNoError; // TODO: return success/failure
+}
+
+bool SciEngine::canLoadGameStateCurrently() {
+ return !_gamestate->execution_stack_base;
+}
+
+bool SciEngine::canSaveGameStateCurrently() {
+ return !_gamestate->execution_stack_base;
+}
+
} // End of namespace Sci
#if PLUGIN_ENABLED_DYNAMIC(SCI)
diff --git a/engines/sci/engine/savegame.cpp b/engines/sci/engine/savegame.cpp
index 619bbfb009..9a136d7a63 100644
--- a/engines/sci/engine/savegame.cpp
+++ b/engines/sci/engine/savegame.cpp
@@ -27,6 +27,7 @@
#include "common/system.h"
#include "common/func.h"
#include "common/serializer.h"
+#include "graphics/thumbnail.h"
#include "sci/sci.h"
#include "sci/gfx/operations.h"
@@ -529,6 +530,7 @@ int gamestate_save(EngineState *s, Common::WriteStream *fh, const char* savename
*/
Common::Serializer ser(0, fh);
sync_SavegameMetadata(ser, meta);
+ Graphics::saveThumbnail(*fh);
s->saveLoadWithSerializer(ser); // FIXME: Error handling?
return 0;
@@ -724,6 +726,15 @@ EngineState *gamestate_restore(EngineState *s, Common::SeekableReadStream *fh) {
return NULL;
}
+ if (meta.savegame_version >= 12) {
+ // We don't need the thumbnail here, so just read it and discard it
+ Graphics::Surface *thumbnail = new Graphics::Surface();
+ assert(thumbnail);
+ Graphics::loadThumbnail(*fh, *thumbnail);
+ delete thumbnail;
+ thumbnail = 0;
+ }
+
// FIXME: Do in-place loading at some point, instead of creating a new EngineState instance from scratch.
retval = new EngineState(s->resMan, s->_kernel, s->_voc, s->_gui, s->_cursor);
diff --git a/engines/sci/engine/savegame.h b/engines/sci/engine/savegame.h
index 5da5486da3..95f3099f07 100644
--- a/engines/sci/engine/savegame.h
+++ b/engines/sci/engine/savegame.h
@@ -36,7 +36,7 @@ namespace Sci {
struct EngineState;
enum {
- CURRENT_SAVEGAME_VERSION = 11,
+ CURRENT_SAVEGAME_VERSION = 12,
MINIMUM_SAVEGAME_VERSION = 9
};
diff --git a/engines/sci/sci.h b/engines/sci/sci.h
index e0e952a8b2..2acfdf730f 100644
--- a/engines/sci/sci.h
+++ b/engines/sci/sci.h
@@ -96,9 +96,14 @@ public:
// Engine APIs
virtual Common::Error run();
+ bool hasFeature(EngineFeature f) const;
void pauseEngineIntern(bool pause);
virtual GUI::Debugger *getDebugger();
Console *getSciDebugger();
+ Common::Error loadGameState(int slot);
+ Common::Error saveGameState(int slot, const char *desc);
+ bool canLoadGameStateCurrently();
+ bool canSaveGameStateCurrently();
const char* getGameID() const;
int getResourceVersion() const;