- fixed level editor menus a bit (still not 100% working)
[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 "globals.h"
27 #include "setup.h"
28 #include "screen.h"
29 #include "level.h"
30 #include "physic.h"
31 #include "scene.h"
32 #include "tile.h"
33 #include "lispreader.h"
34
35 using namespace std;
36
37 st_subset::st_subset()
38 {
39   levels = 0;
40 }
41
42 void st_subset::create(const std::string& subset_name)
43 {
44   Level new_lev;
45   st_subset new_subset;
46   new_subset.name = subset_name;
47   new_subset.title = "Unknown Title";
48   new_subset.description = "No description so far.";
49   new_subset.save();
50   new_lev.init_defaults();
51   new_lev.save(subset_name.c_str(),1);
52 }
53
54 void st_subset::parse (lisp_object_t* cursor)
55 {
56   while(!lisp_nil_p(cursor))
57     {
58       lisp_object_t* cur = lisp_car(cursor);
59       char *s;
60
61       if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
62         {
63           printf("Not good");
64         }
65       else
66         {
67           if (strcmp(lisp_symbol(lisp_car(cur)), "title") == 0)
68             {
69               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
70                 {
71                   title = s;
72                 }
73             }
74           else if (strcmp(lisp_symbol(lisp_car(cur)), "description") == 0)
75             {
76               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
77                 {
78                   description = s;
79                 }
80             }
81         }
82       cursor = lisp_cdr (cursor);
83     }
84 }
85
86 void st_subset::load(char *subset)
87 {
88   FILE* fi;
89   char filename[1024];
90   char str[1024];
91   int i;
92   lisp_object_t* root_obj = 0;
93
94   name = subset;
95
96   snprintf(filename, 1024, "%s/levels/%s/info", st_dir, subset);
97   if(!faccessible(filename))
98     snprintf(filename, 1024, "%s/levels/%s/info", datadir.c_str(), subset);
99   if(faccessible(filename))
100     {
101       fi = fopen(filename, "r");
102       if (fi == NULL)
103         {
104           perror(filename);
105         }
106       lisp_stream_t stream;
107       lisp_stream_init_file (&stream, fi);
108       root_obj = lisp_read (&stream);
109
110       if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
111         {
112           printf("World: Parse Error in file %s", filename);
113         }
114
115       lisp_object_t* cur = lisp_car(root_obj);
116
117       if (!lisp_symbol_p (cur))
118         {
119           printf("World: Read error in %s",filename);
120         }
121
122       if (strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
123         {
124           parse(lisp_cdr(root_obj));
125
126         }
127
128       fclose(fi);
129
130       snprintf(str, 1024, "%s.png", filename);
131       if(faccessible(str))
132         {
133           image = new Surface(str,IGNORE_ALPHA);
134         }
135       else
136         {
137           snprintf(filename, 1024, "%s/images/status/level-subset-info.png", datadir.c_str());
138           image = new Surface(filename,IGNORE_ALPHA);
139         }
140     }
141
142   for(i=1; i != -1; ++i)
143     {
144       /* Get the number of levels in this subset */
145       snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset,i);
146       if(!faccessible(filename))
147         {
148           snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset,i);
149           if(!faccessible(filename))
150             break;
151         }
152     }
153   levels = --i;
154 }
155
156 void st_subset::save()
157 {
158   FILE* fi;
159   string filename;
160
161   /* Save data file: */
162   filename = "/levels/" + name + "/";
163
164   fcreatedir(filename.c_str());
165   filename = string(st_dir) + "/levels/" + name + "/info";
166   if(!fwriteable(filename.c_str()))
167     filename = datadir + "/levels/" + name + "/info";
168   if(fwriteable(filename.c_str()))
169     {
170       fi = fopen(filename.c_str(), "w");
171       if (fi == NULL)
172         {
173           perror(filename.c_str());
174         }
175
176       /* Write header: */
177       fprintf(fi,";SuperTux-Level-Subset\n");
178       fprintf(fi,"(supertux-level-subset\n");
179
180       /* Save title info: */
181       fprintf(fi,"  (title \"%s\")\n", title.c_str());
182
183       /* Save the description: */
184       fprintf(fi,"  (description \"%s\")\n", description.c_str());
185
186       fprintf( fi,")");
187       fclose(fi);
188
189     }
190 }
191
192 void st_subset::free()
193 {
194   title.clear();
195   description.clear();
196   name.clear();
197   delete image;
198   levels = 0;
199 }
200
201 Level::Level()
202 {
203 }
204
205 Level::Level(const std::string& subset, int level)
206 {
207   load(subset, level);
208 }
209
210 Level::Level(const std::string& filename)
211 {
212   load(filename);
213 }
214
215 void
216 Level::init_defaults()
217 {
218   name       = "UnNamed";
219   author     = "UnNamed";
220   theme      = "antarctica";
221   song_title = "Mortimers_chipdisko.mod";
222   bkgd_image = "arctis.png";
223   width      = 21;
224   start_pos_x = 100;
225   start_pos_y = 170;
226   time_left  = 100;
227   gravity    = 10.;
228   bkgd_top.red   = 0;
229   bkgd_top.green = 0;
230   bkgd_top.blue  = 0;
231   bkgd_bottom.red   = 255;
232   bkgd_bottom.green = 255;
233   bkgd_bottom.blue  = 255;
234   endpos     = 0;
235
236   for(int i = 0; i < 15; ++i)
237     {
238       ia_tiles[i].resize(width+1, 0);
239       ia_tiles[i][width] = (unsigned int) '\0';
240
241       for(int y = 0; y < width; ++y)
242         ia_tiles[i][y] = 0;
243
244       bg_tiles[i].resize(width+1, 0);
245       bg_tiles[i][width] = (unsigned int) '\0';
246       for(int y = 0; y < width; ++y)
247         bg_tiles[i][y] = 0;
248
249       fg_tiles[i].resize(width+1, 0);
250       fg_tiles[i][width] = (unsigned int) '\0';
251       for(int y = 0; y < width; ++y)
252         fg_tiles[i][y] = 0;
253     }
254 }
255
256 int
257 Level::load(const std::string& subset, int level)
258 {
259   char filename[1024];
260
261   // Load data file:
262   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
263   if(!faccessible(filename))
264     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
265
266   return load(filename);
267 }
268
269 int 
270 Level::load(const std::string& filename)
271 {
272   FILE * fi;
273   lisp_object_t* root_obj = 0;
274   fi = fopen(filename.c_str(), "r");
275   if (fi == NULL)
276     {
277       perror(filename.c_str());
278       return -1;
279     }
280
281   lisp_stream_t stream;
282   lisp_stream_init_file (&stream, fi);
283   root_obj = lisp_read (&stream);
284
285   if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
286     {
287       printf("World: Parse Error in file %s", filename.c_str());
288     }
289
290   vector<int> ia_tm;
291   vector<int> bg_tm;
292   vector<int> fg_tm;
293
294   int version = 0;
295   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
296     {
297       LispReader reader(lisp_cdr(root_obj));
298       reader.read_int("version",  &version);
299       reader.read_int("width",  &width);
300       if (!reader.read_int("start_pos_x", &start_pos_x)) start_pos_x = 100;
301       if (!reader.read_int("start_pos_y", &start_pos_y)) start_pos_y = 170;
302       reader.read_int("time",  &time_left);
303
304       reader.read_int("bkgd_top_red",  &bkgd_top.red);
305       reader.read_int("bkgd_top_green",  &bkgd_top.green);
306       reader.read_int("bkgd_top_blue",  &bkgd_top.blue);
307
308       reader.read_int("bkgd_bottom_red",  &bkgd_bottom.red);
309       reader.read_int("bkgd_bottom_green",  &bkgd_bottom.green);
310       reader.read_int("bkgd_bottom_blue",  &bkgd_bottom.blue);
311
312       reader.read_float("gravity",  &gravity);
313       reader.read_string("name",  &name);
314       reader.read_string("author", &author);
315       reader.read_string("theme",  &theme);
316       reader.read_string("music",  &song_title);
317       reader.read_string("background",  &bkgd_image);
318       reader.read_string("particle_system", &particle_system);
319       reader.read_int_vector("background-tm",  &bg_tm);
320
321       if (!reader.read_int_vector("interactive-tm", &ia_tm))
322         reader.read_int_vector("tilemap", &ia_tm);
323
324       reader.read_int_vector("foreground-tm",  &fg_tm);
325
326       { // Read ResetPoints
327         lisp_object_t* cur = 0;
328         if (reader.read_lisp("reset-points",  &cur))
329           {
330             while (!lisp_nil_p(cur))
331               {
332                 lisp_object_t* data = lisp_car(cur);
333
334                 ResetPoint pos;
335
336                 LispReader reader(lisp_cdr(data));
337                 if (reader.read_int("x", &pos.x)
338                     && reader.read_int("y", &pos.y))
339                   {
340                     reset_points.push_back(pos);
341                   }
342
343                 cur = lisp_cdr(cur);
344               }
345           }
346       }
347
348       { // Read BadGuys
349         lisp_object_t* cur = 0;
350         if (reader.read_lisp("objects",  &cur))
351           {
352             while (!lisp_nil_p(cur))
353               {
354                 lisp_object_t* data = lisp_car(cur);
355
356                 BadGuyData bg_data;
357                 bg_data.kind = badguykind_from_string(lisp_symbol(lisp_car(data)));
358                 LispReader reader(lisp_cdr(data));
359                 reader.read_int("x", &bg_data.x);
360                 reader.read_int("y", &bg_data.y);
361
362                 badguy_data.push_back(bg_data);
363
364                 cur = lisp_cdr(cur);
365               }
366           }
367       }
368
369       // Convert old levels to the new tile numbers
370       if (version == 0)
371         {
372           std::map<char, int> transtable;
373           transtable['.'] = 0;
374           transtable['x'] = 104;
375           transtable['X'] = 77;
376           transtable['y'] = 78;
377           transtable['Y'] = 105;
378           transtable['A'] = 83;
379           transtable['B'] = 102;
380           transtable['!'] = 103;
381           transtable['a'] = 84;
382           transtable['C'] = 85;
383           transtable['D'] = 86;
384           transtable['E'] = 87;
385           transtable['F'] = 88;
386           transtable['c'] = 89;
387           transtable['d'] = 90;
388           transtable['e'] = 91;
389           transtable['f'] = 92;
390
391           transtable['G'] = 93;
392           transtable['H'] = 94;
393           transtable['I'] = 95;
394           transtable['J'] = 96;
395
396           transtable['g'] = 97;
397           transtable['h'] = 98;
398           transtable['i'] = 99;
399           transtable['j'] = 100
400                             ;
401           transtable['#'] = 11;
402           transtable['['] = 13;
403           transtable['='] = 14;
404           transtable[']'] = 15;
405           transtable['$'] = 82;
406           transtable['^'] = 76;
407           transtable['*'] = 80;
408           transtable['|'] = 79;
409           transtable['\\'] = 81;
410           transtable['&'] = 75;
411
412           int x = 0;
413           int y = 0;
414           for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
415             {
416               if (*i == '0' || *i == '1' || *i == '2')
417                 {
418                   badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
419                                                 x*32, y*32));
420                   *i = 0;
421                 }
422               else
423                 {
424                   std::map<char, int>::iterator j = transtable.find(*i);
425                   if (j != transtable.end())
426                     *i = j->second;
427                   else
428                     printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
429                 }
430               ++x;
431               if (x >= width)
432                 {
433                   x = 0;
434                   ++y;
435                 }
436             }
437         }
438     }
439
440   for(int i = 0; i < 15; ++i)
441     {
442       ia_tiles[i].resize(width + 1, 0);
443       bg_tiles[i].resize(width + 1, 0);
444       fg_tiles[i].resize(width + 1, 0);
445     }
446
447   int i = 0;
448   int j = 0;
449   for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
450     {
451       ia_tiles[j][i] = (*it);
452       if(i == width - 1)
453         {
454           i = -1;
455           ++j;
456         }
457     }
458
459   i = j = 0;
460   for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
461     {
462
463       bg_tiles[j][i] = (*it);
464       if(i == width - 1)
465         {
466           i = -1;
467           ++j;
468         }
469     }
470
471   i = j = 0;
472   for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
473     {
474
475       fg_tiles[j][i] = (*it);
476       if(i == width - 1)
477         {
478           i = -1;
479           ++j;
480         }
481     }
482
483   //  Mark the end position of this level!
484   // FIXME: -10 is a rather random value, we still need some kind of
485   // real levelend gola
486   endpos = 32*(width-10);
487
488   fclose(fi);
489   return 0;
490 }
491
492 /* Save data for level: */
493
494 void 
495 Level::save(const  char * subset, int level)
496 {
497   char filename[1024];
498   char str[80];
499
500   /* Save data file: */
501   sprintf(str, "/levels/%s/", subset);
502   fcreatedir(str);
503   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset, level);
504   if(!fwriteable(filename))
505     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset, level);
506
507   FILE * fi = fopen(filename, "w");
508   if (fi == NULL)
509     {
510       perror(filename);
511       st_shutdown();
512       exit(-1);
513     }
514
515
516   /* Write header: */
517   fprintf(fi,";SuperTux-Level\n");
518   fprintf(fi,"(supertux-level\n");
519
520   fprintf(fi,"  (version %d)\n", 1);
521   fprintf(fi,"  (name \"%s\")\n", name.c_str());
522   fprintf(fi,"  (author \"%s\")\n", author.c_str());
523   fprintf(fi,"  (theme \"%s\")\n", theme.c_str());
524   fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
525   fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
526   fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
527   fprintf(fi,"  (bkgd_top_red %d)\n", bkgd_top.red);
528   fprintf(fi,"  (bkgd_top_green %d)\n", bkgd_top.green);
529   fprintf(fi,"  (bkgd_top_blue %d)\n", bkgd_top.blue);
530   fprintf(fi,"  (bkgd_bottom_red %d)\n", bkgd_bottom.red);
531   fprintf(fi,"  (bkgd_bottom_green %d)\n", bkgd_bottom.green);
532   fprintf(fi,"  (bkgd_bottom_blue %d)\n", bkgd_bottom.blue);
533   fprintf(fi,"  (time %d)\n", time_left);
534   fprintf(fi,"  (width %d)\n", width);
535   fprintf(fi,"  (gravity %2.1f)\n", gravity);
536   fprintf(fi,"  (background-tm ");
537
538   for(int y = 0; y < 15; ++y)
539     {
540       for(int i = 0; i < width; ++i)
541         fprintf(fi," %d ", bg_tiles[y][i]);
542     }
543
544   fprintf( fi,")\n");
545   fprintf(fi,"  (interactive-tm ");
546
547   for(int y = 0; y < 15; ++y)
548     {
549       for(int i = 0; i < width; ++i)
550         fprintf(fi," %d ", ia_tiles[y][i]);
551     }
552
553   fprintf( fi,")\n");
554   fprintf(fi,"  (foreground-tm ");
555
556   for(int y = 0; y < 15; ++y)
557     {
558       for(int i = 0; i < width; ++i)
559         fprintf(fi," %d ", fg_tiles[y][i]);
560     }
561
562   fprintf( fi,")\n");
563
564   fprintf( fi,"(reset-points\n");
565   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
566       i != reset_points.end(); ++i)
567     fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
568   fprintf( fi,")\n");
569
570   fprintf( fi,"(objects\n");
571
572   for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
573       it != badguy_data.end();
574       ++it)
575     fprintf( fi,"(%s (x %d) (y %d))\n",badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y);
576
577   fprintf( fi,")\n");
578
579   fprintf( fi,")\n");
580
581   fclose(fi);
582 }
583
584
585 /* Unload data for this level: */
586
587 void
588 Level::cleanup()
589 {
590   for(int i=0; i < 15; ++i)
591     {
592       bg_tiles[i].clear();
593       ia_tiles[i].clear();
594       fg_tiles[i].clear();
595     }
596
597   reset_points.clear();
598   name.clear();
599   author.clear();
600   theme.clear();
601   song_title.clear();
602   bkgd_image.clear();
603
604   badguy_data.clear();
605 }
606
607 void 
608 Level::load_gfx()
609 {
610   if(!bkgd_image.empty())
611     {
612       char fname[1024];
613       snprintf(fname, 1024, "%s/background/%s", st_dir, bkgd_image.c_str());
614       if(!faccessible(fname))
615         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), bkgd_image.c_str());
616       img_bkgd = new Surface(fname, IGNORE_ALPHA);
617     }
618   else
619     {
620       /* Quick hack to make sure an image is loaded, when we are freeing it afterwards. */
621       load_image(&img_bkgd, theme,"solid0.png", IGNORE_ALPHA);
622     }
623 }
624
625 void
626 Level::free_gfx()
627 {
628   delete img_bkgd;
629 }
630
631 /* Load a level-specific graphic... */
632 void
633 Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
634 {
635   char fname[1024];
636
637   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
638   if(!faccessible(fname))
639     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
640
641   *ptexture = new Surface(fname, use_alpha);
642 }
643
644 /* Change the size of a level (width) */
645 void 
646 Level::change_size (int new_width)
647 {
648   if(new_width < 21)
649     new_width = 21;
650
651   for(int y = 0; y < 15; ++y)
652     {
653       ia_tiles[y].resize(new_width, 0);
654       bg_tiles[y].resize(new_width, 0);
655       fg_tiles[y].resize(new_width, 0);
656     }
657
658   width = new_width;
659 }
660
661 void
662 Level::change(float x, float y, int tm, unsigned int c)
663 {
664   int yy = ((int)y / 32);
665   int xx = ((int)x / 32);
666
667   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
668     {
669       switch(tm)
670         {
671         case TM_BG:
672           bg_tiles[yy][xx] = c;
673           break;
674         case TM_IA:
675           ia_tiles[yy][xx] = c;
676           break;
677         case TM_FG:
678           fg_tiles[yy][xx] = c;
679           break;
680         }
681     }
682 }
683
684 void 
685 Level::free_song(void)
686 {
687   free_music(level_song);
688   free_music(level_song_fast);
689 }
690
691 void
692 Level::load_song()
693 {
694   char* song_path;
695   char* song_subtitle;
696
697   level_song = ::load_song(datadir + "/music/" + song_title);
698
699   song_path = (char *) malloc(sizeof(char) * datadir.length() +
700                               strlen(song_title.c_str()) + 8 + 5);
701   song_subtitle = strdup(song_title.c_str());
702   strcpy(strstr(song_subtitle, "."), "\0");
703   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
704           song_subtitle, strstr(song_title.c_str(), "."));
705   level_song_fast = ::load_song(song_path);
706   free(song_subtitle);
707   free(song_path);
708 }
709
710 unsigned int 
711 Level::gettileid(float x, float y)
712 {
713   int xx, yy;
714   unsigned int c;
715
716   yy = ((int)y / 32);
717   xx = ((int)x / 32);
718
719   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
720     c = ia_tiles[yy][xx];
721   else
722     c = 0;
723
724   return c;
725 }
726
727 /* EOF */