Player should be drawn above enemies.
[supertux.git] / src / sector.cpp
1 //  $Id$
2 //
3 //  SuperTux -  A Jump'n Run
4 //  Copyright (C) 2004 Matthias Braun <matze@braunis.de
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  02111-1307, USA.
19
20 #include <memory>
21 #include <algorithm>
22 #include <stdexcept>
23 #include <iostream>
24 #include <fstream>
25 #include <stdexcept>
26
27 #include "app/globals.h"
28 #include "sector.h"
29 #include "utils/lispreader.h"
30 #include "badguy.h"
31 #include "special.h"
32 #include "gameobjs.h"
33 #include "camera.h"
34 #include "background.h"
35 #include "particlesystem.h"
36 #include "tile.h"
37 #include "tilemap.h"
38 #include "audio/sound_manager.h"
39 #include "gameloop.h"
40 #include "resources.h"
41 #include "interactive_object.h"
42 #include "door.h"
43
44 Sector* Sector::_current = 0;
45
46 Sector::Sector()
47   : gravity(10), player(0), solids(0), background(0), camera(0),
48     currentmusic(LEVEL_MUSIC)
49 {
50   song_title = "Mortimers_chipdisko.mod";
51   player = new Player();
52   add_object(player);
53 }
54
55 Sector::~Sector()
56 {
57   for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
58       ++i)
59     delete *i;
60
61   for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
62       ++i)
63     delete *i;
64     
65   if(_current == this)
66     _current = 0;
67 }
68
69 void
70 Sector::parse(LispReader& lispreader)
71 {
72   _current = this;
73   
74   for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur);
75       cur = lisp_cdr(cur)) {
76     std::string token = lisp_symbol(lisp_car(lisp_car(cur)));
77     // FIXME: doesn't handle empty data
78     lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur)));
79     LispReader reader(lisp_cdr(lisp_car(cur)));
80
81     if(token == "name") {
82       name = lisp_string(data);
83     } else if(token == "gravity") {
84       gravity = lisp_real(data);
85     } else if(token == "music") {
86       song_title = lisp_string(data);
87       load_music();
88     } else if(token == "camera") {
89       if(camera) {
90         std::cerr << "Warning: More than 1 camera defined in sector.\n";
91         continue;
92       }
93       camera = new Camera(this);
94       camera->read(reader);
95       add_object(camera);
96     } else if(token == "background") {
97       background = new Background(reader);
98       add_object(background);
99     } else if(token == "playerspawn") {
100       SpawnPoint* sp = new SpawnPoint;
101       reader.read_string("name", sp->name);
102       reader.read_float("x", sp->pos.x);
103       reader.read_float("y", sp->pos.y);
104       spawnpoints.push_back(sp);
105     } else if(token == "tilemap") {
106       TileMap* tilemap = new TileMap(reader);
107       add_object(tilemap);
108
109       if(tilemap->is_solid()) {
110         if(solids) {
111           std::cerr << "Warning multiple solid tilemaps in sector.\n";
112           continue;
113         }
114         solids = tilemap;
115       }
116     } else if(badguykind_from_string(token) != BAD_INVALID) {
117       add_object(new BadGuy(badguykind_from_string(token), reader));
118     } else if(token == "trampoline") {
119       add_object(new Trampoline(reader));
120     } else if(token == "flying-platform") {
121       add_object(new FlyingPlatform(reader));
122     } else if(token == "particles-snow") {
123       SnowParticleSystem* partsys = new SnowParticleSystem();
124       partsys->parse(reader);
125       add_object(partsys);
126     } else if(token == "particles-clouds") {
127       CloudParticleSystem* partsys = new CloudParticleSystem();
128       partsys->parse(reader);
129       add_object(partsys);
130     } else if(token == "door") {
131       add_object(new Door(reader));
132     } else {
133       std::cerr << "Unknown object type '" << token << "'.\n";
134     }
135   }
136
137   if(!camera) {
138     std::cerr << "sector '" << name << "' does not contain a camera.\n";
139     camera = new Camera(this);
140     add_object(camera);
141   }
142   if(!solids)
143     throw std::runtime_error("sector does not contain a solid tile layer.");
144 }
145
146 void
147 Sector::parse_old_format(LispReader& reader)
148 {
149   _current = this;
150   
151   name = "main";
152   reader.read_float("gravity", gravity);
153
154   std::string backgroundimage;
155   reader.read_string("background", backgroundimage);
156   float bgspeed = .5;
157   reader.read_float("bkgd_speed", bgspeed);
158   bgspeed /= 100;
159
160   Color bkgd_top, bkgd_bottom;
161   int r = 0, g = 0, b = 128;
162   reader.read_int("bkgd_red_top", r);
163   reader.read_int("bkgd_green_top",  g);
164   reader.read_int("bkgd_blue_top",  b);
165   bkgd_top.red = r;
166   bkgd_top.green = g;
167   bkgd_top.blue = b;
168   
169   reader.read_int("bkgd_red_bottom",  r);
170   reader.read_int("bkgd_green_bottom", g);
171   reader.read_int("bkgd_blue_bottom", b);
172   bkgd_bottom.red = r;
173   bkgd_bottom.green = g;
174   bkgd_bottom.blue = b;
175   
176   if(backgroundimage != "") {
177     background = new Background;
178     background->set_image(backgroundimage, bgspeed);
179     add_object(background);
180   } else {
181     background = new Background;
182     background->set_gradient(bkgd_top, bkgd_bottom);
183     add_object(background);
184   }
185
186   std::string particlesystem;
187   reader.read_string("particle_system", particlesystem);
188   if(particlesystem == "clouds")
189     add_object(new CloudParticleSystem());
190   else if(particlesystem == "snow")
191     add_object(new SnowParticleSystem());
192
193   Vector startpos(100, 170);
194   reader.read_float("start_pos_x", startpos.x);
195   reader.read_float("start_pos_y", startpos.y);
196
197   SpawnPoint* spawn = new SpawnPoint;
198   spawn->pos = startpos;
199   spawn->name = "main";
200   spawnpoints.push_back(spawn);
201
202   song_title = "Mortimers_chipdisko.mod";
203   reader.read_string("music", song_title);
204   load_music();
205
206   int width, height = 15;
207   reader.read_int("width", width);
208   reader.read_int("height", height);
209   
210   std::vector<unsigned int> tiles;
211   if(reader.read_int_vector("interactive-tm", tiles)
212       || reader.read_int_vector("tilemap", tiles)) {
213     TileMap* tilemap = new TileMap();
214     tilemap->set(width, height, tiles, LAYER_TILES, true);
215     solids = tilemap;
216     add_object(tilemap);
217   }
218
219   if(reader.read_int_vector("background-tm", tiles)) {
220     TileMap* tilemap = new TileMap();
221     tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
222     add_object(tilemap);
223   }
224
225   if(reader.read_int_vector("foreground-tm", tiles)) {
226     TileMap* tilemap = new TileMap();
227     tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
228     add_object(tilemap);
229   }
230
231   // TODO read resetpoints
232
233   // read objects
234   {
235     lisp_object_t* cur = 0;
236     if(reader.read_lisp("objects", cur)) {
237       while(!lisp_nil_p(cur)) {
238         lisp_object_t* data = lisp_car(cur);
239         std::string object_type = lisp_symbol(lisp_car(data));
240                                                                                 
241         LispReader reader(lisp_cdr(data));
242                                                                                 
243         if(object_type == "trampoline") {
244           add_object(new Trampoline(reader));
245         }
246         else if(object_type == "flying-platform") {
247           add_object(new FlyingPlatform(reader));
248         }
249         else {
250           BadGuyKind kind = badguykind_from_string(object_type);
251           add_object(new BadGuy(kind, reader));
252         }
253                                                                                 
254         cur = lisp_cdr(cur);
255       }
256     }
257   }
258
259   // add a camera
260   camera = new Camera(this);
261   add_object(camera);
262 }
263
264 void
265 Sector::write(LispWriter& writer)
266 {
267   writer.write_string("name", name);
268   writer.write_float("gravity", gravity);
269   writer.write_string("music", song_title);
270
271   // write spawnpoints
272   for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
273       ++i) {
274     SpawnPoint* spawn = *i;
275     writer.start_list("playerspawn");
276     writer.write_string("name", spawn->name);
277     writer.write_float("x", spawn->pos.x);
278     writer.write_float("y", spawn->pos.y);
279     writer.end_list("playerspawn");
280   }
281
282   // write objects
283   for(GameObjects::iterator i = gameobjects.begin();
284       i != gameobjects.end(); ++i) {
285     Serializable* serializable = dynamic_cast<Serializable*> (*i);
286     if(serializable)
287       serializable->write(writer);
288   }
289 }
290
291 void
292 Sector::do_vertical_flip()
293 {
294   for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
295     {
296     TileMap* tilemap = dynamic_cast<TileMap*> (*i);
297     if(tilemap)
298       {
299       tilemap->do_vertical_flip();
300       }
301
302     BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
303     if(badguy)
304       badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32;
305     Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
306     if(trampoline)
307       trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32;
308     FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
309     if(flying_platform)
310       flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32;
311     Door* door = dynamic_cast<Door*> (*i);
312     if(door)
313       door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32);
314     }
315
316   for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
317       ++i) {
318     SpawnPoint* spawn = *i;
319     spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32;
320   }
321 }
322
323 void
324 Sector::add_object(GameObject* object)
325 {
326   gameobjects_new.push_back(object);
327 }
328
329 void
330 Sector::activate(const std::string& spawnpoint)
331 {
332   _current = this;
333
334   // Apply bonuses from former levels
335   switch (player_status.bonus)
336     {
337     case PlayerStatus::NO_BONUS:
338       break;
339                                                                                 
340     case PlayerStatus::FLOWER_BONUS:
341       player->got_power = Player::FIRE_POWER;  // FIXME: add ice power to here
342       // fall through
343                                                                                 
344     case PlayerStatus::GROWUP_BONUS:
345       player->grow(false);
346       break;
347     }
348
349   SpawnPoint* sp = 0;
350   for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
351       ++i) {
352     if((*i)->name == spawnpoint) {
353       sp = *i;
354       break;
355     }
356   }
357   if(!sp) {
358     std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
359   } else {
360     player->move(sp->pos);
361   }
362
363   camera->reset(Vector(player->base.x, player->base.y));
364 }
365
366 void
367 Sector::action(float elapsed_time)
368 {
369   player->check_bounds(camera);
370                                                                                 
371   /* update objects (don't use iterators here, because the list might change
372    * during the iteration)
373    */
374   for(size_t i = 0; i < gameobjects.size(); ++i)
375     if(gameobjects[i]->is_valid())
376       gameobjects[i]->action(elapsed_time);
377                                                                                 
378   /* Handle all possible collisions. */
379   collision_handler();
380                                                                                 
381   update_game_objects();
382 }
383
384 void
385 Sector::update_game_objects()
386 {
387   /** cleanup marked objects */
388   for(std::vector<GameObject*>::iterator i = gameobjects.begin();
389       i != gameobjects.end(); /* nothing */) {
390     if((*i)->is_valid() == false) {
391       BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
392       if(badguy) {
393         badguys.erase(std::remove(badguys.begin(), badguys.end(), badguy),
394             badguys.end());
395       }
396       Bullet* bullet = dynamic_cast<Bullet*> (*i);
397       if(bullet) {
398         bullets.erase(
399             std::remove(bullets.begin(), bullets.end(), bullet),
400             bullets.end());
401       }
402       InteractiveObject* interactive_object =
403           dynamic_cast<InteractiveObject*> (*i);
404       if(interactive_object) {
405         interactive_objects.erase(
406             std::remove(interactive_objects.begin(), interactive_objects.end(),
407                 interactive_object), interactive_objects.end());
408       }
409       Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
410       if(upgrade) {
411         upgrades.erase(
412             std::remove(upgrades.begin(), upgrades.end(), upgrade),
413             upgrades.end());
414       }
415       Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
416       if(trampoline) {
417         trampolines.erase(
418             std::remove(trampolines.begin(), trampolines.end(), trampoline),
419             trampolines.end());
420       }
421       FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
422       if(flying_platform) {
423         flying_platforms.erase(
424             std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
425             flying_platforms.end());
426       }
427       SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
428       if(smoke_cloud) {
429         smoke_clouds.erase(
430             std::remove(smoke_clouds.begin(), smoke_clouds.end(), smoke_cloud),
431             smoke_clouds.end());
432       }
433                                                                                 
434       delete *i;
435       i = gameobjects.erase(i);
436     } else {
437       ++i;
438     }
439   }
440
441   /* add newly created objects */
442   for(std::vector<GameObject*>::iterator i = gameobjects_new.begin();
443       i != gameobjects_new.end(); ++i)
444   {
445           BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
446           if(badguy)
447             badguys.push_back(badguy);
448           Bullet* bullet = dynamic_cast<Bullet*> (*i);
449           if(bullet)
450             bullets.push_back(bullet);
451           Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
452           if(upgrade)
453             upgrades.push_back(upgrade);
454           Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
455           if(trampoline)
456             trampolines.push_back(trampoline);
457           FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
458           if(flying_platform)
459             flying_platforms.push_back(flying_platform);
460           InteractiveObject* interactive_object 
461               = dynamic_cast<InteractiveObject*> (*i);
462           if(interactive_object)
463             interactive_objects.push_back(interactive_object);
464           SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
465           if(smoke_cloud)
466             smoke_clouds.push_back(smoke_cloud);
467
468
469           gameobjects.push_back(*i);
470   }
471   gameobjects_new.clear();
472 }
473
474 void
475 Sector::draw(DrawingContext& context)
476 {
477   context.push_transform();
478   context.set_translation(camera->get_translation());
479   
480   for(GameObjects::iterator i = gameobjects.begin();
481       i != gameobjects.end(); ++i) {
482     if( (*i)->is_valid() )
483       (*i)->draw(context);
484   }
485
486   context.pop_transform();
487 }
488
489 void
490 Sector::collision_handler()
491 {
492   // CO_BULLET & CO_BADGUY check
493   for(unsigned int i = 0; i < bullets.size(); ++i)
494     {
495       for (BadGuys::iterator j = badguys.begin(); j != badguys.end(); ++j)
496         {
497           if((*j)->dying != DYING_NOT)
498             continue;
499                                                                                 
500           if(rectcollision(bullets[i]->base, (*j)->base))
501             {
502               // We have detected a collision and now call the
503               // collision functions of the collided objects.
504               (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
505               bullets[i]->collision(CO_BADGUY);
506               break; // bullet is invalid now, so break
507             }
508         }
509     }
510                                                                                 
511   /* CO_BADGUY & CO_BADGUY check */
512   for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
513     {
514       if((*i)->dying != DYING_NOT)
515         continue;
516                                                                                 
517       BadGuys::iterator j = i;
518       ++j;
519       for (; j != badguys.end(); ++j)
520         {
521           if(j == i || (*j)->dying != DYING_NOT)
522             continue;
523                                                                                 
524           if(rectcollision((*i)->base, (*j)->base))
525             {
526               // We have detected a collision and now call the
527               // collision functions of the collided objects.
528               (*j)->collision(*i, CO_BADGUY);
529               (*i)->collision(*j, CO_BADGUY);
530             }
531         }
532     }
533   if(player->dying != DYING_NOT) return;
534                                                                                 
535   // CO_BADGUY & CO_PLAYER check
536   for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
537     {
538       if((*i)->dying != DYING_NOT)
539         continue;
540                                                                                 
541       if(rectcollision_offset((*i)->base, player->base, 0, 0))
542         {
543           // We have detected a collision and now call the collision
544           // functions of the collided objects.
545           if (player->previous_base.y < player->base.y &&
546               player->previous_base.y + player->previous_base.height
547               < (*i)->base.y + (*i)->base.height/2
548               && !player->invincible_timer.started())
549             {
550               (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
551             }
552           else
553             {
554               player->collision(*i, CO_BADGUY);
555               (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
556             }
557         }
558     }
559                                                                                 
560   // CO_UPGRADE & CO_PLAYER check
561   for(unsigned int i = 0; i < upgrades.size(); ++i)
562     {
563       if(rectcollision(upgrades[i]->base, player->base))
564         {
565           // We have detected a collision and now call the collision
566           // functions of the collided objects.
567           upgrades[i]->collision(player, CO_PLAYER, COLLISION_NORMAL);
568         }
569     }
570                                                                                 
571   // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
572   for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
573   {
574     if (rectcollision((*i)->base, player->base))
575     {
576       if (player->previous_base.y < player->base.y &&
577           player->previous_base.y + player->previous_base.height
578           < (*i)->base.y + (*i)->base.height/2)
579       {
580         (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
581       }
582       else if (player->previous_base.y <= player->base.y)
583       {
584         player->collision(*i, CO_TRAMPOLINE);
585         (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
586       }
587     }
588   }
589                                                                                 
590   // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
591   for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
592   {
593     if (rectcollision((*i)->base, player->base))
594     {
595       if (player->previous_base.y < player->base.y &&
596           player->previous_base.y + player->previous_base.height
597           < (*i)->base.y + (*i)->base.height/2)
598       {
599         (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
600         player->collision(*i, CO_FLYING_PLATFORM);
601       }
602 /*      else if (player->previous_base.y <= player->base.y)
603       {
604       }*/
605     }
606   }
607 }
608
609 void
610 Sector::add_score(const Vector& pos, int s)
611 {
612   player_status.score += s;
613                                                                                 
614   add_object(new FloatingScore(pos, s));
615 }
616                                                                                 
617 void
618 Sector::add_bouncy_distro(const Vector& pos)
619 {
620   add_object(new BouncyDistro(pos));
621 }
622                                                                                 
623 void
624 Sector::add_broken_brick(const Vector& pos, Tile* tile)
625 {
626   add_broken_brick_piece(pos, Vector(-1, -4), tile);
627   add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
628                                                                                 
629   add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
630   add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
631 }
632                                                                                 
633 void
634 Sector::add_broken_brick_piece(const Vector& pos, const Vector& movement,
635     Tile* tile)
636 {
637   add_object(new BrokenBrick(tile, pos, movement));
638 }
639                                                                                 
640 void
641 Sector::add_bouncy_brick(const Vector& pos)
642 {
643   add_object(new BouncyBrick(pos));
644 }
645
646 BadGuy*
647 Sector::add_bad_guy(float x, float y, BadGuyKind kind)
648 {
649   BadGuy* badguy = new BadGuy(kind, x, y);
650   add_object(badguy);
651   return badguy;
652 }
653                                                                                 
654 void
655 Sector::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
656 {
657   add_object(new Upgrade(pos, dir, kind));
658 }
659                                                                                 
660 bool
661 Sector::add_bullet(const Vector& pos, float xm, Direction dir)
662 {
663   if(player->got_power == Player::FIRE_POWER)
664     {
665     if(bullets.size() > MAX_FIRE_BULLETS-1)
666       return false;
667     }
668   else if(player->got_power == Player::ICE_POWER)
669     {
670     if(bullets.size() > MAX_ICE_BULLETS-1)
671       return false;
672     }
673                                                                                 
674   Bullet* new_bullet = 0;
675   if(player->got_power == Player::FIRE_POWER)
676     new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
677   else if(player->got_power == Player::ICE_POWER)
678     new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
679   else
680     throw std::runtime_error("wrong bullet type.");
681   add_object(new_bullet);
682                                                                                 
683   SoundManager::get()->play_sound(IDToSound(SND_SHOOT));
684                                                                                 
685   return true;
686 }
687
688 bool
689 Sector::add_smoke_cloud(const Vector& pos)
690 {
691   add_object(new SmokeCloud(pos));
692   return true;
693 }
694
695 /* Break a brick: */
696 bool
697 Sector::trybreakbrick(const Vector& pos, bool small)
698 {
699   Tile* tile = solids->get_tile_at(pos);
700   if (!tile)
701   {
702     char errmsg[64];
703     sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
704     throw SuperTuxException(errmsg, __FILE__, __LINE__);
705   }
706
707   if (tile->attributes & Tile::BRICK)
708     {
709       if (tile->data > 0)
710         {
711           /* Get a distro from it: */
712           add_bouncy_distro(
713               Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32));
714                                                                                 
715           // TODO: don't handle this in a global way but per-tile...
716           if (!counting_distros)
717             {
718               counting_distros = true;
719               distro_counter = 5;
720             }
721           else
722             {
723               distro_counter--;
724             }
725                                                                                 
726           if (distro_counter <= 0)
727             {
728               counting_distros = false;
729               solids->change_at(pos, tile->next_tile);
730             }
731                                                                                 
732           SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
733           player_status.score = player_status.score + SCORE_DISTRO;
734           player_status.distros++;
735           return true;
736         }
737       else if (!small)
738         {
739           /* Get rid of it: */
740           solids->change_at(pos, tile->next_tile);
741                                                                                 
742           /* Replace it with broken bits: */
743           add_broken_brick(Vector(
744                                  ((int)(pos.x + 1) / 32) * 32,
745                                  (int)(pos.y / 32) * 32), tile);
746                                                                                 
747           /* Get some score: */
748           SoundManager::get()->play_sound(IDToSound(SND_BRICK));
749           player_status.score = player_status.score + SCORE_BRICK;
750                                                                                 
751           return true;
752         }
753     }
754                                                                                 
755   return false;
756 }
757                                                                                 
758 /* Empty a box: */
759 void
760 Sector::tryemptybox(const Vector& pos, Direction col_side)
761 {
762   Tile* tile = solids->get_tile_at(pos);
763   if (!tile)
764   {
765     char errmsg[64];
766     sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
767     throw SuperTuxException(errmsg, __FILE__, __LINE__);
768   }
769
770
771   if (!(tile->attributes & Tile::FULLBOX))
772     return;
773                                                                                 
774   // according to the collision side, set the upgrade direction
775   if(col_side == LEFT)
776     col_side = RIGHT;
777   else
778     col_side = LEFT;
779                                                                                 
780   int posx = ((int)(pos.x+1) / 32) * 32;
781   int posy = (int)(pos.y/32) * 32 - 32;
782   switch(tile->data)
783     {
784     case 1: // Box with a distro!
785       add_bouncy_distro(Vector(posx, posy));
786       SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
787       player_status.score = player_status.score + SCORE_DISTRO;
788       player_status.distros++;
789       break;
790                                                                                 
791     case 2: // Add a fire flower upgrade!
792       if (player->size == SMALL)     /* Tux is small, add mints! */
793         add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
794       else     /* Tux is big, add a fireflower: */
795         add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
796       SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
797       break;
798                                                                                 
799     case 5: // Add an ice flower upgrade!
800       if (player->size == SMALL)     /* Tux is small, add mints! */
801         add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
802       else     /* Tux is big, add an iceflower: */
803         add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
804       SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
805       break;
806                                                                                 
807     case 3: // Add a golden herring
808       add_upgrade(Vector(posx, posy), col_side, UPGRADE_STAR);
809       break;
810                                                                                 
811     case 4: // Add a 1up extra
812       add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
813       break;
814     default:
815       break;
816     }
817                                                                                 
818   /* Empty the box: */
819   solids->change_at(pos, tile->next_tile);
820 }
821                                                                                 
822 /* Try to grab a distro: */
823 void
824 Sector::trygrabdistro(const Vector& pos, int bounciness)
825 {
826   Tile* tile = solids->get_tile_at(pos);
827   if (!tile)
828   {
829     /*char errmsg[64];
830     sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
831     throw SuperTuxException(errmsg, __FILE__, __LINE__); */
832     
833     //Bad tiles (i.e. tiles that are not defined in supertux.stgt but appear in the map) are changed to ID 0 (blank tile)
834     std::cout << "Warning: Undefined tile at " <<(int)pos.x/32 << "/" << (int)pos.y/32 << " (ID: " << (int)solids->get_tile_id_at(pos).id << ")" << std::endl;
835     solids->change_at(pos,0);
836     tile = solids->get_tile_at(pos);
837   }
838
839
840   if (!(tile->attributes & Tile::COIN))
841     return;
842
843   solids->change_at(pos, tile->next_tile);
844   SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
845                                                                             
846   if (bounciness == BOUNCE)
847     {
848       add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32,
849                               (int)(pos.y / 32) * 32));
850     }
851                                                                             
852   player_status.score = player_status.score + SCORE_DISTRO;
853   player_status.distros++;
854
855 }
856                                                                                 
857 /* Try to bump a bad guy from below: */
858 void
859 Sector::trybumpbadguy(const Vector& pos)
860 {
861   // Bad guys:
862   for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
863     {
864       if ((*i)->base.x >= pos.x - 32 && (*i)->base.x <= pos.x + 32 &&
865           (*i)->base.y >= pos.y - 16 && (*i)->base.y <= pos.y + 16)
866         {
867           (*i)->collision(player, CO_PLAYER, COLLISION_BUMP);
868         }
869     }
870                                                                                 
871   // Upgrades:
872   for (unsigned int i = 0; i < upgrades.size(); i++)
873     {
874       if (upgrades[i]->base.height == 32 &&
875           upgrades[i]->base.x >= pos.x - 32 && upgrades[i]->base.x <= pos.x + 32 &&
876           upgrades[i]->base.y >= pos.y - 16 && upgrades[i]->base.y <= pos.y + 16)
877         {
878           upgrades[i]->collision(player, CO_PLAYER, COLLISION_BUMP);
879         }
880     }
881 }
882
883 void
884 Sector::load_music()
885 {
886   char* song_path;
887   char* song_subtitle;
888                                                                                 
889   level_song = SoundManager::get()->load_music(datadir + "/music/" + song_title);
890                                                                                 
891   song_path = (char *) malloc(sizeof(char) * datadir.length() +
892                               strlen(song_title.c_str()) + 8 + 5);
893   song_subtitle = strdup(song_title.c_str());
894   strcpy(strstr(song_subtitle, "."), "\0");
895   sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
896           song_subtitle, strstr(song_title.c_str(), "."));
897   if(!SoundManager::get()->exists_music(song_path)) {
898     level_song_fast = level_song;
899   } else {
900     level_song_fast = SoundManager::get()->load_music(song_path);
901   }
902   free(song_subtitle);
903   free(song_path);
904 }
905
906 void
907 Sector::play_music(int type)
908 {
909   currentmusic = type;
910   switch(currentmusic) {
911     case HURRYUP_MUSIC:
912       SoundManager::get()->play_music(level_song_fast);
913       break;
914     case LEVEL_MUSIC:
915       SoundManager::get()->play_music(level_song);
916       break;
917     case HERRING_MUSIC:
918       SoundManager::get()->play_music(herring_song);
919       break;
920     default:
921       SoundManager::get()->halt_music();
922       break;
923   }
924 }
925
926 int
927 Sector::get_music_type()
928 {
929   return currentmusic;
930 }