[Lua.Mapgen] Add a few more ways to pass a location set to f.find_in

These may be less efficient in some cases, and there's even a couple of degenerate cases, but it's definitely easier to use like this.

This also adds an example of the original method, using a string to reference a separate list.
This commit is contained in:
Celtic Minstrel 2024-02-07 01:34:11 -05:00 committed by Celtic Minstrel
parent 4c4b30aaac
commit 19f3682bdf
2 changed files with 63 additions and 7 deletions

View file

@ -384,11 +384,24 @@ if wesnoth.kernel_type() == "Mapgen Lua Kernel" then
return { "adjacent", f, adjacent = adj, count = count }
end,
---Match hexes from a separate list.
---Specify the list in the second argument to wesnoth.map.filter()
---@param terrain string
---When passing a locset_ref, specify the list
---in the second argument to wesnoth.map.filter()
---
---For example:
---```
---local M = wesnoth.map.create(128, 128, 'Gg')
---local f = wesnoth.map.filter_tags
---local found = M:find(f.find_in("choices"), {choices = {{1,2}, {5,6}}})
---```
---@param x integer
---@param y integer
---@return terrain_filter_tag
find_in = function(terrain)
return { "find_in", terrain }
---@overload fun(xs:string, ys:string):terrain_filter_tag
---@overload fun(loc:location):terrain_filter_tag
---@overload fun(locs:location[]):terrain_filter_tag
---@overload fun(locset_ref:string):terrain_filter_tag
find_in = function(x, y)
return { "find_in", x, y }
end,
---Match hexes within a given distance
---@param r integer

View file

@ -467,10 +467,52 @@ public:
: set_(nullptr)
{
LOG_LMG << "creating findin filter";
lua_geti(L, -1, 2);
std::string id = std::string(luaW_tostring(L, -1));
lua_pop(L, 1);
int idx = lua_absindex(L, -1);
switch(lua_geti(L, idx, 2)) {
case LUA_TTABLE:
// Also accepts a single location of the form {x,y} or {x=x,y=y}
init_from_inline_set(luaW_to_locationset(L, -1));
break;
case LUA_TNUMBER:
lua_geti(L, idx, 3);
init_from_single_loc(luaL_checkinteger(L, -2), luaL_checkinteger(L, -1));
break;
case LUA_TSTRING:
if(lua_geti(L, idx, 3) == LUA_TSTRING) {
init_from_ranges(luaL_checkstring(L, -2), luaL_checkstring(L, -1));
} else {
init_from_named_set(L, luaL_checkstring(L, -1), res_index, ks);
}
break;
}
lua_settop(L, idx);
}
void init_from_inline_set(const location_set& locs) {
inline_ = locs;
set_ = &inline_;
}
void init_from_single_loc(int x, int y) {
map_location loc(x, y, wml_loc());
inline_.insert(loc);
set_ = &inline_;
}
void init_from_ranges(const std::string& xs, const std::string& ys) {
auto xvals = utils::parse_ranges_unsigned(xs), yvals = utils::parse_ranges_unsigned(ys);
// TODO: Probably error if they're different sizes?
for(size_t i = 0; i < std::min(xvals.size(), yvals.size()); i++) {
for(int x = xvals[i].first; x <= xvals[i].second; x++) {
for(int y = yvals[i].first; y <= yvals[i].second; y++) {
inline_.insert(map_location(x, y, wml_loc()));
}
}
}
set_ = &inline_;
}
void init_from_named_set(lua_State* L, const std::string& id, int res_index, known_sets_t& ks) {
//TODO: c++14: use heterogenous lookup.
auto insert_res = ks.insert(known_sets_t::value_type{id, {}});
if(insert_res.second && res_index > 0) {
@ -491,6 +533,7 @@ public:
return false;
}
const location_set* set_;
location_set inline_;
};
class radius_filter : public filter_impl