3 // SuperTux - A Jump'n Run
4 // Copyright (C) 2004 Matthias Braun <matze@braunis.de
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.
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.
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.
27 #include "app/globals.h"
29 #include "utils/lispreader.h"
34 #include "background.h"
35 #include "particlesystem.h"
38 #include "audio/sound_manager.h"
40 #include "resources.h"
41 #include "interactive_object.h"
44 Sector* Sector::_current = 0;
47 : gravity(10), player(0), solids(0), background(0), camera(0),
48 currentmusic(LEVEL_MUSIC)
50 song_title = "Mortimers_chipdisko.mod";
51 player = new Player();
57 for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end();
61 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
70 Sector::parse(LispReader& lispreader)
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)));
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);
88 } else if(token == "camera") {
90 std::cerr << "Warning: More than 1 camera defined in sector.\n";
93 camera = new Camera(this);
96 } else if(token == "background") {
97 background = new Background(reader);
98 add_object(background);
99 } else if(token == "playerspawn") {
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);
109 if(tilemap->is_solid()) {
111 std::cerr << "Warning multiple solid tilemaps in sector.\n";
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);
126 } else if(token == "particles-clouds") {
127 CloudParticleSystem* partsys = new CloudParticleSystem();
128 partsys->parse(reader);
130 } else if(token == "door") {
131 add_object(new Door(reader));
133 std::cerr << "Unknown object type '" << token << "'.\n";
138 std::cerr << "sector '" << name << "' does not contain a camera.\n";
139 camera = new Camera(this);
143 throw std::runtime_error("sector does not contain a solid tile layer.");
147 Sector::parse_old_format(LispReader& reader)
152 reader.read_float("gravity", gravity);
154 std::string backgroundimage;
155 reader.read_string("background", backgroundimage);
157 reader.read_float("bkgd_speed", bgspeed);
159 Color bkgd_top, bkgd_bottom;
160 int r = 0, g = 0, b = 128;
161 reader.read_int("bkgd_red_top", r);
162 reader.read_int("bkgd_green_top", g);
163 reader.read_int("bkgd_blue_top", b);
168 reader.read_int("bkgd_red_bottom", r);
169 reader.read_int("bkgd_green_bottom", g);
170 reader.read_int("bkgd_blue_bottom", b);
172 bkgd_bottom.green = g;
173 bkgd_bottom.blue = b;
175 if(backgroundimage != "") {
176 background = new Background;
177 background->set_image(backgroundimage, bgspeed);
178 add_object(background);
180 background = new Background;
181 background->set_gradient(bkgd_top, bkgd_bottom);
182 add_object(background);
185 std::string particlesystem;
186 reader.read_string("particle_system", particlesystem);
187 if(particlesystem == "clouds")
188 add_object(new CloudParticleSystem());
189 else if(particlesystem == "snow")
190 add_object(new SnowParticleSystem());
192 Vector startpos(100, 170);
193 reader.read_float("start_pos_x", startpos.x);
194 reader.read_float("start_pos_y", startpos.y);
196 SpawnPoint* spawn = new SpawnPoint;
197 spawn->pos = startpos;
198 spawn->name = "main";
199 spawnpoints.push_back(spawn);
201 song_title = "Mortimers_chipdisko.mod";
202 reader.read_string("music", song_title);
205 int width, height = 15;
206 reader.read_int("width", width);
207 reader.read_int("height", height);
209 std::vector<unsigned int> tiles;
210 if(reader.read_int_vector("interactive-tm", tiles)
211 || reader.read_int_vector("tilemap", tiles)) {
212 TileMap* tilemap = new TileMap();
213 tilemap->set(width, height, tiles, LAYER_TILES, true);
218 if(reader.read_int_vector("background-tm", tiles)) {
219 TileMap* tilemap = new TileMap();
220 tilemap->set(width, height, tiles, LAYER_BACKGROUNDTILES, false);
224 if(reader.read_int_vector("foreground-tm", tiles)) {
225 TileMap* tilemap = new TileMap();
226 tilemap->set(width, height, tiles, LAYER_FOREGROUNDTILES, false);
230 // TODO read resetpoints
234 lisp_object_t* cur = 0;
235 if(reader.read_lisp("objects", cur)) {
236 while(!lisp_nil_p(cur)) {
237 lisp_object_t* data = lisp_car(cur);
238 std::string object_type = lisp_symbol(lisp_car(data));
240 LispReader reader(lisp_cdr(data));
242 if(object_type == "trampoline") {
243 add_object(new Trampoline(reader));
245 else if(object_type == "flying-platform") {
246 add_object(new FlyingPlatform(reader));
249 BadGuyKind kind = badguykind_from_string(object_type);
250 add_object(new BadGuy(kind, reader));
259 camera = new Camera(this);
264 Sector::write(LispWriter& writer)
266 writer.write_string("name", name);
267 writer.write_float("gravity", gravity);
268 writer.write_string("music", song_title);
271 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
273 SpawnPoint* spawn = *i;
274 writer.start_list("playerspawn");
275 writer.write_string("name", spawn->name);
276 writer.write_float("x", spawn->pos.x);
277 writer.write_float("y", spawn->pos.y);
278 writer.end_list("playerspawn");
282 for(GameObjects::iterator i = gameobjects.begin();
283 i != gameobjects.end(); ++i) {
284 Serializable* serializable = dynamic_cast<Serializable*> (*i);
286 serializable->write(writer);
291 Sector::do_vertical_flip()
293 for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i)
295 TileMap* tilemap = dynamic_cast<TileMap*> (*i);
298 tilemap->do_vertical_flip();
301 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
303 badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32;
304 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
306 trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32;
307 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
309 flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32;
310 Door* door = dynamic_cast<Door*> (*i);
312 door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32);
315 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
317 SpawnPoint* spawn = *i;
318 spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32;
323 Sector::add_object(GameObject* object)
325 gameobjects_new.push_back(object);
329 Sector::activate(const std::string& spawnpoint)
333 // Apply bonuses from former levels
334 switch (player_status.bonus)
336 case PlayerStatus::NO_BONUS:
339 case PlayerStatus::FLOWER_BONUS:
340 player->got_power = Player::FIRE_POWER; // FIXME: add ice power to here
343 case PlayerStatus::GROWUP_BONUS:
349 for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end();
351 if((*i)->name == spawnpoint) {
357 std::cerr << "Spawnpoint '" << spawnpoint << "' not found.\n";
359 player->move(sp->pos);
362 camera->reset(Vector(player->base.x, player->base.y));
366 Sector::action(float elapsed_time)
368 player->check_bounds(camera);
370 /* update objects (don't use iterators here, because the list might change
371 * during the iteration)
373 for(size_t i = 0; i < gameobjects.size(); ++i)
374 if(gameobjects[i]->is_valid())
375 gameobjects[i]->action(elapsed_time);
377 /* Handle all possible collisions. */
380 update_game_objects();
384 Sector::update_game_objects()
386 /** cleanup marked objects */
387 for(std::vector<GameObject*>::iterator i = gameobjects.begin();
388 i != gameobjects.end(); /* nothing */) {
389 if((*i)->is_valid() == false) {
390 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
392 badguys.erase(std::remove(badguys.begin(), badguys.end(), badguy),
395 Bullet* bullet = dynamic_cast<Bullet*> (*i);
398 std::remove(bullets.begin(), bullets.end(), bullet),
401 InteractiveObject* interactive_object =
402 dynamic_cast<InteractiveObject*> (*i);
403 if(interactive_object) {
404 interactive_objects.erase(
405 std::remove(interactive_objects.begin(), interactive_objects.end(),
406 interactive_object), interactive_objects.end());
408 Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
411 std::remove(upgrades.begin(), upgrades.end(), upgrade),
414 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
417 std::remove(trampolines.begin(), trampolines.end(), trampoline),
420 FlyingPlatform* flying_platform= dynamic_cast<FlyingPlatform*> (*i);
421 if(flying_platform) {
422 flying_platforms.erase(
423 std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform),
424 flying_platforms.end());
426 SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
429 std::remove(smoke_clouds.begin(), smoke_clouds.end(), smoke_cloud),
434 i = gameobjects.erase(i);
440 /* add newly created objects */
441 for(std::vector<GameObject*>::iterator i = gameobjects_new.begin();
442 i != gameobjects_new.end(); ++i)
444 BadGuy* badguy = dynamic_cast<BadGuy*> (*i);
446 badguys.push_back(badguy);
447 Bullet* bullet = dynamic_cast<Bullet*> (*i);
449 bullets.push_back(bullet);
450 Upgrade* upgrade = dynamic_cast<Upgrade*> (*i);
452 upgrades.push_back(upgrade);
453 Trampoline* trampoline = dynamic_cast<Trampoline*> (*i);
455 trampolines.push_back(trampoline);
456 FlyingPlatform* flying_platform = dynamic_cast<FlyingPlatform*> (*i);
458 flying_platforms.push_back(flying_platform);
459 InteractiveObject* interactive_object
460 = dynamic_cast<InteractiveObject*> (*i);
461 if(interactive_object)
462 interactive_objects.push_back(interactive_object);
463 SmokeCloud* smoke_cloud = dynamic_cast<SmokeCloud*> (*i);
465 smoke_clouds.push_back(smoke_cloud);
468 gameobjects.push_back(*i);
470 gameobjects_new.clear();
474 Sector::draw(DrawingContext& context)
476 context.push_transform();
477 context.set_translation(camera->get_translation());
479 for(GameObjects::iterator i = gameobjects.begin();
480 i != gameobjects.end(); ++i) {
481 if( (*i)->is_valid() )
485 context.pop_transform();
489 Sector::collision_handler()
491 // CO_BULLET & CO_BADGUY check
492 for(unsigned int i = 0; i < bullets.size(); ++i)
494 for (BadGuys::iterator j = badguys.begin(); j != badguys.end(); ++j)
496 if((*j)->dying != DYING_NOT)
499 if(rectcollision(bullets[i]->base, (*j)->base))
501 // We have detected a collision and now call the
502 // collision functions of the collided objects.
503 (*j)->collision(bullets[i], CO_BULLET, COLLISION_NORMAL);
504 bullets[i]->collision(CO_BADGUY);
505 break; // bullet is invalid now, so break
510 /* CO_BADGUY & CO_BADGUY check */
511 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
513 if((*i)->dying != DYING_NOT)
516 BadGuys::iterator j = i;
518 for (; j != badguys.end(); ++j)
520 if(j == i || (*j)->dying != DYING_NOT)
523 if(rectcollision((*i)->base, (*j)->base))
525 // We have detected a collision and now call the
526 // collision functions of the collided objects.
527 (*j)->collision(*i, CO_BADGUY);
528 (*i)->collision(*j, CO_BADGUY);
532 if(player->dying != DYING_NOT) return;
534 // CO_BADGUY & CO_PLAYER check
535 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
537 if((*i)->dying != DYING_NOT)
540 if(rectcollision_offset((*i)->base, player->base, 0, 0))
542 // We have detected a collision and now call the collision
543 // functions of the collided objects.
544 if (player->previous_base.y < player->base.y &&
545 player->previous_base.y + player->previous_base.height
546 < (*i)->base.y + (*i)->base.height/2
547 && !player->invincible_timer.started())
549 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
553 player->collision(*i, CO_BADGUY);
554 (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
559 // CO_UPGRADE & CO_PLAYER check
560 for(unsigned int i = 0; i < upgrades.size(); ++i)
562 if(rectcollision(upgrades[i]->base, player->base))
564 // We have detected a collision and now call the collision
565 // functions of the collided objects.
566 upgrades[i]->collision(player, CO_PLAYER, COLLISION_NORMAL);
570 // CO_TRAMPOLINE & (CO_PLAYER or CO_BADGUY)
571 for (Trampolines::iterator i = trampolines.begin(); i != trampolines.end(); ++i)
573 if (rectcollision((*i)->base, player->base))
575 if (player->previous_base.y < player->base.y &&
576 player->previous_base.y + player->previous_base.height
577 < (*i)->base.y + (*i)->base.height/2)
579 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
581 else if (player->previous_base.y <= player->base.y)
583 player->collision(*i, CO_TRAMPOLINE);
584 (*i)->collision(player, CO_PLAYER, COLLISION_NORMAL);
589 // CO_FLYING_PLATFORM & (CO_PLAYER or CO_BADGUY)
590 for (FlyingPlatforms::iterator i = flying_platforms.begin(); i != flying_platforms.end(); ++i)
592 if (rectcollision((*i)->base, player->base))
594 if (player->previous_base.y < player->base.y &&
595 player->previous_base.y + player->previous_base.height
596 < (*i)->base.y + (*i)->base.height/2)
598 (*i)->collision(player, CO_PLAYER, COLLISION_SQUISH);
599 player->collision(*i, CO_FLYING_PLATFORM);
601 /* else if (player->previous_base.y <= player->base.y)
609 Sector::add_score(const Vector& pos, int s)
611 player_status.score += s;
613 add_object(new FloatingScore(pos, s));
617 Sector::add_bouncy_distro(const Vector& pos)
619 add_object(new BouncyDistro(pos));
623 Sector::add_broken_brick(const Vector& pos, Tile* tile)
625 add_broken_brick_piece(pos, Vector(-1, -4), tile);
626 add_broken_brick_piece(pos + Vector(0, 16), Vector(-1.5, -3), tile);
628 add_broken_brick_piece(pos + Vector(16, 0), Vector(1, -4), tile);
629 add_broken_brick_piece(pos + Vector(16, 16), Vector(1.5, -3), tile);
633 Sector::add_broken_brick_piece(const Vector& pos, const Vector& movement,
636 add_object(new BrokenBrick(tile, pos, movement));
640 Sector::add_bouncy_brick(const Vector& pos)
642 add_object(new BouncyBrick(pos));
646 Sector::add_bad_guy(float x, float y, BadGuyKind kind)
648 BadGuy* badguy = new BadGuy(kind, x, y);
654 Sector::add_upgrade(const Vector& pos, Direction dir, UpgradeKind kind)
656 add_object(new Upgrade(pos, dir, kind));
660 Sector::add_bullet(const Vector& pos, float xm, Direction dir)
662 if(player->got_power == Player::FIRE_POWER)
664 if(bullets.size() > MAX_FIRE_BULLETS-1)
667 else if(player->got_power == Player::ICE_POWER)
669 if(bullets.size() > MAX_ICE_BULLETS-1)
673 Bullet* new_bullet = 0;
674 if(player->got_power == Player::FIRE_POWER)
675 new_bullet = new Bullet(pos, xm, dir, FIRE_BULLET);
676 else if(player->got_power == Player::ICE_POWER)
677 new_bullet = new Bullet(pos, xm, dir, ICE_BULLET);
679 throw std::runtime_error("wrong bullet type.");
680 add_object(new_bullet);
682 SoundManager::get()->play_sound(IDToSound(SND_SHOOT));
688 Sector::add_smoke_cloud(const Vector& pos)
690 add_object(new SmokeCloud(pos));
696 Sector::trybreakbrick(const Vector& pos, bool small)
698 Tile* tile = solids->get_tile_at(pos);
702 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
703 throw SuperTuxException(errmsg, __FILE__, __LINE__);
706 if (tile->attributes & Tile::BRICK)
710 /* Get a distro from it: */
712 Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32));
714 // TODO: don't handle this in a global way but per-tile...
715 if (!counting_distros)
717 counting_distros = true;
725 if (distro_counter <= 0)
727 counting_distros = false;
728 solids->change_at(pos, tile->next_tile);
731 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
732 player_status.score = player_status.score + SCORE_DISTRO;
733 player_status.distros++;
739 solids->change_at(pos, tile->next_tile);
741 /* Replace it with broken bits: */
742 add_broken_brick(Vector(
743 ((int)(pos.x + 1) / 32) * 32,
744 (int)(pos.y / 32) * 32), tile);
746 /* Get some score: */
747 SoundManager::get()->play_sound(IDToSound(SND_BRICK));
748 player_status.score = player_status.score + SCORE_BRICK;
759 Sector::tryemptybox(const Vector& pos, Direction col_side)
761 Tile* tile = solids->get_tile_at(pos);
765 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
766 throw SuperTuxException(errmsg, __FILE__, __LINE__);
770 if (!(tile->attributes & Tile::FULLBOX))
773 // according to the collision side, set the upgrade direction
779 int posx = ((int)(pos.x+1) / 32) * 32;
780 int posy = (int)(pos.y/32) * 32 - 32;
783 case 1: // Box with a distro!
784 add_bouncy_distro(Vector(posx, posy));
785 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
786 player_status.score = player_status.score + SCORE_DISTRO;
787 player_status.distros++;
790 case 2: // Add a fire flower upgrade!
791 if (player->size == SMALL) /* Tux is small, add mints! */
792 add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
793 else /* Tux is big, add a fireflower: */
794 add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER);
795 SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
798 case 5: // Add an ice flower upgrade!
799 if (player->size == SMALL) /* Tux is small, add mints! */
800 add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP);
801 else /* Tux is big, add an iceflower: */
802 add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER);
803 SoundManager::get()->play_sound(IDToSound(SND_UPGRADE));
806 case 3: // Add a golden herring
807 add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING);
810 case 4: // Add a 1up extra
811 add_upgrade(Vector(posx, posy), col_side, UPGRADE_1UP);
818 solids->change_at(pos, tile->next_tile);
821 /* Try to grab a distro: */
823 Sector::trygrabdistro(const Vector& pos, int bounciness)
825 Tile* tile = solids->get_tile_at(pos);
829 sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32));
830 throw SuperTuxException(errmsg, __FILE__, __LINE__); */
832 //Bad tiles (i.e. tiles that are not defined in supertux.stgt but appear in the map) are changed to ID 0 (blank tile)
833 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;
834 solids->change_at(pos,0);
835 tile = solids->get_tile_at(pos);
839 if (!(tile->attributes & Tile::COIN))
842 solids->change_at(pos, tile->next_tile);
843 SoundManager::get()->play_sound(IDToSound(SND_DISTRO));
845 if (bounciness == BOUNCE)
847 add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32,
848 (int)(pos.y / 32) * 32));
851 player_status.score = player_status.score + SCORE_DISTRO;
852 player_status.distros++;
856 /* Try to bump a bad guy from below: */
858 Sector::trybumpbadguy(const Vector& pos)
861 for (BadGuys::iterator i = badguys.begin(); i != badguys.end(); ++i)
863 if ((*i)->base.x >= pos.x - 32 && (*i)->base.x <= pos.x + 32 &&
864 (*i)->base.y >= pos.y - 16 && (*i)->base.y <= pos.y + 16)
866 (*i)->collision(player, CO_PLAYER, COLLISION_BUMP);
871 for (unsigned int i = 0; i < upgrades.size(); i++)
873 if (upgrades[i]->base.height == 32 &&
874 upgrades[i]->base.x >= pos.x - 32 && upgrades[i]->base.x <= pos.x + 32 &&
875 upgrades[i]->base.y >= pos.y - 16 && upgrades[i]->base.y <= pos.y + 16)
877 upgrades[i]->collision(player, CO_PLAYER, COLLISION_BUMP);
888 level_song = SoundManager::get()->load_music(datadir + "/music/" + song_title);
890 song_path = (char *) malloc(sizeof(char) * datadir.length() +
891 strlen(song_title.c_str()) + 8 + 5);
892 song_subtitle = strdup(song_title.c_str());
893 strcpy(strstr(song_subtitle, "."), "\0");
894 sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(),
895 song_subtitle, strstr(song_title.c_str(), "."));
896 if(!SoundManager::get()->exists_music(song_path)) {
897 level_song_fast = level_song;
899 level_song_fast = SoundManager::get()->load_music(song_path);
906 Sector::play_music(int type)
909 switch(currentmusic) {
911 SoundManager::get()->play_music(level_song_fast);
914 SoundManager::get()->play_music(level_song);
917 SoundManager::get()->play_music(herring_song);
920 SoundManager::get()->halt_music();
926 Sector::get_music_type()