From a7d1b3961e39a8277eaba7ca145b6be61dfdb6aa Mon Sep 17 00:00:00 2001 From: Kizuno18 <110933270+Kizuno18@users.noreply.github.com> Date: Sat, 18 Jul 2026 16:43:24 -0300 Subject: [PATCH] fix: useInventoryItemWith source stackpos on pre-780 protocols (7.6 usewith) (#1755) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug Fixes: - Improved compatibility when using inventory items on older client versions, reducing silent failures. - The game now correctly identifies the matching inventory item and uses accurate slot/stack information for the action. - If the item isn’t found in the player’s inventory, the game will check nearby containers and proceed when available. --- src/client/game.cpp | 25 +++++++++++++++++++++++++ src/client/game.h | 1 + 2 files changed, 26 insertions(+) diff --git a/src/client/game.cpp b/src/client/game.cpp index 517135f13..d3bd1efab 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -885,6 +885,18 @@ void Game::useInventoryItemWith(const uint16_t itemId, const ThingPtr& toThing) if (!canPerformGameAction() || !toThing) return; + // pre-780 protocols resolve the source item by its real inventory slot and + // stackpos, so the synthetic Position(0xFFFF, 0, 0) below (source stackpos 0) + // addresses the wrong slot and the use silently fails (e.g. rope on 7.6). + // resolve the real item and go through useWith, the same gate the hotkey and + // keybind code already apply. see #1541 + if (getClientVersion() < 780) { + if (const auto& item = findPlayerItem(itemId, -1)) { + useWith(item, toThing); + return; + } + } + const auto& pos = Position(0xFFFF, 0, 0); // means that is a item in inventory if (toThing->isCreature()) m_protocolGame->sendUseOnCreature(pos, itemId, 0, toThing->getId()); @@ -894,6 +906,19 @@ void Game::useInventoryItemWith(const uint16_t itemId, const ThingPtr& toThing) g_lua.callGlobalField("g_game", "onUseWith", pos, itemId, toThing, 0); } +ItemPtr Game::findPlayerItem(const uint32_t itemId, const int subType) +{ + if (m_localPlayer) { + for (int slot = Otc::InventorySlotHead; slot < Otc::LastInventorySlot; ++slot) { + const auto& item = m_localPlayer->getInventoryItem(static_cast(slot)); + if (item && item->getId() == itemId && (subType == -1 || item->getSubType() == subType)) + return item; + } + } + + return findItemInContainers(itemId, subType, 0); +} + ItemPtr Game::findItemInContainers(const uint32_t itemId, const int subType, const uint8_t tier) { for (const auto& it : m_containers) { diff --git a/src/client/game.h b/src/client/game.h index f8fb1fa5d..acf6491f6 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -186,6 +186,7 @@ public: void useInventoryItem(uint16_t itemId); void useInventoryItemWith(uint16_t itemId, const ThingPtr& toThing); ItemPtr findItemInContainers(uint32_t itemId, int subType, uint8_t tier); + ItemPtr findPlayerItem(uint32_t itemId, int subType); // container related int open(const ItemPtr& item, const ContainerPtr& previousContainer);