Lua API: Add __dir metamethod for wesnoth.game_config

This commit is contained in:
Celtic Minstrel 2024-09-12 20:21:30 -04:00 committed by Celtic Minstrel
parent 03924aac1d
commit 6f0567df8f
4 changed files with 166 additions and 105 deletions

View file

@ -1322,65 +1322,63 @@ static int intf_get_era(lua_State *L)
return 1;
}
/**
* Gets some game_config data (__index metamethod).
* - Arg 1: userdata (ignored).
* - Arg 2: string containing the name of the property.
* - Ret 1: something containing the attribute.
*/
int game_lua_kernel::impl_game_config_get(lua_State *L)
{
DBG_LUA << "impl_game_config_get";
char const *m = luaL_checkstring(L, 2);
extern luaW_Registry& gameConfigReg();
static auto& dummy = gameConfigReg(); // just to ensure it's constructed.
// Find the corresponding attribute.
return_bool_attrib("do_healing", play_controller_.gamestate().do_healing_);
return_string_attrib("theme", gamedata().get_theme());
struct game_config_glk_tag {
game_lua_kernel& ref;
game_config_glk_tag(lua_kernel_base& k) : ref(dynamic_cast<game_lua_kernel&>(k)) {}
auto& pc() const { return ref.play_controller_; }
auto& gamedata() const { return ref.gamedata(); }
auto& disp() const { return ref.game_display_; }
};
#define GAME_CONFIG_SIMPLE_SETTER(name) \
GAME_CONFIG_SETTER(#name, decltype(game_config::name), game_lua_kernel) { \
(void) k; \
game_config::name = value; \
}
if(strcmp(m, "global_traits") == 0) {
lua_newtable(L);
for(const config& trait : unit_types.traits()) {
const std::string& id = trait["id"];
//It seems the engine never checks the id field for emptiness or duplicates
//However, the worst that could happen is that the trait read later overwrites the older one,
//and this is not the right place for such checks.
lua_pushstring(L, id.c_str());
luaW_pushconfig(L, trait);
lua_rawset(L, -3);
}
return 1;
GAME_CONFIG_GETTER("do_healing", bool, game_lua_kernel) {
game_config_glk_tag k2{k.ref};
return k2.pc().gamestate().do_healing_;
}
GAME_CONFIG_SETTER("do_healing", bool, game_lua_kernel) {
game_config_glk_tag k2{k.ref};
k2.pc().gamestate().do_healing_ = value;}
GAME_CONFIG_GETTER("theme", std::string, game_lua_kernel) {
game_config_glk_tag k2{k.ref};
return k2.gamedata().get_theme();
}
GAME_CONFIG_SETTER("theme", std::string, game_lua_kernel) {
game_config_glk_tag k2{k.ref};
k2.gamedata().set_theme(value);
k2.disp()->set_theme(value);
}
using traits_map = std::map<std::string, config>;
GAME_CONFIG_GETTER("global_traits", traits_map, game_lua_kernel) {
(void)k;
std::map<std::string, config> result;
for(const config& trait : unit_types.traits()) {
//It seems the engine never checks the id field for emptiness or duplicates
//However, the worst that could happen is that the trait read later overwrites the older one,
//and this is not the right place for such checks.
result.emplace(trait["id"], trait);
}
return lua_kernel_base::impl_game_config_get(L);
return result;
}
/**
* Sets some game_config data (__newindex metamethod).
* - Arg 1: userdata (ignored).
* - Arg 2: string containing the name of the property.
* - Arg 3: something containing the attribute.
*/
int game_lua_kernel::impl_game_config_set(lua_State *L)
{
DBG_LUA << "impl_game_config_set";
char const *m = luaL_checkstring(L, 2);
// Find the corresponding attribute.
modify_int_attrib("base_income", game_config::base_income = value);
modify_int_attrib("village_income", game_config::village_income = value);
modify_int_attrib("village_support", game_config::village_support = value);
modify_int_attrib("poison_amount", game_config::poison_amount = value);
modify_int_attrib("rest_heal_amount", game_config::rest_heal_amount = value);
modify_int_attrib("recall_cost", game_config::recall_cost = value);
modify_int_attrib("kill_experience", game_config::kill_experience = value);
modify_int_attrib("combat_experience", game_config::combat_experience = value);
modify_bool_attrib("do_healing", play_controller_.gamestate().do_healing_ = value);
modify_string_attrib("theme",
gamedata().set_theme(value);
game_display_->set_theme(value);
);
return lua_kernel_base::impl_game_config_set(L);
}
GAME_CONFIG_SIMPLE_SETTER(base_income);
GAME_CONFIG_SIMPLE_SETTER(village_income);
GAME_CONFIG_SIMPLE_SETTER(village_support);
GAME_CONFIG_SIMPLE_SETTER(poison_amount);
GAME_CONFIG_SIMPLE_SETTER(rest_heal_amount);
GAME_CONFIG_SIMPLE_SETTER(recall_cost);
GAME_CONFIG_SIMPLE_SETTER(kill_experience);
GAME_CONFIG_SIMPLE_SETTER(combat_experience);
namespace {
static config find_addon(const std::string& type, const std::string& id)

View file

@ -71,6 +71,7 @@ class game_lua_kernel : public lua_kernel_base
friend struct current_tag;
friend struct scenario_tag;
friend struct schedule_tag;
friend struct game_config_glk_tag;
// Private lua callbacks
int intf_allow_end_turn(lua_State *);
@ -105,8 +106,6 @@ class game_lua_kernel : public lua_kernel_base
int intf_set_village_owner(lua_State *L);
int intf_get_mouseover_tile(lua_State *L);
int intf_get_selected_tile(lua_State *L);
int impl_game_config_get(lua_State *L) override;
int impl_game_config_set(lua_State *L) override;
int impl_scenario_get(lua_State *L);
int impl_scenario_set(lua_State *L);
int impl_scenario_dir(lua_State *L);

View file

@ -29,6 +29,7 @@
#include "scripting/debug_lua.hpp"
#endif
#include "scripting/lua_attributes.hpp"
#include "scripting/lua_color.hpp"
#include "scripting/lua_common.hpp"
#include "scripting/lua_cpp_function.hpp"
@ -908,6 +909,8 @@ lua_kernel_base::lua_kernel_base()
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_set>);
lua_setfield(L, -2, "__newindex");
lua_pushcfunction(L, &dispatch<&lua_kernel_base::impl_game_config_dir>);
lua_setfield(L, -2, "__dir");
lua_pushstring(L, "game config");
lua_setfield(L, -2, "__metatable");
lua_setmetatable(L, -2);
@ -1253,58 +1256,99 @@ static int impl_palette_get(lua_State* L)
push_color_palette(L, game_config::tc_info(m));
return 1;
}
// suppress missing prototype warning (not static because game_lua_kernel referenes it);
luaW_Registry& gameConfigReg();
luaW_Registry& gameConfigReg() {
static luaW_Registry gameConfigReg{"game config"};
return gameConfigReg;
}
static auto& dummy = gameConfigReg(); // just to ensure it's constructed.
#define GAME_CONFIG_SIMPLE_GETTER(name) \
GAME_CONFIG_GETTER(#name, decltype(game_config::name), lua_kernel_base) { \
(void) k; \
return game_config::name; \
}
GAME_CONFIG_SIMPLE_GETTER(base_income);
GAME_CONFIG_SIMPLE_GETTER(village_income);
GAME_CONFIG_SIMPLE_GETTER(village_support);
GAME_CONFIG_SIMPLE_GETTER(poison_amount);
GAME_CONFIG_SIMPLE_GETTER(rest_heal_amount);
GAME_CONFIG_SIMPLE_GETTER(recall_cost);
GAME_CONFIG_SIMPLE_GETTER(kill_experience);
GAME_CONFIG_SIMPLE_GETTER(combat_experience);
GAME_CONFIG_SIMPLE_GETTER(debug);
GAME_CONFIG_SIMPLE_GETTER(debug_lua);
GAME_CONFIG_SIMPLE_GETTER(strict_lua);
GAME_CONFIG_SIMPLE_GETTER(mp_debug);
GAME_CONFIG_GETTER("palettes", lua_index_raw, lua_kernel_base) {
(void)k;
lua_newtable(L);
if(luaL_newmetatable(L, "color palettes")) {
lua_pushcfunction(L, impl_palette_get);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return lua_index_raw(L);
}
GAME_CONFIG_GETTER("red_green_scale", lua_index_raw, lua_kernel_base) {
(void)k;
lua_pushstring(L, "red_green_scale");
push_color_palette(L, game_config::red_green_scale);
return lua_index_raw(L);
}
GAME_CONFIG_GETTER("red_green_scale_text", lua_index_raw, lua_kernel_base) {
(void)k;
lua_pushstring(L, "red_green_scale_text");
push_color_palette(L, game_config::red_green_scale_text);
return lua_index_raw(L);
}
GAME_CONFIG_GETTER("blue_white_scale", lua_index_raw, lua_kernel_base) {
(void)k;
lua_pushstring(L, "blue_white_scale");
push_color_palette(L, game_config::blue_white_scale);
return lua_index_raw(L);
}
GAME_CONFIG_GETTER("blue_white_scale_text", lua_index_raw, lua_kernel_base) {
(void)k;
lua_pushstring(L, "blue_white_scale_text");
push_color_palette(L, game_config::blue_white_scale_text);
return lua_index_raw(L);
}
/**
* Gets some game_config data (__index metamethod).
* - Arg 1: userdata (ignored).
* - Arg 2: string containing the name of the property.
* - Ret 1: something containing the attribute.
*/
int lua_kernel_base::impl_game_config_get(lua_State* L)
{
char const *m = luaL_checkstring(L, 2);
return_int_attrib("base_income", game_config::base_income);
return_int_attrib("village_income", game_config::village_income);
return_int_attrib("village_support", game_config::village_support);
return_int_attrib("poison_amount", game_config::poison_amount);
return_int_attrib("rest_heal_amount", game_config::rest_heal_amount);
return_int_attrib("recall_cost", game_config::recall_cost);
return_int_attrib("kill_experience", game_config::kill_experience);
return_int_attrib("combat_experience", game_config::combat_experience);
return_bool_attrib("debug", game_config::debug);
return_bool_attrib("debug_lua", game_config::debug_lua);
return_bool_attrib("strict_lua", game_config::strict_lua);
return_bool_attrib("mp_debug", game_config::mp_debug);
if(strcmp(m, "palettes") == 0) {
lua_newtable(L);
if(luaL_newmetatable(L, "color palettes")) {
lua_pushcfunction(L, impl_palette_get);
lua_setfield(L, -2, "__index");
}
lua_setmetatable(L, -2);
return 1;
}
if(strcmp(m, "red_green_scale") == 0) {
lua_pushstring(L, "red_green_scale");
push_color_palette(L, game_config::red_green_scale);
return 1;
}
if(strcmp(m, "red_green_scale_text") == 0) {
lua_pushstring(L, "red_green_scale_text");
push_color_palette(L, game_config::red_green_scale_text);
return 1;
}
if(strcmp(m, "blue_white_scale") == 0) {
lua_pushstring(L, "blue_white_scale");
push_color_palette(L, game_config::blue_white_scale);
return 1;
}
if(strcmp(m, "blue_white_scale_text") == 0) {
lua_pushstring(L, "blue_white_scale_text");
push_color_palette(L, game_config::blue_white_scale_text);
return 1;
}
return 0;
return gameConfigReg().get(L);
}
/**
* Sets some game_config data (__newindex metamethod).
* - Arg 1: userdata (ignored).
* - Arg 2: string containing the name of the property.
* - Arg 3: something containing the attribute.
*/
int lua_kernel_base::impl_game_config_set(lua_State* L)
{
std::string err_msg = "unknown modifiable property of game_config: ";
err_msg += luaL_checkstring(L, 2);
return luaL_argerror(L, 2, err_msg.c_str());
return gameConfigReg().set(L);
}
/**
* Gets a list of game_config data (__dir metamethod).
*/
int lua_kernel_base::impl_game_config_dir(lua_State* L)
{
return gameConfigReg().dir(L);
}
/**
* Loads the "package" package into the Lua environment.

View file

@ -138,11 +138,31 @@ protected:
int intf_kernel_type(lua_State* L);
virtual int impl_game_config_get(lua_State* L);
virtual int impl_game_config_set(lua_State* L);
int impl_game_config_get(lua_State* L);
int impl_game_config_set(lua_State* L);
int impl_game_config_dir(lua_State* L);
private:
static lua_kernel_base*& get_lua_kernel_base_ptr(lua_State *L);
std::vector<std::tuple<std::string, std::string>> registered_widget_definitions_;
};
std::vector<std::string> luaW_get_attributes(lua_State* L, int idx);
struct game_config_tag {
lua_kernel_base& ref;
game_config_tag(lua_kernel_base& k) : ref(k) {}
};
#define GAME_CONFIG_GETTER(name, type, kernel_type) \
LATTR_VALID(name, game_config_tag, k) { return dynamic_cast<kernel_type*>(&k.ref) != nullptr; } \
LATTR_GETTER(name, type, game_config_tag, k)
#define GAME_CONFIG_SETTER(name, type, kernel_type) \
LATTR_VALID(name, game_config_tag, k) { return dynamic_cast<kernel_type*>(&k.ref) != nullptr; } \
LATTR_SETTER(name, type, game_config_tag, k)
template<typename T> struct lua_object_traits;
template<> struct lua_object_traits<game_config_tag> {
inline static auto metatable = "game config";
inline static game_config_tag get(lua_State* L, int) {
return lua_kernel_base::get_lua_kernel<lua_kernel_base>(L);
}
};