Esempio n. 1
0
editor_action* editor_action_starting_position::perform(map_context& mc) const
{
	editor_action_ptr undo;

	const std::string* old_loc_id = mc.map().is_starting_position(loc_);
	map_location old_loc = mc.map().special_location(loc_id_);

	if(old_loc_id != nullptr) {
		// If another player was starting at the location, we actually perform two actions, so the undo is an
		// action_chain.
		editor_action_chain* undo_chain = new editor_action_chain();

		undo_chain->append_action(new editor_action_starting_position(loc_, *old_loc_id));
		undo_chain->append_action(new editor_action_starting_position(old_loc, loc_id_));

		undo.reset(undo_chain);

		LOG_ED << "ssp actual: " << *old_loc_id << " to " << map_location() << "\n";

		mc.map().set_special_location(*old_loc_id, map_location());
	} else {
		undo.reset(new editor_action_starting_position(old_loc, loc_id_));
	}

	LOG_ED << "ssp actual: " << loc_id_ << " to " << loc_ << "\n";

	mc.map().set_special_location(loc_id_, loc_);
	mc.set_needs_labels_reset();

	return undo.release();
}
Esempio n. 2
0
bool animate_unit_advancement(const map_location &loc, size_t choice, const bool &fire_event, const bool animate)
{
	const events::command_disabler cmd_disabler;

	unit_map::iterator u = resources::units->find(loc);
	if (u == resources::units->end()) {
		LOG_DP << "animate_unit_advancement suppressed: invalid unit\n";
		return false;
	} else if (!u->advances()) {
		LOG_DP << "animate_unit_advancement suppressed: unit does not advance\n";
		return false;
	}

	const std::vector<std::string>& options = u->advances_to();
	std::vector<config> mod_options = u->get_modification_advances();

	if(choice >= options.size() + mod_options.size()) {
		LOG_DP << "animate_unit_advancement suppressed: invalid option\n";
		return false;
	}

	// When the unit advances, it fades to white, and then switches
	// to the new unit, then fades back to the normal color

	if (animate && !resources::screen->video().update_locked()) {
		unit_animator animator;
		bool with_bars = true;
		animator.add_animation(&*u,"levelout", u->get_location(), map_location(), 0, with_bars);
		animator.start_animations();
		animator.wait_for_end();
	}

	if(choice < options.size()) {
		// chosen_unit is not a reference, since the unit may disappear at any moment.
		std::string chosen_unit = options[choice];
		::advance_unit(loc, chosen_unit, fire_event);
	} else {
		const config &mod_option = mod_options[choice - options.size()];
		::advance_unit(loc, "", fire_event, &mod_option);
	}

	u = resources::units->find(loc);
	resources::screen->invalidate_unit();

	if (animate && u != resources::units->end() && !resources::screen->video().update_locked()) {
		unit_animator animator;
		animator.add_animation(&*u, "levelin", u->get_location(), map_location(), 0, true);
		animator.start_animations();
		animator.wait_for_end();
		animator.set_all_standing();
		resources::screen->invalidate(loc);
		resources::screen->draw();
		events::pump();
	}

	resources::screen->invalidate_all();
	resources::screen->draw();

	return true;
}
	MLFixture()
	{
		va = map_location(3,4);
		vb = map_location(10,8);
		vc = map_location(0,9);
		vz = map_location::ZERO();
		vt1 = va.vector_negation();
		vt2 = vb.vector_sum(vc);
		vt3 = va.vector_sum(vc.vector_negation());

		vs1 = vz.get_direction(nw);
		vs2 = vz.get_direction(n).get_direction(ne);
		vs3 = vz.get_direction(s).get_direction(se);
		vs4 = vz.get_direction(sw).get_direction(se);

		preset_locs.push_back(va);
		preset_locs.push_back(vb);
		preset_locs.push_back(vc);
		preset_locs.push_back(vz);
		preset_locs.push_back(vt1);
		preset_locs.push_back(vt2);
		preset_locs.push_back(vt3);
		preset_locs.push_back(vs1);
		preset_locs.push_back(vs2);
		preset_locs.push_back(vs3);
		preset_locs.push_back(vs4);
	}
Esempio n. 4
0
move::move(config const& cfg, bool hidden)
	: action(cfg,hidden)
	, unit_underlying_id_(0)
	, unit_id_()
	, route_(new pathfind::marked_route())
	, movement_cost_(0)
	, turn_number_(0)
	, arrow_(new arrow(hidden))
	, fake_unit_()
	, arrow_brightness_()
	, arrow_texture_()
	, mover_()
	, fake_unit_hidden_(false)
{
	// Construct and validate unit_
	unit_map::iterator unit_itor = resources::units->find(cfg["unit_"]);
	if(unit_itor == resources::units->end())
		throw action::ctor_err("move: Invalid underlying_id");
	unit_underlying_id_ = unit_itor->underlying_id();

	// Construct and validate route_
	config const& route_cfg = cfg.child("route_");
	if(!route_cfg)
		throw action::ctor_err("move: Invalid route_");
	route_->move_cost = route_cfg["move_cost"];
	BOOST_FOREACH(config const& loc_cfg, route_cfg.child_range("step")) {
		route_->steps.push_back(map_location(loc_cfg["x"],loc_cfg["y"]));
	}
	BOOST_FOREACH(config const& mark_cfg, route_cfg.child_range("mark")) {
		route_->marks[map_location(mark_cfg["x"],mark_cfg["y"])]
			= pathfind::marked_route::mark(mark_cfg["turns"],
				mark_cfg["zoc"].to_bool(),
				mark_cfg["capture"].to_bool(),
				mark_cfg["invisible"].to_bool());
	}

	// Validate route_ some more
	std::vector<map_location> const& steps = route_->steps;
	if(steps.empty())
		throw action::ctor_err("move: Invalid route_");

	// Construct arrow_
	arrow_->set_color(team::get_side_color_index(side_number()));
	arrow_->set_style(arrow::STYLE_STANDARD);
	arrow_->set_path(route_->steps);

	// Construct fake_unit_
	fake_unit_.reset(new game_display::fake_unit(*get_unit()) );
	if(hidden)
		fake_unit_->set_hidden(true);
	fake_unit_->place_on_game_display(resources::screen);
	fake_unit_->set_ghosted(true);
	unit_display::move_unit(route_->steps, *fake_unit_, false); //get facing right
	fake_unit_->set_location(route_->steps.back());

	this->init();
}
Esempio n. 5
0
/**
 * Creates an undo_action based on a config.
 * @param  tag  is the tag of this config, which is used for error reporting.
 *              It should be enclosed in square brackets.
 * @return a pointer that must be deleted, or NULL if the @a cfg could not be parsed.
 */
undo_list::undo_action *
undo_list::undo_action::create(const config & cfg, const std::string & tag)
{
	const std::string str = cfg["type"];
	undo_list::undo_action * res = NULL;
	// The general division of labor in this function is that the various
	// constructors will parse the "unit" child config, while this function
	// parses everything else.

	if ( str == "move" ) {
		res = new move_action(cfg.child("unit", tag), cfg,
		                       cfg["starting_moves"],
		                       cfg["time_bonus"],
		                       cfg["village_owner"],
		                       map_location::parse_direction(cfg["starting_direction"]));
	}

	if ( str == "recruit" ) {
		// Validate the unit type.
		const config & child = cfg.child("unit", tag);
		const unit_type * u_type = unit_types.find(child["type"]);

		if ( !u_type ) {
			// Bad data.
			ERR_NG << "Invalid recruit found in " << tag << "; unit type '"
			       << child["type"] << "' was not found.\n";
			return NULL;
		}
		res = new recruit_action(child, *u_type,
		                          map_location(cfg, NULL),
		                          map_location(cfg.child_or_empty("leader"), NULL));
	}

	else if ( str == "recall" )
		res =  new recall_action(cfg.child("unit", tag),
		                         map_location(cfg, NULL),
		                         map_location(cfg.child_or_empty("leader"), NULL));

	else if ( str == "dismiss" )
		res =  new dismiss_action(cfg.child("unit", tag));

	else if ( str == "auto_shroud" )
		res =  new auto_shroud_action(cfg["active"].to_bool());

	else if ( str == "update_shroud" )
		res =  new update_shroud_action;
	else
	{
		// Unrecognized type.
		ERR_NG << "Unrecognized undo action type: " << str << "." << std::endl;
		return NULL;
	}
	res->replay_data = cfg.child_or_empty("replay_data");
	return res;
}
Esempio n. 6
0
map_location gamemap::special_location(const std::string& id) const
{
	auto it = starting_positions_.left.find(id);
	if (it != starting_positions_.left.end()) {
		auto& coordinate = it->second;
		return map_location(coordinate.x, coordinate.y);
	}
	else {
		return map_location();
	}
}
Esempio n. 7
0
static map_location place_village(const t_translation::t_map& map,
	const size_t x, const size_t y, const size_t radius, const config& cfg,
	tcode_list_cache &adj_liked_cache)
{
	const map_location loc(x,y);
	std::set<map_location> locs;
	get_tiles_radius(loc,radius,locs);
	map_location best_loc;
	int best_rating = 0;
	for(std::set<map_location>::const_iterator i = locs.begin();
			i != locs.end(); ++i) {

		if(i->x < 0 || i->y < 0 || i->x >= static_cast<long>(map.size()) ||
				i->y >= static_cast<long>(map[i->x].size())) {

			continue;
		}

		const t_translation::t_terrain t = map[i->x][i->y];
		const std::string str = t_translation::write_terrain_code(t);
		if (const config &child = cfg.find_child("village", "terrain", str)) {
			tcode_list_cache::iterator l = adj_liked_cache.find(t);
			t_translation::t_list *adjacent_liked;
			if (l != adj_liked_cache.end()) {
				adjacent_liked = &(l->second);
			} else {
				adj_liked_cache[t] = t_translation::read_list(child["adjacent_liked"]);
				adjacent_liked = &(adj_liked_cache[t]);
			}

			int rating = child["rating"];
			map_location adj[6];
			get_adjacent_tiles(map_location(i->x,i->y),adj);
			for(size_t n = 0; n != 6; ++n) {
				if(adj[n].x < 0 || adj[n].y < 0 ||
						adj[n].x >= static_cast<long>(map.size()) ||
						adj[n].y >= static_cast<long>(map[adj[n].x].size())) {

					continue;
				}

				const t_translation::t_terrain t2 = map[adj[n].x][adj[n].y];
				rating += std::count(adjacent_liked->begin(),adjacent_liked->end(),t2);
			}

			if(rating > best_rating) {
				best_loc = map_location(i->x,i->y);
				best_rating = rating;
			}
		}
	}

	return best_loc;
}
/**
 * Helper function which gets a map location from the stack. Handles lua (1-based) to C++ (0-based) conversion.
 * Expected: stack has at least two elements, top is y, next is x.
 */
static map_location pop_map_location(lua_State* L)
{
	if (lua_gettop(L) < 2) {
		luaL_error(L, "pop_map_location: expected to find a map location on the stack, but stack has less than two elements");
		return map_location();
	}
	int y = luaL_checkint(L, -1);
	int x = luaL_checkint(L, -2);
	lua_pop(L, 2);

	return map_location(x-1, y-1);
}
void editor_map::invert_selection()
{
	std::set<map_location> new_selection;
	for (int x = -1; x < w() + 1; ++x) {
		for (int y = -1; y < h() + 1; ++y) {
			if (selection_.find(map_location(x, y)) == selection_.end()) {
				new_selection.insert(map_location(x, y));
			}
		}
	}
	selection_.swap(new_selection);
}
/**
 * Returns a random tile at one of the borders of a map that is of the given
 * dimensions.
 */
map_location default_map_generator_job::random_point_at_side(size_t width, size_t height)
{
	const int side = rng_()%4;
	if(side < 2) {
		const int x = rng_()%width;
		const int y = side == 0 ? 0 : height-1;
		return map_location(x,y);
	} else {
		const int y = rng_()%height;
		const int x = side == 2 ? 0 : width-1;
		return map_location(x,y);
	}
}
Esempio n. 11
0
map_location pathfind::find_vacant_tile(const gamemap& map,
				const unit_map& units,
				const map_location& loc,
				pathfind::VACANT_TILE_TYPE vacancy,
				const unit* pass_check)
{
	if (!map.on_board(loc)) return map_location();
	std::set<map_location> pending_tiles_to_check, tiles_checked;
	pending_tiles_to_check.insert(loc);
	// Iterate out 50 hexes from loc
	for (int distance = 0; distance < 50; ++distance) {
		if (pending_tiles_to_check.empty())
			return map_location();
		//Copy over the hexes to check and clear the old set
		std::set<map_location> tiles_checking;
		tiles_checking.swap(pending_tiles_to_check);
		//Iterate over all the hexes we need to check
		foreach (const map_location &loc, tiles_checking)
		{
			//If this area is not a castle but should, skip it.
			if (vacancy == pathfind::VACANT_CASTLE && !map.is_castle(loc)) continue;
			const bool pass_check_and_unreachable = pass_check
				&& pass_check->movement_cost(map[loc]) == unit_movement_type::UNREACHABLE;
			//If the unit can't reach the tile and we have searched
			//an area of at least radius 10 (arbitrary), skip the tile.
			//Neccessary for cases such as an unreachable
			//starting hex surrounded by 6 other unreachable hexes, in which case
			//the algorithm would not even search distance==1
			//even if there's a reachable hex for distance==2.
			if (pass_check_and_unreachable && distance > 10) continue;
			//If the hex is empty and we do either no pass check or the hex is reachable, return it.
			if (units.find(loc) == units.end() && !pass_check_and_unreachable) return loc;
			map_location adjs[6];
			get_adjacent_tiles(loc,adjs);
			foreach (const map_location &loc, adjs)
			{
				if (!map.on_board(loc)) continue;
				// Add the tile to be checked if it hasn't already been and
				// isn't being checked.
				if (tiles_checked.find(loc) == tiles_checked.end() &&
				    tiles_checking.find(loc) == tiles_checking.end())
				{
					pending_tiles_to_check.insert(loc);
				}
			}
		}
		tiles_checked.swap(tiles_checking);
	}
	return map_location();
}
Esempio n. 12
0
editor_action* mouse_action_starting_position::up_left(editor_display& disp, int x, int y)
{
	if (!click_) return nullptr;
	click_ = false;
	map_location hex = disp.hex_clicked_on(x, y);
	if (!disp.map().on_board(hex)) {
		return nullptr;
	}
	auto player_starting_at_hex = disp.map().is_starting_position(hex);
	 
	if (has_ctrl_modifier()) {
		if (player_starting_at_hex) {
			location_palette_.add_item(*player_starting_at_hex);
		}
		return nullptr;
	}

	std::string new_player_at_hex = location_palette_.selected_item();
	editor_action* a = nullptr;

	if(!player_starting_at_hex || new_player_at_hex != *player_starting_at_hex) {
		// Set a starting position
		a = new editor_action_starting_position(hex, new_player_at_hex);
	}
	else {
		// Erase current starting position
		a = new editor_action_starting_position(map_location(), *player_starting_at_hex);
	}

	update_brush_highlights(disp, hex);

	return a;
}
Esempio n. 13
0
unit_map::const_xy_accessor::const_xy_accessor(const unit_xy_iterator &i) :
	counter_(i.map_),
	i_(i.i_),
	map_(i.map_),
	loc_(i.valid() ? i->first : map_location())
{
}
Esempio n. 14
0
editor_action* mouse_action::key_event(
	editor_display& disp, const SDL_Event& event)
{
	if (!has_alt_modifier() && (event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9')) {
		int side = event.key.keysym.sym - '0';
		if (side >= 1 && side <= gamemap::MAX_PLAYERS) {
			map_location pos = disp.get_map().starting_position(side);
			if (pos.valid()) {
				disp.scroll_to_tile(pos, display::WARP);
			}
		}
		return nullptr;
	}
	if (!disp.map().on_board(previous_move_hex_) || event.type != SDL_KEYUP) {
		return nullptr;
	}
	editor_action* a = nullptr;
	if ((has_alt_modifier() && (event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9'))
	|| event.key.keysym.sym == SDLK_DELETE) {
		int res = event.key.keysym.sym - '0';
		if (res > gamemap::MAX_PLAYERS || event.key.keysym.sym == SDLK_DELETE) res = 0;
		const std::string* old_id = disp.map().is_starting_position(previous_move_hex_);
		if (res == 0 && old_id != nullptr) {
			a = new editor_action_starting_position(map_location(), *old_id);
		} else if (res > 0 && (old_id == nullptr || *old_id == std::to_string(res))) {
			a = new editor_action_starting_position(previous_move_hex_, std::to_string(res));
		}
	}
	return a;
}
/**
 * Generate a lake.
 *
 * It will create water at (x,y), and then have 'lake_fall_off' % chance to
 * make another water tile in each of the directions n,s,e,w.  In each of the
 * directions it does make another water tile, it will have 'lake_fall_off'/2 %
 * chance to make another water tile in each of the directions. This will
 * continue recursively.
 */
bool default_map_generator_job::generate_lake(terrain_map& terrain, int x, int y, int lake_fall_off, std::set<map_location>& locs_touched)
{
	if(x < 0 || y < 0 || x >= terrain.w || y >= terrain.h || lake_fall_off < 0) {
		return false;
	}
	//we checked for this eariler.
	unsigned int ulake_fall_off = lake_fall_off;
	terrain[x][y] = t_translation::SHALLOW_WATER;
	locs_touched.insert(map_location(x,y));

	if((rng_()%100) < ulake_fall_off) {
		generate_lake(terrain,x+1,y,lake_fall_off/2,locs_touched);
	}

	if((rng_()%100) < ulake_fall_off) {
		generate_lake(terrain,x-1,y,lake_fall_off/2,locs_touched);
	}

	if((rng_()%100) < ulake_fall_off) {
		generate_lake(terrain,x,y+1,lake_fall_off/2,locs_touched);
	}

	if((rng_()%100) < ulake_fall_off) {
		generate_lake(terrain,x,y-1,lake_fall_off/2,locs_touched);
	}

	return true;
}
Esempio n. 16
0
void paths::dest_vect::insert(const map_location &loc)
{
	iterator i = lower_bound(*this, loc), i_end = end();
	if (i != i_end && i->curr == loc) return;
	paths::step s = { loc, map_location(), 0 };
	std::vector<step>::insert(i, s);
}
editor_action* mouse_action_starting_position::up_left(editor_display& disp, int x, int y)
{
	if (!click_) return NULL;
	click_ = false;
	map_location hex = disp.hex_clicked_on(x, y);
	if (!disp.map().on_board(hex)) {
		return NULL;
	}
	int player_starting_at_hex = disp.map().is_starting_position(hex) + 1;
	std::vector<std::string> players;
	players.push_back(_("(Player)^None"));
	for (int i = 1; i <= gamemap::MAX_PLAYERS; i++) {
		std::stringstream str;
		str << _("Player") << " " << i;
		players.push_back(str.str());
	}
	gui::dialog pmenu = gui::dialog(disp,
				       _("Choose player"),
				       _("Which player should start here? You can use alt and a number key to set the starting position for a player, and del to clear the starting position under the cursor. Pressing a number key by itself will scroll to that player's starting position."),
				       gui::OK_CANCEL);
	pmenu.set_menu(players);
	int res = pmenu.show();
	editor_action* a = NULL;
	if (res == 0 && player_starting_at_hex != -1) {
		a = new editor_action_starting_position(map_location(), player_starting_at_hex);
	} else if (res > 0 && res != player_starting_at_hex) {
		a = new editor_action_starting_position(hex, res);
	}
	update_brush_highlights(disp, hex);
	return a;
}
editor_action* mouse_action::key_event(
	editor_display& disp, const SDL_Event& event)
{
	if (!has_alt_modifier() && (event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9')) {
		int side = event.key.keysym.sym - '0';
		if (side >= 1 && side <= gamemap::MAX_PLAYERS) {
			map_location pos = disp.get_map().starting_position(side);
			if (pos.valid()) {
				disp.scroll_to_tile(pos, display::WARP);
			}
		}
		return NULL;
	}
	if (!disp.map().on_board(previous_move_hex_) || event.type != SDL_KEYUP) {
		return NULL;
	}
	editor_action* a = NULL;
	if ((has_alt_modifier() && (event.key.keysym.sym >= '1' && event.key.keysym.sym <= '9'))
	|| event.key.keysym.sym == SDLK_DELETE) {
		int res = event.key.keysym.sym - '0';
		if (res > gamemap::MAX_PLAYERS || event.key.keysym.sym == SDLK_DELETE) res = 0;
		int player_starting_at_hex = disp.map().is_starting_position(previous_move_hex_) + 1;
		if (res == 0 && player_starting_at_hex != -1) {
			a = new editor_action_starting_position(map_location(), player_starting_at_hex);
		} else if (res > 0 && res != player_starting_at_hex) {
			a = new editor_action_starting_position(previous_move_hex_, res);
		}
	}
	return a;
}
Esempio n. 19
0
/**
 * Creates an undo_action based on a config.
 * @return a pointer that must be deleted, or nullptr if the @a cfg could not be parsed.
 */
undo_action_base * undo_list::create_action(const config & cfg)
{
	const std::string str = cfg["type"];
	undo_action_base * res = nullptr;
	// The general division of labor in this function is that the various
	// constructors will parse the "unit" child config, while this function
	// parses everything else.

	if ( str == "move" ) {
		res = new undo::move_action(cfg, cfg.child_or_empty("unit"),
		                       cfg["starting_moves"],
		                       map_location::parse_direction(cfg["starting_direction"]));
	}

	else if ( str == "recruit" ) {
		// Validate the unit type.
		const config & child = cfg.child("unit");
		const unit_type * u_type = unit_types.find(child["type"]);

		if ( !u_type ) {
			// Bad data.
			ERR_NG << "Invalid recruit found in [undo] or [redo]; unit type '"
			       << child["type"] << "' was not found.\n";
			return nullptr;
		}
		res = new undo::recruit_action(cfg, *u_type, map_location(cfg.child_or_empty("leader"), nullptr));
	}

	else if ( str == "recall" )
		res =  new undo::recall_action(cfg, map_location(cfg.child_or_empty("leader"), nullptr));

	else if ( str == "dismiss" )
		res =  new undo::dismiss_action(cfg, cfg.child("unit"));

	else if ( str == "auto_shroud" )
		res =  new undo::auto_shroud_action(cfg["active"].to_bool());

	else if ( str == "update_shroud" )
		res =  new undo::update_shroud_action();
	else
	{
		// Unrecognized type.
		ERR_NG << "Unrecognized undo action type: " << str << "." << std::endl;
		return nullptr;
	}
	return res;
}
Esempio n. 20
0
map_location find_vacant_tile(const gamemap& map,
				const unit_map& units,
				const map_location& loc,
				VACANT_TILE_TYPE vacancy,
				const unit* pass_check)
{
	std::set<map_location> pending_tiles_to_check;
	std::set<map_location> tiles_checked;
	pending_tiles_to_check.insert( loc );
	// Iterate out 50 hexes from loc
	for (int distance = 0; distance < 50; ++distance) {
		if (pending_tiles_to_check.empty())
			return map_location();
		//Copy over the hexes to check and clear the old set
		std::set<map_location> tiles_checking = pending_tiles_to_check;
		std::set<map_location>::const_iterator tc_itor = tiles_checking.begin();
		pending_tiles_to_check.clear();
		//Iterate over all the hexes we need to check
		for ( ; tc_itor != tiles_checking.end(); ++tc_itor )
		{
			//If the unit cannot reach this area or it's not a castle but should, skip it.
			if ((vacancy == VACANT_CASTLE && !map.is_castle(*tc_itor))
			|| (pass_check && pass_check->movement_cost(map[*tc_itor])
					== unit_movement_type::UNREACHABLE))
				continue;
			//If the hex is empty, return it.
			if (map.on_board(*tc_itor) && units.find(*tc_itor) == units.end())
				return (*tc_itor);
			map_location adjs[6];
			get_adjacent_tiles(*tc_itor,adjs);
			for (int i = 0; i != 6; ++i)
			{
				//Add the tile to be checked if it hasn't already been and isn't already
				//pending to be checked
				if (pending_tiles_to_check.find(adjs[i]) == pending_tiles_to_check.end() &&
					tiles_checked.find(adjs[i]) == tiles_checked.end() &&
					tiles_checking.find(adjs[i]) == tiles_checking.end())
				{
					pending_tiles_to_check.insert(adjs[i]);
				}
			}
		}
		tiles_checked = tiles_checking;
	}
	return map_location();
}
Esempio n. 21
0
int gamemap::num_valid_starting_positions() const
{
	const int res = is_starting_position(map_location());
	if(res == -1)
		return num_starting_positions()-1;
	else
		return res;
}
Esempio n. 22
0
void terrain_builder::parse_mapstring(const std::string &mapstring,
		struct building_rule &br, anchormap& anchors,
		const config& global_images)
{

	const t_translation::t_map map = t_translation::read_builder_map(mapstring);

	// If there is an empty map leave directly.
	// Determine after conversion, since a
	// non-empty string can return an empty map.
	if(map.empty()) {
		return;
	}

	int lineno = (map[0][0] == t_translation::NONE_TERRAIN) ? 1 : 0;
	int x = lineno;
	int y = 0;
	for(size_t y_off = 0; y_off < map.size(); ++y_off) {
		for(size_t x_off = x; x_off < map[y_off].size(); ++x_off) {

			const t_translation::t_terrain terrain = map[y_off][x_off];

			if(terrain.base == t_translation::TB_DOT) {
				// Dots are simple placeholders,
				// which do not represent actual terrains.
			} else if (terrain.overlay != 0 ) {
				anchors.insert(std::pair<int, map_location>(terrain.overlay, map_location(x, y)));
			} else if (terrain.base == t_translation::TB_STAR) {
				add_constraints(br.constraints, map_location(x, y), t_translation::STAR, global_images);
			} else {
					ERR_NG << "Invalid terrain (" << t_translation::write_terrain_code(terrain) << ") in builder map\n";
					assert(false);
					return;
			}
		x += 2;
		}

		if(lineno % 2 == 1) {
			++y;
			x = 0;
		} else {
			x = 1;
		}
		++lineno;
	}
}
map_location pathfind::find_vacant_tile(const gamemap& map,
				const unit_map& units,
				const map_location& loc,
				pathfind::VACANT_TILE_TYPE vacancy,
				const unit* pass_check)
{
	if (!map.on_board(loc)) return map_location();
	std::set<map_location> pending_tiles_to_check, tiles_checked;
	pending_tiles_to_check.insert(loc);
	// Iterate out 50 hexes from loc
	for (int distance = 0; distance < 50; ++distance) {
		if (pending_tiles_to_check.empty())
			return map_location();
		//Copy over the hexes to check and clear the old set
		std::set<map_location> tiles_checking;
		tiles_checking.swap(pending_tiles_to_check);
		//Iterate over all the hexes we need to check
		foreach (const map_location &loc, tiles_checking)
		{
			//If the unit cannot reach this area or it's not a castle but should, skip it.
			if ((vacancy == pathfind::VACANT_CASTLE && !map.is_castle(loc))
			|| (pass_check && pass_check->movement_cost(map[loc])
					== unit_movement_type::UNREACHABLE))
				continue;
			//If the hex is empty, return it.
			if (units.find(loc) == units.end())
				return loc;
			map_location adjs[6];
			get_adjacent_tiles(loc,adjs);
			foreach (const map_location &loc, adjs)
			{
				if (!map.on_board(loc)) continue;
				// Add the tile to be checked if it hasn't already been and
				// isn't being checked.
				if (tiles_checked.find(loc) == tiles_checked.end() &&
				    tiles_checking.find(loc) == tiles_checking.end())
				{
					pending_tiles_to_check.insert(loc);
				}
			}
		}
		tiles_checked.swap(tiles_checking);
	}
	return map_location();
}
Esempio n. 24
0
void editor_action_starting_position::perform_without_undo(map_context& mc) const
{
	const std::string* old_id = mc.get_map().is_starting_position(loc_);
	if (old_id != nullptr) {
		mc.get_map().set_special_location(*old_id, map_location());
	}
	mc.get_map().set_special_location(loc_id_, loc_);
	mc.set_needs_labels_reset();
}
Esempio n. 25
0
bool terrain_filter::match_internal(const map_location& loc, const bool ignore_xy) const
{
	//Filter Areas
	if (cfg_.has_attribute("area") &&
		resources::tod_manager->get_area_by_id(cfg_["area"]).count(loc) == 0)
		return false;

	if(cfg_.has_attribute("terrain")) {
		if(cache_.parsed_terrain == NULL) {
			cache_.parsed_terrain = new t_translation::t_match(cfg_["terrain"]);
		}
		if(!cache_.parsed_terrain->is_empty) {
			const t_translation::t_terrain letter = resources::game_map->get_terrain_info(loc).number();
			if(!t_translation::terrain_matches(letter, *cache_.parsed_terrain)) {
				return false;
			}
		}
	}

	//Allow filtering on location ranges
	if(!ignore_xy) {
		if(!loc.matches_range(cfg_["x"], cfg_["y"])) {
			return false;
		}
		//allow filtering by searching a stored variable of locations
		if(cfg_.has_attribute("find_in")) {
			variable_info vi(cfg_["find_in"], false, variable_info::TYPE_CONTAINER);
			if(!vi.is_valid) return false;
			if(vi.explicit_index) {
				if(map_location(vi.as_container(),NULL) != loc) {
					return false;
				}
			} else {
				bool found = false;
				BOOST_FOREACH(const config &cfg, vi.as_array()) {
					if (map_location(cfg, NULL) == loc) {
						found = true;
						break;
					}
				}
				if (!found) return false;
			}
		}
	}
Esempio n. 26
0
void gamemap::read(const std::string& data, const bool allow_invalid)
{
	tiles_ = t_translation::ter_map();
	villages_.clear();
	starting_positions_.clear();

	if(data.empty()) {
		w_ = 0;
		h_ = 0;
		if(allow_invalid) return;
	}

	int offset = read_header(data);

	const std::string& data_only = std::string(data, offset);

	try {
		tiles_ = t_translation::read_game_map(data_only, starting_positions_, t_translation::coordinate{ border_size(), border_size() });

	} catch(const t_translation::error& e) {
		// We re-throw the error but as map error.
		// Since all codepaths test for this, it's the least work.
		throw incorrect_map_format_error(e.message);
	}

	// Post processing on the map
	w_ = total_width() - 2 * border_size();
	h_ = total_height() - 2 * border_size();
	//Disabled since there are callcases which pass along a valid map header but empty
	//map data. Still, loading (and actually applying) an empty map causes problems later on.
	//Other callcases which need to load a dummy map use completely empty data :(.
	//VALIDATE((w_ >= 1 && h_ >= 1), "A map needs at least 1 tile, the map cannot be loaded.");

	for(int x = 0; x < total_width(); ++x) {
		for(int y = 0; y < total_height(); ++y) {

			// Is the terrain valid?
			t_translation::terrain_code t = tiles_.get(x, y);
			if(tdata_->map().count(t) == 0) {
				if(!tdata_->try_merge_terrains(t)) {
					std::stringstream ss;
					ss << "Unknown tile in map: (" << t_translation::write_terrain_code(t)
						   << ") '" << t << "'";
					throw incorrect_map_format_error(ss.str().c_str());
				}
			}

			// Is it a village?
			if(x >= border_size() && y >= border_size()
					&& x < total_width()- border_size() && y < total_height()- border_size()
					&& tdata_->is_village(tiles_.get(x, y))) {
				villages_.push_back(map_location(x - border_size(), y - border_size()));
			}
		}
	}
}
editor_action* mouse_action_starting_position::up_right(editor_display& disp, int x, int y)
{
	map_location hex = disp.hex_clicked_on(x, y);
	int player_starting_at_hex = disp.map().is_starting_position(hex) + 1;
	if (player_starting_at_hex != -1) {
		return new editor_action_starting_position(map_location(), player_starting_at_hex);
	} else {
		return NULL;
	}
}
Esempio n. 28
0
editor_action* mouse_action_starting_position::up_right(editor_display& disp, int x, int y)
{
	map_location hex = disp.hex_clicked_on(x, y);
	auto player_starting_at_hex = disp.map().is_starting_position(hex);
	if (player_starting_at_hex != nullptr) {
		return new editor_action_starting_position(map_location(), *player_starting_at_hex);
	} else {
		return nullptr;
	}
}
Esempio n. 29
0
void move_result::do_execute()
{
	LOG_AI_ACTIONS << "start of execution of: "<< *this << std::endl;
	assert(is_success());

	move_spectator_.set_unit(get_info().units.find(from_));

	if (from_ != to_) {
		move_unit(
			/*move_unit_spectator* move_spectator*/ &move_spectator_,
			/*std::vector<map_location> route*/ route_.steps,
			/*replay* move_recorder*/ &recorder,
			/*undo_list* undo_stack*/ NULL,
			/*bool show_move*/ preferences::show_ai_moves(),
			/*map_location *next_unit*/ NULL,
			/*bool continue_move*/ true, //@todo: 1.9 set to false after implemeting interrupt awareness
			/*bool should_clear_shroud*/ true,
			/*bool is_replay*/ false);

		if ( move_spectator_.get_ambusher().valid() || !move_spectator_.get_seen_enemies().empty() || !move_spectator_.get_seen_friends().empty() ) {
			set_gamestate_changed();
		} else if (move_spectator_.get_unit().valid()){
			unit_location_ = move_spectator_.get_unit()->first;
			if (unit_location_ != from_) {
				set_gamestate_changed();
			}
		}
	} else {
		assert(remove_movement_);
	}

	if (move_spectator_.get_unit().valid()){
		unit_location_ = move_spectator_.get_unit()->first;
		if ( remove_movement_ && ( move_spectator_.get_unit()->second.movement_left() > 0 ) && (unit_location_==to_)) {
			stopunit_result_ptr stopunit_res = actions::execute_stopunit_action(get_side(),true,unit_location_,true,false);
			if (!stopunit_res->is_ok()) {
				set_error(stopunit_res->get_status());
			}
			if (stopunit_res->is_gamestate_changed()) {
				set_gamestate_changed();
			}
		}
	} else {
		unit_location_ = map_location();
	}

	if (is_gamestate_changed()) {
		try {
			manager::raise_gamestate_changed();
		} catch (...) {
			is_ok(); //Silences "unchecked result" warning
			throw;
		}
	}
}
void read_locations(const config& cfg, std::vector<map_location>& locs)
{
	const std::vector<std::string> xvals = utils::split(cfg["x"]);
	const std::vector<std::string> yvals = utils::split(cfg["y"]);
	for (unsigned i = 0; i < xvals.size() || i < yvals.size(); ++i)
	{
		int x = lexical_cast<int>(xvals[i])-1;
		int y = lexical_cast<int>(yvals[i])-1;
		locs.push_back(map_location(x,y));
	}
}