some cleanups memory leak fixes and moving of source files
[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
21 #include <config.h>
22
23 #include <map>
24 #include <cstdlib>
25 #include <cstdio>
26 #include <cstring>
27 #include <iostream>
28 #include <fstream>
29 #include <stdexcept>
30
31 #include "app/globals.h"
32 #include "app/setup.h"
33 #include "video/screen.h"
34 #include "level.h"
35 #include "math/physic.h"
36 #include "scene.h"
37 #include "sector.h"
38 #include "tile.h"
39 #include "utils/lispreader.h"
40 #include "resources.h"
41 #include "utils/lispwriter.h"
42 #include "object/gameobjs.h"
43 #include "object/camera.h"
44 #include "object/tilemap.h"
45
46 using namespace std;
47
48 Level::Level()
49   : name("noname"), author("mr. x"), timelimit(500),
50     end_sequence_type(NONE_ENDSEQ_ANIM) 
51 {
52 }
53
54 void
55 Level::load(const std::string& filepath)
56 {
57   LispReader* level = LispReader::load(filepath, "supertux-level");
58
59   int version = 1;
60   level->read_int("version", version);
61   if(version == 1) {
62     load_old_format(*level);
63     delete level;
64     return;
65   }
66
67   for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur);
68       cur = lisp_cdr(cur)) {
69     std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
70     lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
71     LispReader reader(lisp_cdr(lisp_car(cur)));
72
73     if(token == "version") {
74       if(lisp_integer(data) > 2) {
75         std::cerr << "Warning: level format newer than application.\n";
76       }
77     } else if(token == "name") {
78       name = lisp_string(data);
79     } else if(token == "author") {
80       author = lisp_string(data);
81     } else if(token == "time") {
82       timelimit = lisp_integer(data);
83     } else if(token == "sector") {
84       Sector* sector = new Sector;
85       sector->parse(reader);
86       add_sector(sector);
87     } else if(token == "end-sequence-animation") {
88       std::string endsequencename = lisp_string(data);
89       if(endsequencename == "fireworks") {
90         end_sequence_type = FIREWORKS_ENDSEQ_ANIM;
91       } else {
92         std::cout << "Unknown endsequence type: '" << endsequencename <<
93           "'.\n";
94       }
95     } else {
96       std::cerr << "Unknown token '" << token << "' in level file.\n";
97       continue;
98     }
99   }
100   
101   delete level;
102 }
103
104 void
105 Level::load_old_format(LispReader& reader)
106 {
107   reader.read_string("name", name, true);
108   reader.read_string("author", author);
109   reader.read_int("time", timelimit);
110
111   Sector* sector = new Sector;
112   sector->parse_old_format(reader);
113   add_sector(sector);
114 }
115
116 void
117 Level::save(const std::string& filename)
118 {
119   std::string filepath = "levels/" + filename;
120   int last_slash = filepath.find_last_of('/');
121   FileSystem::fcreatedir(filepath.substr(0,last_slash).c_str());
122   filepath = st_dir + "/" + filepath;
123   ofstream file(filepath.c_str(), ios::out);
124   LispWriter* writer = new LispWriter(file);
125
126   writer->write_comment("Level made using SuperTux's built-in Level Editor");
127
128   writer->start_list("supertux-level");
129
130   int version = 2;
131   writer->write_int("version", version);
132
133   writer->write_string("name", name);
134   writer->write_string("author", author);
135   writer->write_int("time", timelimit);
136   writer->write_string("end-sequence-animation",
137       end_sequence_type == FIREWORKS_ENDSEQ_ANIM ? "fireworks" : "none");
138
139   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
140     writer->start_list("sector");
141     i->second->write(*writer);
142     writer->end_list("sector");
143   }
144
145   writer->end_list("supertux-level");
146
147   delete writer;
148   file.close();
149 }
150
151 Level::~Level()
152 {
153   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
154     delete i->second;
155 }
156
157 void
158 Level::do_vertical_flip()
159 {
160 #if 0
161   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
162     i->second->do_vertical_flip();
163 #endif
164 }
165
166 void
167 Level::add_sector(Sector* sector)
168 {
169   sectors.insert(std::make_pair(sector->get_name(), sector));       
170 }
171
172 Sector*
173 Level::get_sector(const std::string& name)
174 {
175   Sectors::iterator i = sectors.find(name);
176   if(i == sectors.end())
177     return 0;
178
179   return i->second;
180 }
181
182 Sector*
183 Level::get_next_sector(const Sector* sector)
184 {
185   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
186     {
187     if(i->second == sector)
188       {
189       i++;
190       if(i == sectors.end())
191         return NULL;
192       return i->second;
193       }
194     }
195   std::cerr << "Warning: Sector not found on level\n";
196   return NULL;
197 }
198
199 Sector*
200 Level::get_previous_sector(const Sector* sector)
201 {
202   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
203     {
204     if(i->second == sector)
205       {
206       if(i == sectors.begin())
207         return NULL;
208       i--;
209       return i->second;
210       }
211     }
212   std::cerr << "Warning: Sector not found on level\n";
213   return NULL;
214 }
215
216 int
217 Level::get_total_sectors()
218 {
219 return sectors.size();
220 }
221
222 int
223 Level::get_total_badguys()
224 {
225   int total_badguys = 0;
226   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
227     total_badguys += i->second->get_total_badguys();
228   return total_badguys;
229 }
230
231 int
232 Level::get_total_coins()
233 {
234   int total_coins = 0;
235   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i) {
236     TileMap* solids = i->second->solids;
237     assert(solids != 0);
238     for(size_t x = 0; x < solids->get_width(); ++x)
239       for(size_t y = 0; y < solids->get_height(); ++y) {
240         const Tile* tile = solids->get_tile(x, y);
241         if(tile == 0) {
242           std::cerr << "Invalid tile in sector '" << i->first << "'.\n";
243           continue;
244         }
245         if(tile->attributes & Tile::COIN)
246           total_coins++;
247       }
248   }
249   return total_coins;
250 }