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