From 215af6f3b41a0460be6333aa1a4be50e8033fa63 Mon Sep 17 00:00:00 2001 From: Jordi Vilalta Prat Date: Tue, 13 Jan 2009 23:22:47 +0000 Subject: Reduced savegame code duplication and added savegame format versioning. svn-id: r35855 --- engines/groovie/detection.cpp | 74 +++++-------------- engines/groovie/module.mk | 1 + engines/groovie/saveload.cpp | 168 ++++++++++++++++++++++++++++++++++++++++++ engines/groovie/saveload.h | 51 +++++++++++++ engines/groovie/script.cpp | 67 ++++++----------- 5 files changed, 260 insertions(+), 101 deletions(-) create mode 100644 engines/groovie/saveload.cpp create mode 100644 engines/groovie/saveload.h diff --git a/engines/groovie/detection.cpp b/engines/groovie/detection.cpp index fef63c3c74..e29a387e46 100644 --- a/engines/groovie/detection.cpp +++ b/engines/groovie/detection.cpp @@ -26,6 +26,7 @@ #include "common/savefile.h" #include "groovie/groovie.h" +#include "groovie/saveload.h" namespace Groovie { @@ -200,6 +201,7 @@ public: SaveStateList listSaves(const char *target) const; int getMaximumSaveSlot() const; void removeSaveState(const char *target, int slot) const; + SaveStateDescriptor querySaveMetaInfos(const char *target, int slot) const; }; bool GroovieMetaEngine::createInstance(OSystem *syst, Engine **engine, const Common::ADGameDescription *gd) const { @@ -213,76 +215,38 @@ bool GroovieMetaEngine::hasFeature(MetaEngineFeature f) const { return (f == kSupportsListSaves) || (f == kSupportsLoadingDuringStartup) || - (f == kSupportsDeleteSave); - //(f == kSavesSupportCreationDate) + (f == kSupportsDeleteSave) || + (f == kSavesSupportMetaInfo); } SaveStateList GroovieMetaEngine::listSaves(const char *target) const { - Common::SaveFileManager *sfm = g_system->getSavefileManager(); - SaveStateList list; - - // Get the list of savefiles - Common::String pattern = Common::String(target) + ".00?"; - Common::StringList savefiles = sfm->listSavefiles(pattern.c_str()); - - // Sort the list of filenames - sort(savefiles.begin(), savefiles.end()); - - // Fill the information for the existing savegames - Common::StringList::iterator it = savefiles.begin(); - while (it != savefiles.end()) { - int slot = it->lastChar() - '0'; - if (slot >= 0 && slot <= 9) { - Common::InSaveFile *file = sfm->openForLoading(it->c_str()); - - // Read the savegame description - Common::String description; - unsigned char c = 1; - for (int i = 0; (c != 0) && (i < 15); i++) { - c = file->readByte(); - switch (c) { - case 0: - break; - case 16: // @ - c = ' '; - break; - case 244: // $ - c = 0; - break; - default: - c += 0x30; - } - if (c != 0) { - description += c; - } - } - delete file; - - list.push_back(SaveStateDescriptor(slot, description)); - } - it++; - } - - return list; + return SaveLoad::listValidSaves(target); } int GroovieMetaEngine::getMaximumSaveSlot() const { - return 9; + return SaveLoad::getMaximumSlot(); } void GroovieMetaEngine::removeSaveState(const char *target, int slot) const { - if (slot < 0 || slot > 9) { + if (!SaveLoad::isSlotValid(slot)) { // Invalid slot, do nothing return; } - char extension[6]; - snprintf(extension, sizeof(extension), ".00%01d", slot); + Common::String filename = SaveLoad::getSlotSaveName(target, slot); + g_system->getSavefileManager()->removeSavefile(filename.c_str()); +} - Common::String filename = target; - filename += extension; +SaveStateDescriptor GroovieMetaEngine::querySaveMetaInfos(const char *target, int slot) const { + SaveStateDescriptor desc; - g_system->getSavefileManager()->removeSavefile(filename.c_str()); + Common::InSaveFile *savefile = SaveLoad::openForLoading(target, slot, &desc); + if (savefile) { + // Loaded correctly + delete savefile; + } + + return desc; } } // End of namespace Groovie diff --git a/engines/groovie/module.mk b/engines/groovie/module.mk index d4216d3437..1e89ff66f5 100644 --- a/engines/groovie/module.mk +++ b/engines/groovie/module.mk @@ -13,6 +13,7 @@ MODULE_OBJS := \ player.o \ resource.o \ roq.o \ + saveload.o \ script.o \ vdx.o diff --git a/engines/groovie/saveload.cpp b/engines/groovie/saveload.cpp new file mode 100644 index 0000000000..0d719ed599 --- /dev/null +++ b/engines/groovie/saveload.cpp @@ -0,0 +1,168 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#include "groovie/saveload.h" + +#include "common/system.h" + +#define SUPPORTED_SAVEFILE_VERSION 1 +// 0 - Just script variables, compatible with the original +// 1 - Added one byte with version number at the beginning + +namespace Groovie { + +int SaveLoad::getMaximumSlot() { + return 9; +} + +bool SaveLoad::isSlotValid(int slot) { + return slot >= 0 && slot <= getMaximumSlot(); +} + +Common::String SaveLoad::getSlotSaveName(const Common::String &target, int slot) { + return target + ".00" + ('0' + slot); +} + +SaveStateList SaveLoad::listValidSaves(const Common::String &target) { + SaveStateList list; + + // Get the list of savefiles + Common::String pattern = target + ".00?"; + Common::StringList savefiles = g_system->getSavefileManager()->listSavefiles(pattern.c_str()); + + // Sort the list of filenames + sort(savefiles.begin(), savefiles.end()); + + // Fill the information for the existing savegames + Common::StringList::iterator it = savefiles.begin(); + while (it != savefiles.end()) { + int slot = it->lastChar() - '0'; + SaveStateDescriptor descriptor; + Common::InSaveFile *file = SaveLoad::openForLoading(target, slot, &descriptor); + if (file) { + // It's a valid savefile, save the descriptor + delete file; + list.push_back(descriptor); + } + it++; + } + + return list; +} + +Common::InSaveFile *SaveLoad::openForLoading(const Common::String &target, int slot, SaveStateDescriptor *descriptor) { + // Validate the slot number + if (!isSlotValid(slot)) { + return NULL; + } + + // Open the savefile + Common::String savename = getSlotSaveName(target, slot); + Common::InSaveFile *savefile = g_system->getSavefileManager()->openForLoading(savename.c_str()); + if (!savefile) { + return NULL; + } + + // Read the savefile version + uint8 version; + if (savefile->size() == 1024) { + version = 0; + } else { + version = savefile->readByte(); + } + + // Verify we can read this version + if (version > SUPPORTED_SAVEFILE_VERSION) { + //TODO: show the error about unsupported savefile version + } + + // Save the current position as the start for the engine data + int metaDataSize = savefile->pos(); + + // Fill the SaveStateDescriptor if it was provided + if (descriptor) { + // Initialize the SaveStateDescriptor + descriptor->setVal("save_slot", Common::String('0' + slot)); + descriptor->setDeletableFlag(true); + descriptor->setWriteProtectedFlag(false); + + // TODO: Add extra information + //setSaveDate(int year, int month, int day) + //setSaveTime(int hour, int min) + //setPlayTime(int hours, int minutes) + + // Read the savegame description + Common::String description; + unsigned char c = 1; + for (int i = 0; (c != 0) && (i < 15); i++) { + c = savefile->readByte(); + switch (c) { + case 0: + break; + case 16: // @ + c = ' '; + break; + case 244: // $ + c = 0; + break; + default: + c += 0x30; + } + if (c != 0) { + description += c; + } + } + descriptor->setVal("description", description); + } + + // Return a substream, skipping the metadata + Common::SeekableSubReadStream *sub = new Common::SeekableSubReadStream(savefile, metaDataSize, savefile->size(), true); + + // Move to the beginning of the substream + sub->seek(0, SEEK_SET); + + return sub; +} + +Common::OutSaveFile *SaveLoad::openForSaving(const Common::String &target, int slot) { + // Validate the slot number + if (!isSlotValid(slot)) { + return NULL; + } + + // Open the savefile + Common::String savename = getSlotSaveName(target, slot); + Common::OutSaveFile *savefile = g_system->getSavefileManager()->openForSaving(savename.c_str()); + if (!savefile) { + return NULL; + } + + // Write the savefile version + savefile->writeByte(SUPPORTED_SAVEFILE_VERSION); + + return savefile; +} + +} // End of Groovie namespace diff --git a/engines/groovie/saveload.h b/engines/groovie/saveload.h new file mode 100644 index 0000000000..b2b81cb6db --- /dev/null +++ b/engines/groovie/saveload.h @@ -0,0 +1,51 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +#ifndef GROOVIE_SAVELOAD_H +#define GROOVIE_SAVELOAD_H + +#include "common/savefile.h" +#include "engines/game.h" + +namespace Groovie { + +class SaveLoad { +public: + // Validating slot numbers + static int getMaximumSlot(); + static bool isSlotValid(int slot); + + // Getting information + static Common::String getSlotSaveName(const Common::String &target, int slot); + static SaveStateList listValidSaves(const Common::String &target); + + // Opening savefiles + static Common::InSaveFile *openForLoading(const Common::String &target, int slot, SaveStateDescriptor *descriptor = NULL); + static Common::OutSaveFile *openForSaving(const Common::String &target, int slot); +}; + +} // End of Groovie namespace + +#endif // GROOVIE_SAVELOAD_H diff --git a/engines/groovie/script.cpp b/engines/groovie/script.cpp index d6ae566012..f36298a497 100644 --- a/engines/groovie/script.cpp +++ b/engines/groovie/script.cpp @@ -28,11 +28,11 @@ #include "groovie/script.h" #include "groovie/groovie.h" #include "groovie/cell.h" +#include "groovie/saveload.h" #include "common/config-manager.h" #include "common/endian.h" #include "common/events.h" -#include "common/savefile.h" #define NUM_OPCODES 90 @@ -360,8 +360,7 @@ bool Script::hotspot(Common::Rect rect, uint16 address, uint8 cursor) { } void Script::loadgame(uint slot) { - Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot); - Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str()); + Common::InSaveFile *file = SaveLoad::openForLoading(ConfMan.getActiveDomainName(), slot); // Loading the variables. It is endian safe because they're byte variables file->read(_variables, 0x400); @@ -372,11 +371,13 @@ void Script::loadgame(uint slot) { void Script::savegame(uint slot) { char save[15]; char newchar; - Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slot); - Common::OutSaveFile *file = _vm->_system->getSavefileManager()->openForSaving(filename.c_str()); + Common::OutSaveFile *file = SaveLoad::openForSaving(ConfMan.getActiveDomainName(), slot); // Saving the variables. It is endian safe because they're byte variables file->write(_variables, 0x400); + delete file; + + // Cache the saved name for (int i = 0; i < 15; i++) { newchar = _variables[i] + 0x30; if ((newchar < 0x30 || newchar > 0x39) && (newchar < 0x41 || newchar > 0x7A)) { @@ -387,8 +388,6 @@ void Script::savegame(uint slot) { } } _saveNames[slot] = save; - - delete file; } // OPCODES @@ -1217,8 +1216,6 @@ void Script::o_hotspot_slot() { Common::Rect rect(left, top, right, bottom); if (hotspot(rect, address, cursor)) { - char savename[15]; - if (_hotspotSlot == slot) { return; } @@ -1227,8 +1224,7 @@ void Script::o_hotspot_slot() { if (!_font) { _font = new Font(_vm->_system); } - strcpy(savename, _saveNames[slot].c_str()); - _font->printstring(savename); + _font->printstring(_saveNames[slot].c_str()); // Save the currently highlighted slot _hotspotSlot = slot; @@ -1252,54 +1248,33 @@ void Script::o_hotspot_slot() { void Script::o_checkvalidsaves() { debugScript(1, true, "CHECKVALIDSAVES"); - // Reset the array of valid saves + // Reset the array of valid saves and the savegame names cache for (int i = 0; i < 10; i++) { setVariable(i, 0); + _saveNames[i] = "E M P T Y"; } // Get the list of savefiles - Common::String pattern = ConfMan.getActiveDomainName() + ".00?"; - Common::StringList savefiles = _vm->_system->getSavefileManager()->listSavefiles(pattern.c_str()); + SaveStateList list = SaveLoad::listValidSaves(ConfMan.getActiveDomainName()); // Mark the existing savefiles as valid uint count = 0; - Common::StringList::iterator it = savefiles.begin(); - while (it != savefiles.end()) { - int8 n = it->lastChar() - '0'; - if (n >= 0 && n <= 9) { - // TODO: Check the contents of the file? - debugScript(2, true, " Found valid savegame: %s", it->c_str()); - setVariable(n, 1); + SaveStateList::iterator it = list.begin(); + while (it != list.end()) { + int8 slot = it->getVal("save_slot").lastChar() - '0'; + if (SaveLoad::isSlotValid(slot)) { + debugScript(2, true, " Found valid savegame: %s", it->getVal("description").c_str()); + + // Mark this slot as used + setVariable(slot, 1); + + // Cache this slot's description + _saveNames[slot] = it->getVal("description"); count++; } it++; } - for (int slots = 0; slots < 10; slots++) { - char savename[15]; - Common::String filename = ConfMan.getActiveDomainName() + ".00" + ('0' + slots); - Common::StringList files = _vm->_system->getSavefileManager()->listSavefiles(filename.c_str()); - if (!files.empty()) { - Common::InSaveFile *file = _vm->_system->getSavefileManager()->openForLoading(filename.c_str()); - if (file) { - uint8 i; - char temp; - - for (i = 0; i < 15; i++) { - file->read(&temp, 1); - savename[i] = temp + 0x30; - } - - delete file; - } else { - strcpy(savename, "ERROR"); - } - } else { - strcpy(savename, "E M P T Y"); - } - _saveNames[slots] = savename; - } - // Save the number of valid saves setVariable(0x104, count); debugScript(1, true, " Found %d valid savegames", count); -- cgit v1.2.3