From 2486b8ba4bcef056fb523d91f4a8445b48aef685 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Thu, 25 Dec 2014 23:58:00 -0500 Subject: [PATCH 1/7] lua: refactor to use lua 5.2 syntax for custom metatables In lua 5.0, the preferred way to define custom metatables is to use registry keys defined by pushing pointers as lightuserdata to lua. (These pointers can be pointers to arbitrary constant objects, as long as they are unique.) In lua 5.2, the preferred way is to use constant strings as the registry indices, and several lua API functions are introduced: "luaL_newmetatable, luaL_setmetatable, luaL_checkudata, luaL_testudata" which greatly simplify the operations for creating the metatable, assigning it to a userdata, and checking if the userdata has that type. This commit switches over the keys associated to textdomains, translatable strings, vconfigs, and lua gui2 dialogs to use the new style, and simplifies some of the implementation details in the process. For instance, luaW_toconfig no longer has to have an optional argument to an index on the stack where the tstring metatable is... these details are handled by the lua API instead. --- src/scripting/game_lua_kernel.cpp | 8 +- src/scripting/lua_common.cpp | 140 +++++++++++++----------------- src/scripting/lua_common.hpp | 4 +- src/scripting/lua_gui2.cpp | 12 +-- src/scripting/lua_types.cpp | 8 -- src/scripting/lua_types.hpp | 4 - 6 files changed, 76 insertions(+), 100 deletions(-) diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 0ca4b57c3dff..27d6cffeae46 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -483,8 +483,8 @@ static int impl_unit_variables_set(lua_State *L) v = lua_tostring(L, 3); break; case LUA_TUSERDATA: - if (luaW_hasmetatable(L, 3, tstringKey)) { - v = *static_cast(lua_touserdata(L, 3)); + if (t_string * t_str = static_cast (luaL_testudata(L, 3, tstringKey))) { + v = *t_str; break; } // no break @@ -777,8 +777,8 @@ int game_lua_kernel::intf_set_variable(lua_State *L) v.as_scalar() = lua_tostring(L, 2); break; case LUA_TUSERDATA: - if (luaW_hasmetatable(L, 2, tstringKey)) { - v.as_scalar() = *static_cast(lua_touserdata(L, 2)); + if (t_string * t_str = static_cast (luaL_testudata(L, 2, tstringKey))) { + v.as_scalar() = *t_str; break; } // no break diff --git a/src/scripting/lua_common.cpp b/src/scripting/lua_common.cpp index 8b8c5c25f259..b6e88c330891 100644 --- a/src/scripting/lua_common.cpp +++ b/src/scripting/lua_common.cpp @@ -39,6 +39,10 @@ #include // for operator new #include // for string, basic_string +static const char * gettextKey = "gettext"; +static const char * vconfigKey = "vconfig"; +const char * tstringKey = "translatable string"; + namespace lua_common { /** @@ -65,13 +69,11 @@ int intf_textdomain(lua_State *L) { size_t l; char const *m = luaL_checklstring(L, 1, &l); + void *p = lua_newuserdata(L, l + 1); memcpy(p, m, l + 1); - lua_pushlightuserdata(L - , gettextKey); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, gettextKey); return 1; } @@ -108,17 +110,12 @@ static int impl_tstring_concat(lua_State *L) { // Create a new t_string. t_string *t = new(lua_newuserdata(L, sizeof(t_string))) t_string; - - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); + luaL_setmetatable(L, tstringKey); // Append both arguments to t. tstring_concat_aux(L, *t, 1); tstring_concat_aux(L, *t, 2); - lua_setmetatable(L, -2); return 1; } @@ -159,15 +156,11 @@ static int impl_vconfig_get(lua_State *L) unsigned pos = lua_tointeger(L, 2) - 1; if (pos >= len) return 0; std::advance(i, pos); + lua_createtable(L, 2, 0); lua_pushstring(L, i.get_key().c_str()); lua_rawseti(L, -2, 1); - new(lua_newuserdata(L, sizeof(vconfig))) vconfig(i.get_child()); - lua_pushlightuserdata(L - , vconfigKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaW_pushvconfig(L, vconfig(i.get_child())); lua_rawseti(L, -2, 2); return 1; } @@ -254,14 +247,16 @@ int intf_tovconfig(lua_State *L) */ std::string register_gettext_metatable(lua_State *L) { - lua_pushlightuserdata(L - , gettextKey); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, lua_common::impl_gettext); - lua_setfield(L, -2, "__call"); + luaL_newmetatable(L, gettextKey); + + static luaL_Reg const callbacks[] = { + { "__call", &impl_gettext}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "message domain"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding gettext metatable...\n"; } @@ -271,18 +266,18 @@ std::string register_gettext_metatable(lua_State *L) */ std::string register_tstring_metatable(lua_State *L) { - lua_pushlightuserdata(L - , tstringKey); - lua_createtable(L, 0, 4); - lua_pushcfunction(L, impl_tstring_concat); - lua_setfield(L, -2, "__concat"); - lua_pushcfunction(L, impl_tstring_collect); - lua_setfield(L, -2, "__gc"); - lua_pushcfunction(L, impl_tstring_tostring); - lua_setfield(L, -2, "__tostring"); + luaL_newmetatable(L, tstringKey); + + static luaL_Reg const callbacks[] = { + { "__concat", &impl_tstring_concat}, + { "__gc", &impl_tstring_collect}, + { "__tostring", &impl_tstring_tostring}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "translatable string"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding tstring metatable...\n"; } @@ -292,18 +287,18 @@ std::string register_tstring_metatable(lua_State *L) */ std::string register_vconfig_metatable(lua_State *L) { - lua_pushlightuserdata(L - , vconfigKey); - lua_createtable(L, 0, 4); - lua_pushcfunction(L, impl_vconfig_collect); - lua_setfield(L, -2, "__gc"); - lua_pushcfunction(L, impl_vconfig_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, impl_vconfig_size); - lua_setfield(L, -2, "__len"); + luaL_newmetatable(L, vconfigKey); + + static luaL_Reg const callbacks[] = { + { "__gc", &impl_vconfig_collect}, + { "__index", &impl_vconfig_get}, + { "__len", &impl_vconfig_size}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + lua_pushstring(L, "wml object"); lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); return "Adding vconfig metatable...\n"; } @@ -313,21 +308,13 @@ std::string register_vconfig_metatable(lua_State *L) void luaW_pushvconfig(lua_State *L, vconfig const &cfg) { new(lua_newuserdata(L, sizeof(vconfig))) vconfig(cfg); - lua_pushlightuserdata(L - , vconfigKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, vconfigKey); } void luaW_pushtstring(lua_State *L, t_string const &v) { new(lua_newuserdata(L, sizeof(t_string))) t_string(v); - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - lua_setmetatable(L, -2); + luaL_setmetatable(L, tstringKey); } @@ -384,9 +371,12 @@ bool luaW_totstring(lua_State *L, int index, t_string &str) break; case LUA_TUSERDATA: { - if (!luaW_hasmetatable(L, index, tstringKey)) return false; - str = *static_cast(lua_touserdata(L, index)); - break; + if (t_string * tstr = static_cast (luaL_checkudata(L, index, tstringKey))) { + str = *tstr; + break; + } else { + return false; + } } default: return false; @@ -437,7 +427,7 @@ void luaW_pushconfig(lua_State *L, config const &cfg) #define return_misformed() \ do { lua_settop(L, initial_top); return false; } while (0) -bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) +bool luaW_toconfig(lua_State *L, int index, config &cfg) { if (!lua_checkstack(L, LUA_MINSTACK)) return false; @@ -453,10 +443,12 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) break; case LUA_TUSERDATA: { - if (!luaW_hasmetatable(L, index, vconfigKey)) + if (vconfig * ptr = static_cast (luaL_checkudata(L, index, vconfigKey))) { + cfg = ptr->get_parsed_config(); + return true; + } else { return false; - cfg = static_cast(lua_touserdata(L, index))->get_parsed_config(); - return true; + } } case LUA_TNONE: case LUA_TNIL: @@ -465,15 +457,6 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) return false; } - // Get t_string's metatable, so that it can be used later to detect t_string object. - if (!tstring_meta) { - lua_pushlightuserdata(L - , tstringKey); - - lua_rawget(L, LUA_REGISTRYINDEX); - tstring_meta = initial_top + 1; - } - // First convert the children (integer indices). for (int i = 1, i_end = lua_rawlen(L, index); i <= i_end; ++i) { @@ -483,7 +466,7 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) char const *m = lua_tostring(L, -1); if (!m) return_misformed(); lua_rawgeti(L, -2, 2); - if (!luaW_toconfig(L, -1, cfg.add_child(m), tstring_meta)) + if (!luaW_toconfig(L, -1, cfg.add_child(m))) return_misformed(); lua_pop(L, 3); } @@ -506,12 +489,12 @@ bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta) break; case LUA_TUSERDATA: { - if (!lua_getmetatable(L, -1)) return_misformed(); - bool tstr = lua_rawequal(L, -1, tstring_meta) != 0; - lua_pop(L, 1); - if (!tstr) return_misformed(); - v = *static_cast(lua_touserdata(L, -1)); - break; + if (t_string * tptr = static_cast(luaL_testudata(L, -1, tstringKey))) { + v = *tptr; + break; + } else { + return_misformed(); + } } default: return_misformed(); @@ -546,10 +529,11 @@ bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg) break; } case LUA_TUSERDATA: - if (!luaW_hasmetatable(L, index, vconfigKey)) + if (vconfig * ptr = static_cast (luaL_testudata(L, index, vconfigKey))) { + vcfg = *ptr; + } else { return false; - vcfg = *static_cast(lua_touserdata(L, index)); - break; + } case LUA_TNONE: case LUA_TNIL: break; diff --git a/src/scripting/lua_common.hpp b/src/scripting/lua_common.hpp index c53a3dbbdc98..750103ae7519 100644 --- a/src/scripting/lua_common.hpp +++ b/src/scripting/lua_common.hpp @@ -34,7 +34,9 @@ namespace lua_common { std::string register_gettext_metatable(lua_State *L); std::string register_tstring_metatable(lua_State *L); std::string register_vconfig_metatable(lua_State *L); + } +extern const char * tstringKey; /** * Pushes a vconfig on the top of the stack. @@ -86,7 +88,7 @@ void luaW_pushconfig(lua_State *L, config const &cfg); * @note If the table has holes in the integer keys or floating-point keys, * some keys will be ignored and the error will go undetected. */ -bool luaW_toconfig(lua_State *L, int index, config &cfg, int tstring_meta = 0); +bool luaW_toconfig(lua_State *L, int index, config &cfg); /** * Converts an optional table or vconfig to a config object. diff --git a/src/scripting/lua_gui2.cpp b/src/scripting/lua_gui2.cpp index 5744f2c73c5c..4933ba35221b 100644 --- a/src/scripting/lua_gui2.cpp +++ b/src/scripting/lua_gui2.cpp @@ -54,6 +54,8 @@ static lg::log_domain log_scripting_lua("scripting/lua"); #define ERR_LUA LOG_STREAM(err, log_scripting_lua) +static const char * dlgclbkKey = "dialog callback"; + namespace { struct scoped_dialog { @@ -75,7 +77,7 @@ namespace { scoped_dialog::scoped_dialog(lua_State *l, gui2::twindow *w) : L(l), prev(current), window(w), callbacks() { - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_createtable(L, 1, 0); lua_pushvalue(L, -2); @@ -89,7 +91,7 @@ namespace { { delete window; current = prev; - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_pushvalue(L, -1); lua_rawget(L, LUA_REGISTRYINDEX); @@ -305,7 +307,7 @@ namespace { // helpers of intf_set_dialog_callback() cb = i->second; } lua_State *L = scoped_dialog::current->L; - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); lua_rawgeti(L, -1, cb); @@ -337,7 +339,7 @@ int intf_set_dialog_callback(lua_State *L) scoped_dialog::callback_map::iterator i = m.find(w); if (i != m.end()) { - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); lua_pushnil(L); @@ -374,7 +376,7 @@ int intf_set_dialog_callback(lua_State *L) else return luaL_argerror(L, lua_gettop(L), "unsupported widget"); - lua_pushlightuserdata(L + lua_pushstring(L , dlgclbkKey); lua_rawget(L, LUA_REGISTRYINDEX); int n = lua_rawlen(L, -1) + 1; diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index 340cd1677af1..66320d6dfa05 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -15,29 +15,21 @@ #include "lua_types.hpp" /* Dummy pointer for getting unique keys for Lua's registry. */ -static char const v_dlgclbkKey = 0; static char const v_executeKey = 0; static char const v_getsideKey = 0; -static char const v_gettextKey = 0; static char const v_gettypeKey = 0; static char const v_getraceKey = 0; static char const v_getunitKey = 0; -static char const v_tstringKey = 0; static char const v_unitvarKey = 0; static char const v_ustatusKey = 0; -static char const v_vconfigKey = 0; static char const v_currentscriptKey = 0; -luatypekey const dlgclbkKey = static_cast(const_cast(&v_dlgclbkKey)); luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); luatypekey const getsideKey = static_cast(const_cast(&v_getsideKey)); -luatypekey const gettextKey = static_cast(const_cast(&v_gettextKey)); luatypekey const gettypeKey = static_cast(const_cast(&v_gettypeKey)); luatypekey const getraceKey = static_cast(const_cast(&v_getraceKey)); luatypekey const getunitKey = static_cast(const_cast(&v_getunitKey)); -luatypekey const tstringKey = static_cast(const_cast(&v_tstringKey)); luatypekey const unitvarKey = static_cast(const_cast(&v_unitvarKey)); luatypekey const ustatusKey = static_cast(const_cast(&v_ustatusKey)); -luatypekey const vconfigKey = static_cast(const_cast(&v_vconfigKey)); luatypekey const currentscriptKey = static_cast(const_cast(&v_currentscriptKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index a3a9b3d2b5d7..5cf905588b5b 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -19,17 +19,13 @@ typedef void* luatypekey; // i dont want to cast to void* each time .... // a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time). -extern luatypekey const dlgclbkKey; extern luatypekey const executeKey; extern luatypekey const getsideKey; -extern luatypekey const gettextKey; extern luatypekey const gettypeKey; extern luatypekey const getraceKey; extern luatypekey const getunitKey; -extern luatypekey const tstringKey; extern luatypekey const unitvarKey; extern luatypekey const ustatusKey; -extern luatypekey const vconfigKey; extern luatypekey const currentscriptKey; #endif From 017050df7069f27f468e19c23fbd7782bd7972fe Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 00:06:05 -0500 Subject: [PATCH 2/7] ilua: eliminate the "_" holds last executed command feature the ilua `_pretty_print` feature has the property that it sets _ to be what was printed, as an interpreter feature so that _ represents the results of the previous expression. However it appears that this may conflict with some parts of our api, for instance the _ is used to hold the return value of wesnoth.textdomain in the lua implementation of [harm_unit]. Note that there is no actual bug that I have observed, I merely anticipate that this _ feature won't be compatible with our established gettext conventions. --- data/lua/ilua.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/data/lua/ilua.lua b/data/lua/ilua.lua index 5d556f4c75d9..63ca2f554868 100644 --- a/data/lua/ilua.lua +++ b/data/lua/ilua.lua @@ -9,8 +9,6 @@ local pretty_print_limit = 20 local max_depth = 7 local table_clever = true --- suppress strict warnings -_ = true -- imported global functions local sub = string.sub @@ -102,7 +100,6 @@ function ilua._pretty_print(...) for i,val in ipairs(arg) do print(ilua.val2str(val)) end - _G['_'] = arg[1] end -- From 95b2c41a19251e8f849110572d776c91a4008906 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 00:19:56 -0500 Subject: [PATCH 3/7] lua: get rid of lua "currentscriptKey" from an old branch This key was created in the first attempt at application scripting but it was reappropriated to be used as the key for the "thread table" when the present solution based on coroutines was found. The key has been renamed and moved to its site of usage now. --- src/scripting/application_lua_kernel.cpp | 5 ++++- src/scripting/lua_types.cpp | 2 -- src/scripting/lua_types.hpp | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/scripting/application_lua_kernel.cpp b/src/scripting/application_lua_kernel.cpp index f42636378295..90a689bfc62d 100644 --- a/src/scripting/application_lua_kernel.cpp +++ b/src/scripting/application_lua_kernel.cpp @@ -127,9 +127,12 @@ bool application_lua_kernel::thread::is_running() { return started_ ? (lua_status(T_) == LUA_YIELD) : (lua_status(T_) == LUA_OK); } +static char * v_threadtableKey = 0; +static void * const threadtableKey = static_cast (& v_threadtableKey); + static lua_State * get_new_thread(lua_State * L) { - lua_pushlightuserdata(L , currentscriptKey); + lua_pushlightuserdata(L , threadtableKey); lua_pushvalue(L,1); // duplicate script key, since we need to store later // stack is now [script key] [script key] diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index 66320d6dfa05..a982a4fcf0a0 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -22,7 +22,6 @@ static char const v_getraceKey = 0; static char const v_getunitKey = 0; static char const v_unitvarKey = 0; static char const v_ustatusKey = 0; -static char const v_currentscriptKey = 0; luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); @@ -32,4 +31,3 @@ luatypekey const getraceKey = static_cast(const_cast(&v_getraceK luatypekey const getunitKey = static_cast(const_cast(&v_getunitKey)); luatypekey const unitvarKey = static_cast(const_cast(&v_unitvarKey)); luatypekey const ustatusKey = static_cast(const_cast(&v_ustatusKey)); -luatypekey const currentscriptKey = static_cast(const_cast(&v_currentscriptKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index 5cf905588b5b..e295ca5059f5 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -26,6 +26,5 @@ extern luatypekey const getraceKey; extern luatypekey const getunitKey; extern luatypekey const unitvarKey; extern luatypekey const ustatusKey; -extern luatypekey const currentscriptKey; #endif From 2239ab3f6592bdd18b0c07051b4b3fe5b8142459 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 01:07:57 -0500 Subject: [PATCH 4/7] add a unit test for lua get_sides return object --- data/test/scenarios/test_lua.cfg | 12 ++++++++++++ wml_test_schedule | 1 + 2 files changed, 13 insertions(+) create mode 100644 data/test/scenarios/test_lua.cfg diff --git a/data/test/scenarios/test_lua.cfg b/data/test/scenarios/test_lua.cfg new file mode 100644 index 000000000000..97578255e446 --- /dev/null +++ b/data/test/scenarios/test_lua.cfg @@ -0,0 +1,12 @@ +{GENERIC_UNIT_TEST "lua_get_sides" ( + [event] + name = prestart + [lua] + code = << local s = wesnoth.get_sides({}) + local result = (s[1].side == 1) and (s[1].name == "Alice") and (s[2].side == 2) and (s[2].name == "Bob") + wesnoth.set_variable("result", result) >> + [/lua] + + {RETURN ({VARIABLE_CONDITIONAL result boolean_equals true})} + [/event] +)} diff --git a/wml_test_schedule b/wml_test_schedule index dc8e4318b846..2b5ea61f879d 100644 --- a/wml_test_schedule +++ b/wml_test_schedule @@ -87,6 +87,7 @@ # 0 lua_dofile 0 lua_require +0 lua_get_sides # # Pathfinding # From 1969267d192da67d1e20f176cef13937978698d3 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 02:41:42 -0500 Subject: [PATCH 5/7] lua: move code related to get_sides metatable to its own file --- src/CMakeLists.txt | 1 + src/SConscript | 1 + src/scripting/game_lua_kernel.cpp | 149 +++------------------------- src/scripting/lua_team.cpp | 160 ++++++++++++++++++++++++++++++ src/scripting/lua_team.hpp | 34 +++++++ src/scripting/lua_types.cpp | 2 - src/scripting/lua_types.hpp | 1 - 7 files changed, 209 insertions(+), 139 deletions(-) create mode 100644 src/scripting/lua_team.cpp create mode 100644 src/scripting/lua_team.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c41de6575132..f4d33c7e1169 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -971,6 +971,7 @@ set(wesnoth-main_SRC scripting/lua_kernel_base.cpp scripting/lua_map_location_ops.cpp scripting/lua_rng.cpp + scripting/lua_team.cpp scripting/lua_types.cpp scripting/mapgen_lua_kernel.cpp scripting/plugins/context.cpp diff --git a/src/SConscript b/src/SConscript index aa0519600ec2..61b108144e0f 100644 --- a/src/SConscript +++ b/src/SConscript @@ -544,6 +544,7 @@ wesnoth_sources = Split(""" scripting/lua_kernel_base.cpp scripting/lua_map_location_ops.cpp scripting/lua_rng.cpp + scripting/lua_team.cpp scripting/lua_types.cpp scripting/mapgen_lua_kernel.cpp scripting/plugins/context.cpp diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 27d6cffeae46..fbeea94ff2d1 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -77,6 +77,7 @@ #include "scripting/lua_common.hpp" #include "scripting/lua_cpp_function.hpp" #include "scripting/lua_gui2.hpp" // for show_gamestate_inspector +#include "scripting/lua_team.hpp" #include "scripting/lua_types.hpp" // for getunitKey, dlgclbkKey, etc #include "sdl/utils.hpp" // for surface #include "side_filter.hpp" // for side_filter @@ -959,101 +960,6 @@ int game_lua_kernel::intf_lock_view(lua_State *L) return 0; } -/** - * Gets some data on a side (__index metamethod). - * - Arg 1: full userdata containing the team. - * - Arg 2: string containing the name of the property. - * - Ret 1: something containing the attribute. - */ -static int impl_side_get(lua_State *L) -{ - // Hidden metamethod, so arg1 has to be a pointer to a team. - team &t = **static_cast(lua_touserdata(L, 1)); - char const *m = luaL_checkstring(L, 2); - - // Find the corresponding attribute. - return_int_attrib("side", t.side()); - return_int_attrib("gold", t.gold()); - return_tstring_attrib("objectives", t.objectives()); - return_int_attrib("village_gold", t.village_gold()); - return_int_attrib("village_support", t.village_support()); - return_int_attrib("recall_cost", t.recall_cost()); - return_int_attrib("base_income", t.base_income()); - return_int_attrib("total_income", t.total_income()); - return_bool_attrib("objectives_changed", t.objectives_changed()); - return_bool_attrib("fog", t.uses_fog()); - return_bool_attrib("shroud", t.uses_shroud()); - return_bool_attrib("hidden", t.hidden()); - return_bool_attrib("scroll_to_leader", t.get_scroll_to_leader()); - return_string_attrib("flag", t.flag()); - return_string_attrib("flag_icon", t.flag_icon()); - return_tstring_attrib("user_team_name", t.user_team_name()); - return_string_attrib("team_name", t.team_name()); - return_string_attrib("name", t.name()); - return_string_attrib("color", t.color()); - return_cstring_attrib("controller", team::CONTROLLER_to_string(t.controller()).c_str()); - return_string_attrib("defeat_condition", team::DEFEAT_CONDITION_to_string(t.defeat_condition())); - return_bool_attrib("lost", t.lost()); - - if (strcmp(m, "recruit") == 0) { - std::set const &recruits = t.recruits(); - lua_createtable(L, recruits.size(), 0); - int i = 1; - BOOST_FOREACH(std::string const &r, t.recruits()) { - lua_pushstring(L, r.c_str()); - lua_rawseti(L, -2, i++); - } - return 1; - } - - return_cfg_attrib("__cfg", t.write(cfg)); - return 0; -} - -/** - * Sets some data on a side (__newindex metamethod). - * - Arg 1: full userdata containing the team. - * - Arg 2: string containing the name of the property. - * - Arg 3: something containing the attribute. - */ -static int impl_side_set(lua_State *L) -{ - // Hidden metamethod, so arg1 has to be a pointer to a team. - team &t = **static_cast(lua_touserdata(L, 1)); - char const *m = luaL_checkstring(L, 2); - - // Find the corresponding attribute. - modify_int_attrib("gold", t.set_gold(value)); - modify_tstring_attrib("objectives", t.set_objectives(value, true)); - modify_int_attrib("village_gold", t.set_village_gold(value)); - modify_int_attrib("village_support", t.set_village_support(value)); - modify_int_attrib("recall_cost", t.set_recall_cost(value)); - modify_int_attrib("base_income", t.set_base_income(value)); - modify_bool_attrib("objectives_changed", t.set_objectives_changed(value)); - modify_bool_attrib("hidden", t.set_hidden(value)); - modify_bool_attrib("scroll_to_leader", t.set_scroll_to_leader(value)); - modify_tstring_attrib("user_team_name", t.change_team(t.team_name(), value)); - modify_string_attrib("team_name", t.change_team(value, t.user_team_name())); - modify_string_attrib("controller", t.change_controller_by_wml(value)); - modify_string_attrib("color", t.set_color(value)); - modify_string_attrib("defeat_condition", t.set_defeat_condition_string(value)); - modify_bool_attrib("lost", t.set_lost(value)); - - if (strcmp(m, "recruit") == 0) { - t.set_recruits(std::set()); - if (!lua_istable(L, 3)) return 0; - for (int i = 1;; ++i) { - lua_rawgeti(L, 3, i); - if (lua_isnil(L, -1)) break; - t.add_recruit(lua_tostring(L, -1)); - lua_pop(L, 1); - } - return 0; - } - - return luaL_argerror(L, 2, "unknown modifiable property"); -} - /** * Gets a terrain code. * - Args 1,2: map location. @@ -2899,25 +2805,12 @@ int game_lua_kernel::intf_get_sides(lua_State* L) sides = filter.get_teams(); } - //keep this stack in the loop: - //1: getsideKey getmetatable - //2: return table - //3: userdata for a side - //4: getsideKey metatable copy (of index 1) - lua_settop(L, 0); - lua_pushlightuserdata(L - , getsideKey); - lua_rawget(L, LUA_REGISTRYINDEX); lua_createtable(L, sides.size(), 0); unsigned index = 1; BOOST_FOREACH(int side, sides) { - // Create a full userdata containing a pointer to the team. - team** t = static_cast(lua_newuserdata(L, sizeof(team*))); - *t = &(teams()[side - 1]); - lua_pushvalue(L, 1); - lua_setmetatable(L, 3); - lua_rawseti(L, 2, index); + luaW_pushteam(L, teams()[side - 1]); + lua_rawseti(L, -2, index); ++index; } @@ -3774,18 +3667,7 @@ game_lua_kernel::game_lua_kernel(const config &cfg, CVideo * video, game_state & lua_setglobal(L, "wesnoth"); // Create the getside metatable. - cmd_log_ << "Adding getside metatable...\n"; - - lua_pushlightuserdata(L - , getsideKey); - lua_createtable(L, 0, 3); - lua_pushcfunction(L, impl_side_get); - lua_setfield(L, -2, "__index"); - lua_pushcfunction(L, impl_side_set); - lua_setfield(L, -2, "__newindex"); - lua_pushstring(L, "side"); - lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); + cmd_log_ << lua_team::register_metatable(L); // Create the gettype metatable. cmd_log_ << "Adding gettype metatable...\n"; @@ -3938,21 +3820,16 @@ void game_lua_kernel::initialize() // Still needed for backwards compatibility. lua_getglobal(L, "wesnoth"); - lua_pushlightuserdata(L - , getsideKey); - lua_rawget(L, LUA_REGISTRYINDEX); - lua_createtable(L, teams().size(), 0); - for (unsigned i = 0; i != teams().size(); ++i) - { - // Create a full userdata containing a pointer to the team. - team **p = static_cast(lua_newuserdata(L, sizeof(team *))); - *p = &teams()[i]; - lua_pushvalue(L, -3); - lua_setmetatable(L, -2); - lua_rawseti(L, -2, i + 1); + lua_pushstring(L, "get_sides"); + lua_rawget(L, -2); + lua_createtable(L, 0, 0); + + if (!protected_call(1, 1, boost::bind(&lua_kernel_base::log_error, this, _1, _2))) { + cmd_log_ << "Failed to compute wesnoth.sides\n"; + } else { + lua_setfield(L, -2, "sides"); + cmd_log_ << "Added wesnoth.sides\n"; } - lua_setfield(L, -3, "sides"); - lua_pop(L, 2); // Create the unit_types table. cmd_log_ << "Adding unit_types table...\n"; diff --git a/src/scripting/lua_team.cpp b/src/scripting/lua_team.cpp new file mode 100644 index 000000000000..4214d4693559 --- /dev/null +++ b/src/scripting/lua_team.cpp @@ -0,0 +1,160 @@ +/* + Copyright (C) 2014 by Chris Beck + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#include "scripting/lua_team.hpp" + +#include "lua/lua.h" +#include "lua/lauxlib.h" +#include "scripting/lua_common.hpp" +#include "team.hpp" + +#include +#include + +/** + * Implementation for a lua reference to a team, + * used by the wesnoth in-game sides table. + * + * (The userdata has type team** because lua holds + * only a pointer to a team, not a full-size team. + * If it were a full object then we would cast to + * type team *, since checkudata returns a pointer + * to the type corresponding to the sizeof expr + * used when we allocated the userdata.) + */ + +// Registry key +static const char * Team = "side"; + +/** + * Gets some data on a side (__index metamethod). + * - Arg 1: full userdata containing the team. + * - Arg 2: string containing the name of the property. + * - Ret 1: something containing the attribute. + */ +static int impl_side_get(lua_State *L) +{ + // Hidden metamethod, so arg1 has to be a pointer to a team. + team &t = **static_cast(luaL_checkudata(L, 1, Team)); + char const *m = luaL_checkstring(L, 2); + + // Find the corresponding attribute. + return_int_attrib("side", t.side()); + return_int_attrib("gold", t.gold()); + return_tstring_attrib("objectives", t.objectives()); + return_int_attrib("village_gold", t.village_gold()); + return_int_attrib("village_support", t.village_support()); + return_int_attrib("recall_cost", t.recall_cost()); + return_int_attrib("base_income", t.base_income()); + return_int_attrib("total_income", t.total_income()); + return_bool_attrib("objectives_changed", t.objectives_changed()); + return_bool_attrib("fog", t.uses_fog()); + return_bool_attrib("shroud", t.uses_shroud()); + return_bool_attrib("hidden", t.hidden()); + return_bool_attrib("scroll_to_leader", t.get_scroll_to_leader()); + return_string_attrib("flag", t.flag()); + return_string_attrib("flag_icon", t.flag_icon()); + return_tstring_attrib("user_team_name", t.user_team_name()); + return_string_attrib("team_name", t.team_name()); + return_string_attrib("name", t.name()); + return_string_attrib("color", t.color()); + return_cstring_attrib("controller", team::CONTROLLER_to_string(t.controller()).c_str()); + return_string_attrib("defeat_condition", team::DEFEAT_CONDITION_to_string(t.defeat_condition())); + return_bool_attrib("lost", t.lost()); + + if (strcmp(m, "recruit") == 0) { + std::set const &recruits = t.recruits(); + lua_createtable(L, recruits.size(), 0); + int i = 1; + BOOST_FOREACH(std::string const &r, t.recruits()) { + lua_pushstring(L, r.c_str()); + lua_rawseti(L, -2, i++); + } + return 1; + } + + return_cfg_attrib("__cfg", t.write(cfg)); + return 0; +} + +/** + * Sets some data on a side (__newindex metamethod). + * - Arg 1: full userdata containing the team. + * - Arg 2: string containing the name of the property. + * - Arg 3: something containing the attribute. + */ +static int impl_side_set(lua_State *L) +{ + // Hidden metamethod, so arg1 has to be a pointer to a team. + team &t = **static_cast(luaL_checkudata(L, 1, Team)); + char const *m = luaL_checkstring(L, 2); + + // Find the corresponding attribute. + modify_int_attrib("gold", t.set_gold(value)); + modify_tstring_attrib("objectives", t.set_objectives(value, true)); + modify_int_attrib("village_gold", t.set_village_gold(value)); + modify_int_attrib("village_support", t.set_village_support(value)); + modify_int_attrib("recall_cost", t.set_recall_cost(value)); + modify_int_attrib("base_income", t.set_base_income(value)); + modify_bool_attrib("objectives_changed", t.set_objectives_changed(value)); + modify_bool_attrib("hidden", t.set_hidden(value)); + modify_bool_attrib("scroll_to_leader", t.set_scroll_to_leader(value)); + modify_tstring_attrib("user_team_name", t.change_team(t.team_name(), value)); + modify_string_attrib("team_name", t.change_team(value, t.user_team_name())); + modify_string_attrib("controller", t.change_controller_by_wml(value)); + modify_string_attrib("color", t.set_color(value)); + modify_string_attrib("defeat_condition", t.set_defeat_condition_string(value)); + modify_bool_attrib("lost", t.set_lost(value)); + + if (strcmp(m, "recruit") == 0) { + t.set_recruits(std::set()); + if (!lua_istable(L, 3)) return 0; + for (int i = 1;; ++i) { + lua_rawgeti(L, 3, i); + if (lua_isnil(L, -1)) break; + t.add_recruit(lua_tostring(L, -1)); + lua_pop(L, 1); + } + return 0; + } + + return luaL_argerror(L, 2, "unknown modifiable property"); +} + +namespace lua_team { + + std::string register_metatable(lua_State * L) + { + luaL_newmetatable(L, Team); + + static luaL_Reg const callbacks[] = { + { "__index", &impl_side_get}, + { "__newindex", &impl_side_set}, + { NULL, NULL } + }; + luaL_setfuncs(L, callbacks, 0); + + lua_pushstring(L, "side"); + lua_setfield(L, -2, "__metatable"); + + return "Adding getside metatable...\n"; + } +} + +void luaW_pushteam(lua_State *L, team & tm) +{ + team** t = static_cast(lua_newuserdata(L, sizeof(team*))); + *t = &tm; + luaL_setmetatable(L, Team); +} diff --git a/src/scripting/lua_team.hpp b/src/scripting/lua_team.hpp new file mode 100644 index 000000000000..06c117d116ce --- /dev/null +++ b/src/scripting/lua_team.hpp @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 by Chris Beck + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#ifndef LUA_TEAM_HPP_INCLUDED +#define LUA_TEAM_HPP_INCLUDED + +class team; +struct lua_State; + +#include + +/** + * This namespace contains bindings for lua to hold a pointer to a team, + * and to access and modify it. + */ +namespace lua_team { + std::string register_metatable(lua_State *); +} //end namespace lua_team + +// Create a full userdata containing a pointer to the team. +void luaW_pushteam(lua_State *, team &); + +#endif diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index a982a4fcf0a0..f2b7a8e36347 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -16,7 +16,6 @@ /* Dummy pointer for getting unique keys for Lua's registry. */ static char const v_executeKey = 0; -static char const v_getsideKey = 0; static char const v_gettypeKey = 0; static char const v_getraceKey = 0; static char const v_getunitKey = 0; @@ -25,7 +24,6 @@ static char const v_ustatusKey = 0; luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); -luatypekey const getsideKey = static_cast(const_cast(&v_getsideKey)); luatypekey const gettypeKey = static_cast(const_cast(&v_gettypeKey)); luatypekey const getraceKey = static_cast(const_cast(&v_getraceKey)); luatypekey const getunitKey = static_cast(const_cast(&v_getunitKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index e295ca5059f5..906c252098c6 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -20,7 +20,6 @@ typedef void* luatypekey; // i dont want to cast to void* each time .... // a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time). extern luatypekey const executeKey; -extern luatypekey const getsideKey; extern luatypekey const gettypeKey; extern luatypekey const getraceKey; extern luatypekey const getunitKey; From 2aca986bcb79b64a0befcc9266b96b9396328a79 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 12:49:14 -0500 Subject: [PATCH 6/7] move unit_type::alignment_description impl into .cpp file --- src/unit_types.cpp | 26 ++++++++++++++++++++++++++ src/unit_types.hpp | 19 +------------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/unit_types.cpp b/src/unit_types.cpp index 46d7f69fc165..a09d893cce1f 100644 --- a/src/unit_types.cpp +++ b/src/unit_types.cpp @@ -26,6 +26,7 @@ //#include "gettext.hpp" #include "loadscreen.hpp" #include "log.hpp" +#include "make_enum.hpp" #include "portrait.hpp" #include "unit.hpp" #include "unit_abilities.hpp" @@ -1142,6 +1143,31 @@ bool unit_type::resistance_filter_matches(const config& cfg, bool attacker, cons if (!unit_abilities::filter_base_matches(cfg, res)) return false; return true; } + +/** Implementation detail of unit_type::alignment_description */ + +MAKE_ENUM (ALIGNMENT_FEMALE_VARIATION, + (FEMALE_LAWFUL, N_("female^lawful")) + (FEMALE_NEUTRAL, N_("female^neutral")) + (FEMALE_CHAOTIC, N_("female^chaotic")) + (FEMALE_LIMINAL, N_("female^liminal")) +) + +MAKE_ENUM_STREAM_OPS1(ALIGNMENT_FEMALE_VARIATION) + +std::string unit_type::alignment_description(ALIGNMENT align, unit_race::GENDER gender) +{ + std::string str = std::string(); + if (gender == unit_race::FEMALE) { + ALIGNMENT_FEMALE_VARIATION fem = static_cast (align); + str = lexical_cast(fem); + } else { + str = lexical_cast(align); + } + return translation::sgettext(str.c_str()); +} + + /* ** unit_type_data ** */ diff --git a/src/unit_types.hpp b/src/unit_types.hpp index e6d48e806f8b..2bdd222fa041 100644 --- a/src/unit_types.hpp +++ b/src/unit_types.hpp @@ -235,25 +235,9 @@ class unit_type (CHAOTIC, N_("chaotic")) (LIMINAL, N_("liminal")) ) - MAKE_ENUM (ALIGNMENT_FEMALE_VARIATION, - (FEMALE_LAWFUL, N_("female^lawful")) - (FEMALE_NEUTRAL, N_("female^neutral")) - (FEMALE_CHAOTIC, N_("female^chaotic")) - (FEMALE_LIMINAL, N_("female^liminal")) - ) ALIGNMENT alignment() const { return alignment_; } - inline static std::string alignment_description(ALIGNMENT align, unit_race::GENDER gender = unit_race::MALE) - { - std::string str = std::string(); - if (gender == unit_race::FEMALE) { - ALIGNMENT_FEMALE_VARIATION fem = static_cast (align); - str = lexical_cast(fem); - } else { - str = lexical_cast(align); - } - return translation::sgettext(str.c_str()); - } + static std::string alignment_description(ALIGNMENT align, unit_race::GENDER gender = unit_race::MALE); fixed_t alpha() const { return alpha_; } @@ -390,7 +374,6 @@ class unit_type }; MAKE_ENUM_STREAM_OPS2(unit_type, ALIGNMENT) -MAKE_ENUM_STREAM_OPS2(unit_type, ALIGNMENT_FEMALE_VARIATION) class unit_type_data : private boost::noncopyable From a669f2525557c46e554cb851a536eec6a1390bd8 Mon Sep 17 00:00:00 2001 From: Chris Beck Date: Fri, 26 Dec 2014 17:15:44 -0500 Subject: [PATCH 7/7] lua: move code related to getting unit types to its own file --- src/CMakeLists.txt | 1 + src/SConscript | 1 + src/scripting/game_lua_kernel.cpp | 53 +++------------------ src/scripting/lua_types.cpp | 2 - src/scripting/lua_types.hpp | 1 - src/scripting/lua_unit_type.cpp | 79 +++++++++++++++++++++++++++++++ src/scripting/lua_unit_type.hpp | 34 +++++++++++++ 7 files changed, 121 insertions(+), 50 deletions(-) create mode 100644 src/scripting/lua_unit_type.cpp create mode 100644 src/scripting/lua_unit_type.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f4d33c7e1169..ef49229dadaa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -973,6 +973,7 @@ set(wesnoth-main_SRC scripting/lua_rng.cpp scripting/lua_team.cpp scripting/lua_types.cpp + scripting/lua_unit_type.cpp scripting/mapgen_lua_kernel.cpp scripting/plugins/context.cpp scripting/plugins/manager.cpp diff --git a/src/SConscript b/src/SConscript index 61b108144e0f..b1f29a1ed716 100644 --- a/src/SConscript +++ b/src/SConscript @@ -546,6 +546,7 @@ wesnoth_sources = Split(""" scripting/lua_rng.cpp scripting/lua_team.cpp scripting/lua_types.cpp + scripting/lua_unit_type.cpp scripting/mapgen_lua_kernel.cpp scripting/plugins/context.cpp scripting/plugins/manager.cpp diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index fbeea94ff2d1..06794715254f 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -79,6 +79,7 @@ #include "scripting/lua_gui2.hpp" // for show_gamestate_inspector #include "scripting/lua_team.hpp" #include "scripting/lua_types.hpp" // for getunitKey, dlgclbkKey, etc +#include "scripting/lua_unit_type.hpp" #include "sdl/utils.hpp" // for surface #include "side_filter.hpp" // for side_filter #include "sound.hpp" // for commit_music_changes, etc @@ -199,33 +200,6 @@ namespace { }; }//unnamed namespace for queued_event_context -/** - * Gets some data on a unit type (__index metamethod). - * - Arg 1: table containing an "id" field. - * - Arg 2: string containing the name of the property. - * - Ret 1: something containing the attribute. - */ -static int impl_unit_type_get(lua_State *L) -{ - char const *m = luaL_checkstring(L, 2); - lua_pushstring(L, "id"); - lua_rawget(L, 1); - const unit_type *utp = unit_types.find(lua_tostring(L, -1)); - if (!utp) return luaL_argerror(L, 1, "unknown unit type"); - unit_type const &ut = *utp; - - // Find the corresponding attribute. - return_tstring_attrib("name", ut.type_name()); - return_int_attrib("max_hitpoints", ut.hitpoints()); - return_int_attrib("max_moves", ut.movement()); - return_int_attrib("max_experience", ut.experience_needed()); - return_int_attrib("cost", ut.cost()); - return_int_attrib("level", ut.level()); - return_int_attrib("recall_cost", ut.recall_cost()); - return_cfgref_attrib("__cfg", ut.get_cfg()); - return 0; -} - /** * Gets some data on a race (__index metamethod). * - Arg 1: table containing an "id" field. @@ -3670,16 +3644,7 @@ game_lua_kernel::game_lua_kernel(const config &cfg, CVideo * video, game_state & cmd_log_ << lua_team::register_metatable(L); // Create the gettype metatable. - cmd_log_ << "Adding gettype metatable...\n"; - - lua_pushlightuserdata(L - , gettypeKey); - lua_createtable(L, 0, 2); - lua_pushcfunction(L, impl_unit_type_get); - lua_setfield(L, -2, "__index"); - lua_pushstring(L, "unit type"); - lua_setfield(L, -2, "__metatable"); - lua_rawset(L, LUA_REGISTRYINDEX); + cmd_log_ << lua_unit_type::register_metatable(L); //Create the getrace metatable cmd_log_ << "Adding getrace metatable...\n"; @@ -3834,26 +3799,20 @@ void game_lua_kernel::initialize() // Create the unit_types table. cmd_log_ << "Adding unit_types table...\n"; + lua_settop(L, 0); lua_getglobal(L, "wesnoth"); - lua_pushlightuserdata(L - , gettypeKey); - lua_rawget(L, LUA_REGISTRYINDEX); lua_newtable(L); BOOST_FOREACH(const unit_type_data::unit_type_map::value_type &ut, unit_types.types()) { - lua_createtable(L, 0, 1); - lua_pushstring(L, ut.first.c_str()); - lua_setfield(L, -2, "id"); - lua_pushvalue(L, -3); - lua_setmetatable(L, -2); + luaW_pushunittype(L, ut.first); lua_setfield(L, -2, ut.first.c_str()); } - lua_setfield(L, -3, "unit_types"); - lua_pop(L, 2); + lua_setfield(L, -2, "unit_types"); //Create the races table. cmd_log_ << "Adding races table...\n"; + lua_settop(L, 0); lua_getglobal(L, "wesnoth"); lua_pushlightuserdata(L , getraceKey); diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index f2b7a8e36347..dbb1f0ff9d5b 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -16,7 +16,6 @@ /* Dummy pointer for getting unique keys for Lua's registry. */ static char const v_executeKey = 0; -static char const v_gettypeKey = 0; static char const v_getraceKey = 0; static char const v_getunitKey = 0; static char const v_unitvarKey = 0; @@ -24,7 +23,6 @@ static char const v_ustatusKey = 0; luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); -luatypekey const gettypeKey = static_cast(const_cast(&v_gettypeKey)); luatypekey const getraceKey = static_cast(const_cast(&v_getraceKey)); luatypekey const getunitKey = static_cast(const_cast(&v_getunitKey)); luatypekey const unitvarKey = static_cast(const_cast(&v_unitvarKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index 906c252098c6..0f071c378434 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -20,7 +20,6 @@ typedef void* luatypekey; // i dont want to cast to void* each time .... // a drawback is, that these are now normal static variables wich are initialised at initialisation time (so you shoudn't use these at/before initialisation time). extern luatypekey const executeKey; -extern luatypekey const gettypeKey; extern luatypekey const getraceKey; extern luatypekey const getunitKey; extern luatypekey const unitvarKey; diff --git a/src/scripting/lua_unit_type.cpp b/src/scripting/lua_unit_type.cpp new file mode 100644 index 000000000000..f01dad80ad3b --- /dev/null +++ b/src/scripting/lua_unit_type.cpp @@ -0,0 +1,79 @@ +/* + Copyright (C) 2014 by Chris Beck + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#include "scripting/lua_unit_type.hpp" + +#include "lua/lua.h" +#include "lua/lauxlib.h" +#include "scripting/lua_common.hpp" +#include "unit_types.hpp" + +#include +#include + +/** + * Implementation for a lua reference to a unit_type. + */ + +// Registry key +static const char * UnitType = "unit type"; + +/** + * Gets some data on a unit type (__index metamethod). + * - Arg 1: table containing an "id" field. + * - Arg 2: string containing the name of the property. + * - Ret 1: something containing the attribute. + */ +static int impl_unit_type_get(lua_State *L) +{ + char const *m = luaL_checkstring(L, 2); + lua_pushstring(L, "id"); + lua_rawget(L, 1); + const unit_type *utp = unit_types.find(lua_tostring(L, -1)); + if (!utp) return luaL_argerror(L, 1, "unknown unit type"); + unit_type const &ut = *utp; + + // Find the corresponding attribute. + return_tstring_attrib("name", ut.type_name()); + return_int_attrib("max_hitpoints", ut.hitpoints()); + return_int_attrib("max_moves", ut.movement()); + return_int_attrib("max_experience", ut.experience_needed()); + return_int_attrib("cost", ut.cost()); + return_int_attrib("level", ut.level()); + return_int_attrib("recall_cost", ut.recall_cost()); + return_cfgref_attrib("__cfg", ut.get_cfg()); + return 0; +} + +namespace lua_unit_type { + std::string register_metatable(lua_State * L) + { + luaL_newmetatable(L, UnitType); + + lua_pushcfunction(L, impl_unit_type_get); + lua_setfield(L, -2, "__index"); + lua_pushstring(L, "unit type"); + lua_setfield(L, -2, "__metatable"); + + return "Adding unit type metatable...\n"; + } +} + +void luaW_pushunittype(lua_State *L, const std::string & id) +{ + lua_createtable(L, 0, 1); + lua_pushstring(L, id.c_str()); + lua_setfield(L, -2, "id"); + luaL_setmetatable(L, UnitType); +} diff --git a/src/scripting/lua_unit_type.hpp b/src/scripting/lua_unit_type.hpp new file mode 100644 index 000000000000..cb053c37b6dd --- /dev/null +++ b/src/scripting/lua_unit_type.hpp @@ -0,0 +1,34 @@ +/* + Copyright (C) 2014 by Chris Beck + Part of the Battle for Wesnoth Project http://www.wesnoth.org/ + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY. + + See the COPYING file for more details. +*/ + +#ifndef LUA_UNIT_TYPE_HPP_INCLUDED +#define LUA_UNIT_TYPE_HPP_INCLUDED + +struct lua_State; + +#include + +/** + * This namespace contains bindings for lua to hold a reference to a + * unit type and access its stats. + */ +namespace lua_unit_type { + std::string register_metatable(lua_State *); +} //end namespace lua_team + +/// Create a lua object containing a reference to a unittype, and a +/// metatable to access the properties. +void luaW_pushunittype(lua_State *, const std::string &); + +#endif