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