Exemplo n.º 1
0
void addons_client::send_request(const config& request, config& response)
{
	check_connected();

	response.clear();
	this->conn_->transfer(request, response);
}
	static void cfg_to_value(const config &cfg, config &value)
	{
		if (const config &v = cfg.child("value")) {
			value = v;
		} else {
			value.clear();
		}
	}
/** Read the file with the tips-of-the-day. */
void read_tips_of_day(config& tips_of_day)
{
	tips_of_day.clear();
	LOG_CF << "Loading tips of day\n";
	try {
		scoped_istream stream = preprocess_file(get_wml_location("hardwired/tips.cfg"));
		read(tips_of_day, *stream);
	} catch(config::error&) {
		ERR_CF << "Could not read data/hardwired/tips.cfg\n";
	}

	//We shuffle the tips after each initial loading.
	config::const_child_itors itors = tips_of_day.child_range("tip");
	if (itors.first != itors.second ) {
		std::vector<config> tips(itors.first, itors.second);
		std::random_shuffle(tips.begin(), tips.end());
		tips_of_day.clear();
		foreach (const config &tip, tips) {
			tips_of_day.add_child("tip", tip);
		}
Exemplo n.º 4
0
game_display* game_display::create_dummy_display(CVideo& video)
{
	static unit_map dummy_umap;
	static config dummy_cfg;
	static gamemap dummy_map(dummy_cfg, "");
	static gamestatus dummy_status(dummy_cfg, 0);
	static std::vector<team> dummy_teams;
	dummy_cfg.clear();
	return new game_display(dummy_umap, video, dummy_map, dummy_status,
			dummy_teams, dummy_cfg, dummy_cfg, dummy_cfg);
}
Exemplo n.º 5
0
/** Read the file with the tips-of-the-day. */
static void read_tips_of_day(config& tips_of_day)
{
	loadscreen::global_loadscreen->disable_increments = true;
	
	tips_of_day.clear();

#ifdef FREE_VERSION
	std::string filename = get_cache_dir() + "/tips_free";
#else
	std::string filename = get_cache_dir() + "/tips";
#endif
	std::string checkFilename = filename + ".cache.dat";
	if (!file_exists(checkFilename))
	{
		try {
#ifdef FREE_VERSION
			scoped_istream stream = preprocess_file(get_wml_location("hardwired/tips_free.cfg"));
#else
			scoped_istream stream = preprocess_file(get_wml_location("hardwired/tips.cfg"));
#endif
			read(tips_of_day, *stream);
		} catch(config::error&) {
	//		ERR_CONFIG << "Could not read data/hardwired/tips.cfg\n";
		}
	
		tips_of_day.saveCache(filename);
	}
	else
	{
		tips_of_day.loadCache(filename);
	}
	
	
	//we shuffle the tips after each initial loading. We only shuffle if
	//the upload_log preference has been set. If it hasn't been set, it's the
	//user's first time playing since this feature has been added, so we'll
	//leave the tips in their default order, which will always contain a tip
	//regarding the upload log first, so the user sees it.
	config::child_itors tips = tips_of_day.child_range("tip");
	if (tips.first != tips.second && preferences::has_upload_log()) {
		std::random_shuffle(tips.first, tips.second);
	}
	
	//Make sure that the upload log preference is set, if it's not already, so
	//that we know next time we've already seen the message about uploads.
	if(!preferences::has_upload_log()) 
	{
		//preferences::set_upload_log(preferences::upload_log());
		preferences::set_upload_log(false);
	}
	loadscreen::global_loadscreen->disable_increments = false;

}
Exemplo n.º 6
0
const config& load_campagin_scenario(const std::string& campaign_id, const std::string& scenario_id, const std::string& type)
{
	config campaign_cfg;
	static config scenario_cfg;

	if (!scenario_id.empty() && scenario_id != "null") {
		wml_config_from_file(game_config::path + "/xwml/campaigns/" + campaign_id + ".bin", campaign_cfg);
		scenario_cfg = campaign_cfg.find_child(type, "id", scenario_id);
	} else {
		scenario_cfg.clear();
	}
	return scenario_cfg;
}
Exemplo n.º 7
0
/** Read the file with the tips-of-the-day. */
void read_tips_of_day(config& tips_of_day)
{
	tips_of_day.clear();
	LOG_CF << "Loading tips of day\n";
	try {
		scoped_istream stream = preprocess_file(get_wml_location("hardwired/tips.cfg"));
		read(tips_of_day, *stream);
	} catch(config::error&) {
		ERR_CF << "Could not read data/hardwired/tips.cfg\n";
	}

	//we shuffle the tips after each initial loading. We only shuffle if
	//the upload_log preference has been set. If it hasn't been set, it's the
	//user's first time playing since this feature has been added, so we'll
	//leave the tips in their default order, which will always contain a tip
	//regarding the upload log first, so the user sees it.
	config::const_child_itors itors = tips_of_day.child_range("tip");
	if (itors.first != itors.second && preferences::has_upload_log()) {
		std::vector<config> tips(itors.first, itors.second);
		std::random_shuffle(tips.begin(), tips.end());
		tips_of_day.clear();
		foreach (const config &tip, tips) {
			tips_of_day.add_child("tip", tip);
		}
Exemplo n.º 8
0
bool addons_client::request_addons_list(config& cfg)
{
	cfg.clear();

	config response_buf;

	/** @todo FIXME: get rid of this legacy "campaign"/"campaigns" silliness */

	this->send_simple_request("request_campaign_list", response_buf);
	this->wait_for_transfer_done(_("Downloading list of add-ons..."));

	cfg = response_buf.child("campaigns");

	return !this->update_last_error(response_buf);
}
Exemplo n.º 9
0
static void enter_connect_mode(game_display& disp, const config& game_config, hero_map& heros, hero_map& heros_start,
		card_map& cards,
		config& gamelist, const mp_game_settings& params,
		const int num_turns, mp::controller default_controller, bool local_players_only = false)
{
	mp::ui::result res;
	game_state state;
	const network::manager net_manager(1,1);
	network_game_manager m;

	gamelist.clear();
	statistics::fresh_stats();

	// if (gui2::new_widgets) {
		gui2::tmp_side_creator dlg(heros, disp, *resources::game_map, game_config, gamelist, params, num_turns, default_controller, local_players_only);
		dlg.show(disp.video());
		switch (dlg.get_legacy_result()) {
		case gui2::tmp_side_creator::PLAY:
			res = mp::ui::PLAY;
			dlg.start_game();
			state = dlg.get_state();
			// lobby may modify hero's side_feature
			heros_start = heros;
			break;
		case gui2::tmp_side_creator::CREATE:
			res = mp::ui::CREATE;
			break;
		default:
			res = mp::ui::QUIT;
		}

	switch (res) {
	case mp::ui::PLAY:
		play_game(disp, state, game_config, heros, heros_start, cards, IO_SERVER);
		recorder.clear();

		break;
	case mp::ui::CREATE:
		enter_create_mode(disp, game_config, heros, heros_start, cards, gamelist, default_controller, local_players_only);
		break;
	case mp::ui::QUIT:
	default:
		network::send_data(config("refresh_lobby"), 0);
		break;
	}
}
Exemplo n.º 10
0
bool addons_client::download_addon(config& archive_cfg, const std::string& id, const std::string& title)
{
	archive_cfg.clear();

	config request_buf;
	request_buf.add_child("request_campaign")["name"] = id;

	utils::string_map i18n_symbols;
	i18n_symbols["addon_title"] = title;

	LOG_ADDONS << "downloading " << id << '\n';

	this->send_request(request_buf, archive_cfg);
	this->wait_for_transfer_done(vgettext("Downloading add-on <i>$addon_title</i>...", i18n_symbols));

	return !this->update_last_error(archive_cfg);
}
Exemplo n.º 11
0
static void enter_wait_mode(game_display& disp, const config& game_config, mp::chat& chat, config& gamelist, bool observe)
{
	mp::ui::result res;
	game_state state;
	network_game_manager m;
	upload_log nolog(false);

	gamelist.clear();
	statistics::fresh_stats();

	{
		mp::wait ui(disp, game_config, chat, gamelist);

		ui.join_game(observe);

		run_lobby_loop(disp, ui);
		res = ui.get_result();

		if (res == mp::ui::PLAY) {
			ui.start_game();
			// FIXME commented a pointeless if since the else does exactly the same thing
			//if (preferences::skip_mp_replay()){
				//FIXME implement true skip replay
				//state = ui.request_snapshot();
				//state = ui.get_state();
			//}
			//else{
				state = ui.get_state();
			//}
		}
	}

	switch (res) {
	case mp::ui::PLAY:
		play_game(disp, state, game_config, nolog, IO_CLIENT,
			preferences::skip_mp_replay() && observe);
		recorder.clear();

		break;
	case mp::ui::QUIT:
	default:
		break;
	}
}
Exemplo n.º 12
0
static void enter_connect_mode(game_display& disp, const config& game_config,
		mp::chat& chat, config& gamelist, const mp_game_settings& params,
		const int num_turns, mp::controller default_controller, bool local_players_only = false)
{
	mp::ui::result res;
	game_state state;
	const network::manager net_manager(1,1);
	network_game_manager m;
	upload_log nolog(false);

	gamelist.clear();
	statistics::fresh_stats();

	{
		mp::connect ui(disp, game_config, chat, gamelist, params, num_turns, default_controller, local_players_only);
		run_lobby_loop(disp, ui);

		res = ui.get_result();

		// start_game() updates the parameters to reflect game start,
		// so it must be called before get_level()
		if (res == mp::ui::PLAY) {
			ui.start_game();
			state = ui.get_state();
		}
	}

	switch (res) {
	case mp::ui::PLAY:
		play_game(disp, state, game_config, nolog, IO_SERVER);
		recorder.clear();

		break;
	case mp::ui::CREATE:
		enter_create_mode(disp, game_config, chat, gamelist, default_controller, local_players_only);
		break;
	case mp::ui::QUIT:
	default:
		network::send_data(config("refresh_lobby"), 0, true);
		break;
	}
}
Exemplo n.º 13
0
bool addons_client::download_addon(config& archive_cfg, const std::string& id, const std::string& title, bool increase_downloads)
{
	archive_cfg.clear();

	config request_buf;
	config& request_body = request_buf.add_child("request_campaign");

	request_body["name"] = id;
	request_body["increase_downloads"] = increase_downloads;

	utils::string_map i18n_symbols;
	i18n_symbols["addon_title"] = font::escape_text(title);

	LOG_ADDONS << "downloading " << id << '\n';

	this->send_request(request_buf, archive_cfg);
	this->wait_for_transfer_done(VGETTEXT("Downloading add-on <i>$addon_title</i>...", i18n_symbols));

	return !this->update_last_error(archive_cfg);
}
Exemplo n.º 14
0
void manager::read_save_file(const std::string& name, config& cfg, std::string* error_log)
{
	std::string modified_name = name;
	replace_space2underbar(modified_name);

	// Try reading the file both with and without underscores, if needed append .gz as well
	scoped_istream file_stream = istream_file(get_saves_dir() + "/" + modified_name);
	if (file_stream->fail()) {
		file_stream = istream_file(get_saves_dir() + "/" + name);
	}
	if(file_stream->fail() && !is_gzip_file(modified_name)) {
		file_stream = istream_file(get_saves_dir() + "/" + modified_name + ".gz");
		if (file_stream->fail()) {
			file_stream = istream_file(get_saves_dir() + "/" + name + ".gz");
		}
		modified_name += ".gz";
	}

	cfg.clear();
	try{
		/*
		 * Test the modified name, since it might use a .gz
		 * file even when not requested.
		 */
		if(is_gzip_file(modified_name)) {
			read_gz(cfg, *file_stream);
		} else {
			read(cfg, *file_stream);
		}
	} catch (config::error &err)
	{
		LOG_SAVE << err.message;
		if (error_log) *error_log += err.message;
		throw game::load_game_failed();
	}

	if(cfg.empty()) {
		LOG_SAVE << "Could not parse file data into config\n";
		throw game::load_game_failed();
	}
}
Exemplo n.º 15
0
void wml_config_from_file(const std::string &fname, config &cfg, uint32_t* nfiles, uint32_t* sum_size, uint32_t* modified)
{
	posix_file_t						fp = INVALID_FILE;
	uint32_t							datalen, fsizelow, fsizehigh, max_str_len, bytertd, tdcnt, idx, len;
	uint8_t								*data = NULL, *namebuf = NULL, *valbuf = NULL;
	char								tdname[MAXLEN_TEXTDOMAIN + 1];

	std::vector<std::string>			tdomain;

	posix_print("<xwml.cpp>::wml_config_from_file------fname: %s\n", fname.c_str());

	cfg.clear();	// 首先清空,以下是增加方式

	posix_fopen(fname.c_str(), GENERIC_READ, OPEN_EXISTING, fp);
	if (fp == INVALID_FILE) {
		posix_print("------<xwml.cpp>::wml_config_from_file, cannot create %s for read\n", fname.c_str());
		goto exit;
	}
	posix_fsize(fp, fsizelow, fsizehigh);
	if (fsizelow <= 16) {
		goto exit;
	}
	posix_fseek(fp, 0, 0);
	posix_fread(fp, &len, 4, bytertd);
	// 判断是不是XWML
	if (len != mmioFOURCC('X', 'W', 'M', 'L')) {
		goto exit;
	}
	posix_fread(fp, &len, 4, bytertd);
	if (nfiles) {
		*nfiles = len;
	}
	posix_fread(fp, &len, 4, bytertd);
	if (sum_size) {
		*sum_size = len;
	}
	posix_fread(fp, &len, 4, bytertd);
	if (modified) {
		*modified = len;
	}
	posix_fread(fp, &max_str_len, sizeof(max_str_len), bytertd);
			
	// 读出po
	posix_fread(fp, &tdcnt, sizeof(tdcnt), bytertd);
	datalen = fsizelow - 16 - sizeof(max_str_len) - sizeof(tdcnt);
	for (idx = 0; idx < tdcnt; idx ++) {
		posix_fread(fp, &len, sizeof(uint32_t), bytertd);
		posix_fread(fp, tdname, len, bytertd);
		tdname[len] = 0;
		tdomain.push_back(tdname);

		datalen -= sizeof(uint32_t) + len;

		t_string::add_textdomain(tdomain.back(), get_intl_dir());
	}
		
	data = (uint8_t *)malloc(datalen);
	namebuf = (uint8_t *)malloc(max_str_len + 1 + 1024);
	valbuf = (uint8_t *)malloc(max_str_len + 1 + 1024);

	// 剩下数据读出sram
	posix_fread(fp, data, datalen, bytertd);

	wml_config_from_data(data, datalen, namebuf, valbuf, tdomain, cfg);

exit:
	if (fp != INVALID_FILE) {
		posix_fclose(fp);
	}
	if (data) {
		free(data);
	}
	if (namebuf) {
		free(namebuf);
	}
	if (valbuf) {
		free(valbuf);
	}
	return;
}
Exemplo n.º 16
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, config& economy_area)
{
	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;

	pathfind::reallocate_pq(width, height);

	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");
	// If the [naming] child is empty, we cannot provide good names.
	std::map<map_location,std::string>* misc_labels = naming.empty() ? NULL : labels;
	// 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 && misc_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) {
							misc_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 && misc_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);
						misc_labels->erase(loc);
						misc_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");
		// tower fix
		const int min_x = width/3 + ((width >= 60)? 3: 1);
		const int min_y = height/3 + ((height >= 60)? 3: 1);
		const int max_x = (width/3)*2 - ((width >= 60)? 4: 1);
		const int max_y = (height/3)*2 - ((height >= 60)? 4: 1);
		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(misc_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);
						misc_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(misc_labels != NULL && terrain[x][y] != letter && name_count++ == name_frequency && on_bridge == false) {
						misc_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.
	economy_area.clear();
	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;
		}
		if (!cfg["no_ea"].to_bool()) {
			// place economy area
			std::stringstream name, str;
			if (y > (int)height / 2) {
				terrain[x][y - 4] = t_translation::ECONOMY_AREA;
				str << "(" << x + 1 - width / 3 << "," << y - 3 - height / 3 << ")";
				terrain[x + 1][y - 4] = t_translation::ECONOMY_AREA;
				str << "(" << x + 2 - width / 3 << "," << y - 3 - height / 3 << ")";
			} else {
				terrain[x][y + 4] = t_translation::ECONOMY_AREA;
				str << "(" << x + 1 - width / 3 << "," << y + 5 - height / 3 << ")";
				terrain[x + 1][y + 4] = t_translation::ECONOMY_AREA;
				str << "(" << x + 2 - width / 3 << "," << y + 5 - height / 3 << ")";
			}
			name << "economy_area" << player;
			economy_area[name.str()] = str.str();
		}

		// 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)
	 */
	if ( misc_labels != NULL ) {
		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);
						}
						misc_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, misc_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, misc_labels, name);
					}
				}
			}//for (y)
		}//for (x)
	}//if (misc_labels)

	// don't process, remark villages
	nvillages = 0;

	if (nvillages > 0)
	{
		config naming_cfg = cfg.child_or_empty("village_naming");
		// If the [village_naming] child is empty, we cannot provide good names.
		std::map<map_location,std::string>* village_labels = naming_cfg.empty() ? NULL : labels;
		// 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 ( village_labels != NULL ) {
								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);
								village_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);
}
Exemplo n.º 17
0
void set_about(const config &cfg)
{
	about_list.clear();
	images.clear();
	images_default = "";

	for (const config &about : cfg.child_range("about"))
	{
		about_list.add_child("about", about);
		const std::string &im = about["images"];
		if (!images.empty())
		{
			if (images_default.empty())
				images_default = im;
			else
				images_default += ',' + im;
		}
	}

	for (const config &campaign : cfg.child_range("campaign"))
	{
		config::const_child_itors abouts = campaign.child_range("about");
		if (abouts.first == abouts.second) continue;

		config temp;
		std::ostringstream text;
		const std::string &id = campaign["id"];
		temp["title"] = campaign["name"];
		temp["id"] = id;
		std::string campaign_images;

		for (const config &about : abouts)
		{
			const std::string &subtitle = about["title"];
			if (!subtitle.empty())
			{
				text << '+';
				if (subtitle[0] == '_')
					text << translation::gettext(subtitle.substr(1, subtitle.size() - 1).c_str());
				else
					text << subtitle;
				text << '\n';
			}

			for (const std::string &line : utils::split(about["text"], '\n'))
			{
				text << "    " << line << '\n';
			}

			for (const config &entry : about.child_range("entry"))
			{
				text << "    " << entry["name"] << '\n';
			}

			const std::string &im = about["images"];
			if (!im.empty())
			{
				if (campaign_images.empty())
					campaign_images = im;
				else
					campaign_images += ',' + im;
			}
		}

		images[id] = campaign_images;
		temp["text"] = text.str();
		about_list.add_child("about",temp);
	}
}
Exemplo n.º 18
0
static network::connection network_data_dialog(display& disp, const std::string& msg, config& cfg, network::connection connection_num, network::statistics (*get_stats)(network::connection handle))
{
	const size_t width = 300;
	const size_t height = 80;
	const size_t border = 20;
	const int left = disp.w()/2 - width/2;
	const int top  = disp.h()/2 - height/2;

	const events::event_context dialog_events_context;

	gui::button cancel_button(disp.video(),_("Cancel"));
	std::vector<gui::button*> buttons_ptr(1,&cancel_button);

	gui::dialog_frame frame(disp.video(), msg, gui::dialog_frame::default_style, true, &buttons_ptr);
	SDL_Rect centered_layout = frame.layout(left,top,width,height).interior;
	centered_layout.x = disp.w() / 2 - centered_layout.w / 2;
	centered_layout.y = disp.h() / 2 - centered_layout.h / 2;
	// HACK: otherwise we get an empty useless space in the dialog below the progressbar
	centered_layout.h = height;
	frame.layout(centered_layout);
	frame.draw();

	const SDL_Rect progress_rect = create_rect(centered_layout.x + border
			, centered_layout.y + border
			, centered_layout.w - border * 2
			, centered_layout.h - border * 2);

	gui::progress_bar progress(disp.video());
	progress.set_location(progress_rect);

	events::raise_draw_event();
	disp.flip();

	network::statistics old_stats = get_stats(connection_num);

	cfg.clear();
	for(;;) {
		const network::connection res = network::receive_data(cfg,connection_num,100);
		const network::statistics stats = get_stats(connection_num);
		if(stats.current_max != 0 && stats != old_stats) {
			old_stats = stats;
			progress.set_progress_percent((stats.current*100)/stats.current_max);
			std::ostringstream stream;
			stream << stats.current/1024 << "/" << stats.current_max/1024 << _("KB");
			progress.set_text(stream.str());
		}

		events::raise_draw_event();
		disp.flip();
		events::pump();

		if(res != 0) {
			return res;
		}


		if(cancel_button.pressed()) {
			return res;
		}
	}
}