aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/mortevielle/detection.cpp27
-rw-r--r--engines/mortevielle/disk.cpp157
-rw-r--r--engines/mortevielle/module.mk2
-rw-r--r--engines/mortevielle/mortevielle.cpp181
-rw-r--r--engines/mortevielle/mortevielle.h9
-rw-r--r--engines/mortevielle/prog.cpp105
-rw-r--r--engines/mortevielle/prog.h2
-rw-r--r--engines/mortevielle/saveload.cpp318
-rw-r--r--engines/mortevielle/saveload.h (renamed from engines/mortevielle/disk.h)39
9 files changed, 563 insertions, 277 deletions
diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp
index ec0b01622a..35e5cada81 100644
--- a/engines/mortevielle/detection.cpp
+++ b/engines/mortevielle/detection.cpp
@@ -25,6 +25,7 @@
#include "mortevielle/mortevielle.h"
#include "mortevielle/detection_tables.h"
+#include "mortevielle/saveload.h"
namespace Mortevielle {
uint32 MortevielleEngine::getGameFlags() const { return _gameDescription->flags; }
@@ -52,6 +53,9 @@ public:
virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const;
virtual bool hasFeature(MetaEngineFeature f) const;
+ virtual int getMaximumSaveSlot() const;
+ virtual SaveStateList listSaves(const char *target) const;
+ virtual SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const;
};
bool MortevielleMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
@@ -62,9 +66,30 @@ bool MortevielleMetaEngine::createInstance(OSystem *syst, Engine **engine, const
}
bool MortevielleMetaEngine::hasFeature(MetaEngineFeature f) const {
- return false;
+ switch (f) {
+ case kSupportsListSaves:
+ case kSupportsDeleteSave:
+ case kSupportsLoadingDuringStartup:
+ case kSavesSupportMetaInfo:
+ case kSavesSupportThumbnail:
+ case kSavesSupportCreationDate:
+ return true;
+ default:
+ return false;
+ }
+}
+
+int MortevielleMetaEngine::getMaximumSaveSlot() const { return 99; }
+
+SaveStateList MortevielleMetaEngine::listSaves(const char *target) const {
+ return Mortevielle::SavegameManager::listSaves(target);
}
+SaveStateDescriptor MortevielleMetaEngine::querySaveMetaInfos(const char *target, int slot) const {
+ return Mortevielle::SavegameManager::querySaveMetaInfos(slot);
+}
+
+
#if PLUGIN_ENABLED_DYNAMIC(MORTEVIELLE)
REGISTER_PLUGIN_DYNAMIC(MORTEVIELLE, PLUGIN_TYPE_ENGINE, MortevielleMetaEngine);
#else
diff --git a/engines/mortevielle/disk.cpp b/engines/mortevielle/disk.cpp
deleted file mode 100644
index 25bf7faca3..0000000000
--- a/engines/mortevielle/disk.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- */
-
-/*
- * This code is based on original Mortville Manor DOS source code
- * Copyright (c) 1988-1989 Lankhor
- */
-
-#include "common/file.h"
-#include "common/system.h"
-#include "common/savefile.h"
-#include "common/serializer.h"
-#include "mortevielle/alert.h"
-#include "mortevielle/disk.h"
-#include "mortevielle/mor.h"
-#include "mortevielle/mor2.h"
-#include "mortevielle/mouse.h"
-#include "mortevielle/ovd1.h"
-#include "mortevielle/prog.h"
-#include "mortevielle/var_mor.h"
-
-namespace Mortevielle {
-
-/**
- * Ensure disk 1 data is available
- */
-void dem1() {
-/* Deprecated in ScummVM
- int k;
-
- // -- demande de disk 1 -- //Translation: Ask for disk #1
- assign(f, "mort.005");
- //*$i-*
- k = ioresult;
- reset(f);
- while (ioresult != 0) {
- show_mouse();
- k = do_alert(al_mess, 1);
- hide_mouse();
- reset(f);
- }
- close(f);
- */
-}
-
-/**
- * Handle saving or loading savegame data
- */
-static void sync_save(Common::Serializer &sz) {
- sz.syncAsSint16LE(s1.conf);
- sz.syncBytes((byte *)&s1.pourc[0], 11);
- sz.syncBytes((byte *)&s1.teauto[0], 43);
- sz.syncBytes((byte *)&s1.sjer[0], 31);
- sz.syncAsSint16LE(s1.mlieu);
- sz.syncAsSint16LE(s1.iboul);
- sz.syncAsSint16LE(s1.ibag);
- sz.syncAsSint16LE(s1.icave);
- sz.syncAsSint16LE(s1.ivier);
- sz.syncAsSint16LE(s1.ipuit);
- sz.syncAsSint16LE(s1.derobj);
- sz.syncAsSint16LE(s1.iloic);
- sz.syncAsSint16LE(s1.icryp);
- sz.syncAsByte(s1.ipre);
- sz.syncAsByte(s1.heure);
-
- sz.syncBytes(bufcha, 391);
-}
-
-void takesav(int n) {
- int i;
- Common::String st;
-
- dem1();
- // -- Load the file 'sauve#n.mor'
- Common::String saveName = Common::String::format("sav%d.mor", n);
-
- // Try loading first from the save area
- Common::SeekableReadStream *stream = g_system->getSavefileManager()->openForLoading(saveName);
-
- // If not present, try loading from the program folder
- Common::File f;
- if (stream == NULL) {
- if (!f.open(saveName))
- error("Unable to open save file '%s'", saveName);
-
- stream = f.readStream(f.size());
- f.close();
- }
-
- Common::Serializer sz(stream, NULL);
- sync_save(sz);
-
- s = s1;
- for (i = 0; i <= 389; i ++) tabdon[i + acha] = bufcha[i];
-
- // Close the stream
- delete stream;
-}
-
-void ld_game(int n) {
- hide_mouse();
- maivid();
- takesav(n);
- /* -- disquette 2 -- */ //Translation: Floppy #2
- dem2();
- /* -- mises en place -- */ //Translation: Initialization
- theure();
- dprog();
- antegame();
- show_mouse();
-}
-
-void sv_game(int n) {
- Common::OutSaveFile *f;
- int i;
-
- hide_mouse();
- tmaj3();
- dem1();
- /* -- sauvegarde du fichier 'sauve#n.mor' -- */ //Translation: save file 'sauve%d.mor'
- for (i = 0; i <= 389; i ++) bufcha[i] = tabdon[i + acha];
- s1 = s;
- if (s1.mlieu == 26) s1.mlieu = 15;
-
- Common::String saveName = Common::String::format("sav%d.mor", n);
- f = g_system->getSavefileManager()->openForSaving(saveName);
-
- Common::Serializer sz(NULL, f);
- sync_save(sz);
-
- f->finalize();
- delete f;
-
- dem2();
- show_mouse();
-}
-
-} // End of namespace Mortevielle
diff --git a/engines/mortevielle/module.mk b/engines/mortevielle/module.mk
index 2d16106e0c..28c6c7fc6d 100644
--- a/engines/mortevielle/module.mk
+++ b/engines/mortevielle/module.mk
@@ -6,7 +6,6 @@ MODULE_OBJS := \
asm.o \
boite.o \
detection.o \
- disk.o \
droite.o \
graphics.o \
keyboard.o \
@@ -22,6 +21,7 @@ MODULE_OBJS := \
parole2.o \
prog.o \
ques.o \
+ saveload.o \
sound.o \
sprint.o \
taffich.o \
diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp
index 35d71c92aa..cbe2613716 100644
--- a/engines/mortevielle/mortevielle.cpp
+++ b/engines/mortevielle/mortevielle.cpp
@@ -21,6 +21,7 @@
*/
#include "common/system.h"
+#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "engines/util.h"
#include "engines/engine.h"
@@ -28,16 +29,20 @@
#include "graphics/palette.h"
#include "graphics/pixelformat.h"
#include "mortevielle/mortevielle.h"
+#include "mortevielle/actions.h"
+#include "mortevielle/alert.h"
#include "mortevielle/asm.h"
-#include "mortevielle/disk.h"
#include "mortevielle/keyboard.h"
#include "mortevielle/level15.h"
+#include "mortevielle/menu.h"
#include "mortevielle/mor.h"
#include "mortevielle/mor2.h"
#include "mortevielle/mouse.h"
#include "mortevielle/ovd1.h"
#include "mortevielle/parole2.h"
#include "mortevielle/prog.h"
+#include "mortevielle/saveload.h"
+#include "mortevielle/taffich.h"
#include "mortevielle/var_mor.h"
namespace Mortevielle {
@@ -50,15 +55,58 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const ADGameDescription *g
g_vm = this;
_lastGameFrame = 0;
_mouseClick = false;
+ _inMainGameLoop = false;
}
MortevielleEngine::~MortevielleEngine() {
}
+/**
+ * Specifies whether the engine supports given features
+ */
bool MortevielleEngine::hasFeature(EngineFeature f) const {
- return false;
+ return
+ (f == kSupportsRTL) ||
+ (f == kSupportsLoadingDuringRuntime) ||
+ (f == kSupportsSavingDuringRuntime);
+}
+
+/**
+ * Return true if a game can currently be loaded
+ */
+bool MortevielleEngine::canLoadGameStateCurrently() {
+ // Saving is only allowed in the main game event loop
+ return _inMainGameLoop;
}
+/**
+ * Return true if a game can currently be saved
+ */
+bool MortevielleEngine::canSaveGameStateCurrently() {
+ // Loading is only allowed in the main game event loop
+ return _inMainGameLoop;
+}
+
+/**
+ * Load in a savegame at the specified slot number
+ */
+Common::Error MortevielleEngine::loadGameState(int slot) {
+ return _savegameManager.loadGame(slot);
+}
+
+/**
+ * Save the current game
+ */
+Common::Error MortevielleEngine::saveGameState(int slot, const Common::String &desc) {
+ if (slot == 0)
+ return Common::kWritingFailed;
+
+ return _savegameManager.saveGame(slot, desc);
+}
+
+/**
+ * Initialise the game state
+ */
Common::ErrorCode MortevielleEngine::initialise() {
// Initialise graphics mode
initGraphics(SCREEN_WIDTH, SCREEN_HEIGHT, true);
@@ -361,12 +409,23 @@ Common::Error MortevielleEngine::run() {
if (err != Common::kNoError)
return err;
- // Show the game introduction
- showIntroduction();
+ // Check for a savegame
+ int loadSlot = 0;
+ if (ConfMan.hasKey("save_slot")) {
+ int gameToLoad = ConfMan.getInt("save_slot");
+ if (gameToLoad >= 1 && gameToLoad <= 999)
+ loadSlot = gameToLoad;
+ }
+
+ if (loadSlot == 0)
+ // Show the game introduction
+ showIntroduction();
+ // Either load the initial game state savegame, or the specified savegame number
adzon();
- takesav(0);
+ _savegameManager.takesav(loadSlot);
+ // Run the main game loop
mainGame();
return Common::kNoError;
@@ -425,4 +484,116 @@ void MortevielleEngine::mainGame() {
} while (!arret);
}
+/**
+ * This method handles repeatedly calling a sub-method to wait for a user action and then handling it
+ */
+void MortevielleEngine::tjouer() {
+ antegame();
+ do {
+ tecran();
+ CHECK_QUIT;
+ } while (!((arret) || (solu) || (perdu)));
+ if (solu)
+ tmaj1();
+ else if (perdu)
+ tencore();
+}
+
+/**
+ * Waits for the user to select an action, and then handles it
+ */
+void MortevielleEngine::tecran() {
+ const char idem[] = "Idem";
+ const int lim = 20000;
+ int temps = 0;
+ char inkey = '\0';
+ bool oo, funct = 0;
+
+ clsf3();
+ oo = false;
+ ctrm = 0;
+ if (! iesc) {
+ draw_menu();
+ imen = true;
+ temps = 0;
+ key = 0;
+ funct = false;
+ inkey = '.';
+
+ _inMainGameLoop = true;
+ do {
+ mdn();
+ tinke();
+ mov_mouse(funct, inkey);
+ CHECK_QUIT;
+ temps = temps + 1;
+ } while (!((choisi) || (temps > lim) || (funct) || (anyone)));
+ _inMainGameLoop = false;
+
+ erase_menu();
+ imen = false;
+ if ((inkey == '\1') || (inkey == '\3') || (inkey == '\5') || (inkey == '\7') || (inkey == '\11')) {
+ change_gd((uint)pred(int, ord(inkey)) >> 1);
+ return;
+ }
+ if (choisi && (msg[3] == sauve)) {
+ Common::String saveName = Common::String::format("Savegame #%d", msg[4] & 7);
+ g_vm->_savegameManager.saveGame(msg[4] & 7, saveName);
+ }
+ if (choisi && (msg[3] == charge))
+ g_vm->_savegameManager.loadGame((msg[4] & 7) - 1);
+ if (inkey == '\103') { /* F9 */
+ temps = do_alert(stpou, 1);
+ return;
+ } else if (inkey == '\77') {
+ if ((mnumo != no_choice) && ((msg[3] == action) || (msg[3] == saction))) {
+ msg[4] = mnumo;
+ ecr3(idem);
+ } else return;
+ } else if (inkey == '\104') {
+ if ((x != 0) && (y != 0)) num = 9999;
+ return;
+ }
+ }
+ if (inkey == '\73') {
+ arret = true;
+ tmaj3();
+ } else {
+ if ((funct) && (inkey != '\77')) return;
+ if (temps > lim) {
+ repon(2, 141);
+ if (num == 9999) num = 0;
+ } else {
+ mnumo = msg[3];
+ if ((msg[3] == action) || (msg[3] == saction)) mnumo = msg[4];
+ if (! anyone) {
+ if ((fouil) || (obpart)) {
+ if (y_s < 12) return;
+ if ((msg[4] == sonder) || (msg[4] == soulever)) {
+ oo = true;
+ if ((msg[4] == soulever) || (obpart)) {
+ finfouil();
+ caff = s.mlieu;
+ crep = 998;
+ } else tsuiv();
+ mennor();
+ }
+ }
+ }
+ do {
+ if (! oo) tsitu();
+ if ((ctrm == 0) && (! perdu) && (! solu)) {
+ taffich();
+ if (okdes) {
+ okdes = false;
+ dessin(0);
+ }
+ if ((! syn) || (col)) repon(2, crep);
+ }
+ } while (!(! syn));
+ if (ctrm != 0) tctrm();
+ }
+ }
+}
+
} // End of namespace Mortevielle
diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h
index 863cbdb95e..6dad5a0a79 100644
--- a/engines/mortevielle/mortevielle.h
+++ b/engines/mortevielle/mortevielle.h
@@ -33,6 +33,7 @@
#include "common/error.h"
#include "graphics/surface.h"
#include "mortevielle/graphics.h"
+#include "mortevielle/saveload.h"
#include "mortevielle/sound.h"
namespace Mortevielle {
@@ -56,6 +57,7 @@ private:
uint32 _lastGameFrame;
bool _mouseClick;
Common::Point _mousePos;
+ bool _inMainGameLoop;
Common::ErrorCode initialise();
Common::ErrorCode loadMortDat();
@@ -65,6 +67,8 @@ private:
void initMouse();
void showIntroduction();
void mainGame();
+ void tjouer();
+ void tecran();
void divers(int np, bool b);
public:
ScreenSurface _screenSurface;
@@ -72,10 +76,15 @@ public:
GfxSurface _backgroundSurface;
Common::RandomSource _randomSource;
SoundManager _soundManager;
+ SavegameManager _savegameManager;
public:
MortevielleEngine(OSystem *system, const ADGameDescription *gameDesc);
~MortevielleEngine();
virtual bool hasFeature(EngineFeature f) const;
+ virtual bool canLoadGameStateCurrently();
+ virtual bool canSaveGameStateCurrently();
+ virtual Common::Error loadGameState(int slot);
+ virtual Common::Error saveGameState(int slot, const Common::String &desc);
virtual Common::Error run();
uint32 getGameFlags() const;
diff --git a/engines/mortevielle/prog.cpp b/engines/mortevielle/prog.cpp
index 5f2fd3cb65..ba2c4ded91 100644
--- a/engines/mortevielle/prog.cpp
+++ b/engines/mortevielle/prog.cpp
@@ -219,100 +219,6 @@ L2:
mennor();
}
-void sv_game(int n);
-
-void ld_game(int n);
-
-void tecran() {
- const char idem[] = "Idem";
- const int lim = 20000;
- int temps = 0;
- char inkey = '\0';
- bool oo, funct = 0;
-
- clsf3();
- oo = false;
- ctrm = 0;
- if (! iesc) {
- draw_menu();
- imen = true;
- temps = 0;
- key = 0;
- funct = false;
- inkey = '.';
-
- do {
- mdn();
- tinke();
- mov_mouse(funct, inkey);
- CHECK_QUIT;
- temps = temps + 1;
- } while (!((choisi) || (temps > lim) || (funct) || (anyone)));
-
- erase_menu();
- imen = false;
- if ((inkey == '\1') || (inkey == '\3') || (inkey == '\5') || (inkey == '\7') || (inkey == '\11')) {
- change_gd((uint)pred(int, ord(inkey)) >> 1);
- return;
- }
- if (choisi && (msg[3] == sauve))
- sv_game(msg[4] & 7);
- if (choisi && (msg[3] == charge))
- ld_game((msg[4] & 7) - 1);
- if (inkey == '\103') { /* F9 */
- temps = do_alert(stpou, 1);
- return;
- } else if (inkey == '\77') {
- if ((mnumo != no_choice) && ((msg[3] == action) || (msg[3] == saction))) {
- msg[4] = mnumo;
- ecr3(idem);
- } else return;
- } else if (inkey == '\104') {
- if ((x != 0) && (y != 0)) num = 9999;
- return;
- }
- }
- if (inkey == '\73') {
- arret = true;
- tmaj3();
- } else {
- if ((funct) && (inkey != '\77')) return;
- if (temps > lim) {
- repon(2, 141);
- if (num == 9999) num = 0;
- } else {
- mnumo = msg[3];
- if ((msg[3] == action) || (msg[3] == saction)) mnumo = msg[4];
- if (! anyone) {
- if ((fouil) || (obpart)) {
- if (y_s < 12) return;
- if ((msg[4] == sonder) || (msg[4] == soulever)) {
- oo = true;
- if ((msg[4] == soulever) || (obpart)) {
- finfouil();
- caff = s.mlieu;
- crep = 998;
- } else tsuiv();
- mennor();
- }
- }
- }
- do {
- if (! oo) tsitu();
- if ((ctrm == 0) && (! perdu) && (! solu)) {
- taffich();
- if (okdes) {
- okdes = false;
- dessin(0);
- }
- if ((! syn) || (col)) repon(2, crep);
- }
- } while (!(! syn));
- if (ctrm != 0) tctrm();
- }
- }
-}
-
/* NIVEAU 1 */
void theure() {
@@ -326,15 +232,4 @@ void theure() {
else min = 0;
}
-
-void tjouer() {
- antegame();
- do {
- tecran();
- CHECK_QUIT;
- } while (!((arret) || (solu) || (perdu)));
- if (solu) tmaj1();
- else if (perdu) tencore();
-}
-
} // End of namespace Mortevielle
diff --git a/engines/mortevielle/prog.h b/engines/mortevielle/prog.h
index fbcd92f469..f51b2214b7 100644
--- a/engines/mortevielle/prog.h
+++ b/engines/mortevielle/prog.h
@@ -37,11 +37,9 @@ extern void antegame();
/* procedure PROGRAMME */
extern void tmaj3();
extern void tsitu();
-extern void tecran();
/* NIVEAU 1 */
extern void theure();
-extern void tjouer();
} // End of namespace Mortevielle
#endif
diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp
new file mode 100644
index 0000000000..d0cd603845
--- /dev/null
+++ b/engines/mortevielle/saveload.cpp
@@ -0,0 +1,318 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+/*
+ * This code is based on original Mortville Manor DOS source code
+ * Copyright (c) 1988-1989 Lankhor
+ */
+
+#include "common/file.h"
+#include "common/system.h"
+#include "mortevielle/alert.h"
+#include "mortevielle/mor.h"
+#include "mortevielle/mor2.h"
+#include "mortevielle/mortevielle.h"
+#include "mortevielle/mouse.h"
+#include "mortevielle/ovd1.h"
+#include "mortevielle/prog.h"
+#include "mortevielle/saveload.h"
+#include "mortevielle/var_mor.h"
+
+namespace Mortevielle {
+
+static const char SAVEGAME_ID[4] = { 'M', 'O', 'R', 'T' };
+
+Common::String SavegameManager::generateSaveName(int slotNumber) {
+ return Common::String::format("sav%d.mor", slotNumber);
+}
+
+/**
+ * Handle saving or loading savegame data
+ */
+void SavegameManager::sync_save(Common::Serializer &sz) {
+ sz.syncAsSint16LE(s1.conf);
+ sz.syncBytes((byte *)&s1.pourc[0], 11);
+ sz.syncBytes((byte *)&s1.teauto[0], 43);
+ sz.syncBytes((byte *)&s1.sjer[0], 31);
+ sz.syncAsSint16LE(s1.mlieu);
+ sz.syncAsSint16LE(s1.iboul);
+ sz.syncAsSint16LE(s1.ibag);
+ sz.syncAsSint16LE(s1.icave);
+ sz.syncAsSint16LE(s1.ivier);
+ sz.syncAsSint16LE(s1.ipuit);
+ sz.syncAsSint16LE(s1.derobj);
+ sz.syncAsSint16LE(s1.iloic);
+ sz.syncAsSint16LE(s1.icryp);
+ sz.syncAsByte(s1.ipre);
+ sz.syncAsByte(s1.heure);
+
+ sz.syncBytes(bufcha, 391);
+}
+
+/**
+ * Inner code for loading a saved game
+ */
+void SavegameManager::takesav(int n) {
+ int i;
+ Common::String st;
+
+ // -- Load the file
+ Common::String filename = generateSaveName(n);
+
+ // Try loading first from the save area
+ Common::SeekableReadStream *stream = g_system->getSavefileManager()->openForLoading(filename);
+
+ // If not present, try loading from the program folder
+ Common::File f;
+ if (stream == NULL) {
+ if (!f.open(filename))
+ error("Unable to open save file '%s'", filename);
+
+ stream = f.readStream(f.size());
+ f.close();
+ }
+
+ // Check whether it's a ScummVM saved game
+ char buffer[4];
+ stream->read(buffer, 4);
+ if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) {
+ // Yes, it is, so skip over the savegame header
+ SavegameHeader header;
+ readSavegameHeader(stream, header);
+ delete header.thumbnail;
+ } else {
+ stream->seek(0);
+ }
+
+ // Read the game contents
+ Common::Serializer sz(stream, NULL);
+ sync_save(sz);
+
+ s = s1;
+ for (i = 0; i <= 389; i ++) tabdon[i + acha] = bufcha[i];
+
+ // Close the stream
+ delete stream;
+}
+
+/**
+ * Load a saved game
+ */
+Common::Error SavegameManager::loadGame(int n) {
+ hide_mouse();
+ maivid();
+ takesav(n);
+
+ /* Initialization */
+ theure();
+ dprog();
+ antegame();
+ show_mouse();
+ return Common::kNoError;
+}
+
+/**
+ * Save the game
+ */
+Common::Error SavegameManager::saveGame(int n, const Common::String &saveName) {
+ Common::OutSaveFile *f;
+ int i;
+
+ hide_mouse();
+ tmaj3();
+
+ for (i = 0; i <= 389; i ++)
+ bufcha[i] = tabdon[i + acha];
+ s1 = s;
+ if (s1.mlieu == 26)
+ s1.mlieu = 15;
+
+ Common::String filename = generateSaveName(n);
+ f = g_system->getSavefileManager()->openForSaving(filename);
+
+ // Write out the savegame header
+ f->write(&SAVEGAME_ID[0], 4);
+
+ // Write out the header
+ SavegameHeader header;
+ writeSavegameHeader(f, saveName);
+
+ // Write out the savegame contents
+ Common::Serializer sz(NULL, f);
+ sync_save(sz);
+
+ // Close the save file
+ f->finalize();
+ delete f;
+
+ dem2();
+ show_mouse();
+ return Common::kNoError;
+}
+
+void SavegameManager::writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName) {
+ // Write out a savegame header
+ out->writeByte(SAVEGAME_VERSION);
+
+ // Write savegame name
+ out->writeString(saveName);
+ out->writeByte(0);
+
+ // Get the active palette
+ uint8 thumbPalette[256 * 3];
+ g_system->getPaletteManager()->grabPalette(thumbPalette, 0, 256);
+
+ // Create a thumbnail and save it
+ Graphics::Surface *thumb = new Graphics::Surface();
+ Graphics::Surface s = g_vm->_screenSurface.lockArea(Common::Rect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT));
+
+ ::createThumbnail(thumb, (const byte *)s.pixels, SCREEN_WIDTH, SCREEN_HEIGHT, thumbPalette);
+ Graphics::saveThumbnail(*out, *thumb);
+ thumb->free();
+ delete thumb;
+
+ // Write out the save date/time
+ TimeDate td;
+ g_system->getTimeAndDate(td);
+ out->writeSint16LE(td.tm_year + 1900);
+ out->writeSint16LE(td.tm_mon + 1);
+ out->writeSint16LE(td.tm_mday);
+ out->writeSint16LE(td.tm_hour);
+ out->writeSint16LE(td.tm_min);
+}
+
+bool SavegameManager::readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header) {
+ header.thumbnail = NULL;
+
+ // Get the savegame version
+ header.version = in->readByte();
+
+ // Read in the save name
+ header.saveName.clear();
+ char ch;
+ while ((ch = (char)in->readByte()) != '\0')
+ header.saveName += ch;
+
+ // Get the thumbnail
+ header.thumbnail = Graphics::loadThumbnail(*in);
+ if (!header.thumbnail)
+ return false;
+
+ // Read in save date/time
+ header.saveYear = in->readSint16LE();
+ header.saveMonth = in->readSint16LE();
+ header.saveDay = in->readSint16LE();
+ header.saveHour = in->readSint16LE();
+ header.saveMinutes = in->readSint16LE();
+
+ return true;
+}
+
+SaveStateList SavegameManager::listSaves(const char *target) {
+ Common::String pattern = "sav*.mor";
+ Common::StringArray files = g_system->getSavefileManager()->listSavefiles(pattern);
+ sort(files.begin(), files.end()); // Sort (hopefully ensuring we are sorted numerically..)
+
+ SaveStateList saveList;
+ for (Common::StringArray::const_iterator file = files.begin(); file != files.end(); ++file) {
+ // Obtain the last 3 digits of the filename, since they correspond to the save slot
+ const Common::String &fname = *file;
+ int slotNumber = atoi(fname.c_str() + 3);
+
+ Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fname);
+ if (in) {
+ // There can be two types of savegames: original interpreter savegames, and ScummVM savegames.
+ // Original interpreter savegames are 497 bytes, and still need to be supported because the
+ // initial game state is stored as a savegame
+ bool validFlag = false;
+ Common::String saveDescription;
+
+ char buffer[4];
+ in->read(buffer, 4);
+ if (!strncmp(&buffer[0], &SAVEGAME_ID[0], 4)) {
+ // ScummVm savegame. Read in the header to get the savegame name
+ SavegameHeader header;
+ validFlag = readSavegameHeader(in, header);
+
+ if (validFlag) {
+ delete header.thumbnail;
+ saveDescription = header.saveName;
+ }
+ } else if (file->size() == 497) {
+ // Form an appropriate savegame name
+ saveDescription = (slotNumber == 0) ? "Initial game state" :
+ Common::String::format("Savegame #%d", slotNumber);
+ validFlag = true;
+ }
+
+ if (validFlag)
+ // Got a valid savegame
+ saveList.push_back(SaveStateDescriptor(slotNumber, saveDescription));
+
+ delete in;
+ }
+ }
+
+ return saveList;
+}
+
+SaveStateDescriptor SavegameManager::querySaveMetaInfos(int slot) {
+ Common::String fileName = Mortevielle::SavegameManager::generateSaveName(slot);
+ Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName);
+
+ if (f) {
+ // Check to see if it's a ScummVM savegame or not
+ char buffer[4];
+ f->read(buffer, 4);
+
+ bool hasHeader = !strncmp(&buffer[0], &SAVEGAME_ID[0], 4);
+
+ if (!hasHeader) {
+ // Original savegame perhaps?
+ delete f;
+
+ SaveStateDescriptor desc(slot, Common::String::format("Savegame #%d", slot));
+ desc.setDeletableFlag(slot != 0);
+ desc.setWriteProtectedFlag(slot == 0);
+ return desc;
+ } else {
+ // Get the savegame header information
+ SavegameHeader header;
+ readSavegameHeader(f, header);
+ delete f;
+
+ // Create the return descriptor
+ SaveStateDescriptor desc(slot, header.saveName);
+ desc.setDeletableFlag(true);
+ desc.setWriteProtectedFlag(false);
+ desc.setThumbnail(header.thumbnail);
+ desc.setSaveDate(header.saveYear, header.saveMonth, header.saveDay);
+ desc.setSaveTime(header.saveHour, header.saveMinutes);
+
+ return desc;
+ }
+ }
+
+ return SaveStateDescriptor();
+}
+
+} // End of namespace Mortevielle
diff --git a/engines/mortevielle/disk.h b/engines/mortevielle/saveload.h
index 06df8e029a..7f2edd8b53 100644
--- a/engines/mortevielle/disk.h
+++ b/engines/mortevielle/saveload.h
@@ -25,15 +25,42 @@
* Copyright (c) 1988-1989 Lankhor
*/
-#ifndef MORTEVIELLE_DISK_H
-#define MORTEVIELLE_DISK_H
+#ifndef MORTEVIELLE_SAVELOAD_H
+#define MORTEVIELLE_SAVELOAD_H
+
+#include "common/savefile.h"
+#include "common/serializer.h"
+#include "graphics/palette.h"
+#include "graphics/scaler.h"
+#include "graphics/thumbnail.h"
+
+#define SAVEGAME_VERSION 1
namespace Mortevielle {
-extern void dem1();
-extern void takesav(int n);
-extern void ld_game(int n);
-extern void sv_game(int n);
+struct SavegameHeader {
+ uint8 version;
+ Common::String saveName;
+ Graphics::Surface *thumbnail;
+ int saveYear, saveMonth, saveDay;
+ int saveHour, saveMinutes;
+ int totalFrames;
+};
+
+class SavegameManager {
+private:
+ void sync_save(Common::Serializer &sz);
+public:
+ void takesav(int n);
+ Common::Error loadGame(int n);
+ Common::Error saveGame(int n, const Common::String &saveName);
+
+ static void writeSavegameHeader(Common::OutSaveFile *out, const Common::String &saveName);
+ static bool readSavegameHeader(Common::InSaveFile *in, SavegameHeader &header);
+ static Common::String generateSaveName(int slotNumber);
+ static SaveStateList listSaves(const char *target);
+ static SaveStateDescriptor querySaveMetaInfos(int slot);
+};
} // End of namespace Mortevielle
#endif