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