Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/bindermFS16/src/orxonox/LevelManager.cc @ 11181

Last change on this file since 11181 was 11181, checked in by binderm, 8 years ago

some minor changes

  • Property svn:eol-style set to native
File size: 12.7 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Fabian 'x3n' Landau
24 *   Co-authors:
25 *      Damian 'Mozork' Frick
26 *
27 */
28
29/**
30    @file LevelManager.cc
31    @brief Implementation of the LevelManager singleton.
32*/
33
34#include "LevelManager.h"
35
36#include <map>
37
38#include "core/singleton/ScopedSingletonIncludes.h"
39#include "core/commandline/CommandLineIncludes.h"
40#include "core/config/ConfigValueIncludes.h"
41#include "core/CoreIncludes.h"
42#include "core/ClassTreeMask.h"
43#include "core/Loader.h"
44#include "core/Resource.h"
45#include "core/XMLFile.h"
46#include "Level.h"
47#include "PlayerManager.h"
48
49namespace orxonox
50{
51
52    LevelStatus::LevelStatus()
53    {
54        this->won = false;
55        this->nextLevels.insert(this->nextLevels.begin(),1);
56    }
57
58    LevelStatus::~LevelStatus()
59    {}
60
61
62    //check if index level is activated...
63    int LevelManager::missionactivate(int index)
64    {
65
66        if (allLevelStatus_[index].won)
67            return 1;
68
69        //check if level is activated
70        for(unsigned int i=0;i<allLevelStatus_.size();i++)
71        {
72            std::vector<int> nextLevels=allLevelStatus_[i].nextLevels;
73            bool won=allLevelStatus_[i].won;
74            if(nextLevels[index]==1&&won)
75                return 1;
76        };
77
78        //check if level visible but not activated
79        for(unsigned int i=0;i<allLevelStatus_.size();i++)
80        {
81            std::vector<int> nextLevels=allLevelStatus_[i].nextLevels;
82            bool won=allLevelStatus_[i].won;
83            if(nextLevels[index]==2&&won)
84                return 2;
85        };
86        return 0;
87    }
88
89    //updates the won variable of the corresponding LevelStatus in allLevelStatus_
90    void LevelManager::setLevelStatus(const int completedLevel)
91    {
92        allLevelStatus_[completedLevel].won=true;   
93    }
94
95    //build up allLevelStatus
96    //has to be done once per game (not per level)
97    //all connections between the levels are saved in here
98    void LevelManager::buildallLevelStatus()
99    {
100        LevelStatus level;
101        allLevelStatus_.assign (10,level);
102        allLevelStatus_[0].won=true;
103
104       
105        allLevelStatus_[1].nextLevels.push_back(2);
106        allLevelStatus_[1].nextLevels.push_back(2);
107        allLevelStatus_[1].nextLevels.push_back(1);
108        allLevelStatus_[1].nextLevels.push_back(2);
109
110
111    }
112
113
114
115    SetCommandLineArgument(level, "").shortcut("l").information("Default level file (overrides LevelManager::defaultLevelName_ configValue)");
116
117    ManageScopedSingleton(LevelManager, ScopeID::ROOT, false);
118
119    RegisterAbstractClass(LevelManager).inheritsFrom<Configurable>();
120
121    /**
122    @brief
123        Constructor. Registers the object, sets config values and initializes variables.
124    */
125    LevelManager::LevelManager()
126    {
127        RegisterObject(LevelManager);
128        this->setConfigValues();
129
130
131
132        // check override
133        if (!CommandLineParser::getArgument("level")->hasDefaultValue())
134        {
135            ModifyConfigValue(defaultLevelName_, tset, CommandLineParser::getValue("level").get<std::string>());
136        }
137
138        this->compileAvailableLevelList();
139        this->nextIndex_ = 0;
140        this->nextLevel_ = this->availableLevels_.begin();
141
142        buildallLevelStatus();
143    }
144
145
146    LevelManager::~LevelManager()
147    {
148        // Delete all the LevelInfoItem objects because the LevelManager created them
149        for (LevelInfoItem* info : availableLevels_)
150            info->destroy();
151    }
152
153    /**
154    @brief
155        Set the config values for this object.
156    */
157    void LevelManager::setConfigValues()
158    {
159        SetConfigValue(defaultLevelName_, "missionOne.oxw")
160            .description("Sets the pre selection of the level in the main menu.");
161        SetConfigValue(lastFinishedCampaignMission_,  "")
162            .description("The last finished mission of a campaign");
163        SetConfigValue(campaignMissions_,  std::vector<std::string>())
164            .description("The list of missions in the campaign");
165    }
166
167    /**
168     * @brief Stores the argument in the corresponding config value.
169     */
170    void LevelManager::setLastFinishedCampaignMission(const std::string& lastFinishedCampaignMission)
171    {
172        ModifyConfigValue(lastFinishedCampaignMission_, set, lastFinishedCampaignMission);
173    }
174
175
176
177    /**
178    @brief
179        Request activity for the input Level.
180        The Level will be added to the list of Levels whose activity is requested. The list is accessed in a FIFO manner.
181        If the Level is the only Level in the list it will be immediately activated. If not it will be activated as soon as it reaches the front of the list.
182    @param level
183        A pointer to the Level whose activity is requested.
184    */
185    void LevelManager::requestActivity(Level* level)
186    {
187        assert( std::find(this->levels_.begin(), this->levels_.end(), level)==this->levels_.end() );
188        // If the level is already in list.
189        if( std::find(this->levels_.begin(), this->levels_.end(), level)!=this->levels_.end() )
190            return;
191        // If it isn't insert it at the back.
192        this->levels_.push_back(level);
193        // If it is the only level in the list activate it.
194        if (this->levels_.size() == 1)
195            this->activateNextLevel();
196    }
197
198    /**
199    @brief
200        Release activity for the input Level.
201        Removes the Level from the list. If the Level was the one currently active, it is deactivated and the next Level in line is activated.
202    @param level
203        A pointer to the Level whose activity is to be released.
204    */
205    void LevelManager::releaseActivity(Level* level)
206    {
207        if (this->levels_.size() > 0)
208        {
209            // If the level is the active level in the front of the list.
210            if (this->levels_.front() == level)
211            {
212                // Deactivate it, remove it from the list and activate the next level in line.
213                level->setActive(false);
214                this->levels_.pop_front();
215                this->activateNextLevel();
216            }
217            else // Else just remove it from the list.
218                this->levels_.erase(std::find(this->levels_.begin(), this->levels_.end(), level));
219        }
220    }
221
222    /**
223    @brief
224        Get the currently active Level.
225    @return
226        Returns a pointer to the currently active level or nullptr if there currently are no active Levels.
227    */
228    Level* LevelManager::getActiveLevel()
229    {
230        if (this->levels_.size() > 0)
231            return this->levels_.front();
232        else
233            return nullptr;
234    }
235
236    /**
237    @brief
238        Activate the next Level.
239    */
240    void LevelManager::activateNextLevel()
241    {
242        if (this->levels_.size() > 0)
243        {
244            // Activate the level that is the first in the list of levels whose activity has been requested.
245            this->levels_.front()->setActive(true);
246            // Make every player enter the newly activated level.
247            for (const auto& mapEntry : PlayerManager::getInstance().getClients())
248                this->levels_.front()->playerEntered(mapEntry.second);
249        }
250    }
251
252    /**
253    @brief
254        Set the default Level.
255    @param levelName
256        The filename of the default Level.
257    */
258    void LevelManager::setDefaultLevel(const std::string& levelName)
259    {
260        ModifyConfigValue(defaultLevelName_, set, levelName);
261    }
262
263    /**
264    @brief
265        Get the number of available Levels.
266        Also updates the list of available Levels.
267    @return
268        Returns the number of available Levels.
269    */
270    unsigned int LevelManager::getNumberOfLevels()
271    {
272        this->updateAvailableLevelList();
273
274        return this->availableLevels_.size();
275    }
276
277    /**
278    @brief
279        Get the LevelInfoItem at the given index in the list of available Levels.
280        The LevelInfoItems are sorted in alphabetical order accoridng to the name of the Level.
281        This method is most efficiently called with consecutive indices (or at least ascending indices).
282    @param index
283        The index of the item that should be returned.
284    @return
285        Returns a pointer to the LevelInfoItem at the given index.
286    */
287    LevelInfoItem* LevelManager::getAvailableLevelListItem(unsigned int index)
288    {
289        if(index >= this->availableLevels_.size())
290            return nullptr;
291
292        // If this index directly follows the last we can optimize a lot.
293        if(index == this->nextIndex_)
294        {
295            this->nextIndex_++;
296            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
297            this->nextLevel_++;
298            return *it;
299        }
300        else
301        {
302            // If this index is bigger than the last, we can optimize a little.
303            if(index < this->nextIndex_)
304            {
305                this->nextIndex_ = 0;
306                this->nextLevel_ = this->availableLevels_.begin();
307            }
308
309            while(this->nextIndex_ != index)
310            {
311                this->nextIndex_++;
312                this->nextLevel_++;
313            }
314            this->nextIndex_++;
315            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
316            this->nextLevel_++;
317            return *it;
318        }
319    }
320
321    /**
322    @brief
323        Compile the list of available Levels.
324        Iterates over all *.oxw files, loads the LevelInfo objects in them and from that it creates the LevelInfoItems which are inserted in a list.
325    */
326    void LevelManager::compileAvailableLevelList()
327    {
328        // Get all files matching the level criteria
329        Ogre::StringVectorPtr levels = Resource::findResourceNames("*.oxw");
330
331        // We only want to load as little as possible
332        ClassTreeMask mask;
333        mask.exclude(Class(BaseObject));
334        mask.include(Class(LevelInfo));
335
336        // Iterate over all the found *.oxw files
337        orxout(internal_info) << "Loading LevelInfos..." << endl;
338        std::set<std::string> names;
339        for (Ogre::StringVector::const_iterator it = levels->begin(); it != levels->end(); ++it)
340        {
341            // TODO: Replace with tag?
342            if (it->find("old/") != 0)
343            {
344                LevelInfoItem* info = nullptr;
345
346                // Load the LevelInfo object from the level file.
347                XMLFile file = XMLFile(*it);
348                Loader::getInstance().load(&file, mask, false, true);
349
350                // Find the LevelInfo object we've just loaded (if there was one)
351                for(LevelInfo* levelInfo : ObjectList<LevelInfo>())
352                    if(levelInfo->getXMLFilename() == *it)
353                        info = levelInfo->copy();
354
355                // We don't need the loaded stuff anymore
356                Loader::getInstance().unload(&file);
357
358                if(info == nullptr)
359                {
360                    // Create a default LevelInfoItem object that merely contains the name
361                    std::string filenameWOExtension = it->substr(0, it->find(".oxw"));
362                    info = new LevelInfoItem(filenameWOExtension, *it);
363                }
364
365                // Warn about levels with the same name.
366                if(!names.insert(info->getName()).second)
367                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with name '" << info->getName() << "' found!" << endl;
368
369                // Warn about multiple items so that it gets fixed quickly
370                if(availableLevels_.find(info) != availableLevels_.end())
371                {
372                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with same name '" << info->getName() << "' and filename found! Exluding..." << endl;
373                    // Delete LevelInfoItem to avoid a dangling pointer
374                    delete info;
375                }
376                else
377                    this->availableLevels_.insert(info);
378            }
379        }
380    }
381
382    /**
383    @brief
384        Update the list of available Levels.
385    */
386    void LevelManager::updateAvailableLevelList(void)
387    {
388        //TODO: Implement some kind of update?
389    }
390}
Note: See TracBrowser for help on using the repository browser.