ecd15c9950d04cb2d946a6e8ea44f5da4fb1b7c3
[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   st_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   level_save(&new_lev,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 st_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 st_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 st_level::load(const char* filename)
249 {
250   FILE * fi;
251   lisp_object_t* root_obj = 0;
252   fi = fopen(filename, "r");
253   if (fi == NULL)
254     {
255       perror(filename);
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);
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 level_save(st_level* plevel,const  char * subset, int level)
446 {
447   FILE * fi;
448   char filename[1024];
449   int y,i;
450   char str[80];
451
452   /* Save data file: */
453   sprintf(str, "/levels/%s/", subset);
454   fcreatedir(str);
455   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset, level);
456   if(!fwriteable(filename))
457     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset, level);
458
459   fi = fopen(filename, "w");
460   if (fi == NULL)
461     {
462       perror(filename);
463       st_shutdown();
464       exit(-1);
465     }
466
467
468   /* Write header: */
469   fprintf(fi,";SuperTux-Level\n");
470   fprintf(fi,"(supertux-level\n");
471
472   fprintf(fi,"  (version %d)\n", 1);
473   fprintf(fi,"  (name \"%s\")\n", plevel->name.c_str());
474   fprintf(fi,"  (theme \"%s\")\n", plevel->theme.c_str());
475   fprintf(fi,"  (music \"%s\")\n", plevel->song_title.c_str());
476   fprintf(fi,"  (background \"%s\")\n", plevel->bkgd_image.c_str());
477   fprintf(fi,"  (particle_system \"%s\")\n", plevel->particle_system.c_str());
478   fprintf(fi,"  (bkgd_red %d)\n", plevel->bkgd_red);
479   fprintf(fi,"  (bkgd_green %d)\n", plevel->bkgd_green);
480   fprintf(fi,"  (bkgd_blue %d)\n", plevel->bkgd_blue);
481   fprintf(fi,"  (time %d)\n", plevel->time_left);
482   fprintf(fi,"  (width %d)\n", plevel->width);
483   fprintf(fi,"  (gravity %2.1f)\n", plevel->gravity);
484   fprintf(fi,"  (background-tm ");
485
486   for(y = 0; y < 15; ++y)
487     {
488       for(i = 0; i < plevel->width; ++i)
489         fprintf(fi," %d ", plevel->bg_tiles[y][i]);
490     }
491
492   fprintf( fi,")\n");
493   fprintf(fi,"  (interactive-tm ");
494
495   for(y = 0; y < 15; ++y)
496     {
497       for(i = 0; i < plevel->width; ++i)
498         fprintf(fi," %d ", plevel->ia_tiles[y][i]);
499     }
500
501   fprintf( fi,")\n");
502   fprintf(fi,"  (foreground-tm ");
503
504   for(y = 0; y < 15; ++y)
505     {
506       for(i = 0; i < plevel->width; ++i)
507         fprintf(fi," %d ", plevel->fg_tiles[y][i]);
508     }
509
510   fprintf( fi,")\n");
511   fprintf( fi,"(objects\n");
512
513   for(std::vector<BadGuyData>::iterator it = plevel->
514       badguy_data.begin();
515       it != plevel->badguy_data.end();
516       ++it)
517     fprintf( fi,"(%s (x %d) (y %d))\n",badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y);
518
519   fprintf( fi,")\n");
520
521   fprintf( fi,")\n");
522
523   fclose(fi);
524 }
525
526
527 /* Unload data for this level: */
528
529 void
530 st_level::cleanup()
531 {
532   for(int i=0; i < 15; ++i)
533     free(bg_tiles[i]);
534   for(int i=0; i < 15; ++i)
535     free(ia_tiles[i]);
536   for(int i=0; i < 15; ++i)
537     free(fg_tiles[i]);
538
539   name.clear();
540   theme.clear();
541   song_title.clear();
542   bkgd_image.clear();
543
544   badguy_data.clear();
545 }
546
547 /* Load graphics: */
548
549 void level_load_gfx(st_level *plevel)
550 {
551   level_load_image(&img_brick[0],plevel->theme,"brick0.png", IGNORE_ALPHA);
552   level_load_image(&img_brick[1],plevel->theme,"brick1.png", IGNORE_ALPHA);
553
554   level_load_image(&img_solid[0],plevel->theme,"solid0.png", USE_ALPHA);
555   level_load_image(&img_solid[1],plevel->theme,"solid1.png", USE_ALPHA);
556   level_load_image(&img_solid[2],plevel->theme,"solid2.png", USE_ALPHA);
557   level_load_image(&img_solid[3],plevel->theme,"solid3.png", USE_ALPHA);
558
559   level_load_image(&img_bkgd_tile[0][0],plevel->theme,"bkgd-00.png", USE_ALPHA);
560   level_load_image(&img_bkgd_tile[0][1],plevel->theme,"bkgd-01.png", USE_ALPHA);
561   level_load_image(&img_bkgd_tile[0][2],plevel->theme,"bkgd-02.png", USE_ALPHA);
562   level_load_image(&img_bkgd_tile[0][3],plevel->theme,"bkgd-03.png", USE_ALPHA);
563
564   level_load_image(&img_bkgd_tile[1][0],plevel->theme,"bkgd-10.png", USE_ALPHA);
565   level_load_image(&img_bkgd_tile[1][1],plevel->theme,"bkgd-11.png", USE_ALPHA);
566   level_load_image(&img_bkgd_tile[1][2],plevel->theme,"bkgd-12.png", USE_ALPHA);
567   level_load_image(&img_bkgd_tile[1][3],plevel->theme,"bkgd-13.png", USE_ALPHA);
568
569   if(!plevel->bkgd_image.empty())
570     {
571       char fname[1024];
572       snprintf(fname, 1024, "%s/background/%s", st_dir, plevel->bkgd_image.c_str());
573       if(!faccessible(fname))
574         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), plevel->bkgd_image.c_str());
575       texture_load(&img_bkgd, fname, IGNORE_ALPHA);
576     }
577   else
578     {
579       /* Quick hack to make sure an image is loaded, when we are freeing it afterwards. */#
580       level_load_image(&img_bkgd, plevel->theme,"solid0.png", IGNORE_ALPHA);
581     }
582 }
583
584 /* Free graphics data for this level: */
585
586 void level_free_gfx(void)
587 {
588   int i;
589
590   for (i = 0; i < 2; i++)
591     {
592       texture_free(&img_brick[i]);
593     }
594   for (i = 0; i < 4; i++)
595     {
596       texture_free(&img_solid[i]);
597       texture_free(&img_bkgd_tile[0][i]);
598       texture_free(&img_bkgd_tile[1][i]);
599     }
600
601   texture_free(&img_bkgd);
602 }
603
604 /* Load a level-specific graphic... */
605
606 void level_load_image(texture_type* ptexture, string theme,const  char * file, int use_alpha)
607 {
608   char fname[1024];
609
610   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
611   if(!faccessible(fname))
612     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
613
614   texture_load(ptexture, fname, use_alpha);
615 }
616
617 void tilemap_change_size(unsigned int** tilemap[15], int w, int old_w)
618 {
619   int j,y;
620   for(y = 0; y < 15; ++y)
621     {
622       *tilemap[y] = (unsigned int*) realloc(*tilemap[y],(w+1)*sizeof(unsigned int));
623       if(w > old_w)
624         for(j = 0; j < w - old_w; ++j)
625           *tilemap[y][old_w+j] = 0;
626       *tilemap[y][w] = 0;
627     }
628 }
629
630 /* Change the size of a level (width) */
631 void level_change_size (st_level* plevel, int new_width)
632 {
633   if(new_width < 21)
634     new_width = 21;
635   tilemap_change_size((unsigned int***)&plevel->ia_tiles,new_width,plevel->width);
636   tilemap_change_size((unsigned int***)&plevel->bg_tiles,new_width,plevel->width);
637   tilemap_change_size((unsigned int***)&plevel->fg_tiles,new_width,plevel->width);
638   plevel->width = new_width;
639
640 }
641
642 /* Edit a piece of the map! */
643
644 void level_change(st_level* plevel, float x, float y, int tm, unsigned int c)
645 {
646   int xx, yy;
647
648   yy = ((int)y / 32);
649   xx = ((int)x / 32);
650
651   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= plevel->width)
652     {
653       switch(tm)
654         {
655         case TM_BG:
656           plevel->bg_tiles[yy][xx] = c;
657           break;
658         case TM_IA:
659           plevel->ia_tiles[yy][xx] = c;
660           break;
661         case TM_FG:
662           plevel->fg_tiles[yy][xx] = c;
663           break;
664         }
665     }
666 }
667
668 /* Free music data for this level: */
669
670 void level_free_song(void)
671 {
672   free_music(level_song);
673   free_music(level_song_fast);
674 }
675
676 /* Load music: */
677
678 void level_load_song(st_level* plevel)
679 {
680
681   char * song_path;
682   char * song_subtitle;
683
684   level_song = load_song(datadir + "/music/" + plevel->song_title);
685
686   song_path = (char *) malloc(sizeof(char) * datadir.length() +
687                               strlen(plevel->song_title.c_str()) + 8 + 5);
688   song_subtitle = strdup(plevel->song_title.c_str());
689   strcpy(strstr(song_subtitle, "."), "\0");
690   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), song_subtitle, strstr(plevel->song_title.c_str(), "."));
691   level_song_fast = load_song(song_path);
692   free(song_subtitle);
693   free(song_path);
694 }
695
696
697 unsigned int gettileid(float x, float y)
698 {
699   int xx, yy;
700   unsigned int c;
701
702   yy = ((int)y / 32);
703   xx = ((int)x / 32);
704
705   if (yy >= 0 && yy < 15 && xx >= 0 && xx <= current_level.width)
706     c = current_level.ia_tiles[yy][xx];
707   else
708     c = 0;
709
710   return c;
711 }
712
713 Tile* gettile(float x, float y)
714 {
715   return TileManager::instance()->get(gettileid(x, y));
716 }
717
718 bool issolid(float x, float y)
719 {
720   Tile* tile = TileManager::instance()->get(gettileid(x,y));
721   return tile && tile->solid;
722 }
723
724 bool isbrick(float x, float y)
725 {
726   Tile* tile = TileManager::instance()->get(gettileid(x,y));
727   return tile && tile->brick;
728 }
729
730 bool isice(float x, float y)
731 {
732   Tile* tile = TileManager::instance()->get(gettileid(x,y));
733   return tile && tile->ice;
734 }
735
736 bool isfullbox(float x, float y)
737 {
738   Tile* tile = TileManager::instance()->get(gettileid(x,y));
739   return tile && tile->fullbox;
740 }
741
742 bool isdistro(float x, float y)
743 {
744   Tile* tile = TileManager::instance()->get(gettileid(x,y));
745   return tile && tile->distro;
746 }
747
748 /* EOF */