add wesnoth.terrain_mask lua function
`[terrain_mask]` had multiple unexpected behviours, see for example #3364 in parituclar `wesnoth.wml_actions.terrain_mask { x =2, y=2, mask="Ww"}` will change the tile at (1,2) instead of (2,2), so instead of reusing the old terrain mask code i wrote a new function that behaves as one would expect. `wesnoth.terrain_mask` does not have a `border=` parameter but a `is_odd` parameter that specifies that a map is in the odd format __ __ /00\__/20\__ \__/10\__/30\ /01\__/21\__/ \__/11\__/31\ /02\__/22\__/ \__/ \__/ instead of the even map format __ __ __/10\__/30\ /00\__/20\__/ \__/11\__/31\ /01\__/21\__/ \__/12\__/32\ \__/ \__/ (Monospaced font required to see ascii images.) The lua function also has a lua interfacte, meaning it does not take wml tables but normal lua tables making it easier to use from lua code.
This commit is contained in:
parent
8d6524c6e2
commit
a3367ee848
6 changed files with 222 additions and 28 deletions
|
@ -283,10 +283,8 @@ 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(mask_map, cfg, loc);
|
||||
map_->overlay_old(mask_map, cfg, loc);
|
||||
}
|
||||
|
||||
bool game_board::change_terrain(const map_location &loc, const std::string &t_str,
|
||||
|
|
|
@ -156,7 +156,7 @@ public:
|
|||
|
||||
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);
|
||||
void overlay_map(const gamemap & o, const config & cfg, map_location loc);
|
||||
|
||||
bool change_terrain(const map_location &loc, const std::string &t,
|
||||
const std::string & mode, bool replace_if_failed); //used only by lua
|
||||
|
|
107
src/map/map.cpp
107
src/map/map.cpp
|
@ -205,30 +205,8 @@ std::string gamemap::write() const
|
|||
{
|
||||
return t_translation::write_game_map(tiles_, starting_positions_, t_translation::coordinate{ border_size(), border_size() }) + "\n";
|
||||
}
|
||||
namespace
|
||||
{
|
||||
struct overlay_rule
|
||||
{
|
||||
t_translation::ter_list old_;
|
||||
t_translation::ter_list new_;
|
||||
terrain_type_data::merge_mode mode_;
|
||||
boost::optional<t_translation::terrain_code> terrain_;
|
||||
bool use_old_;
|
||||
bool replace_if_failed_;
|
||||
|
||||
overlay_rule()
|
||||
: old_()
|
||||
, new_()
|
||||
, mode_(terrain_type_data::BOTH)
|
||||
, terrain_()
|
||||
, use_old_(false)
|
||||
, replace_if_failed_(false)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
void gamemap::overlay(const gamemap& m, const config& rules_cfg, map_location loc)
|
||||
void gamemap::overlay_old(const gamemap& m, const config& rules_cfg, map_location loc)
|
||||
{
|
||||
int xpos = loc.x;
|
||||
int ypos = loc.y;
|
||||
|
@ -296,6 +274,89 @@ void gamemap::overlay(const gamemap& m, const config& rules_cfg, map_location lo
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
int ypos = loc.wml_y();
|
||||
|
||||
const int xstart = std::max<int>(0, -xpos);
|
||||
const int xend = std::min<int>(m.total_width(), total_width() -xpos);
|
||||
const int xoffset = xpos;
|
||||
|
||||
const int ystart_even = std::max<int>(0, -ypos);
|
||||
const int yend_even = std::min<int>(m.total_height(), total_height() - ypos);
|
||||
const int yoffset_even = ypos;
|
||||
|
||||
const int ystart_odd = std::max<int>(0, -ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
|
||||
const int yend_odd = std::min<int>(m.total_height(), total_height() - ypos +(xpos & 1) -(m_is_odd ? 1 : 0));
|
||||
const int yoffset_odd = ypos -(xpos & 1) + (m_is_odd ? 1 : 0);
|
||||
|
||||
for(int x1 = xstart; x1 != xend; ++x1) {
|
||||
int ystart, yend, yoffset;
|
||||
if(x1 & 1) {
|
||||
ystart = ystart_odd , yend = yend_odd , yoffset = yoffset_odd;
|
||||
}
|
||||
else {
|
||||
ystart = ystart_even, yend = yend_even, yoffset = yoffset_even;
|
||||
}
|
||||
for(int y1 = ystart; y1 != yend; ++y1) {
|
||||
const int x2 = x1 + xoffset;
|
||||
const int y2 = y1 + yoffset;//ypos + ((xpos & 1) && (x1 & 1) ? 1 : 0);
|
||||
|
||||
const t_translation::terrain_code t = m.tiles_.get(x1,y1);
|
||||
const t_translation::terrain_code current = tiles_.get(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 = ¤t_rule;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!rule) {
|
||||
set_terrain(map_location(x2, y2, wml_loc()), t);
|
||||
}
|
||||
else if(!rule->use_old_) {
|
||||
set_terrain(map_location(x2, y2, wml_loc()), rule->terrain_ ? *rule->terrain_ : t , rule->mode_, rule->replace_if_failed_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ignore_special_locations) {
|
||||
for(auto& pair : m.starting_positions_.left) {
|
||||
|
||||
int x = pair.second.wml_x();
|
||||
int y = pair.second.wml_y();
|
||||
if(x & 1) {
|
||||
if(x < xstart || x >= xend || y < ystart_odd || y >= yend_odd) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(x < xstart || x >= xend || y < ystart_even || y >= yend_even) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int x_new = x + xoffset;
|
||||
int y_new = y + ((x & 1 ) ? yoffset_odd : yoffset_even);
|
||||
map_location pos_new = map_location(x_new, y_new, wml_loc());
|
||||
|
||||
starting_positions_.left.erase(pair.first);
|
||||
starting_positions_.insert(starting_positions::value_type(pair.first, t_translation::coordinate(pos_new.x, pos_new.y)));
|
||||
}
|
||||
}
|
||||
}
|
||||
t_translation::terrain_code gamemap::get_terrain(const map_location& loc) const
|
||||
{
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ class config;
|
|||
#include "terrain/translation.hpp"
|
||||
#include "terrain/type_data.hpp"
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
//class terrain_type_data; Can't forward declare because of enum
|
||||
|
||||
/**
|
||||
|
@ -83,8 +85,30 @@ public:
|
|||
|
||||
std::string write() const;
|
||||
|
||||
struct overlay_rule
|
||||
{
|
||||
t_translation::ter_list old_;
|
||||
t_translation::ter_list new_;
|
||||
terrain_type_data::merge_mode mode_;
|
||||
boost::optional<t_translation::terrain_code> terrain_;
|
||||
bool use_old_;
|
||||
bool replace_if_failed_;
|
||||
|
||||
overlay_rule()
|
||||
: old_()
|
||||
, new_()
|
||||
, mode_(terrain_type_data::BOTH)
|
||||
, terrain_()
|
||||
, use_old_(false)
|
||||
, replace_if_failed_(false)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
/** Overlays another map onto this one at the given position. */
|
||||
void overlay(const gamemap& m, const config& rules, map_location loc);
|
||||
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);
|
||||
|
||||
/** Effective map width. */
|
||||
int w() const { return w_; }
|
||||
|
|
|
@ -1011,6 +1011,115 @@ int game_lua_kernel::intf_set_terrain(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool luaW_tableget(lua_State *L, int index, const char* key)
|
||||
{
|
||||
lua_pushstring(L, key);
|
||||
lua_gettable(L, index);
|
||||
if(lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static utils::string_view luaW_tostring(lua_State *L, int index)
|
||||
{
|
||||
size_t len = 0;
|
||||
const char* str = lua_tolstring (L, index, &len);
|
||||
return utils::string_view(str, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaplces part of rhe map.
|
||||
* - Arg 1: map location.
|
||||
* - Arg 2: map data string.
|
||||
* - Arg 3: table for optional named arguments
|
||||
* - is_odd: boolen, if Arg2 has the odd mapo format (as if it was cut from a odd map location)
|
||||
* - ignore_special_locations: boolean
|
||||
* - rules: table of tables
|
||||
*/
|
||||
int game_lua_kernel::intf_terrain_mask(lua_State *L)
|
||||
{
|
||||
map_location loc = luaW_checklocation(L, 1);
|
||||
std::string t_str(luaL_checkstring(L, 2));
|
||||
bool is_odd = false;
|
||||
bool ignore_special_locations = false;
|
||||
std::vector<gamemap::overlay_rule> rules;
|
||||
|
||||
if(lua_istable(L, 3)) {
|
||||
if(luaW_tableget(L, 3, "is_odd")) {
|
||||
is_odd = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if(luaW_tableget(L, 3, "ignore_special_locations")) {
|
||||
ignore_special_locations = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
if(luaW_tableget(L, 3, "rules")) {
|
||||
if(!lua_istable(L, -1)) {
|
||||
return luaL_argerror(L, 3, "rules must be a table");
|
||||
}
|
||||
|
||||
for (int i = 1, i_end = lua_rawlen(L, -1); i <= i_end; ++i)
|
||||
{
|
||||
lua_rawgeti(L, -1, i);
|
||||
if(!lua_istable(L, -1)) {
|
||||
return luaL_argerror(L, 3, "rules must be a table of tables");
|
||||
}
|
||||
rules.push_back(gamemap::overlay_rule());
|
||||
auto& rule = rules.back();
|
||||
if(luaW_tableget(L, -1, "old")) {
|
||||
rule.old_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "new")) {
|
||||
rule.new_ = t_translation::read_list(luaW_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "mode")) {
|
||||
auto str = luaW_tostring(L, -1);
|
||||
rule.mode_ = str == "base" ? terrain_type_data::BASE : (str == "overlay" ? terrain_type_data::OVERLAY : terrain_type_data::BOTH);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "terrain")) {
|
||||
const t_translation::ter_list terrain = t_translation::read_list(luaW_tostring(L, -1));
|
||||
if(!terrain.empty()) {
|
||||
rule.terrain_ = terrain[0];
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "use_old")) {
|
||||
rule.use_old_ = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
if(luaW_tableget(L, -1, "replace_if_failed")) {
|
||||
rule.replace_if_failed_ = luaW_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gamemap mask_map(resources::gameboard->map().tdata(), "");
|
||||
mask_map.read(t_str, false);
|
||||
board().map_->overlay(mask_map, loc, rules, is_odd, ignore_special_locations);
|
||||
|
||||
if (game_display_) {
|
||||
game_display_->needs_rebuild(true);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets details about a terrain.
|
||||
* - Arg 1: terrain code string.
|
||||
|
@ -4112,6 +4221,7 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
|
|||
{ "switch_ai", &intf_switch_ai },
|
||||
{ "synchronize_choice", &intf_synchronize_choice },
|
||||
{ "synchronize_choices", &intf_synchronize_choices },
|
||||
{ "terrain_mask", &dispatch<&game_lua_kernel::intf_terrain_mask > },
|
||||
{ "zoom", &dispatch<&game_lua_kernel::intf_zoom > },
|
||||
{ "teleport", &dispatch<&game_lua_kernel::intf_teleport > },
|
||||
{ "unit_ability", &dispatch<&game_lua_kernel::intf_unit_ability > },
|
||||
|
|
|
@ -91,6 +91,7 @@ class game_lua_kernel : public lua_kernel_base
|
|||
int intf_lock_view(lua_State *L);
|
||||
int intf_get_terrain(lua_State *L);
|
||||
int intf_set_terrain(lua_State *L);
|
||||
int intf_terrain_mask(lua_State *L);
|
||||
int intf_get_terrain_info(lua_State *L);
|
||||
int intf_get_time_of_day(lua_State *L);
|
||||
int intf_get_village_owner(lua_State *L);
|
||||
|
|
Loading…
Add table
Reference in a new issue