/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx 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, or (at your option) any later version. ### File Specific: main-programmer: Patrick Boenzli co-programmer: ... */ #define DEBUG_SPECIAL_MODULE DEBUG_MODULE_LOAD #include "game_loader.h" #include "util/loading/load_param.h" #include "shell_command.h" #include "campaign.h" #include "util/loading/resource_manager.h" #include "event_handler.h" using namespace std; SHELL_COMMAND(quit, GameLoader, stop) ->describe("quits the game") ->setAlias("orxoquit"); GameLoader* GameLoader::singletonRef = NULL; /** * simple constructor */ GameLoader::GameLoader () { this->setClassID(CL_GAME_LOADER, "GameLoader"); this->setName("GameLoader"); this->bRun = true; } /** * simple deconstructor */ GameLoader::~GameLoader () { if( this->currentCampaign) delete this->currentCampaign; this->currentCampaign = NULL; } /** * initializes the GameLoader */ ErrorMessage GameLoader::init() { if(this->currentCampaign != NULL) this->currentCampaign->init(); this->eventHandler = EventHandler::getInstance(); this->eventHandler->subscribe(this, ES_GAME, KeyMapper::PEV_PAUSE); this->eventHandler->subscribe(this, ES_ALL, EV_MAIN_QUIT); //< External Quit Event this->eventHandler->subscribe(this, ES_GAME, KeyMapper::PEV_QUIT); this->eventHandler->subscribe(this, ES_GAME, KeyMapper::PEV_NEXT_WORLD); this->eventHandler->subscribe(this, ES_GAME, KeyMapper::PEV_PREVIOUS_WORLD); } /** * reads a campaign definition file into a campaign class * @param fileName to be loaded * @returns the loaded campaign * * this will interprete the map/campaign files and recursivly load a tree of worlds/campaigns */ ErrorMessage GameLoader::loadCampaign(const std::string& fileName) { ErrorMessage errorCode; std::string campaignName = ResourceManager::getFullName(fileName); if (!campaignName.empty()) { this->currentCampaign = this->fileToCampaign(campaignName); } } /** * reads a campaign definition file into a campaign class * @param fileName to be loaded * @returns the loaded campaign * * this will interprete the map/campaign files and recursivly load a tree of worlds/campaigns */ ErrorMessage GameLoader::loadNetworkCampaign(const std::string& fileName) { ErrorMessage errorCode; std::string campaignName = ResourceManager::getFullName(fileName); if (!campaignName.empty()) { this->currentCampaign = this->fileToCampaign(campaignName); } } /** * loads a debug campaign for test purposes only. * @param campaignID the identifier of the campaign. * @returns error message if not able to do so. */ ErrorMessage GameLoader::loadDebugCampaign(Uint32 campaignID) { switch(campaignID) { /* Debug Level 0: Debug level used to test the base frame work. As you can see, all storyentity data is allocated before game start. the storyentity will load themselfs shortly before start through the StoryEntity::init() funtion. */ case DEBUG_CAMPAIGN_0: { /* Campaign* debugCampaign = new Campaign(); World* world0 = new World(DEBUG_WORLD_0); world0->setNextStoryID(WORLD_ID_1); debugCampaign->addEntity(world0, WORLD_ID_0); World* world1 = new World(DEBUG_WORLD_1); world1->setNextStoryID(WORLD_ID_2); debugCampaign->addEntity(world1, WORLD_ID_1); World* world2 = new World(DEBUG_WORLD_2); world2->setNextStoryID(WORLD_ID_GAMEEND); debugCampaign->addEntity(world2, WORLD_ID_2); this->currentCampaign = debugCampaign; break;*/ } } } /** * starts the current entity * @returns error code if this action has caused a error */ ErrorMessage GameLoader::start() { if(this->currentCampaign != NULL) { this->currentCampaign->start(); } } /** * stops the current entity * @returns error code if this action has caused a error * * ATTENTION: this function shouldn't call other functions, or if so, they must return * after finishing. If you ignore or forget to do so, the current entity is not able to * terminate and it will run in the background or the ressources can't be freed or even * worse: are freed and the program will end in a segmentation fault! * hehehe, have ya seen it... :) */ void GameLoader::stop() { if(this->currentCampaign != NULL) this->currentCampaign->stop(); } /** * pause the current entity * @returns error code if this action has caused a error * * this pauses the current entity or passes this call forth to the running entity. */ ErrorMessage GameLoader::pause() { this->isPaused = true; if(this->currentCampaign != NULL) this->currentCampaign->pause(); } /** * resumes a pause * @returns error code if this action has caused a error * * this resumess the current entity or passes this call forth to the running entity. */ ErrorMessage GameLoader::resume() { this->isPaused = false; if(this->currentCampaign != NULL) this->currentCampaign->resume(); } /** * reads a campaign definition file into a campaign class * @param fileName to be loaded * @returns the loaded campaign * * this will interprete the map/campaign files and recursivly load a tree of worlds/campaigns */ Campaign* GameLoader::fileToCampaign(const std::string& fileName) { /* do not entirely load the campaign. just the current world before start of each world, it has to be initialized so it can load everything it needs into memory then. */ if( fileName.empty()) { PRINTF(2)("No filename specified for loading"); return NULL; } TiXmlDocument XMLDoc(fileName); // load the campaign document if( !XMLDoc.LoadFile(fileName)) { // report an error PRINTF(1)("Could not load XML File %s: %s @ %d:%d\n", fileName.c_str(), XMLDoc.ErrorDesc(), XMLDoc.ErrorRow(), XMLDoc.ErrorCol()); return NULL; } // check basic validity TiXmlElement* root = XMLDoc.RootElement(); assert( root != NULL); if( strcmp( root->Value(), "Campaign")) { // report an error PRINTF(2)("Specified XML File is not an orxonox campaign file (Campaign element missing)\n"); return NULL; } // construct campaign return new Campaign( root); } /** * handle keyboard commands * @param event the event to handle */ void GameLoader::process(const Event& event) { if( event.type == KeyMapper::PEV_NEXT_WORLD) { if( likely(event.bPressed)) { this->switchToNextLevel(); } } else if( event.type == KeyMapper::PEV_PAUSE) { if( likely(event.bPressed)) { if(this->isPaused) this->resume(); else this->pause(); } } else if( event.type == KeyMapper::PEV_QUIT) { if( event.bPressed) this->stop(); } else if (event.type == EV_MAIN_QUIT) this->stop(); } /** * this changes to the next level */ void GameLoader::switchToNextLevel() { if(this->currentCampaign != NULL) this->currentCampaign->switchToNextLevel(); }