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