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 -- 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/src/CMakeLists.txt b/src/CMakeLists.txt index c41de6575132..ef49229dadaa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -971,7 +971,9 @@ 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/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 aa0519600ec2..b1f29a1ed716 100644 --- a/src/SConscript +++ b/src/SConscript @@ -544,7 +544,9 @@ 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/lua_unit_type.cpp scripting/mapgen_lua_kernel.cpp scripting/plugins/context.cpp scripting/plugins/manager.cpp 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/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 117b533d3de0..e73983c1e4ab 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -77,7 +77,9 @@ #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 "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 @@ -198,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. @@ -483,8 +458,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 +752,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 @@ -959,101 +934,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 +2779,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; } @@ -3775,30 +3642,10 @@ 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"; - - 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"; @@ -3939,45 +3786,34 @@ 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"; + 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_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_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 340cd1677af1..dbb1f0ff9d5b 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -15,29 +15,15 @@ #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..0f071c378434 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -19,17 +19,10 @@ 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 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 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 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 #