diff --git a/src/scripting/game_lua_kernel.cpp b/src/scripting/game_lua_kernel.cpp index 5d5b46c0318c..826b552b94a3 100644 --- a/src/scripting/game_lua_kernel.cpp +++ b/src/scripting/game_lua_kernel.cpp @@ -297,6 +297,16 @@ static int impl_unit_get(lua_State *L) lua_setmetatable(L, -2); return 1; } + if (strcmp(m, "attacks") == 0) { + lua_createtable(L, 1, 0); + lua_pushvalue(L, 1); + // hack: store the unit at -1 becasue we want positive indexes to refers to the attacks. + lua_rawseti(L, -2, -1); + lua_pushlightuserdata(L, uattacksKey); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + return 1; + } return_bool_attrib("hidden", u.get_hidden()); return_bool_attrib("petrified", u.incapacitated()); return_bool_attrib("resting", u.resting()); @@ -402,6 +412,182 @@ static int impl_unit_variables_get(lua_State *L) luaW_pushscalar(L, u->variables()[m]); return 1; } +/** + * Gets the attacks of a unit (__index metamethod). + * - Arg 1: table containing the userdata containing the unit id. + * - Arg 2: index (int) or id (string) identyfying teh units attack. + * - Ret 1: the units attack. + */ +static int impl_unit_attacks_get(lua_State *L) +{ + if (!lua_istable(L, 1)) { + return luaL_typerror(L, 1, "unit attacks"); + } + lua_rawgeti(L, 1, -1); + const unit_const_ptr u = luaW_tounit(L, -1); + if (!u) { + return luaL_argerror(L, 1, "unknown unit"); + } + const attack_type* attack = NULL; + const std::vector& attacks = u->attacks(); + if(!lua_isnumber(L,2)) { + std::string attack_id = luaL_checkstring(L, 2); + BOOST_FOREACH(const attack_type& at, attacks) { + if(at.id() == attack_id) { + attack = &at; + break; + } + } + if (attack == NULL) { + //return nil on invalid index, just like lua tables do. + return 0; + } + } + else + { + // + size_t index = luaL_checkinteger(L, 2) - 1; + if (index >= attacks.size()) { + //return nil on invalid index, just like lua tables do. + return 0; + } + attack = &attacks[index]; + } + + // stack { lua_unit }, id/index, lua_unit + lua_createtable(L, 2, 0); + // stack { lua_unit }, id/index, lua_unit, table + lua_pushvalue(L, -2); + // stack { lua_unit }, id/index, lua_unit, table, lua_unit + lua_rawseti(L, -2, 1); + // stack { lua_unit }, id/index, lua_unit, table + lua_pushstring(L, attack->id().c_str()); + // stack { lua_unit }, id/index, lua_unit, table, attack id + lua_rawseti(L, -2, 2); + // stack { lua_unit }, id/index, lua_unit, table + lua_pushlightuserdata(L, uattackKey); + lua_rawget(L, LUA_REGISTRYINDEX); + lua_setmetatable(L, -2); + return 1; +} + +/** + * Counts the attacks of a unit (__len metamethod). + * - Arg 1: table containing the userdata containing the unit id. + * - Ret 1: size of unit attacks vector. + */ +static int impl_unit_attacks_len(lua_State *L) +{ + if (!lua_istable(L, 1)) { + return luaL_typerror(L, 1, "unit attacks"); + } + lua_rawgeti(L, 1, -1); + const unit_const_ptr u = luaW_tounit(L, -1); + if (!u) { + return luaL_argerror(L, 1, "unknown unit"); + } + lua_pushinteger(L, u->attacks().size()); + return 1; +} + +/** + * Gets a propoerty of a units attack (__index metamethod). + * - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack. + * - Arg 2: string + * - Ret 1: + */ +static int impl_unit_attack_get(lua_State *L) +{ + if (!lua_istable(L, 1)) { + return luaL_typerror(L, 1, "unit attack"); + } + lua_rawgeti(L, 1, 1); + const unit_const_ptr u = luaW_tounit(L, -1); + if (!u) { + return luaL_argerror(L, 1, "unknown unit"); + } + lua_rawgeti(L, 1, 2); + std::string attack_id = luaL_checkstring(L, -1); + char const *m = luaL_checkstring(L, 2); + BOOST_FOREACH(const attack_type& attack, u->attacks()) + { + if(attack.id() == attack_id) + { + + return_string_attrib("description", attack.name()); + return_string_attrib("name", attack.id()); + return_string_attrib("type", attack.type()); + return_string_attrib("icon", attack.icon()); + return_string_attrib("range", attack.range()); + // "min_range" + // "max_range" + return_int_attrib("damage", attack.damage()); + return_int_attrib("number", attack.num_attacks()); + return_int_attrib("attack_weight", attack.attack_weight()); + return_int_attrib("defense_weight", attack.defense_weight()); + //"accuracy" + return_int_attrib("movement_used", attack.movement_used()); + // "parry" + return_cfgref_attrib("specials", attack.specials()); + std::string err_msg = "unknown property of attack: "; + err_msg += m; + return luaL_argerror(L, 2, err_msg.c_str()); + } + } + return luaL_argerror(L, 1, "invalid attack id"); +} + +/** + * Gets a propoerty of a units attack (__index metamethod). + * - Arg 1: table containing the userdata containing the unit id. and a string identyfying the attack. + * - Arg 2: string + * - Ret 1: + */ +static int impl_unit_attack_set(lua_State *L) +{ + if (!lua_istable(L, 1)) { + return luaL_typerror(L, 1, "unit attack"); + } + lua_rawgeti(L, 1, 1); + const unit_ptr u = luaW_tounit(L, -1); + if (!u) { + return luaL_argerror(L, 1, "unknown unit"); + } + lua_rawgeti(L, 1, 2); + std::string attack_id = luaL_checkstring(L, -1); + char const *m = luaL_checkstring(L, 2); + BOOST_FOREACH(attack_type& attack, u->attacks()) + { + if(attack.id() == attack_id) + { + + modify_tstring_attrib("description", attack.set_name(value)); + // modify_string_attrib("name", attack.set_id(value)); + modify_string_attrib("type", attack.set_type(value)); + modify_string_attrib("icon", attack.set_icon(value)); + modify_string_attrib("range", attack.set_range(value)); + // "min_range" + // "max_range" + modify_int_attrib("damage", attack.set_damage(value)); + modify_int_attrib("number", attack.set_num_attacks(value)); + modify_int_attrib("attack_weight", attack.set_attack_weight(value)); + modify_int_attrib("defense_weight", attack.set_defense_weight(value)); + //"accuracy" + modify_int_attrib("movement_used", attack.set_movement_used(value)); + // "parry" + + if (strcmp(m, "specials") == 0) { \ + attack.set_specials(luaW_checkconfig(L, 3)); + return 0; + } + return_cfgref_attrib("specials", attack.specials()); + std::string err_msg = "unknown modifyable property of attack: "; + err_msg += m; + return luaL_argerror(L, 2, err_msg.c_str()); + } + } + return luaL_argerror(L, 1, "invalid attack id"); +} /** * Sets the variable of a unit (__newindex metamethod). @@ -3881,6 +4067,31 @@ game_lua_kernel::game_lua_kernel(const config &cfg, CVideo * video, game_state & lua_setfield(L, -2, "__metatable"); lua_rawset(L, LUA_REGISTRYINDEX); + // Create the unit attacks metatable. + cmd_log_ << "Adding unit attacks metatable...\n"; + + lua_pushlightuserdata(L, uattacksKey); + lua_createtable(L, 0, 3); + lua_pushcfunction(L, impl_unit_attacks_get); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, impl_unit_attacks_len); + lua_setfield(L, -2, "__len"); + lua_pushstring(L, "unit attacks"); + lua_setfield(L, -2, "__metatable"); + lua_rawset(L, LUA_REGISTRYINDEX); + + + + lua_pushlightuserdata(L, uattackKey); + lua_createtable(L, 0, 3); + lua_pushcfunction(L, impl_unit_attack_get); + lua_setfield(L, -2, "__index"); + lua_pushcfunction(L, impl_unit_attack_set); + lua_setfield(L, -2, "__newindex"); + lua_pushstring(L, "unit attack"); + lua_setfield(L, -2, "__metatable"); + lua_rawset(L, LUA_REGISTRYINDEX); + // Create the unit variables metatable. cmd_log_ << "Adding unit variables metatable...\n"; diff --git a/src/scripting/lua_types.cpp b/src/scripting/lua_types.cpp index 432859335be4..871335345871 100644 --- a/src/scripting/lua_types.cpp +++ b/src/scripting/lua_types.cpp @@ -19,9 +19,13 @@ static char const v_executeKey = 0; static char const v_getunitKey = 0; static char const v_unitvarKey = 0; static char const v_ustatusKey = 0; +static char const v_uattacksKey = 0; +static char const v_uattackKey = 0; luatypekey const executeKey = static_cast(const_cast(&v_executeKey)); 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 uattacksKey = static_cast(const_cast(&v_uattacksKey)); +luatypekey const uattackKey = static_cast(const_cast(&v_uattackKey)); diff --git a/src/scripting/lua_types.hpp b/src/scripting/lua_types.hpp index 9ac7a3cb8629..9ada769aa1d1 100644 --- a/src/scripting/lua_types.hpp +++ b/src/scripting/lua_types.hpp @@ -23,5 +23,7 @@ extern luatypekey const executeKey; extern luatypekey const getunitKey; extern luatypekey const unitvarKey; extern luatypekey const ustatusKey; +extern luatypekey const uattacksKey; +extern luatypekey const uattackKey; #endif diff --git a/src/unit_attack_type.hpp b/src/unit_attack_type.hpp index f891e1f21b16..ed0a00e7102b 100644 --- a/src/unit_attack_type.hpp +++ b/src/unit_attack_type.hpp @@ -46,6 +46,23 @@ class attack_type int num_attacks() const { return num_attacks_; } double attack_weight() const { return attack_weight_; } double defense_weight() const { return defense_weight_; } + const config specials() const { return specials_; } + + void set_name(const t_string& value) { description_ = value; } + // void set_id(const std::string& value) { return id = value; } + void set_type(const std::string& value) { type_ = value; } + void set_icon(const std::string& value) { icon_ = value; } + void set_range(const std::string& value) { range_ = value; } + // void set_min_range(int value) { min_range_ = value; } + // void set_max_range(int value) { max_range_ = value; } + // void set_accuracy(int value) { accuracy_ = value; } + // void set_parry(int value) { parry_ = value; } + void set_damage(int value) { damage_ = value; } + void set_num_attacks(int value) { num_attacks_ = value; } + void set_attack_weight(double value) { attack_weight_ = value; } + void set_defense_weight(double value) { defense_weight_ = value; } + void set_specials(config value) { specials_ = value; } + // In unit_abilities.cpp: @@ -70,6 +87,7 @@ class attack_type bool describe_modification(const config& cfg,std::string* description); int movement_used() const { return movement_used_; } + void set_movement_used(int value) { movement_used_ = value; } void write(config& cfg) const; inline config to_config() const { config c; write(c); return c; }