Пример #1
0
/**
 * Constructor from a config.
 */
clearer_info::clearer_info(const config & cfg) :
	underlying_id(cfg["underlying_id"].to_size_t()),
	sight_range(cfg["vision"].to_int()),
	slowed(cfg.child_or_empty("status")["slowed"].to_bool()),
	costs(cfg.child_or_empty("vision_costs"))
{
}
Пример #2
0
/**
 * Constructor from a config
 */
movetype::movetype(const config & cfg) :
	movement_(cfg.child_or_empty("movement_costs"), nullptr, &vision_),    // This is not access before initialization; the address is merely stored at this point.
	vision_(cfg.child_or_empty("vision_costs"), &movement_, &jamming_), // This is not access before initialization; the address is merely stored at this point.
	jamming_(cfg.child_or_empty("jamming_costs"), &vision_, nullptr),
	defense_(cfg.child_or_empty("defense")),
	resist_(cfg.child_or_empty("resistance")),
	flying_(cfg["flies"].to_bool(false))
{
}
Пример #3
0
/**
 * Constructor for when read from a saved config.
 * This is the reverse of to_config() and corresponds to reading [menu_item].
 * Handlers are not initialized.
 */
wml_menu_item::wml_menu_item(const std::string& id, const config & cfg) :
		item_id_(id),
		event_name_(make_item_name(id)),
		hotkey_id_(make_item_hotkey(id)),
		image_(cfg["image"].str()),
		description_(cfg["description"].t_str()),
		needs_select_(cfg["needs_select"].to_bool(false)),
		show_if_(cfg.child_or_empty("show_if"), true),
		filter_location_(cfg.child_or_empty("filter_location"), true),
		command_(cfg.child_or_empty("command")),
		default_hotkey_(cfg.child_or_empty("default_hotkey")),
		use_hotkey_(cfg["use_hotkey"].to_bool(true)),
		use_wml_menu_(cfg["use_hotkey"].str() != "only")
{
}
Пример #4
0
carryover_info::carryover_info(const config& cfg, bool from_snpashot)
	: carryover_sides_()
	, variables_(cfg.child_or_empty("variables"))
	, rng_(cfg)
	, wml_menu_items_()
	, next_scenario_(cfg["next_scenario"])
	, next_underlying_unit_id_(cfg["next_underlying_unit_id"].to_int(0))
{
	for(const config& side : cfg.child_range("side"))
	{
		if(side["lost"].to_bool(false) || !side["persistent"].to_bool(true) || side["save_id"].empty())
		{
			//this shouldn't happen outside a snpshot.
			if(!from_snpashot) {
				ERR_NG << "found invalid carryover data in saved game, lost='" << side["lost"] << "' persistent='" << side["persistent"] << "' save_id='" << side["save_id"] << "'\n";
			}
			continue;
		}
		this->carryover_sides_.emplace_back(side);
	}
	for(const config& item : cfg.child_range("menu_item"))
	{
		wml_menu_items_.push_back(new config(item));
	}
}
Пример #5
0
gamemap::gamemap(const tdata_cache& tdata, const config& level):
		tiles_(1),
		tdata_(tdata),
		villages_(),
		borderCache_(),
		terrainFrequencyCache_(),
		w_(-1),
		h_(-1),
		total_width_(0),
		total_height_(0),
		border_size_(gamemap::default_border)
{
	DBG_G << "loading map: '" << level.debug() << "'\n";

	const config& map_child = level.child_or_empty("map");

	if (map_child.empty()) {
		const std::string& map_data = level["map_data"];
		if (!map_data.empty()) {
			read(map_data);
		} else {
			w_ = 0;
			h_ = 0;
			total_width_ = 0;
			total_height_ = 0;
		}
	} else {
		read(map_child["data"], true);
	}
}
Пример #6
0
attack_type::attack_type(const config& cfg) :
	self_loc_(),
	other_loc_(),
	is_attacker_(false),
	other_attack_(nullptr),
	description_(cfg["description"].t_str()),
	id_(cfg["name"]),
	type_(cfg["type"]),
	icon_(cfg["icon"]),
	range_(cfg["range"]),
	min_range_(cfg["min_range"].to_int(1)),
	max_range_(cfg["max_range"].to_int(1)),
	damage_(cfg["damage"]),
	num_attacks_(cfg["number"]),
	attack_weight_(cfg["attack_weight"].to_double(1.0)),
	defense_weight_(cfg["defense_weight"].to_double(1.0)),
	accuracy_(cfg["accuracy"]),
	movement_used_(cfg["movement_used"].to_int(100000)),
	parry_(cfg["parry"]),
	specials_(cfg.child_or_empty("specials"))
{
	if (description_.empty())
		description_ = translation::egettext(id_.c_str());

	if(icon_.empty()){
		if (id_ != "")
			icon_ = "attacks/" + id_ + ".png";
		else
			icon_ = "attacks/blank-attack.png";
	}
}
Пример #7
0
gamemap::gamemap(const config& cfg, const config& level):
		tiles_(1),
		terrainList_(),
		tcodeToTerrain_(),
		villages_(),
		borderCache_(),
		terrainFrequencyCache_(),
		w_(-1),
		h_(-1),
		total_width_(0),
		total_height_(0),
		border_size_(gamemap::SINGLE_TILE_BORDER),
		usage_(IS_MAP)
{
	DBG_G << "loading map: '" << level.debug() << "'\n";
	const config::const_child_itors &terrains = cfg.child_range("terrain_type");
	create_terrain_maps(terrains, terrainList_, tcodeToTerrain_);

	const config& map_child = level.child_or_empty("map");

	if (map_child.empty()) {
		const std::string& map_data = level["map_data"];
		if (!map_data.empty()) {
			read(map_data);
		} else {
			w_ = 0;
			h_ = 0;
			total_width_ = 0;
			total_height_ = 0;
		}
	} else {
		read(map_child["data"], true, map_child["border_size"], map_child["usage"]);
	}
}
Пример #8
0
	shroud_clearing_action(const config& cfg)
		: route()
		, view_info(cfg.child_or_empty("unit"))
		, original_village_owner(cfg["village_owner"].to_int())
		, take_village_timebonus(cfg["village_timebonus"].to_bool())
	{
		read_locations(cfg, route);
	}
Пример #9
0
game_data::game_data(const config& level)
		: variable_set()
		, scoped_variables()
		, last_selected(map_location::null_location())
		, rng_(level)
		, variables_(level.child_or_empty("variables"))
		, phase_(INITIAL)
		, can_end_turn_(level["can_end_turn"].to_bool(true))
		, next_scenario_(level["next_scenario"])
{
}
Пример #10
0
/**
 * Note that initially we get access only to readonly context (engine is created rather early, when there's no way to move/attack.
 * We inject full ai_context later.
 */
engine_lua::engine_lua( readonly_context &context, const config &cfg )
	: engine(context,cfg)
	, code_(cfg["code"])
	, lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
		cfg["code"].str().c_str(), this))
{
	name_ = "lua";

	config data(cfg.child_or_empty("data"));
	lua_ai_context_->set_persistent_data(data);
}
Пример #11
0
/**
 * Note that initially we get access only to readonly context (engine is created rather early, when there's no way to move/attack.
 * We inject full ai_context later.
 */
engine_lua::engine_lua( readonly_context &context, const config &cfg )
	: engine(context,cfg)
	, code_(cfg["code"])
	, lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
		get_engine_code(cfg).c_str(), this))
{
	name_ = "lua";
	config data(cfg.child_or_empty("data"));

	if (lua_ai_context_) { // The context might be NULL if the config contains errors
		lua_ai_context_->set_persistent_data(data);
	}
}
Пример #12
0
turn_info::PROCESS_DATA_RESULT turn_info::process_network_data(const config& cfg,
		network::connection from, std::deque<config>& backlog, bool skip_replay)
{
	if (const config &rnd_seed = cfg.child("random_seed")) {
		rand_rng::set_seed(rnd_seed["seed"]);
		//may call a callback function, see rand_rng::set_seed_callback
	}

	if (const config &msg = cfg.child("message"))
	{
		resources::screen->add_chat_message(time(NULL), msg["sender"], msg["side"],
				msg["message"], events::chat_handler::MESSAGE_PUBLIC,
				preferences::message_bell());
	}

	if (const config &msg = cfg.child("whisper") /*&& is_observer()*/)
	{
		resources::screen->add_chat_message(time(NULL), "whisper: " + msg["sender"].str(), 0,
				msg["message"], events::chat_handler::MESSAGE_PRIVATE,
				preferences::message_bell());
	}

	BOOST_FOREACH(const config &ob, cfg.child_range("observer")) {
		resources::screen->add_observer(ob["name"]);
	}

	BOOST_FOREACH(const config &ob, cfg.child_range("observer_quit")) {
		resources::screen->remove_observer(ob["name"]);
	}

	if (cfg.child("leave_game")) {
		throw network::error("");
	}

	bool turn_end = false;

	config::const_child_itors turns = cfg.child_range("turn");
	if (turns.first != turns.second && from != network::null_connection) {
		//forward the data to other peers
		network::send_data_all_except(cfg, from);
	}

	const config& change = cfg.child_or_empty("change_controller");
	const std::string& side_drop = cfg["side_drop"].str();

	BOOST_FOREACH(const config &t, turns)
	{
		handle_turn(turn_end, t, skip_replay, backlog);
	}
Пример #13
0
carryover::carryover(const config& side)
		: add_(!side["carryover_add"].empty() ? side["carryover_add"].to_bool() : side["add"].to_bool())
		, current_player_(side["current_player"])
		, gold_(!side["carryover_gold"].empty() ? side["carryover_gold"].to_int() : side["gold"].to_int())
		// if we load it from a snapshot we need to read the recruits from "recruits" and not from "previous_recruits".
		, previous_recruits_(side.has_attribute("recruit") ? utils::set_split(side["recruit"]) :utils::set_split(side["previous_recruits"]))
		, recall_list_()
		, save_id_(side["save_id"])
		, variables_(side.child_or_empty("variables"))
{
	for(const config& u : side.child_range("unit")) {
		recall_list_.push_back(u);
		config& u_back = recall_list_.back();
		u_back.remove_attributes("side", "goto_x", "goto_y", "x", "y", "hidden");
	}
}
Пример #14
0
/**
 * Note that initially we get access only to readonly context (engine is created rather early, when there's no way to move/attack.
 * We inject full ai_context later.
 */
engine_lua::engine_lua( readonly_context &context, const config &cfg )
	: engine(context,cfg)
	, code_(get_engine_code(cfg))
	, lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
		get_engine_code(cfg).c_str(), this))
{
	name_ = "lua";
	config data(cfg.child_or_empty("data"));
	config args(cfg.child_or_empty("args"));

	if (lua_ai_context_) { // The context might be nullptr if the config contains errors
		lua_ai_context_->set_persistent_data(data);
		lua_ai_context_->set_arguments(args);
		lua_ai_context_->update_state();
	}
}
Пример #15
0
mp_game_settings::mp_game_settings(const config& cfg)
	: name(cfg["scenario"].str())
	, password()
	, hash(cfg["hash"].str())
	, mp_era(cfg["mp_era"].str())
	, mp_era_addon_id(cfg["mp_era_addon_id"].str())
	, mp_scenario(cfg["mp_scenario"].str())
	, mp_scenario_name(cfg["mp_scenario_name"].str())
	, mp_campaign(cfg["mp_campaign"].str())
	, active_mods(utils::split(cfg["active_mods"], ','))
	, side_users(utils::map_split(cfg["side_users"]))
	, show_connect(cfg["show_connect"].to_bool(true))
	, num_turns(cfg["mp_num_turns"])
	, village_gold(cfg["mp_village_gold"])
	, village_support(cfg["mp_village_support"])
	, xp_modifier(cfg["experience_modifier"].to_int(100))
	, mp_countdown_init_time(cfg["mp_countdown_init_time"])
	, mp_countdown_reservoir_time(cfg["mp_countdown_reservoir_time"])
	, mp_countdown_turn_bonus(cfg["mp_countdown_turn_bonus"])
	, mp_countdown_action_bonus(cfg["mp_countdown_action_bonus"])
	, mp_countdown(cfg["mp_countdown"].to_bool())
	, use_map_settings(cfg["mp_use_map_settings"].to_bool())
	, random_start_time(cfg["mp_random_start_time"].to_bool())
	, fog_game(cfg["mp_fog"].to_bool())
	, shroud_game(cfg["mp_shroud"].to_bool())
	, allow_observers(cfg["observer"].to_bool())
	, registered_users_only(cfg["registered_users_only"].to_bool())
	, shuffle_sides(cfg["shuffle_sides"].to_bool())
	, saved_game(cfg["savegame"].to_bool())
	, random_faction_mode(cfg["random_faction_mode"].to_enum<RANDOM_FACTION_MODE>(RANDOM_FACTION_MODE::DEFAULT))
	, options(cfg.child_or_empty("options"))
	, addons()
{
	for (const config & a : cfg.child_range("addon")) {
		if (!a["id"].empty()) {
			addons.insert(std::make_pair(a["id"].str(), addon_version_info(a)));
		}
	}
}
Пример #16
0
carryover_info::carryover_info(const config& cfg, bool from_snpashot)
	: carryover_sides_()
	, variables_(cfg.child_or_empty("variables"))
	, rng_(cfg)
	, wml_menu_items_()
	, next_scenario_(cfg["next_scenario"])
	, next_underlying_unit_id_(cfg["next_underlying_unit_id"].to_int(0))
{
	for(const config& side : cfg.child_range("side"))
	{
		if(side["lost"].to_bool(false) || !side["persistent"].to_bool(true))
		{
			//this shouldnt happen outside a snpshot.
			assert(from_snpashot);
			continue;
		}
		this->carryover_sides_.push_back(carryover(side));
	}
	for(const config& item : cfg.child_range("menu_item"))
	{
		wml_menu_items_.push_back(new config(item));
	}
}
Пример #17
0
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;
				}
			}
		}
	}
Пример #18
0
	shroud_clearing_action(const config& cfg)
		: route()
		, view_info(cfg.child_or_empty("unit"))
	{
		read_locations(cfg, route);
	}
Пример #19
0
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();
}
Пример #20
0
std::string default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center,
                                 size_t iterations, size_t hill_size,
						         size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles,
								 std::map<map_location,std::string>* labels, const config& cfg)
{
	log_scope("map generation");

	// Odd widths are nasty
	VALIDATE(is_even(width), _("Random maps with an odd width aren't supported."));

	int ticks = SDL_GetTicks();

	// Find out what the 'flatland' on this map is, i.e. grassland.
	std::string flatland = cfg["default_flatland"];
	if(flatland == "") {
		flatland = t_translation::write_terrain_code(t_translation::GRASS_LAND);
	}

	const t_translation::t_terrain grassland = t_translation::read_terrain_code(flatland);

	// We want to generate a map that is 9 times bigger
	// than the actual size desired.
	// Only the middle part of the map will be used,
	// but the rest is so that the map we end up using
	// can have a context (e.g. rivers flowing from
	// out of the map into the map, same for roads, etc.)
	width *= 3;
	height *= 3;

	LOG_NG << "generating height map...\n";
	// Generate the height of everything.
	const height_map heights = generate_height_map(width,height,iterations,hill_size,island_size,island_off_center);
	LOG_NG << "done generating height map...\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	config naming = cfg.child_or_empty("naming");
	// HACK: dummy names to satisfy unit_race requirements
	naming["id"] = "village_naming";
	naming["plural_name"] = "villages";

	// Make a dummy race for generating names
	const unit_race name_generator(naming);

	std::vector<terrain_height_mapper> height_conversion;

	BOOST_FOREACH(const config &h, cfg.child_range("height")) {
		height_conversion.push_back(terrain_height_mapper(h));
	}

	terrain_map terrain(width, t_translation::t_list(height, grassland));
	size_t x, y;
	for(x = 0; x != heights.size(); ++x) {
		for(y = 0; y != heights[x].size(); ++y) {
			for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin();
			    i != height_conversion.end(); ++i) {
				if(i->convert_terrain(heights[x][y])) {
					terrain[x][y] = i->convert_to();
					break;
				}
			}
		}
	}

	std::map<int, t_translation::coordinate> starting_positions;
	LOG_NG << output_map(terrain, starting_positions);
	LOG_NG << "placed land forms\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	// Now that we have our basic set of flatland/hills/mountains/water,
	// we can place lakes and rivers on the map.
	// All rivers are sourced at a lake.
	// Lakes must be in high land - at least 'min_lake_height'.
	// (Note that terrain below a certain altitude may be made
	// into bodies of water in the code above - i.e. 'sea',
	// but these are not considered 'lakes', because
	// they are not sources of rivers).
	//
	// We attempt to place 'max_lakes' lakes.
	// Each lake will be placed at a random location,
	// if that random location meets the minimum terrain requirements for a lake.
	// We will also attempt to source a river from each lake.
	std::set<location> lake_locs;

	std::map<location, std::string> river_names, lake_names, road_names, bridge_names, mountain_names, forest_names, swamp_names;

	const size_t nlakes = max_lakes > 0 ? (rand()%max_lakes) : 0;
	for(size_t lake = 0; lake != nlakes; ++lake) {
		for(int tries = 0; tries != 100; ++tries) {
			const int x = rand()%width;
			const int y = rand()%height;
			if (heights[x][y] > cfg["min_lake_height"].to_int()) {
				std::vector<location> river = generate_river(heights,
					terrain, x, y, cfg["river_frequency"]);

				if(river.empty() == false && labels != NULL) {
					std::string base_name;
					LOG_NG << "generating name for river...\n";
					const std::string& name = generate_name(name_generator,"river_name",&base_name);
					LOG_NG << "named river '" << name << "'\n";
					size_t name_frequency = 20;
					for(std::vector<location>::const_iterator r = river.begin(); r != river.end(); ++r) {

						const map_location loc(r->x-width/3,r->y-height/3);

						if(((r - river.begin())%name_frequency) == name_frequency/2) {
							labels->insert(std::pair<map_location,std::string>(loc,name));
						}

						river_names.insert(std::pair<location,std::string>(loc,base_name));
					}

					LOG_NG << "put down river name...\n";
				}

				LOG_NG << "generating lake...\n";
				std::set<location> locs;
				bool res = generate_lake(terrain, x, y, cfg["lake_size"], locs);
				if(res && labels != NULL) {
					bool touches_other_lake = false;

					std::string base_name;
					const std::string& name = generate_name(name_generator,"lake_name",&base_name);

					std::set<location>::const_iterator i;

					// Only generate a name if the lake hasn't touched any other lakes,
					// so that we don't end up with one big lake with multiple names.
					for(i = locs.begin(); i != locs.end(); ++i) {
						if(lake_locs.count(*i) != 0) {
							touches_other_lake = true;

							// Reassign the name of this lake to be the same as the other lake
							const location loc(i->x-width/3,i->y-height/3);
							const std::map<location,std::string>::const_iterator other_name = lake_names.find(loc);
							if(other_name != lake_names.end()) {
								base_name = other_name->second;
							}
						}

						lake_locs.insert(*i);
					}

					if(!touches_other_lake) {
						const map_location loc(x-width/3,y-height/3);
						labels->erase(loc);
						labels->insert(std::pair<map_location,std::string>(loc,name));
					}

					for(i = locs.begin(); i != locs.end(); ++i) {
						const location loc(i->x-width/3,i->y-height/3);
						lake_names.insert(std::pair<location, std::string>(loc, base_name));
					}
				}

				break;
			}
		}
	}

	LOG_NG << "done generating rivers...\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	const size_t default_dimensions = 40*40*9;

	/*
	 * Convert grassland terrain to other types of flat terrain.
	 *
	 * We generate a 'temperature map' which uses the height generation
	 * algorithm to generate the temperature levels all over the map.  Then we
	 * can use a combination of height and terrain to divide terrain up into
	 * more interesting types than the default.
	 */
	const height_map temperature_map = generate_height_map(width,height,
		cfg["temperature_iterations"].to_int() * width * height / default_dimensions,
		cfg["temperature_size"], 0, 0);

	LOG_NG << "generated temperature map...\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	std::vector<terrain_converter> converters;
	BOOST_FOREACH(const config &cv, cfg.child_range("convert")) {
		converters.push_back(terrain_converter(cv));
	}

	LOG_NG << "created terrain converters\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();


	// Iterate over every flatland tile, and determine
	// what type of flatland it is, based on our [convert] tags.
	for(x = 0; x != width; ++x) {
		for(y = 0; y != height; ++y) {
			for(std::vector<terrain_converter>::const_iterator i = converters.begin(); i != converters.end(); ++i) {
				if(i->convert_terrain(terrain[x][y],heights[x][y],temperature_map[x][y])) {
					terrain[x][y] = i->convert_to();
					break;
				}
			}
		}
	}

	LOG_NG << "placing villages...\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	/*
	 * Place villages in a 'grid', to make placing fair, but with villages
	 * displaced from their position according to terrain and randomness, to
	 * add some variety.
	 */
	std::set<location> villages;

	LOG_NG << "placing castles...\n";

	/** Try to find configuration for castles. */
	const config &castle_config = cfg.child("castle");
	if (!castle_config) {
		LOG_NG << "Could not find castle configuration\n";
		return std::string();
	}

	/*
	 * Castle configuration tag contains a 'valid_terrain' attribute which is a
	 * list of terrains that the castle may appear on.
	 */
	const t_translation::t_list list =
		t_translation::read_list(castle_config["valid_terrain"]);

	const is_valid_terrain terrain_tester(terrain, list);

	/*
	 * Attempt to place castles at random.
	 *
	 * Once we have placed castles, we run a sanity check to make sure that the
	 * castles are well-placed.  If the castles are not well-placed, we try
	 * again.  Definition of 'well-placed' is if no two castles are closer than
	 * 'min_distance' hexes from each other, and the castles appear on a
	 * terrain listed in 'valid_terrain'.
	 */
	std::vector<location> castles;
	std::set<location> failed_locs;

	for(size_t player = 0; player != nplayers; ++player) {
		LOG_NG << "placing castle for " << player << "\n";
		log_scope("placing castle");
		const int min_x = width/3 + 3;
		const int min_y = height/3 + 3;
		const int max_x = (width/3)*2 - 4;
		const int max_y = (height/3)*2 - 4;
		int min_distance = castle_config["min_distance"];

		location best_loc;
		int best_ranking = 0;
		for(int x = min_x; x != max_x; ++x) {
			for(int y = min_y; y != max_y; ++y) {
				const location loc(x,y);
				if(failed_locs.count(loc)) {
					continue;
				}

				const int ranking = rank_castle_location(x,y,terrain_tester,min_x,max_x,min_y,max_y,min_distance,castles,best_ranking);
				if(ranking <= 0) {
					failed_locs.insert(loc);
				}

				if(ranking > best_ranking) {
					best_ranking = ranking;
					best_loc = loc;
				}
			}
		}
		if(best_ranking == 0) {
			ERR_NG << "No castle location found, aborting.\n";
			std::string error = _("No valid castle location found. Too many or too few mountain hexes? (please check the 'max hill size' parameter)");
			throw mapgen_exception(error);
		}
		assert(std::find(castles.begin(), castles.end(), best_loc) == castles.end());
		castles.push_back(best_loc);
		// Make sure the location can't get a second castle.
		failed_locs.insert(best_loc);
	}

	LOG_NG << "placing roads...\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	// Place roads.
	// We select two tiles at random locations on the borders
	// of the map, and try to build roads between them.
	int nroads = cfg["roads"];
	if(roads_between_castles) {
		nroads += castles.size()*castles.size();
	}

	std::set<location> bridges;

	road_path_calculator calc(terrain,cfg);
	for (int road = 0; road != nroads; ++road) {
		log_scope("creating road");

		/*
		 * We want the locations to be on the portion of the map we're actually
		 * going to use, since roads on other parts of the map won't have any
		 * influence, and doing it like this will be quicker.
		 */
		location src = random_point_at_side(width/3 + 2,height/3 + 2);
		location dst = random_point_at_side(width/3 + 2,height/3 + 2);

		src.x += width/3 - 1;
		src.y += height/3 - 1;
		dst.x += width/3 - 1;
		dst.y += height/3 - 1;

		if (roads_between_castles && road < int(castles.size() * castles.size())) {
			const size_t src_castle = road/castles.size();
			const size_t dst_castle = road%castles.size();
			if(src_castle >= dst_castle) {
				continue;
			}

			src = castles[src_castle];
			dst = castles[dst_castle];
		}

		// If the road isn't very interesting (on the same border), don't draw it.
		else if(src.x == dst.x || src.y == dst.y) {
			continue;
		}

		if (calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) {
			continue;
		}

		// Search a path out for the road
		pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height);

		std::string road_base_name;
		const std::string& name = generate_name(name_generator, "road_name", &road_base_name);
		const int name_frequency = 20;
		int name_count = 0;

		bool on_bridge = false;

		// Draw the road.
		// If the search failed, rt.steps will simply be empty.
		for(std::vector<location>::const_iterator step = rt.steps.begin();
				step != rt.steps.end(); ++step) {

			const int x = step->x;
			const int y = step->y;

			if(x < 0 || y < 0 || x >= static_cast<long>(width) ||
					y >= static_cast<long>(height)) {

				continue;
			}

			// Find the configuration which tells us
			// what to convert this tile to, to make it into a road.
			if (const config &child = cfg.find_child("road_cost", "terrain",
					t_translation::write_terrain_code(terrain[x][y])))
			{
				// Convert to bridge means that we want to convert
				// depending upon the direction the road is going.
				// Typically it will be in a format like,
				// convert_to_bridge=\,|,/
				// '|' will be used if the road is going north-south
				// '/' will be used if the road is going south west-north east
				// '\' will be used if the road is going south east-north west
				// The terrain will be left unchanged otherwise
				// (if there is no clear direction).
				const std::string &convert_to_bridge = child["convert_to_bridge"];
				if(convert_to_bridge.empty() == false) {
					if(step == rt.steps.begin() || step+1 == rt.steps.end())
						continue;

					const location& last = *(step-1);
					const location& next = *(step+1);

					location adj[6];
					get_adjacent_tiles(*step,adj);

					int direction = -1;

					// If we are going north-south
					if((last == adj[0] && next == adj[3]) || (last == adj[3] && next == adj[0])) {
						direction = 0;
					}

					// If we are going south west-north east
					else if((last == adj[1] && next == adj[4]) || (last == adj[4] && next == adj[1])) {
						direction = 1;
					}

					// If we are going south east-north west
					else if((last == adj[2] && next == adj[5]) || (last == adj[5] && next == adj[2])) {
						direction = 2;
					}

					if(labels != NULL && on_bridge == false) {
						on_bridge = true;
						std::string bridge_base_name;
						const std::string& name = generate_name(name_generator, "bridge_name", &bridge_base_name);
						const location loc(x - width / 3, y-height/3);
						labels->insert(std::pair<map_location,std::string>(loc,name));
						bridge_names.insert(std::pair<location,std::string>(loc, bridge_base_name)); //add to use for village naming
						bridges.insert(loc);
					}

					if(direction != -1) {
						const std::vector<std::string> items = utils::split(convert_to_bridge);
						if(size_t(direction) < items.size() && items[direction].empty() == false) {
							terrain[x][y] = t_translation::read_terrain_code(items[direction]);
						}

						continue;
					}
				} else {
					on_bridge = false;
				}

				// Just a plain terrain substitution for a road
				const std::string &convert_to = child["convert_to"];
				if(convert_to.empty() == false) {
					const t_translation::t_terrain letter =
						t_translation::read_terrain_code(convert_to);
					if(labels != NULL && terrain[x][y] != letter && name_count++ == name_frequency && on_bridge == false) {
						labels->insert(std::pair<map_location,std::string>(map_location(x-width/3,y-height/3),name));
						name_count = 0;
					}

					terrain[x][y] = letter;
					const location loc(x - width / 3, y - height / 3); //add to use for village naming
					road_names.insert(std::pair<location,std::string>(loc, road_base_name));
				}
			}
		}

		LOG_NG << "looked at " << calc.calls << " locations\n";
	}


	// Now that road drawing is done, we can plonk down the castles.
	for(std::vector<location>::const_iterator c = castles.begin(); c != castles.end(); ++c) {
		if(c->valid() == false) {
			continue;
		}

		const int x = c->x;
		const int y = c->y;
		const int player = c - castles.begin() + 1;
		const struct t_translation::coordinate coord(x, y);
		starting_positions.insert(std::pair<int, t_translation::coordinate>(player, coord));
		terrain[x][y] = t_translation::HUMAN_KEEP;

		const int castles[13][2] = {
		  {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1},
		  {-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2}
		};

		for (size_t i = 0; i < castle_size - 1; i++) {
		  terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE;
		}

		// Remove all labels under the castle tiles
		if(labels != NULL) {
		  labels->erase(location(x-width/3,y-height/3));
		  for (size_t i = 0; i < castle_size - 1; i++) {
		    labels->erase(location(x+castles[i][0]-width/3,
					   y+castles[i][1]-height/3));
		  }

		}

	}

	LOG_NG << "placed castles\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	/*Random naming for landforms: mountains, forests, swamps, hills
	 *we name these now that everything else is placed (as e.g., placing
	 * roads could split a forest)
	 */
	for (x = width / 3; x < (width / 3)*2; x++) {
		for (y = height / 3; y < (height / 3) * 2;y++) {
		//check the terrain of the tile
		const location loc(x - width / 3, y - height / 3);
		const t_translation::t_terrain terr = terrain[x][y];
		std::string name, base_name;
		std::set<std::string> used_names;
		if (t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) {
			//name every 15th mountain
			if ((rand()%15) == 0) {
				for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
					name = generate_name(name_generator, "mountain_name", &base_name);
				}
				labels->insert(std::pair<map_location, std::string>(loc, name));
				mountain_names.insert(std::pair<location, std::string>(loc, base_name));
			}
		}
		else if (t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) {
			//if the forest tile is not named yet, name it
			const std::map<location, std::string>::const_iterator forest_name = forest_names.find(loc);
			if(forest_name == forest_names.end()) {
				for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
					name = generate_name(name_generator, "forest_name", &base_name);
				}
				forest_names.insert(std::pair<location, std::string>(loc, base_name));
				// name all connected forest tiles accordingly
				flood_name(loc, base_name, forest_names, t_translation::ALL_FORESTS, terrain, width, height, 0, labels, name);
			}
		}
		else if (t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) {
			//if the swamp tile is not named yet, name it
			const std::map<location, std::string>::const_iterator swamp_name = swamp_names.find(loc);
			if(swamp_name == swamp_names.end()) {
				for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
					name = generate_name(name_generator, "swamp_name", &base_name);
				}
				swamp_names.insert(std::pair<location, std::string>(loc, base_name));
				// name all connected swamp tiles accordingly
				flood_name(loc, base_name, swamp_names, t_translation::ALL_SWAMPS, terrain, width, height, 0, labels, name);
			}
		}

		}
	}

	if (nvillages > 0)
	{
		config naming_cfg = cfg.child_or_empty("village_naming");
		// HACK: dummy names to satisfy unit_race requirements
		naming_cfg["id"] = "village_naming";
		naming_cfg["plural_name"] = "villages";

		const unit_race village_names_generator(naming_cfg);

		// First we work out the size of the x and y distance between villages
		const size_t tiles_per_village = ((width*height)/9)/nvillages;
		size_t village_x = 1, village_y = 1;

		// Alternate between incrementing the x and y value.
		// When they are high enough to equal or exceed the tiles_per_village,
		// then we have them to the value we want them at.
		while(village_x*village_y < tiles_per_village) {
			if(village_x < village_y) {
				++village_x;
			} else {
				++village_y;
			}
		}

		std::set<std::string> used_names;
		tcode_list_cache adj_liked_cache;

		for(size_t vx = 0; vx < width; vx += village_x) {
			LOG_NG << "village at " << vx << "\n";
			for(size_t vy = rand()%village_y; vy < height; vy += village_y) {

				const size_t add_x = rand()%3;
				const size_t add_y = rand()%3;
				const size_t x = (vx + add_x) - 1;
				const size_t y = (vy + add_y) - 1;

				const map_location res = place_village(terrain,x,y,2,cfg,adj_liked_cache);

				if(res.x >= static_cast<long>(width) / 3 &&
						res.x  < static_cast<long>(width * 2) / 3 &&
						res.y >= static_cast<long>(height) / 3 &&
						res.y  < static_cast<long>(height * 2) / 3) {

					const std::string str =
						t_translation::write_terrain_code(terrain[res.x][res.y]);
					if (const config &child = cfg.find_child("village", "terrain", str))
					{
						const std::string &convert_to = child["convert_to"];
						if(convert_to != "") {
							terrain[res.x][res.y] =
								t_translation::read_terrain_code(convert_to);

							villages.insert(res);

							if(labels != NULL && naming_cfg.empty() == false) {
								const map_location loc(res.x-width/3,res.y-height/3);

								map_location adj[6];
								get_adjacent_tiles(loc,adj);

								std::string name_type = "village_name";
								const t_translation::t_list
									field    = t_translation::t_list(1, t_translation::GRASS_LAND),
									forest   = t_translation::t_list(1, t_translation::FOREST),
									mountain = t_translation::t_list(1, t_translation::MOUNTAIN),
									hill     = t_translation::t_list(1, t_translation::HILL);

								size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0;

								utils::string_map symbols;

								size_t n;
								for(n = 0; n != 6; ++n) {
									const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]);
									if(road_name != road_names.end()) {
										symbols["road"] = road_name->second;
										name_type = "village_name_road";
										break;
									}

									const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]);
									if(river_name != river_names.end()) {
										symbols["river"] = river_name->second;
										name_type = "village_name_river";

										const std::map<location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]);
										if(bridge_name != bridge_names.end()) {
										//we should always end up here, since if there is an adjacent bridge, there has to be an adjacent river too
										symbols["bridge"] = bridge_name->second;
										name_type = "village_name_river_bridge";
										}

										break;
									}

									const std::map<location,std::string>::const_iterator forest_name = forest_names.find(adj[n]);
									if(forest_name != forest_names.end()) {
										symbols["forest"] = forest_name->second;
										name_type = "village_name_forest";
										break;
									}

									const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]);
									if(lake_name != lake_names.end()) {
										symbols["lake"] = lake_name->second;
										name_type = "village_name_lake";
										break;
									}

									const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]);
									if(mountain_name != mountain_names.end()) {
										symbols["mountain"] = mountain_name->second;
										name_type = "village_name_mountain";
										break;
									}

									const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]);
									if(swamp_name != swamp_names.end()) {
										symbols["swamp"] = swamp_name->second;
										name_type = "village_name_swamp";
										break;
									}

									const t_translation::t_terrain terr =
										terrain[adj[n].x+width/3][adj[n].y+height/3];

									if(std::count(field.begin(),field.end(),terr) > 0) {
										++field_count;
									} else if(std::count(forest.begin(),forest.end(),terr) > 0) {
										++forest_count;
									} else if(std::count(hill.begin(),hill.end(),terr) > 0) {
										++hill_count;
									} else if(std::count(mountain.begin(),mountain.end(),terr) > 0) {
										++mountain_count;
									}
								}

								if(n == 6) {
									if(field_count == 6) {
										name_type = "village_name_grassland";
									} else if(forest_count >= 2) {
										name_type = "village_name_forest";
									} else if(mountain_count >= 1) {
										name_type = "village_name_mountain_anonymous";
									} else if(hill_count >= 2) {
										name_type = "village_name_hill";
									}
								}

								std::string name;
								for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) {
									name = generate_name(village_names_generator,name_type,NULL,&symbols);
								}

								used_names.insert(name);
								labels->insert(std::pair<map_location,std::string>(loc,name));
							}
						}
					}
				}
			}
		}
	}

	LOG_NG << "placed villages\n";
	LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks();

	return output_map(terrain, starting_positions);
}
Пример #21
0
/*WIKI
 * @page = GUIToolkitWML
 * @order = 1_window
 * @begin{parent}{name=gui/window/}
 * == Resolution ==
 * @begin{tag}{name="resolution"}{min="0"}{max="-1"}
 * @begin{table}{config}
 * window_width & unsigned & 0 &   Width of the application window. $
 * window_height & unsigned & 0 &  Height of the application window. $
 *
 *
 * automatic_placement & bool & true &
 *     Automatically calculate the best size for the window and place it. If
 *     automatically placed ''vertical_placement'' and ''horizontal_placement''
 *     can be used to modify the final placement. If not automatically placed
 *     the ''width'' and ''height'' are mandatory. $
 *
 *
 * x & f_unsigned & 0 &            X coordinate of the window to show. $
 * y & f_unsigned & 0 &            Y coordinate of the window to show. $
 * width & f_unsigned & 0 &        Width of the window to show. $
 * height & f_unsigned & 0 &       Height of the window to show. $
 *
 * reevaluate_best_size & f_bool & false &
 *     The foo $
 *
 * functions & function & "" &
 *     The function definitions s available for the formula fields in window. $
 *
 * vertical_placement & v_align & "" &
 *     The vertical placement of the window. $
 *
 * horizontal_placement & h_align & "" &
 *     The horizontal placement of the window. $
 *
 *
 * maximum_width & unsigned & 0 &
 *     The maximum width of the window (only used for automatic placement). $
 *
 * maximum_height & unsigned & 0 &
 *     The maximum height of the window (only used for automatic placement). $
 *
 *
 * click_dismiss & bool & false &
 *     Does the window need click dismiss behavior? Click dismiss behavior
 *     means that any mouse click will close the dialog. Note certain widgets
 *     will automatically disable this behavior since they need to process the
 *     clicks as well, for example buttons do need a click and a misclick on
 *     button shouldn't close the dialog. NOTE with some widgets this behavior
 *     depends on their contents (like scrolling labels) so the behavior might
 *     get changed depending on the data in the dialog. NOTE the default
 *     behavior might be changed since it will be disabled when can't be used
 *     due to widgets which use the mouse, including buttons, so it might be
 *     wise to set the behavior explicitly when not wanted and no mouse using
 *     widgets are available. This means enter, escape or an external source
 *     needs to be used to close the dialog (which is valid). $
 *
 *
 * definition & string & "default" &
 *     Definition of the window which we want to show. $
 *
 *
 * linked_group & sections & [] &  A group of linked widget sections. $
 *
 *
 * tooltip & section & &
 *     Information regarding the tooltip for this window. $
 *
 * helptip & section & &
 *     Information regarding the helptip for this window. $
 *
 *
 * grid & grid & &                 The grid with the widgets to show. $
 * @end{table}
 * @begin{tag}{name="linked_group"}{min=0}{max=-1}
 * A linked_group section has the following fields:
 * @begin{table}{config}
 *     id & string & &               The unique id of the group (unique in this
 *                                   window). $
 *     fixed_width & bool & false &  Should widget in this group have the same
 *                                   width. $
 *     fixed_height & bool & false & Should widget in this group have the same
 *                                   height. $
 * @end{table}
 * @end{tag}{name="linked_group"}
 * A linked group needs to have at least one size fixed.
 * @begin{tag}{name="tooltip"}{min=0}{max=1}
 * A tooltip and helptip section have the following field:
 * @begin{table}{config}
 *     id & string & &               The id of the tip to show.
 * Note more fields will probably be added later on.
 * @end{table}{config}
 * @end{tag}{name=tooltip}
 * @begin{tag}{name="foreground"}{min=0}{max=1}
 * @end{tag}{name="foreground"}
 * @begin{tag}{name="background"}{min=0}{max=1}
 * @end{tag}{name="background"}
 * @end{tag}{name="resolution"}
 * @end{parent}{name=gui/window/}
 * @begin{parent}{name=gui/window/resolution/}
 * @begin{tag}{name="helptip"}{min=0}{max=1}{super="gui/window/resolution/tooltip"}
 * @end{tag}{name="helptip"}
 * @end{parent}{name=gui/window/resolution/}
 */
twindow_builder::tresolution::tresolution(const config& cfg)
	: window_width(cfg["window_width"])
	, window_height(cfg["window_height"])
	, automatic_placement(cfg["automatic_placement"].to_bool(true))
	, x(cfg["x"])
	, y(cfg["y"])
	, width(cfg["width"])
	, height(cfg["height"])
	, reevaluate_best_size(cfg["reevaluate_best_size"])
	, functions()
	, vertical_placement(implementation::get_v_align(cfg["vertical_placement"]))
	, horizontal_placement(
			  implementation::get_h_align(cfg["horizontal_placement"]))
	, maximum_width(cfg["maximum_width"])
	, maximum_height(cfg["maximum_height"])
	, click_dismiss(cfg["click_dismiss"].to_bool())
	, definition(cfg["definition"])
	, linked_groups()
	, tooltip(cfg.child_or_empty("tooltip"), "tooltip")
	, helptip(cfg.child_or_empty("helptip"), "helptip")
	, grid(0)
{
	if(!cfg["functions"].empty()) {
		game_logic::formula(cfg["functions"], &functions).evaluate();
	}

	const config& c = cfg.child("grid");

	VALIDATE(c, _("No grid defined."));

	grid = new tbuilder_grid(c);

	if(!automatic_placement) {
		VALIDATE(width.has_formula() || width(),
				 missing_mandatory_wml_key("resolution", "width"));
		VALIDATE(height.has_formula() || height(),
				 missing_mandatory_wml_key("resolution", "height"));
	}

	DBG_GUI_P << "Window builder: parsing resolution " << window_width << ','
			  << window_height << '\n';

	if(definition.empty()) {
		definition = "default";
	}

	for(const auto & lg : cfg.child_range("linked_group"))
	{
		tlinked_group linked_group;
		linked_group.id = lg["id"].str();
		linked_group.fixed_width = lg["fixed_width"].to_bool();
		linked_group.fixed_height = lg["fixed_height"].to_bool();

		VALIDATE(!linked_group.id.empty(),
				 missing_mandatory_wml_key("linked_group", "id"));

		if(!(linked_group.fixed_width || linked_group.fixed_height)) {
			utils::string_map symbols;
			symbols["id"] = linked_group.id;
			t_string msg
					= vgettext("Linked '$id' group needs a 'fixed_width' or "
							   "'fixed_height' key.",
							   symbols);

			VALIDATE(false, msg);
		}

		linked_groups.push_back(linked_group);
	}
}
Пример #22
0
	/**
	 * @todo This might not be 100% correct, but at the moment
	 * it is not possible to show the fog and shroud per player.
	 * This might change in the future.
	 * NOTE when 'load game' is selected there are no sides.
	 */
	const config& side_cfg() const
	{
		return initial_->child_or_empty("side");
	}
Пример #23
0
	lua_stage_wrapper( ai_context &context, const config &cfg, lua_ai_context &lua_ai_ctx )
		: stage(context,cfg),action_handler_(),code_(cfg["code"]),serialized_evaluation_state_(cfg.child_or_empty("args"))
	{
		action_handler_ =  std::shared_ptr<lua_ai_action_handler>(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(),lua_ai_ctx));
	}
Пример #24
0
void team::team_info::read(const config& cfg)
{
	gold = cfg["gold"];
	income = cfg["income"];
	team_name = cfg["team_name"].str();
	user_team_name = cfg["user_team_name"];
	side_name = cfg["side_name"];
	faction = cfg["faction"].str();
	faction_name = cfg["faction_name"];
	save_id = cfg["save_id"].str();
	current_player = cfg["current_player"].str();
	countdown_time = cfg["countdown_time"].str();
	action_bonus_count = cfg["action_bonus_count"];
	flag = cfg["flag"].str();
	flag_icon = cfg["flag_icon"].str();
	id = cfg["id"].str();
	scroll_to_leader = cfg["scroll_to_leader"].to_bool(true);
	objectives = cfg["objectives"];
	objectives_changed = cfg["objectives_changed"].to_bool();
	disallow_observers = cfg["disallow_observers"].to_bool();
	allow_player = cfg["allow_player"].to_bool(true);
	chose_random = cfg["chose_random"].to_bool(false);
	no_leader = cfg["no_leader"].to_bool();
	defeat_condition = cfg["defeat_condition"].to_enum<team::DEFEAT_CONDITION>(team::DEFEAT_CONDITION::NO_LEADER);
	lost = cfg["lost"].to_bool(false);
	hidden = cfg["hidden"].to_bool();
	no_turn_confirmation = cfg["suppress_end_turn_confirmation"].to_bool();
	side = cfg["side"].to_int(1);
	carryover_percentage = cfg["carryover_percentage"].to_int(game_config::gold_carryover_percentage);
	carryover_add = cfg["carryover_add"].to_bool(false);
	carryover_bonus = cfg["carryover_bonus"].to_double(1);
	carryover_gold = cfg["carryover_gold"].to_int(0);
	variables = cfg.child_or_empty("variables");
	is_local = cfg["is_local"].to_bool(true);

	color = get_side_color_id_from_config(cfg);

	// If starting new scenario override settings from [ai] tags
	if(!user_team_name.translatable())
		user_team_name = t_string::from_serialized(user_team_name);

	display* disp = display::get_singleton();

	//
	// FIXME: the display isn't constructed at this point when launching a game,
	// but we still want to add the ai config. On the other hand, when creating
	// a scenario in the editor, the display IS constructed, but there's no AI
	// manager. All of which leads to this awkward conditional. We really should
	// figure out a better one...
	//
	// --vultraz, 2018-01-26
	//
	if(!disp || !disp->in_editor()) {
		if(cfg.has_attribute("ai_config")) {
			ai::manager::get_singleton().add_ai_for_side_from_file(side, cfg["ai_config"], true);
		} else {
			ai::manager::get_singleton().add_ai_for_side_from_config(side, cfg, true);
		}
	}

	std::vector<std::string> recruits = utils::split(cfg["recruit"]);
	can_recruit.insert(recruits.begin(), recruits.end());

	// at the start of a scenario "start_gold" is not set, we need to take the
	// value from the gold setting (or fall back to the gold default)
	if(!cfg["start_gold"].empty()) {
		start_gold = cfg["start_gold"];
	} else if(!cfg["gold"].empty()) {
		start_gold = gold;
	} else {
		start_gold = default_team_gold_;
	}

	if(team_name.empty()) {
		team_name = cfg["side"].str();
	}

	if(save_id.empty()) {
		save_id = id;
	}

	income_per_village = cfg["village_gold"].to_int(game_config::village_income);
	recall_cost = cfg["recall_cost"].to_int(game_config::recall_cost);

	const std::string& village_support = cfg["village_support"];
	if(village_support.empty()) {
		support_per_village = game_config::village_support;
	} else {
		support_per_village = lexical_cast_default<int>(village_support, game_config::village_support);
	}

	controller = team::CONTROLLER::AI;
	controller.parse(cfg["controller"].str());

	// TODO: Why do we read disallow observers differently when controller is empty?
	if(controller == CONTROLLER::EMPTY) {
		disallow_observers = cfg["disallow_observers"].to_bool(true);
	}

	// override persistence flag if it is explicitly defined in the config
	// by default, persistence of a team is set depending on the controller
	persistent = cfg["persistent"].to_bool(this->controller == CONTROLLER::HUMAN);

	//========================================================
	// END OF MESSY CODE

	// Share_view and share_maps can't both be enabled,
	// so share_view overrides share_maps.
	share_vision = cfg["share_vision"].to_enum<team::SHARE_VISION>(team::SHARE_VISION::ALL);
	handle_legacy_share_vision(cfg);

	LOG_NG << "team_info::team_info(...): team_name: " << team_name << ", share_vision: " << share_vision << ".\n";
}
	static ministage cfg_to_value(const config &cfg)
	{
		return ministage(cfg.child_or_empty("value"));
	}
	static config cfg_to_value(const config &cfg)
	{
		return cfg.child_or_empty("value");
	}
Пример #27
0
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 = "";
	}
}
Пример #28
0
engine_fai::engine_fai( readonly_context &context, const config &cfg )
	: engine(context,cfg), formula_ai_(context,cfg.child_or_empty("formula_ai"))
{
	name_ = "fai";
	formula_ai_.on_create();
}
Пример #29
0
	lua_candidate_action_wrapper_base( rca_context &context, const config &cfg)
		: candidate_action(context, cfg),evaluation_action_handler_(),execution_action_handler_(),serialized_evaluation_state_(cfg.child_or_empty("args"))
	{
		// do nothing
	}