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