mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-22 23:30:14 +00:00
Implement Dungeon Finder UI window with role/dungeon selection
- Add renderDungeonFinderWindow() with status display (not queued / role check / queued+wait time / proposal / in dungeon / finished) - Role checkboxes (Tank/Healer/DPS) and dungeon combo (25 entries covering Vanilla, TBC, and WotLK including Random/Heroic) - Accept/Decline buttons during Proposal state, Teleport button while InDungeon, Leave Queue button while Queued/RoleCheck - Store lfgProposalId_ on GameHandler so UI can pass it to lfgAcceptProposal(); expose getLfgProposalId() and getLfgTimeInQueueMs() getters - Toggle window with I key (when chat input is not active)
This commit is contained in:
parent
63c6039dbb
commit
200a00d4f5
4 changed files with 212 additions and 6 deletions
|
|
@ -737,8 +737,10 @@ public:
|
|||
LfgState getLfgState() const { return lfgState_; }
|
||||
bool isLfgQueued() const { return lfgState_ == LfgState::Queued; }
|
||||
bool isLfgInDungeon() const { return lfgState_ == LfgState::InDungeon; }
|
||||
uint32_t getLfgDungeonId() const { return lfgDungeonId_; }
|
||||
int32_t getLfgAvgWaitSec() const { return lfgAvgWaitSec_; }
|
||||
uint32_t getLfgDungeonId() const { return lfgDungeonId_; }
|
||||
uint32_t getLfgProposalId() const { return lfgProposalId_; }
|
||||
int32_t getLfgAvgWaitSec() const { return lfgAvgWaitSec_; }
|
||||
uint32_t getLfgTimeInQueueMs() const { return lfgTimeInQueueMs_; }
|
||||
|
||||
// ---- Phase 5: Loot ----
|
||||
void lootTarget(uint64_t guid);
|
||||
|
|
@ -1585,6 +1587,7 @@ private:
|
|||
// LFG / Dungeon Finder state
|
||||
LfgState lfgState_ = LfgState::None;
|
||||
uint32_t lfgDungeonId_ = 0; // current dungeon entry
|
||||
uint32_t lfgProposalId_ = 0; // pending proposal id (0 = none)
|
||||
int32_t lfgAvgWaitSec_ = -1; // estimated wait, -1=unknown
|
||||
uint32_t lfgTimeInQueueMs_= 0; // ms already in queue
|
||||
|
||||
|
|
|
|||
|
|
@ -227,6 +227,7 @@ private:
|
|||
void renderBankWindow(game::GameHandler& gameHandler);
|
||||
void renderGuildBankWindow(game::GameHandler& gameHandler);
|
||||
void renderAuctionHouseWindow(game::GameHandler& gameHandler);
|
||||
void renderDungeonFinderWindow(game::GameHandler& gameHandler);
|
||||
|
||||
/**
|
||||
* Inventory screen
|
||||
|
|
@ -259,6 +260,11 @@ private:
|
|||
int bagBarPickedSlot_ = -1; // Visual drag in progress (-1 = none)
|
||||
int bagBarDragSource_ = -1; // Mouse pressed on this slot, waiting for drag or click (-1 = none)
|
||||
|
||||
// Dungeon Finder state
|
||||
bool showDungeonFinder_ = false;
|
||||
uint8_t lfgRoles_ = 0x08; // default: DPS (0x02=tank, 0x04=healer, 0x08=dps)
|
||||
uint32_t lfgSelectedDungeon_ = 861; // default: random dungeon (entry 861 = Random Dungeon WotLK)
|
||||
|
||||
// Chat settings
|
||||
bool chatShowTimestamps_ = false;
|
||||
int chatFontSize_ = 1; // 0=small, 1=medium, 2=large
|
||||
|
|
|
|||
|
|
@ -9073,15 +9073,18 @@ void GameHandler::handleLfgProposalUpdate(network::Packet& packet) {
|
|||
if (remaining < 17) return;
|
||||
/*bool canOverride =*/ packet.readUInt8();
|
||||
|
||||
lfgDungeonId_ = dungeonId;
|
||||
lfgDungeonId_ = dungeonId;
|
||||
lfgProposalId_ = proposalId;
|
||||
|
||||
switch (proposalState) {
|
||||
case 0:
|
||||
lfgState_ = LfgState::Queued;
|
||||
lfgState_ = LfgState::Queued;
|
||||
lfgProposalId_ = 0;
|
||||
addSystemChatMessage("Dungeon Finder: Group proposal failed.");
|
||||
break;
|
||||
case 1:
|
||||
lfgState_ = LfgState::InDungeon;
|
||||
lfgState_ = LfgState::InDungeon;
|
||||
lfgProposalId_ = 0;
|
||||
addSystemChatMessage("Dungeon Finder: Group found! Entering dungeon...");
|
||||
break;
|
||||
case 2:
|
||||
|
|
@ -9094,7 +9097,6 @@ void GameHandler::handleLfgProposalUpdate(network::Packet& packet) {
|
|||
|
||||
LOG_INFO("SMSG_LFG_PROPOSAL_UPDATE: dungeonId=", dungeonId,
|
||||
" proposalId=", proposalId, " state=", proposalState);
|
||||
(void)proposalId;
|
||||
}
|
||||
|
||||
void GameHandler::handleLfgRoleCheckUpdate(network::Packet& packet) {
|
||||
|
|
|
|||
|
|
@ -412,6 +412,7 @@ void GameScreen::render(game::GameHandler& gameHandler) {
|
|||
renderBankWindow(gameHandler);
|
||||
renderGuildBankWindow(gameHandler);
|
||||
renderAuctionHouseWindow(gameHandler);
|
||||
renderDungeonFinderWindow(gameHandler);
|
||||
// renderQuestMarkers(gameHandler); // Disabled - using 3D billboard markers now
|
||||
renderMinimapMarkers(gameHandler);
|
||||
renderDeathScreen(gameHandler);
|
||||
|
|
@ -8877,4 +8878,198 @@ void GameScreen::renderDingEffect() {
|
|||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Dungeon Finder window (toggle with hotkey or bag-bar button)
|
||||
// ---------------------------------------------------------------------------
|
||||
void GameScreen::renderDungeonFinderWindow(game::GameHandler& gameHandler) {
|
||||
// Toggle on I key when not typing
|
||||
if (!chatInputActive && ImGui::IsKeyPressed(ImGuiKey_I, false)) {
|
||||
showDungeonFinder_ = !showDungeonFinder_;
|
||||
}
|
||||
|
||||
if (!showDungeonFinder_) return;
|
||||
|
||||
auto* window = core::Application::getInstance().getWindow();
|
||||
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
|
||||
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(screenW * 0.5f - 175.0f, screenH * 0.2f),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSize(ImVec2(350, 0), ImGuiCond_Always);
|
||||
|
||||
bool open = true;
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize;
|
||||
if (!ImGui::Begin("Dungeon Finder", &open, flags)) {
|
||||
ImGui::End();
|
||||
if (!open) showDungeonFinder_ = false;
|
||||
return;
|
||||
}
|
||||
if (!open) {
|
||||
ImGui::End();
|
||||
showDungeonFinder_ = false;
|
||||
return;
|
||||
}
|
||||
|
||||
using LfgState = game::GameHandler::LfgState;
|
||||
LfgState state = gameHandler.getLfgState();
|
||||
|
||||
// ---- Status banner ----
|
||||
switch (state) {
|
||||
case LfgState::None:
|
||||
ImGui::TextColored(ImVec4(0.6f, 0.6f, 0.6f, 1.0f), "Status: Not queued");
|
||||
break;
|
||||
case LfgState::RoleCheck:
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "Status: Role check in progress...");
|
||||
break;
|
||||
case LfgState::Queued: {
|
||||
int32_t avgSec = gameHandler.getLfgAvgWaitSec();
|
||||
uint32_t qMs = gameHandler.getLfgTimeInQueueMs();
|
||||
int qMin = static_cast<int>(qMs / 60000);
|
||||
int qSec = static_cast<int>((qMs % 60000) / 1000);
|
||||
ImGui::TextColored(ImVec4(0.3f, 0.9f, 0.3f, 1.0f), "Status: In queue (%d:%02d)", qMin, qSec);
|
||||
if (avgSec >= 0) {
|
||||
int aMin = avgSec / 60;
|
||||
int aSec = avgSec % 60;
|
||||
ImGui::TextColored(ImVec4(0.8f, 0.8f, 0.8f, 1.0f),
|
||||
"Avg wait: %d:%02d", aMin, aSec);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case LfgState::Proposal:
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.1f, 1.0f), "Status: Group found!");
|
||||
break;
|
||||
case LfgState::Boot:
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.3f, 0.3f, 1.0f), "Status: Vote kick in progress");
|
||||
break;
|
||||
case LfgState::InDungeon:
|
||||
ImGui::TextColored(ImVec4(0.4f, 0.8f, 1.0f, 1.0f), "Status: In dungeon");
|
||||
break;
|
||||
case LfgState::FinishedDungeon:
|
||||
ImGui::TextColored(ImVec4(0.6f, 1.0f, 0.6f, 1.0f), "Status: Dungeon complete");
|
||||
break;
|
||||
case LfgState::RaidBrowser:
|
||||
ImGui::TextColored(ImVec4(0.8f, 0.6f, 1.0f, 1.0f), "Status: Raid browser");
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// ---- Proposal accept/decline ----
|
||||
if (state == LfgState::Proposal) {
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.9f, 0.3f, 1.0f),
|
||||
"A group has been found for your dungeon!");
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("Accept", ImVec2(120, 0))) {
|
||||
gameHandler.lfgAcceptProposal(gameHandler.getLfgProposalId(), true);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Decline", ImVec2(120, 0))) {
|
||||
gameHandler.lfgAcceptProposal(gameHandler.getLfgProposalId(), false);
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
// ---- Teleport button (in dungeon) ----
|
||||
if (state == LfgState::InDungeon) {
|
||||
if (ImGui::Button("Teleport to Dungeon", ImVec2(-1, 0))) {
|
||||
gameHandler.lfgTeleport(true);
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
// ---- Role selection (only when not queued/in dungeon) ----
|
||||
bool canConfigure = (state == LfgState::None || state == LfgState::FinishedDungeon);
|
||||
|
||||
if (canConfigure) {
|
||||
ImGui::Text("Role:");
|
||||
ImGui::SameLine();
|
||||
bool isTank = (lfgRoles_ & 0x02) != 0;
|
||||
bool isHealer = (lfgRoles_ & 0x04) != 0;
|
||||
bool isDps = (lfgRoles_ & 0x08) != 0;
|
||||
if (ImGui::Checkbox("Tank", &isTank)) lfgRoles_ = (lfgRoles_ & ~0x02) | (isTank ? 0x02 : 0);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("Healer", &isHealer)) lfgRoles_ = (lfgRoles_ & ~0x04) | (isHealer ? 0x04 : 0);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Checkbox("DPS", &isDps)) lfgRoles_ = (lfgRoles_ & ~0x08) | (isDps ? 0x08 : 0);
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// ---- Dungeon selection ----
|
||||
ImGui::Text("Dungeon:");
|
||||
|
||||
struct DungeonEntry { uint32_t id; const char* name; };
|
||||
static const DungeonEntry kDungeons[] = {
|
||||
{ 861, "Random Dungeon" },
|
||||
{ 862, "Random Heroic" },
|
||||
// Vanilla classics
|
||||
{ 36, "Deadmines" },
|
||||
{ 43, "Ragefire Chasm" },
|
||||
{ 47, "Razorfen Kraul" },
|
||||
{ 48, "Blackfathom Deeps" },
|
||||
{ 52, "Uldaman" },
|
||||
{ 57, "Dire Maul: East" },
|
||||
{ 70, "Onyxia's Lair" },
|
||||
// TBC heroics
|
||||
{ 264, "The Blood Furnace" },
|
||||
{ 269, "The Shattered Halls" },
|
||||
// WotLK normals/heroics
|
||||
{ 576, "The Nexus" },
|
||||
{ 578, "The Oculus" },
|
||||
{ 595, "The Culling of Stratholme" },
|
||||
{ 599, "Halls of Stone" },
|
||||
{ 600, "Drak'Tharon Keep" },
|
||||
{ 601, "Azjol-Nerub" },
|
||||
{ 604, "Gundrak" },
|
||||
{ 608, "Violet Hold" },
|
||||
{ 619, "Ahn'kahet: Old Kingdom" },
|
||||
{ 623, "Halls of Lightning" },
|
||||
{ 632, "The Forge of Souls" },
|
||||
{ 650, "Trial of the Champion" },
|
||||
{ 658, "Pit of Saron" },
|
||||
{ 668, "Halls of Reflection" },
|
||||
};
|
||||
|
||||
// Find current index
|
||||
int curIdx = 0;
|
||||
for (int i = 0; i < (int)(sizeof(kDungeons)/sizeof(kDungeons[0])); ++i) {
|
||||
if (kDungeons[i].id == lfgSelectedDungeon_) { curIdx = i; break; }
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
if (ImGui::BeginCombo("##dungeon", kDungeons[curIdx].name)) {
|
||||
for (int i = 0; i < (int)(sizeof(kDungeons)/sizeof(kDungeons[0])); ++i) {
|
||||
bool selected = (kDungeons[i].id == lfgSelectedDungeon_);
|
||||
if (ImGui::Selectable(kDungeons[i].name, selected))
|
||||
lfgSelectedDungeon_ = kDungeons[i].id;
|
||||
if (selected) ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
|
||||
// ---- Join button ----
|
||||
bool rolesOk = (lfgRoles_ != 0);
|
||||
if (!rolesOk) {
|
||||
ImGui::BeginDisabled();
|
||||
}
|
||||
if (ImGui::Button("Join Dungeon Finder", ImVec2(-1, 0))) {
|
||||
gameHandler.lfgJoin(lfgSelectedDungeon_, lfgRoles_);
|
||||
}
|
||||
if (!rolesOk) {
|
||||
ImGui::EndDisabled();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.4f, 0.4f, 1.0f), "Select at least one role.");
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Leave button (when queued or role check) ----
|
||||
if (state == LfgState::Queued || state == LfgState::RoleCheck) {
|
||||
if (ImGui::Button("Leave Queue", ImVec2(-1, 0))) {
|
||||
gameHandler.lfgLeave();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
}} // namespace wowee::ui
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue