diff --git a/src/lua/functions/creatures/monster/loot_functions.cpp b/src/lua/functions/creatures/monster/loot_functions.cpp index 3fe3a188368..6dc39ac4cb0 100644 --- a/src/lua/functions/creatures/monster/loot_functions.cpp +++ b/src/lua/functions/creatures/monster/loot_functions.cpp @@ -12,231 +12,193 @@ #include "creatures/monsters/monsters.hpp" #include "lua/functions/creatures/monster/loot_functions.hpp" -int LootFunctions::luaCreateLoot(lua_State* L) { - // Loot() will create a new loot item - const auto loot = std::make_shared(); - pushUserdata(L, loot); - setMetatable(L, -1, "Loot"); +#define CHECK_NULL(loot, L) \ + if (!loot) { \ + g_logger().error("Invalid loot object"); \ + lua_pushnil(L); \ + return 1; \ + } + +#define CHECK_ARGS(expectedArgs) \ + if (lua_gettop(L) != expectedArgs) { \ + g_logger().error("Wrong number of arguments. Expected " + std::to_string(expectedArgs) + ", got " + std::to_string(lua_gettop(L))); \ + lua_pushnil(L); \ + return 1; \ + } + +#define SET_BOOL_RESULT(L, result) \ + lua_pushboolean(L, result); \ return 1; + +#define SET_ATTRIBUTE(loot, attribute, value) \ + loot->lootBlock.attribute = value; \ + SET_BOOL_RESULT(L, true) + +#define SET_STRING_ATTRIBUTE(loot, attribute, value) \ + loot->lootBlock.attribute = value; \ + SET_BOOL_RESULT(L, true) + +#define SET_NUMERIC_ATTRIBUTE(loot, attribute, type) \ + type attribute = static_cast(luaL_checkinteger(L, 2)); \ + SET_ATTRIBUTE(loot, attribute, attribute) + +#define SET_UNIQUE_ATTRIBUTE(loot, attribute) \ + if (lua_gettop(L) == 1) { \ + pushBoolean(L, loot->lootBlock.attribute); \ + return 1; \ + } else if (!lua_isboolean(L, 2)) { \ + g_logger().error("Invalid argument type. Boolean expected"); \ + lua_pushnil(L); \ + return 1; \ + } \ + loot->lootBlock.attribute = lua_toboolean(L, 2); \ + SET_BOOL_RESULT(L, true) + +int LootFunctions::luaCreateLoot(lua_State* L) { + try { + auto newLoot = std::make_shared(); + pushUserdata(L, newLoot); + setMetatable(L, -1, "Loot"); + return 1; + } catch (const std::exception &e) { + g_logger().error("Error creating loot: " + std::string(e.what())); + lua_pushnil(L); + return 1; + } } int LootFunctions::luaLootSetId(lua_State* L) { - // loot:setId(id) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - if (isNumber(L, 2)) { - loot->lootBlock.id = getNumber(L, 2); - pushBoolean(L, true); - } else { - g_logger().warn("[LootFunctions::luaLootSetId] - " - "Unknown loot item loot, int value expected"); - lua_pushnil(L); - } - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, id, uint16_t); } int LootFunctions::luaLootSetIdFromName(lua_State* L) { - // loot:setIdFromName(name) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot && isString(L, 2)) { - auto name = getString(L, 2); - auto ids = Item::items.nameToItems.equal_range(asLowerCaseString(name)); - - if (ids.first == Item::items.nameToItems.cend()) { - g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Unknown loot item {}", - name); - lua_pushnil(L); - return 1; - } + CHECK_NULL(loot, L); - if (std::next(ids.first) != ids.second) { - g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Non-unique loot item {}", - name); - lua_pushnil(L); - return 1; - } + if (!isString(L, 2)) { + g_logger().error("Unknown loot item or invalid argument type"); + lua_pushnil(L); + return 1; + } - loot->lootBlock.id = ids.first->second; - pushBoolean(L, true); - } else { - g_logger().warn("[LootFunctions::luaLootSetIdFromName] - " - "Unknown loot item loot, string value expected"); + auto name = getString(L, 2); + auto ids = Item::items.nameToItems.equal_range(asLowerCaseString(name)); + if (ids.first == Item::items.nameToItems.cend() || std::next(ids.first) != ids.second) { + g_logger().error("Unknown or non-unique loot item " + name); lua_pushnil(L); + return 1; } - return 1; + + loot->lootBlock.id = ids.first->second; + SET_BOOL_RESULT(L, true); } int LootFunctions::luaLootSetSubType(lua_State* L) { - // loot:setSubType(type) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.subType = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, subType, uint16_t); } int LootFunctions::luaLootSetChance(lua_State* L) { - // loot:setChance(chance) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.chance = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, chance, uint32_t); } int LootFunctions::luaLootSetMinCount(lua_State* L) { - // loot:setMinCount(min) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.countmin = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, countmin, uint32_t); } int LootFunctions::luaLootSetMaxCount(lua_State* L) { - // loot:setMaxCount(max) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.countmax = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, countmax, uint32_t); } int LootFunctions::luaLootSetActionId(lua_State* L) { - // loot:setActionId(actionid) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.actionId = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, actionId, uint32_t); } int LootFunctions::luaLootSetText(lua_State* L) { - // loot:setText(text) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.text = getString(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_STRING_ATTRIBUTE(loot, text, luaL_checkstring(L, 2)); } int LootFunctions::luaLootSetNameItem(lua_State* L) { - // loot:setNameItem(name) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.name = getString(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_STRING_ATTRIBUTE(loot, name, luaL_checkstring(L, 2)); } int LootFunctions::luaLootSetArticle(lua_State* L) { - // loot:setArticle(article) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.article = getString(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_STRING_ATTRIBUTE(loot, article, luaL_checkstring(L, 2)); } int LootFunctions::luaLootSetAttack(lua_State* L) { - // loot:setAttack(attack) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.attack = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, attack, uint32_t); } int LootFunctions::luaLootSetDefense(lua_State* L) { - // loot:setDefense(defense) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.defense = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, defense, uint32_t); } int LootFunctions::luaLootSetExtraDefense(lua_State* L) { - // loot:setExtraDefense(defense) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.extraDefense = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, extraDefense, uint32_t); } int LootFunctions::luaLootSetArmor(lua_State* L) { - // loot:setArmor(armor) const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.armor = getNumber(L, 2); - pushBoolean(L, true); - } else { + CHECK_NULL(loot, L); + uint32_t armor = 0; + if (!getNumber(L, 2, armor)) { + g_logger().error("Invalid armor value"); lua_pushnil(L); + return 1; } - return 1; + loot->lootBlock.armor = armor; + SET_BOOL_RESULT(L, true); } int LootFunctions::luaLootSetShootRange(lua_State* L) { - // loot:setShootRange(range) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.shootRange = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, shootRange, uint32_t); } int LootFunctions::luaLootSetHitChance(lua_State* L) { - // loot:setHitChance(chance) + CHECK_ARGS(2); const auto loot = getUserdataShared(L, 1); - if (loot) { - loot->lootBlock.hitChance = getNumber(L, 2); - pushBoolean(L, true); - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + SET_NUMERIC_ATTRIBUTE(loot, hitChance, uint32_t); } int LootFunctions::luaLootSetUnique(lua_State* L) { @@ -245,9 +207,12 @@ int LootFunctions::luaLootSetUnique(lua_State* L) { if (loot) { if (lua_gettop(L) == 1) { pushBoolean(L, loot->lootBlock.unique); - } else { - loot->lootBlock.unique = getBoolean(L, 2); + } else if (lua_isboolean(L, 2)) { + loot->lootBlock.unique = lua_toboolean(L, 2); pushBoolean(L, true); + } else { + g_logger().error("[LootFunctions::luaLootSetUnique] - Invalid argument type. Boolean expected"); + lua_pushnil(L); } } else { lua_pushnil(L); @@ -256,18 +221,10 @@ int LootFunctions::luaLootSetUnique(lua_State* L) { } int LootFunctions::luaLootAddChildLoot(lua_State* L) { - // loot:addChildLoot(loot) const auto loot = getUserdataShared(L, 1); - if (loot) { - const auto childLoot = getUserdata(L, 2); - if (childLoot) { - loot->lootBlock.childLoot.push_back(childLoot->lootBlock); - pushBoolean(L, true); - } else { - pushBoolean(L, false); - } - } else { - lua_pushnil(L); - } - return 1; + CHECK_NULL(loot, L); + const auto childLoot = getUserdata(L, 2); + CHECK_NULL(childLoot, L); + loot->lootBlock.childLoot.push_back(childLoot->lootBlock); + SET_BOOL_RESULT(L, true); }