Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

logic to show only certain levels and not all together, also not all shown levels have to be activated

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