From 9368c8a715efbbe71cd3df1f59a0df70b3f54743 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 18 Mar 2026 11:23:35 -0700 Subject: [PATCH] feat: add confirmation dialog before spending talent points Clicking a learnable talent now opens a modal confirmation popup showing the spell name and rank, preventing accidental talent spending. --- include/ui/talent_screen.hpp | 6 ++++++ src/ui/talent_screen.cpp | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/include/ui/talent_screen.hpp b/include/ui/talent_screen.hpp index 72eafc2a..82a674e4 100644 --- a/include/ui/talent_screen.hpp +++ b/include/ui/talent_screen.hpp @@ -45,6 +45,12 @@ private: std::unordered_map spellTooltips; // spellId -> description std::unordered_map bgTextureCache_; // tabId -> bg texture + // Talent learn confirmation + bool talentConfirmOpen_ = false; + uint32_t pendingTalentId_ = 0; + uint32_t pendingTalentRank_ = 0; + std::string pendingTalentName_; + // GlyphProperties.dbc cache: glyphId -> { spellId, isMajor } struct GlyphInfo { uint32_t spellId = 0; bool isMajor = false; }; std::unordered_map glyphProperties_; // glyphId -> info diff --git a/src/ui/talent_screen.cpp b/src/ui/talent_screen.cpp index c2b92eff..5f87712f 100644 --- a/src/ui/talent_screen.cpp +++ b/src/ui/talent_screen.cpp @@ -176,6 +176,29 @@ void TalentScreen::renderTalentTrees(game::GameHandler& gameHandler) { ImGui::EndTabBar(); } + + // Talent learn confirmation popup + if (talentConfirmOpen_) { + ImGui::OpenPopup("Learn Talent?##talent_confirm"); + talentConfirmOpen_ = false; + } + if (ImGui::BeginPopupModal("Learn Talent?##talent_confirm", nullptr, + ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove)) { + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0.3f, 1.0f), "%s", pendingTalentName_.c_str()); + ImGui::Text("Rank %u", pendingTalentRank_ + 1); + ImGui::Spacing(); + ImGui::TextWrapped("Spend a talent point?"); + ImGui::Spacing(); + if (ImGui::Button("Learn", ImVec2(80, 0))) { + gameHandler.learnTalent(pendingTalentId_, pendingTalentRank_); + ImGui::CloseCurrentPopup(); + } + ImGui::SameLine(); + if (ImGui::Button("Cancel", ImVec2(80, 0))) { + ImGui::CloseCurrentPopup(); + } + ImGui::EndPopup(); + } } void TalentScreen::renderTalentTree(game::GameHandler& gameHandler, uint32_t tabId, @@ -574,10 +597,15 @@ void TalentScreen::renderTalent(game::GameHandler& gameHandler, ImGui::EndTooltip(); } - // Handle click — currentRank is 1-indexed (0=not learned, 1=rank1, ...) - // CMSG_LEARN_TALENT requestedRank must equal current count of learned ranks (same value) + // Handle click — open confirmation dialog instead of learning directly if (clicked && canLearn && prereqsMet) { - gameHandler.learnTalent(talent.talentId, currentRank); + talentConfirmOpen_ = true; + pendingTalentId_ = talent.talentId; + pendingTalentRank_ = currentRank; + uint32_t nextSpell = (currentRank < 5) ? talent.rankSpells[currentRank] : 0; + pendingTalentName_ = nextSpell ? gameHandler.getSpellName(nextSpell) : ""; + if (pendingTalentName_.empty()) + pendingTalentName_ = spellId ? gameHandler.getSpellName(spellId) : "Talent"; } ImGui::PopID();