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