move [terrain_mask] to lua

and implement it using wesnoth.terrain_mask.

This also fixes an issue where [terrain_mask] would not remove
removed villages from the teams villages list after [terrain_mask].

This also adds an alignment parameter to [terrain_mask].

(cherry-picked from commit 09c56ef2fe)
This commit is contained in:
gfgtdf 2018-08-13 13:52:39 +02:00
parent e4c170f249
commit 42af4c3378
7 changed files with 45 additions and 126 deletions

View file

@ -965,3 +965,44 @@ function wesnoth.wml_actions.store_unit_defense(cfg)
end
wml.variables[cfg.variable or "terrain_defense"] = defense
end
function wml_actions.terrain_mask(cfg)
cfg = helper.parsed(cfg)
local alignment = cfg.alignment
local is_odd = false
local border = cfg.border
local mask = cfg.mask
local x = cfg.x or helper.wml_error("[terrain_mask] missing x attribute")
local y = cfg.y or helper.wml_error("[terrain_mask] missing y attribute")
if alignment == "even" then
is_odd = false
elseif alignment == "odd" then
is_odd = true
elseif alignment == "raw" then
--todo: maybe rename this value?
is_odd = (number % 2 != 0)
elseif border == false then
is_odd = true
else
is_odd = false
-- the old [terrain_mask] code would insert the terrain as one
-- tile to the northwest from the specified hex.
-- todo: deprecate this strange behaviour or at least not make it
-- the default behaviour anymore.
local new_loc = wesnoth.map.get_direction({x, y}, "nw")
x, y = new_loc[1], new_loc[2]
end
local rules = {}
for rule in wml.child_range(cfg, 'rule') do
rules[#rules] = rule
end
if cfg.mask_file then
mask = wesnoth.read_file(cfg.mask_file)
end
wesnoth.terrain_mask({x, y}, mask, {
is_odd = is_odd,
rules = rules,
ignore_special_locations = cfg.ignore_special_locations,
})
end

View file

@ -303,7 +303,7 @@ IMPLEMENT_ACTION(apply_mask)
void editor_action_apply_mask::perform_without_undo(map_context& mc) const
{
mc.map().overlay(mask_, config(), {0, 0});
mc.map().overlay(mask_, {0, 0, wml_loc()});
mc.set_needs_terrain_rebuild();
}

View file

@ -283,10 +283,6 @@ boost::optional<std::string> game_board::replace_map(const gamemap & newmap) {
return ret;
}
void game_board::overlay_map(const gamemap & mask_map, const config & cfg, map_location loc) {
map_->overlay_old(mask_map, cfg, loc);
}
bool game_board::change_terrain(const map_location &loc, const std::string &t_str,
const std::string & mode_str, bool replace_if_failed)
{

View file

@ -155,8 +155,7 @@ public:
// Manipulator from actionwml
bool try_add_unit_to_recall_list(const map_location& loc, const unit_ptr u);
boost::optional<std::string> replace_map (const gamemap & r);
void overlay_map(const gamemap & o, const config & cfg, map_location loc);
boost::optional<std::string> replace_map(const gamemap & r);
bool change_terrain(const map_location &loc, const std::string &t,
const std::string & mode, bool replace_if_failed); //used only by lua

View file

@ -862,41 +862,6 @@ WML_HANDLER_FUNCTION(store_time_of_day,, cfg)
}
}
/// Creating a mask of the terrain
WML_HANDLER_FUNCTION(terrain_mask,, cfg)
{
map_location loc = cfg_to_loc(cfg, 1, 1);
gamemap mask_map(resources::gameboard->map().tdata(), "");
try {
if(!cfg["mask_file"].empty()) {
const std::string& maskfile = filesystem::get_wml_location(cfg["mask_file"].str());
if(filesystem::file_exists(maskfile)) {
mask_map.read(filesystem::read_file(maskfile), false);
} else {
throw incorrect_map_format_error("Invalid file path");
}
} else {
mask_map.read(cfg["mask"], false);
}
} catch(const incorrect_map_format_error&) {
ERR_NG << "terrain mask is in the incorrect format, and couldn't be applied" << std::endl;
return;
} catch(const wml_exception& e) {
e.show();
return;
}
if (!cfg["border"].to_bool(true)) {
mask_map.add_fog_border();
}
resources::gameboard->overlay_map(mask_map, cfg.get_parsed_config(), loc);
game_display::get_singleton()->needs_rebuild(true);
}
WML_HANDLER_FUNCTION(tunnel,, cfg)
{
const bool remove = cfg["remove"].to_bool(false);

View file

@ -207,74 +207,6 @@ std::string gamemap::write() const
return t_translation::write_game_map(tiles_, starting_positions_, t_translation::coordinate{ border_size(), border_size() }) + "\n";
}
void gamemap::overlay_old(const gamemap& m, const config& rules_cfg, map_location loc)
{
int xpos = loc.x;
int ypos = loc.y;
//const config::const_child_itors &rules = rules_cfg.child_range("rule");
std::vector<overlay_rule> rules(rules_cfg.child_count("rule"));
for(std::size_t i = 0; i <rules.size(); ++i)
{
const config& cfg = rules_cfg.child("rule", i);
rules[i].old_ = t_translation::read_list(cfg["old"].str());
rules[i].new_ = t_translation::read_list(cfg["new"].str());
rules[i].mode_ = cfg["layer"] == "base" ? terrain_type_data::BASE : cfg["layer"] == "overlay" ? terrain_type_data::OVERLAY : terrain_type_data::BOTH;
const t_translation::ter_list& terrain = t_translation::read_list(cfg["terrain"].str());
if(!terrain.empty()) {
rules[i].terrain_ = terrain[0];
}
rules[i].use_old_ = cfg["use_old"].to_bool();
rules[i].replace_if_failed_ = cfg["replace_if_failed"].to_bool();
}
const int xstart = std::max<int>(-border_size(), -xpos - border_size());
const int ystart = std::max<int>(-border_size(), -ypos - border_size() - ((xpos & 1) ? 1 : 0));
const int xend = std::min<int>(m.w() + border_size(), w() + border_size() - xpos);
const int yend = std::min<int>(m.h() + border_size(), h() + border_size() - ypos);
for(int x1 = xstart; x1 < xend; ++x1) {
for(int y1 = ystart; y1 < yend; ++y1) {
const int x2 = x1 + xpos;
const int y2 = y1 + ypos + ((xpos & 1) && (x1 & 1) ? 1 : 0);
const t_translation::terrain_code t = m[{x1,y1}];
const t_translation::terrain_code current = (*this)[{x2, y2}];
if(t == t_translation::FOGGED || t == t_translation::VOID_TERRAIN) {
continue;
}
// See if there is a matching rule
const overlay_rule* rule = nullptr;
for(const overlay_rule& current_rule : rules)
{
if(!current_rule.old_.empty() && !t_translation::terrain_matches(current, current_rule.old_)) {
continue;
}
if(!current_rule.new_.empty() && !t_translation::terrain_matches(t, current_rule.new_)) {
continue;
}
rule = &current_rule;
break;
}
if (!rule) {
set_terrain(map_location(x2, y2), t);
}
else if(!rule->use_old_) {
set_terrain(map_location(x2, y2), rule->terrain_ ? *rule->terrain_ : t , rule->mode_, rule->replace_if_failed_);
}
}
}
if (!rules_cfg["ignore_special_locations"].to_bool(false)) {
for(auto& pair : m.starting_positions_.left) {
starting_positions_.left.erase(pair.first);
starting_positions_.insert(starting_positions::value_type(pair.first, t_translation::coordinate(pair.second.x + xpos, pair.second.y + ypos+ ((xpos & 1) && (pair.second.x & 1) ? 1 : 0))));
}
}
}
void gamemap::overlay(const gamemap& m, map_location loc, const std::vector<overlay_rule>& rules, bool m_is_odd, bool ignore_special_locations)
{
int xpos = loc.wml_x();
@ -510,16 +442,3 @@ std::vector<map_location> gamemap::parse_location_range(const std::string &x, co
}
return res;
}
void gamemap::add_fog_border()
{
t_translation::ter_map tiles_new(tiles_.w + 1, tiles_.h + 1);
for (int x = 0, x_end = tiles_new.w; x != x_end; ++x) {
for (int y = 0, y_end = tiles_new.h; y != y_end; ++y) {
tiles_new.get(x, y) = (x == 0 || y == 0) ? t_translation::VOID_TERRAIN : tiles_.get(x - 1, y - 1);
}
}
++w_;
++h_;
tiles_ = tiles_new;
}

View file

@ -107,8 +107,7 @@ public:
};
/** Overlays another map onto this one at the given position. */
void overlay_old(const gamemap& m, const config& rules, map_location loc);
void overlay(const gamemap& m, map_location loc, const std::vector<overlay_rule>& rules, bool is_odd, bool ignore_special_locations);
void overlay(const gamemap& m, map_location loc, const std::vector<overlay_rule>& rules = std::vector<overlay_rule>(), bool is_odd = false, bool ignore_special_locations = false);
/** Effective map width. */
int w() const { return w_; }
@ -229,7 +228,7 @@ public:
}
}
}
void add_fog_border();
protected:
t_translation::ter_map tiles_;