X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fsector.cpp;h=4cde141967339ab83157baebf95a6242dc6c90f2;hb=546364c9567ef212ea9276201facf73f5ada696a;hp=0976bb80687a071e0d434591c31c93e7dcdbbf7e;hpb=cf4de5d58eb99a11369c329c01bfa5abe4b0a398;p=supertux.git diff --git a/src/sector.cpp b/src/sector.cpp index 0976bb806..4cde14196 100644 --- a/src/sector.cpp +++ b/src/sector.cpp @@ -16,15 +16,17 @@ // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "sector.h" #include +#include #include #include #include #include -#include "lispreader.h" +#include "app/globals.h" +#include "sector.h" +#include "utils/lispreader.h" #include "badguy.h" #include "special.h" #include "gameobjs.h" @@ -33,16 +35,18 @@ #include "particlesystem.h" #include "tile.h" #include "tilemap.h" -#include "music_manager.h" +#include "audio/sound_manager.h" #include "gameloop.h" #include "resources.h" #include "interactive_object.h" #include "door.h" +#include "statistics.h" Sector* Sector::_current = 0; Sector::Sector() - : gravity(10), player(0), solids(0), background(0), camera(0), + : end_sequence_animation_type(NONE_ENDSEQ_ANIM), + gravity(10), player(0), solids(0), background(0), camera(0), currentmusic(LEVEL_MUSIC) { song_title = "Mortimers_chipdisko.mod"; @@ -64,6 +68,23 @@ Sector::~Sector() _current = 0; } +Sector *Sector::create(const std::string& name, size_t width, size_t height) +{ + Sector *sector = new Sector; + sector->name = name; + TileMap *background = new TileMap(LAYER_BACKGROUNDTILES, false, width, height); + TileMap *interactive = new TileMap(LAYER_TILES, true, width, height); + TileMap *foreground = new TileMap(LAYER_FOREGROUNDTILES, false, width, height); + sector->add_object(background); + sector->add_object(interactive); + sector->add_object(foreground); + sector->solids = interactive; + sector->camera = new Camera(sector); + sector->add_object(sector->camera); + sector->update_game_objects(); + return sector; +} + void Sector::parse(LispReader& lispreader) { @@ -72,16 +93,21 @@ Sector::parse(LispReader& lispreader) for(lisp_object_t* cur = lispreader.get_lisp(); !lisp_nil_p(cur); cur = lisp_cdr(cur)) { std::string token = lisp_symbol(lisp_car(lisp_car(cur))); + // FIXME: doesn't handle empty data lisp_object_t* data = lisp_car(lisp_cdr(lisp_car(cur))); LispReader reader(lisp_cdr(lisp_car(cur))); if(token == "name") { name = lisp_string(data); } else if(token == "gravity") { - gravity = lisp_integer(data); + gravity = lisp_real(data); } else if(token == "music") { song_title = lisp_string(data); load_music(); + } else if(token == "end-sequence-animation") { + std::string end_seq_anim = lisp_string(data); + if(end_seq_anim == "fireworks") + end_sequence_animation_type = FIREWORKS_ENDSEQ_ANIM; } else if(token == "camera") { if(camera) { std::cerr << "Warning: More than 1 camera defined in sector.\n"; @@ -93,7 +119,7 @@ Sector::parse(LispReader& lispreader) } else if(token == "background") { background = new Background(reader); add_object(background); - } else if(token == "playerspawn") { + } else if(token == "spawn-points") { SpawnPoint* sp = new SpawnPoint; reader.read_string("name", sp->name); reader.read_float("x", sp->pos.x); @@ -152,6 +178,7 @@ Sector::parse_old_format(LispReader& reader) reader.read_string("background", backgroundimage); float bgspeed = .5; reader.read_float("bkgd_speed", bgspeed); + bgspeed /= 100; Color bkgd_top, bkgd_bottom; int r = 0, g = 0, b = 128; @@ -179,6 +206,13 @@ Sector::parse_old_format(LispReader& reader) add_object(background); } + std::string end_seq_anim; + reader.read_string("end-sequence-animation", end_seq_anim); + if(end_seq_anim == "fireworks") + end_sequence_animation_type = FIREWORKS_ENDSEQ_ANIM; +// else +// end_sequence_animation = NONE_ENDSEQ_ANIM; + std::string particlesystem; reader.read_string("particle_system", particlesystem); if(particlesystem == "clouds") @@ -224,7 +258,27 @@ Sector::parse_old_format(LispReader& reader) add_object(tilemap); } - // TODO read resetpoints + // read reset-points (now spawn-points) + { + lisp_object_t* cur = 0; + if(reader.read_lisp("reset-points", cur)) { + while(!lisp_nil_p(cur)) { + lisp_object_t* data = lisp_car(cur); + LispReader reader(lisp_cdr(data)); + + Vector sp_pos; + if(reader.read_float("x", sp_pos.x) && reader.read_float("y", sp_pos.y)) + { + SpawnPoint* sp = new SpawnPoint; + sp->name = "main"; + sp->pos = sp_pos; + spawnpoints.push_back(sp); + } + + cur = lisp_cdr(cur); + } + } + } // read objects { @@ -262,7 +316,20 @@ Sector::write(LispWriter& writer) { writer.write_string("name", name); writer.write_float("gravity", gravity); + writer.write_string("music", song_title); + // write spawnpoints + for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end(); + ++i) { + SpawnPoint* spawn = *i; + writer.start_list("spawn-points"); + writer.write_string("name", spawn->name); + writer.write_float("x", spawn->pos.x); + writer.write_float("y", spawn->pos.y); + writer.end_list("spawn-points"); + } + + // write objects for(GameObjects::iterator i = gameobjects.begin(); i != gameobjects.end(); ++i) { Serializable* serializable = dynamic_cast (*i); @@ -272,30 +339,41 @@ Sector::write(LispWriter& writer) } void +Sector::do_vertical_flip() +{ + for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i) + { + TileMap* tilemap = dynamic_cast (*i); + if(tilemap) + { + tilemap->do_vertical_flip(); + } + + BadGuy* badguy = dynamic_cast (*i); + if(badguy) + badguy->start_position.y = solids->get_height()*32 - badguy->start_position.y - 32; + Trampoline* trampoline = dynamic_cast (*i); + if(trampoline) + trampoline->base.y = solids->get_height()*32 - trampoline->base.y - 32; + FlyingPlatform* flying_platform = dynamic_cast (*i); + if(flying_platform) + flying_platform->base.y = solids->get_height()*32 - flying_platform->base.y - 32; + Door* door = dynamic_cast (*i); + if(door) + door->set_area(door->get_area().x, solids->get_height()*32 - door->get_area().y - 32); + } + + for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end(); + ++i) { + SpawnPoint* spawn = *i; + spawn->pos.y = solids->get_height()*32 - spawn->pos.y - 32; + } +} + +void Sector::add_object(GameObject* object) { - // XXX a bit hackish, at least try to keep the number of these things down... - BadGuy* badguy = dynamic_cast (object); - if(badguy) - badguys.push_back(badguy); - Bullet* bullet = dynamic_cast (object); - if(bullet) - bullets.push_back(bullet); - Upgrade* upgrade = dynamic_cast (object); - if(upgrade) - upgrades.push_back(upgrade); - Trampoline* trampoline = dynamic_cast (object); - if(trampoline) - trampolines.push_back(trampoline); - FlyingPlatform* flying_platform = dynamic_cast (object); - if(flying_platform) - flying_platforms.push_back(flying_platform); - InteractiveObject* interactive_object - = dynamic_cast (object); - if(interactive_object) - interactive_objects.push_back(interactive_object); - - gameobjects.push_back(object); + gameobjects_new.push_back(object); } void @@ -335,6 +413,22 @@ Sector::activate(const std::string& spawnpoint) camera->reset(Vector(player->base.x, player->base.y)); } +Vector +Sector::get_best_spawn_point(Vector pos) +{ +Vector best_reset_point = Vector(-1,-1); + +for(SpawnPoints::iterator i = spawnpoints.begin(); i != spawnpoints.end(); + ++i) { + if((*i)->name != "main") + continue; + if((*i)->pos.x > best_reset_point.x && (*i)->pos.x < pos.x) + best_reset_point = (*i)->pos; + } + +return best_reset_point; +} + void Sector::action(float elapsed_time) { @@ -350,6 +444,12 @@ Sector::action(float elapsed_time) /* Handle all possible collisions. */ collision_handler(); + update_game_objects(); +} + +void +Sector::update_game_objects() +{ /** cleanup marked objects */ for(std::vector::iterator i = gameobjects.begin(); i != gameobjects.end(); /* nothing */) { @@ -390,13 +490,59 @@ Sector::action(float elapsed_time) std::remove(flying_platforms.begin(), flying_platforms.end(), flying_platform), flying_platforms.end()); } - + SmokeCloud* smoke_cloud = dynamic_cast (*i); + if(smoke_cloud) { + smoke_clouds.erase( + std::remove(smoke_clouds.begin(), smoke_clouds.end(), smoke_cloud), + smoke_clouds.end()); + } + Particles* particle = dynamic_cast (*i); + if(particle) { + particles.erase( + std::remove(particles.begin(), particles.end(), particle), + particles.end()); + } + delete *i; i = gameobjects.erase(i); } else { ++i; } } + + /* add newly created objects */ + for(std::vector::iterator i = gameobjects_new.begin(); + i != gameobjects_new.end(); ++i) + { + BadGuy* badguy = dynamic_cast (*i); + if(badguy) + badguys.push_back(badguy); + Bullet* bullet = dynamic_cast (*i); + if(bullet) + bullets.push_back(bullet); + Upgrade* upgrade = dynamic_cast (*i); + if(upgrade) + upgrades.push_back(upgrade); + Trampoline* trampoline = dynamic_cast (*i); + if(trampoline) + trampolines.push_back(trampoline); + FlyingPlatform* flying_platform = dynamic_cast (*i); + if(flying_platform) + flying_platforms.push_back(flying_platform); + InteractiveObject* interactive_object + = dynamic_cast (*i); + if(interactive_object) + interactive_objects.push_back(interactive_object); + SmokeCloud* smoke_cloud = dynamic_cast (*i); + if(smoke_cloud) + smoke_clouds.push_back(smoke_cloud); + Particles* particle = dynamic_cast (*i); + if(particle) + particles.push_back(particle); + + gameobjects.push_back(*i); + } + gameobjects_new.clear(); } void @@ -537,9 +683,9 @@ Sector::collision_handler() void Sector::add_score(const Vector& pos, int s) { - player_status.score += s; + global_stats.add_points(SCORE_STAT, s); - add_object(new FloatingScore(pos, s)); + add_object(new FloatingText(pos, s)); } void @@ -572,10 +718,12 @@ Sector::add_bouncy_brick(const Vector& pos) } BadGuy* -Sector::add_bad_guy(float x, float y, BadGuyKind kind) +Sector::add_bad_guy(float x, float y, BadGuyKind kind, bool activate) { BadGuy* badguy = new BadGuy(kind, x, y); add_object(badguy); + if(activate) + badguy->activate(LEFT); return badguy; } @@ -607,17 +755,44 @@ Sector::add_bullet(const Vector& pos, float xm, Direction dir) else throw std::runtime_error("wrong bullet type."); add_object(new_bullet); - - play_sound(sounds[SND_SHOOT], SOUND_CENTER_SPEAKER); + + SoundManager::get()->play_sound(IDToSound(SND_SHOOT)); return true; } +bool +Sector::add_smoke_cloud(const Vector& pos) +{ + add_object(new SmokeCloud(pos)); + return true; +} + +bool +Sector::add_particles(const Vector& epicenter, int min_angle, int max_angle, const Vector& initial_velocity, const Vector& acceleration, int number, Color color, int size, int life_time, int drawing_layer) +{ + add_object(new Particles(epicenter, min_angle, max_angle, initial_velocity, acceleration, number, color, size, life_time, drawing_layer)); + return true; +} + +void +Sector::add_floating_text(const Vector& pos, const std::string& text) +{ + add_object(new FloatingText(pos, text)); +} + /* Break a brick: */ bool Sector::trybreakbrick(const Vector& pos, bool small) { Tile* tile = solids->get_tile_at(pos); + if (!tile) + { + char errmsg[64]; + sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32)); + throw SuperTuxException(errmsg, __FILE__, __LINE__); + } + if (tile->attributes & Tile::BRICK) { if (tile->data > 0) @@ -642,9 +817,10 @@ Sector::trybreakbrick(const Vector& pos, bool small) counting_distros = false; solids->change_at(pos, tile->next_tile); } - - play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); - player_status.score = player_status.score + SCORE_DISTRO; + + SoundManager::get()->play_sound(IDToSound(SND_DISTRO)); + global_stats.add_points(SCORE_STAT, SCORE_DISTRO); + global_stats.add_points(COINS_COLLECTED_STAT, 1); player_status.distros++; return true; } @@ -659,8 +835,8 @@ Sector::trybreakbrick(const Vector& pos, bool small) (int)(pos.y / 32) * 32), tile); /* Get some score: */ - play_sound(sounds[SND_BRICK], SOUND_CENTER_SPEAKER); - player_status.score = player_status.score + SCORE_BRICK; + SoundManager::get()->play_sound(IDToSound(SND_BRICK)); + global_stats.add_points(SCORE_STAT, SCORE_BRICK); return true; } @@ -674,6 +850,14 @@ void Sector::tryemptybox(const Vector& pos, Direction col_side) { Tile* tile = solids->get_tile_at(pos); + if (!tile) + { + char errmsg[64]; + sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32)); + throw SuperTuxException(errmsg, __FILE__, __LINE__); + } + + if (!(tile->attributes & Tile::FULLBOX)) return; @@ -689,8 +873,9 @@ Sector::tryemptybox(const Vector& pos, Direction col_side) { case 1: // Box with a distro! add_bouncy_distro(Vector(posx, posy)); - play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); - player_status.score = player_status.score + SCORE_DISTRO; + SoundManager::get()->play_sound(IDToSound(SND_DISTRO)); + global_stats.add_points(SCORE_STAT, SCORE_DISTRO); + global_stats.add_points(COINS_COLLECTED_STAT, 1); player_status.distros++; break; @@ -699,7 +884,7 @@ Sector::tryemptybox(const Vector& pos, Direction col_side) add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP); else /* Tux is big, add a fireflower: */ add_upgrade(Vector(posx, posy), col_side, UPGRADE_FIREFLOWER); - play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER); + SoundManager::get()->play_sound(IDToSound(SND_UPGRADE)); break; case 5: // Add an ice flower upgrade! @@ -707,11 +892,11 @@ Sector::tryemptybox(const Vector& pos, Direction col_side) add_upgrade(Vector(posx, posy), col_side, UPGRADE_GROWUP); else /* Tux is big, add an iceflower: */ add_upgrade(Vector(posx, posy), col_side, UPGRADE_ICEFLOWER); - play_sound(sounds[SND_UPGRADE], SOUND_CENTER_SPEAKER); + SoundManager::get()->play_sound(IDToSound(SND_UPGRADE)); break; case 3: // Add a golden herring - add_upgrade(Vector(posx, posy), col_side, UPGRADE_HERRING); + add_upgrade(Vector(posx, posy), col_side, UPGRADE_STAR); break; case 4: // Add a 1up extra @@ -730,20 +915,35 @@ void Sector::trygrabdistro(const Vector& pos, int bounciness) { Tile* tile = solids->get_tile_at(pos); + if (!tile) + { + /*char errmsg[64]; + sprintf(errmsg, "Invalid tile at %i,%i", (int)((pos.x+1)/32*32), (int)((pos.y+1)/32*32)); + throw SuperTuxException(errmsg, __FILE__, __LINE__); */ + + //Bad tiles (i.e. tiles that are not defined in supertux.stgt but appear in the map) are changed to ID 0 (blank tile) + 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; + solids->change_at(pos,0); + tile = solids->get_tile_at(pos); + } + + if (!(tile->attributes & Tile::COIN)) return; solids->change_at(pos, tile->next_tile); - play_sound(sounds[SND_DISTRO], SOUND_CENTER_SPEAKER); - + SoundManager::get()->play_sound(IDToSound(SND_DISTRO)); + if (bounciness == BOUNCE) { add_bouncy_distro(Vector(((int)(pos.x + 1) / 32) * 32, (int)(pos.y / 32) * 32)); } - player_status.score = player_status.score + SCORE_DISTRO; + global_stats.add_points(SCORE_STAT, SCORE_DISTRO); + global_stats.add_points(COINS_COLLECTED_STAT, 1); player_status.distros++; + } /* Try to bump a bad guy from below: */ @@ -778,7 +978,7 @@ Sector::load_music() char* song_path; char* song_subtitle; - level_song = music_manager->load_music(datadir + "/music/" + song_title); + level_song = SoundManager::get()->load_music(datadir + "/music/" + song_title); song_path = (char *) malloc(sizeof(char) * datadir.length() + strlen(song_title.c_str()) + 8 + 5); @@ -786,10 +986,10 @@ Sector::load_music() strcpy(strstr(song_subtitle, "."), "\0"); sprintf(song_path, "%s/music/%s-fast%s", datadir.c_str(), song_subtitle, strstr(song_title.c_str(), ".")); - if(!music_manager->exists_music(song_path)) { + if(!SoundManager::get()->exists_music(song_path)) { level_song_fast = level_song; } else { - level_song_fast = music_manager->load_music(song_path); + level_song_fast = SoundManager::get()->load_music(song_path); } free(song_subtitle); free(song_path); @@ -801,16 +1001,16 @@ Sector::play_music(int type) currentmusic = type; switch(currentmusic) { case HURRYUP_MUSIC: - music_manager->play_music(level_song_fast); + SoundManager::get()->play_music(level_song_fast); break; case LEVEL_MUSIC: - music_manager->play_music(level_song); + SoundManager::get()->play_music(level_song); break; case HERRING_MUSIC: - music_manager->play_music(herring_song); + SoundManager::get()->play_music(herring_song); break; default: - music_manager->halt_music(); + SoundManager::get()->halt_music(); break; } } @@ -820,3 +1020,16 @@ Sector::get_music_type() { return currentmusic; } + +int +Sector::get_total_badguys() +{ + int total_badguys = 0; + for(GameObjects::iterator i = gameobjects_new.begin(); i != gameobjects_new.end(); ++i) + { + BadGuy* badguy = dynamic_cast (*i); + if(badguy) + total_badguys++; + } + return total_badguys; +}