869c1e2ba4cc63697e807b14696fd3cff08095d5
[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 #include "resources.h"
35 #include "music_manager.h"
36 #include "gameobjs.h"
37
38 using namespace std;
39
40 LevelSubset::LevelSubset()
41     : image(0), levels(0)
42 {
43 }
44
45 LevelSubset::~LevelSubset()
46 {
47   delete image;
48 }
49
50 void LevelSubset::create(const std::string& subset_name)
51 {
52   Level new_lev;
53   LevelSubset new_subset;
54   new_subset.name = subset_name;
55   new_subset.title = "Unknown Title";
56   new_subset.description = "No description so far.";
57   new_subset.save();
58   new_lev.init_defaults();
59   new_lev.save(subset_name, 1);
60 }
61
62 void LevelSubset::parse (lisp_object_t* cursor)
63 {
64   while(!lisp_nil_p(cursor))
65     {
66       lisp_object_t* cur = lisp_car(cursor);
67       char *s;
68
69       if (!lisp_cons_p(cur) || !lisp_symbol_p (lisp_car(cur)))
70         {
71           printf("Not good");
72         }
73       else
74         {
75           if (strcmp(lisp_symbol(lisp_car(cur)), "title") == 0)
76             {
77               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
78                 {
79                   title = s;
80                 }
81             }
82           else if (strcmp(lisp_symbol(lisp_car(cur)), "description") == 0)
83             {
84               if(( s = lisp_string(lisp_car(lisp_cdr(cur)))) != NULL)
85                 {
86                   description = s;
87                 }
88             }
89         }
90       cursor = lisp_cdr (cursor);
91     }
92 }
93
94 void LevelSubset::load(char *subset)
95 {
96   FILE* fi;
97   char filename[1024];
98   char str[1024];
99   int i;
100   lisp_object_t* root_obj = 0;
101
102   name = subset;
103
104   snprintf(filename, 1024, "%s/levels/%s/info", st_dir, subset);
105   if(!faccessible(filename))
106     snprintf(filename, 1024, "%s/levels/%s/info", datadir.c_str(), subset);
107   if(faccessible(filename))
108     {
109       fi = fopen(filename, "r");
110       if (fi == NULL)
111         {
112           perror(filename);
113         }
114       lisp_stream_t stream;
115       lisp_stream_init_file (&stream, fi);
116       root_obj = lisp_read (&stream);
117
118       if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
119         {
120           printf("World: Parse Error in file %s", filename);
121         }
122
123       lisp_object_t* cur = lisp_car(root_obj);
124
125       if (!lisp_symbol_p (cur))
126         {
127           printf("World: Read error in %s",filename);
128         }
129
130       if (strcmp(lisp_symbol(cur), "supertux-level-subset") == 0)
131         {
132           parse(lisp_cdr(root_obj));
133
134         }
135
136       lisp_free(root_obj);
137       fclose(fi);
138
139       snprintf(str, 1024, "%s.png", filename);
140       if(faccessible(str))
141         {
142           delete image;
143           image = new Surface(str,IGNORE_ALPHA);
144         }
145       else
146         {
147           snprintf(filename, 1024, "%s/images/status/level-subset-info.png", datadir.c_str());
148           delete image;
149           image = new Surface(filename,IGNORE_ALPHA);
150         }
151     }
152
153   for(i=1; i != -1; ++i)
154     {
155       /* Get the number of levels in this subset */
156       snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset,i);
157       if(!faccessible(filename))
158         {
159           snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset,i);
160           if(!faccessible(filename))
161             break;
162         }
163     }
164   levels = --i;
165 }
166
167 void LevelSubset::save()
168 {
169   FILE* fi;
170   string filename;
171
172   /* Save data file: */
173   filename = "/levels/" + name + "/";
174
175   fcreatedir(filename.c_str());
176   filename = string(st_dir) + "/levels/" + name + "/info";
177   if(!fwriteable(filename.c_str()))
178     filename = datadir + "/levels/" + name + "/info";
179   if(fwriteable(filename.c_str()))
180     {
181       fi = fopen(filename.c_str(), "w");
182       if (fi == NULL)
183         {
184           perror(filename.c_str());
185         }
186
187       /* Write header: */
188       fprintf(fi,";SuperTux-Level-Subset\n");
189       fprintf(fi,"(supertux-level-subset\n");
190
191       /* Save title info: */
192       fprintf(fi,"  (title \"%s\")\n", title.c_str());
193
194       /* Save the description: */
195       fprintf(fi,"  (description \"%s\")\n", description.c_str());
196
197       fprintf( fi,")");
198       fclose(fi);
199
200     }
201 }
202
203 Level::Level()
204   : img_bkgd(0)
205 {
206   init_defaults();
207 }
208
209 Level::Level(const std::string& subset, int level)
210   : img_bkgd(0)
211 {
212   if(load(subset, level) < 0)
213     st_abort("Couldn't load level from subset", subset.c_str());
214 }
215
216 Level::Level(const std::string& filename)
217   : img_bkgd(0)
218 {
219   if(load(filename) < 0)
220     st_abort("Couldn't load level " , filename.c_str());
221 }
222
223 Level::~Level()
224 {
225   delete img_bkgd;
226 }
227
228 void
229 Level::init_defaults()
230 {
231   name       = "UnNamed";
232   author     = "UnNamed";
233   song_title = "Mortimers_chipdisko.mod";
234   bkgd_image = "arctis.png";
235   width      = 21;
236   height     = 15;
237   start_pos_x = 100;
238   start_pos_y = 170;
239   time_left  = 100;
240   gravity    = 10.;
241   back_scrolling = false;
242   hor_autoscroll_speed = 0;
243   bkgd_speed = 50;
244   bkgd_top.red   = 0;
245   bkgd_top.green = 0;
246   bkgd_top.blue  = 0;
247   bkgd_bottom.red   = 255;
248   bkgd_bottom.green = 255;
249   bkgd_bottom.blue  = 255;
250
251   bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
252   ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
253   fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
254
255   for(int i = 0; i < height; ++i)
256     {
257       ia_tiles[i].resize(width+1, 0);
258       ia_tiles[i][width] = (unsigned int) '\0';
259
260       for(int y = 0; y < width; ++y)
261         ia_tiles[i][y] = 0;
262
263       bg_tiles[i].resize(width+1, 0);
264       bg_tiles[i][width] = (unsigned int) '\0';
265       for(int y = 0; y < width; ++y)
266         bg_tiles[i][y] = 0;
267
268       fg_tiles[i].resize(width+1, 0);
269       fg_tiles[i][width] = (unsigned int) '\0';
270       for(int y = 0; y < width; ++y)
271         fg_tiles[i][y] = 0;
272     }
273 }
274
275 int
276 Level::load(const std::string& subset, int level)
277 {
278   char filename[1024];
279
280   // Load data file:
281   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(), level);
282   if(!faccessible(filename))
283     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(), subset.c_str(), level);
284
285   return load(filename);
286 }
287
288 int 
289 Level::load(const std::string& filename)
290 {
291   lisp_object_t* root_obj = lisp_read_from_file(filename);
292   if (!root_obj)
293     {
294       std::cout << "Level: Couldn't load file: " << filename << std::endl;
295       return -1;
296     }
297
298   if (root_obj->type == LISP_TYPE_EOF || root_obj->type == LISP_TYPE_PARSE_ERROR)
299     {
300       printf("World: Parse Error in file %s", filename.c_str());
301       return -1;
302     }
303
304   vector<int> ia_tm;
305   vector<int> bg_tm;
306   vector<int> fg_tm;
307
308   int version = 0;
309   if (strcmp(lisp_symbol(lisp_car(root_obj)), "supertux-level") == 0)
310     {
311       LispReader reader(lisp_cdr(root_obj));
312       version = 0;
313       reader.read_int("version",  &version);
314       if(!reader.read_int("width",  &width))
315         st_abort("No width specified for level.", "");
316       if (!reader.read_int("start_pos_x", &start_pos_x)) start_pos_x = 100;
317       if (!reader.read_int("start_pos_y", &start_pos_y)) start_pos_y = 170;
318       time_left = 500;
319       if(!reader.read_int("time",  &time_left)) {
320         printf("Warning no time specified for level.\n");
321       }
322       
323       height = 15;
324       reader.read_int("height",  &height);
325       
326       back_scrolling = false;
327       reader.read_bool("back_scrolling",  &back_scrolling);
328
329       hor_autoscroll_speed = 0;
330       reader.read_float("hor_autoscroll_speed",  &hor_autoscroll_speed);
331       
332       bkgd_speed = 50;
333       reader.read_int("bkgd_speed",  &bkgd_speed);
334
335       
336       bkgd_top.red = bkgd_top.green = bkgd_top.blue = 0;
337       reader.read_int("bkgd_red_top",  &bkgd_top.red);
338       reader.read_int("bkgd_green_top",  &bkgd_top.green);
339       reader.read_int("bkgd_blue_top",  &bkgd_top.blue);
340
341       bkgd_bottom.red = bkgd_bottom.green = bkgd_bottom.blue = 0;
342       reader.read_int("bkgd_red_bottom",  &bkgd_bottom.red);
343       reader.read_int("bkgd_green_bottom",  &bkgd_bottom.green);
344       reader.read_int("bkgd_blue_bottom",  &bkgd_bottom.blue);
345
346       gravity = 10;
347       reader.read_float("gravity",  &gravity);
348       name = "Noname";
349       reader.read_string("name",  &name);
350       author = "unknown author";
351       reader.read_string("author", &author);
352       song_title = "";
353       reader.read_string("music",  &song_title);
354       bkgd_image = "";
355       reader.read_string("background",  &bkgd_image);
356       particle_system = "";
357       reader.read_string("particle_system", &particle_system);
358
359       reader.read_int_vector("background-tm",  &bg_tm);
360
361       if (!reader.read_int_vector("interactive-tm", &ia_tm))
362         reader.read_int_vector("tilemap", &ia_tm);
363
364       reader.read_int_vector("foreground-tm",  &fg_tm);
365
366       { // Read ResetPoints
367         lisp_object_t* cur = 0;
368         if (reader.read_lisp("reset-points",  &cur))
369           {
370             while (!lisp_nil_p(cur))
371               {
372                 lisp_object_t* data = lisp_car(cur);
373
374                 ResetPoint pos;
375
376                 LispReader reader(lisp_cdr(data));
377                 if (reader.read_int("x", &pos.x)
378                     && reader.read_int("y", &pos.y))
379                   {
380                     reset_points.push_back(pos);
381                   }
382
383                 cur = lisp_cdr(cur);
384               }
385           }
386       }
387
388       { // Read BadGuys
389         lisp_object_t* cur = 0;
390         if (reader.read_lisp("objects",  &cur))
391           {
392             while (!lisp_nil_p(cur))
393               {
394                 lisp_object_t* data = lisp_car(cur);
395                 std::string object_type = "";
396
397                 LispReader reader(lisp_cdr(data));
398                 reader.read_string("type", &object_type);
399
400                 if (object_type == "badguy" || object_type == "")
401                 {
402                   BadGuyData bg_data;
403                   bg_data.kind = badguykind_from_string(lisp_symbol(lisp_car(data)));
404                   reader.read_int("x", &bg_data.x);
405                   reader.read_int("y", &bg_data.y);
406                   reader.read_bool("stay-on-platform", &bg_data.stay_on_platform);
407
408                   badguy_data.push_back(bg_data);
409                 }
410                 else
411                 {
412                     if (lisp_symbol(lisp_car(data)) == "trampoline")
413                     {
414                       ObjectData<TrampolineData> _trampoline_data;
415                     }
416                 }
417
418                 cur = lisp_cdr(cur);
419               }
420           }
421       }
422
423       // Convert old levels to the new tile numbers
424       if (version == 0)
425         {
426           std::map<char, int> transtable;
427           transtable['.'] = 0;
428           transtable['x'] = 104;
429           transtable['X'] = 77;
430           transtable['y'] = 78;
431           transtable['Y'] = 105;
432           transtable['A'] = 83;
433           transtable['B'] = 102;
434           transtable['!'] = 103;
435           transtable['a'] = 84;
436           transtable['C'] = 85;
437           transtable['D'] = 86;
438           transtable['E'] = 87;
439           transtable['F'] = 88;
440           transtable['c'] = 89;
441           transtable['d'] = 90;
442           transtable['e'] = 91;
443           transtable['f'] = 92;
444
445           transtable['G'] = 93;
446           transtable['H'] = 94;
447           transtable['I'] = 95;
448           transtable['J'] = 96;
449
450           transtable['g'] = 97;
451           transtable['h'] = 98;
452           transtable['i'] = 99;
453           transtable['j'] = 100
454                             ;
455           transtable['#'] = 11;
456           transtable['['] = 13;
457           transtable['='] = 14;
458           transtable[']'] = 15;
459           transtable['$'] = 82;
460           transtable['^'] = 76;
461           transtable['*'] = 80;
462           transtable['|'] = 79;
463           transtable['\\'] = 81;
464           transtable['&'] = 75;
465
466           int x = 0;
467           int y = 0;
468           for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
469             {
470               if (*i == '0' || *i == '1' || *i == '2')
471                 {
472                   badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
473                                                    x*32, y*32, false));
474                   *i = 0;
475                 }
476               else
477                 {
478                   std::map<char, int>::iterator j = transtable.find(*i);
479                   if (j != transtable.end())
480                     *i = j->second;
481                   else
482                     printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
483                 }
484               ++x;
485               if (x >= width)
486                 {
487                   x = 0;
488                   ++y;
489                 }
490             }
491         }
492     }
493
494   bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
495   ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
496   fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
497
498   for(int i = 0; i < height; ++i)
499     {
500       ia_tiles[i].resize(width + 1, 0);
501       bg_tiles[i].resize(width + 1, 0);
502       fg_tiles[i].resize(width + 1, 0);
503     }
504
505   int i = 0;
506   int j = 0;
507   for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
508     {
509       ia_tiles[j][i] = (*it);
510       if(i == width - 1)
511         {
512           i = -1;
513           ++j;
514         }
515     }
516
517   i = j = 0;
518   for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
519     {
520
521       bg_tiles[j][i] = (*it);
522       if(i == width - 1)
523         {
524           i = -1;
525           ++j;
526         }
527     }
528
529   i = j = 0;
530   for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
531     {
532
533       fg_tiles[j][i] = (*it);
534       if(i == width - 1)
535         {
536           i = -1;
537           ++j;
538         }
539     }
540
541   lisp_free(root_obj);
542   return 0;
543 }
544
545 /* Save data for level: */
546
547 void 
548 Level::save(const std::string& subset, int level)
549 {
550   char filename[1024];
551   char str[80];
552
553   /* Save data file: */
554   sprintf(str, "/levels/%s/", subset.c_str());
555   fcreatedir(str);
556   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(),
557       level);
558   if(!fwriteable(filename))
559     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
560         subset.c_str(), level);
561
562   FILE * fi = fopen(filename, "w");
563   if (fi == NULL)
564     {
565       perror(filename);
566       st_shutdown();
567       exit(-1);
568     }
569
570
571   /* Write header: */
572   fprintf(fi,";SuperTux level made using the built-in leveleditor\n");
573   fprintf(fi,"(supertux-level\n");
574
575   fprintf(fi,"  (version %d)\n", 1);
576   fprintf(fi,"  (name \"%s\")\n", name.c_str());
577   fprintf(fi,"  (author \"%s\")\n", author.c_str());
578   fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
579   fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
580   fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
581   fprintf(fi,"  (bkgd_speed %d)\n", bkgd_speed);
582   fprintf(fi,"  (bkgd_red_top %d)\n", bkgd_top.red);
583   fprintf(fi,"  (bkgd_green_top %d)\n", bkgd_top.green);
584   fprintf(fi,"  (bkgd_blue_top %d)\n", bkgd_top.blue);
585   fprintf(fi,"  (bkgd_red_bottom %d)\n", bkgd_bottom.red);
586   fprintf(fi,"  (bkgd_green_bottom %d)\n", bkgd_bottom.green);
587   fprintf(fi,"  (bkgd_blue_bottom %d)\n", bkgd_bottom.blue);
588   fprintf(fi,"  (time %d)\n", time_left);
589   fprintf(fi,"  (width %d)\n", width);
590   fprintf(fi,"  (height %d)\n", height);
591   if(back_scrolling)
592     fprintf(fi,"  (back_scrolling #t)\n"); 
593   else
594     fprintf(fi,"  (back_scrolling #f)\n");
595   fprintf(fi,"  (hor_autoscroll_speed %2.1f)\n", hor_autoscroll_speed);
596   fprintf(fi,"  (gravity %2.1f)\n", gravity);
597   fprintf(fi,"  (background-tm ");
598
599   for(int y = 0; y < height; ++y)
600     {
601       for(int i = 0; i < width; ++i)
602         fprintf(fi," %d ", bg_tiles[y][i]);
603       fprintf(fi,"\n");
604     }
605
606   fprintf( fi,")\n");
607   fprintf(fi,"  (interactive-tm ");
608
609   for(int y = 0; y < height; ++y)
610     {
611       for(int i = 0; i < width; ++i)
612         fprintf(fi," %d ", ia_tiles[y][i]);
613       fprintf(fi,"\n");
614     }
615
616   fprintf( fi,")\n");
617   fprintf(fi,"  (foreground-tm ");
618
619   for(int y = 0; y < height; ++y)
620     {
621       for(int i = 0; i < width; ++i)
622         fprintf(fi," %d ", fg_tiles[y][i]);
623       fprintf(fi,"\n");
624     }
625
626   fprintf( fi,")\n");
627
628   fprintf( fi,"(reset-points\n");
629   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
630       i != reset_points.end(); ++i)
631     fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
632   fprintf( fi,")\n");
633
634   fprintf( fi,"(objects\n");
635
636   for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
637       it != badguy_data.end();
638       ++it)
639     fprintf( fi,"  (%s (x %d) (y %d) (stay-on-platform %s))\n",
640              badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y,
641              it->stay_on_platform ? "#t" : "#f");
642
643   fprintf( fi,")\n");
644
645   fprintf( fi,")\n");
646
647   fclose(fi);
648 }
649
650
651 /* Unload data for this level: */
652
653 void
654 Level::cleanup()
655 {
656   for(int i=0; i < 15; ++i)
657     {
658       bg_tiles[i].clear();
659       ia_tiles[i].clear();
660       fg_tiles[i].clear();
661     }
662
663   reset_points.clear();
664   name = "";
665   author = "";
666   song_title = "";
667   bkgd_image = "";
668
669   badguy_data.clear();
670 }
671
672 void 
673 Level::load_gfx()
674 {
675   if(!bkgd_image.empty())
676     {
677       char fname[1024];
678       snprintf(fname, 1024, "%s/background/%s", st_dir, bkgd_image.c_str());
679       if(!faccessible(fname))
680         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), bkgd_image.c_str());
681       delete img_bkgd;
682       img_bkgd = new Surface(fname, IGNORE_ALPHA);
683     }
684   else
685     {
686       delete img_bkgd;
687       img_bkgd = 0;
688     }
689 }
690
691 /* Load a level-specific graphic... */
692 void Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
693 {
694   char fname[1024];
695
696   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
697   if(!faccessible(fname))
698     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
699
700   *ptexture = new Surface(fname, use_alpha);
701 }
702
703 /* Change the size of a level */
704 void 
705 Level::change_width (int new_width)
706 {
707   if(new_width < 21)
708     new_width = 21;
709
710   for(int y = 0; y < height; ++y)
711     {
712       ia_tiles[y].resize(new_width, 0);
713       bg_tiles[y].resize(new_width, 0);
714       fg_tiles[y].resize(new_width, 0);
715     }
716
717   width = new_width;
718 }
719
720 void 
721 Level::change_height (int new_height)
722 {
723   if(new_height < 15)
724     new_height = 15;
725
726   bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
727   ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
728   fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
729
730   height = new_height;
731 }
732
733 void
734 Level::change(float x, float y, int tm, unsigned int c)
735 {
736   int yy = ((int)y / 32);
737   int xx = ((int)x / 32);
738
739   if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
740     {
741       switch(tm)
742         {
743         case TM_BG:
744           bg_tiles[yy][xx] = c;
745           break;
746         case TM_IA:
747           ia_tiles[yy][xx] = c;
748           break;
749         case TM_FG:
750           fg_tiles[yy][xx] = c;
751           break;
752         }
753     }
754 }
755
756 void Level::draw_bg()
757 {
758   // Tile background horizontally
759   int sx = (int)((float)scroll_x * ((float)bkgd_speed/100.0f)) % img_bkgd->w;
760   for (int i = 0; (i-1)*img_bkgd->w <= screen->w; i++)
761     img_bkgd->draw_part(i == 0 ? sx : 0, 0,
762                         i == 0 ? 0 : (img_bkgd->w * i) - sx, 0,
763                         i == 0 ? img_bkgd->w - sx : img_bkgd->w, img_bkgd->h);
764 }
765
766 void
767 Level::load_song()
768 {
769   char* song_path;
770   char* song_subtitle;
771
772   level_song = music_manager->load_music(datadir + "/music/" + song_title);
773
774   song_path = (char *) malloc(sizeof(char) * datadir.length() +
775                               strlen(song_title.c_str()) + 8 + 5);
776   song_subtitle = strdup(song_title.c_str());
777   strcpy(strstr(song_subtitle, "."), "\0");
778   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
779           song_subtitle, strstr(song_title.c_str(), "."));
780   if(!music_manager->exists_music(song_path)) {
781     level_song_fast = level_song;
782   } else {
783     level_song_fast = music_manager->load_music(song_path);
784   }
785   free(song_subtitle);
786   free(song_path);
787 }
788
789 MusicRef
790 Level::get_level_music()
791 {
792   return level_song;
793 }
794
795 MusicRef
796 Level::get_level_music_fast()
797 {
798   return level_song_fast;
799 }
800
801 unsigned int 
802 Level::gettileid(float x, float y) const
803 {
804   int xx, yy;
805   unsigned int c;
806
807   yy = ((int)y / 32);
808   xx = ((int)x / 32);
809
810   if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
811     c = ia_tiles[yy][xx];
812   else
813     c = 0;
814
815   return c;
816 }
817
818 unsigned int
819 Level::get_tile_at(int x, int y) const
820 {
821   if(x < 0 || x > width || y < 0 || y > height)
822     return 0;
823   
824   return ia_tiles[y][x];
825 }
826
827 /* EOF */