mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
feat: implement master loot UI for SMSG_LOOT_MASTER_LIST
Parse master loot candidate GUIDs from SMSG_LOOT_MASTER_LIST and display a "Give to..." popup menu on item click when master loot is active. Sends CMSG_LOOT_MASTER_GIVE with loot GUID, slot, and target GUID. Clears candidates when loot window is closed.
This commit is contained in:
parent
6957ba97ea
commit
2f479c6230
3 changed files with 66 additions and 4 deletions
|
|
@ -1230,6 +1230,11 @@ public:
|
||||||
void setAutoLoot(bool enabled) { autoLoot_ = enabled; }
|
void setAutoLoot(bool enabled) { autoLoot_ = enabled; }
|
||||||
bool isAutoLoot() const { return autoLoot_; }
|
bool isAutoLoot() const { return autoLoot_; }
|
||||||
|
|
||||||
|
// Master loot candidates (from SMSG_LOOT_MASTER_LIST)
|
||||||
|
const std::vector<uint64_t>& getMasterLootCandidates() const { return masterLootCandidates_; }
|
||||||
|
bool hasMasterLootCandidates() const { return !masterLootCandidates_.empty(); }
|
||||||
|
void lootMasterGive(uint8_t lootSlot, uint64_t targetGuid);
|
||||||
|
|
||||||
// Group loot roll
|
// Group loot roll
|
||||||
struct LootRollEntry {
|
struct LootRollEntry {
|
||||||
uint64_t objectGuid = 0;
|
uint64_t objectGuid = 0;
|
||||||
|
|
@ -2493,6 +2498,7 @@ private:
|
||||||
bool lootWindowOpen = false;
|
bool lootWindowOpen = false;
|
||||||
bool autoLoot_ = false;
|
bool autoLoot_ = false;
|
||||||
LootResponseData currentLoot;
|
LootResponseData currentLoot;
|
||||||
|
std::vector<uint64_t> masterLootCandidates_; // from SMSG_LOOT_MASTER_LIST
|
||||||
|
|
||||||
// Group loot roll state
|
// Group loot roll state
|
||||||
bool pendingLootRollActive_ = false;
|
bool pendingLootRollActive_ = false;
|
||||||
|
|
|
||||||
|
|
@ -3342,10 +3342,19 @@ void GameHandler::handlePacket(network::Packet& packet) {
|
||||||
case Opcode::SMSG_LOOT_ROLL_WON:
|
case Opcode::SMSG_LOOT_ROLL_WON:
|
||||||
handleLootRollWon(packet);
|
handleLootRollWon(packet);
|
||||||
break;
|
break;
|
||||||
case Opcode::SMSG_LOOT_MASTER_LIST:
|
case Opcode::SMSG_LOOT_MASTER_LIST: {
|
||||||
// Master looter list — no UI yet; consume to avoid unhandled warning.
|
// uint8 count + count * uint64 guid — eligible recipients for master looter
|
||||||
packet.setReadPos(packet.getSize());
|
masterLootCandidates_.clear();
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 1) break;
|
||||||
|
uint8_t mlCount = packet.readUInt8();
|
||||||
|
masterLootCandidates_.reserve(mlCount);
|
||||||
|
for (uint8_t i = 0; i < mlCount; ++i) {
|
||||||
|
if (packet.getSize() - packet.getReadPos() < 8) break;
|
||||||
|
masterLootCandidates_.push_back(packet.readUInt64());
|
||||||
|
}
|
||||||
|
LOG_INFO("SMSG_LOOT_MASTER_LIST: ", (int)masterLootCandidates_.size(), " candidates");
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Opcode::SMSG_GOSSIP_MESSAGE:
|
case Opcode::SMSG_GOSSIP_MESSAGE:
|
||||||
handleGossipMessage(packet);
|
handleGossipMessage(packet);
|
||||||
break;
|
break;
|
||||||
|
|
@ -15585,6 +15594,7 @@ void GameHandler::lootItem(uint8_t slotIndex) {
|
||||||
void GameHandler::closeLoot() {
|
void GameHandler::closeLoot() {
|
||||||
if (!lootWindowOpen) return;
|
if (!lootWindowOpen) return;
|
||||||
lootWindowOpen = false;
|
lootWindowOpen = false;
|
||||||
|
masterLootCandidates_.clear();
|
||||||
if (currentLoot.lootGuid != 0 && targetGuid == currentLoot.lootGuid) {
|
if (currentLoot.lootGuid != 0 && targetGuid == currentLoot.lootGuid) {
|
||||||
clearTarget();
|
clearTarget();
|
||||||
}
|
}
|
||||||
|
|
@ -15595,6 +15605,16 @@ void GameHandler::closeLoot() {
|
||||||
currentLoot = LootResponseData{};
|
currentLoot = LootResponseData{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameHandler::lootMasterGive(uint8_t lootSlot, uint64_t targetGuid) {
|
||||||
|
if (state != WorldState::IN_WORLD || !socket) return;
|
||||||
|
// CMSG_LOOT_MASTER_GIVE: uint64 lootGuid + uint8 slotIndex + uint64 targetGuid
|
||||||
|
network::Packet pkt(wireOpcode(Opcode::CMSG_LOOT_MASTER_GIVE));
|
||||||
|
pkt.writeUInt64(currentLoot.lootGuid);
|
||||||
|
pkt.writeUInt8(lootSlot);
|
||||||
|
pkt.writeUInt64(targetGuid);
|
||||||
|
socket->send(pkt);
|
||||||
|
}
|
||||||
|
|
||||||
void GameHandler::interactWithNpc(uint64_t guid) {
|
void GameHandler::interactWithNpc(uint64_t guid) {
|
||||||
if (state != WorldState::IN_WORLD || !socket) return;
|
if (state != WorldState::IN_WORLD || !socket) return;
|
||||||
auto packet = GossipHelloPacket::build(guid);
|
auto packet = GossipHelloPacket::build(guid);
|
||||||
|
|
|
||||||
|
|
@ -12164,7 +12164,43 @@ void GameScreen::renderLootWindow(game::GameHandler& gameHandler) {
|
||||||
|
|
||||||
// Process deferred loot pickup (after loop to avoid iterator invalidation)
|
// Process deferred loot pickup (after loop to avoid iterator invalidation)
|
||||||
if (lootSlotClicked >= 0) {
|
if (lootSlotClicked >= 0) {
|
||||||
gameHandler.lootItem(static_cast<uint8_t>(lootSlotClicked));
|
if (gameHandler.hasMasterLootCandidates()) {
|
||||||
|
// Master looter: open popup to choose recipient
|
||||||
|
char popupId[32];
|
||||||
|
snprintf(popupId, sizeof(popupId), "##MLGive%d", lootSlotClicked);
|
||||||
|
ImGui::OpenPopup(popupId);
|
||||||
|
} else {
|
||||||
|
gameHandler.lootItem(static_cast<uint8_t>(lootSlotClicked));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Master loot "Give to" popups
|
||||||
|
if (gameHandler.hasMasterLootCandidates()) {
|
||||||
|
for (const auto& item : loot.items) {
|
||||||
|
char popupId[32];
|
||||||
|
snprintf(popupId, sizeof(popupId), "##MLGive%d", item.slotIndex);
|
||||||
|
if (ImGui::BeginPopup(popupId)) {
|
||||||
|
ImGui::TextDisabled("Give to:");
|
||||||
|
ImGui::Separator();
|
||||||
|
const auto& candidates = gameHandler.getMasterLootCandidates();
|
||||||
|
for (uint64_t candidateGuid : candidates) {
|
||||||
|
auto entity = gameHandler.getEntityManager().getEntity(candidateGuid);
|
||||||
|
auto* unit = entity ? dynamic_cast<game::Unit*>(entity.get()) : nullptr;
|
||||||
|
const char* cName = unit ? unit->getName().c_str() : nullptr;
|
||||||
|
char nameBuf[64];
|
||||||
|
if (!cName || cName[0] == '\0') {
|
||||||
|
snprintf(nameBuf, sizeof(nameBuf), "Player 0x%llx",
|
||||||
|
static_cast<unsigned long long>(candidateGuid));
|
||||||
|
cName = nameBuf;
|
||||||
|
}
|
||||||
|
if (ImGui::MenuItem(cName)) {
|
||||||
|
gameHandler.lootMasterGive(item.slotIndex, candidateGuid);
|
||||||
|
ImGui::CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loot.items.empty() && loot.gold == 0) {
|
if (loot.items.empty() && loot.gold == 0) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue