Merged changes from branches/supertux-milestone2-grumbel/ to trunk/supertux/
[supertux.git] / src / supertux / level.cpp
1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
17 #include "supertux/level.hpp"
18
19 #include "lisp/list_iterator.hpp"
20 #include "lisp/parser.hpp"
21 #include "object/block.hpp"
22 #include "object/coin.hpp"
23 #include "supertux/sector.hpp"
24 #include "supertux/tile_manager.hpp"
25 #include "supertux/tile_set.hpp"
26 #include "trigger/secretarea_trigger.hpp"
27
28 using namespace std;
29
30 Level::Level() :
31   name("noname"), 
32   author("Mr. X"), 
33   tileset(NULL), 
34   free_tileset(false)
35 {
36 }
37
38 Level::~Level()
39 {
40   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
41     delete *i;
42   if(free_tileset)
43     delete tileset;
44 }
45
46 void
47 Level::load(const std::string& filepath)
48 {
49   try {
50     filename = filepath;
51     lisp::Parser parser;
52     const lisp::Lisp* root = parser.parse(filepath);
53
54     const lisp::Lisp* level = root->get_lisp("supertux-level");
55     if(!level)
56       throw std::runtime_error("file is not a supertux-level file.");
57
58     int version = 1;
59     level->get("version", version);
60     if(version == 1) {
61       log_info << "level uses old format: version 1" << std::endl;
62       tileset = tile_manager->get_tileset("images/tiles.strf");
63       load_old_format(*level);
64       return;
65     }
66
67     const lisp::Lisp* tilesets_lisp = level->get_lisp("tilesets");
68     if(tilesets_lisp != NULL) {
69       tileset      = tile_manager->parse_tileset_definition(*tilesets_lisp);
70       free_tileset = true;
71     }
72     std::string tileset_name;
73     if(level->get("tileset", tileset_name)) {
74       if(tileset != NULL) {
75         log_warning << "multiple tilesets specified in level" << std::endl;
76       } else {
77         tileset = tile_manager->get_tileset(tileset_name);
78       }
79     }
80     /* load default tileset */
81     if(tileset == NULL) {
82       tileset = tile_manager->get_tileset("images/tiles.strf");
83     }
84     current_tileset = tileset;
85
86     contact = "";
87     license = "";
88
89     lisp::ListIterator iter(level);
90     while(iter.next()) {
91       const std::string& token = iter.item();
92       if(token == "version") {
93         iter.value()->get(version);
94         if(version > 2) {
95           log_warning << "level format newer than application" << std::endl;
96         }
97       } else if(token == "tileset" || token == "tilesets") {
98         continue;
99       } else if(token == "name") {
100         iter.value()->get(name);
101       } else if(token == "author") {
102         iter.value()->get(author);
103       } else if(token == "contact") {
104         iter.value()->get(contact);
105       } else if(token == "license") {
106         iter.value()->get(license);
107       } else if(token == "on-menukey-script") {
108         iter.value()->get(on_menukey_script);
109       } else if(token == "sector") {
110         Sector* sector = new Sector(this);
111         sector->parse(*(iter.lisp()));
112         add_sector(sector);
113       } else {
114         log_warning << "Unknown token '" << token << "' in level file" << std::endl;
115       }
116     }
117
118     if (license == "") {
119       log_warning << "The level author did not specify a license for this level. You might not be allowed to share it." << std::endl;
120
121     }
122   } catch(std::exception& e) {
123     std::stringstream msg;
124     msg << "Problem when reading level '" << filepath << "': " << e.what();
125     throw std::runtime_error(msg.str());
126   }
127
128   current_tileset = NULL;
129 }
130
131 void
132 Level::load_old_format(const Reader& reader)
133 {
134   reader.get("name", name);
135   reader.get("author", author);
136
137   Sector* sector = new Sector(this);
138   sector->parse_old_format(reader);
139   add_sector(sector);
140 }
141
142 void
143 Level::add_sector(Sector* sector)
144 {
145   Sector* test = get_sector(sector->get_name());
146   if(test != 0) {
147     throw std::runtime_error("Trying to add 2 sectors with same name");
148   }
149   sectors.push_back(sector);
150 }
151
152 Sector*
153 Level::get_sector(const std::string& name)
154 {
155   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
156     Sector* sector = *i;
157     if(sector->get_name() == name)
158       return sector;
159   }
160
161   return 0;
162 }
163
164 size_t
165 Level::get_sector_count()
166 {
167   return sectors.size();
168 }
169
170 Sector*
171 Level::get_sector(size_t num)
172 {
173   return sectors.at(num);
174 }
175
176 int
177 Level::get_total_coins()
178 {
179   int total_coins = 0;
180   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
181     Sector* sector = *i;
182     for(Sector::GameObjects::iterator o = sector->gameobjects.begin();
183         o != sector->gameobjects.end(); ++o) {
184       Coin* coin = dynamic_cast<Coin*> (*o);
185       if(coin)
186       {
187         total_coins++;
188         continue;
189       }
190       BonusBlock *block = dynamic_cast<BonusBlock*> (*o);
191       if(block)
192       {
193         if (block->contents == BonusBlock::CONTENT_COIN)
194         {
195           total_coins++;
196           continue;
197         }
198 #if 0
199         // FIXME: do we want this? q.v. src/object/oneup.cpp
200         else if (block->contents == BonusBlock::CONTENT_1UP)
201         {
202           total_coins += 100;
203           continue;
204         }
205 #endif
206       }
207     }
208   }
209   return total_coins;
210 }
211
212 int
213 Level::get_total_badguys()
214 {
215   int total_badguys = 0;
216   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
217     total_badguys += (*i)->get_total_badguys();
218   return total_badguys;
219 }
220
221 int
222 Level::get_total_secrets()
223 {
224   int total_secrets = 0;
225   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
226     total_secrets += (*i)->get_total_count<SecretAreaTrigger>();
227   return total_secrets;
228 }
229
230 /* EOF */