/* 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. * */ #include "common/scummsys.h" #include "zvision/save_manager.h" #include "zvision/zvision.h" #include "zvision/script_manager.h" #include "zvision/render_manager.h" #include "common/system.h" #include "graphics/surface.h" #include "graphics/thumbnail.h" #include "gui/message.h" namespace ZVision { const uint32 SaveManager::SAVEGAME_ID = MKTAG('Z', 'E', 'N', 'G'); void SaveManager::saveGame(uint slot, const Common::String &saveName) { // The games only support 20 slots assert(slot <= 1 && slot <= 20); Common::SaveFileManager *saveFileManager = g_system->getSavefileManager(); Common::OutSaveFile *file = saveFileManager->openForSaving(_engine->generateSaveFileName(slot)); // Write out the savegame header file->writeUint32BE(SAVEGAME_ID); // Write version file->writeByte(SAVE_VERSION); // Write savegame name file->writeString(saveName); file->writeByte(0); // We can't call writeGameSaveData because the save menu is actually // a room, so writeGameSaveData would save us in the save menu. // However, an auto save is performed before each room change, so we // can copy the data from there. We can guarantee that an auto save file will // exist before this is called because the save menu can only be accessed // after the first room (the main menu) has loaded. Common::InSaveFile *autoSaveFile = saveFileManager->openForLoading(_engine->generateAutoSaveFileName()); // Skip over the header info autoSaveFile->readSint32BE(); // SAVEGAME_ID autoSaveFile->readByte(); // Version autoSaveFile->seek(5, SEEK_CUR); // The string "auto" with terminating NULL // Read the rest to a buffer uint32 size = autoSaveFile->size() - autoSaveFile->pos(); byte *buffer = new byte[size]; autoSaveFile->read(buffer, size); // Then write the buffer to the new file file->write(buffer, size); // Cleanup delete[] buffer; file->finalize(); delete file; } void SaveManager::autoSave() { Common::OutSaveFile *file = g_system->getSavefileManager()->openForSaving(_engine->generateAutoSaveFileName()); // Write out the savegame header file->writeUint32BE(SAVEGAME_ID); // Version file->writeByte(SAVE_VERSION); file->writeString("auto"); file->writeByte(0); writeSaveGameData(file); // Cleanup file->finalize(); delete file; } void SaveManager::writeSaveGameData(Common::OutSaveFile *file) { // Create a thumbnail and save it Graphics::saveThumbnail(*file); // Write out the save date/time TimeDate td; g_system->getTimeAndDate(td); file->writeSint16LE(td.tm_year + 1900); file->writeSint16LE(td.tm_mon + 1); file->writeSint16LE(td.tm_mday); file->writeSint16LE(td.tm_hour); file->writeSint16LE(td.tm_min); ScriptManager *scriptManager = _engine->getScriptManager(); // Write out the current location Location currentLocation = scriptManager->getCurrentLocation(); file->writeByte(currentLocation.world); file->writeByte(currentLocation.room); file->writeByte(currentLocation.node); file->writeByte(currentLocation.view); file->writeUint32LE(currentLocation.offset); // Write out the current state table values scriptManager->serializeStateTable(file); } Common::Error SaveManager::loadGame(uint slot) { // The games only support 20 slots assert(slot <= 1 && slot <= 20); Common::InSaveFile *saveFile = g_system->getSavefileManager()->openForLoading(_engine->generateSaveFileName(slot)); if (saveFile == 0) { return Common::kPathDoesNotExist; } // Read the header SaveGameHeader header; if (!readSaveGameHeader(saveFile, header)) { return Common::kUnknownError; } char world = (char)saveFile->readByte(); char room = (char)saveFile->readByte(); char node = (char)saveFile->readByte(); char view = (char)saveFile->readByte(); uint32 offset = (char)saveFile->readUint32LE(); ScriptManager *scriptManager = _engine->getScriptManager(); // Update the state table values scriptManager->deserializeStateTable(saveFile); // Load the room scriptManager->changeLocation(world, room, node, view, offset); return Common::kNoError; } bool SaveManager::readSaveGameHeader(Common::InSaveFile *in, SaveGameHeader &header) { if (in->readUint32BE() != SAVEGAME_ID) { warning("File is not a ZVision save file. Aborting load"); return false; } // Read in the version header.version = in->readByte(); // Check that the save version isn't newer than this binary if (header.version > SAVE_VERSION) { uint tempVersion = header.version; GUI::MessageDialog dialog(Common::String::format("This save file uses version %u, but this engine only supports up to version %d. You will need an updated version of the engine to use this save file.", tempVersion, SAVE_VERSION), "OK"); dialog.runModal(); } // 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; } } // End of namespace ZVision