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