X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fworldmap%2Fworldmap.cpp;h=94856d1a32ef6a32f6f5ed706a7155493b3020e9;hb=5667d7e94d85f968ab914bc457edd689fc907253;hp=e25c1628bf8e6fb1d19415fd52f14507128da4eb;hpb=691335a74a0717e839f440c6151f1517cf89548d;p=supertux.git diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index e25c1628b..94856d1a3 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -54,6 +54,9 @@ #include "main.hpp" #include "spawn_point.hpp" #include "file_system.hpp" +#include "physfs/physfs_stream.hpp" +#include "tile_manager.hpp" +#include "tile_set.hpp" #include "gui/menu.hpp" #include "gui/mousecursor.hpp" #include "control/joystickkeyboardcontroller.hpp" @@ -67,6 +70,8 @@ #include "worldmap/tux.hpp" #include "worldmap/sprite_change.hpp" +static const float CAMERA_PAN_SPEED = 5.0; + namespace WorldMapNS { enum WorldMapMenuIDs { @@ -134,10 +139,10 @@ string_to_direction(const std::string& directory) //--------------------------------------------------------------------------- WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpoint) - : tux(0), ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), force_spawnpoint(force_spawnpoint), in_level(false) + : tux(0), tileset(NULL), free_tileset(false), + ambient_light( 1.0f, 1.0f, 1.0f, 1.0f ), force_spawnpoint(force_spawnpoint), + in_level(false), panning(false) { - tile_manager.reset(new TileManager("images/worldmap.strf")); - tux = new Tux(this); add_object(tux); @@ -180,6 +185,9 @@ WorldMap::~WorldMap() { using namespace Scripting; + if(free_tileset) + delete tileset; + for(GameObjects::iterator i = game_objects.begin(); i != game_objects.end(); ++i) { GameObject* object = *i; @@ -248,7 +256,7 @@ WorldMap::try_unexpose(GameObject* object) } void -WorldMap::move_to_spawnpoint(const std::string& spawnpoint) +WorldMap::move_to_spawnpoint(const std::string& spawnpoint, bool pan) { for(SpawnPoints::iterator i = spawn_points.begin(); i != spawn_points.end(); ++i) { SpawnPoint* sp = *i; @@ -256,6 +264,11 @@ WorldMap::move_to_spawnpoint(const std::string& spawnpoint) Vector p = sp->pos; tux->set_tile_pos(p); tux->set_direction(sp->auto_dir); + if(pan) { + panning = true; + pan_pos = get_camera_pos_for_tux(); + clamp_camera_position(pan_pos); + } return; } } @@ -282,20 +295,39 @@ WorldMap::load(const std::string& filename) lisp::Parser parser; const lisp::Lisp* root = parser.parse(map_filename); - const lisp::Lisp* lisp = root->get_lisp("supertux-level"); - if(!lisp) + const lisp::Lisp* level = root->get_lisp("supertux-level"); + if(level == NULL) throw std::runtime_error("file isn't a supertux-level file."); - lisp->get("name", name); + level->get("name", name); - const lisp::Lisp* sector = lisp->get_lisp("sector"); + const lisp::Lisp* sector = level->get_lisp("sector"); if(!sector) - throw std::runtime_error("No sector sepcified in worldmap file."); + throw std::runtime_error("No sector specified in worldmap file."); + + const lisp::Lisp* tilesets_lisp = level->get_lisp("tilesets"); + if(tilesets_lisp != NULL) { + tileset = tile_manager->parse_tileset_definition(*tilesets_lisp); + free_tileset = true; + } + std::string tileset_name; + if(level->get("tileset", tileset_name)) { + if(tileset != NULL) { + log_warning << "multiple tilesets specified in level" << std::endl; + } else { + tileset = tile_manager->get_tileset(tileset_name); + } + } + /* load default tileset */ + if(tileset == NULL) { + tileset = tile_manager->get_tileset("images/worldmap.strf"); + } + current_tileset = tileset; lisp::ListIterator iter(sector); while(iter.next()) { if(iter.item() == "tilemap") { - add_object(new TileMap(*(iter.lisp()), tile_manager.get())); + add_object(new TileMap(*(iter.lisp()))); } else if(iter.item() == "background") { add_object(new Background(*(iter.lisp()))); } else if(iter.item() == "music") { @@ -323,7 +355,7 @@ WorldMap::load(const std::string& filename) add_object(teleporter); } else if(iter.item() == "ambient-light") { std::vector vColor; - sector->get_vector( "ambient-light", vColor ); + sector->get( "ambient-light", vColor ); if(vColor.size() < 3) { log_warning << "(ambient-light) requires a color as argument" << std::endl; } else { @@ -335,6 +367,8 @@ WorldMap::load(const std::string& filename) log_warning << "Unknown token '" << iter.item() << "' in worldmap" << std::endl; } } + current_tileset = NULL; + if(solid_tilemaps.size() == 0) throw std::runtime_error("No solid tilemap specified"); @@ -477,10 +511,10 @@ WorldMap::finished_level(Level* gamelevel) int dirdata = available_directions_at(tux->get_tile_pos()); // first, test for crossroads if (dirdata == Tile::WORLDMAP_CNSE || - dirdata == Tile::WORLDMAP_CNSW || - dirdata == Tile::WORLDMAP_CNEW || - dirdata == Tile::WORLDMAP_CSEW || - dirdata == Tile::WORLDMAP_CNSEW) + dirdata == Tile::WORLDMAP_CNSW || + dirdata == Tile::WORLDMAP_CNEW || + dirdata == Tile::WORLDMAP_CSEW || + dirdata == Tile::WORLDMAP_CNSEW) dir = D_NONE; else if (dirdata & Tile::WORLDMAP_NORTH && tux->back_direction != D_NORTH) @@ -510,14 +544,39 @@ WorldMap::finished_level(Level* gamelevel) } } +Vector +WorldMap::get_camera_pos_for_tux() { + Vector camera_offset; + Vector tux_pos = tux->get_pos(); + camera_offset.x = tux_pos.x - SCREEN_WIDTH/2; + camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2; + return camera_offset; +} + +void +WorldMap::clamp_camera_position(Vector& c) { + if (c.x < 0) + c.x = 0; + if (c.y < 0) + c.y = 0; + + if (c.x > (int)get_width()*32 - SCREEN_WIDTH) + c.x = (int)get_width()*32 - SCREEN_WIDTH; + if (c.y > (int)get_height()*32 - SCREEN_HEIGHT) + c.y = (int)get_height()*32 - SCREEN_HEIGHT; + + if (int(get_width()*32) < SCREEN_WIDTH) + c.x = get_width()*16.0 - SCREEN_WIDTH/2.0; + if (int(get_height()*32) < SCREEN_HEIGHT) + c.y = get_height()*16.0 - SCREEN_HEIGHT/2.0; +} + void WorldMap::update(float delta) { if(!in_level) { Menu* menu = Menu::current(); if(menu != NULL) { - menu->update(); - if(menu == worldmap_menu.get()) { switch (worldmap_menu->check()) { @@ -536,7 +595,9 @@ WorldMap::update(float delta) // update GameObjects for(size_t i = 0; i < game_objects.size(); ++i) { GameObject* object = game_objects[i]; - object->update(delta); + if(!panning || object != tux) { + object->update(delta); + } } // remove old GameObjects @@ -563,25 +624,34 @@ WorldMap::update(float delta) if (tm->is_solid()) solid_tilemaps.push_back(tm); } - // position "camera" - Vector tux_pos = tux->get_pos(); - camera_offset.x = tux_pos.x - SCREEN_WIDTH/2; - camera_offset.y = tux_pos.y - SCREEN_HEIGHT/2; + Vector requested_pos; - if (camera_offset.x < 0) - camera_offset.x = 0; - if (camera_offset.y < 0) - camera_offset.y = 0; + // position "camera" + if(!panning) { + camera_offset = get_camera_pos_for_tux(); + } else { + Vector delta = pan_pos - camera_offset; + float mag = delta.norm(); + if(mag > CAMERA_PAN_SPEED) { + delta *= CAMERA_PAN_SPEED/mag; + } + camera_offset += delta; + if(camera_offset == pan_pos) { + panning = false; + } + } - if (camera_offset.x > (int)get_width()*32 - SCREEN_WIDTH) - camera_offset.x = (int)get_width()*32 - SCREEN_WIDTH; - if (camera_offset.y > (int)get_height()*32 - SCREEN_HEIGHT) - camera_offset.y = (int)get_height()*32 - SCREEN_HEIGHT; + requested_pos = camera_offset; + clamp_camera_position(camera_offset); - if (int(get_width()*32) < SCREEN_WIDTH) - camera_offset.x = get_width()*16.0 - SCREEN_WIDTH/2.0; - if (int(get_height()*32) < SCREEN_HEIGHT) - camera_offset.y = get_height()*16.0 - SCREEN_HEIGHT/2.0; + if(panning) { + if(requested_pos.x != camera_offset.x) { + pan_pos.x = camera_offset.x; + } + if(requested_pos.y != camera_offset.y) { + pan_pos.y = camera_offset.y; + } + } // handle input bool enter_level = false; @@ -590,8 +660,8 @@ WorldMap::update(float delta) || main_controller->pressed(Controller::MENU_SELECT)) { /* some people define UP and JUMP on the same key... */ if(!main_controller->pressed(Controller::UP)) - enter_level = true; - } + enter_level = true; + } if(main_controller->pressed(Controller::PAUSE_MENU)) on_escape_press(); @@ -605,7 +675,7 @@ WorldMap::update(float delta) // TODO: an animation, camera scrolling or a fading would be a nice touch sound_manager->play("sounds/warp.wav"); tux->back_direction = D_NONE; - move_to_spawnpoint(teleporter->spawnpoint); + move_to_spawnpoint(teleporter->spawnpoint, true); } } @@ -634,14 +704,14 @@ WorldMap::update(float delta) if (level->pos == tux->get_tile_pos()) { try { Vector shrinkpos = Vector(level->pos.x*32 + 16 - camera_offset.x, - level->pos.y*32 + 16 - camera_offset.y); + level->pos.y*32 + 8 - camera_offset.y); std::string levelfile = levels_path + level->get_name(); // update state and savegame save_state(); main_loop->push_screen(new GameSession(levelfile, &level->statistics), - new ShrinkFade(shrinkpos, 0.5)); + new ShrinkFade(shrinkpos, 1.0f)); in_level = true; } catch(std::exception& e) { log_fatal << "Couldn't load level: " << e.what() << std::endl; @@ -739,7 +809,9 @@ WorldMap::draw(DrawingContext& context) for(GameObjects::iterator i = game_objects.begin(); i != game_objects.end(); ++i) { GameObject* object = *i; - object->draw(context); + if(!panning || object != tux) { + object->draw(context); + } } /* @@ -783,10 +855,10 @@ WorldMap::draw_status(DrawingContext& context) if(level->title == "") get_level_title(*level); - context.draw_text(white_text, level->title, + context.draw_text(normal_font, level->title, Vector(SCREEN_WIDTH/2, - SCREEN_HEIGHT - white_text->get_height() - 30), - ALIGN_CENTER, LAYER_FOREGROUND1); + SCREEN_HEIGHT - normal_font->get_height() - 30), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::level_title_color); // if level is solved, draw level picture behind stats /* @@ -813,10 +885,10 @@ WorldMap::draw_status(DrawingContext& context) if (special_tile->pos == tux->get_tile_pos()) { /* Display an in-map message in the map, if any as been selected */ if(!special_tile->map_message.empty() && !special_tile->passive_message) - context.draw_text(gold_text, special_tile->map_message, + context.draw_text(normal_font, special_tile->map_message, Vector(SCREEN_WIDTH/2, - SCREEN_HEIGHT - white_text->get_height() - 60), - ALIGN_CENTER, LAYER_FOREGROUND1); + SCREEN_HEIGHT - normal_font->get_height() - 60), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::message_color); break; } } @@ -824,17 +896,17 @@ WorldMap::draw_status(DrawingContext& context) // display teleporter messages Teleporter* teleporter = at_teleporter(tux->get_tile_pos()); if (teleporter && (teleporter->message != "")) { - Vector pos = Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 30); - context.draw_text(white_text, teleporter->message, pos, ALIGN_CENTER, LAYER_FOREGROUND1); + Vector pos = Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - normal_font->get_height() - 30); + context.draw_text(normal_font, teleporter->message, pos, ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::teleporter_message_color); } } /* Display a passive message in the map, if needed */ if(passive_message_timer.started()) - context.draw_text(gold_text, passive_message, - Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - white_text->get_height() - 60), - ALIGN_CENTER, LAYER_FOREGROUND1); + context.draw_text(normal_font, passive_message, + Vector(SCREEN_WIDTH/2, SCREEN_HEIGHT - normal_font->get_height() - 60), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::message_color); context.pop_transform(); } @@ -866,6 +938,15 @@ WorldMap::setup() throw SquirrelError(global_vm, "Couldn't set worldmap in roottable"); sq_pop(global_vm, 1); + //Run default.nut just before init script + try { + IFileStream in(levels_path + "/default.nut"); + run_script(in, "WorldMap::default.nut"); + } catch(std::exception& ) { + // doesn't exist or erroneous; do nothing + } + + if(init_script != "") { std::istringstream in(init_script); run_script(in, "WorldMap::init"); @@ -941,13 +1022,13 @@ WorldMap::save_state() for(LevelTiles::iterator i = levels.begin(); i != levels.end(); ++i) { LevelTile* level = *i; - sq_pushstring(vm, level->get_name().c_str(), -1); - sq_newtable(vm); + sq_pushstring(vm, level->get_name().c_str(), -1); + sq_newtable(vm); - store_bool(vm, "solved", level->solved); - level->statistics.serialize_to_squirrel(vm); + store_bool(vm, "solved", level->solved); + level->statistics.serialize_to_squirrel(vm); - sq_createslot(vm, -3); + sq_createslot(vm, -3); } sq_createslot(vm, -3);