Common::Error SciEngine::saveGameState(int slot, const Common::String &desc) { Common::String fileName = Common::String::format("%s.%03d", _targetName.c_str(), slot); Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::OutSaveFile *out = saveFileMan->openForSaving(fileName); const char *version = ""; if (!out) { warning("Opening savegame \"%s\" for writing failed", fileName.c_str()); return Common::kWritingFailed; } if (!gamestate_save(_gamestate, out, desc, version)) { warning("Saving the game state to '%s' failed", fileName.c_str()); return Common::kWritingFailed; } else { out->finalize(); if (out->err()) { warning("Writing the savegame failed"); return Common::kWritingFailed; } delete out; } return Common::kNoError; }
reg_t kSaveGame(EngineState *s, int argc, reg_t *argv) { Common::String game_id; int16 virtualId = argv[1].toSint16(); int16 savegameId = -1; Common::String game_description; Common::String version; if (argc > 3) version = s->_segMan->getString(argv[3]); // We check here, we don't want to delete a users save in case we are within a kernel function if (s->executionStackBase) { warning("kSaveGame - won't save from within kernel function"); return NULL_REG; } if (argv[0].isNull()) { // Direct call, from a patched Game::save if ((argv[1] != SIGNAL_REG) || (!argv[2].isNull())) error("kSaveGame: assumed patched call isn't accurate"); // we are supposed to show a dialog for the user and let him choose where to save g_sci->_soundCmd->pauseAll(true); // pause music GUI::SaveLoadChooser *dialog = new GUI::SaveLoadChooser(_("Save game:"), _("Save"), true); savegameId = dialog->runModalWithCurrentTarget(); game_description = dialog->getResultString(); if (game_description.empty()) { // create our own description for the saved game, the user didnt enter it game_description = dialog->createDefaultSaveDescription(savegameId); } delete dialog; g_sci->_soundCmd->pauseAll(false); // unpause music ( we can't have it paused during save) if (savegameId < 0) return NULL_REG; } else { // Real call from script game_id = s->_segMan->getString(argv[0]); if (argv[2].isNull()) error("kSaveGame: called with description being NULL"); game_description = s->_segMan->getString(argv[2]); debug(3, "kSaveGame(%s,%d,%s,%s)", game_id.c_str(), virtualId, game_description.c_str(), version.c_str()); Common::Array<SavegameDesc> saves; listSavegames(saves); if ((virtualId >= SAVEGAMEID_OFFICIALRANGE_START) && (virtualId <= SAVEGAMEID_OFFICIALRANGE_END)) { // savegameId is an actual Id, so search for it just to make sure savegameId = virtualId - SAVEGAMEID_OFFICIALRANGE_START; if (findSavegame(saves, savegameId) == -1) return NULL_REG; } else if (virtualId < SAVEGAMEID_OFFICIALRANGE_START) { // virtualId is low, we assume that scripts expect us to create new slot if (virtualId == s->_lastSaveVirtualId) { // if last virtual id is the same as this one, we assume that caller wants to overwrite last save savegameId = s->_lastSaveNewId; } else { uint savegameNr; // savegameId is in lower range, scripts expect us to create a new slot for (savegameId = 0; savegameId < SAVEGAMEID_OFFICIALRANGE_START; savegameId++) { for (savegameNr = 0; savegameNr < saves.size(); savegameNr++) { if (savegameId == saves[savegameNr].id) break; } if (savegameNr == saves.size()) break; } if (savegameId == SAVEGAMEID_OFFICIALRANGE_START) error("kSavegame: no more savegame slots available"); } } else { error("kSaveGame: invalid savegameId used"); } // Save in case caller wants to overwrite last newly created save s->_lastSaveVirtualId = virtualId; s->_lastSaveNewId = savegameId; } s->r_acc = NULL_REG; Common::String filename = g_sci->getSavegameName(savegameId); Common::SaveFileManager *saveFileMan = g_sci->getSaveFileManager(); Common::OutSaveFile *out; out = saveFileMan->openForSaving(filename); if (!out) { warning("Error opening savegame \"%s\" for writing", filename.c_str()); } else { if (!gamestate_save(s, out, game_description, version)) { warning("Saving the game failed"); } else { s->r_acc = TRUE_REG; // save successful } out->finalize(); if (out->err()) { warning("Writing the savegame failed"); s->r_acc = NULL_REG; // write failure } delete out; } return s->r_acc; }
reg_t kSaveGame(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(); int savedir_id; // Savegame ID, derived from savedir_nr and the savegame ID list char *game_description = kernel_dereference_char_pointer(s, argv[2], 0); char *version = argc > 3 ? strdup(kernel_dereference_char_pointer(s, argv[3], 0)) : NULL; debug(3, "kSaveGame(%s,%d,%s,%s)", game_id, savedir_nr, game_description, version); s->game_version = version; Common::Array<SavegameDesc> saves; listSavegames(saves); fprintf(stderr, "savedir_nr = %d\n", savedir_nr); if (savedir_nr >= 0 && (uint)savedir_nr < saves.size()) { // Overwrite savedir_id = saves[savedir_nr].id; } else if (savedir_nr >= 0 && savedir_nr < MAX_SAVEGAME_NR) { uint i = 0; fprintf(stderr, "searching for hole\n"); savedir_id = 0; // First, look for holes while (i < saves.size()) { if (saves[i].id == savedir_id) { ++savedir_id; i = 0; } else ++i; } if (savedir_id >= MAX_SAVEGAME_NR) { warning("Internal error: Free savegame ID is %d, shouldn't happen", savedir_id); return NULL_REG; } // This loop terminates when savedir_id is not in [x | ex. n. saves [n].id = x] } else { warning("Savegame ID %d is not allowed", savedir_nr); return NULL_REG; } Common::String filename = ((Sci::SciEngine*)g_engine)->getSavegameName(savedir_id); Common::SaveFileManager *saveFileMan = g_engine->getSaveFileManager(); Common::OutSaveFile *out; if (!(out = saveFileMan->openForSaving(filename))) { warning("Error opening savegame \"%s\" for writing", filename.c_str()); s->r_acc = NULL_REG; return NULL_REG; } if (gamestate_save(s, out, game_description)) { warning("Saving the game failed."); s->r_acc = NULL_REG; } else { out->finalize(); if (out->err()) { delete out; warning("Writing the savegame failed."); s->r_acc = NULL_REG; } else { delete out; s->r_acc = make_reg(0, 1); } } free(s->game_version); s->game_version = NULL; return s->r_acc; }