From ef08366efcc24f99184a64b0af535087e138f48a Mon Sep 17 00:00:00 2001 From: Kelsi Date: Thu, 12 Mar 2026 10:06:11 -0700 Subject: [PATCH] feat: add /use and /equip slash commands for inventory items by name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - /use — searches backpack then bags (case-insensitive), calls useItemBySlot() / useItemInBag() for the first match - /equip — same search, calls autoEquipItemBySlot() / autoEquipItemInBag() for the first match - Both commands print an error if the item is not found - Added both to tab-autocomplete list and /help output --- src/ui/game_screen.cpp | 103 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index c650ecbe..35907642 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -1944,7 +1944,7 @@ void GameScreen::renderChatWindow(game::GameHandler& gameHandler) { static const std::vector kCmds = { "/afk", "/away", "/cast", "/chathelp", "/clear", "/dance", "/do", "/dnd", "/e", "/emote", - "/follow", "/g", "/guild", "/guildinfo", + "/equip", "/follow", "/g", "/guild", "/guildinfo", "/gmticket", "/grouploot", "/i", "/instance", "/invite", "/j", "/join", "/kick", "/l", "/leave", "/local", "/me", @@ -1952,7 +1952,7 @@ void GameScreen::renderChatWindow(game::GameHandler& gameHandler) { "/raidwarning", "/random", "/reply", "/roll", "/s", "/say", "/setloot", "/shout", "/stopattack", "/stopfollow", "/t", "/time", - "/trade", "/uninvite", "/w", "/whisper", + "/trade", "/uninvite", "/use", "/w", "/whisper", "/who", "/wts", "/wtb", "/y", "/yell", "/zone" }; @@ -3900,6 +3900,7 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) { " /gleader /groster /ginfo /gcreate /gdisband", "Combat: /startattack /stopattack /stopcasting /cast /duel /pvp", " /forfeit /follow /stopfollow /assist", + "Items: /use /equip ", "Target: /target /cleartarget /focus /clearfocus", "Movement: /sit /stand /kneel /dismount", "Misc: /played /time /zone /afk [msg] /dnd [msg] /inspect", @@ -4595,6 +4596,104 @@ void GameScreen::sendChatMessage(game::GameHandler& gameHandler) { return; } + // /use — use an item from backpack/bags by name + if (cmdLower == "use" && spacePos != std::string::npos) { + std::string useArg = command.substr(spacePos + 1); + while (!useArg.empty() && useArg.front() == ' ') useArg.erase(useArg.begin()); + while (!useArg.empty() && useArg.back() == ' ') useArg.pop_back(); + std::string useArgLower = useArg; + for (char& c : useArgLower) c = static_cast(std::tolower(static_cast(c))); + + bool found = false; + const auto& inv = gameHandler.getInventory(); + // Search backpack + for (int s = 0; s < inv.getBackpackSize() && !found; ++s) { + const auto& slot = inv.getBackpackSlot(s); + if (slot.empty()) continue; + const auto* info = gameHandler.getItemInfo(slot.item.itemId); + if (!info) continue; + std::string nameLow = info->name; + for (char& c : nameLow) c = static_cast(std::tolower(static_cast(c))); + if (nameLow == useArgLower) { + gameHandler.useItemBySlot(s); + found = true; + } + } + // Search bags + for (int b = 0; b < game::Inventory::NUM_BAG_SLOTS && !found; ++b) { + for (int s = 0; s < inv.getBagSize(b) && !found; ++s) { + const auto& slot = inv.getBagSlot(b, s); + if (slot.empty()) continue; + const auto* info = gameHandler.getItemInfo(slot.item.itemId); + if (!info) continue; + std::string nameLow = info->name; + for (char& c : nameLow) c = static_cast(std::tolower(static_cast(c))); + if (nameLow == useArgLower) { + gameHandler.useItemInBag(b, s); + found = true; + } + } + } + if (!found) { + game::MessageChatData sysMsg; + sysMsg.type = game::ChatType::SYSTEM; + sysMsg.language = game::ChatLanguage::UNIVERSAL; + sysMsg.message = "Item not found: '" + useArg + "'."; + gameHandler.addLocalChatMessage(sysMsg); + } + chatInputBuffer[0] = '\0'; + return; + } + + // /equip — auto-equip an item from backpack/bags by name + if (cmdLower == "equip" && spacePos != std::string::npos) { + std::string equipArg = command.substr(spacePos + 1); + while (!equipArg.empty() && equipArg.front() == ' ') equipArg.erase(equipArg.begin()); + while (!equipArg.empty() && equipArg.back() == ' ') equipArg.pop_back(); + std::string equipArgLower = equipArg; + for (char& c : equipArgLower) c = static_cast(std::tolower(static_cast(c))); + + bool found = false; + const auto& inv = gameHandler.getInventory(); + // Search backpack + for (int s = 0; s < inv.getBackpackSize() && !found; ++s) { + const auto& slot = inv.getBackpackSlot(s); + if (slot.empty()) continue; + const auto* info = gameHandler.getItemInfo(slot.item.itemId); + if (!info) continue; + std::string nameLow = info->name; + for (char& c : nameLow) c = static_cast(std::tolower(static_cast(c))); + if (nameLow == equipArgLower) { + gameHandler.autoEquipItemBySlot(s); + found = true; + } + } + // Search bags + for (int b = 0; b < game::Inventory::NUM_BAG_SLOTS && !found; ++b) { + for (int s = 0; s < inv.getBagSize(b) && !found; ++s) { + const auto& slot = inv.getBagSlot(b, s); + if (slot.empty()) continue; + const auto* info = gameHandler.getItemInfo(slot.item.itemId); + if (!info) continue; + std::string nameLow = info->name; + for (char& c : nameLow) c = static_cast(std::tolower(static_cast(c))); + if (nameLow == equipArgLower) { + gameHandler.autoEquipItemInBag(b, s); + found = true; + } + } + } + if (!found) { + game::MessageChatData sysMsg; + sysMsg.type = game::ChatType::SYSTEM; + sysMsg.language = game::ChatLanguage::UNIVERSAL; + sysMsg.message = "Item not found: '" + equipArg + "'."; + gameHandler.addLocalChatMessage(sysMsg); + } + chatInputBuffer[0] = '\0'; + return; + } + // Targeting commands if (cmdLower == "cleartarget") { gameHandler.clearTarget();