Common::Error SciEngine::loadGameState(int slot) { Common::String fileName = Common::String::format("%s.%03d", _targetName.c_str(), slot); Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::SeekableReadStream *in = saveFileMan->openForLoading(fileName); if (in) { // found a savegame file gamestate_restore(_gamestate, in); delete in; } if (_gamestate->r_acc != make_reg(0, 1)) { return Common::kNoError; } else { warning("Restoring gamestate '%s' failed", fileName.c_str()); return Common::kUnknownError; } }
reg_t kRestoreGame(EngineState *s, int funct_nr, int argc, reg_t *argv) { char *game_id = kernel_dereference_char_pointer(s, argv[0], 0); int savedir_nr = argv[1].toUint16(); debug(3, "kRestoreGame(%s,%d)", game_id, savedir_nr); Common::Array<SavegameDesc> saves; listSavegames(saves); savedir_nr = saves[savedir_nr].id; if (savedir_nr > -1) { Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::String filename = ((Sci::SciEngine*)g_engine)->getSavegameName(savedir_nr); Common::SeekableReadStream *in; if ((in = saveFileMan->openForLoading(filename))) { // found a savegame file EngineState *newstate = gamestate_restore(s, in); delete in; if (newstate) { s->successor = newstate; script_abort_flag = 2; // Abort current game with replay shrink_execution_stack(s, s->execution_stack_base + 1); } else { s->r_acc = make_reg(0, 1); warning("Restoring failed (game_id = '%s')", game_id); } return s->r_acc; } } s->r_acc = make_reg(0, 1); warning("Savegame #%d not found", savedir_nr); return s->r_acc; }
reg_t kRestoreGame(EngineState *s, int argc, reg_t *argv) { Common::String game_id = !argv[0].isNull() ? s->_segMan->getString(argv[0]) : ""; int16 savegameId = argv[1].toSint16(); bool pausedMusic = false; debug(3, "kRestoreGame(%s,%d)", game_id.c_str(), savegameId); if (argv[0].isNull()) { // Direct call, either from launcher or from a patched Game::restore if (savegameId == -1) { // we are supposed to show a dialog for the user and let him choose a saved game g_sci->_soundCmd->pauseAll(true); // pause music GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Restore game:"), _("Restore"), false); savegameId = dialog->runModalWithCurrentTarget(); delete dialog; if (savegameId < 0) { g_sci->_soundCmd->pauseAll(false); // unpause music return s->r_acc; } pausedMusic = true; } // don't adjust ID of the saved game, it's already correct } else { if (argv[2].isNull()) error("kRestoreGame: called with parameter 2 being NULL"); // Real call from script, we need to adjust ID if ((savegameId < SAVEGAMEID_OFFICIALRANGE_START) || (savegameId > SAVEGAMEID_OFFICIALRANGE_END)) { warning("Savegame ID %d is not allowed", savegameId); return TRUE_REG; } savegameId -= SAVEGAMEID_OFFICIALRANGE_START; } s->r_acc = NULL_REG; // signals success Common::Array<SavegameDesc> saves; listSavegames(saves); if (findSavegame(saves, savegameId) == -1) { s->r_acc = TRUE_REG; warning("Savegame ID %d not found", savegameId); } else { Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); Common::String filename = g_sci->getSavegameName(savegameId); Common::SeekableReadStream *in; in = saveFileMan->openForLoading(filename); if (in) { // found a savegame file gamestate_restore(s, in); delete in; if (g_sci->getGameId() == GID_MOTHERGOOSE256) { // WORKAROUND: Mother Goose SCI1/SCI1.1 does some weird things for // saving a previously restored game. // We set the current savedgame-id directly and remove the script // code concerning this via script patch. s->variables[VAR_GLOBAL][0xB3].setOffset(SAVEGAMEID_OFFICIALRANGE_START + savegameId); } } else { s->r_acc = TRUE_REG; warning("Savegame #%d not found", savegameId); } } if (!s->r_acc.isNull()) { // no success? if (pausedMusic) g_sci->_soundCmd->pauseAll(false); // unpause music } return s->r_acc; }
bool GuestAdditions::restoreFromLauncher() const { assert(_state->_delayedRestoreGameId != -1); #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { if (_restoring) { // Recursion will occur if a restore fails, as // _delayedRestoreGameId will not be reset so the kernel will try // to keep restoring forever _state->_delayedRestoreGameId = -1; _restoring = false; return false; } // Delayed restore should not happen until after the benchmarking room. // In particular, in SQ6, delayed restore must not happen until room 100 // (the Sierra logo & main menu room), otherwise the game scripts will // try to make calls to the subtitles ScrollWindow, which does not // exist. In other games, restoring early either breaks benchmarking, // or, when trying to load an invalid save game, makes the dialog // telling the user that the game is invalid impossible to read if (strcmp(_segMan->getObjectName(_state->variables[VAR_GLOBAL][kGlobalVarCurrentRoom]), "speedRoom") == 0) { return false; } _restoring = true; if (g_sci->getGameId() == GID_SHIVERS) { // Shivers accepts the save game number as a parameter to // `SHIVERS::restore` reg_t args[] = { make_reg(0, _state->_delayedRestoreGameId - kSaveIdShift) }; invokeSelector(g_sci->getGameObject(), SELECTOR(restore), 1, args); } else { // When `Game::restore` is invoked, it will call to `Restore::doit` // which will automatically return the `_delayedRestoreGameId` instead // of prompting the user for a save game invokeSelector(g_sci->getGameObject(), SELECTOR(restore)); } _restoring = false; return true; } else { #else { #endif int savegameId = _state->_delayedRestoreGameId; // delayedRestoreGameId gets destroyed within gamestate_restore()! Common::String fileName = g_sci->getSavegameName(savegameId); Common::SeekableReadStream *in = g_sci->getSaveFileManager()->openForLoading(fileName); if (in) { // found a savegame file gamestate_restore(_state, in); delete in; if (_state->r_acc != make_reg(0, 1)) { gamestate_afterRestoreFixUp(_state, savegameId); return true; } } error("Restoring gamestate '%s' failed", fileName.c_str()); } } #pragma mark - #pragma mark Message type sync void GuestAdditions::syncMessageTypeFromScummVM() const { switch (_features->getMessageTypeSyncStrategy()) { case kMessageTypeSyncStrategyDefault: syncMessageTypeFromScummVMUsingDefaultStrategy(); break; #ifdef ENABLE_SCI32 case kMessageTypeSyncStrategyShivers: syncMessageTypeFromScummVMUsingShiversStrategy(); break; case kMessageTypeSyncStrategyLSL6Hires: syncMessageTypeFromScummVMUsingLSL6HiresStrategy(); break; #endif case kMessageTypeSyncStrategyNone: break; } } void GuestAdditions::syncMessageTypeFromScummVMUsingDefaultStrategy() const { uint8 value = 0; if (ConfMan.getBool("subtitles")) { value |= kMessageTypeSubtitles; } if (!ConfMan.getBool(("speech_mute"))) { value |= kMessageTypeSpeech; } if (value == kMessageTypeSubtitles + kMessageTypeSpeech && !_features->supportsSpeechWithSubtitles()) { value &= ~kMessageTypeSubtitles; } if (value) { _state->variables[VAR_GLOBAL][kGlobalVarMessageType] = make_reg(0, value); } if (g_sci->getGameId() == GID_GK1) { if (value == kMessageTypeSubtitles) { _state->variables[VAR_GLOBAL][kGlobalVarGK1NarratorMode] = NULL_REG; } else if (value == kMessageTypeSpeech) { _state->variables[VAR_GLOBAL][kGlobalVarGK1NarratorMode] = TRUE_REG; } } }