Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: on loot functions #2448

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
295 changes: 126 additions & 169 deletions src/lua/functions/creatures/monster/loot_functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Loot>();
pushUserdata<Loot>(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<type>(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<Loot>();
pushUserdata<Loot>(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<Loot>(L, 1);
if (loot) {
if (isNumber(L, 2)) {
loot->lootBlock.id = getNumber<uint16_t>(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<Loot>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.subType = getNumber<uint16_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.chance = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.countmin = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.countmax = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.actionId = getNumber<uint32_t>(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<Loot>(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<Loot>(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<Loot>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.attack = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.defense = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.extraDefense = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.armor = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.shootRange = getNumber<uint32_t>(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<Loot>(L, 1);
if (loot) {
loot->lootBlock.hitChance = getNumber<uint32_t>(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) {
Expand All @@ -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);
Expand All @@ -256,18 +221,10 @@ int LootFunctions::luaLootSetUnique(lua_State* L) {
}

int LootFunctions::luaLootAddChildLoot(lua_State* L) {
// loot:addChildLoot(loot)
const auto loot = getUserdataShared<Loot>(L, 1);
if (loot) {
const auto childLoot = getUserdata<Loot>(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<Loot>(L, 2);
CHECK_NULL(childLoot, L);
loot->lootBlock.childLoot.push_back(childLoot->lootBlock);
SET_BOOL_RESULT(L, true);
}