diff options
author | Strangerke | 2013-07-29 12:02:06 -0700 |
---|---|---|
committer | Strangerke | 2013-07-29 12:02:06 -0700 |
commit | a05e0c697a7545a27d2e390054314613262ebb45 (patch) | |
tree | f1dc8671641482bf05a8ac919c72df75bf4e0053 /engines/mortevielle/saveload.cpp | |
parent | 67af740f3ae63b2f1f1ccf643f7eb51888d6de9b (diff) | |
parent | c7277df1ed0a11c62971a859f101852083debd57 (diff) | |
download | scummvm-rg350-a05e0c697a7545a27d2e390054314613262ebb45.tar.gz scummvm-rg350-a05e0c697a7545a27d2e390054314613262ebb45.tar.bz2 scummvm-rg350-a05e0c697a7545a27d2e390054314613262ebb45.zip |
Merge pull request #347 from Strangerke/mortevielle
New Engine : Mortevielle
Diffstat (limited to 'engines/mortevielle/saveload.cpp')
-rw-r--r-- | engines/mortevielle/saveload.cpp | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp new file mode 100644 index 0000000000..ff3bee5c06 --- /dev/null +++ b/engines/mortevielle/saveload.cpp @@ -0,0 +1,328 @@ +/* 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) 1987-1989 Lankhor + */ + +#include "mortevielle/mortevielle.h" +#include "mortevielle/dialogs.h" +#include "mortevielle/mouse.h" +#include "mortevielle/saveload.h" + +#include "common/file.h" +#include "common/system.h" + +namespace Mortevielle { + +static const char SAVEGAME_ID[4] = { 'M', 'O', 'R', 'T' }; + +void SavegameManager::setParent(MortevielleEngine *vm) { + _vm = vm; +} + +/** + * Handle saving or loading savegame data + */ +void SavegameManager::sync_save(Common::Serializer &sz) { + sz.syncAsSint16LE(g_vm->_saveStruct._faithScore); + for (int i = 0; i < 11; ++i) + sz.syncAsByte(g_vm->_saveStruct._pctHintFound[i]); + for (int i = 0; i < 43; ++i) + sz.syncAsByte(g_vm->_saveStruct._availableQuestion[i]); + for (int i = 0; i < 31; ++i) + sz.syncAsByte(g_vm->_saveStruct._inventory[i]); + + sz.syncAsSint16LE(g_vm->_saveStruct._currPlace); + sz.syncAsSint16LE(g_vm->_saveStruct._atticBallHoleObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._atticRodHoleObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._cellarObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._secretPassageObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._wellObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._selectedObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._purpleRoomObjectId); + sz.syncAsSint16LE(g_vm->_saveStruct._cryptObjectId); + sz.syncAsByte(g_vm->_saveStruct._alreadyEnteredManor); + sz.syncAsByte(g_vm->_saveStruct._fullHour); + + sz.syncBytes(_tabdonSaveBuffer, 391); +} + +/** + * Inner code for loading a saved game + * @remarks Originally called 'takesav' + */ +void SavegameManager::loadSavegame(const Common::String &filename) { + // Try loading first from the save area + Common::SeekableReadStream *stream = g_system->getSavefileManager()->openForLoading(filename); + + Common::File f; + if (stream == NULL) { + if (!f.open(filename)) + error("Unable to open save file '%s'", filename.c_str()); + + 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); + + g_vm->_coreVar = g_vm->_saveStruct; + for (int i = 0; i <= 389; ++i) + g_vm->_tabdon[i + kAcha] = _tabdonSaveBuffer[i]; + + // Close the stream + delete stream; +} + +/** + * Load a saved game + */ +Common::Error SavegameManager::loadGame(const Common::String &filename) { + g_vm->_mouse.hideMouse(); + g_vm->displayEmptyHand(); + loadSavegame(filename); + + /* Initialization */ + g_vm->charToHour(); + g_vm->initGame(); + g_vm->gameLoaded(); + g_vm->_mouse.showMouse(); + return Common::kNoError; +} + +/** + * Save the game + */ +Common::Error SavegameManager::saveGame(int n, const Common::String &saveName) { + Common::OutSaveFile *f; + int i; + + g_vm->_mouse.hideMouse(); + g_vm->hourToChar(); + + for (i = 0; i <= 389; ++i) + _tabdonSaveBuffer[i] = g_vm->_tabdon[i + kAcha]; + g_vm->_saveStruct = g_vm->_coreVar; + if (g_vm->_saveStruct._currPlace == ROOM26) + g_vm->_saveStruct._currPlace = LANDING; + + Common::String filename = _vm->generateSaveFilename(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; + + // Skipped: dialog asking to swap floppy + + g_vm->_mouse.showMouse(); + return Common::kNoError; +} + +Common::Error SavegameManager::loadGame(int slot) { + return loadGame(_vm->generateSaveFilename(slot)); +} + +Common::Error SavegameManager::saveGame(int slot) { + return saveGame(slot, _vm->generateSaveFilename(slot)); +} + +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 Common::String &target) { + Common::String pattern = target; + pattern += ".???"; + + 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() + fname.size() - 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(const Common::String &fileName) { + Common::InSaveFile *f = g_system->getSavefileManager()->openForLoading(fileName); + + if (f) { + // Get the slot number + int slot = 1; + if (fileName.size() > 4 && fileName[fileName.size() - 4] == '.') + slot = atoi(fileName.c_str() + fileName.size() - 3); + + // 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 - %s", 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 |