/** * \brief __newindex function of the environment of the savegame file. * * This special __newindex function catches declaration of global variables * to store them into the savegame. * * \param l The Lua context that is calling this function. * \return Number of values to return to Lua. */ int Savegame::l_newindex(lua_State* l) { return LuaTools::exception_boundary_handle(l, [&] { lua_getfield(l, LUA_REGISTRYINDEX, "savegame"); Savegame* savegame = static_cast<Savegame*>(lua_touserdata(l, -1)); lua_pop(l, 1); const std::string& key = LuaTools::check_string(l, 2); switch (lua_type(l, 3)) { case LUA_TBOOLEAN: savegame->set_boolean(key, lua_toboolean(l, 3)); break; case LUA_TNUMBER: savegame->set_integer(key, (int) lua_tointeger(l, 3)); break; case LUA_TSTRING: savegame->set_string(key, lua_tostring(l, 3)); break; default: LuaTools::type_error(l, 3, "string, number or boolean"); } return 0; }); }
void Levelset::refresh() { for(std::vector<Level*>::iterator i = levels.begin(); i != levels.end(); ++i) { Savegame* savegame = SavegameManager::instance()->get((*i)->resname); if (savegame) { (*i)->accessible = (savegame->get_status() != Savegame::NONE); (*i)->finished = (savegame->get_status() == Savegame::FINISHED); } } if (!levels.empty()) { levels[0]->accessible = true; for(std::vector<Level*>::size_type i = 0; i < levels.size()-1; ++i) if (levels[i]->finished) levels[i+1]->accessible = true; } completion = 0; for(std::vector<Level*>::iterator i = levels.begin(); i != levels.end(); ++i) if ((*i)->finished) completion += 1; completion = Math::clamp(0, completion * 100 / int(levels.size()), 100); }
void SavegameManager::store(Savegame& arg_savegame) { Savegame* savegame = new Savegame(arg_savegame); SavegameTable::iterator i = find(savegame->get_filename()); if (i == savegames.end()) { // don't know anything about the savegame savegames.push_back(savegame); } else { // already have such a savegame if ((*i)->get_status() == Savegame::FINISHED && savegame->get_status() == Savegame::ACCESSIBLE) { // saved savegame is better then new game delete savegame; } else { // new game is better or equal, save it delete *i; *i = savegame; } } flush(); }
/** * \brief __newindex function of the environment of the savegame file. * * This special __newindex function catches declaration of global variables * to store them into the savegame. * * \param l The Lua context that is calling this function. * \return Number of values to return to Lua. */ int Savegame::l_newindex(lua_State* l) { lua_getfield(l, LUA_REGISTRYINDEX, "savegame"); Savegame* savegame = static_cast<Savegame*>(lua_touserdata(l, -1)); lua_pop(l, 1); const std::string& key = luaL_checkstring(l, 2); switch (lua_type(l, 3)) { case LUA_TBOOLEAN: savegame->set_boolean(key, lua_toboolean(l, 3)); break; case LUA_TNUMBER: savegame->set_integer(key, int(lua_tointeger(l, 3))); break; case LUA_TSTRING: savegame->set_string(key, lua_tostring(l, 3)); break; default: luaL_typerror(l, 3, "string, number or boolean"); } return 0; }
bool LevelDot::finished() { Savegame* savegame = SavegameManager::instance()->get(plf.get_resname()); if (savegame && savegame->get_status() == Savegame::FINISHED) return true; else return false; }
bool LevelDot::accessible() { Savegame* savegame = SavegameManager::instance()->get(plf.get_resname()); if (savegame && savegame->get_status() != Savegame::NONE) return true; else return false; }
SavegameManager::SavegameManager(const std::string& arg_filename) : filename(System::get_userdir() + arg_filename), savegames() { assert(instance_ == 0); instance_ = this; std::shared_ptr<lisp::Lisp> sexpr; try { sexpr = lisp::Parser::parse(filename); } catch (const std::runtime_error& e) { std::cerr << "SavegameManager: " << e.what() << std::endl; return; } if (!sexpr) { std::cerr << "SavegameManager: Couldn't find savegame file '" << filename << "', starting with an empty one." << std::endl; return; } SExprFileReader reader(sexpr->get_list_elem(0)); if (reader.get_name() != "pingus-savegame") { std::cerr << "Error: " << filename << ": not a (pingus-savegame) file" << std::endl; return; } const std::vector<FileReader>& sections = reader.get_sections(); for(std::vector<FileReader>::const_iterator i = sections.begin(); i != sections.end(); ++i) { Savegame* savegame = new Savegame(*i); SavegameTable::iterator j = find(savegame->get_filename()); if (j != savegames.end()) { // overwrite duplicates, shouldn't happen, but harmless std::cout << "SavegameManager: name collision: " << savegame->get_filename() << std::endl; delete *j; *j = savegame; } else { savegames.push_back(savegame); } } }
void iwSaveLoad::RefreshTable() { static bool loadedOnce = false; GetCtrl<ctrlTable>(0)->DeleteAllItems(); std::vector<std::string> saveFiles = ListDir(GetFilePath(FILE_PATHS[85]), "sav"); for(std::vector<std::string>::iterator it = saveFiles.begin(); it != saveFiles.end(); ++it) { Savegame save; // Datei öffnen if(!save.Load(*it, false, false)) { // Show errors only first time this is loaded if(!loadedOnce) { LOG.write(_("Invalid Savegame %1%! Reason: %2%\n")) % *it % (save.GetLastErrorMsg().empty() ? _("Unknown") : save.GetLastErrorMsg()); } continue; } // Zeitstring erstellen std::string dateStr = TIME.FormatTime("%d.%m.%Y - %H:%i", &save.save_time); // Dateiname noch rausextrahieren aus dem Pfad bfs::path path = *it; if(!path.has_filename()) continue; bfs::path fileName = path.filename(); // ".sav" am Ende weg RTTR_Assert(fileName.has_extension()); fileName.replace_extension(); std::string fileNameStr = cvWideStringToUTF8(fileName.wstring()); std::string startGF = helpers::toString(save.start_gf); // Und das Zeug zur Tabelle hinzufügen GetCtrl<ctrlTable>(0)->AddRow(0, fileNameStr.c_str(), save.mapName.c_str(), dateStr.c_str(), startGF.c_str(), it->c_str()); } // Nach Zeit Sortieren bool bFalse = false; GetCtrl<ctrlTable>(0)->SortRows(2, &bFalse); loadedOnce = true; }
void LevelDot::unlock() { Savegame* savegame = SavegameManager::instance()->get(plf.get_resname()); if (savegame == 0 || savegame->get_status() == Savegame::NONE) { Savegame savegame_(plf.get_resname(), Savegame::ACCESSIBLE, 0, 0); SavegameManager::instance()->store(savegame_); } else { } }
/** * @brief Creates a game. * @param solarus the application object * @param savegame the saved data of this game (the specified object will be copied and stored into the game) */ Game::Game(Solarus &solarus, Savegame &savegame): Screen(solarus), savegame(savegame), pause_key_available(true), pause_menu(NULL), gameover_sequence(NULL), reseting(false), restarting(false), keys_effect(NULL), current_map(NULL), next_map(NULL), previous_map_surface(NULL), transition_style(Transition::IMMEDIATE), transition(NULL), dungeon(NULL), crystal_switch_state(false), hud(NULL), hud_enabled(true), dialog_box(NULL) { // notify objects get_equipment().set_game(*this); solarus.get_debug_keys().set_game(this); // initialize members controls = new GameControls(*this); dialog_box = new DialogBox(*this); hero = new Hero(get_equipment()); keys_effect = new KeysEffect(); hud = new HUD(*this); // launch the starting map set_current_map(savegame.get_integer(Savegame::STARTING_MAP), "", Transition::FADE); }
/** * \brief Implementation of sol.game.load(). * \param l The Lua context that is calling this function. * \return Number of values to return to Lua. */ int LuaContext::game_api_load(lua_State* l) { const std::string& file_name = luaL_checkstring(l, 1); if (FileTools::get_quest_write_dir().empty()) { error(l, "Cannot load savegame: no write directory was specified in quest.dat"); } Savegame* savegame = new Savegame(get_lua_context(l).get_main_loop(), file_name); RefCountable::ref(savegame); savegame->get_equipment().load_items(); push_game(l, *savegame); RefCountable::unref(savegame); return 1; }
unsigned int BasicMonster::save(Savegame& sg) { unsigned int id; if (sg.saved(this, &id)) return id; SaveBlock store("BasicMonster", id); storeAll(sg, store); sg << store; return id; }
// for Savegame bool Storage::createSavegame(int grp, int lvl, int timespent, int cols_left, int cols_over, QStringList used, QStringList marked) { //qDebug() << "createSavegame"; if (! m_db.isOpen()) return false; bool ret = false; QDateTime now = QDateTime::currentDateTime(); Savegame *m = new Savegame; m->created = now.toTime_t(); m->updated = now.toTime_t(); m->grp = grp; m->lvl = lvl; m->timespent = timespent; m->cols_left = cols_left; m->cols_over = cols_over; m->setUsedCells(used); m->setMarkedCells(marked); QSqlQuery q; ret = q.prepare("INSERT INTO sg (created, updated, grp, lvl, timespent, cleft, cover, cused, cmarked) " "VALUES (:created, :updated, :grp, :lvl, :timespent, :cleft, :cover, :cused, :cmarked)"); if (ret) { q.bindValue(":created", m->created); q.bindValue(":updated", m->updated); q.bindValue(":grp", m->grp); q.bindValue(":lvl", m->lvl); q.bindValue(":timespent", m->timespent); q.bindValue(":cleft", m->cols_left); q.bindValue(":cover", m->cols_over); q.bindValue(":cused", m->cells_used); q.bindValue(":cmarked", m->cells_marked); ret = q.exec(); } if (ret) m->id = q.lastInsertId().toInt(); //qDebug() << "created with id" << m->id; return ret; }
unsigned int Object::save(Savegame& sg) { unsigned int id; if (sg.saved(this,&id)) return id; SaveBlock store("Object", id); store ("type", (int) type) ("name", name) ("formatFlags", formatFlags); store ("symbol", sym) ("color", color) ("visible", visible); sg << store; return id; }
unsigned int Tool::save(Savegame& sg) { unsigned int id; if (sg.saved(this,&id)) return id; SaveBlock store("Tool", id); store ("name", name) ("symbol", sym) ("color", color); store ("amount", amount) ("weight", weight) ("active", active); store ("tool", tool); sg << store; return id; }
void LevelDot::draw(DrawingContext& gc) { Vector2i mpos = gc.screen_to_world(Vector2i(Input::Controller::current()->get_pointer(Input::STANDARD_POINTER)->get_pos())); float x = static_cast<float>(mpos.x) - pos.x; float y = static_cast<float>(mpos.y) - pos.y; bool highlight = false; if (Math::sqrt(x*x + y*y) < 30.0f) highlight = true; Savegame* savegame = SavegameManager::instance()->get(plf.get_resname()); if (savegame && (savegame->get_status() == Savegame::FINISHED || savegame->get_status() == Savegame::ACCESSIBLE)) { if (savegame->get_status() == Savegame::FINISHED) if (highlight) { gc.draw (highlight_green_dot_sur, pos); } else { gc.draw (green_dot_sur, pos); } else if (highlight) gc.draw (highlight_red_dot_sur, pos); else gc.draw (red_dot_sur, pos); } else { gc.draw (inaccessible_dot_sur, pos); } }
void iwSaveLoad::RefreshTable() { static bool loadedOnce = false; GetCtrl<ctrlTable>(0)->DeleteAllItems(); std::vector<std::string> saveFiles = ListDir(RTTRCONFIG.ExpandPath(FILE_PATHS[85]), "sav"); for(auto& saveFile : saveFiles) { Savegame save; // Datei öffnen if(!save.Load(saveFile, false, false)) { // Show errors only first time this is loaded if(!loadedOnce) { LOG.write(_("Invalid Savegame %1%! Reason: %2%\n")) % saveFile % (save.GetLastErrorMsg().empty() ? _("Unknown") : save.GetLastErrorMsg()); } continue; } // Zeitstring erstellen std::string dateStr = s25util::Time::FormatTime("%d.%m.%Y - %H:%i", save.GetSaveTime()); // Dateiname noch rausextrahieren aus dem Pfad bfs::path path = saveFile; if(!path.has_filename()) continue; // Just filename w/o extension bfs::path fileName = path.stem(); std::string startGF = helpers::toString(save.start_gf); // Und das Zeug zur Tabelle hinzufügen GetCtrl<ctrlTable>(0)->AddRow(0, fileName.string().c_str(), save.GetMapName().c_str(), dateStr.c_str(), startGF.c_str(), saveFile.c_str()); } // Nach Zeit Sortieren bool bFalse = false; GetCtrl<ctrlTable>(0)->SortRows(2, &bFalse); loadedOnce = true; }
/** * @brief Deletes a save file. * @param save_number number of the savegame to delete (0 to 2) */ void SelectionMenuConfirmErase::delete_save_file(int save_number) { Savegame *savegame = menu->get_savegame(save_number); FileTools::data_file_delete(savegame->get_file_name().c_str()); menu->reload_savegames(); }
void dskSinglePlayer::Msg_ButtonClick(const unsigned int ctrl_id) { switch(ctrl_id) { case 3: // "Letztes Spiel fortsetzen" { std::vector<std::string> savFiles = ListDir(GetFilePath(FILE_PATHS[85]), "sav"); bfs::path path; unser_time_t recent = 0; for(std::vector<std::string>::iterator it = savFiles.begin(); it != savFiles.end(); ++it) { Savegame save; // Datei öffnen if (!save.Load(*it, false, false)) continue; if (save.save_time > recent) { recent = save.save_time; path = *it; } } if (recent != 0) { // Dateiname noch rausextrahieren aus dem Pfad if(!path.has_filename()) return; bfs::path fileName = path.filename(); // ".sav" am Ende weg RTTR_Assert(fileName.has_extension()); fileName.replace_extension(); // Server info CreateServerInfo csi; csi.gamename = fileName.string(); csi.password = "******"; csi.port = 3665; csi.type = ServerType::LOCAL; csi.ipv6 = false; csi.use_upnp = false; WINDOWMANAGER.Switch(new dskSelectMap(csi)); if(GAMESERVER.TryToStart(csi, path.string(), MAPTYPE_SAVEGAME)) WINDOWMANAGER.ShowAfterSwitch(new iwPleaseWait); else WINDOWMANAGER.Show(new iwMsgbox(_("Error"), _("The specified file couldn't be loaded!"), NULL, MSB_OK, MSB_EXCLAMATIONRED)); } else WINDOWMANAGER.Show(new iwMsgbox(_("Error"), _("The specified file couldn't be loaded!"), NULL, MSB_OK, MSB_EXCLAMATIONRED)); } break; case 4: // "Replay abspielen" { WINDOWMANAGER.Show(new iwPlayReplay); } break; case 5: // "Kampagne" { /// @todo Hier dann Auswahl zwischen Kampagne(n) und "Freies Spiel" WINDOWMANAGER.Show(new iwMsgbox(_("Not available"), _("Please use \'Unlimited Play\' to create a Singleplayer game."), this, MSB_OK, MSB_EXCLAMATIONGREEN)); } break; case 6: // "Freies Spiel" { PrepareSinglePlayerServer(); } break; case 7: // "Spiel laden" { PrepareLoadGame(); } break; case 8: // "Zurück" { WINDOWMANAGER.Switch(new dskMainMenu); } break; } }
void dskSinglePlayer::Msg_ButtonClick(const unsigned int ctrl_id) { switch(ctrl_id) { case 3: // "Letztes Spiel fortsetzen" { std::list<std::string> liste; std::string tmp = GetFilePath(FILE_PATHS[85]); tmp += "*.sav"; ListDir(tmp.c_str(), false, NULL, NULL, &liste); std::string path; unser_time_t recent = 0; for(std::list<std::string>::iterator it = liste.begin(); it != liste.end(); ++it) { Savegame save; // Datei öffnen if (!save.Load(*it, false, false)) continue; if (save.save_time > recent) { recent = save.save_time; path = *it; } } if (recent != 0) { // Dateiname noch rausextrahieren aus dem Pfad size_t pos = path.find_last_of('/'); if(pos == std::string::npos) return; std::string extracted_filename = path.substr(pos + 1); // ".sav" am Ende weg assert(extracted_filename.length() >= 4); extracted_filename.erase(extracted_filename.length() - 4); // Server info CreateServerInfo csi; csi.gamename = extracted_filename; csi.password = "******"; csi.port = 3665; csi.type = NP_LOCAL; csi.ipv6 = false; csi.use_upnp = false; WindowManager::inst().Switch(new dskSelectMap(csi)); if(GAMESERVER.TryToStart(csi, path, MAPTYPE_SAVEGAME)) { WindowManager::inst().Draw(); WindowManager::inst().Show(new iwPleaseWait); } else { WindowManager::inst().Show(new iwMsgbox(_("Error"), _("The specified file couldn't be loaded!"), this, MSB_OK, MSB_EXCLAMATIONRED)); } } else { WindowManager::inst().Show(new iwMsgbox(_("Error"), _("The specified file couldn't be loaded!"), this, MSB_OK, MSB_EXCLAMATIONRED)); } liste.clear(); } break; case 4: // "Replay abspielen" { WindowManager::inst().Show(new iwPlayReplay); } break; case 5: // "Kampagne" { /// @todo Hier dann Auswahl zwischen Kampagne(n) und "Freies Spiel" WindowManager::inst().Show(new iwMsgbox(_("Not available"), _("Please use \'Unlimited Play\' to create a Singleplayer game."), this, MSB_OK, MSB_EXCLAMATIONGREEN)); } break; case 6: // "Freies Spiel" { PrepareSinglePlayerServer(); } break; case 7: // "Spiel laden" { PrepareLoadGame(); } break; case 8: // "Zurück" { WindowManager::inst().Switch(new dskMainMenu); } break; } }
/** * \brief Converts this savegame v1 into a savegame v2. * \param savegame_v2 The savegame to fill. */ void SavegameConverterV1::convert_to_v2(Savegame& savegame_v2) { // 1. Built-in values. savegame_v2.set_string(Savegame::KEY_STARTING_POINT, get_string(STARTING_POINT)); if (!get_string(STARTING_MAP).empty()) { savegame_v2.set_string(Savegame::KEY_STARTING_MAP, get_string(STARTING_MAP)); } else { // Older v1 savegames used integers to identify maps. std::ostringstream oss; oss << get_integer(STARTING_MAP_INT); savegame_v2.set_string(Savegame::KEY_STARTING_MAP, oss.str()); } savegame_v2.set_integer(Savegame::KEY_CURRENT_LIFE, get_integer(CURRENT_LIFE)); savegame_v2.set_integer(Savegame::KEY_CURRENT_MONEY, get_integer(CURRENT_MONEY)); savegame_v2.set_integer(Savegame::KEY_CURRENT_MAGIC, get_integer(CURRENT_MAGIC)); savegame_v2.set_integer(Savegame::KEY_MAX_LIFE, get_integer(MAX_LIFE)); savegame_v2.set_integer(Savegame::KEY_MAX_MONEY, get_integer(MAX_MONEY)); savegame_v2.set_integer(Savegame::KEY_MAX_MAGIC, get_integer(MAX_MAGIC)); savegame_v2.set_string(Savegame::KEY_ITEM_SLOT_1, get_string(ITEM_SLOT_0)); savegame_v2.set_string(Savegame::KEY_ITEM_SLOT_2, get_string(ITEM_SLOT_1)); savegame_v2.set_string(Savegame::KEY_KEYBOARD_ACTION, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_ACTION_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_ATTACK, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_SWORD_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_ITEM_1, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_ITEM_1_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_ITEM_2, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_ITEM_2_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_PAUSE, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_PAUSE_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_RIGHT, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_RIGHT_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_UP, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_UP_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_LEFT, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_LEFT_KEY)))); savegame_v2.set_string(Savegame::KEY_KEYBOARD_DOWN, InputEvent::get_keyboard_key_name( InputEvent::KeyboardKey(get_integer(KEYBOARD_DOWN_KEY)))); savegame_v2.set_string(Savegame::KEY_JOYPAD_ACTION, get_string(JOYPAD_ACTION_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_ATTACK, get_string(JOYPAD_SWORD_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_ITEM_1, get_string(JOYPAD_ITEM_1_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_ITEM_2, get_string(JOYPAD_ITEM_2_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_PAUSE, get_string(JOYPAD_PAUSE_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_RIGHT, get_string(JOYPAD_RIGHT_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_UP, get_string(JOYPAD_UP_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_LEFT, get_string(JOYPAD_LEFT_KEY)); savegame_v2.set_string(Savegame::KEY_JOYPAD_DOWN, get_string(JOYPAD_DOWN_KEY)); savegame_v2.set_integer(Savegame::KEY_ABILITY_RESISTANCE, get_integer(ABILITY_TUNIC)); savegame_v2.set_integer(Savegame::KEY_ABILITY_SWORD, get_integer(ABILITY_SWORD)); savegame_v2.set_integer(Savegame::KEY_ABILITY_SHIELD, get_integer(ABILITY_SHIELD)); savegame_v2.set_integer(Savegame::KEY_ABILITY_LIFT, get_integer(ABILITY_LIFT)); savegame_v2.set_integer(Savegame::KEY_ABILITY_SWIM, get_integer(ABILITY_SWIM)); savegame_v2.set_integer(Savegame::KEY_ABILITY_SWORD_KNOWLEDGE, get_integer(ABILITY_SWORD_KNOWLEDGE)); savegame_v2.set_integer(Savegame::KEY_ABILITY_DETECT_WEAK_WALLS, get_integer(ABILITY_DETECT_WEAK_WALLS)); savegame_v2.set_integer(Savegame::KEY_ABILITY_GET_BACK_FROM_DEATH, get_integer(ABILITY_GET_BACK_FROM_DEATH)); savegame_v2.set_integer(Savegame::KEY_ABILITY_RUN, get_integer(ABILITY_RUN)); // 2. Values that used to be built-in in v1 and become pure data in v2. savegame_v2.set_string("player_name", get_string(PLAYER_NAME)); savegame_v2.set_integer("pause_last_submenu", get_integer(PAUSE_LAST_SUBMENU) + 1); savegame_v2.set_integer("pause_inventory_last_item_index", get_integer(INVENTORY_LAST_ITEM_INDEX) + 1); for (int i = 0; i < 40; i++) { int index = 200 + i * 10; std::ostringstream oss; oss << "dungeon_" << (i + 1); const std::string& dungeon_number = oss.str(); // Dungeon finished (integer replaced by a boolean). if (get_integer(index) > 0) { savegame_v2.set_boolean(dungeon_number + "_finished", true); } // Got the map? (integer replaced by a boolean). ++index; if (get_integer(index) > 0) { savegame_v2.set_boolean(dungeon_number + "_map", true); } // Got the compass? (integer replaced by a boolean). ++index; if (get_integer(index) > 0) { savegame_v2.set_boolean(dungeon_number + "_compass", true); } // Got the big key? (integer replaced by a boolean). ++index; if (get_integer(index) > 0) { savegame_v2.set_boolean(dungeon_number + "_big_key", true); } // Got the boss key? (integer replaced by a boolean). ++index; if (get_integer(index) > 0) { savegame_v2.set_boolean(dungeon_number + "_boss_key", true); } // Number of small keys. ++index; int nb_small_keys = get_integer(index); if (nb_small_keys > 0) { savegame_v2.set_integer(dungeon_number + "_small_keys", nb_small_keys); } } // 3. Custom values. int i; for (i = 32; i < 64; i++) { const std::string& value = get_string(i); if (!value.empty()) { std::ostringstream oss; oss << "s" << i; savegame_v2.set_string(oss.str(), value); } } for (i = 1024; i < 2048; i++) { int value = get_integer(i); if (value != 0) { std::ostringstream oss; oss << "i" << i; savegame_v2.set_integer(oss.str(), value); } } for (i = 0; i < 32768; i++) { bool value = get_boolean(i); if (value) { std::ostringstream oss; oss << "b" << i; savegame_v2.set_boolean(oss.str(), value); } } }