X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;f=src%2Fworldmap%2Fworldmap.cpp;h=94856d1a32ef6a32f6f5ed706a7155493b3020e9;hb=5667d7e94d85f968ab914bc457edd689fc907253;hp=5b4595905b60b47eaaba0e6e0600ba95470e4bd4;hpb=c307442e4bf1352cf1807b171b5ab175ba063b31;p=supertux.git diff --git a/src/worldmap/worldmap.cpp b/src/worldmap/worldmap.cpp index 5b4595905..94856d1a3 100644 --- a/src/worldmap/worldmap.cpp +++ b/src/worldmap/worldmap.cpp @@ -36,6 +36,7 @@ #include "shrinkfade.hpp" #include "video/surface.hpp" #include "video/drawing_context.hpp" +#include "sprite/sprite.hpp" #include "sprite/sprite_manager.hpp" #include "audio/sound_manager.hpp" #include "lisp/parser.hpp" @@ -53,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" @@ -66,6 +70,8 @@ #include "worldmap/tux.hpp" #include "worldmap/sprite_change.hpp" +static const float CAMERA_PAN_SPEED = 5.0; + namespace WorldMapNS { enum WorldMapMenuIDs { @@ -133,10 +139,10 @@ string_to_direction(const std::string& directory) //--------------------------------------------------------------------------- WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpoint) - : tux(0), solids(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); @@ -153,8 +159,6 @@ WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpo worldmap_menu->add_hl(); worldmap_menu->add_entry(MNID_QUITWORLDMAP, _("Quit World")); - load(filename); - // create a new squirrel table for the worldmap using namespace Scripting; @@ -170,13 +174,31 @@ WorldMap::WorldMap(const std::string& filename, const std::string& force_spawnpo sq_addref(global_vm, &worldmap_table); sq_pop(global_vm, 1); + + sound_manager->preload("sounds/warp.wav"); + + // load worldmap objects + load(filename); } WorldMap::~WorldMap() { using namespace Scripting; - save_state(); + if(free_tileset) + delete tileset; + + for(GameObjects::iterator i = game_objects.begin(); + i != game_objects.end(); ++i) { + GameObject* object = *i; + try_unexpose(object); + object->unref(); + } + + for(SpawnPoints::iterator i = spawn_points.begin(); + i != spawn_points.end(); ++i) { + delete *i; + } for(ScriptList::iterator i = scripts.begin(); i != scripts.end(); ++i) { @@ -189,17 +211,6 @@ WorldMap::~WorldMap() if(current_ == this) current_ = NULL; - - for(GameObjects::iterator i = game_objects.begin(); - i != game_objects.end(); ++i) { - GameObject* object = *i; - object->unref(); - } - - for(SpawnPoints::iterator i = spawn_points.begin(); - i != spawn_points.end(); ++i) { - delete *i; - } } void @@ -207,15 +218,45 @@ WorldMap::add_object(GameObject* object) { TileMap* tilemap = dynamic_cast (object); if(tilemap != 0 && tilemap->is_solid()) { - solids = tilemap; + solid_tilemaps.push_back(tilemap); } object->ref(); + try_expose(object); game_objects.push_back(object); } void -WorldMap::move_to_spawnpoint(const std::string& spawnpoint) +WorldMap::try_expose(GameObject* object) +{ + ScriptInterface* interface = dynamic_cast (object); + if(interface != NULL) { + HSQUIRRELVM vm = Scripting::global_vm; + sq_pushobject(vm, worldmap_table); + interface->expose(vm, -1); + sq_pop(vm, 1); + } +} + +void +WorldMap::try_unexpose(GameObject* object) +{ + ScriptInterface* interface = dynamic_cast (object); + if(interface != NULL) { + HSQUIRRELVM vm = Scripting::global_vm; + SQInteger oldtop = sq_gettop(vm); + sq_pushobject(vm, worldmap_table); + try { + interface->unexpose(vm, -1); + } catch(std::exception& e) { + log_warning << "Couldn't unregister object: " << e.what() << std::endl; + } + sq_settop(vm, oldtop); + } +} + +void +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; @@ -223,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; } } @@ -247,22 +293,41 @@ WorldMap::load(const std::string& filename) try { lisp::Parser parser; - std::auto_ptr root (parser.parse(map_filename)); + 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") { @@ -290,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 { @@ -302,7 +367,9 @@ WorldMap::load(const std::string& filename) log_warning << "Unknown token '" << iter.item() << "' in worldmap" << std::endl; } } - if(solids == 0) + current_tileset = NULL; + + if(solid_tilemaps.size() == 0) throw std::runtime_error("No solid tilemap specified"); move_to_spawnpoint("main"); @@ -323,7 +390,7 @@ WorldMap::get_level_title(LevelTile& level) try { lisp::Parser parser; - std::auto_ptr root (parser.parse(levels_path + level.get_name())); + const lisp::Lisp* root = parser.parse(levels_path + level.get_name()); const lisp::Lisp* level_lisp = root->get_lisp("supertux-level"); if(!level_lisp) @@ -338,7 +405,7 @@ WorldMap::get_level_title(LevelTile& level) void WorldMap::calculate_total_stats() { - total_stats.reset(); + total_stats.zero(); for(LevelTiles::iterator i = levels.begin(); i != levels.end(); ++i) { LevelTile* level = *i; if (level->solved) { @@ -386,30 +453,32 @@ WorldMap::path_ok(Direction direction, const Vector& old_pos, Vector* new_pos) { *new_pos = get_next_tile(old_pos, direction); - if (!(new_pos->x >= 0 && new_pos->x < solids->get_width() - && new_pos->y >= 0 && new_pos->y < solids->get_height())) + if (!(new_pos->x >= 0 && new_pos->x < get_width() + && new_pos->y >= 0 && new_pos->y < get_height())) { // New position is outsite the tilemap return false; } else { // Check if the tile allows us to go to new_pos + int old_tile_data = tile_data_at(old_pos); + int new_tile_data = tile_data_at(*new_pos); switch(direction) { case D_WEST: - return (at(old_pos)->getData() & Tile::WORLDMAP_WEST - && at(*new_pos)->getData() & Tile::WORLDMAP_EAST); + return (old_tile_data & Tile::WORLDMAP_WEST + && new_tile_data & Tile::WORLDMAP_EAST); case D_EAST: - return (at(old_pos)->getData() & Tile::WORLDMAP_EAST - && at(*new_pos)->getData() & Tile::WORLDMAP_WEST); + return (old_tile_data & Tile::WORLDMAP_EAST + && new_tile_data & Tile::WORLDMAP_WEST); case D_NORTH: - return (at(old_pos)->getData() & Tile::WORLDMAP_NORTH - && at(*new_pos)->getData() & Tile::WORLDMAP_SOUTH); + return (old_tile_data & Tile::WORLDMAP_NORTH + && new_tile_data & Tile::WORLDMAP_SOUTH); case D_SOUTH: - return (at(old_pos)->getData() & Tile::WORLDMAP_SOUTH - && at(*new_pos)->getData() & Tile::WORLDMAP_NORTH); + return (old_tile_data & Tile::WORLDMAP_SOUTH + && new_tile_data & Tile::WORLDMAP_NORTH); case D_NONE: assert(!"path_ok() can't walk if direction is NONE"); @@ -439,15 +508,13 @@ WorldMap::finished_level(Level* gamelevel) // FIXME: Mostly a hack Direction dir = D_NONE; - const Tile* tile = at(tux->get_tile_pos()); - - int dirdata = tile->getData() & Tile::WORLDMAP_DIR_MASK; + 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) @@ -477,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()) { @@ -503,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 @@ -511,6 +605,7 @@ WorldMap::update(float delta) i != game_objects.end(); ) { GameObject* object = *i; if(!object->is_valid()) { + try_unexpose(object); object->unref(); i = game_objects.erase(i); } else { @@ -518,25 +613,45 @@ WorldMap::update(float delta) } } + /* update solid_tilemaps list */ + //FIXME: this could be more efficient + solid_tilemaps.clear(); + for(std::vector::iterator i = game_objects.begin(); + i != game_objects.end(); ++i) + { + TileMap* tm = dynamic_cast(*i); + if (!tm) continue; + if (tm->is_solid()) solid_tilemaps.push_back(tm); + } + + Vector requested_pos; + // 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; - - if (camera_offset.x < 0) - camera_offset.x = 0; - if (camera_offset.y < 0) - camera_offset.y = 0; - - if (camera_offset.x > (int)solids->get_width()*32 - SCREEN_WIDTH) - camera_offset.x = (int)solids->get_width()*32 - SCREEN_WIDTH; - if (camera_offset.y > (int)solids->get_height()*32 - SCREEN_HEIGHT) - camera_offset.y = (int)solids->get_height()*32 - SCREEN_HEIGHT; - - if (int(solids->get_width()*32) < SCREEN_WIDTH) - camera_offset.x = solids->get_width()*16.0 - SCREEN_WIDTH/2.0; - if (int(solids->get_height()*32) < SCREEN_HEIGHT) - camera_offset.y = solids->get_height()*16.0 - SCREEN_HEIGHT/2.0; + 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; + } + } + + requested_pos = camera_offset; + clamp_camera_position(camera_offset); + + 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; @@ -545,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(); @@ -560,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); } } @@ -576,8 +691,8 @@ WorldMap::update(float delta) LevelTile* level = at_level(); if (!level) { //Respawn if player on a tile with no level and nowhere to go. - const Tile* tile = at(tux->get_tile_pos()); - if(!( tile->getData() & ( Tile::WORLDMAP_NORTH | Tile::WORLDMAP_SOUTH | Tile::WORLDMAP_WEST | Tile::WORLDMAP_EAST ))){ + int tile_data = tile_data_at(tux->get_tile_pos()); + if(!( tile_data & ( Tile::WORLDMAP_NORTH | Tile::WORLDMAP_SOUTH | Tile::WORLDMAP_WEST | Tile::WORLDMAP_EAST ))){ log_warning << "Player at illegal position " << tux->get_tile_pos().x << ", " << tux->get_tile_pos().y << " respawning." << std::endl; move_to_spawnpoint("main"); return; @@ -589,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; @@ -610,10 +725,25 @@ WorldMap::update(float delta) } } -const Tile* -WorldMap::at(Vector p) +int +WorldMap::tile_data_at(Vector p) +{ + int dirs = 0; + + for(std::list::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) { + TileMap* tilemap = *i; + const Tile* tile = tilemap->get_tile((int)p.x, (int)p.y); + int dirdata = tile->getData(); + dirs |= dirdata; + } + + return dirs; +} + +int +WorldMap::available_directions_at(Vector p) { - return solids->get_tile((int) p.x, (int) p.y); + return tile_data_at(p) & Tile::WORLDMAP_DIR_MASK; } LevelTile* @@ -668,7 +798,7 @@ WorldMap::at_teleporter(const Vector& pos) void WorldMap::draw(DrawingContext& context) { - if (int(solids->get_width()*32) < SCREEN_WIDTH || int(solids->get_height()*32) < SCREEN_HEIGHT) + if (int(get_width()*32) < SCREEN_WIDTH || int(get_height()*32) < SCREEN_HEIGHT) context.draw_filled_rect(Vector(0, 0), Vector(SCREEN_WIDTH, SCREEN_HEIGHT), Color(0.0f, 0.0f, 0.0f, 1.0f), LAYER_BACKGROUND0); @@ -679,9 +809,32 @@ 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); + } } +/* + // FIXME: make this a runtime switch similar to draw_collrects/show_collrects? + // draw visual indication of possible walk directions + static int flipme = 0; + if (flipme++ & 0x04) + for (int x = 0; x < get_width(); x++) { + for (int y = 0; y < get_height(); y++) { + int data = tile_data_at(Vector(x,y)); + int px = x * 32; + int py = y * 32; + const int W = 4; + if (data & Tile::WORLDMAP_NORTH) context.draw_filled_rect(Rect(px + 16-W, py , px + 16+W, py + 16-W), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + if (data & Tile::WORLDMAP_SOUTH) context.draw_filled_rect(Rect(px + 16-W, py + 16+W, px + 16+W, py + 32 ), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + if (data & Tile::WORLDMAP_EAST) context.draw_filled_rect(Rect(px + 16+W, py + 16-W, px + 32 , py + 16+W), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + if (data & Tile::WORLDMAP_WEST) context.draw_filled_rect(Rect(px , py + 16-W, px + 16-W, py + 16+W), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + if (data & Tile::WORLDMAP_DIR_MASK) context.draw_filled_rect(Rect(px + 16-W, py + 16-W, px + 16+W, py + 16+W), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + if (data & Tile::WORLDMAP_STOP) context.draw_filled_rect(Rect(px + 4 , py + 4 , px + 28 , py + 28 ), Color(0.2f, 0.2f, 0.2f, 0.7f), LAYER_FOREGROUND1 + 1000); + } + } +*/ + draw_status(context); context.pop_transform(); } @@ -702,10 +855,10 @@ WorldMap::draw_status(DrawingContext& context) if(level->title == "") get_level_title(*level); - context.draw_text(white_text, level->title, - Vector(SCREEN_WIDTH/2, - SCREEN_HEIGHT - white_text->get_height() - 30), - CENTER_ALLIGN, LAYER_FOREGROUND1); + context.draw_text(normal_font, level->title, + Vector(SCREEN_WIDTH/2, + SCREEN_HEIGHT - normal_font->get_height() - 30), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::level_title_color); // if level is solved, draw level picture behind stats /* @@ -732,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), - CENTER_ALLIGN, LAYER_FOREGROUND1); + SCREEN_HEIGHT - normal_font->get_height() - 60), + ALIGN_CENTER, LAYER_FOREGROUND1, WorldMap::message_color); break; } } @@ -743,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, CENTER_ALLIGN, 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), - CENTER_ALLIGN, 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(); } @@ -785,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"); @@ -794,9 +956,12 @@ WorldMap::setup() void WorldMap::leave() { - // remove worldmap_table from roottable using namespace Scripting; + // save state of world and player + save_state(); + + // remove worldmap_table from roottable sq_pushroottable(global_vm); sq_pushstring(global_vm, "worldmap", -1); if(SQ_FAILED(sq_deleteslot(global_vm, -2, SQFalse))) @@ -804,100 +969,6 @@ WorldMap::leave() sq_pop(global_vm, 1); } -static void store_float(HSQUIRRELVM vm, const char* name, float val) -{ - sq_pushstring(vm, name, -1); - sq_pushfloat(vm, val); - if(SQ_FAILED(sq_createslot(vm, -3))) - throw Scripting::SquirrelError(vm, "Couldn't add float value to table"); -} - -/* -static void store_int(HSQUIRRELVM vm, const char* name, int val) -{ - sq_pushstring(vm, name, -1); - sq_pushinteger(vm, val); - if(SQ_FAILED(sq_createslot(vm, -3))) - throw Scripting::SquirrelError(vm, "Couldn't add float value to table"); -} -*/ - -static void store_string(HSQUIRRELVM vm, const char* name, const std::string& val) -{ - sq_pushstring(vm, name, -1); - sq_pushstring(vm, val.c_str(), val.length()); - if(SQ_FAILED(sq_createslot(vm, -3))) - throw Scripting::SquirrelError(vm, "Couldn't add float value to table"); -} - -static void store_bool(HSQUIRRELVM vm, const char* name, bool val) -{ - sq_pushstring(vm, name, -1); - sq_pushbool(vm, val ? SQTrue : SQFalse); - if(SQ_FAILED(sq_createslot(vm, -3))) - throw Scripting::SquirrelError(vm, "Couldn't add float value to table"); -} - -static float read_float(HSQUIRRELVM vm, const char* name) -{ - sq_pushstring(vm, name, -1); - if(SQ_FAILED(sq_get(vm, -2))) { - std::ostringstream msg; - msg << "Couldn't get float value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - - float result; - if(SQ_FAILED(sq_getfloat(vm, -1, &result))) { - std::ostringstream msg; - msg << "Couldn't get float value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - sq_pop(vm, 1); - - return result; -} - -static std::string read_string(HSQUIRRELVM vm, const char* name) -{ - sq_pushstring(vm, name, -1); - if(SQ_FAILED(sq_get(vm, -2))) { - std::ostringstream msg; - msg << "Couldn't get string value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - - const char* result; - if(SQ_FAILED(sq_getstring(vm, -1, &result))) { - std::ostringstream msg; - msg << "Couldn't get string value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - sq_pop(vm, 1); - - return std::string(result); -} - -static bool read_bool(HSQUIRRELVM vm, const char* name) -{ - sq_pushstring(vm, name, -1); - if(SQ_FAILED(sq_get(vm, -2))) { - std::ostringstream msg; - msg << "Couldn't get bool value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - - SQBool result; - if(SQ_FAILED(sq_getbool(vm, -1, &result))) { - std::ostringstream msg; - msg << "Couldn't get bool value for '" << name << "' from table"; - throw Scripting::SquirrelError(vm, msg.str()); - } - sq_pop(vm, 1); - - return result == SQTrue; -} - void WorldMap::save_state() { @@ -951,18 +1022,20 @@ 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); - // TODO write statistics - // i->statistics.write(writer); + store_bool(vm, "solved", level->solved); + level->statistics.serialize_to_squirrel(vm); - sq_createslot(vm, -3); + sq_createslot(vm, -3); } sq_createslot(vm, -3); + // overall statistics... + total_stats.serialize_to_squirrel(vm); + // push world into worlds table sq_createslot(vm, -3); } catch(std::exception& ) { @@ -970,7 +1043,7 @@ WorldMap::save_state() } sq_settop(vm, oldtop); - + if(World::current() != NULL) World::current()->save_state(); } @@ -1025,12 +1098,17 @@ WorldMap::load_state() if(SQ_SUCCEEDED(sq_get(vm, -2))) { level->solved = read_bool(vm, "solved"); level->sprite->set_action(level->solved ? "solved" : "default"); - // i->statistics.parse(*level); + level->statistics.unserialize_from_squirrel(vm); sq_pop(vm, 1); } } + + // leave state table sq_pop(vm, 1); + // load overall statistics + total_stats.unserialize_from_squirrel(vm); + } catch(std::exception& e) { log_debug << "Not loading worldmap state: " << e.what() << std::endl; } @@ -1093,4 +1171,26 @@ WorldMap::run_script(std::istream& in, const std::string& sourcename) return vm; } +float +WorldMap::get_width() const +{ + float width = 0; + for(std::list::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) { + TileMap* solids = *i; + if (solids->get_width() > width) width = solids->get_width(); + } + return width; +} + +float +WorldMap::get_height() const +{ + float height = 0; + for(std::list::const_iterator i = solid_tilemaps.begin(); i != solid_tilemaps.end(); i++) { + TileMap* solids = *i; + if (solids->get_height() > height) height = solids->get_height(); + } + return height; +} + } // namespace WorldMapNS