From 6a0a7e3926264d0636afd22d03a8e48641e168f5 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Fri, 19 Feb 2021 21:24:32 -0500 Subject: [PATCH] Implement a map iterator --- src/scripting/game_lua_kernel.cpp | 1 + src/scripting/lua_terrainmap.cpp | 74 +++++++++++++++++++++++++++++++ src/scripting/lua_terrainmap.hpp | 1 + 3 files changed, 76 insertions(+) diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 217b31fa29fd9..6808be2c8e95e 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -4138,6 +4138,7 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports {"terrain_mask", &intf_terrain_mask}, {"on_board", &intf_on_board}, {"on_border", &intf_on_border}, + {"iter", &intf_terrainmap_iter}, // Shroud operations {"place_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, true>}, {"remove_shroud", &dispatch2<&game_lua_kernel::intf_shroud_op, false>}, diff --git a/src/scripting/lua_terrainmap.cpp b/src/scripting/lua_terrainmap.cpp index c485082ef0e78..6b36f2515c441 100644 --- a/src/scripting/lua_terrainmap.cpp +++ b/src/scripting/lua_terrainmap.cpp @@ -345,6 +345,80 @@ static int impl_terrainmap_set(lua_State *L) return luaL_argerror(L, 2, err_msg.c_str()); } +/* +The map iterator, when called with false as its parameter +is roughly equivalent to the following Lua function: + +function map_iter() + local map, x, y = wesnoth.map.get(), 0, 1 + return function() + if x == map.playable_width then + if y == map.playable_height then + return nil + else + x, y = 1, y + 1 + end + else + x = x + 1 + end + return x, y, map[{x, y}] + end +end + +*/ + +template +static int impl_terrainmap_iter(lua_State* L) +{ + // Retrieve the upvalues stored with the function + gamemap_base& tm = luaW_checkterrainmap(L, lua_upvalueindex(1)); + map_location prev_loc = luaW_checklocation(L, lua_upvalueindex(2)); + int w = with_border ? tm.total_width() - 1 : tm.w(); + int h = with_border ? tm.total_height() - 1 : tm.h(); + int x, y; + + // Given the previous location, determine the next one to be returned + if(prev_loc.wml_x() == w) { + if(prev_loc.wml_y() == h) { + lua_pushnil(L); + return 1; + } else { + x = with_border ? 0 : 1; + y = prev_loc.wml_y() + 1; + } + } else { + x = prev_loc.wml_x() + 1; + y = prev_loc.wml_y(); + } + + // Assign the upvalue representing the previous location + map_location next_loc(x, y, wml_loc{}); + luaW_pushlocation(L, next_loc); + lua_replace(L, lua_upvalueindex(2)); + + // Return the new location and its terrain code + lua_pushinteger(L, x); + lua_pushinteger(L, y); + luaW_push_terrain(L, tm, next_loc); + + return 3; +} + +static int intf_terrainmap_iter(lua_State* L) +{ + gamemap_base& tm = luaW_checkterrainmap(L, 1); + bool with_border = lua_isboolean(L, 2) ? luaW_toboolean(L, 2) : false; + lua_settop(L, 1); + luaW_pushlocation(L, map_location(with_border ? -1 : 0, 1, wml_loc{})); + + if(with_border) { + lua_pushcclosure(L, impl_terrainmap_iter, 2); + } else { + lua_pushcclosure(L, impl_terrainmap_iter, 2); + } + return 1; +} + static int intf_on_board(lua_State* L) { gamemap_base& tm = luaW_checkterrainmap(L, 1); diff --git a/src/scripting/lua_terrainmap.hpp b/src/scripting/lua_terrainmap.hpp index 450b539ab2db9..7e41044487ea9 100644 --- a/src/scripting/lua_terrainmap.hpp +++ b/src/scripting/lua_terrainmap.hpp @@ -58,6 +58,7 @@ int intf_terrainmap_create(lua_State *L); int intf_terrainmap_get(lua_State *L); int intf_replace_if_failed(lua_State* L); +int intf_terrainmap_iter(lua_State* L); int intf_on_board(lua_State* L); int intf_on_border(lua_State* L);