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