/* * 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: * Reto Grieder * Co-authors: * ... * */ #include "RootGameState.h" #include "util/String.h" #include "util/SubString.h" #include "util/Debug.h" #include "util/Exception.h" #include "Core.h" #include "Clock.h" #include "CommandLine.h" namespace orxonox { SetCommandLineArgument(state, "gui").shortcut("s"); RootGameState::RootGameState(const std::string& name) : GameState(name) , stateRequest_("") { } RootGameState::~RootGameState() { } /** @brief Internal method that actually makes the state transition. Since it is internal, the method can assume certain things to be granted (like 'this' is always active). */ void RootGameState::makeTransition(GameStateBase* source, GameStateBase* destination) { if (source != 0) { // transition was not initiated by root itself this->activeChild_ = 0; } if (destination == this) { // this marks the end of the game. return; } // Check for 'destination' in the children map first std::map::const_iterator it = this->grandchildrenToChildren_.find(destination); if (it != this->grandchildrenToChildren_.end()) { OrxAssert(dynamic_cast(it->second) != 0, "There was a mix with RootGameState and GameState, could not cast."); GameStateBase* child = static_cast(it->second); // child state. Don't use 'state', might be a grandchild! this->activeChild_ = child; child->makeTransition(this, destination); } else { // root doesn't have a parent.. OrxAssert(false, "GameState '" + destination->getName() + "' not found in children list of Root."); } } void RootGameState::gotoState(const std::string& name) { GameStateBase* request = getState(name); if (request) { GameStateBase* current = getCurrentState(); if (current) { current->makeTransition(0, request); } else { // Root is not yet active. This is a violation. ThrowException(GameState, "Activate Root before requesting a state."); } } else { COUT(2) << "Warning: GameState '" << name << "' doesn't exist." << std::endl; } } /** @brief Makes a state transition according to the state tree. You can choose any state in the tree to do the call. The function finds the current state on its own. @param state The state to be entered, has to exist in the tree. */ void RootGameState::requestState(const std::string& name) { this->stateRequest_ = name; } /** @brief Starts the game. The little 'while' denotes the main loop. Whenever the root state is selected, the game ends. @param name State to start with (usually main menu or specified by command line) */ void RootGameState::start(int argc, char** argv) { #ifdef NDEBUG try { #endif // start global orxonox time Clock clock; // create the Core settings to configure the output level Core::getInstance(); parseArguments(argc, argv); this->activate(); // get initial state from command line gotoState(CommandLine::getValue("state")); while (this->activeChild_) { clock.capture(); this->tick(clock); if (this->stateRequest_ != "") gotoState(stateRequest_); } this->deactivate(); #ifdef NDEBUG } // Note: These are all unhandled exceptions that should not have made its way here! // almost complete game catch block to display the messages appropriately. catch (std::exception& ex) { COUT(1) << ex.what() << std::endl; COUT(1) << "Program aborted." << std::endl; abort(); } // anything that doesn't inherit from std::exception catch (...) { COUT(1) << "An unidentifiable exception has occured. Program aborted." << std::endl; abort(); } #endif } /** @brief Parses both command line and start.ini for CommandLineArguments. */ void RootGameState::parseArguments(int argc, char** argv) { // parse command line first std::vector args; for (int i = 1; i < argc; ++i) args.push_back(argv[i]); try { orxonox::CommandLine::parse(args); } catch (orxonox::ArgumentException& ex) { COUT(1) << ex.what() << std::endl; COUT(0) << "Usage:" << std::endl << "orxonox " << CommandLine::getUsageInformation() << std::endl; } // look for additional arguments in start.ini std::ifstream file; file.open("start.ini"); args.clear(); if (file) { while (!file.eof()) { std::string line; std::getline(file, line); line = removeTrailingWhitespaces(line); //if (!(line[0] == '#' || line[0] == '%')) //{ SubString tokens(line, " ", " ", false, 92, false, 34, false, 40, 41, false, '#'); for (unsigned i = 0; i < tokens.size(); ++i) if (tokens[i][0] != '#') args.push_back(tokens[i]); //args.insert(args.end(), tokens.getAllStrings().begin(), tokens.getAllStrings().end()); //} } file.close(); } try { orxonox::CommandLine::parse(args); } catch (orxonox::ArgumentException& ex) { COUT(1) << "An Exception occured while parsing start.ini" << std::endl; COUT(1) << ex.what() << std::endl; COUT(0) << "Usage:" << std::endl << "orxonox " << CommandLine::getUsageInformation() << std::endl; } } }