MORTEVIELLE: Implemented ScummVM savegame functionality with metadata

This commit is contained in:
Paul Gilbert 2012-02-12 12:34:51 +11:00 committed by Strangerke
parent 80302552e8
commit bae25fc2aa
9 changed files with 563 additions and 277 deletions

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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