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