SaveStateDescriptor SwordMetaEngine::querySaveMetaInfos(const char *target, int slot) const { Common::String fileName = Common::String::format("sword1.%03d", slot); char name[40]; uint32 playTime = 0; byte versionSave; Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(fileName); if (in) { in->skip(4); // header in->read(name, sizeof(name)); in->read(&versionSave, 1); // version SaveStateDescriptor desc(slot, name); if (versionSave < 2) // These older version of the savegames used a flag to signal presence of thumbnail in->skip(1); if (Graphics::checkThumbnailHeader(*in)) { Graphics::Surface *thumbnail; if (!Graphics::loadThumbnail(*in, thumbnail)) { delete in; return SaveStateDescriptor(); } desc.setThumbnail(thumbnail); } uint32 saveDate = in->readUint32BE(); uint16 saveTime = in->readUint16BE(); if (versionSave > 1) // Previous versions did not have playtime data playTime = in->readUint32BE(); int day = (saveDate >> 24) & 0xFF; int month = (saveDate >> 16) & 0xFF; int year = saveDate & 0xFFFF; desc.setSaveDate(year, month, day); int hour = (saveTime >> 8) & 0xFF; int minutes = saveTime & 0xFF; desc.setSaveTime(hour, minutes); if (versionSave > 1) { desc.setPlayTime(playTime * 1000); } else { //We have no playtime data desc.setPlayTime(0); } delete in; return desc; } return SaveStateDescriptor(); }
static byte *readSavegameThumbnail(const Common::String &filename, uint &fileSize, bool &isPNG) { byte *pFileData; Common::SaveFileManager *sfm = g_system->getSavefileManager(); Common::InSaveFile *file = sfm->openForLoading(lastPathComponent(filename, '/')); if (!file) error("Save file \"%s\" could not be loaded.", filename.c_str()); // Seek to the actual PNG image loadString(*file); // Marker (BS25SAVEGAME) Common::String storedVersionID = loadString(*file); // Version if (storedVersionID != "SCUMMVM1") loadString(*file); loadString(*file); // Description uint32 compressedGamedataSize = atoi(loadString(*file).c_str()); loadString(*file); // Uncompressed game data size file->skip(compressedGamedataSize); // Skip the game data and move to the thumbnail itself uint32 thumbnailStart = file->pos(); fileSize = file->size() - thumbnailStart; // Check if the thumbnail is in our own format, or a PNG file. uint32 header = file->readUint32BE(); isPNG = (header != MKTAG('S','C','R','N')); file->seek(-4, SEEK_CUR); pFileData = new byte[fileSize]; file->read(pFileData, fileSize); delete file; return pFileData; }
SaveStateDescriptor DreamWebMetaEngine::querySaveMetaInfos(const char *target, int slot) const { Common::String filename = Common::String::format("DREAMWEB.D%02d", slot); Common::InSaveFile *in = g_system->getSavefileManager()->openForLoading(filename.c_str()); if (in) { DreamWeb::FileHeader header; in->read((uint8 *)&header, sizeof(DreamWeb::FileHeader)); Common::String saveName; byte descSize = header.len(0); byte i; for (i = 0; i < descSize; i++) saveName += (char)in->readByte(); SaveStateDescriptor desc(slot, saveName); // Check if there is a ScummVM data block if (header.len(6) == SCUMMVM_BLOCK_MAGIC_SIZE) { // Skip the game data for (i = 1; i <= 5; i++) in->skip(header.len(i)); uint32 tag = in->readUint32BE(); if (tag != SCUMMVM_HEADER) { warning("ScummVM data block found, but the block header is incorrect - skipping"); delete in; return desc; } byte version = in->readByte(); if (version > SAVEGAME_VERSION) { warning("ScummVM data block found, but it has been saved with a newer version of ScummVM - skipping"); delete in; return desc; } uint32 saveDate = in->readUint32LE(); uint32 saveTime = in->readUint32LE(); uint32 playTime = in->readUint32LE(); Graphics::Surface *thumbnail = Graphics::loadThumbnail(*in); int day = (saveDate >> 24) & 0xFF; int month = (saveDate >> 16) & 0xFF; int year = saveDate & 0xFFFF; int hour = (saveTime >> 16) & 0xFF; int minutes = (saveTime >> 8) & 0xFF; desc.setSaveDate(year, month, day); desc.setSaveTime(hour, minutes); desc.setPlayTime(playTime * 1000); desc.setThumbnail(thumbnail); } delete in; return desc; } return SaveStateDescriptor(); }
Common::Error ToucheEngine::loadGameState(int num) { bool loadOk = false; Common::String gameStateFileName = generateGameStateFileName(_targetName.c_str(), num); Common::InSaveFile *f = _saveFileMan->openForLoading(gameStateFileName); if (f) { uint16 version = f->readUint16LE(); if (version < kCurrentGameStateVersion) { warning("Unsupported gamestate version %d (index %d)", version, num); } else { f->skip(2 + kGameStateDescriptionLen); loadGameStateData(f); if (f->err() || f->eos()) { warning("Can't read file '%s'", gameStateFileName.c_str()); } else { loadOk = true; } } delete f; } return loadOk ? Common::kNoError : Common::kUnknownError; }
int16 GameDatabaseV3::loadgame(const char *filename, int16 version) { Common::InSaveFile *in; uint32 expectedSize = 4 + 4 + 2 + _gameStateSize; if (!(in = g_system->getSavefileManager()->openForLoading(filename))) { warning("Can't open file '%s', game not loaded", filename); return 1; } uint32 header = in->readUint32BE(); if (header != MKTAG('S','G','A','M')) { warning("Save game header missing"); delete in; return 1; } uint32 size = in->readUint32LE(); int16 saveVersion = in->readUint16LE(); if (saveVersion != version) { warning("Save game %s was saved with a different version of the game. Game version is %d, save version is %d", filename, version, saveVersion); delete in; return 1; } if (size != expectedSize) { warning("Unexpected save game size. Expected %d, size is %d", expectedSize, size); delete in; return 1; } in->skip(64); // skip savegame description in->read(_gameState, _gameStateSize); delete in; _objectPropertyCache.clear(); // make sure to clear cache return 0; }
/** * Restore game from supplied slot number */ bool FileManager::restoreGame(const int16 slot) { debugC(1, kDebugFile, "restoreGame(%d)", slot); int16 savegameId; if (slot == -1) { GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser("Restore game:", "Restore", false); savegameId = dialog->runModalWithCurrentTarget(); delete dialog; } else { savegameId = slot; } if (savegameId < 0) // dialog aborted return false; Common::String savegameFile = _vm->getSavegameFilename(savegameId); Common::SaveFileManager *saveMan = g_system->getSavefileManager(); Common::InSaveFile *in = saveMan->openForLoading(savegameFile); if (!in) return false; // Initialize new-game status _vm->initStatus(); // Check version, can't restore from different versions int saveVersion = in->readByte(); if (saveVersion != kSavegameVersion) { warning("Savegame of incompatible version"); delete in; return false; } // Skip over description int32 saveGameNameSize = in->readSint16BE(); in->skip(saveGameNameSize); Graphics::skipThumbnail(*in); in->skip(6); // Skip date & time // If hero image is currently swapped, swap it back before restore if (_vm->_heroImage != kHeroIndex) _vm->_object->swapImages(kHeroIndex, _vm->_heroImage); _vm->_object->restoreObjects(in); _vm->_heroImage = in->readByte(); // If hero swapped in saved game, swap it byte heroImg = _vm->_heroImage; if (heroImg != kHeroIndex) _vm->_object->swapImages(kHeroIndex, _vm->_heroImage); _vm->_heroImage = heroImg; Status &gameStatus = _vm->getGameStatus(); int score = in->readSint16BE(); _vm->setScore(score); gameStatus._storyModeFl = (in->readByte() == 1); _vm->_mouse->setJumpExitFl(in->readByte() == 1); gameStatus._gameOverFl = (in->readByte() == 1); for (int i = 0; i < _vm->_numStates; i++) _vm->_screenStates[i] = in->readByte(); _vm->_scheduler->restoreSchedulerData(in); // Restore palette and change it if necessary _vm->_screen->restorePal(in); // Restore maze status _vm->_maze._enabledFl = (in->readByte() == 1); _vm->_maze._size = in->readByte(); _vm->_maze._x1 = in->readSint16BE(); _vm->_maze._y1 = in->readSint16BE(); _vm->_maze._x2 = in->readSint16BE(); _vm->_maze._y2 = in->readSint16BE(); _vm->_maze._x3 = in->readSint16BE(); _vm->_maze._x4 = in->readSint16BE(); _vm->_maze._firstScreenIndex = in->readByte(); _vm->_scheduler->restoreScreen(*_vm->_screenPtr); if ((_vm->getGameStatus()._viewState = (Vstate) in->readByte()) != kViewPlay) _vm->_screen->hideCursor(); delete in; return true; }
void SagaEngine::load(const char *fileName) { Common::InSaveFile *in; int commonBufferSize; int sceneNumber, insetSceneNumber; int mapx, mapy; char title[TITLESIZE]; if (!(in = _saveFileMan->openForLoading(fileName))) { return; } _saveHeader.type = in->readUint32BE(); _saveHeader.size = in->readUint32LE(); _saveHeader.version = in->readUint32LE(); in->read(_saveHeader.name, sizeof(_saveHeader.name)); // Some older saves were not written in an endian safe fashion. // We try to detect this here by checking for extremly high version values. // If found, we retry with the data swapped. if (_saveHeader.version > 0xFFFFFF) { warning("This savegame is not endian safe, retrying with the data swapped"); _saveHeader.version = SWAP_BYTES_32(_saveHeader.version); } debug(2, "Save version: 0x%X", _saveHeader.version); if (_saveHeader.version < 4) warning("This savegame is not endian-safe. There may be problems"); if (_saveHeader.type != MKTAG('S','A','G','A')) { error("SagaEngine::load wrong save game format"); } if (_saveHeader.version > 4) { in->read(title, TITLESIZE); debug(0, "Save is for: %s", title); } if (_saveHeader.version >= 6) { // We don't need the thumbnail here, so just read it and discard it Graphics::skipThumbnail(*in); in->readUint32BE(); // save date in->readUint16BE(); // save time if (_saveHeader.version >= 8) { uint32 playTime = in->readUint32BE(); g_engine->setTotalPlayTime(playTime * 1000); } } // Clear pending events here, and don't process queued music events _events->clearList(false); // Surrounding scene sceneNumber = in->readSint32LE(); #ifdef ENABLE_IHNM if (getGameId() == GID_IHNM) { int currentChapter = _scene->currentChapterNumber(); _scene->setChapterNumber(in->readSint32LE()); in->skip(4); // obsolete, was used for setting the protagonist if (_scene->currentChapterNumber() != currentChapter) _scene->changeScene(-2, 0, kTransitionFade, _scene->currentChapterNumber()); _scene->setCurrentMusicTrack(in->readSint32LE()); _scene->setCurrentMusicRepeat(in->readSint32LE()); _music->stop(); if (_scene->currentChapterNumber() == 8) _interface->setMode(kPanelChapterSelection); if (!isIHNMDemo()) { _music->play(_music->_songTable[_scene->getCurrentMusicTrack()], _scene->getCurrentMusicRepeat() ? MUSIC_LOOP : MUSIC_NORMAL); } else { _music->play(3, MUSIC_LOOP); } } #endif // Inset scene insetSceneNumber = in->readSint32LE(); #ifdef ENABLE_IHNM if (getGameId() == GID_IHNM) { _globalFlags = in->readUint32LE(); for (int i = 0; i < ARRAYSIZE(_ethicsPoints); i++) _ethicsPoints[i] = in->readSint16LE(); } #endif _interface->loadState(in); _actor->loadState(in); commonBufferSize = in->readSint16LE(); _script->_commonBuffer.resize(commonBufferSize); in->read(_script->_commonBuffer.getBuffer(), commonBufferSize); if (getGameId() == GID_ITE) { mapx = in->readSint16LE(); mapy = in->readSint16LE(); _isoMap->setMapPosition(mapx, mapy); } // Note: the mapx, mapy ISO map positions were incorrectly saved // for IHNM too, which has no ISO map scenes, up to save version 6. // Since they're at the end of the savegame, we just ignore them delete in; // Mute volume to prevent outScene music play int volume = _music->getVolume(); _music->setVolume(0); _scene->clearSceneQueue(); _scene->changeScene(sceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade); _events->handleEvents(0); //dissolve backgrounds if (insetSceneNumber != sceneNumber) { _render->setFlag(RF_DISABLE_ACTORS); _scene->draw(); _render->drawScene(); _render->clearFlag(RF_DISABLE_ACTORS); _scene->changeScene(insetSceneNumber, ACTOR_NO_ENTRANCE, kTransitionNoFade); } _music->setVolume(volume); _interface->draw(); // Abort any scene entry protagonist animations and auto-cue speeches. // Fixes bug #10009. _actor->abortAllSpeeches(); _actor->_protagonist->_location = _actor->_protagonist->_finalTarget; _actor->actorEndWalk(ID_PROTAG, true); }