BonusBlock::BonusBlock(const ReaderMapping& lisp) : Block(SpriteManager::current()->create("images/objects/bonus_block/bonusblock.sprite")), contents(), object(0), hit_counter(1), sprite_name(), script(), lightsprite() { Vector pos; contents = CONTENT_COIN; auto iter = lisp.get_iter(); while(iter.next()) { const std::string& token = iter.get_key(); if(token == "x") { iter.get(pos.x); } else if(token == "y") { iter.get(pos.y); } else if(token == "sprite") { iter.get(sprite_name); sprite = SpriteManager::current()->create(sprite_name); } else if(token == "count") { iter.get(hit_counter); } else if(token == "script") { iter.get(script); } else if(token == "data") { int d = 0; iter.get(d); get_content_by_data(d); } else if(token == "contents") { std::string contentstring; iter.get(contentstring); contents = get_content_from_string(contentstring); } else { if(contents == CONTENT_CUSTOM) { ReaderMapping object_mapping = iter.as_mapping(); GameObjectPtr game_object = ObjectFactory::instance().create(token, object_mapping); object = std::dynamic_pointer_cast<MovingObject>(game_object); if(object == 0) throw std::runtime_error( "Only MovingObjects are allowed inside BonusBlocks"); } else { log_warning << "Invalid element '" << token << "' in bonusblock" << std::endl; } } } if(contents == CONTENT_CUSTOM && object == 0) throw std::runtime_error("Need to specify content object for custom block"); if(contents == CONTENT_LIGHT) { SoundManager::current()->preload("sounds/switch.ogg"); lightsprite = Surface::create("/images/objects/lightmap_light/bonusblock_light.png"); } bbox.set_pos(pos); }
void JoystickConfig::read(const ReaderMapping& joystick_lisp) { joystick_lisp.get("dead-zone", dead_zone); joystick_lisp.get("jump-with-up", jump_with_up_joy); joystick_lisp.get("use-game-controller", use_game_controller); auto iter = joystick_lisp.get_iter(); while(iter.next()) { if (iter.get_key() == "map") { int button = -1; int axis = 0; int hat = -1; std::string control; auto map = iter.as_mapping(); map.get("control", control); int i = 0; for(i = 0; Controller::controlNames[i] != 0; ++i) { if (control == Controller::controlNames[i]) break; } if (Controller::controlNames[i] == 0) { log_info << "Invalid control '" << control << "' in buttonmap" << std::endl; } else { if (map.get("button", button)) { bind_joybutton(0, button, Controller::Control(i)); } else if (map.get("axis", axis)) { bind_joyaxis(0, axis, Controller::Control(i)); } else if (map.get("hat", hat)) { if (hat != SDL_HAT_UP && hat != SDL_HAT_DOWN && hat != SDL_HAT_LEFT && hat != SDL_HAT_RIGHT) { log_info << "Invalid axis '" << axis << "' in axismap" << std::endl; } else { bind_joyhat(0, hat, Controller::Control(i)); } } } } } }
void LevelParser::load(const std::string& filepath) { try { m_level.m_filename = filepath; register_translation_directory(filepath); auto doc = ReaderDocument::from_file(filepath); auto root = doc.get_root(); if(root.get_name() != "supertux-level") throw std::runtime_error("file is not a supertux-level file."); auto level = root.get_mapping(); int version = 1; level.get("version", version); if(version == 1) { log_info << "[" << filepath << "] level uses old format: version 1" << std::endl; load_old_format(level); } else if (version == 2) { level.get("tileset", m_level.m_tileset); level.get("name", m_level.m_name); level.get("author", m_level.m_author); level.get("contact", m_level.m_contact); level.get("license", m_level.m_license); level.get("target-time", m_level.m_target_time); auto iter = level.get_iter(); while(iter.next()) { if (iter.get_key() == "sector") { auto sector = SectorParser::from_reader(m_level, iter.as_mapping()); m_level.add_sector(std::move(sector)); } } if (m_level.m_license.empty()) { log_warning << "[" << filepath << "] The level author \"" << m_level.m_author << "\" did not specify a license for this level \"" << m_level.m_name << "\". You might not be allowed to share it." << std::endl; } } else { log_warning << "[" << filepath << "] level format version " << version << " is not supported" << std::endl; } } catch(std::exception& e) { std::stringstream msg; msg << "Problem when reading level '" << filepath << "': " << e.what(); throw std::runtime_error(msg.str()); } m_level.m_stats.init(m_level); }
void Path::read(const ReaderMapping& reader) { auto iter = reader.get_iter(); mode = CIRCULAR; while(iter.next()) { if(iter.get_key() == "mode") { std::string mode_string; iter.get(mode_string); if(mode_string == "oneshot") mode = ONE_SHOT; else if(mode_string == "pingpong") mode = PING_PONG; else if(mode_string == "circular") mode = CIRCULAR; else if(mode_string == "unordered") mode = UNORDERED; else { std::ostringstream msg; msg << "Unknown pathmode '" << mode_string << "' found"; throw std::runtime_error(msg.str()); } continue; } else if (iter.get_key() == "node") { ReaderMapping node_mapping = iter.as_mapping(); // each new node will inherit all values from the last one Node node; node.time = 1; if( (!node_mapping.get("x", node.position.x) || !node_mapping.get("y", node.position.y))) throw std::runtime_error("Path node without x and y coordinate specified"); node_mapping.get("time", node.time); if(node.time <= 0) throw std::runtime_error("Path node with non-positive time"); nodes.push_back(node); } else { log_warning << "unknown token '" << iter.get_key() << "' in Path nodes list. Ignored." << std::endl; } } if (nodes.empty()) throw std::runtime_error("Path with zero nodes"); }
SpriteData::SpriteData(const ReaderMapping& lisp, const std::string& basedir) : actions(), name() { auto iter = lisp.get_iter(); while(iter.next()) { if(iter.get_key() == "name") { iter.get(name); } else if(iter.get_key() == "action") { parse_action(iter.as_mapping(), basedir); } else { log_warning << "Unknown sprite field: " << iter.get_key() << std::endl; } } if(actions.empty()) throw std::runtime_error("Error: Sprite without actions."); }
ObjectGroup::ObjectGroup(const ReaderMapping& reader) : name(), icons(), for_worldmap(false) { icons.clear(); icons.push_back( ObjectIcon("#move", "images/engine/editor/arrow.png") ); reader.get("name", name); reader.get("worldmap", for_worldmap); auto iter = reader.get_iter(); while(iter.next()) { const std::string& token = iter.get_key(); if (token == "object") { icons.push_back( ObjectIcon( iter.as_mapping() ) ); } } }
void SectorParser::parse(const ReaderMapping& sector) { bool has_background = false; auto iter = sector.get_iter(); while(iter.next()) { if(iter.get_key() == "name") { iter.get(m_sector.name); } else if(iter.get_key() == "gravity") { iter.get(m_sector.gravity); } else if(iter.get_key() == "music") { iter.get(m_sector.music); } else if(iter.get_key() == "spawnpoint") { auto sp = std::make_shared<SpawnPoint>(iter.as_mapping()); if (sp->name != "" && sp->pos.x >= 0 && sp->pos.y >= 0) { m_sector.spawnpoints.push_back(sp); } } else if(iter.get_key() == "init-script") { iter.get(m_sector.init_script); } else if(iter.get_key() == "ambient-light") { std::vector<float> vColor; sector.get( "ambient-light", vColor ); if(vColor.size() < 3) { log_warning << "(ambient-light) requires a color as argument" << std::endl; } else { m_sector.ambient_light = Color( vColor ); } } else { GameObjectPtr object = parse_object(iter.get_key(), iter.as_mapping()); if(object) { if(std::dynamic_pointer_cast<Background>(object)) { has_background = true; } else if(std::dynamic_pointer_cast<Gradient>(object)) { has_background = true; } m_sector.add_object(object); } } } if(!has_background) { auto gradient = std::make_shared<Gradient>(); gradient->set_gradient(Color(0.3, 0.4, 0.75), Color(1, 1, 1)); m_sector.add_object(gradient); } m_sector.update_game_objects(); if (m_sector.solid_tilemaps.empty()) { log_warning << "sector '" << m_sector.name << "' does not contain a solid tile layer." << std::endl; } fix_old_tiles(); if (!m_sector.camera) { log_warning << "sector '" << m_sector.name << "' does not contain a camera." << std::endl; m_sector.update_game_objects(); m_sector.add_object(std::make_shared<Camera>(&m_sector, "Camera")); } m_sector.update_game_objects(); m_sector.foremost_layer = m_sector.calculate_foremost_layer(); }
TextScroller::TextScroller(const std::string& filename) : defaultspeed(DEFAULT_SPEED), speed(defaultspeed), music(), background(), lines(), scroll(0), fading(false) { std::string text; std::string background_file; try { register_translation_directory(filename); auto doc = ReaderDocument::parse(filename); auto root = doc.get_root(); if(root.get_name() != "supertux-text") { throw std::runtime_error("File isn't a supertux-text file"); } else { auto text_lisp = root.get_mapping(); int version = 1; text_lisp.get("version", version); if (version == 1) { log_info << "[" << filename << "] Text uses old format: version 1" << std::endl; if(!text_lisp.get("text", text)) { throw std::runtime_error("File doesn't contain a text field"); } // Split text string lines into a vector lines = InfoBoxLine::split(text, static_cast<float>(SCREEN_WIDTH) - 2.0f * LEFT_BORDER); } else if (version == 2) { ReaderMapping content; if (!text_lisp.get("content", content)) { throw std::runtime_error("File doesn't contain content"); } else { auto iter = content.get_iter(); while (iter.next()) { if (iter.get_key() == "image") { std::string image_file; iter.get(image_file); lines.emplace_back(new InfoBoxLine('!', image_file)); } else if (iter.get_key() == "person") { bool simple; std::string name, info, image_file; if (!iter.as_mapping().get("simple", simple)) { simple = false; } if (simple) { if (!iter.as_mapping().get("name", name) || !iter.as_mapping().get("info", info)) { throw std::runtime_error("Simple entry requires both name and info specified"); } if (iter.as_mapping().get("image", image_file)) { log_warning << "[" << filename << "] Simple person entry shouldn't specify images" << std::endl; } lines.emplace_back(new InfoBoxLine(' ', name + " (" + info + ")")); } else { if (iter.as_mapping().get("name", name)) { lines.emplace_back(new InfoBoxLine('\t', name)); } if (iter.as_mapping().get("image", image_file) && !simple) { lines.emplace_back(new InfoBoxLine('!', image_file)); } if (iter.as_mapping().get("info", info)) { lines.emplace_back(new InfoBoxLine(' ', info)); } } } else if (iter.get_key() == "blank") { // Empty line lines.emplace_back(new InfoBoxLine('\t', "")); } else if (iter.get_key() == "text") { std::string type, string; if (!iter.as_mapping().get("type", type)) { type = "normal"; } if (!iter.as_mapping().get("string", string)) { throw std::runtime_error("Text entry requires a string"); } if (type == "normal") lines.emplace_back(new InfoBoxLine('\t', string)); else if (type == "normal-left") lines.emplace_back(new InfoBoxLine('#', string)); else if (type == "small") lines.emplace_back(new InfoBoxLine(' ', string)); else if (type == "heading") lines.emplace_back(new InfoBoxLine('-', string)); else if (type == "reference") lines.emplace_back(new InfoBoxLine('*', string)); else { log_warning << "[" << filename << "] Unknown text type '" << type << "'" << std::endl; lines.emplace_back(new InfoBoxLine('\t', string)); } } else { log_warning << "[" << filename << "] Unknown token '" << iter.get_key() << "'" << std::endl; } } } } else { throw std::runtime_error("File format version is not supported"); } if (!text_lisp.get("background", background_file)) { throw std::runtime_error("File doesn't contain a background file"); } text_lisp.get("speed", defaultspeed); text_lisp.get("music", music); } } catch (std::exception& e) { std::ostringstream msg; msg << "Couldn't load file '" << filename << "': " << e.what() << std::endl; throw std::runtime_error(msg.str()); } // load background image background = Surface::create("images/background/" + background_file); }
void WorldMapParser::load_worldmap(const std::string& filename) { m_worldmap.m_map_filename = physfsutil::realpath(filename); m_worldmap.m_levels_path = FileSystem::dirname(m_worldmap.m_map_filename); try { register_translation_directory(m_worldmap.m_map_filename); auto doc = ReaderDocument::from_file(m_worldmap.m_map_filename); auto root = doc.get_root(); if (root.get_name() != "supertux-level") throw std::runtime_error("file isn't a supertux-level file."); auto level_ = root.get_mapping(); level_.get("name", m_worldmap.m_name); std::string tileset_name; if (level_.get("tileset", tileset_name)) { if (m_worldmap.m_tileset != nullptr) { log_warning << "multiple tilesets specified in level_" << std::endl; } else { m_worldmap.m_tileset = TileManager::current()->get_tileset(tileset_name); } } /* load default tileset */ if (m_worldmap.m_tileset == nullptr) { m_worldmap.m_tileset = TileManager::current()->get_tileset("images/worldmap.strf"); } boost::optional<ReaderMapping> sector; if (!level_.get("sector", sector)) { throw std::runtime_error("No sector specified in worldmap file."); } else { auto iter = sector->get_iter(); while (iter.next()) { if (iter.get_key() == "tilemap") { m_worldmap.add<TileMap>(m_worldmap.m_tileset, iter.as_mapping()); } else if (iter.get_key() == "background") { m_worldmap.add<Background>(iter.as_mapping()); } else if (iter.get_key() == "music") { const auto& sx = iter.get_sexp(); if (sx.is_array() && sx.as_array().size() == 2 && sx.as_array()[1].is_string()) { std::string value; iter.get(value); m_worldmap.add<MusicObject>().set_music(value); } else { m_worldmap.add<MusicObject>(iter.as_mapping()); } } else if (iter.get_key() == "init-script") { iter.get(m_worldmap.m_init_script); } else if (iter.get_key() == "worldmap-spawnpoint") { auto sp = std::make_unique<SpawnPoint>(iter.as_mapping()); m_worldmap.m_spawn_points.push_back(std::move(sp)); } else if (iter.get_key() == "level") { auto& level = m_worldmap.add<LevelTile>(m_worldmap.m_levels_path, iter.as_mapping()); load_level_information(level); } else if (iter.get_key() == "special-tile") { m_worldmap.add<SpecialTile>(iter.as_mapping()); } else if (iter.get_key() == "sprite-change") { m_worldmap.add<SpriteChange>(iter.as_mapping()); } else if (iter.get_key() == "teleporter") { m_worldmap.add<Teleporter>(iter.as_mapping()); } else if (iter.get_key() == "decal") { m_worldmap.add<Decal>(iter.as_mapping()); } else if (iter.get_key() == "path") { m_worldmap.add<PathGameObject>(iter.as_mapping()); } else if (iter.get_key() == "ambient-light") { const auto& sx = iter.get_sexp(); if (sx.is_array() && sx.as_array().size() >= 3 && sx.as_array()[1].is_real() && sx.as_array()[2].is_real() && sx.as_array()[3].is_real()) { // for backward compatibilty std::vector<float> vColor; bool hasColor = sector->get("ambient-light", vColor); if (vColor.size() < 3 || !hasColor) { log_warning << "(ambient-light) requires a color as argument" << std::endl; } else { m_worldmap.add<AmbientLight>(Color(vColor)); } } else { // modern format m_worldmap.add<AmbientLight>(iter.as_mapping()); } } else if (iter.get_key() == "name") { // skip } else { log_warning << "Unknown token '" << iter.get_key() << "' in worldmap" << std::endl; } } } m_worldmap.flush_game_objects(); if (m_worldmap.get_solid_tilemaps().empty()) throw std::runtime_error("No solid tilemap specified"); m_worldmap.move_to_spawnpoint("main"); } catch(std::exception& e) { std::stringstream msg; msg << "Problem when parsing worldmap '" << m_worldmap.m_map_filename << "': " << e.what(); throw std::runtime_error(msg.str()); } m_worldmap.finish_construction(); }