game_info::game_info(const config& game, const config& game_config, const std::vector<std::string>& installed_addons) : mini_map() , id(game["id"]) , map_data(game["map_data"]) , name(game["name"]) , scenario() , remote_scenario(false) , map_info() , map_size_info() , era() , era_short() , gold(game["mp_village_gold"]) , support(game["mp_village_support"]) , xp(game["experience_modifier"].str() + "%") , vision() , status() , time_limit() , vacant_slots(lexical_cast_default<int>(game["slots"], 0)) // Can't use to_int() here. , current_turn(0) , reloaded(game["savegame"].to_bool()) , started(false) , fog(game["mp_fog"].to_bool()) , shroud(game["mp_shroud"].to_bool()) , observers(game["observer"].to_bool(true)) , shuffle_sides(game["shuffle_sides"].to_bool(true)) , use_map_settings(game["mp_use_map_settings"].to_bool()) , registered_users_only(game["registered_users_only"].to_bool()) , verified(true) , password_required(game["password"].to_bool()) , have_era(true) , have_all_mods(true) , has_friends(false) , has_ignored(false) , display_status(NEW) , required_addons() , addons_outcome(SATISFIED) { const auto parse_requirements = [&](const config& c, const std::string& id_key) { if(c.has_attribute(id_key)) { if(std::find(installed_addons.begin(), installed_addons.end(), c[id_key].str()) == installed_addons.end()) { required_addon r; r.addon_id = c[id_key].str(); r.outcome = NEED_DOWNLOAD; r.message = vgettext("Missing addon: $id", {{"id", c[id_key].str()}}); required_addons.push_back(r); if(addons_outcome == SATISFIED) { addons_outcome = NEED_DOWNLOAD; } } } }; for(const config& addon : game.child_range("addon")) { parse_requirements(addon, "id"); } /* * Modifications have a different format than addons. The id and addon_id are keys sent by the * server, so we have to parse them separately here and add them to the required_addons vector. */ for(const config& mod : game.child_range("modification")) { parse_requirements(mod, "addon_id"); } std::string turn = game["turn"]; if(!game["mp_era"].empty()) { const config& era_cfg = game_config.find_child("era", "id", game["mp_era"]); if(era_cfg) { era = era_cfg["name"].str(); era_short = era_cfg["short_name"].str(); if(era_short.empty()) { era_short = make_short_name(era); } ADDON_REQ result = check_addon_version_compatibility(era_cfg, game); addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far } else { have_era = !game["require_era"].to_bool(true); era = vgettext("Unknown era: $era_id", {{"era_id", game["mp_era_addon_id"].str()}}); era_short = make_short_name(era); verified = false; addons_outcome = NEED_DOWNLOAD; } } else { era = _("Unknown era"); era_short = "??"; verified = false; } std::stringstream info_stream; info_stream << era; if(!game.child_or_empty("modification").empty()) { for(const config& cfg : game.child_range("modification")) { if(const config& mod = game_config.find_child("modification", "id", cfg["id"])) { mod_info += (mod_info.empty() ? "" : ", ") + mod["name"].str(); if(cfg["require_modification"].to_bool(false)) { ADDON_REQ result = check_addon_version_compatibility(mod, game); addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far } } else { mod_info += (mod_info.empty() ? "" : ", ") + cfg["addon_id"].str(); if(cfg["require_modification"].to_bool(false)) { have_all_mods = false; mod_info += " " + _("(missing)"); addons_outcome = NEED_DOWNLOAD; } } } } if(map_data.empty()) { map_data = filesystem::read_map(game["mp_scenario"]); } if(map_data.empty()) { info_stream << " — ??×??"; } else { try { gamemap map(std::make_shared<terrain_type_data>(game_config), map_data); // mini_map = image::getMinimap(minimap_size_, minimap_size_, map, // 0); std::ostringstream msi; msi << map.w() << font::unicode_multiplication_sign << map.h(); map_size_info = msi.str(); info_stream << " — " + map_size_info; } catch(incorrect_map_format_error& e) { ERR_CF << "illegal map: " << e.message << std::endl; verified = false; } catch(wml_exception& e) { ERR_CF << "map could not be loaded: " << e.dev_message << '\n'; verified = false; } } info_stream << " "; // // Check scenarios and campaigns // if(!game["mp_scenario"].empty() && game["mp_campaign"].empty()) { // Check if it's a multiplayer scenario const config* level_cfg = &game_config.find_child("multiplayer", "id", game["mp_scenario"]); // Check if it's a user map if(!*level_cfg) { level_cfg = &game_config.find_child("generic_multiplayer", "id", game["mp_scenario"]); } if(*level_cfg) { scenario = formatter() << "<b>" << _("(S)") << "</b>" << " " << (*level_cfg)["name"].str(); info_stream << scenario; // Reloaded games do not match the original scenario hash, so it makes no sense // to test them, since they always would appear as remote scenarios if(!reloaded) { if(const config& hashes = game_config.child("multiplayer_hashes")) { std::string hash = game["hash"]; bool hash_found = false; for(const auto & i : hashes.attribute_range()) { if(i.first == game["mp_scenario"] && i.second == hash) { hash_found = true; break; } } if(!hash_found) { remote_scenario = true; info_stream << " — "; info_stream << _("Remote scenario"); verified = false; } } } if((*level_cfg)["require_scenario"].to_bool(false)) { ADDON_REQ result = check_addon_version_compatibility((*level_cfg), game); addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far } } else { scenario = vgettext("Unknown scenario: $scenario_id", {{"scenario_id", game["mp_scenario_name"].str()}}); info_stream << scenario; verified = false; } } else if(!game["mp_campaign"].empty()) { if(const config& level_cfg = game_config.find_child("campaign", "id", game["mp_campaign"])) { std::stringstream campaign_text; campaign_text << "<b>" << _("(C)") << "</b>" << " " << level_cfg["name"] << " — " << game["mp_scenario_name"]; // Difficulty config difficulties = gui2::dialogs::generate_difficulty_config(level_cfg); for(const config& difficulty : difficulties.child_range("difficulty")) { if(difficulty["define"] == game["difficulty_define"]) { campaign_text << " — " << difficulty["description"]; break; } } scenario = campaign_text.str(); info_stream << campaign_text.rdbuf(); // TODO: should we have this? //if(game["require_scenario"].to_bool(false)) { ADDON_REQ result = check_addon_version_compatibility(level_cfg, game); addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far //} } else { scenario = vgettext("Unknown campaign: $campaign_id", {{"campaign_id", game["mp_campaign"].str()}}); info_stream << scenario; verified = false; } } else { scenario = _("Unknown scenario"); info_stream << scenario; verified = false; } // Remove any newlines that might have been in game titles boost::replace_all(scenario, "\n", " " + font::unicode_em_dash + " "); if(reloaded) { info_stream << " — "; info_stream << _("Reloaded game"); verified = false; } if(!turn.empty()) { started = true; int index = turn.find_first_of('/'); if(index > -1) { const std::string current_turn_string = turn.substr(0, index); current_turn = lexical_cast<unsigned int>(current_turn_string); } status = _("Turn") + " " + turn; } else { started = false; if(vacant_slots > 0) { status = _n("Vacant Slot:", "Vacant Slots:", vacant_slots) + " " + game["slots"]; } } if(fog) { vision = _("Fog"); if(shroud) { vision += "/"; vision += _("Shroud"); } } else if(shroud) { vision = _("Shroud"); } else { vision = _("none"); } if(game["mp_countdown"].to_bool()) { time_limit = formatter() << game["mp_countdown_init_time"].str() << "+" << game["mp_countdown_turn_bonus"].str() << "/" << game["mp_countdown_action_bonus"].str(); } map_info = info_stream.str(); }
game_info::game_info(const config& game, const config& game_config) : mini_map() , id(game["id"]) , map_data(game["map_data"]) , name(game["name"]) , scenario() , remote_scenario(false) , map_info() , map_size_info() , era() , era_short() , gold(game["mp_village_gold"]) , support(game["mp_village_support"]) , xp(game["experience_modifier"].str() + "%") , vision() , status() , time_limit() , vacant_slots(lexical_cast_default<int>(game["slots"], 0)) // Can't use to_int() here. , current_turn(0) , reloaded(game["savegame"].to_bool()) , started(false) , fog(game["mp_fog"].to_bool()) , shroud(game["mp_shroud"].to_bool()) , observers(game["observer"].to_bool(true)) , shuffle_sides(game["shuffle_sides"].to_bool(true)) , use_map_settings(game["mp_use_map_settings"].to_bool()) , verified(true) , password_required(game["password"].to_bool()) , have_era(true) , have_all_mods(true) , has_friends(false) , has_ignored(false) , display_status(NEW) { std::string turn = game["turn"]; if(!game["mp_era"].empty()) { const config& era_cfg = game_config.find_child("era", "id", game["mp_era"]); utils::string_map symbols; symbols["era_id"] = game["mp_era"]; if(era_cfg) { era = era_cfg["name"].str(); era_short = era_cfg["short_name"].str(); if(era_short.empty()) { era_short = make_short_name(era); } } else { have_era = !game["require_era"].to_bool(true); era = vgettext("Unknown era: $era_id", symbols); era_short = "?" + make_short_name(era); verified = false; } } else { era = _("Unknown era"); era_short = "??"; verified = false; } map_info = era; if(!game.child_or_empty("modification").empty()) { BOOST_FOREACH(const config &cfg, game.child_range("modification")) { if (cfg["require_modification"].to_bool(false)) { const config &mod = game_config.find_child("modification", "id", cfg["id"]); if (!mod) { have_all_mods = false; break; } } } }
game_info::game_info(const config& game, const config& game_config) : mini_map() , id(game["id"]) , map_data(game["map_data"]) , name(game["name"]) , scenario() , remote_scenario(false) , map_info() , map_size_info() , era() , era_short() , gold(game["mp_village_gold"]) , support(game["mp_village_support"]) , xp(game["experience_modifier"].str() + "%") , vision() , status() , time_limit() , vacant_slots(lexical_cast_default<int>(game["slots"], 0)) // Can't use to_int() here. , current_turn(0) , reloaded(game["savegame"].to_bool()) , started(false) , fog(game["mp_fog"].to_bool()) , shroud(game["mp_shroud"].to_bool()) , observers(game["observer"].to_bool(true)) , shuffle_sides(game["shuffle_sides"].to_bool(true)) , use_map_settings(game["mp_use_map_settings"].to_bool()) , verified(true) , password_required(game["password"].to_bool()) , have_era(true) , have_all_mods(true) , has_friends(false) , has_ignored(false) , display_status(NEW) { std::string turn = game["turn"]; if(!game["mp_era"].empty()) { const config& era_cfg = game_config.find_child("era", "id", game["mp_era"]); utils::string_map symbols; symbols["era_id"] = game["mp_era"]; if(era_cfg) { era = era_cfg["name"].str(); era_short = era_cfg["short_name"].str(); if(era_short.empty()) { era_short = make_short_name(era); } } else { have_era = !game["require_era"].to_bool(true); era = vgettext("Unknown era: $era_id", symbols); era_short = "?" + make_short_name(era); verified = false; } } else { era = _("Unknown era"); era_short = "??"; verified = false; } map_info = era; if(!game.child_or_empty("modification").empty()) { for(const config &cfg : game.child_range("modification")) { if (cfg["require_modification"].to_bool(false)) { const config &mod = game_config.find_child("modification", "id", cfg["id"]); if (!mod) { have_all_mods = false; break; } } } } if(map_data.empty()) { map_data = filesystem::read_map(game["mp_scenario"]); } if(map_data.empty()) { map_info += " — ??×??"; } else { try { gamemap map(boost::make_shared<terrain_type_data>(game_config), map_data); // mini_map = image::getMinimap(minimap_size_, minimap_size_, map, // 0); std::ostringstream msi; msi << map.w() << utils::unicode_multiplication_sign << map.h(); map_size_info = msi.str(); map_info += " — " + map_size_info; } catch(incorrect_map_format_error& e) { ERR_CF << "illegal map: " << e.message << std::endl; verified = false; } catch(twml_exception& e) { ERR_CF << "map could not be loaded: " << e.dev_message << '\n'; verified = false; } } map_info += " "; if(!game["mp_scenario"].empty()) { // check if it's a multiplayer scenario const config* level_cfg = &game_config.find_child("multiplayer", "id", game["mp_scenario"]); if(!*level_cfg) { // check if it's a user map level_cfg = &game_config.find_child("generic_multiplayer", "id", game["mp_scenario"]); } if(*level_cfg) { scenario = (*level_cfg)["name"].str(); map_info += scenario; // reloaded games do not match the original scenario hash, // so it makes no sense to test them, they always would appear // as remote scenarios if(!reloaded) { if(const config& hashes = game_config.child("multiplayer_hashes")) { std::string hash = game["hash"]; bool hash_found = false; for(const auto & i : hashes.attribute_range()) { if(i.first == game["mp_scenario"] && i.second == hash) { hash_found = true; break; } } if(!hash_found) { remote_scenario = true; map_info += " — "; map_info += _("Remote scenario"); verified = false; } } } } else { utils::string_map symbols; symbols["scenario_id"] = game["mp_scenario"]; scenario = vgettext("Unknown scenario: $scenario_id", symbols); map_info += scenario; verified = false; } } else { scenario = _("Unknown scenario"); map_info += scenario; verified = false; } if(reloaded) { map_info += " — "; map_info += _("Reloaded game"); verified = false; } if(!turn.empty()) { started = true; int index = turn.find_first_of('/'); if(index > -1) { const std::string current_turn_string = turn.substr(0, index); current_turn = lexical_cast<unsigned int>(current_turn_string); } status = _("Turn ") + turn; } else { started = false; if(vacant_slots > 0) { status = std::string( _n("Vacant Slot:", "Vacant Slots:", vacant_slots)) + " " + game["slots"]; } } if(fog) { vision = _("Fog"); if(shroud) { vision += "/"; vision += _("Shroud"); } } else if(shroud) { vision = _("Shroud"); } else { vision = _("none"); } if(game["mp_countdown"].to_bool()) { time_limit = game["mp_countdown_init_time"].str() + "+" + game["mp_countdown_turn_bonus"].str() + "/" + game["mp_countdown_action_bonus"].str(); } else { time_limit = ""; } }