b2748d9ef3191cd5033e20045d35d732cc4d3331
[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 <map>
22 #include <cstdlib>
23 #include <cstdio>
24 #include <cstring>
25 #include <iostream>
26 #include <fstream>
27 #include <stdexcept>
28
29 #include "globals.h"
30 #include "setup.h"
31 #include "camera.h"
32 #include "screen/screen.h"
33 #include "level.h"
34 #include "physic.h"
35 #include "scene.h"
36 #include "sector.h"
37 #include "tile.h"
38 #include "lispreader.h"
39 #include "resources.h"
40 #include "gameobjs.h"
41 #include "lispwriter.h"
42
43 using namespace std;
44
45 LevelSubset::LevelSubset()
46     : image(0), levels(0)
47 {
48 }
49
50 LevelSubset::~LevelSubset()
51 {
52   delete image;
53 }
54
55 void LevelSubset::create(const std::string& subset_name)
56 {
57   Level new_lev;
58   LevelSubset new_subset;
59   new_subset.name = subset_name;
60   new_subset.title = "Unknown Title";
61   new_subset.description = "No description so far.";
62   new_subset.save();
63   //new_lev.save(subset_name, 1, 0);
64 }
65
66 void LevelSubset::parse (lisp_object_t* cursor)
67 {
68   while(!lisp_nil_p(cursor))
69     {
70       lisp_object_t* cur = lisp_car(cursor);
71       char *s;
72
73       if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
74         {
75           printf("Not good");
76         }
77       else
78         {
79           if (strcmp(lisp_symbol(lisp_car(cur)), "title") == 0)
80             {
81               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
82                 {
83                   title = s;
84                 }
85             }
86           else if (strcmp(lisp_symbol(lisp_car(cur)), "description") == 0)
87             {
88               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
89                 {
90                   description = s;
91                 }
92             }
93         }
94       cursor = lisp_cdr (cursor);
95     }
96 }
97
98 void LevelSubset::load(const char* subset)
99 {
100   FILE* fi;
101   char filename[1024];
102   char str[1024];
103   int i;
104   lisp_object_t* root_obj = 0;
105
106   name = subset;
107
108   snprintf(filename, 1024, "%s/levels/%s/info", st_dir, subset);
109   if(!faccessible(filename))
110     snprintf(filename, 1024, "%s/levels/%s/info", datadir.c_str(), subset);
111   if(faccessible(filename))
112     {
113       fi = fopen(filename, "r");
114       if (fi == NULL)
115         {
116           perror(filename);
117         }
118       lisp_stream_t stream;
119       lisp_stream_init_file (&stream, fi);
120       root_obj = lisp_read (&stream);
121
122       if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
123         {
124           printf("World: Parse Error in file %s", filename);
125         }
126
127       lisp_object_t* cur = lisp_car(root_obj);
128
129       if (!lisp_symbol_p (cur))
130         {
131           printf("World: Read error in %s",filename);
132         }
133
134       if (strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
135         {
136           parse(lisp_cdr(root_obj));
137
138         }
139
140       lisp_free(root_obj);
141       fclose(fi);
142
143       snprintf(str, 1024, "%s.png", filename);
144       if(faccessible(str))
145         {
146           delete image;
147           image = new Surface(str,IGNORE_ALPHA);
148         }
149       else
150         {
151           snprintf(filename, 1024, "%s/images/status/level-subset-info.png", datadir.c_str());
152           delete image;
153           image = new Surface(filename,IGNORE_ALPHA);
154         }
155     }
156
157   for(i=1; i != -1; ++i)
158     {
159       /* Get the number of levels in this subset */
160       snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset,i);
161       if(!faccessible(filename))
162         {
163           snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset,i);
164           if(!faccessible(filename))
165             break;
166         }
167     }
168   levels = --i;
169 }
170
171 void
172 LevelSubset::save()
173 {
174   FILE* fi;
175   string filename;
176
177   /* Save data file: */
178   filename = "/levels/" + name + "/";
179
180   fcreatedir(filename.c_str());
181   filename = string(st_dir) + "/levels/" + name + "/info";
182   if(!fwriteable(filename.c_str()))
183     filename = datadir + "/levels/" + name + "/info";
184   if(fwriteable(filename.c_str()))
185     {
186       fi = fopen(filename.c_str(), "w");
187       if (fi == NULL)
188         {
189           perror(filename.c_str());
190         }
191
192       /* Write header: */
193       fprintf(fi,";SuperTux-Level-Subset\n");
194       fprintf(fi,"(supertux-level-subset\n");
195
196       /* Save title info: */
197       fprintf(fi,"  (title \"%s\")\n", title.c_str());
198
199       /* Save the description: */
200       fprintf(fi,"  (description \"%s\")\n", description.c_str());
201
202       fprintf( fi,")");
203       fclose(fi);
204     }
205 }
206
207 std::string
208 LevelSubset::get_level_filename(unsigned int num)
209 {
210   char filename[1024];
211                                                                                 
212   // Load data file:
213   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir,
214       name.c_str(), num);
215   if(!faccessible(filename))
216     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
217         name.c_str(), num);
218
219   return std::string(filename);
220 }
221
222 //---------------------------------------------------------------------------
223
224 Level::Level()
225   : name("noname"), author("mr. x"), time_left(500)
226 {
227 }
228
229 void
230 Level::load(const std::string& filename)
231 {
232   LispReader* level = LispReader::load(filename, "supertux-level");
233
234   int version = 1;
235   level->read_int("version", version);
236   if(version == 1) {
237     load_old_format(*level);
238     delete level;
239     return;
240   }
241
242   for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur);
243       cur = lisp_cdr(cur)) {
244     std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
245     lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
246     LispReader reader(lisp_cdr(lisp_car(cur)));
247
248     if(token == "name") {
249       name = lisp_string(data);
250     } else if(token == "author") {
251       author = lisp_string(data);
252     } else if(token == "time") {
253       time_left = lisp_integer(data);
254     } else if(token == "sector") {
255       Sector* sector = new Sector;
256       sector->parse(reader);
257       add_sector(sector);
258     } else {
259       std::cerr << "Unknown token '" << token << "' in level file.\n";
260       continue;
261     }
262   }
263   
264   delete level;
265 }
266
267 void
268 Level::load_old_format(LispReader& reader)
269 {
270   reader.read_string("name", name);
271   reader.read_string("author", author);
272   reader.read_int("time", time_left);
273
274   Sector* sector = new Sector;
275   sector->parse_old_format(reader);
276   add_sector(sector);
277 }
278
279 void
280 Level::save(const std::string& filename)
281 {
282 #if 0
283   LispReader* level = LispReader::load(filename, "supertux-level");
284
285   int version = 1;
286   level->read_int("version", version);
287   if(version == 1) {
288     load_old_format(*level);
289     return;
290   }
291
292   for(lisp_object_t* cur = level->get_lisp(); !lisp_nil_p(cur);
293       cur = lisp_cdr(cur)) {
294     std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
295     lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
296     LispReader reader(lisp_cdr(lisp_car(cur)));
297
298     if(token == "name") {
299       name = lisp_string(data);
300     } else if(token == "author") {
301       author = lisp_string(data);
302     } else if(token == "time") {
303       time_left = lisp_integer(data);
304     } else if(token == "sector") {
305       Sector* sector = new Sector;
306       sector->parse(reader);
307       add_sector(sector);
308     } else {
309       std::cerr << "Unknown token '" << token << "' in level file.\n";
310       continue;
311     }
312   }
313   
314   delete level;
315 #endif
316 }
317
318 Level::~Level()
319 {
320   for(Sectors::iterator i = sectors.begin(); i != sectors.end(); ++i)
321     delete i->second;
322 }
323
324 void
325 Level::add_sector(Sector* sector)
326 {
327   sectors.insert(std::make_pair(sector->get_name(), sector));       
328 }
329
330 Sector*
331 Level::get_sector(const std::string& name)
332 {
333   Sectors::iterator i = sectors.find(name);
334   if(i == sectors.end())
335     return 0;
336
337   return i->second;
338 }
339