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