From 863faf9b544041276b515c0de3f89213bfb91e1f Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 13 Mar 2026 03:32:45 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20correct=20talent=20rank=20indexing=20?= =?UTF-8?q?=E2=80=94=20store=201-indexed,=20fix=20prereq=20and=20learn=20c?= =?UTF-8?q?hecks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SMSG_TALENTS_INFO wire format sends 0-indexed ranks (0=has rank 1). Both handlers were storing raw 0-indexed values, but handleSpellLearnedServer correctly stored rank+1 (1-indexed). This caused: - getTalentRank() returning 0 for both "not learned" and "has rank 1", making pointsInTree always wrong and blocking tier access - Prereq check `prereqRank < DBC_prereqRank` always met when not learned (0 < 0 = false), incorrectly unlocking talents - Click handler sending wrong desiredRank to server Fixes: - Both SMSG_TALENTS_INFO handlers: store rank+1u (1-indexed) - talent_screen.cpp prereq check: change < to <= (DBC is 0-indexed, storage is 1-indexed; must use > for "met", <= for "not met") - talent_screen.cpp click handler: send currentRank directly (1-indexed value equals what CMSG_LEARN_TALENT requestedRank expects) - Tooltip: display prereqRank+1 so "Requires 1 point" shows correctly --- src/game/game_handler.cpp | 4 ++-- src/ui/talent_screen.cpp | 23 +++++++++-------------- 2 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 17f845e7..2621d11a 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -12701,7 +12701,7 @@ void GameHandler::handleInspectResults(network::Packet& packet) { if (packet.getSize() - packet.getReadPos() < 5) break; uint32_t talentId = packet.readUInt32(); uint8_t rank = packet.readUInt8(); - learnedTalents_[g][talentId] = rank; + learnedTalents_[g][talentId] = rank + 1u; // wire sends 0-indexed; store 1-indexed } if (packet.getSize() - packet.getReadPos() < 1) break; learnedGlyphs_[g].fill(0); @@ -16545,7 +16545,7 @@ void GameHandler::handleTalentsInfo(network::Packet& packet) { if (packet.getSize() - packet.getReadPos() < 5) break; uint32_t talentId = packet.readUInt32(); uint8_t rank = packet.readUInt8(); - learnedTalents_[g][talentId] = rank; + learnedTalents_[g][talentId] = rank + 1u; // wire sends 0-indexed; store 1-indexed } learnedGlyphs_[g].fill(0); if (packet.getSize() - packet.getReadPos() < 1) break; diff --git a/src/ui/talent_screen.cpp b/src/ui/talent_screen.cpp index e0598ad2..bed817ab 100644 --- a/src/ui/talent_screen.cpp +++ b/src/ui/talent_screen.cpp @@ -303,7 +303,7 @@ void TalentScreen::renderTalentTree(game::GameHandler& gameHandler, uint32_t tab if (fromIt == talentPositions.end() || toIt == talentPositions.end()) continue; uint8_t prereqRank = gameHandler.getTalentRank(talent->prereqTalent[i]); - bool met = prereqRank >= talent->prereqRank[i]; + bool met = prereqRank > talent->prereqRank[i]; // storage 1-indexed, DBC 0-indexed ImU32 lineCol = met ? IM_COL32(100, 220, 100, 200) : IM_COL32(120, 120, 120, 150); ImVec2 from = fromIt->second.center; @@ -374,7 +374,7 @@ void TalentScreen::renderTalent(game::GameHandler& gameHandler, for (int i = 0; i < 3; ++i) { if (talent.prereqTalent[i] != 0) { uint8_t prereqRank = gameHandler.getTalentRank(talent.prereqTalent[i]); - if (prereqRank < talent.prereqRank[i]) { + if (prereqRank <= talent.prereqRank[i]) { // storage 1-indexed, DBC 0-indexed prereqsMet = false; canLearn = false; break; @@ -541,14 +541,15 @@ void TalentScreen::renderTalent(game::GameHandler& gameHandler, if (!prereq || prereq->rankSpells[0] == 0) continue; uint8_t prereqCurrentRank = gameHandler.getTalentRank(talent.prereqTalent[i]); - bool met = prereqCurrentRank >= talent.prereqRank[i]; + bool met = prereqCurrentRank > talent.prereqRank[i]; // storage 1-indexed, DBC 0-indexed ImVec4 pColor = met ? ImVec4(0.3f, 0.9f, 0.3f, 1) : ImVec4(1.0f, 0.3f, 0.3f, 1); const std::string& prereqName = gameHandler.getSpellName(prereq->rankSpells[0]); ImGui::Spacing(); + const uint8_t reqRankDisplay = talent.prereqRank[i] + 1u; // DBC 0-indexed → display 1-indexed ImGui::TextColored(pColor, "Requires %u point%s in %s", - talent.prereqRank[i], - talent.prereqRank[i] > 1 ? "s" : "", + reqRankDisplay, + reqRankDisplay > 1 ? "s" : "", prereqName.empty() ? "prerequisite" : prereqName.c_str()); } @@ -573,16 +574,10 @@ void TalentScreen::renderTalent(game::GameHandler& gameHandler, ImGui::EndTooltip(); } - // Handle click + // Handle click — currentRank is 1-indexed (0=not learned, 1=rank1, ...) + // CMSG_LEARN_TALENT requestedRank must equal current count of learned ranks (same value) if (clicked && canLearn && prereqsMet) { - const auto& learned = gameHandler.getLearnedTalents(); - uint8_t desiredRank; - if (learned.find(talent.talentId) == learned.end()) { - desiredRank = 0; // First rank (0-indexed on wire) - } else { - desiredRank = currentRank; // currentRank is already the next 0-indexed rank to learn - } - gameHandler.learnTalent(talent.talentId, desiredRank); + gameHandler.learnTalent(talent.talentId, currentRank); } ImGui::PopID();