/* * ORXONOX - the hottest 3D action shooter ever to exist * > www.orxonox.net < * * * License notice: * * This program 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 2 * of the License, or (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Author: * Damian 'Mozork' Frick * Co-authors: * ... * */ #include "LevelInfo.h" #include #include #include "util/SubString.h" #include "core/CoreIncludes.h" #include "core/XMLPort.h" #include "LevelManager.h" namespace orxonox { // LevelInfoItem //! The list of allowed tags. /*static*/ std::set LevelInfoItem::possibleTags_s = std::set(); /** @brief Default constructor. */ LevelInfoItem::LevelInfoItem() { } /** @brief Constructor. Initializes the object. @param name The name of the Level. @param filename The XML-filename of the Level. */ LevelInfoItem::LevelInfoItem(const std::string& name, const std::string filename) { this->setName(name); this->setXMLFilename(filename); } /** @brief Destructor. */ LevelInfoItem::~LevelInfoItem() { } /** @brief Initialize the set of allowed tags. */ /*static*/ void LevelInfoItem::initializeTags(void) { if(!LevelInfoItem::initialized_s) { LevelInfoItem::possibleTags_s.insert("test"); LevelInfoItem::possibleTags_s.insert("showcase"); LevelInfoItem::possibleTags_s.insert("tutorial"); LevelInfoItem::possibleTags_s.insert("presentation"); LevelInfoItem::possibleTags_s.insert("mission"); LevelInfoItem::possibleTags_s.insert("gametype"); LevelInfoItem::possibleTags_s.insert("minigame"); LevelInfoItem::possibleTags_s.insert("shipselection"); LevelInfoItem::possibleTags_s.insert("Orxobros"); } } /** @brief Set the tags the Level is tagged with. @param tags A comma-seperated string of all the tags to be set. */ void LevelInfoItem::setTags(const std::string& tags) { SubString substr = SubString(tags, ",", " "); // Split the string into tags. const std::vector& tokens = substr.getAllStrings(); for (const std::string& token : tokens) this->addTag(token, false); this->tagsUpdated(); } /** @brief Set the starting ship models of the level @param ships A comma-seperated string of all the allowed ship models for the shipselection. */ void LevelInfoItem::setStartingShips(const std::string& ships) { SubString substr = SubString(ships, ",", " "); // Split the string into tags. const std::vector& tokens = substr.getAllStrings(); for(const std::string& token : tokens) this->addStartingShip(token, false); this->startingshipsUpdated(); } /** @brief Add a tag to the set of tags the Level is tagged with. @param tag The tag to be added. @param update Whether the comma-seperated string of all tags should be updated. Default is true. @return Returns true if the tag was successfully added, if the tag was already present it returns false. */ bool LevelInfoItem::addTag(const std::string& tag, bool update) { if(!this->validateTag(tag)) { orxout(internal_warning) << "Bad LevelInfo tag '" << tag << "' in " << this->getXMLFilename() << ". Ignoring..." << endl; return false; } bool success = this->tags_.insert(*LevelInfoItem::possibleTags_s.find(tag)).second; if(update && success) this->tagsUpdated(); return success; } /** @brief Add a ship model to allowed models for the shipselection @param ship The ship model to be added. @param update Whether the comma-seperated string of all ship models should be updated. Default is true. @return Returns true if the ship was successfully added, if the ship was already present it returns false. */ bool LevelInfoItem::addStartingShip(const std::string& ship, bool update) { bool success = this->startingShips_.insert(ship).second; if(update && success) this->startingshipsUpdated(); return success; } /** @brief Updates the comma-seperated string of all tags, if the set of tags has changed. */ void LevelInfoItem::tagsUpdated(void) { std::stringstream stream; std::set::iterator temp; for(std::set::iterator it = this->tags_.begin(); it != this->tags_.end(); ) { temp = it; if(++it == this->tags_.end()) // If this is the last tag we don't add a comma. stream << *temp; else stream << *temp << ", "; } this->tagsString_ = std::string(stream.str()); } /** @brief Updates the comma-seperated string of all ships, if the set of tags has changed. */ void LevelInfoItem::startingshipsUpdated(void) { std::stringstream stream; std::set::iterator temp; for(std::set::iterator it = this->startingShips_.begin(); it != this->startingShips_.end(); ) { temp = it; if(++it == this->startingShips_.end()) // If this is the last ship we don't add a comma. stream << *temp; else stream << *temp << ", "; } this->startingShipsString_ = std::string(stream.str()); } void LevelInfoItem::changeStartingShip(const std::string& model) { static std::string shipSelectionTag = "shipselection"; //HACK: Read Level XML File, find "shipselection", replace with ship model std::string levelPath = "../levels/"; levelPath.append(this->getXMLFilename()); std::string tempPath = "../levels/"; tempPath.append("_temp.oxw"); orxout(user_status) << levelPath << endl; orxout(user_status) << tempPath << endl; std::ifstream myLevel (levelPath.c_str()); std::ofstream tempLevel (tempPath.c_str()); while(!myLevel.eof()) { std::string buff; std::getline(myLevel, buff); std::string pawndesignString = "pawndesign="; size_t found = buff.find(pawndesignString.append(shipSelectionTag)); if (found!= std::string::npos) buff = buff.substr(0, found + 11) + model + buff.substr(found+11+shipSelectionTag.length(), std::string::npos); tempLevel.write(buff.c_str(), buff.length()); tempLevel << std::endl; } myLevel.close(); tempLevel.close(); orxout(user_status) << "done" << endl; } void LevelInfoItem::changeStartingLevel(const std::string& model) { static std::string shipSelectionTag = "orxobros"; //HACK: Read Level XML File, find "shipselection", replace with ship model std::string levelPath = "../levels/"; levelPath.append(this->getXMLFilename()); std::string tempPath = "../levels/"; //tempPath.append("_temp.oxw"); orxout(user_status) << levelPath << endl; orxout(user_status) << tempPath << endl; std::ifstream myLevel (levelPath.c_str()); std::ofstream tempLevel (tempPath.c_str()); /*while(!myLevel.eof()) { std::string buff; std::getline(myLevel, buff); std::string pawndesignString = "pawndesign="; size_t found = buff.find(pawndesignString.append(shipSelectionTag)); if (found!= std::string::npos) buff = buff.substr(0, found + 11) + model + buff.substr(found+11+shipSelectionTag.length(), std::string::npos); tempLevel.write(buff.c_str(), buff.length()); tempLevel << std::endl; } myLevel.close(); tempLevel.close(); */ orxout(user_status) << "done" << endl; } // LevelInfo RegisterClass(LevelInfo); LevelInfo::LevelInfo(Context* context) : BaseObject(context) { RegisterObject(LevelInfo); this->xmlfilename_ = this->getFilename(); } /** @brief Destructor. */ LevelInfo::~LevelInfo() { } /** @brief Creates a LevelInfo object through XML. */ void LevelInfo::XMLPort(Element& xmlelement, XMLPort::Mode mode) { SUPER(LevelInfo, XMLPort, xmlelement, mode); XMLPortParam(LevelInfo, "description", setDescription, getDescription, xmlelement, mode); XMLPortParam(LevelInfo, "screenshot", setScreenshot, getScreenshot, xmlelement, mode); XMLPortParam(LevelInfo, "tags", setTags, getTags, xmlelement, mode); XMLPortParam(LevelInfo, "startingships", setStartingShips, getStartingShips, xmlelement, mode); } /** @brief Copies the contents of this LevelInfo object to a new LevelInfoItem object. This is needed, because a LeveInfo object is only created within the scope of the XML-file it is loaded with and is destroyed once that is unloaded. @return Returns a new LevelInfoItem with the same contents as the LevelInfo object. */ LevelInfoItem* LevelInfo::copy(void) { LevelInfoItem* info = new LevelInfoItem(this->BaseObject::getName(), this->getXMLFilename()); info->setDescription(this->getDescription()); info->setScreenshot(this->getScreenshot()); info->setTags(this->getTags()); info->setStartingShips(this->getStartingShips()); return info; } }