Y background scrolling. It should start be drawing from the bottom of the level to...
[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 (strcmp(lisp_symbol(lisp_car(data)),"trampoline") == 0)
413                     {
414                       ObjectData<TrampolineData> _trampoline_data;
415
416                       _trampoline_data.type = OBJ_TRAMPOLINE;
417                       reader.read_int("x", &_trampoline_data.x);
418                       reader.read_int("y", &_trampoline_data.y);
419                       reader.read_int("power", &_trampoline_data.type_specific.power);
420
421                       trampoline_data.push_back(_trampoline_data);
422                     }
423                 }
424
425                 cur = lisp_cdr(cur);
426               }
427           }
428       }
429
430       // Convert old levels to the new tile numbers
431       if (version == 0)
432         {
433           std::map<char, int> transtable;
434           transtable['.'] = 0;
435           transtable['x'] = 104;
436           transtable['X'] = 77;
437           transtable['y'] = 78;
438           transtable['Y'] = 105;
439           transtable['A'] = 83;
440           transtable['B'] = 102;
441           transtable['!'] = 103;
442           transtable['a'] = 84;
443           transtable['C'] = 85;
444           transtable['D'] = 86;
445           transtable['E'] = 87;
446           transtable['F'] = 88;
447           transtable['c'] = 89;
448           transtable['d'] = 90;
449           transtable['e'] = 91;
450           transtable['f'] = 92;
451
452           transtable['G'] = 93;
453           transtable['H'] = 94;
454           transtable['I'] = 95;
455           transtable['J'] = 96;
456
457           transtable['g'] = 97;
458           transtable['h'] = 98;
459           transtable['i'] = 99;
460           transtable['j'] = 100
461                             ;
462           transtable['#'] = 11;
463           transtable['['] = 13;
464           transtable['='] = 14;
465           transtable[']'] = 15;
466           transtable['$'] = 82;
467           transtable['^'] = 76;
468           transtable['*'] = 80;
469           transtable['|'] = 79;
470           transtable['\\'] = 81;
471           transtable['&'] = 75;
472
473           int x = 0;
474           int y = 0;
475           for(std::vector<int>::iterator i = ia_tm.begin(); i != ia_tm.end(); ++i)
476             {
477               if (*i == '0' || *i == '1' || *i == '2')
478                 {
479                   badguy_data.push_back(BadGuyData(static_cast<BadGuyKind>(*i-'0'),
480                                                    x*32, y*32, false));
481                   *i = 0;
482                 }
483               else
484                 {
485                   std::map<char, int>::iterator j = transtable.find(*i);
486                   if (j != transtable.end())
487                     *i = j->second;
488                   else
489                     printf("Error: conversion will fail, unsupported char: '%c' (%d)\n", *i, *i);
490                 }
491               ++x;
492               if (x >= width)
493                 {
494                   x = 0;
495                   ++y;
496                 }
497             }
498         }
499     }
500
501   bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
502   ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
503   fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
504
505   for(int i = 0; i < height; ++i)
506     {
507       ia_tiles[i].resize(width + 1, 0);
508       bg_tiles[i].resize(width + 1, 0);
509       fg_tiles[i].resize(width + 1, 0);
510     }
511
512   int i = 0;
513   int j = 0;
514   for(vector<int>::iterator it = ia_tm.begin(); it != ia_tm.end(); ++it, ++i)
515     {
516       ia_tiles[j][i] = (*it);
517       if(i == width - 1)
518         {
519           i = -1;
520           ++j;
521         }
522     }
523
524   i = j = 0;
525   for(vector<int>::iterator it = bg_tm.begin(); it != bg_tm.end(); ++it, ++i)
526     {
527
528       bg_tiles[j][i] = (*it);
529       if(i == width - 1)
530         {
531           i = -1;
532           ++j;
533         }
534     }
535
536   i = j = 0;
537   for(vector<int>::iterator it = fg_tm.begin(); it != fg_tm.end(); ++it, ++i)
538     {
539
540       fg_tiles[j][i] = (*it);
541       if(i == width - 1)
542         {
543           i = -1;
544           ++j;
545         }
546     }
547
548   lisp_free(root_obj);
549   return 0;
550 }
551
552 /* Save data for level: */
553
554 void 
555 Level::save(const std::string& subset, int level)
556 {
557   char filename[1024];
558   char str[80];
559
560   /* Save data file: */
561   sprintf(str, "/levels/%s/", subset.c_str());
562   fcreatedir(str);
563   snprintf(filename, 1024, "%s/levels/%s/level%d.stl", st_dir, subset.c_str(),
564       level);
565   if(!fwriteable(filename))
566     snprintf(filename, 1024, "%s/levels/%s/level%d.stl", datadir.c_str(),
567         subset.c_str(), level);
568
569   FILE * fi = fopen(filename, "w");
570   if (fi == NULL)
571     {
572       perror(filename);
573       st_shutdown();
574       exit(-1);
575     }
576
577
578   /* Write header: */
579   fprintf(fi,";SuperTux level made using the built-in leveleditor\n");
580   fprintf(fi,"(supertux-level\n");
581
582   fprintf(fi,"  (version %d)\n", 1);
583   fprintf(fi,"  (name \"%s\")\n", name.c_str());
584   fprintf(fi,"  (author \"%s\")\n", author.c_str());
585   fprintf(fi,"  (music \"%s\")\n", song_title.c_str());
586   fprintf(fi,"  (background \"%s\")\n", bkgd_image.c_str());
587   fprintf(fi,"  (particle_system \"%s\")\n", particle_system.c_str());
588   fprintf(fi,"  (bkgd_speed %d)\n", bkgd_speed);
589   fprintf(fi,"  (bkgd_red_top %d)\n", bkgd_top.red);
590   fprintf(fi,"  (bkgd_green_top %d)\n", bkgd_top.green);
591   fprintf(fi,"  (bkgd_blue_top %d)\n", bkgd_top.blue);
592   fprintf(fi,"  (bkgd_red_bottom %d)\n", bkgd_bottom.red);
593   fprintf(fi,"  (bkgd_green_bottom %d)\n", bkgd_bottom.green);
594   fprintf(fi,"  (bkgd_blue_bottom %d)\n", bkgd_bottom.blue);
595   fprintf(fi,"  (time %d)\n", time_left);
596   fprintf(fi,"  (width %d)\n", width);
597   fprintf(fi,"  (height %d)\n", height);
598   if(back_scrolling)
599     fprintf(fi,"  (back_scrolling #t)\n"); 
600   else
601     fprintf(fi,"  (back_scrolling #f)\n");
602   fprintf(fi,"  (hor_autoscroll_speed %2.1f)\n", hor_autoscroll_speed);
603   fprintf(fi,"  (gravity %2.1f)\n", gravity);
604   fprintf(fi,"  (background-tm ");
605
606   for(int y = 0; y < height; ++y)
607     {
608       for(int i = 0; i < width; ++i)
609         fprintf(fi," %d ", bg_tiles[y][i]);
610       fprintf(fi,"\n");
611     }
612
613   fprintf( fi,")\n");
614   fprintf(fi,"  (interactive-tm ");
615
616   for(int y = 0; y < height; ++y)
617     {
618       for(int i = 0; i < width; ++i)
619         fprintf(fi," %d ", ia_tiles[y][i]);
620       fprintf(fi,"\n");
621     }
622
623   fprintf( fi,")\n");
624   fprintf(fi,"  (foreground-tm ");
625
626   for(int y = 0; y < height; ++y)
627     {
628       for(int i = 0; i < width; ++i)
629         fprintf(fi," %d ", fg_tiles[y][i]);
630       fprintf(fi,"\n");
631     }
632
633   fprintf( fi,")\n");
634
635   fprintf( fi,"(reset-points\n");
636   for(std::vector<ResetPoint>::iterator i = reset_points.begin();
637       i != reset_points.end(); ++i)
638     fprintf( fi,"(point (x %d) (y %d))\n",i->x, i->y);
639   fprintf( fi,")\n");
640
641   fprintf( fi,"(objects\n");
642
643   for(std::vector<BadGuyData>::iterator it = badguy_data.begin();
644       it != badguy_data.end();
645       ++it)
646     fprintf( fi,"  (%s (x %d) (y %d) (stay-on-platform %s))\n",
647              badguykind_to_string((*it).kind).c_str(),(*it).x,(*it).y,
648              it->stay_on_platform ? "#t" : "#f");
649
650   fprintf( fi,")\n");
651
652   fprintf( fi,")\n");
653
654   fclose(fi);
655 }
656
657
658 /* Unload data for this level: */
659
660 void
661 Level::cleanup()
662 {
663   for(int i=0; i < 15; ++i)
664     {
665       bg_tiles[i].clear();
666       ia_tiles[i].clear();
667       fg_tiles[i].clear();
668     }
669
670   reset_points.clear();
671   name = "";
672   author = "";
673   song_title = "";
674   bkgd_image = "";
675
676   badguy_data.clear();
677 }
678
679 void 
680 Level::load_gfx()
681 {
682   if(!bkgd_image.empty())
683     {
684       char fname[1024];
685       snprintf(fname, 1024, "%s/background/%s", st_dir, bkgd_image.c_str());
686       if(!faccessible(fname))
687         snprintf(fname, 1024, "%s/images/background/%s", datadir.c_str(), bkgd_image.c_str());
688       delete img_bkgd;
689       img_bkgd = new Surface(fname, IGNORE_ALPHA);
690     }
691   else
692     {
693       delete img_bkgd;
694       img_bkgd = 0;
695     }
696 }
697
698 /* Load a level-specific graphic... */
699 void Level::load_image(Surface** ptexture, string theme,const  char * file, int use_alpha)
700 {
701   char fname[1024];
702
703   snprintf(fname, 1024, "%s/themes/%s/%s", st_dir, theme.c_str(), file);
704   if(!faccessible(fname))
705     snprintf(fname, 1024, "%s/images/themes/%s/%s", datadir.c_str(), theme.c_str(), file);
706
707   *ptexture = new Surface(fname, use_alpha);
708 }
709
710 /* Change the size of a level */
711 void 
712 Level::change_width (int new_width)
713 {
714   if(new_width < 21)
715     new_width = 21;
716
717   for(int y = 0; y < height; ++y)
718     {
719       ia_tiles[y].resize(new_width, 0);
720       bg_tiles[y].resize(new_width, 0);
721       fg_tiles[y].resize(new_width, 0);
722     }
723
724   width = new_width;
725 }
726
727 void 
728 Level::change_height (int new_height)
729 {
730   if(new_height < 15)
731     new_height = 15;
732
733   bg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
734   ia_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
735   fg_tiles.resize(height+1, std::vector<unsigned int>(width, 0));
736
737   height = new_height;
738 }
739
740 void
741 Level::change(float x, float y, int tm, unsigned int c)
742 {
743   int yy = ((int)y / 32);
744   int xx = ((int)x / 32);
745
746   if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
747     {
748       switch(tm)
749         {
750         case TM_BG:
751           bg_tiles[yy][xx] = c;
752           break;
753         case TM_IA:
754           ia_tiles[yy][xx] = c;
755           break;
756         case TM_FG:
757           fg_tiles[yy][xx] = c;
758           break;
759         }
760     }
761 }
762
763 void Level::draw_bg()
764 {
765   // Tile background horizontally
766   int sx = (int)((float)scroll_x * ((float)bkgd_speed/100.0f)) % img_bkgd->w;
767   int sy = (int)((float)scroll_y * ((float)bkgd_speed/100.0f)) % img_bkgd->h;
768   for (int x = 0; (x-1)*img_bkgd->w <= screen->w; x++)
769     for (int y = 0; (y-1)*img_bkgd->h <= screen->h; y++)
770       img_bkgd->draw_part(x == 0 ? sx : 0, y == 0 ? sy : 0,
771                         x == 0 ? 0 : (img_bkgd->w * x) - sx, y == 0 ? 0 : (img_bkgd->h * y) - sy + (height*32 - screen->h),
772                         x == 0 ? img_bkgd->w - sx : img_bkgd->w, y == 0 ? img_bkgd->h - sy : img_bkgd->h);
773 }
774
775 void
776 Level::load_song()
777 {
778   char* song_path;
779   char* song_subtitle;
780
781   level_song = music_manager->load_music(datadir + "/music/" + song_title);
782
783   song_path = (char *) malloc(sizeof(char) * datadir.length() +
784                               strlen(song_title.c_str()) + 8 + 5);
785   song_subtitle = strdup(song_title.c_str());
786   strcpy(strstr(song_subtitle, "."), "\0");
787   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), 
788           song_subtitle, strstr(song_title.c_str(), "."));
789   if(!music_manager->exists_music(song_path)) {
790     level_song_fast = level_song;
791   } else {
792     level_song_fast = music_manager->load_music(song_path);
793   }
794   free(song_subtitle);
795   free(song_path);
796 }
797
798 MusicRef
799 Level::get_level_music()
800 {
801   return level_song;
802 }
803
804 MusicRef
805 Level::get_level_music_fast()
806 {
807   return level_song_fast;
808 }
809
810 unsigned int 
811 Level::gettileid(float x, float y) const
812 {
813   int xx, yy;
814   unsigned int c;
815
816   yy = ((int)y / 32);
817   xx = ((int)x / 32);
818
819   if (yy >= 0 && yy < height && xx >= 0 && xx <= width)
820     c = ia_tiles[yy][xx];
821   else
822     c = 0;
823
824   return c;
825 }
826
827 unsigned int
828 Level::get_tile_at(int x, int y) const
829 {
830   if(x < 0 || x > width || y < 0 || y > height)
831     return 0;
832   
833   return ia_tiles[y][x];
834 }
835
836 /* EOF */