added/updated some .cvsignores
[supertux.git] / src / level.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2004 SuperTux Development Team, see AUTHORS for details
5 //
6 //  This program is free software; you can redistribute it and/or
7 //  modify it under the terms of the GNU General Public License
8 //  as published by the Free Software Foundation; either version 2
9 //  of the License, or (at your option) any later version.
10 //
11 //  This program is distributed in the hope that it will be useful,
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 //  GNU General Public License for more details.
15 // 
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program; if not, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20 #include <config.h>
21
22 #include <map>
23 #include <cstdlib>
24 #include <cstdio>
25 #include <cstring>
26 #include <iostream>
27 #include <fstream>
28 #include <sstream>
29 #include <memory>
30 #include <stdexcept>
31
32 #include "app/globals.h"
33 #include "app/setup.h"
34 #include "video/screen.h"
35 #include "lisp/parser.h"
36 #include "lisp/lisp.h"
37 #include "lisp/list_iterator.h"
38 #include "lisp/writer.h"
39 #include "level.h"
40 #include "math/physic.h"
41 #include "scene.h"
42 #include "sector.h"
43 #include "tile.h"
44 #include "resources.h"
45 #include "object/gameobjs.h"
46 #include "object/camera.h"
47 #include "object/tilemap.h"
48 #include "object/coin.h"
49
50 using namespace std;
51
52 Level::Level()
53   : name("noname"), author("mr. x"), timelimit(500),
54     end_sequence_type(NONE_ENDSEQ_ANIM) 
55 {
56 }
57
58 void
59 Level::load(const std::string& filepath)
60 {
61   try {
62     lisp::Parser parser;
63     std::auto_ptr<lisp::Lisp> root (parser.parse(filepath));
64
65     const lisp::Lisp* level = root->get_lisp("supertux-level");
66     if(!level)
67       throw std::runtime_error("file is not a supertux-level file.");
68
69     int version = 1;
70     level->get("version", version);
71     if(version == 1) {
72       load_old_format(*level);
73       return;
74     }
75
76     lisp::ListIterator iter(level);
77     while(iter.next()) {
78       const std::string& token = iter.item();
79       if(token == "version") {
80         iter.value()->get(version);
81         if(version > 2) {
82           std::cerr << "Warning: level format newer than application.\n";
83         }
84       } else if(token == "name") {
85         iter.value()->get(name);
86       } else if(token == "author") {
87         iter.value()->get(author);
88       } else if(token == "time") {
89         iter.value()->get(timelimit);
90       } else if(token == "sector") {
91         Sector* sector = new Sector;
92         sector->parse(*(iter.lisp()));
93         add_sector(sector);
94       } else if(token == "end-sequence-animation") {
95         std::string endsequencename;
96         iter.value()->get(endsequencename);
97         if(endsequencename == "fireworks") {
98           end_sequence_type = FIREWORKS_ENDSEQ_ANIM;
99         } else {
100           std::cout << "Unknown endsequence type: '" << endsequencename <<
101             "'.\n";
102         }
103       } else {
104         std::cerr << "Unknown token '" << token << "' in level file.\n";
105         continue;
106       }
107     }
108   } catch(std::exception& e) {
109     std::stringstream msg;
110     msg << "Problem when reading level '" << filepath << "': " << e.what();
111     throw std::runtime_error(msg.str());
112   }
113 }
114
115 void
116 Level::load_old_format(const lisp::Lisp& reader)
117 {
118   reader.get("name", name);
119   reader.get("author", author);
120   reader.get("time", timelimit);
121
122   Sector* sector = new Sector;
123   sector->parse_old_format(reader);
124   add_sector(sector);
125 }
126
127 void
128 Level::save(const std::string& filename)
129 {
130   std::string filepath = "levels/" + filename;
131   int last_slash = filepath.find_last_of('/');
132   FileSystem::fcreatedir(filepath.substr(0,last_slash).c_str());
133   filepath = st_dir + "/" + filepath;
134   ofstream file(filepath.c_str(), ios::out);
135   lisp::Writer* writer = new lisp::Writer(file);
136
137   writer->write_comment("Level made using SuperTux's built-in Level Editor");
138
139   writer->start_list("supertux-level");
140
141   int version = 2;
142   writer->write_int("version", version);
143
144   writer->write_string("name", name, true);
145   writer->write_string("author", author);
146   writer->write_int("time", timelimit);
147   writer->write_string("end-sequence-animation",
148       end_sequence_type == FIREWORKS_ENDSEQ_ANIM ? "fireworks" : "none");
149
150   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
151     writer->start_list("sector");
152     i->second->write(*writer);
153     writer->end_list("sector");
154   }
155
156   writer->end_list("supertux-level");
157
158   delete writer;
159   file.close();
160 }
161
162 Level::~Level()
163 {
164   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
165     delete i->second;
166 }
167
168 void
169 Level::add_sector(Sector* sector)
170 {
171   sectors.insert(std::make_pair(sector->get_name(), sector));       
172 }
173
174 Sector*
175 Level::get_sector(const std::string& name)
176 {
177   Sectors::iterator i = sectors.find(name);
178   if(i == sectors.end())
179     return 0;
180
181   return i->second;
182 }
183
184 Sector*
185 Level::get_next_sector(const Sector* sector)
186 {
187   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
188     {
189     if(i->second == sector)
190       {
191       i++;
192       if(i == sectors.end())
193         return NULL;
194       return i->second;
195       }
196     }
197   std::cerr << "Warning: Sector not found on level\n";
198   return NULL;
199 }
200
201 Sector*
202 Level::get_previous_sector(const Sector* sector)
203 {
204   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
205     {
206     if(i->second == sector)
207       {
208       if(i == sectors.begin())
209         return NULL;
210       i--;
211       return i->second;
212       }
213     }
214   std::cerr << "Warning: Sector not found on level\n";
215   return NULL;
216 }
217
218 int
219 Level::get_total_sectors()
220 {
221 return sectors.size();
222 }
223
224 int
225 Level::get_total_badguys()
226 {
227   int total_badguys = 0;
228   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
229     total_badguys += i->second->get_total_badguys();
230   return total_badguys;
231 }
232
233 int
234 Level::get_total_coins()
235 {
236   int total_coins = 0;
237   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
238     Sector* sector = i->second;
239     for(Sector::GameObjects::iterator o = sector->gameobjects.begin();
240         o != sector->gameobjects.end(); ++o) {
241       Coin* coin = dynamic_cast<Coin*> (*o);
242       if(coin)
243         total_coins++;
244     }
245   }
246   return total_coins;
247 }