9ae1831ee2fd13e0e4b7ada03f9ac9ae8493934a
[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                 reader.read_bool("stay-on-platform", &bg_data.stay_on_platform);
362
363                 badguy_data.push_back(bg_data);
364
365                 cur = lisp_cdr(cur);
366               }
367           }
368       }
369
370       // Convert old levels to the new tile numbers
371       if (version == 0)
372         {
373           std::map<char, int> transtable;
374           transtable['.'] = 0;
375           transtable['x'] = 104;
376           transtable['X'] = 77;
377           transtable['y'] = 78;
378           transtable['Y'] = 105;
379           transtable['A'] = 83;
380           transtable['B'] = 102;
381           transtable['!'] = 103;
382           transtable['a'] = 84;
383           transtable['C'] = 85;
384           transtable['D'] = 86;
385           transtable['E'] = 87;
386           transtable['F'] = 88;
387           transtable['c'] = 89;
388           transtable['d'] = 90;
389           transtable['e'] = 91;
390           transtable['f'] = 92;
391
392           transtable['G'] = 93;
393           transtable['H'] = 94;
394           transtable['I'] = 95;
395           transtable['J'] = 96;
396
397           transtable['g'] = 97;
398           transtable['h'] = 98;
399           transtable['i'] = 99;
400           transtable['j'] = 100
401                             ;
402           transtable['#'] = 11;
403           transtable['['] = 13;
404           transtable['='] = 14;
405           transtable[']'] = 15;
406           transtable['$'] = 82;
407           transtable['^'] = 76;
408           transtable['*'] = 80;
409           transtable['|'] = 79;
410           transtable['\\'] = 81;
411           transtable['&'] = 75;
412
413           int x = 0;
414           int y = 0;
415           for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
416             {
417               if (*i == '0' || *i == '1' || *i == '2')
418                 {
419                   badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
420                                                    x*32, y*32, false));
421                   *i = 0;
422                 }
423               else
424                 {
425                   std::map<char, int>::iterator j = transtable.find(*i);
426                   if (j != transtable.end())
427                     *i = j->second;
428                   else
429                     printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
430                 }
431               ++x;
432               if (x >= width)
433                 {
434                   x = 0;
435                   ++y;
436                 }
437             }
438         }
439     }
440
441   for(int i = 0; i < 15; ++i)
442     {
443       ia_tiles[i].resize(width + 1, 0);
444       bg_tiles[i].resize(width + 1, 0);
445       fg_tiles[i].resize(width + 1, 0);
446     }
447
448   int i = 0;
449   int j = 0;
450   for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
451     {
452       ia_tiles[j][i] = (*it);
453       if(i == width - 1)
454         {
455           i = -1;
456           ++j;
457         }
458     }
459
460   i = j = 0;
461   for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
462     {
463
464       bg_tiles[j][i] = (*it);
465       if(i == width - 1)
466         {
467           i = -1;
468           ++j;
469         }
470     }
471
472   i = j = 0;
473   for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
474     {
475
476       fg_tiles[j][i] = (*it);
477       if(i == width - 1)
478         {
479           i = -1;
480           ++j;
481         }
482     }
483
484   //  Mark the end position of this level!
485   // FIXME: -10 is a rather random value, we still need some kind of
486   // real levelend gola
487   endpos = 32*(width-10);
488
489   fclose(fi);
490   return 0;
491 }
492
493 /* Save data for level: */
494
495 void 
496 Level::save(const  char * subset, int level)
497 {
498   char filename[1024];
499   char str[80];
500
501   /* Save data file: */
502   sprintf(str, "/levels/%s/", subset);
503   fcreatedir(str);
504   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset, level);
505   if(!fwriteable(filename))
506     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset, level);
507
508   FILE * fi = fopen(filename, "w");
509   if (fi == NULL)
510     {
511       perror(filename);
512       st_shutdown();
513       exit(-1);
514     }
515
516
517   /* Write header: */
518   fprintf(fi,";SuperTux-Level\n");
519   fprintf(fi,"(supertux-level\n");
520
521   fprintf(fi,"  (version %d)\n", 1);
522   fprintf(fi,"  (name \"%s\")\n", name.c_str());
523   fprintf(fi,"  (author \"%s\")\n", author.c_str());
524   fprintf(fi,"  (theme \"%s\")\n", theme.c_str());
525   fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
526   fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
527   fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
528   fprintf(fi,"  (bkgd_top_red %d)\n", bkgd_top.red);
529   fprintf(fi,"  (bkgd_top_green %d)\n", bkgd_top.green);
530   fprintf(fi,"  (bkgd_top_blue %d)\n", bkgd_top.blue);
531   fprintf(fi,"  (bkgd_bottom_red %d)\n", bkgd_bottom.red);
532   fprintf(fi,"  (bkgd_bottom_green %d)\n", bkgd_bottom.green);
533   fprintf(fi,"  (bkgd_bottom_blue %d)\n", bkgd_bottom.blue);
534   fprintf(fi,"  (time %d)\n", time_left);
535   fprintf(fi,"  (width %d)\n", width);
536   fprintf(fi,"  (gravity %2.1f)\n", gravity);
537   fprintf(fi,"  (background-tm ");
538
539   for(int y = 0; y < 15; ++y)
540     {
541       for(int i = 0; i < width; ++i)
542         fprintf(fi," %d ", bg_tiles[y][i]);
543     }
544
545   fprintf( fi,")\n");
546   fprintf(fi,"  (interactive-tm ");
547
548   for(int y = 0; y < 15; ++y)
549     {
550       for(int i = 0; i < width; ++i)
551         fprintf(fi," %d ", ia_tiles[y][i]);
552     }
553
554   fprintf( fi,")\n");
555   fprintf(fi,"  (foreground-tm ");
556
557   for(int y = 0; y < 15; ++y)
558     {
559       for(int i = 0; i < width; ++i)
560         fprintf(fi," %d ", fg_tiles[y][i]);
561     }
562
563   fprintf( fi,")\n");
564
565   fprintf( fi,"(reset-points\n");
566   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
567       i != reset_points.end(); ++i)
568     fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
569   fprintf( fi,")\n");
570
571   fprintf( fi,"(objects\n");
572
573   for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
574       it != badguy_data.end();
575       ++it)
576     fprintf( fi,"(%s (x %d) (y %d) (stay-on-platform %s))\n",
577              badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y,
578              it->stay_on_platform ? "#t" : "#f");
579
580   fprintf( fi,")\n");
581
582   fprintf( fi,")\n");
583
584   fclose(fi);
585 }
586
587
588 /* Unload data for this level: */
589
590 void
591 Level::cleanup()
592 {
593   for(int i=0; i < 15; ++i)
594     {
595       bg_tiles[i].clear();
596       ia_tiles[i].clear();
597       fg_tiles[i].clear();
598     }
599
600   reset_points.clear();
601   name.clear();
602   author.clear();
603   theme.clear();
604   song_title.clear();
605   bkgd_image.clear();
606
607   badguy_data.clear();
608 }
609
610 void 
611 Level::load_gfx()
612 {
613   if(!bkgd_image.empty())
614     {
615       char fname[1024];
616       snprintf(fname, 1024, "%s/background/%s", st_dir, bkgd_image.c_str());
617       if(!faccessible(fname))
618         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), bkgd_image.c_str());
619       img_bkgd = new Surface(fname, IGNORE_ALPHA);
620     }
621   else
622     {
623       /* Quick hack to make sure an image is loaded, when we are freeing it afterwards. */
624       load_image(&img_bkgd, theme,"solid0.png", IGNORE_ALPHA);
625     }
626 }
627
628 void
629 Level::free_gfx()
630 {
631   delete img_bkgd;
632 }
633
634 /* Load a level-specific graphic... */
635 void
636 Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
637 {
638   char fname[1024];
639
640   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
641   if(!faccessible(fname))
642     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
643
644   *ptexture = new Surface(fname, use_alpha);
645 }
646
647 /* Change the size of a level (width) */
648 void 
649 Level::change_size (int new_width)
650 {
651   if(new_width < 21)
652     new_width = 21;
653
654   for(int y = 0; y < 15; ++y)
655     {
656       ia_tiles[y].resize(new_width, 0);
657       bg_tiles[y].resize(new_width, 0);
658       fg_tiles[y].resize(new_width, 0);
659     }
660
661   width = new_width;
662 }
663
664 void
665 Level::change(float x, float y, int tm, unsigned int c)
666 {
667   int yy = ((int)y / 32);
668   int xx = ((int)x / 32);
669
670   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
671     {
672       switch(tm)
673         {
674         case TM_BG:
675           bg_tiles[yy][xx] = c;
676           break;
677         case TM_IA:
678           ia_tiles[yy][xx] = c;
679           break;
680         case TM_FG:
681           fg_tiles[yy][xx] = c;
682           break;
683         }
684     }
685 }
686
687 void 
688 Level::free_song(void)
689 {
690   free_music(level_song);
691   free_music(level_song_fast);
692 }
693
694 void
695 Level::load_song()
696 {
697   char* song_path;
698   char* song_subtitle;
699
700   level_song = ::load_song(datadir + "/music/" + song_title);
701
702   song_path = (char *) malloc(sizeof(char) * datadir.length() +
703                               strlen(song_title.c_str()) + 8 + 5);
704   song_subtitle = strdup(song_title.c_str());
705   strcpy(strstr(song_subtitle, "."), "\0");
706   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
707           song_subtitle, strstr(song_title.c_str(), "."));
708   level_song_fast = ::load_song(song_path);
709   free(song_subtitle);
710   free(song_path);
711 }
712
713 unsigned int 
714 Level::gettileid(float x, float y)
715 {
716   int xx, yy;
717   unsigned int c;
718
719   yy = ((int)y / 32);
720   xx = ((int)x / 32);
721
722   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= width)
723     c = ia_tiles[yy][xx];
724   else
725     c = 0;
726
727   return c;
728 }
729
730 /* EOF */