bbd09158ac656d87bcc22e328620ee3e62e0e83e
[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   : img_bkgd(0), level_song(0), level_song_fast(0)
203 {
204 }
205
206 Level::Level(const std::string& subset, int level)
207   : img_bkgd(0), level_song(0), level_song_fast(0)
208 {
209   load(subset, level);
210 }
211
212 Level::Level(const std::string& filename)
213   : img_bkgd(0), level_song(0), level_song_fast(0)
214 {
215   load(filename);
216 }
217
218 Level::~Level()
219 {
220   free_gfx();
221   free_song();
222 }
223
224 void
225 Level::init_defaults()
226 {
227   name       = "UnNamed";
228   author     = "UnNamed";
229   theme      = "antarctica";
230   song_title = "Mortimers_chipdisko.mod";
231   bkgd_image = "arctis.png";
232   width      = 21;
233   start_pos_x = 100;
234   start_pos_y = 170;
235   time_left  = 100;
236   gravity    = 10.;
237   bkgd_top.red   = 0;
238   bkgd_top.green = 0;
239   bkgd_top.blue  = 0;
240   bkgd_bottom.red   = 255;
241   bkgd_bottom.green = 255;
242   bkgd_bottom.blue  = 255;
243   endpos     = 0;
244
245   for(int i = 0; i < 15; ++i)
246     {
247       ia_tiles[i].resize(width+1, 0);
248       ia_tiles[i][width] = (unsigned int) '\0';
249
250       for(int y = 0; y < width; ++y)
251         ia_tiles[i][y] = 0;
252
253       bg_tiles[i].resize(width+1, 0);
254       bg_tiles[i][width] = (unsigned int) '\0';
255       for(int y = 0; y < width; ++y)
256         bg_tiles[i][y] = 0;
257
258       fg_tiles[i].resize(width+1, 0);
259       fg_tiles[i][width] = (unsigned int) '\0';
260       for(int y = 0; y < width; ++y)
261         fg_tiles[i][y] = 0;
262     }
263 }
264
265 int
266 Level::load(const std::string& subset, int level)
267 {
268   char filename[1024];
269
270   // Load data file:
271   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
272   if(!faccessible(filename))
273     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
274
275   return load(filename);
276 }
277
278 int 
279 Level::load(const std::string& filename)
280 {
281   FILE * fi;
282   lisp_object_t* root_obj = 0;
283   fi = fopen(filename.c_str(), "r");
284   if (fi == NULL)
285     {
286       perror(filename.c_str());
287       return -1;
288     }
289
290   lisp_stream_t stream;
291   lisp_stream_init_file (&stream, fi);
292   root_obj = lisp_read (&stream);
293
294   if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
295     {
296       printf("World: Parse Error in file %s", filename.c_str());
297     }
298
299   vector<int> ia_tm;
300   vector<int> bg_tm;
301   vector<int> fg_tm;
302
303   int version = 0;
304   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
305     {
306       LispReader reader(lisp_cdr(root_obj));
307       reader.read_int("version",  &version);
308       reader.read_int("width",  &width);
309       if (!reader.read_int("start_pos_x", &start_pos_x)) start_pos_x = 100;
310       if (!reader.read_int("start_pos_y", &start_pos_y)) start_pos_y = 170;
311       reader.read_int("time",  &time_left);
312
313       reader.read_int("bkgd_top_red",  &bkgd_top.red);
314       reader.read_int("bkgd_top_green",  &bkgd_top.green);
315       reader.read_int("bkgd_top_blue",  &bkgd_top.blue);
316
317       reader.read_int("bkgd_bottom_red",  &bkgd_bottom.red);
318       reader.read_int("bkgd_bottom_green",  &bkgd_bottom.green);
319       reader.read_int("bkgd_bottom_blue",  &bkgd_bottom.blue);
320
321       reader.read_float("gravity",  &gravity);
322       reader.read_string("name",  &name);
323       reader.read_string("author", &author);
324       reader.read_string("theme",  &theme);
325       reader.read_string("music",  &song_title);
326       reader.read_string("background",  &bkgd_image);
327       reader.read_string("particle_system", &particle_system);
328       reader.read_int_vector("background-tm",  &bg_tm);
329
330       if (!reader.read_int_vector("interactive-tm", &ia_tm))
331         reader.read_int_vector("tilemap", &ia_tm);
332
333       reader.read_int_vector("foreground-tm",  &fg_tm);
334
335       { // Read ResetPoints
336         lisp_object_t* cur = 0;
337         if (reader.read_lisp("reset-points",  &cur))
338           {
339             while (!lisp_nil_p(cur))
340               {
341                 lisp_object_t* data = lisp_car(cur);
342
343                 ResetPoint pos;
344
345                 LispReader reader(lisp_cdr(data));
346                 if (reader.read_int("x", &pos.x)
347                     && reader.read_int("y", &pos.y))
348                   {
349                     reset_points.push_back(pos);
350                   }
351
352                 cur = lisp_cdr(cur);
353               }
354           }
355       }
356
357       { // Read BadGuys
358         lisp_object_t* cur = 0;
359         if (reader.read_lisp("objects",  &cur))
360           {
361             while (!lisp_nil_p(cur))
362               {
363                 lisp_object_t* data = lisp_car(cur);
364
365                 BadGuyData bg_data;
366                 bg_data.kind = badguykind_from_string(lisp_symbol(lisp_car(data)));
367                 LispReader reader(lisp_cdr(data));
368                 reader.read_int("x", &bg_data.x);
369                 reader.read_int("y", &bg_data.y);
370                 reader.read_bool("stay-on-platform", &bg_data.stay_on_platform);
371
372                 badguy_data.push_back(bg_data);
373
374                 cur = lisp_cdr(cur);
375               }
376           }
377       }
378
379       // Convert old levels to the new tile numbers
380       if (version == 0)
381         {
382           std::map<char, int> transtable;
383           transtable['.'] = 0;
384           transtable['x'] = 104;
385           transtable['X'] = 77;
386           transtable['y'] = 78;
387           transtable['Y'] = 105;
388           transtable['A'] = 83;
389           transtable['B'] = 102;
390           transtable['!'] = 103;
391           transtable['a'] = 84;
392           transtable['C'] = 85;
393           transtable['D'] = 86;
394           transtable['E'] = 87;
395           transtable['F'] = 88;
396           transtable['c'] = 89;
397           transtable['d'] = 90;
398           transtable['e'] = 91;
399           transtable['f'] = 92;
400
401           transtable['G'] = 93;
402           transtable['H'] = 94;
403           transtable['I'] = 95;
404           transtable['J'] = 96;
405
406           transtable['g'] = 97;
407           transtable['h'] = 98;
408           transtable['i'] = 99;
409           transtable['j'] = 100
410                             ;
411           transtable['#'] = 11;
412           transtable['['] = 13;
413           transtable['='] = 14;
414           transtable[']'] = 15;
415           transtable['$'] = 82;
416           transtable['^'] = 76;
417           transtable['*'] = 80;
418           transtable['|'] = 79;
419           transtable['\\'] = 81;
420           transtable['&'] = 75;
421
422           int x = 0;
423           int y = 0;
424           for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
425             {
426               if (*i == '0' || *i == '1' || *i == '2')
427                 {
428                   badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
429                                                    x*32, y*32, false));
430                   *i = 0;
431                 }
432               else
433                 {
434                   std::map<char, int>::iterator j = transtable.find(*i);
435                   if (j != transtable.end())
436                     *i = j->second;
437                   else
438                     printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
439                 }
440               ++x;
441               if (x >= width)
442                 {
443                   x = 0;
444                   ++y;
445                 }
446             }
447         }
448     }
449
450   for(int i = 0; i < 15; ++i)
451     {
452       ia_tiles[i].resize(width + 1, 0);
453       bg_tiles[i].resize(width + 1, 0);
454       fg_tiles[i].resize(width + 1, 0);
455     }
456
457   int i = 0;
458   int j = 0;
459   for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
460     {
461       ia_tiles[j][i] = (*it);
462       if(i == width - 1)
463         {
464           i = -1;
465           ++j;
466         }
467     }
468
469   i = j = 0;
470   for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
471     {
472
473       bg_tiles[j][i] = (*it);
474       if(i == width - 1)
475         {
476           i = -1;
477           ++j;
478         }
479     }
480
481   i = j = 0;
482   for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
483     {
484
485       fg_tiles[j][i] = (*it);
486       if(i == width - 1)
487         {
488           i = -1;
489           ++j;
490         }
491     }
492
493   //  Mark the end position of this level!
494   // FIXME: -10 is a rather random value, we still need some kind of
495   // real levelend gola
496   endpos = 32*(width-20);
497
498   fclose(fi);
499   return 0;
500 }
501
502 /* Save data for level: */
503
504 void 
505 Level::save(const  char * subset, int level)
506 {
507   char filename[1024];
508   char str[80];
509
510   /* Save data file: */
511   sprintf(str, "/levels/%s/", subset);
512   fcreatedir(str);
513   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset, level);
514   if(!fwriteable(filename))
515     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset, level);
516
517   FILE * fi = fopen(filename, "w");
518   if (fi == NULL)
519     {
520       perror(filename);
521       st_shutdown();
522       exit(-1);
523     }
524
525
526   /* Write header: */
527   fprintf(fi,";SuperTux-Level\n");
528   fprintf(fi,"(supertux-level\n");
529
530   fprintf(fi,"  (version %d)\n", 1);
531   fprintf(fi,"  (name \"%s\")\n", name.c_str());
532   fprintf(fi,"  (author \"%s\")\n", author.c_str());
533   fprintf(fi,"  (theme \"%s\")\n", theme.c_str());
534   fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
535   fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
536   fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
537   fprintf(fi,"  (bkgd_top_red %d)\n", bkgd_top.red);
538   fprintf(fi,"  (bkgd_top_green %d)\n", bkgd_top.green);
539   fprintf(fi,"  (bkgd_top_blue %d)\n", bkgd_top.blue);
540   fprintf(fi,"  (bkgd_bottom_red %d)\n", bkgd_bottom.red);
541   fprintf(fi,"  (bkgd_bottom_green %d)\n", bkgd_bottom.green);
542   fprintf(fi,"  (bkgd_bottom_blue %d)\n", bkgd_bottom.blue);
543   fprintf(fi,"  (time %d)\n", time_left);
544   fprintf(fi,"  (width %d)\n", width);
545   fprintf(fi,"  (gravity %2.1f)\n", gravity);
546   fprintf(fi,"  (background-tm ");
547
548   for(int y = 0; y < 15; ++y)
549     {
550       for(int i = 0; i < width; ++i)
551         fprintf(fi," %d ", bg_tiles[y][i]);
552     }
553
554   fprintf( fi,")\n");
555   fprintf(fi,"  (interactive-tm ");
556
557   for(int y = 0; y < 15; ++y)
558     {
559       for(int i = 0; i < width; ++i)
560         fprintf(fi," %d ", ia_tiles[y][i]);
561     }
562
563   fprintf( fi,")\n");
564   fprintf(fi,"  (foreground-tm ");
565
566   for(int y = 0; y < 15; ++y)
567     {
568       for(int i = 0; i < width; ++i)
569         fprintf(fi," %d ", fg_tiles[y][i]);
570     }
571
572   fprintf( fi,")\n");
573
574   fprintf( fi,"(reset-points\n");
575   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
576       i != reset_points.end(); ++i)
577     fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
578   fprintf( fi,")\n");
579
580   fprintf( fi,"(objects\n");
581
582   for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
583       it != badguy_data.end();
584       ++it)
585     fprintf( fi,"(%s (x %d) (y %d) (stay-on-platform %s))\n",
586              badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y,
587              it->stay_on_platform ? "#t" : "#f");
588
589   fprintf( fi,")\n");
590
591   fprintf( fi,")\n");
592
593   fclose(fi);
594 }
595
596
597 /* Unload data for this level: */
598
599 void
600 Level::cleanup()
601 {
602   for(int i=0; i < 15; ++i)
603     {
604       bg_tiles[i].clear();
605       ia_tiles[i].clear();
606       fg_tiles[i].clear();
607     }
608
609   reset_points.clear();
610   name.clear();
611   author.clear();
612   theme.clear();
613   song_title.clear();
614   bkgd_image.clear();
615
616   badguy_data.clear();
617 }
618
619 void 
620 Level::load_gfx()
621 {
622   if(!bkgd_image.empty())
623     {
624       char fname[1024];
625       snprintf(fname, 1024, "%s/background/%s", st_dir, bkgd_image.c_str());
626       if(!faccessible(fname))
627         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), bkgd_image.c_str());
628       img_bkgd = new Surface(fname, IGNORE_ALPHA);
629     }
630   else
631     {
632       /* Quick hack to make sure an image is loaded, when we are freeing it afterwards. */
633       load_image(&img_bkgd, theme,"solid0.png", IGNORE_ALPHA);
634     }
635 }
636
637 void
638 Level::free_gfx()
639 {
640   delete img_bkgd;
641 }
642
643 /* Load a level-specific graphic... */
644 void
645 Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
646 {
647   char fname[1024];
648
649   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
650   if(!faccessible(fname))
651     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
652
653   *ptexture = new Surface(fname, use_alpha);
654 }
655
656 /* Change the size of a level (width) */
657 void 
658 Level::change_size (int new_width)
659 {
660   if(new_width < 21)
661     new_width = 21;
662
663   for(int y = 0; y < 15; ++y)
664     {
665       ia_tiles[y].resize(new_width, 0);
666       bg_tiles[y].resize(new_width, 0);
667       fg_tiles[y].resize(new_width, 0);
668     }
669
670   width = new_width;
671 }
672
673 void
674 Level::change(float x, float y, int tm, unsigned int c)
675 {
676   int yy = ((int)y / 32);
677   int xx = ((int)x / 32);
678
679   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
680     {
681       switch(tm)
682         {
683         case TM_BG:
684           bg_tiles[yy][xx] = c;
685           break;
686         case TM_IA:
687           ia_tiles[yy][xx] = c;
688           break;
689         case TM_FG:
690           fg_tiles[yy][xx] = c;
691           break;
692         }
693     }
694 }
695
696 void 
697 Level::free_song(void)
698 {
699   if(level_song_fast != level_song) {
700     free_music(level_song_fast);
701     level_song_fast = 0;
702   }
703     
704   free_music(level_song);
705   level_song = 0;
706 }
707
708 void
709 Level::load_song()
710 {
711   free_song();
712   
713   char* song_path;
714   char* song_subtitle;
715
716   level_song = ::load_song(datadir + "/music/" + song_title);
717   if(!level_song)
718     st_abort("Couldn't load song: " , song_title.c_str());
719
720   song_path = (char *) malloc(sizeof(char) * datadir.length() +
721                               strlen(song_title.c_str()) + 8 + 5);
722   song_subtitle = strdup(song_title.c_str());
723   strcpy(strstr(song_subtitle, "."), "\0");
724   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
725           song_subtitle, strstr(song_title.c_str(), "."));
726   level_song_fast = ::load_song(song_path);
727   if(!level_song_fast) {
728     level_song_fast = level_song;
729   }
730   free(song_subtitle);
731   free(song_path);
732 }
733
734 Mix_Music*
735 Level::get_level_music()
736 {
737   return level_song;
738 }
739
740 Mix_Music*
741 Level::get_level_music_fast()
742 {
743   return level_song_fast;
744 }
745
746 unsigned int 
747 Level::gettileid(float x, float y)
748 {
749   int xx, yy;
750   unsigned int c;
751
752   yy = ((int)y / 32);
753   xx = ((int)x / 32);
754
755   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
756     c = ia_tiles[yy][xx];
757   else
758     c = 0;
759
760   return c;
761 }
762
763 /* EOF */