From 0a26eef1540e37960bf99b84d10145b689a3c89b Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 6 Feb 2026 19:24:44 -0800 Subject: [PATCH] Send CMSG_LOOT_MONEY for online gold looting and replace action bar right-click removal with drag-to-ground --- include/game/world_packets.hpp | 6 ++++ include/ui/game_screen.hpp | 4 +++ src/game/game_handler.cpp | 12 ++++---- src/game/world_packets.cpp | 5 ++++ src/ui/game_screen.cpp | 52 ++++++++++++++++++++++++++++++---- 5 files changed, 67 insertions(+), 12 deletions(-) diff --git a/include/game/world_packets.hpp b/include/game/world_packets.hpp index 1f18ade2..a55bfb5f 100644 --- a/include/game/world_packets.hpp +++ b/include/game/world_packets.hpp @@ -1137,6 +1137,12 @@ public: static network::Packet build(uint8_t srcBag, uint8_t srcSlot); }; +/** CMSG_LOOT_MONEY packet builder (empty body) */ +class LootMoneyPacket { +public: + static network::Packet build(); +}; + /** CMSG_LOOT_RELEASE packet builder */ class LootReleasePacket { public: diff --git a/include/ui/game_screen.hpp b/include/ui/game_screen.hpp index b873b865..e4394237 100644 --- a/include/ui/game_screen.hpp +++ b/include/ui/game_screen.hpp @@ -171,6 +171,10 @@ private: std::unordered_map spellIconIds_; bool spellIconDbLoaded_ = false; GLuint getSpellIcon(uint32_t spellId, pipeline::AssetManager* am); + + // Action bar drag state (-1 = not dragging) + int actionBarDragSlot_ = -1; + GLuint actionBarDragIcon_ = 0; }; } // namespace ui diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index b7d60b91..84577564 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -4164,13 +4164,13 @@ void GameHandler::handleLootResponse(network::Packet& packet) { if (currentLoot.gold > 0) { if (singlePlayerMode_) { addMoneyCopper(currentLoot.gold); + currentLoot.gold = 0; + } else if (state == WorldState::IN_WORLD && socket) { + // Auto-loot gold by sending CMSG_LOOT_MONEY (server handles the rest) + auto pkt = LootMoneyPacket::build(); + socket->send(pkt); + currentLoot.gold = 0; } - std::string msg = "You loot "; - msg += std::to_string(currentLoot.getGold()) + "g "; - msg += std::to_string(currentLoot.getSilver()) + "s "; - msg += std::to_string(currentLoot.getCopper()) + "c."; - addSystemChatMessage(msg); - currentLoot.gold = 0; // Clear gold from loot window after collecting } } diff --git a/src/game/world_packets.cpp b/src/game/world_packets.cpp index 13927601..6118ebc6 100644 --- a/src/game/world_packets.cpp +++ b/src/game/world_packets.cpp @@ -1928,6 +1928,11 @@ network::Packet AutoEquipItemPacket::build(uint8_t srcBag, uint8_t srcSlot) { return packet; } +network::Packet LootMoneyPacket::build() { + network::Packet packet(static_cast(Opcode::CMSG_LOOT_MONEY)); + return packet; +} + network::Packet LootReleasePacket::build(uint64_t lootGuid) { network::Packet packet(static_cast(Opcode::CMSG_LOOT_RELEASE)); packet.writeUInt64(lootGuid); diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index e5a3a137..5fe17137 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -1505,6 +1505,22 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { const auto& held = inventoryScreen.getHeldItem(); gameHandler.setActionBarSlot(i, game::ActionBarSlot::ITEM, held.itemId); inventoryScreen.returnHeldItem(gameHandler.getInventory()); + } else if (clicked && actionBarDragSlot_ >= 0) { + // Dropping a dragged action bar slot onto another slot - swap or place + if (i != actionBarDragSlot_) { + // Swap the two slots + const auto& dragSrc = bar[actionBarDragSlot_]; + auto srcType = dragSrc.type; + auto srcId = dragSrc.id; + gameHandler.setActionBarSlot(actionBarDragSlot_, slot.type, slot.id); + gameHandler.setActionBarSlot(i, srcType, srcId); + } + actionBarDragSlot_ = -1; + actionBarDragIcon_ = 0; + } else if (clicked && !slot.isEmpty()) { + // Pick up this action bar slot for dragging + actionBarDragSlot_ = i; + actionBarDragIcon_ = iconTex; } else if (clicked) { if (slot.type == game::ActionBarSlot::SPELL && slot.isReady()) { uint64_t target = gameHandler.hasTarget() ? gameHandler.getTargetGuid() : 0; @@ -1514,11 +1530,6 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { } } - // Right-click to clear slot - if (ImGui::IsItemClicked(ImGuiMouseButton_Right) && !slot.isEmpty()) { - gameHandler.setActionBarSlot(i, game::ActionBarSlot::EMPTY, 0); - } - // Tooltip if (ImGui::IsItemHovered() && slot.type == game::ActionBarSlot::SPELL && slot.id != 0) { std::string fullName = getSpellName(slot.id); @@ -1533,7 +1544,6 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { } else { ImGui::Text("Item #%u", slot.id); } - ImGui::TextDisabled("(Right-click to remove)"); ImGui::EndTooltip(); } @@ -1567,6 +1577,36 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) { ImGui::PopStyleColor(); ImGui::PopStyleVar(); + + // Handle action bar drag: render icon at cursor and detect drop outside + if (actionBarDragSlot_ >= 0) { + ImVec2 mousePos = ImGui::GetMousePos(); + + // Draw dragged icon at cursor + if (actionBarDragIcon_) { + ImGui::GetForegroundDrawList()->AddImage( + (ImTextureID)(uintptr_t)actionBarDragIcon_, + ImVec2(mousePos.x - 20, mousePos.y - 20), + ImVec2(mousePos.x + 20, mousePos.y + 20)); + } else { + ImGui::GetForegroundDrawList()->AddRectFilled( + ImVec2(mousePos.x - 20, mousePos.y - 20), + ImVec2(mousePos.x + 20, mousePos.y + 20), + IM_COL32(80, 80, 120, 180)); + } + + // On mouse release, check if outside the action bar area + if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { + bool insideBar = (mousePos.x >= barX && mousePos.x <= barX + barW && + mousePos.y >= barY && mousePos.y <= barY + barH); + if (!insideBar) { + // Dropped outside - clear the slot + gameHandler.setActionBarSlot(actionBarDragSlot_, game::ActionBarSlot::EMPTY, 0); + } + actionBarDragSlot_ = -1; + actionBarDragIcon_ = 0; + } + } } // ============================================================