From c32ae8146e6a22e1e6e1e45be1246369bbd3b8a3 Mon Sep 17 00:00:00 2001 From: Celtic Minstrel Date: Tue, 10 Sep 2024 22:38:34 -0400 Subject: [PATCH] Lua API: Add __dir metamethod to unit variables and unit statuses --- src/scripting/lua_unit.cpp | 56 ++++++++++++++++++++++++++++++++++++++ src/units/unit.cpp | 10 +++++++ src/units/unit.hpp | 6 ++++ 3 files changed, 72 insertions(+) diff --git a/src/scripting/lua_unit.cpp b/src/scripting/lua_unit.cpp index a2965f5fee3..1f48f098c35 100644 --- a/src/scripting/lua_unit.cpp +++ b/src/scripting/lua_unit.cpp @@ -832,6 +832,32 @@ static int impl_unit_status_set(lua_State *L) return 0; } +/** + * List statuses on a unit (__dir metamethod) + * This returns all known statuses (regardless of state) plus any currently set to true. + */ +static int impl_unit_status_dir(lua_State *L) +{ + if(!lua_istable(L, 1)) { + return luaW_type_error(L, 1, "unit status"); + } + lua_rawgeti(L, 1, 1); + unit* u = luaW_tounit(L, -1); + if(!u) { + return luaL_argerror(L, 1, "unknown unit"); + } + std::vector states; + states.reserve(unit::NUMBER_OF_STATES); + for(unit::state_t s = unit::STATE_SLOWED; s < unit::NUMBER_OF_STATES; s = unit::state_t(s + 1)) { + states.push_back(unit::get_known_boolean_state_name(s)); + } + for(auto s : u->get_states()) { + states.push_back(s); + } + lua_push(L, states); + return 1; +} + /** * Gets the variable of a unit (__index metamethod). * - Arg 1: table containing the userdata containing the unit id. @@ -886,6 +912,32 @@ static int impl_unit_variables_set(lua_State *L) return 0; } +/** + * List variables on a unit (__dir metamethod) + */ +static int impl_unit_variables_dir(lua_State *L) +{ + if(!lua_istable(L, 1)) { + return luaW_type_error(L, 1, "unit variables"); + } + lua_rawgeti(L, 1, 1); + unit* u = luaW_tounit(L, -1); + if(!u) { + return luaL_argerror(L, 2, "unknown unit"); + } + config& vars = u->variables(); + std::vector variables; + variables.reserve(vars.attribute_count() + vars.all_children_count()); + for(const auto& attr : vars.attribute_range()) { + variables.push_back(attr.first); + } + for(auto attr : vars.all_children_range()) { + variables.push_back(attr.key); + } + lua_push(L, variables); + return 1; +} + namespace lua_units { std::string register_metatables(lua_State* L) { @@ -918,6 +970,8 @@ namespace lua_units { lua_setfield(L, -2, "__index"); lua_pushcfunction(L, impl_unit_status_set); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, impl_unit_status_dir); + lua_setfield(L, -2, "__dir"); lua_pushstring(L, "unit status"); lua_setfield(L, -2, "__metatable"); @@ -929,6 +983,8 @@ namespace lua_units { lua_setfield(L, -2, "__index"); lua_pushcfunction(L, impl_unit_variables_set); lua_setfield(L, -2, "__newindex"); + lua_pushcfunction(L, impl_unit_variables_dir); + lua_setfield(L, -2, "__dir"); lua_pushstring(L, "unit variables"); lua_setfield(L, -2, "__metatable"); diff --git a/src/units/unit.cpp b/src/units/unit.cpp index 56c23addd7d..9f136ef414b 100644 --- a/src/units/unit.cpp +++ b/src/units/unit.cpp @@ -1357,6 +1357,16 @@ unit::state_t unit::get_known_boolean_state_id(const std::string& state) return STATE_UNKNOWN; } +std::string unit::get_known_boolean_state_name(state_t state) +{ + for(const auto& p : known_boolean_state_names_) { + if(p.second == state) { + return p.first; + } + } + return ""; +} + std::map unit::known_boolean_state_names_ { {"slowed", STATE_SLOWED}, {"poisoned", STATE_POISONED}, diff --git a/src/units/unit.hpp b/src/units/unit.hpp index a6c8feb3cc6..8894d25b2c5 100644 --- a/src/units/unit.hpp +++ b/src/units/unit.hpp @@ -889,6 +889,12 @@ public: */ static state_t get_known_boolean_state_id(const std::string& state); + /** + * Convert a built-in status effect ID to a string status effect ID + * @returns the string representing the status, or an empty string for STATE_UNKNOWN + */ + static std::string get_known_boolean_state_name(state_t state); + /** * Check if the unit has been poisoned * @returns true if it's poisoned