/* * Copyright 2010 OpenXcom Developers. * * This file is part of OpenXcom. * * OpenXcom 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 3 of the License, or * (at your option) any later version. * * OpenXcom 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 OpenXcom. If not, see . */ #include "SavedGame.h" #include #include #include #include "../dirent.h" #include "yaml.h" #include "../Ruleset/Ruleset.h" #include "../Engine/RNG.h" #include "../Engine/Language.h" #include "../Interface/TextList.h" #include "../Engine/Exception.h" #include "../Engine/Options.h" #include "SavedBattleGame.h" #include "GameTime.h" #include "Country.h" #include "Base.h" #include "Craft.h" #include "Region.h" #include "Ufo.h" #include "Waypoint.h" #include "UfopaediaSaved.h" namespace OpenXcom { /** * Initializes a brand new saved game according to the specified difficulty. * @param difficulty Game difficulty. */ SavedGame::SavedGame(GameDifficulty difficulty) : _difficulty(difficulty), _funds(0), _countries(), _regions(), _bases(), _ufos(), _craftId(), _waypoints(), _ufoId(1), _waypointId(1), _battleGame(0) { RNG::init(); _time = new GameTime(6, 1, 1, 1999, 12, 0, 0); _ufopaedia = new UfopaediaSaved(); } /** * Deletes the game content from memory. */ SavedGame::~SavedGame() { delete _time; for (std::vector::iterator i = _countries.begin(); i != _countries.end(); ++i) { delete *i; } for (std::vector::iterator i = _regions.begin(); i != _regions.end(); ++i) { delete *i; } for (std::vector::iterator i = _bases.begin(); i != _bases.end(); ++i) { delete *i; } for (std::vector::iterator i = _ufos.begin(); i != _ufos.end(); ++i) { delete *i; } for (std::vector::iterator i = _waypoints.begin(); i != _waypoints.end(); ++i) { delete *i; } delete _battleGame; delete _ufopaedia; } /** * Gets all the saves found in the user folder * and adds them to a text list. * @param list Text list. * @param lang Loaded language. */ void SavedGame::getList(TextList *list, Language *lang) { DIR *dp = opendir(Options::getUserFolder().c_str()); if (dp == 0) { throw Exception("Failed to open saves directory"); } struct dirent *dirp; while ((dirp = readdir(dp)) != 0) { std::string file = dirp->d_name; // Check if it's a valid save if (file.find(".sav") == std::string::npos) { continue; } std::string fullname = Options::getUserFolder() + file; std::ifstream fin(fullname.c_str()); if (!fin) { closedir(dp); throw Exception("Failed to load savegame"); } YAML::Parser parser(fin); YAML::Node doc; parser.GetNextDocument(doc); GameTime time = GameTime(6, 1, 1, 1999, 12, 0, 0); time.load(doc["time"]); std::stringstream saveTime; std::wstringstream saveDay, saveMonth, saveYear; saveTime << time.getHour() << ":" << std::setfill('0') << std::setw(2) << time.getMinute(); saveDay << time.getDay() << lang->getString(time.getDayString()); saveMonth << lang->getString(time.getMonthString()); saveYear << time.getYear(); list->addRow(5, Language::utf8ToWstr(file.substr(0, file.length()-4)).c_str(), Language::utf8ToWstr(saveTime.str()).c_str(), saveDay.str().c_str(), saveMonth.str().c_str(), saveYear.str().c_str()); fin.close(); } closedir(dp); } /** * Loads a saved game's contents from a YAML file. * @note Assumes the saved game is blank. * @param filename YAML filename. * @param rule Ruleset for the saved game. */ void SavedGame::load(const std::string &filename, Ruleset *rule) { unsigned int size = 0; std::string s = Options::getUserFolder() + filename + ".sav"; std::ifstream fin(s.c_str()); if (!fin) { throw Exception("Failed to load savegame"); } YAML::Parser parser(fin); YAML::Node doc; // Get brief save info parser.GetNextDocument(doc); std::string v; doc["version"] >> v; if (v != Options::getVersion()) { throw Exception("Version mismatch"); } _time->load(doc["time"]); // Get full save data parser.GetNextDocument(doc); int a = 0; doc["difficulty"] >> a; _difficulty = (GameDifficulty)a; doc["funds"] >> _funds; size = doc["countries"].size(); for (unsigned int i = 0; i < size; ++i) { std::string type; doc["countries"][i]["type"] >> type; Country *c = new Country(rule->getCountry(type), false); c->load(doc["countries"][i]); _countries.push_back(c); } size = doc["regions"].size(); for (unsigned int i = 0; i < size; ++i) { std::string type; doc["regions"][i]["type"] >> type; Region *r = new Region(rule->getRegion(type)); r->load(doc["regions"][i]); _regions.push_back(r); } size = doc["ufos"].size(); for (unsigned int i = 0; i < size; ++i) { std::string type; doc["ufos"][i]["type"] >> type; Ufo *u = new Ufo(rule->getUfo(type)); u->load(doc["ufos"][i]); _ufos.push_back(u); } doc["craftId"] >> _craftId; size = doc["waypoints"].size(); for (unsigned int i = 0; i < size; ++i) { Waypoint *w = new Waypoint(); w->load(doc["waypoints"][i]); _waypoints.push_back(w); } doc["ufoId"] >> _ufoId; doc["waypointId"] >> _waypointId; size = doc["bases"].size(); for (unsigned int i = 0; i < size; ++i) { Base *b = new Base(rule); b->load(doc["bases"][i], this); _bases.push_back(b); } if (const YAML::Node *pName = doc.FindValue("battleGame")) { _battleGame = new SavedBattleGame(); _battleGame->load(*pName); } fin.close(); } /** * Saves a saved game's contents to a YAML file. * @param filename YAML filename. */ void SavedGame::save(const std::string &filename) const { std::string s = Options::getUserFolder() + filename + ".sav"; std::ofstream sav(s.c_str()); if (!sav) { throw Exception("Failed to save savegame"); } YAML::Emitter out; // Saves the brief game info used in the saves list out << YAML::BeginDoc; out << YAML::BeginMap; out << YAML::Key << "version" << YAML::Value << Options::getVersion(); out << YAML::Key << "time" << YAML::Value; _time->save(out); out << YAML::EndMap; // Saves the full game data to the save out << YAML::BeginDoc; out << YAML::BeginMap; out << YAML::Key << "difficulty" << YAML::Value << _difficulty; out << YAML::Key << "funds" << YAML::Value << _funds; out << YAML::Key << "countries" << YAML::Value; out << YAML::BeginSeq; for (std::vector::const_iterator i = _countries.begin(); i != _countries.end(); ++i) { (*i)->save(out); } out << YAML::EndSeq; out << YAML::Key << "regions" << YAML::Value; out << YAML::BeginSeq; for (std::vector::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { (*i)->save(out); } out << YAML::EndSeq; out << YAML::Key << "bases" << YAML::Value; out << YAML::BeginSeq; for (std::vector::const_iterator i = _bases.begin(); i != _bases.end(); ++i) { (*i)->save(out); } out << YAML::EndSeq; out << YAML::Key << "ufos" << YAML::Value; out << YAML::BeginSeq; for (std::vector::const_iterator i = _ufos.begin(); i != _ufos.end(); ++i) { (*i)->save(out); } out << YAML::EndSeq; out << YAML::Key << "craftId" << YAML::Value << _craftId; out << YAML::Key << "waypoints" << YAML::Value; out << YAML::BeginSeq; for (std::vector::const_iterator i = _waypoints.begin(); i != _waypoints.end(); ++i) { (*i)->save(out); } out << YAML::EndSeq; out << YAML::Key << "ufoId" << YAML::Value << _ufoId; out << YAML::Key << "waypointId" << YAML::Value << _waypointId; if (_battleGame != 0) { out << YAML::Key << "battleGame" << YAML::Value; _battleGame->save(out); } out << YAML::EndMap; sav << out.c_str(); sav.close(); } /** * Returns the player's current funds. * @return Current funds. */ int SavedGame::getFunds() const { return _funds; } /** * Changes the player's funds to a new value. * @param funds New funds. */ void SavedGame::setFunds(int funds) { _funds = funds; } /** * Gives the player his monthly funds, taking in account * all maintenance and profit costs. */ void SavedGame::monthlyFunding() { _funds += getCountryFunding() - getBaseMaintenance(); } /** * Returns the current time of the game. * @return Pointer to the game time. */ GameTime *const SavedGame::getTime() const { return _time; } /** * Returns the list of countries in the game world. * @return Pointer to country list. */ std::vector *const SavedGame::getCountries() { return &_countries; } /** * Adds up the monthly funding of all the countries. * @return Total funding. */ int SavedGame::getCountryFunding() const { int total = 0; for (std::vector::const_iterator i = _countries.begin(); i != _countries.end(); ++i) { total += (*i)->getFunding(); } return total; } /** * Returns the list of world regions. * @return Pointer to region list. */ std::vector *const SavedGame::getRegions() { return &_regions; } /** * Returns the list of player bases. * @return Pointer to base list. */ std::vector *const SavedGame::getBases() { return &_bases; } /** * Adds up the monthly maintenance of all the bases. * @return Total maintenance. */ int SavedGame::getBaseMaintenance() const { int total = 0; for (std::vector::const_iterator i = _bases.begin(); i != _bases.end(); ++i) { total += (*i)->getMonthlyMaintenace(); } return total; } /** * Returns the latest craft IDs for each type. * @return Pointer to ID list. */ std::map *const SavedGame::getCraftIds() { return &_craftId; } /** * Returns the list of alien UFOs. * @return Pointer to UFO list. */ std::vector *const SavedGame::getUfos() { return &_ufos; } /** * Returns the latest ufo ID. * @return Pointer to ID value. */ int *const SavedGame::getUfoId() { return &_ufoId; } /** * Returns the latest waypoint ID. * @return Pointer to ID value. */ int *const SavedGame::getWaypointId() { return &_waypointId; } /** * Returns the list of craft waypoints. * @return Pointer to waypoint list. */ std::vector *const SavedGame::getWaypoints() { return &_waypoints; } /** * Get pointer to the battleGame object. * @return Pointer to the battleGame object. */ SavedBattleGame *const SavedGame::getBattleGame() { return _battleGame; } /** * Set battleGame object. * @param battleGame Pointer to the battleGame object. */ void SavedGame::setBattleGame(SavedBattleGame *battleGame) { delete _battleGame; _battleGame = battleGame; } /** * Handles the end battle stuff. */ void SavedGame::endBattle() { // craft goes back home for (std::vector::iterator i = _bases.begin(); i != _bases.end(); ++i) { for (std::vector::iterator j = (*i)->getCrafts()->begin(); j != (*i)->getCrafts()->end(); ++j) { if ((*j)->isInBattlescape()) { (*j)->returnToBase(); (*j)->setLowFuel(true); (*j)->setInBattlescape(false); } } } // UFO crash/landing site disappears for (std::vector::iterator i = _ufos.begin(); i != _ufos.end(); ++i) { if ((*i)->isInBattlescape()) { delete *i; _ufos.erase(i); break; } } // bye save game, battle is over setBattleGame(0); } /** * Get pointer to the ufopaedia object. * @return Pointer to the ufopaedia object. */ UfopaediaSaved *SavedGame::getUfopaedia() { return _ufopaedia; } }