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