Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/archive/Presentation_FS16/src/orxonox/LevelManager.cc @ 11642

Last change on this file since 11642 was 11206, checked in by fvultier, 9 years ago

merged campain menu

  • Property svn:eol-style set to native
File size: 14.0 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 *      Matthias Binder
27 *
28 */
29
30/**
31    @file LevelManager.cc
32    @brief Implementation of the LevelManager singleton.
33*/
34
35#include "LevelManager.h"
36#include "LevelStatus.h"
37
38#include <map>
39
40#include "core/singleton/ScopedSingletonIncludes.h"
41#include "core/commandline/CommandLineIncludes.h"
42#include "core/config/ConfigValueIncludes.h"
43#include "core/CoreIncludes.h"
44#include "core/ClassTreeMask.h"
45#include "core/Loader.h"
46#include "core/Resource.h"
47#include "core/XMLFile.h"
48#include "Level.h"
49#include "PlayerManager.h"
50
51
52namespace orxonox
53{
54
55
56
57
58    SetCommandLineArgument(level, "").shortcut("l").information("Default level file (overrides LevelManager::defaultLevelName_ configValue)");
59
60    ManageScopedSingleton(LevelManager, ScopeID::ROOT, false);
61
62    RegisterAbstractClass(LevelManager).inheritsFrom<Configurable>();
63
64    /**
65    @brief
66        Constructor. Registers the object, sets config values and initializes variables.
67    */
68    LevelManager::LevelManager()
69    {
70        RegisterObject(LevelManager);
71        this->setConfigValues();
72
73
74
75        // check override
76        if (!CommandLineParser::getArgument("level")->hasDefaultValue())
77        {
78            ModifyConfigValue(defaultLevelName_, tset, CommandLineParser::getValue("level").get<std::string>());
79        }
80
81        this->compileAvailableLevelList();
82        this->nextIndex_ = 0;
83        this->nextLevel_ = this->availableLevels_.begin();
84
85        buildallLevelStatus();
86    }
87
88
89    LevelManager::~LevelManager()
90    {
91        // Delete all the LevelInfoItem objects because the LevelManager created them
92        for (LevelInfoItem* info : availableLevels_)
93            info->destroy();
94        for(unsigned int i = 0; i<allLevelStatus_.size();++i)
95        {
96            allLevelStatus_[i]->destroy();
97        }
98    }
99
100    /**
101    @brief
102        Set the config values for this object.
103    */
104    void LevelManager::setConfigValues()
105    {
106
107        SetConfigValue(defaultLevelName_, "missionOne.oxw")
108            .description("Sets the pre selection of the level in the main menu.");
109        SetConfigValue(lastWonMission_,  "")
110            .description("The last finished mission of a campaign");
111        SetConfigValue(campaignMissions_,  std::vector<std::string>())
112            .description("The list of missions in the campaign");
113    }
114
115
116    /**
117    @brief
118        Request activity for the input Level.
119        The Level will be added to the list of Levels whose activity is requested. The list is accessed in a FIFO manner.
120        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.
121    @param level
122        A pointer to the Level whose activity is requested.
123    */
124    void LevelManager::requestActivity(Level* level)
125    {
126        assert( std::find(this->levels_.begin(), this->levels_.end(), level)==this->levels_.end() );
127        // If the level is already in list.
128        if( std::find(this->levels_.begin(), this->levels_.end(), level)!=this->levels_.end() )
129            return;
130        // If it isn't insert it at the back.
131        this->levels_.push_back(level);
132        // If it is the only level in the list activate it.
133        if (this->levels_.size() == 1)
134            this->activateNextLevel();
135    }
136
137    /**
138    @brief
139        Release activity for the input Level.
140        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.
141    @param level
142        A pointer to the Level whose activity is to be released.
143    */
144    void LevelManager::releaseActivity(Level* level)
145    {
146        if (this->levels_.size() > 0)
147        {
148            // If the level is the active level in the front of the list.
149            if (this->levels_.front() == level)
150            {
151                // Deactivate it, remove it from the list and activate the next level in line.
152                level->setActive(false);
153                this->levels_.pop_front();
154                this->activateNextLevel();
155            }
156            else // Else just remove it from the list.
157                this->levels_.erase(std::find(this->levels_.begin(), this->levels_.end(), level));
158        }
159    }
160
161    /**
162    @brief
163        Get the currently active Level.
164    @return
165        Returns a pointer to the currently active level or nullptr if there currently are no active Levels.
166    */
167    Level* LevelManager::getActiveLevel()
168    {
169        if (this->levels_.size() > 0)
170            return this->levels_.front();
171        else
172            return nullptr;
173    }
174
175    /**
176    @brief
177        Activate the next Level.
178    */
179    void LevelManager::activateNextLevel()
180    {
181
182        if (this->levels_.size() > 0)
183        {
184            // Activate the level that is the first in the list of levels whose activity has been requested.
185            this->levels_.front()->setActive(true);
186            // Make every player enter the newly activated level.
187            for (const auto& mapEntry : PlayerManager::getInstance().getClients())
188                this->levels_.front()->playerEntered(mapEntry.second);
189        }
190    }
191
192    /**
193    @brief
194        Set the default Level.
195    @param levelName
196        The filename of the default Level.
197    */
198    void LevelManager::setDefaultLevel(const std::string& levelName)
199    {
200        ModifyConfigValue(defaultLevelName_, set, levelName);
201    }
202
203    /**
204    @brief
205        Get the number of available Levels.
206        Also updates the list of available Levels.
207    @return
208        Returns the number of available Levels.
209    */
210    unsigned int LevelManager::getNumberOfLevels()
211    {
212        this->updateAvailableLevelList();
213
214        return this->availableLevels_.size();
215    }
216
217    /**
218    @brief
219        Get the LevelInfoItem at the given index in the list of available Levels.
220        The LevelInfoItems are sorted in alphabetical order accoridng to the name of the Level.
221        This method is most efficiently called with consecutive indices (or at least ascending indices).
222    @param index
223        The index of the item that should be returned.
224    @return
225        Returns a pointer to the LevelInfoItem at the given index.
226    */
227    LevelInfoItem* LevelManager::getAvailableLevelListItem(unsigned int index)
228    {
229        if(index >= this->availableLevels_.size())
230            return nullptr;
231
232        // If this index directly follows the last we can optimize a lot.
233        if(index == this->nextIndex_)
234        {
235            this->nextIndex_++;
236            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
237            this->nextLevel_++;
238            return *it;
239        }
240        else
241        {
242            // If this index is bigger than the last, we can optimize a little.
243            if(index < this->nextIndex_)
244            {
245                this->nextIndex_ = 0;
246                this->nextLevel_ = this->availableLevels_.begin();
247            }
248
249            while(this->nextIndex_ != index)
250            {
251                this->nextIndex_++;
252                this->nextLevel_++;
253            }
254            this->nextIndex_++;
255            std::set<LevelInfoItem*, LevelInfoCompare>::iterator it = this->nextLevel_;
256            this->nextLevel_++;
257            return *it;
258        }
259    }
260
261    /**
262    @brief
263        Compile the list of available Levels.
264        Iterates over all *.oxw files, loads the LevelInfo objects in them and from that it creates the LevelInfoItems which are inserted in a list.
265    */
266    void LevelManager::compileAvailableLevelList()
267    {
268        // Get all files matching the level criteria
269        Ogre::StringVectorPtr levels = Resource::findResourceNames("*.oxw");
270
271        // We only want to load as little as possible
272        ClassTreeMask mask;
273        mask.exclude(Class(BaseObject));
274        mask.include(Class(LevelInfo));
275
276        // Iterate over all the found *.oxw files
277        orxout(internal_info) << "Loading LevelInfos..." << endl;
278        std::set<std::string> names;
279        for (Ogre::StringVector::const_iterator it = levels->begin(); it != levels->end(); ++it)
280        {
281            // TODO: Replace with tag?
282            if (it->find("old/") != 0)
283            {
284                LevelInfoItem* info = nullptr;
285
286                // Load the LevelInfo object from the level file.
287                XMLFile file = XMLFile(*it);
288                Loader::getInstance().load(&file, mask, false, true);
289
290                // Find the LevelInfo object we've just loaded (if there was one)
291                for(LevelInfo* levelInfo : ObjectList<LevelInfo>())
292                    if(levelInfo->getXMLFilename() == *it)
293                        info = levelInfo->copy();
294
295                // We don't need the loaded stuff anymore
296                Loader::getInstance().unload(&file);
297
298                if(info == nullptr)
299                {
300                    // Create a default LevelInfoItem object that merely contains the name
301                    std::string filenameWOExtension = it->substr(0, it->find(".oxw"));
302                    info = new LevelInfoItem(filenameWOExtension, *it);
303                }
304
305                // Warn about levels with the same name.
306                if(!names.insert(info->getName()).second)
307                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with name '" << info->getName() << "' found!" << endl;
308
309                // Warn about multiple items so that it gets fixed quickly
310                if(availableLevels_.find(info) != availableLevels_.end())
311                {
312                    orxout(internal_warning) << "Multiple levels (" << info->getXMLFilename() << ") with same name '" << info->getName() << "' and filename found! Exluding..." << endl;
313                    // Delete LevelInfoItem to avoid a dangling pointer
314                    delete info;
315                }
316                else
317                    this->availableLevels_.insert(info);
318            }
319        }
320    }
321
322    /**
323    @brief
324        Update the list of available Levels.
325    */
326    void LevelManager::updateAvailableLevelList(void)
327    {
328        //TODO: Implement some kind of update?
329    }
330
331
332
333    /**
334    @brief
335        first updates allLevelStatus and then check if the level with index i is activated
336    */
337    int LevelManager::missionactivate(int index)
338    {
339        updateAllLevelStatus();
340        int activated = allLevelStatus_[index]->activated;
341        return activated;
342    }
343    /**
344    @brief
345        update the last won mission to won=true
346    */
347
348    void LevelManager::updatewon(int lastwon)
349    {
350        allLevelStatus_[lastwon]->won=true;
351
352    }
353
354    /**
355    @brief
356        checks if a level is won
357        if a level is won, the other levels should be shown as saved in 'nextLevels' of the won level
358        therefore 'activated' of all other levels will be updated to the correct value
359        if more than one level is won, the level with the highes index decides which other levels will be shown, activated or not activated
360    */
361
362    void LevelManager::updateAllLevelStatus()
363    {
364        for(unsigned int i =0;i<allLevelStatus_.size();i++)
365        {
366            if(allLevelStatus_[i]->won)
367            {
368                allLevelStatus_[i]->activated=1;
369                std::vector<int> nextLevels=allLevelStatus_[i]->nextLevels;
370                for(unsigned int j=0;j<allLevelStatus_.size();j++)
371                {
372                    allLevelStatus_[j]->activated=nextLevels[j];
373                }
374            }
375        }
376    }
377
378    /**
379    @brief
380        the name of the last won mission is saved in the config file
381    */
382
383    void LevelManager::setLevelStatus(const std::string& LevelWon)
384    {
385       
386           
387        ModifyConfigValue(lastWonMission_, set, LevelWon);
388
389        /**
390        TODO: save allLevelWon_ into the config file
391        */
392    }
393
394
395    /**
396    @brief
397        build up allLevelStatus_
398        has to be done once per game (not per level)
399        all connections between the levels are saved in the allLevelStatus_
400        also the won variable of the LevelStatus have to be set to the corresponding allLevelWon_ values
401    */
402    void LevelManager::buildallLevelStatus()
403    {
404        for(unsigned int i =0;i<campaignMissions_.size();++i)
405        {
406            LevelStatus* level= new LevelStatus(this->getContext());
407            allLevelStatus_.push_back(level);
408        }
409
410        /**
411        TODO: allLevelWon_ should be loaded into the allLevelSatus_ such that the progress of the campaign can be saved
412        */
413
414        allLevelStatus_[0]->activated=1;
415
416
417        std::vector<int> v={1,1,1,0,0,0,0,0,0};
418        allLevelStatus_[0]->nextLevels=v;
419
420        v={1,1,2,1,0,0,0,0,0};
421        allLevelStatus_[1]->nextLevels=v;
422
423        v={1,2,1,0,1,0,0,0,0};
424        allLevelStatus_[2]->nextLevels=v;
425
426        v={1,1,2,1,0,1,1,0,0};
427        allLevelStatus_[3]->nextLevels=v;
428
429        v={1,2,1,0,1,0,0,1,1};
430        allLevelStatus_[4]->nextLevels=v;
431
432        v={1,1,2,1,0,1,2,0,0};
433        allLevelStatus_[5]->nextLevels=v;
434
435        v={1,1,2,1,0,2,1,0,0};
436        allLevelStatus_[6]->nextLevels=v;
437
438        v={1,2,1,0,1,0,0,1,2};
439        allLevelStatus_[7]->nextLevels=v;
440
441        v={1,2,1,0,1,0,0,2,1};
442        allLevelStatus_[8]->nextLevels=v;
443
444    }
445}
Note: See TracBrowser for help on using the repository browser.