diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 81257c6f..8b7a445a 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1151,6 +1151,13 @@ public: uint8_t itemQuality = 0; uint32_t rollCountdownMs = 60000; // Duration of roll window in ms std::chrono::steady_clock::time_point rollStartedAt{}; + + struct PlayerRollResult { + std::string playerName; + uint8_t rollNum = 0; + uint8_t rollType = 0; // 0=need,1=greed,2=disenchant,96=pass + }; + std::vector playerRolls; // live roll results from group members }; bool hasPendingLootRoll() const { return pendingLootRollActive_; } const LootRollEntry& getPendingLootRoll() const { return pendingLootRoll_; } diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 773f9a91..054d4865 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -19993,6 +19993,7 @@ void GameHandler::handleLootRoll(network::Packet& packet) { pendingLootRoll_.objectGuid = objectGuid; pendingLootRoll_.slot = slot; pendingLootRoll_.itemId = itemId; + pendingLootRoll_.playerRolls.clear(); // Ensure item info is in cache; query if not queryItemInfo(itemId, 0); // Look up item name from cache @@ -20017,6 +20018,28 @@ void GameHandler::handleLootRoll(network::Packet& packet) { } if (rollerName.empty()) rollerName = "Someone"; + // Track in the live roll list while our popup is open for the same item + if (pendingLootRollActive_ && + pendingLootRoll_.objectGuid == objectGuid && + pendingLootRoll_.slot == slot) { + bool found = false; + for (auto& r : pendingLootRoll_.playerRolls) { + if (r.playerName == rollerName) { + r.rollNum = rollNum; + r.rollType = rollType; + found = true; + break; + } + } + if (!found) { + LootRollEntry::PlayerRollResult prr; + prr.playerName = rollerName; + prr.rollNum = rollNum; + prr.rollType = rollType; + pendingLootRoll_.playerRolls.push_back(std::move(prr)); + } + } + auto* info = getItemInfo(itemId); std::string iName = info ? info->name : std::to_string(itemId); diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 33f3e02a..493de4d3 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -8706,6 +8706,48 @@ void GameScreen::renderLootRollPopup(game::GameHandler& gameHandler) { if (ImGui::Button("Pass", ImVec2(70, 30))) { gameHandler.sendLootRoll(roll.objectGuid, roll.slot, 96); } + + // Live roll results from group members + if (!roll.playerRolls.empty()) { + ImGui::Separator(); + ImGui::TextDisabled("Rolls so far:"); + // Roll-type label + color + static const char* kRollLabels[] = {"Need", "Greed", "Disenchant", "Pass"}; + static const ImVec4 kRollColors[] = { + ImVec4(0.2f, 0.9f, 0.2f, 1.0f), // Need — green + ImVec4(0.3f, 0.6f, 1.0f, 1.0f), // Greed — blue + ImVec4(0.7f, 0.3f, 0.9f, 1.0f), // Disenchant — purple + ImVec4(0.5f, 0.5f, 0.5f, 1.0f), // Pass — gray + }; + auto rollTypeIndex = [](uint8_t t) -> int { + if (t == 0) return 0; + if (t == 1) return 1; + if (t == 2) return 2; + return 3; // pass (96 or unknown) + }; + + if (ImGui::BeginTable("##lootrolls", 3, + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("Player", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 72.0f); + ImGui::TableSetupColumn("Roll", ImGuiTableColumnFlags_WidthFixed, 32.0f); + for (const auto& r : roll.playerRolls) { + int ri = rollTypeIndex(r.rollType); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(0); + ImGui::TextUnformatted(r.playerName.c_str()); + ImGui::TableSetColumnIndex(1); + ImGui::TextColored(kRollColors[ri], "%s", kRollLabels[ri]); + ImGui::TableSetColumnIndex(2); + if (r.rollType != 96) { + ImGui::TextColored(kRollColors[ri], "%d", static_cast(r.rollNum)); + } else { + ImGui::TextDisabled("—"); + } + } + ImGui::EndTable(); + } + } } ImGui::End(); }