From 64020c2807cf24d84393dd960336b85184e5ffac Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Wed, 2 Aug 2023 03:03:53 -0300 Subject: [PATCH 01/13] fix: use item and use with for guests in houses --- .../scripts/actions/other/teleport.lua | 8 +- src/enums/item_dummy_ids.hpp | 41 +++++++++ src/enums/item_ladder_ids.hpp | 45 ++++++++++ src/game/game.cpp | 83 +++++++++++++++---- .../functions/core/game/game_functions.cpp | 36 ++++++++ .../functions/core/game/game_functions.hpp | 6 ++ 6 files changed, 201 insertions(+), 18 deletions(-) create mode 100644 src/enums/item_dummy_ids.hpp create mode 100644 src/enums/item_ladder_ids.hpp diff --git a/data-otservbr-global/scripts/actions/other/teleport.lua b/data-otservbr-global/scripts/actions/other/teleport.lua index 3e2de42568f..0a785d2c883 100644 --- a/data-otservbr-global/scripts/actions/other/teleport.lua +++ b/data-otservbr-global/scripts/actions/other/teleport.lua @@ -1,4 +1,6 @@ -local upFloorIds = {1948, 1968, 5542, 20474, 20475, 1968, 28656, 31262, 31129, 31130, 34243} +local ladderTable = Game.getLadderTable() + +local upFloorIds = ladderTable local teleport = Action() @@ -12,5 +14,7 @@ function teleport.onUse(player, item, fromPosition, target, toPosition, isHotkey return true end -teleport:id(435, 1948, 1968, 5542, 20474, 20475, 28656, 31129, 31130, 31262, 34243) +-- Gate +teleport:id(435) +teleport:id(unpack(ladderTable)) teleport:register() diff --git a/src/enums/item_dummy_ids.hpp b/src/enums/item_dummy_ids.hpp new file mode 100644 index 00000000000..af9d28f45a3 --- /dev/null +++ b/src/enums/item_dummy_ids.hpp @@ -0,0 +1,41 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2022 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#ifndef SRC_ENUMS_ITEM_DUMMY_IDS_HPP +#define SRC_ENUMS_ITEM_DUMMY_IDS_HPP + +enum class ItemDummyIds_t : uint16_t { + Item_1 = 28558, + Item_2 = 28559, + Item_3 = 28560, + Item_4 = 28561, + Item_5 = 28562, + Item_6 = 28563, + Item_7 = 28564, + Item_8 = 28565, + Item_9 = 26077, +}; + +namespace ItemDummyIdsArray { + constexpr std::array get() { + return { + static_cast(ItemDummyIds_t::Item_1), + static_cast(ItemDummyIds_t::Item_2), + static_cast(ItemDummyIds_t::Item_3), + static_cast(ItemDummyIds_t::Item_4), + static_cast(ItemDummyIds_t::Item_5), + static_cast(ItemDummyIds_t::Item_6), + static_cast(ItemDummyIds_t::Item_7), + static_cast(ItemDummyIds_t::Item_8), + static_cast(ItemDummyIds_t::Item_9), + }; + } +} + +#endif // SRC_ENUMS_ITEM_DUMMY_IDS_HPP diff --git a/src/enums/item_ladder_ids.hpp b/src/enums/item_ladder_ids.hpp new file mode 100644 index 00000000000..4f0af63eb7f --- /dev/null +++ b/src/enums/item_ladder_ids.hpp @@ -0,0 +1,45 @@ +/** + * Canary - A free and open-source MMORPG server emulator + * Copyright (©) 2019-2022 OpenTibiaBR + * Repository: https://github.com/opentibiabr/canary + * License: https://github.com/opentibiabr/canary/blob/main/LICENSE + * Contributors: https://github.com/opentibiabr/canary/graphs/contributors + * Website: https://docs.opentibiabr.com/ + */ + +#ifndef SRC_ENUMS_ITEM_LADDER_IDS_HPP +#define SRC_ENUMS_ITEM_LADDER_IDS_HPP + +enum class ItemLadderIds_t : uint16_t { + Item_1 = 1948, + Item_2 = 1968, + Item_3 = 5542, + Item_4 = 20474, + Item_5 = 20475, + Item_6 = 28656, + Item_7 = 21935, + Item_8 = 31129, + Item_9 = 31130, + Item_10 = 34243, + Item_11 = 33770, +}; + +namespace ItemLadderIdsArray { + constexpr std::array get() { + return { + static_cast(ItemLadderIds_t::Item_1), + static_cast(ItemLadderIds_t::Item_2), + static_cast(ItemLadderIds_t::Item_3), + static_cast(ItemLadderIds_t::Item_4), + static_cast(ItemLadderIds_t::Item_5), + static_cast(ItemLadderIds_t::Item_6), + static_cast(ItemLadderIds_t::Item_7), + static_cast(ItemLadderIds_t::Item_8), + static_cast(ItemLadderIds_t::Item_9), + static_cast(ItemLadderIds_t::Item_10), + static_cast(ItemLadderIds_t::Item_11), + }; + } +} + +#endif // SRC_ENUMS_ITEM_LADDER_IDS_HPP diff --git a/src/game/game.cpp b/src/game/game.cpp index 6850273e897..b7ab65f7a65 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -24,6 +24,8 @@ #include "io/io_wheel.hpp" #include "io/iomarket.h" #include "items/items.h" +#include "enums/item_dummy_ids.hpp" +#include "enums/item_ladder_ids.hpp" #include "lua/scripts/lua_environment.hpp" #include "creatures/monsters/monster.h" #include "lua/creature/movement.h" @@ -85,6 +87,65 @@ namespace InternalGame { } } + bool playerCanUseItemOnHouseTile(Player* player, Item* item) { + if (!player || !item) { + return false; + } + + auto itemTile = item->getTile(); + if (!itemTile) { + return false; + } + + if (HouseTile* houseTile = dynamic_cast(itemTile)) { + House* house = houseTile->getHouse(); + // If not invited return false + if (!house || !house->isInvited(player)) { + return false; + } + + // Check is guest player + auto isGuest = house->getHouseAccessLevel(player) == HOUSE_GUEST; + // Cannot use in browse field + auto container = item->getParent() ? item->getParent()->getContainer() : nullptr; + if (isGuest && container && container->getID() == ITEM_BROWSEFIELD) { + return false; + } + + auto realItemParent = item->getRealParent(); + // Check if item is not in player inventory or player backpack/storeinbox + auto canUseItem = realItemParent && (realItemParent == player || realItemParent->getContainer()); + auto array = ItemLadderIdsArray::get(); + bool isExceptedItem = std::find(array.begin(), array.end(), item->getID()) != array.end(); + if (isGuest && !canUseItem && !isExceptedItem) { + return false; + } + } + + return true; + } + + bool playerCanUseItemWithOnHouseTile(Player* player, Item* item, const Position &toPos, int toStackPos, int toItemId) { + if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS)) { + if (HouseTile* houseTile = dynamic_cast(item->getTile())) { + House* house = houseTile->getHouse(); + Thing* targetThing = g_game().internalGetThing(player, toPos, toStackPos, toItemId, STACKPOS_FIND_THING); + auto targetItem = targetThing ? targetThing->getItem() : nullptr; + uint16_t targetId = targetItem ? targetItem->getID() : 0; + auto invitedCheckUseWith = house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST); + + auto array = ItemDummyIdsArray::get(); + bool isExceptedItem = std::find(array.begin(), array.end(), targetId) != array.end(); + if (targetId != 0 && !isExceptedItem && invitedCheckUseWith) { + player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); + return false; + } + } + } + + return true; + } + } // Namespace InternalGame Game::Game() { @@ -2981,14 +3042,9 @@ void Game::playerUseItemEx(uint32_t playerId, const Position &fromPos, uint8_t f return; } - if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS)) { - if (HouseTile* houseTile = dynamic_cast(item->getTile())) { - House* house = houseTile->getHouse(); - if (house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST)) { - player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); - return; - } - } + if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS) && !InternalGame::playerCanUseItemWithOnHouseTile(player, item, toPos, toStackPos, toItemId)) { + player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); + return; } Position walkToPos = fromPos; @@ -3115,14 +3171,9 @@ void Game::playerUseItem(uint32_t playerId, const Position &pos, uint8_t stackPo return; } - if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS)) { - if (HouseTile* houseTile = dynamic_cast(item->getTile())) { - House* house = houseTile->getHouse(); - if (house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST)) { - player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); - return; - } - } + if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS) && !InternalGame::playerCanUseItemOnHouseTile(player, item)) { + player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); + return; } const ItemType &it = Item::items[item->getID()]; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index f1bc6db742d..9873b5c2b99 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -14,6 +14,8 @@ #include "game/functions/game_reload.hpp" #include "game/game.h" #include "items/item.h" +#include "enums/item_dummy_ids.hpp" +#include "enums/item_ladder_ids.hpp" #include "io/iobestiary.h" #include "io/io_bosstiary.hpp" #include "io/iologindata.h" @@ -652,6 +654,40 @@ int GameFunctions::luaGameGetInfluencedMonsters(lua_State* L) { return 1; } +int GameFunctions::luaGameGetLadderTable(lua_State* L) { + // Game.getLadderTable() + lua_newtable(L); + int index = 1; + auto array = ItemLadderIdsArray::get(); + for (const auto &itemId : array) { + if (itemId == 0) { + continue; + } + + lua_pushnumber(L, static_cast(itemId)); + lua_rawseti(L, -2, index++); + } + + return 1; +} + +int GameFunctions::luaGameGetDummyTable(lua_State* L) { + // Game.getDummyTable() + lua_newtable(L); + int index = 1; + auto array = ItemLadderIdsArray::get(); + for (const auto &itemId : array) { + if (itemId == 0) { + continue; + } + + lua_pushnumber(L, static_cast(itemId)); + lua_rawseti(L, -2, index++); + } + + return 1; +} + int GameFunctions::luaGameMakeFiendishMonster(lua_State* L) { // Game.makeFiendishMonster(monsterId[default= 0]) uint32_t monsterId = getNumber(L, 1, 0); diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index a2a5ddd2c36..3ae677799dd 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -76,6 +76,9 @@ class GameFunctions final : LuaScriptInterface { registerMethod(L, "Game", "getBoostedBoss", GameFunctions::luaGameGetBoostedBoss); registerMethod(L, "Game", "createHazardArea", GameFunctions::luaGameCreateHazardArea); + + registerMethod(L, "Game", "getLadderTable", GameFunctions::luaGameGetLadderTable); + registerMethod(L, "Game", "getDummyTable", GameFunctions::luaGameGetDummyTable); } private: @@ -139,6 +142,9 @@ class GameFunctions final : LuaScriptInterface { static int luaGameGetBoostedBoss(lua_State* L); static int luaGameCreateHazardArea(lua_State* L); + + static int luaGameGetLadderTable(lua_State* L); + static int luaGameGetDummyTable(lua_State* L); }; #endif // SRC_LUA_FUNCTIONS_CORE_GAME_GAME_FUNCTIONS_HPP_ From d93a5d715bedfb2c73676850a51753c2c3feee96 Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Wed, 2 Aug 2023 06:11:18 +0000 Subject: [PATCH 02/13] Code format - (Clang-format) --- src/enums/item_ladder_ids.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/enums/item_ladder_ids.hpp b/src/enums/item_ladder_ids.hpp index 4f0af63eb7f..98ee21cd618 100644 --- a/src/enums/item_ladder_ids.hpp +++ b/src/enums/item_ladder_ids.hpp @@ -28,16 +28,16 @@ namespace ItemLadderIdsArray { constexpr std::array get() { return { static_cast(ItemLadderIds_t::Item_1), - static_cast(ItemLadderIds_t::Item_2), - static_cast(ItemLadderIds_t::Item_3), - static_cast(ItemLadderIds_t::Item_4), - static_cast(ItemLadderIds_t::Item_5), - static_cast(ItemLadderIds_t::Item_6), - static_cast(ItemLadderIds_t::Item_7), - static_cast(ItemLadderIds_t::Item_8), - static_cast(ItemLadderIds_t::Item_9), - static_cast(ItemLadderIds_t::Item_10), - static_cast(ItemLadderIds_t::Item_11), + static_cast(ItemLadderIds_t::Item_2), + static_cast(ItemLadderIds_t::Item_3), + static_cast(ItemLadderIds_t::Item_4), + static_cast(ItemLadderIds_t::Item_5), + static_cast(ItemLadderIds_t::Item_6), + static_cast(ItemLadderIds_t::Item_7), + static_cast(ItemLadderIds_t::Item_8), + static_cast(ItemLadderIds_t::Item_9), + static_cast(ItemLadderIds_t::Item_10), + static_cast(ItemLadderIds_t::Item_11), }; } } From 707f1a85280a2ee8d746f3234ff381792d1e2dcc Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 4 Aug 2023 15:32:13 -0300 Subject: [PATCH 03/13] fix: change to items.xml instead of cpp hardcoded --- data/items/items.xml | 38 +++++++++++++--- src/enums/item_dummy_ids.hpp | 41 ----------------- src/enums/item_ladder_ids.hpp | 45 ------------------- src/game/game.cpp | 11 +---- src/items/functions/item/item_parse.cpp | 7 +++ src/items/functions/item/item_parse.hpp | 3 ++ src/items/item.h | 6 +++ src/items/items.h | 22 +++++++++ src/items/items_definitions.hpp | 4 ++ .../functions/core/game/game_functions.cpp | 36 ++++++--------- 10 files changed, 89 insertions(+), 124 deletions(-) delete mode 100644 src/enums/item_dummy_ids.hpp delete mode 100644 src/enums/item_ladder_ids.hpp diff --git a/data/items/items.xml b/data/items/items.xml index dae30e562a3..7657bd98447 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -2675,7 +2675,9 @@ - + + + @@ -2721,7 +2723,9 @@ - + + + @@ -11075,7 +11079,9 @@ - + + + @@ -31520,7 +31526,9 @@ - + + + @@ -40932,39 +40940,47 @@ + + + + + + + + @@ -41364,7 +41380,9 @@ - + + + @@ -44588,9 +44606,11 @@ + + @@ -49089,7 +49109,9 @@ - + + + @@ -50824,7 +50846,9 @@ - + + + diff --git a/src/enums/item_dummy_ids.hpp b/src/enums/item_dummy_ids.hpp deleted file mode 100644 index af9d28f45a3..00000000000 --- a/src/enums/item_dummy_ids.hpp +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Canary - A free and open-source MMORPG server emulator - * Copyright (©) 2019-2022 OpenTibiaBR - * Repository: https://github.com/opentibiabr/canary - * License: https://github.com/opentibiabr/canary/blob/main/LICENSE - * Contributors: https://github.com/opentibiabr/canary/graphs/contributors - * Website: https://docs.opentibiabr.com/ - */ - -#ifndef SRC_ENUMS_ITEM_DUMMY_IDS_HPP -#define SRC_ENUMS_ITEM_DUMMY_IDS_HPP - -enum class ItemDummyIds_t : uint16_t { - Item_1 = 28558, - Item_2 = 28559, - Item_3 = 28560, - Item_4 = 28561, - Item_5 = 28562, - Item_6 = 28563, - Item_7 = 28564, - Item_8 = 28565, - Item_9 = 26077, -}; - -namespace ItemDummyIdsArray { - constexpr std::array get() { - return { - static_cast(ItemDummyIds_t::Item_1), - static_cast(ItemDummyIds_t::Item_2), - static_cast(ItemDummyIds_t::Item_3), - static_cast(ItemDummyIds_t::Item_4), - static_cast(ItemDummyIds_t::Item_5), - static_cast(ItemDummyIds_t::Item_6), - static_cast(ItemDummyIds_t::Item_7), - static_cast(ItemDummyIds_t::Item_8), - static_cast(ItemDummyIds_t::Item_9), - }; - } -} - -#endif // SRC_ENUMS_ITEM_DUMMY_IDS_HPP diff --git a/src/enums/item_ladder_ids.hpp b/src/enums/item_ladder_ids.hpp deleted file mode 100644 index 98ee21cd618..00000000000 --- a/src/enums/item_ladder_ids.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/** - * Canary - A free and open-source MMORPG server emulator - * Copyright (©) 2019-2022 OpenTibiaBR - * Repository: https://github.com/opentibiabr/canary - * License: https://github.com/opentibiabr/canary/blob/main/LICENSE - * Contributors: https://github.com/opentibiabr/canary/graphs/contributors - * Website: https://docs.opentibiabr.com/ - */ - -#ifndef SRC_ENUMS_ITEM_LADDER_IDS_HPP -#define SRC_ENUMS_ITEM_LADDER_IDS_HPP - -enum class ItemLadderIds_t : uint16_t { - Item_1 = 1948, - Item_2 = 1968, - Item_3 = 5542, - Item_4 = 20474, - Item_5 = 20475, - Item_6 = 28656, - Item_7 = 21935, - Item_8 = 31129, - Item_9 = 31130, - Item_10 = 34243, - Item_11 = 33770, -}; - -namespace ItemLadderIdsArray { - constexpr std::array get() { - return { - static_cast(ItemLadderIds_t::Item_1), - static_cast(ItemLadderIds_t::Item_2), - static_cast(ItemLadderIds_t::Item_3), - static_cast(ItemLadderIds_t::Item_4), - static_cast(ItemLadderIds_t::Item_5), - static_cast(ItemLadderIds_t::Item_6), - static_cast(ItemLadderIds_t::Item_7), - static_cast(ItemLadderIds_t::Item_8), - static_cast(ItemLadderIds_t::Item_9), - static_cast(ItemLadderIds_t::Item_10), - static_cast(ItemLadderIds_t::Item_11), - }; - } -} - -#endif // SRC_ENUMS_ITEM_LADDER_IDS_HPP diff --git a/src/game/game.cpp b/src/game/game.cpp index b7ab65f7a65..54ef34f6983 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -24,8 +24,6 @@ #include "io/io_wheel.hpp" #include "io/iomarket.h" #include "items/items.h" -#include "enums/item_dummy_ids.hpp" -#include "enums/item_ladder_ids.hpp" #include "lua/scripts/lua_environment.hpp" #include "creatures/monsters/monster.h" #include "lua/creature/movement.h" @@ -115,9 +113,7 @@ namespace InternalGame { auto realItemParent = item->getRealParent(); // Check if item is not in player inventory or player backpack/storeinbox auto canUseItem = realItemParent && (realItemParent == player || realItemParent->getContainer()); - auto array = ItemLadderIdsArray::get(); - bool isExceptedItem = std::find(array.begin(), array.end(), item->getID()) != array.end(); - if (isGuest && !canUseItem && !isExceptedItem) { + if (isGuest && !canUseItem && !item->isLadder()) { return false; } } @@ -133,10 +129,7 @@ namespace InternalGame { auto targetItem = targetThing ? targetThing->getItem() : nullptr; uint16_t targetId = targetItem ? targetItem->getID() : 0; auto invitedCheckUseWith = house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST); - - auto array = ItemDummyIdsArray::get(); - bool isExceptedItem = std::find(array.begin(), array.end(), targetId) != array.end(); - if (targetId != 0 && !isExceptedItem && invitedCheckUseWith) { + if (targetId != 0 && !targetItem->isDummy() && invitedCheckUseWith) { player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); return false; } diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index 44949217af2..0c81cebbee1 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -84,6 +84,13 @@ void ItemParse::parseType(const std::string &tmpStrValue, pugi::xml_attribute va if (itemType.type == ITEM_TYPE_CONTAINER) { itemType.group = ITEM_GROUP_CONTAINER; } + if (itemType.type == ITEM_TYPE_LADDER) { + Item::items.addLadderId(itemType.id); + } + if (itemType.type == ITEM_TYPE_DUMMY) { + Item::items.addDummyId(itemType.id); + } + } else { SPDLOG_WARN("[Items::parseItemNode] - Unknown type: {}", valueAttribute.as_string()); } diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index 82a985c4963..60537769d57 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -176,6 +176,9 @@ const phmap::flat_hash_map ItemTypesMap = { { "food", ITEM_TYPE_FOOD }, { "valuable", ITEM_TYPE_VALUABLE }, { "potion", ITEM_TYPE_POTION }, + + { "ladder", ITEM_TYPE_LADDER }, + { "dummy", ITEM_TYPE_DUMMY }, }; const phmap::flat_hash_map TileStatesMap = { diff --git a/src/items/item.h b/src/items/item.h index dcc66005161..c642e685763 100644 --- a/src/items/item.h +++ b/src/items/item.h @@ -475,6 +475,12 @@ class Item : virtual public Thing, public ItemProperties { bool isSpellBook() const { return items[id].isSpellBook(); } + bool isLadder() const { + return items[id].isLadder(); + } + bool isDummy() const { + return items[id].isDummy(); + } const std::string &getName() const { if (hasAttribute(ItemAttribute_t::NAME)) { diff --git a/src/items/items.h b/src/items/items.h index 9ac8561dd99..4a38913f94a 100644 --- a/src/items/items.h +++ b/src/items/items.h @@ -172,6 +172,12 @@ class ItemType { bool isQuiver() const { return (type == ITEM_TYPE_QUIVER); } + bool isLadder() const { + return (type == ITEM_TYPE_LADDER); + } + bool isDummy() const { + return (type == ITEM_TYPE_DUMMY); + } bool hasSubType() const { return (isFluidContainer() || isSplash() || stackable || charges != 0); } @@ -378,8 +384,24 @@ class Items { NameMap nameToItems; + void addLadderId(uint16_t newId) { + ladders.push_back(newId); + } + void addDummyId(uint16_t newId) { + dummys.push_back(newId); + } + + const std::vector& getLadders() const { + return ladders; + } + const std::vector& getDummys() const { + return dummys; + } + private: std::vector items; + std::vector ladders; + std::vector dummys; InventoryVector inventory; }; diff --git a/src/items/items_definitions.hpp b/src/items/items_definitions.hpp index 9a4e1453929..4a2286ea2d4 100644 --- a/src/items/items_definitions.hpp +++ b/src/items/items_definitions.hpp @@ -180,6 +180,10 @@ enum ItemTypes_t { ITEM_TYPE_GOLD, ITEM_TYPE_UNASSIGNED, + // Other types + ITEM_TYPE_LADDER, + ITEM_TYPE_DUMMY, + ITEM_TYPE_LAST, }; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 9873b5c2b99..ba1229a7006 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -14,8 +14,6 @@ #include "game/functions/game_reload.hpp" #include "game/game.h" #include "items/item.h" -#include "enums/item_dummy_ids.hpp" -#include "enums/item_ladder_ids.hpp" #include "io/iobestiary.h" #include "io/io_bosstiary.hpp" #include "io/iologindata.h" @@ -656,16 +654,13 @@ int GameFunctions::luaGameGetInfluencedMonsters(lua_State* L) { int GameFunctions::luaGameGetLadderTable(lua_State* L) { // Game.getLadderTable() - lua_newtable(L); - int index = 1; - auto array = ItemLadderIdsArray::get(); - for (const auto &itemId : array) { - if (itemId == 0) { - continue; - } - - lua_pushnumber(L, static_cast(itemId)); - lua_rawseti(L, -2, index++); + const auto ladders = Item::items.getLadders(); + lua_createtable(L, static_cast(ladders.size()), 0); + int index = 0; + for (const auto ladderId : ladders) { + ++index; + lua_pushnumber(L, static_cast(ladderId)); + lua_rawseti(L, -2, index); } return 1; @@ -673,16 +668,13 @@ int GameFunctions::luaGameGetLadderTable(lua_State* L) { int GameFunctions::luaGameGetDummyTable(lua_State* L) { // Game.getDummyTable() - lua_newtable(L); - int index = 1; - auto array = ItemLadderIdsArray::get(); - for (const auto &itemId : array) { - if (itemId == 0) { - continue; - } - - lua_pushnumber(L, static_cast(itemId)); - lua_rawseti(L, -2, index++); + const auto dummys = Item::items.getDummys(); + lua_createtable(L, static_cast(dummys.size()), 0); + int index = 0; + for (const auto dummyId : dummys) { + ++index; + lua_pushnumber(L, static_cast(dummyId)); + lua_rawseti(L, -2, index); } return 1; From e7224825a7e77b54b5ec9c8c7f3ab21bf7ae4f1c Mon Sep 17 00:00:00 2001 From: GitHub Actions Date: Fri, 4 Aug 2023 18:32:56 +0000 Subject: [PATCH 04/13] Code format - (Clang-format) --- src/items/items.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/items.h b/src/items/items.h index 4a38913f94a..22ee5b585fc 100644 --- a/src/items/items.h +++ b/src/items/items.h @@ -391,10 +391,10 @@ class Items { dummys.push_back(newId); } - const std::vector& getLadders() const { + const std::vector &getLadders() const { return ladders; } - const std::vector& getDummys() const { + const std::vector &getDummys() const { return dummys; } From 14ce08e06158891e282863c223d266bbebf69691 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 4 Aug 2023 15:39:02 -0300 Subject: [PATCH 05/13] fix: add missing ladder to items.xml --- data/items/items.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/data/items/items.xml b/data/items/items.xml index 7657bd98447..658ad7bd70d 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -44812,7 +44812,9 @@ - + + + From d644015eaaf8b11ff5c27fb3507a1f750e784820 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Fri, 4 Aug 2023 16:33:58 -0300 Subject: [PATCH 06/13] fix: reload all warning and review comments (Luan) --- data-otservbr-global/scripts/actions/other/teleport.lua | 3 +-- src/game/game.cpp | 8 ++------ src/items/items.cpp | 2 ++ src/lua/functions/core/game/game_functions.cpp | 6 +++--- src/lua/functions/core/game/game_functions.hpp | 8 ++++---- 5 files changed, 12 insertions(+), 15 deletions(-) diff --git a/data-otservbr-global/scripts/actions/other/teleport.lua b/data-otservbr-global/scripts/actions/other/teleport.lua index 0a785d2c883..7e763f00594 100644 --- a/data-otservbr-global/scripts/actions/other/teleport.lua +++ b/data-otservbr-global/scripts/actions/other/teleport.lua @@ -1,4 +1,4 @@ -local ladderTable = Game.getLadderTable() +local ladderTable = Game.getLadderIds() local upFloorIds = ladderTable @@ -14,7 +14,6 @@ function teleport.onUse(player, item, fromPosition, target, toPosition, isHotkey return true end --- Gate teleport:id(435) teleport:id(unpack(ladderTable)) teleport:register() diff --git a/src/game/game.cpp b/src/game/game.cpp index 54ef34f6983..b7378efcb36 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -97,23 +97,19 @@ namespace InternalGame { if (HouseTile* houseTile = dynamic_cast(itemTile)) { House* house = houseTile->getHouse(); - // If not invited return false if (!house || !house->isInvited(player)) { return false; } - // Check is guest player auto isGuest = house->getHouseAccessLevel(player) == HOUSE_GUEST; - // Cannot use in browse field auto container = item->getParent() ? item->getParent()->getContainer() : nullptr; if (isGuest && container && container->getID() == ITEM_BROWSEFIELD) { return false; } auto realItemParent = item->getRealParent(); - // Check if item is not in player inventory or player backpack/storeinbox - auto canUseItem = realItemParent && (realItemParent == player || realItemParent->getContainer()); - if (isGuest && !canUseItem && !item->isLadder()) { + auto isItemInGuestInventory = realItemParent && (realItemParent == player || realItemParent->getContainer()); + if (isGuest && !isItemInGuestInventory && !item->isLadder()) { return false; } } diff --git a/src/items/items.cpp b/src/items/items.cpp index 1d9ff17f705..ce85815b4f1 100644 --- a/src/items/items.cpp +++ b/src/items/items.cpp @@ -19,6 +19,8 @@ Items::Items() = default; void Items::clear() { items.clear(); + ladders.clear(); + dummys.clear(); nameToItems.clear(); } diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index ba1229a7006..50cdd09502f 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -652,8 +652,8 @@ int GameFunctions::luaGameGetInfluencedMonsters(lua_State* L) { return 1; } -int GameFunctions::luaGameGetLadderTable(lua_State* L) { - // Game.getLadderTable() +int GameFunctions::luaGameGetLadderIds(lua_State* L) { + // Game.getDummyIds() const auto ladders = Item::items.getLadders(); lua_createtable(L, static_cast(ladders.size()), 0); int index = 0; @@ -666,7 +666,7 @@ int GameFunctions::luaGameGetLadderTable(lua_State* L) { return 1; } -int GameFunctions::luaGameGetDummyTable(lua_State* L) { +int GameFunctions::luaGameGetDummyIds(lua_State* L) { // Game.getDummyTable() const auto dummys = Item::items.getDummys(); lua_createtable(L, static_cast(dummys.size()), 0); diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index 3ae677799dd..9b2bef4084e 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -77,8 +77,8 @@ class GameFunctions final : LuaScriptInterface { registerMethod(L, "Game", "createHazardArea", GameFunctions::luaGameCreateHazardArea); - registerMethod(L, "Game", "getLadderTable", GameFunctions::luaGameGetLadderTable); - registerMethod(L, "Game", "getDummyTable", GameFunctions::luaGameGetDummyTable); + registerMethod(L, "Game", "getLadderIds", GameFunctions::luaGameGetLadderIds); + registerMethod(L, "Game", "getDummyIds", GameFunctions::luaGameGetDummyIds); } private: @@ -143,8 +143,8 @@ class GameFunctions final : LuaScriptInterface { static int luaGameCreateHazardArea(lua_State* L); - static int luaGameGetLadderTable(lua_State* L); - static int luaGameGetDummyTable(lua_State* L); + static int luaGameGetLadderIds(lua_State* L); + static int luaGameGetDummyIds(lua_State* L); }; #endif // SRC_LUA_FUNCTIONS_CORE_GAME_GAME_FUNCTIONS_HPP_ From 2121998a3d13f6fecf25e951366b1b16852932b5 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sat, 5 Aug 2023 11:44:46 -0300 Subject: [PATCH 07/13] fix: check nullpointer and rename some variables --- src/game/game.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index b7378efcb36..099a64f26eb 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -102,8 +102,9 @@ namespace InternalGame { } auto isGuest = house->getHouseAccessLevel(player) == HOUSE_GUEST; - auto container = item->getParent() ? item->getParent()->getContainer() : nullptr; - if (isGuest && container && container->getID() == ITEM_BROWSEFIELD) { + auto itemParentContainer = item->getParent() ? item->getParent()->getContainer() : nullptr; + auto itemParentContainerIsBrowseField = itemParentContainer && itemParentContainer->getID() == ITEM_BROWSEFIELD; + if (isGuest && itemParentContainerIsBrowseField) { return false; } @@ -118,14 +119,23 @@ namespace InternalGame { } bool playerCanUseItemWithOnHouseTile(Player* player, Item* item, const Position &toPos, int toStackPos, int toItemId) { + if (!player || !item) { + return false; + } + + auto itemTile = item->getTile(); + if (!itemTile) { + return false; + } + if (g_configManager().getBoolean(ONLY_INVITED_CAN_MOVE_HOUSE_ITEMS)) { - if (HouseTile* houseTile = dynamic_cast(item->getTile())) { + if (HouseTile* houseTile = dynamic_cast(itemTile)) { House* house = houseTile->getHouse(); Thing* targetThing = g_game().internalGetThing(player, toPos, toStackPos, toItemId, STACKPOS_FIND_THING); auto targetItem = targetThing ? targetThing->getItem() : nullptr; uint16_t targetId = targetItem ? targetItem->getID() : 0; auto invitedCheckUseWith = house && item->getRealParent() && item->getRealParent() != player && (!house->isInvited(player) || house->getHouseAccessLevel(player) == HOUSE_GUEST); - if (targetId != 0 && !targetItem->isDummy() && invitedCheckUseWith) { + if (targetId != 0 && targetItem && !targetItem->isDummy() && invitedCheckUseWith) { player->sendCancelMessage(RETURNVALUE_CANNOTUSETHISOBJECT); return false; } From d697ed62a800ffabebc0e7059f1f0d4b83fb896b Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sat, 5 Aug 2023 12:12:25 -0300 Subject: [PATCH 08/13] fix: rename variable --- src/game/game.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/game.cpp b/src/game/game.cpp index 099a64f26eb..672c9ea6246 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -103,8 +103,8 @@ namespace InternalGame { auto isGuest = house->getHouseAccessLevel(player) == HOUSE_GUEST; auto itemParentContainer = item->getParent() ? item->getParent()->getContainer() : nullptr; - auto itemParentContainerIsBrowseField = itemParentContainer && itemParentContainer->getID() == ITEM_BROWSEFIELD; - if (isGuest && itemParentContainerIsBrowseField) { + auto isItemParentContainerBrowseField = itemParentContainer && itemParentContainer->getID() == ITEM_BROWSEFIELD; + if (isGuest && isItemParentContainerBrowseField) { return false; } From d2bb1f95e3a0d15bb07e663138415d024ff824e4 Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Sun, 6 Aug 2023 19:03:46 -0300 Subject: [PATCH 09/13] Update src/lua/functions/core/game/game_functions.cpp --- src/lua/functions/core/game/game_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 50cdd09502f..461b602f3ac 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -667,7 +667,7 @@ int GameFunctions::luaGameGetLadderIds(lua_State* L) { } int GameFunctions::luaGameGetDummyIds(lua_State* L) { - // Game.getDummyTable() + // Game.getDummyIds() const auto dummys = Item::items.getDummys(); lua_createtable(L, static_cast(dummys.size()), 0); int index = 0; From 0e1fbaf6ef70fe58c6491cd9ea34b14faeffae3d Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 7 Aug 2023 10:51:47 -0300 Subject: [PATCH 10/13] fix: remove dummy from hardcoded lua and move to items.cpp --- data/items/items.xml | 32 +++++++++---- data/libs/exercise_training.lua | 6 ++- src/items/functions/item/item_parse.cpp | 27 +++++++++-- src/items/functions/item/item_parse.hpp | 3 +- src/items/items.h | 8 ++-- .../functions/core/game/game_functions.cpp | 46 +++++++++++++++---- 6 files changed, 94 insertions(+), 28 deletions(-) diff --git a/data/items/items.xml b/data/items/items.xml index 658ad7bd70d..21c1c2fce8f 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -40940,47 +40940,63 @@ - + + + - + + + - + + + - + + + - + + + - + + + - + + + - + + + diff --git a/data/libs/exercise_training.lua b/data/libs/exercise_training.lua index 80c7a60b8b9..38bc809ee0b 100644 --- a/data/libs/exercise_training.lua +++ b/data/libs/exercise_training.lua @@ -29,9 +29,11 @@ ExerciseWeaponsTable = { [35290] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true } } -FreeDummies = {28558, 28565} +local dummyIds = Game.getDummyIds() +FreeDummies = {unpack(dummyIds[false])} +HouseDummies = {unpack(dummyIds[true])} + MaxAllowedOnADummy = configManager.getNumber(configKeys.MAX_ALLOWED_ON_A_DUMMY) -HouseDummies = {28559, 28560, 28561, 28562, 28563, 28564} local magicLevelRate = configManager.getNumber(configKeys.RATE_MAGIC) local skillLevelRate = configManager.getNumber(configKeys.RATE_SKILL) diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index 0c81cebbee1..a45313f7152 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -14,7 +14,7 @@ void ItemParse::initParse(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType) { // Parse all item attributes - ItemParse::parseType(tmpStrValue, valueAttribute, itemType); + ItemParse::parseType(tmpStrValue, attributeNode, valueAttribute, itemType); ItemParse::parseDescription(tmpStrValue, valueAttribute, itemType); ItemParse::parseRuneSpellName(tmpStrValue, valueAttribute, itemType); ItemParse::parseWeight(tmpStrValue, valueAttribute, itemType); @@ -74,7 +74,27 @@ void ItemParse::initParse(const std::string &tmpStrValue, pugi::xml_node attribu ItemParse::parseReflectDamage(tmpStrValue, valueAttribute, itemType); } -void ItemParse::parseType(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType) { +void ItemParse::parseDummyPremium(pugi::xml_node attributeNode, ItemType &itemType) { + for (auto subAttributeNode : attributeNode.children()) { + pugi::xml_attribute subKeyAttribute = subAttributeNode.attribute("key"); + if (!subKeyAttribute) { + continue; + } + + pugi::xml_attribute subValueAttribute = subAttributeNode.attribute("value"); + if (!subValueAttribute) { + continue; + } + + auto stringValue = asLowerCaseString(subKeyAttribute.as_string()); + if (stringValue == "premium") { + bool isPremium = subValueAttribute.as_bool(); + Item::items.addDummyId(itemType.id, isPremium); + } + } +} + +void ItemParse::parseType(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType) { std::string stringValue = tmpStrValue; if (stringValue == "type") { stringValue = asLowerCaseString(valueAttribute.as_string()); @@ -88,9 +108,8 @@ void ItemParse::parseType(const std::string &tmpStrValue, pugi::xml_attribute va Item::items.addLadderId(itemType.id); } if (itemType.type == ITEM_TYPE_DUMMY) { - Item::items.addDummyId(itemType.id); + parseDummyPremium(attributeNode, itemType); } - } else { SPDLOG_WARN("[Items::parseItemNode] - Unknown type: {}", valueAttribute.as_string()); } diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index 60537769d57..cc6fa4fe84b 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -250,7 +250,8 @@ class ItemParse : public Items { static void initParse(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); protected: - static void parseType(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); + static void parseDummyPremium(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); + static void parseType(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseDescription(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseRuneSpellName(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseWeight(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); diff --git a/src/items/items.h b/src/items/items.h index 22ee5b585fc..02193f22ac5 100644 --- a/src/items/items.h +++ b/src/items/items.h @@ -387,21 +387,21 @@ class Items { void addLadderId(uint16_t newId) { ladders.push_back(newId); } - void addDummyId(uint16_t newId) { - dummys.push_back(newId); + void addDummyId(uint16_t newId, bool isPremium) { + dummys[newId] = isPremium; } const std::vector &getLadders() const { return ladders; } - const std::vector &getDummys() const { + const std::unordered_map &getDummys() const { return dummys; } private: std::vector items; std::vector ladders; - std::vector dummys; + std::unordered_map dummys; InventoryVector inventory; }; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index 461b602f3ac..e19787682ac 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -653,7 +653,7 @@ int GameFunctions::luaGameGetInfluencedMonsters(lua_State* L) { } int GameFunctions::luaGameGetLadderIds(lua_State* L) { - // Game.getDummyIds() + // Game.getLadderIds() const auto ladders = Item::items.getLadders(); lua_createtable(L, static_cast(ladders.size()), 0); int index = 0; @@ -667,16 +667,44 @@ int GameFunctions::luaGameGetLadderIds(lua_State* L) { } int GameFunctions::luaGameGetDummyIds(lua_State* L) { - // Game.getDummyIds() - const auto dummys = Item::items.getDummys(); - lua_createtable(L, static_cast(dummys.size()), 0); - int index = 0; - for (const auto dummyId : dummys) { - ++index; - lua_pushnumber(L, static_cast(dummyId)); - lua_rawseti(L, -2, index); + /** + * @brief Retrieve dummy IDs categorized by type. + * @details This function provides a table containing two sub-tables: one for free dummies and one for house (or premium) dummies. + + * @note usage on lua: + local dummyIds = Game.getDummyIds() + local freeDummies = {unpack(dummyIds[false])} -- Extract free dummy IDs + local houseDummies = {unpack(dummyIds[true])} -- Extract house (or premium) dummy IDs + */ + + const auto &dummys = Item::items.getDummys(); + // Table for the two categories of dummies + lua_createtable(L, 0, 2); + lua_pushboolean(L, true); + // Subtable for premium dummies + lua_newtable(L); + int premiumIndex = 0; + for (const auto &[dummyId, isPremium] : dummys) { + if (isPremium) { + premiumIndex++; + lua_pushnumber(L, static_cast(dummyId)); + lua_rawseti(L, -2, premiumIndex); + } } + lua_settable(L, -3); + lua_pushboolean(L, false); + // Subtable for free dummies + lua_newtable(L); + int freeIndex = 0; + for (const auto &[dummyId, isPremium] : dummys) { + if (!isPremium) { + freeIndex++; + lua_pushnumber(L, static_cast(dummyId)); + lua_rawseti(L, -2, freeIndex); + } + } + lua_settable(L, -3); return 1; } From 751c98fb76d9e08cc09118ac5aa29cc82d65c3fe Mon Sep 17 00:00:00 2001 From: Eduardo Dantas Date: Mon, 7 Aug 2023 11:00:43 -0300 Subject: [PATCH 11/13] fix: compilation --- src/items/functions/item/item_parse.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index cc6fa4fe84b..bc72eb024c8 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -249,8 +249,8 @@ class ItemParse : public Items { public: static void initParse(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); - protected: - static void parseDummyPremium(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); + private: + static void parseDummyPremium(pugi::xml_node attributeNode, ItemType &itemType); static void parseType(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseDescription(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseRuneSpellName(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); From a8ae7fe06a696c9edc5abc60e3ab52d3d9a0be52 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 7 Aug 2023 12:11:13 -0700 Subject: [PATCH 12/13] feat: configurable rate per dummy --- .../actions/other/exercise_training.lua | 8 +++- data/items/items.xml | 16 ++++---- data/libs/exercise_training.lua | 20 ++++------ src/items/functions/item/item_parse.cpp | 10 ++--- src/items/functions/item/item_parse.hpp | 2 +- src/items/items.h | 8 ++-- .../functions/core/game/game_functions.cpp | 39 ++++--------------- .../functions/core/game/game_functions.hpp | 4 +- 8 files changed, 41 insertions(+), 66 deletions(-) diff --git a/data-otservbr-global/scripts/actions/other/exercise_training.lua b/data-otservbr-global/scripts/actions/other/exercise_training.lua index 25cfcab3cae..addeffd164b 100644 --- a/data-otservbr-global/scripts/actions/other/exercise_training.lua +++ b/data-otservbr-global/scripts/actions/other/exercise_training.lua @@ -1,4 +1,8 @@ local exerciseTraining = Action() +local dummies = Game.getDummies() +local function isDummy(id) + return dummies[id] and dummies[id] > 0 +end function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, isHotkey) if not target then @@ -7,7 +11,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, local playerId = player:getId() local targetId = target:getId() - if target:isItem() and (table.contains(HouseDummies, targetId) or table.contains(FreeDummies, targetId)) then + if target:isItem() and isDummy(targetId) then if onExerciseTraining[playerId] then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "This exercise dummy can only be used after a 30 second cooldown.") LeaveTraining(playerId) @@ -29,7 +33,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, local targetPos = target:getPosition() local targetHouse = Tile(targetPos):getHouse() - if table.contains(HouseDummies, targetId) then + if targetHouse and isDummy(targetId) then if playerHouse ~= targetHouse then player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You must be inside the house to use this dummy.") return true diff --git a/data/items/items.xml b/data/items/items.xml index 4fd279cb7ba..0bd2a909bac 100644 --- a/data/items/items.xml +++ b/data/items/items.xml @@ -40941,7 +40941,7 @@ - + @@ -40949,7 +40949,7 @@ - + @@ -40957,7 +40957,7 @@ - + @@ -40965,7 +40965,7 @@ - + @@ -40973,7 +40973,7 @@ - + @@ -40981,7 +40981,7 @@ - + @@ -40989,13 +40989,13 @@ - + - + diff --git a/data/libs/exercise_training.lua b/data/libs/exercise_training.lua index 38bc809ee0b..084527c6839 100644 --- a/data/libs/exercise_training.lua +++ b/data/libs/exercise_training.lua @@ -29,14 +29,8 @@ ExerciseWeaponsTable = { [35290] = { skill = SKILL_MAGLEVEL, effect = CONST_ANI_FIRE, allowFarUse = true } } -local dummyIds = Game.getDummyIds() -FreeDummies = {unpack(dummyIds[false])} -HouseDummies = {unpack(dummyIds[true])} - -MaxAllowedOnADummy = configManager.getNumber(configKeys.MAX_ALLOWED_ON_A_DUMMY) - -local magicLevelRate = configManager.getNumber(configKeys.RATE_MAGIC) -local skillLevelRate = configManager.getNumber(configKeys.RATE_SKILL) +local dummies = Game.getDummies() +local maxAllowedOnADummy = configManager.getNumber(configKeys.MAX_ALLOWED_ON_A_DUMMY) function LeaveTraining(playerId) if onExerciseTraining[playerId] then @@ -96,14 +90,14 @@ function ExerciseEvent(playerId, tilePosition, weaponId, dummyId) end local isMagic = ExerciseWeaponsTable[weaponId].skill == SKILL_MAGLEVEL - local bonusDummy = table.contains(HouseDummies, dummyId) or nil - - if bonusDummy then bonusDummy = 1.1 else bonusDummy = 1 end + if not dummies[dummyId] then return false end + local rate = dummies[dummyId] / 100 + Spdlog.info(rate) if isMagic then - player:addManaSpent(500 * bonusDummy) + player:addManaSpent(500 * rate) else - player:addSkillTries(ExerciseWeaponsTable[weaponId].skill, 7 * bonusDummy) + player:addSkillTries(ExerciseWeaponsTable[weaponId].skill, 7 * rate) end weapon:setAttribute(ITEM_ATTRIBUTE_CHARGES, (weaponCharges - 1)) diff --git a/src/items/functions/item/item_parse.cpp b/src/items/functions/item/item_parse.cpp index a45313f7152..e099877e652 100644 --- a/src/items/functions/item/item_parse.cpp +++ b/src/items/functions/item/item_parse.cpp @@ -74,7 +74,7 @@ void ItemParse::initParse(const std::string &tmpStrValue, pugi::xml_node attribu ItemParse::parseReflectDamage(tmpStrValue, valueAttribute, itemType); } -void ItemParse::parseDummyPremium(pugi::xml_node attributeNode, ItemType &itemType) { +void ItemParse::parseDummyRate(pugi::xml_node attributeNode, ItemType &itemType) { for (auto subAttributeNode : attributeNode.children()) { pugi::xml_attribute subKeyAttribute = subAttributeNode.attribute("key"); if (!subKeyAttribute) { @@ -87,9 +87,9 @@ void ItemParse::parseDummyPremium(pugi::xml_node attributeNode, ItemType &itemTy } auto stringValue = asLowerCaseString(subKeyAttribute.as_string()); - if (stringValue == "premium") { - bool isPremium = subValueAttribute.as_bool(); - Item::items.addDummyId(itemType.id, isPremium); + if (stringValue == "rate") { + uint16_t rate = subValueAttribute.as_uint(); + Item::items.addDummyId(itemType.id, rate); } } } @@ -108,7 +108,7 @@ void ItemParse::parseType(const std::string &tmpStrValue, pugi::xml_node attribu Item::items.addLadderId(itemType.id); } if (itemType.type == ITEM_TYPE_DUMMY) { - parseDummyPremium(attributeNode, itemType); + parseDummyRate(attributeNode, itemType); } } else { SPDLOG_WARN("[Items::parseItemNode] - Unknown type: {}", valueAttribute.as_string()); diff --git a/src/items/functions/item/item_parse.hpp b/src/items/functions/item/item_parse.hpp index bc72eb024c8..29885a2a627 100644 --- a/src/items/functions/item/item_parse.hpp +++ b/src/items/functions/item/item_parse.hpp @@ -250,7 +250,7 @@ class ItemParse : public Items { static void initParse(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); private: - static void parseDummyPremium(pugi::xml_node attributeNode, ItemType &itemType); + static void parseDummyRate(pugi::xml_node attributeNode, ItemType &itemType); static void parseType(const std::string &tmpStrValue, pugi::xml_node attributeNode, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseDescription(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); static void parseRuneSpellName(const std::string &tmpStrValue, pugi::xml_attribute valueAttribute, ItemType &itemType); diff --git a/src/items/items.h b/src/items/items.h index 02193f22ac5..b7260c0fb82 100644 --- a/src/items/items.h +++ b/src/items/items.h @@ -387,21 +387,21 @@ class Items { void addLadderId(uint16_t newId) { ladders.push_back(newId); } - void addDummyId(uint16_t newId, bool isPremium) { - dummys[newId] = isPremium; + void addDummyId(uint16_t newId, uint16_t rate) { + dummys[newId] = rate; } const std::vector &getLadders() const { return ladders; } - const std::unordered_map &getDummys() const { + const std::unordered_map &getDummys() const { return dummys; } private: std::vector items; std::vector ladders; - std::unordered_map dummys; + std::unordered_map dummys; InventoryVector inventory; }; diff --git a/src/lua/functions/core/game/game_functions.cpp b/src/lua/functions/core/game/game_functions.cpp index e19787682ac..de9b0a1ee1a 100644 --- a/src/lua/functions/core/game/game_functions.cpp +++ b/src/lua/functions/core/game/game_functions.cpp @@ -666,45 +666,22 @@ int GameFunctions::luaGameGetLadderIds(lua_State* L) { return 1; } -int GameFunctions::luaGameGetDummyIds(lua_State* L) { +int GameFunctions::luaGameGetDummies(lua_State* L) { /** * @brief Retrieve dummy IDs categorized by type. * @details This function provides a table containing two sub-tables: one for free dummies and one for house (or premium) dummies. * @note usage on lua: - local dummyIds = Game.getDummyIds() - local freeDummies = {unpack(dummyIds[false])} -- Extract free dummy IDs - local houseDummies = {unpack(dummyIds[true])} -- Extract house (or premium) dummy IDs + local dummies = Game.getDummies() + local rate = dummies[1] -- Retrieve dummy rate */ - const auto &dummys = Item::items.getDummys(); - // Table for the two categories of dummies - lua_createtable(L, 0, 2); - lua_pushboolean(L, true); - // Subtable for premium dummies - lua_newtable(L); - int premiumIndex = 0; - for (const auto &[dummyId, isPremium] : dummys) { - if (isPremium) { - premiumIndex++; - lua_pushnumber(L, static_cast(dummyId)); - lua_rawseti(L, -2, premiumIndex); - } - } - lua_settable(L, -3); - - lua_pushboolean(L, false); - // Subtable for free dummies - lua_newtable(L); - int freeIndex = 0; - for (const auto &[dummyId, isPremium] : dummys) { - if (!isPremium) { - freeIndex++; - lua_pushnumber(L, static_cast(dummyId)); - lua_rawseti(L, -2, freeIndex); - } + const auto &dummies = Item::items.getDummys(); + lua_createtable(L, dummies.size(), 0); + for (const auto &[dummyId, rate] : dummies) { + lua_pushnumber(L, static_cast(rate)); + lua_rawseti(L, -2, dummyId); } - lua_settable(L, -3); return 1; } diff --git a/src/lua/functions/core/game/game_functions.hpp b/src/lua/functions/core/game/game_functions.hpp index 9b2bef4084e..e59a25c6950 100644 --- a/src/lua/functions/core/game/game_functions.hpp +++ b/src/lua/functions/core/game/game_functions.hpp @@ -78,7 +78,7 @@ class GameFunctions final : LuaScriptInterface { registerMethod(L, "Game", "createHazardArea", GameFunctions::luaGameCreateHazardArea); registerMethod(L, "Game", "getLadderIds", GameFunctions::luaGameGetLadderIds); - registerMethod(L, "Game", "getDummyIds", GameFunctions::luaGameGetDummyIds); + registerMethod(L, "Game", "getDummies", GameFunctions::luaGameGetDummies); } private: @@ -144,7 +144,7 @@ class GameFunctions final : LuaScriptInterface { static int luaGameCreateHazardArea(lua_State* L); static int luaGameGetLadderIds(lua_State* L); - static int luaGameGetDummyIds(lua_State* L); + static int luaGameGetDummies(lua_State* L); }; #endif // SRC_LUA_FUNCTIONS_CORE_GAME_GAME_FUNCTIONS_HPP_ From d5c4ceb33c3ee6d41544346f9137fcde3639826c Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 7 Aug 2023 12:11:56 -0700 Subject: [PATCH 13/13] fix: max allowed --- .../scripts/actions/other/exercise_training.lua | 4 +++- data/libs/exercise_training.lua | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/data-otservbr-global/scripts/actions/other/exercise_training.lua b/data-otservbr-global/scripts/actions/other/exercise_training.lua index addeffd164b..927a15c6ed1 100644 --- a/data-otservbr-global/scripts/actions/other/exercise_training.lua +++ b/data-otservbr-global/scripts/actions/other/exercise_training.lua @@ -1,4 +1,6 @@ local exerciseTraining = Action() + +local maxAllowedOnADummy = configManager.getNumber(configKeys.MAX_ALLOWED_ON_A_DUMMY) local dummies = Game.getDummies() local function isDummy(id) return dummies[id] and dummies[id] > 0 @@ -44,7 +46,7 @@ function exerciseTraining.onUse(player, item, fromPosition, target, toPosition, playersOnDummy = playersOnDummy + 1 end - if playersOnDummy == MaxAllowedOnADummy then + if playersOnDummy == maxAllowedOnADummy then player:sendTextMessage(MESSAGE_FAILURE, "That exercise dummy is busy.") return true end diff --git a/data/libs/exercise_training.lua b/data/libs/exercise_training.lua index 084527c6839..a0960028d4d 100644 --- a/data/libs/exercise_training.lua +++ b/data/libs/exercise_training.lua @@ -30,7 +30,6 @@ ExerciseWeaponsTable = { } local dummies = Game.getDummies() -local maxAllowedOnADummy = configManager.getNumber(configKeys.MAX_ALLOWED_ON_A_DUMMY) function LeaveTraining(playerId) if onExerciseTraining[playerId] then @@ -92,7 +91,6 @@ function ExerciseEvent(playerId, tilePosition, weaponId, dummyId) local isMagic = ExerciseWeaponsTable[weaponId].skill == SKILL_MAGLEVEL if not dummies[dummyId] then return false end local rate = dummies[dummyId] / 100 - Spdlog.info(rate) if isMagic then player:addManaSpent(500 * rate)