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