Implement complete talent system with dual spec support

Network Protocol:
- Add SMSG_TALENTS_INFO (0x4C0) packet parsing for talent data
- Add CMSG_LEARN_TALENT (0x251) to request learning talents
- Add MSG_TALENT_WIPE_CONFIRM (0x2AB) opcode for spec switching
- Parse talent spec, unspent points, and learned talent ranks

DBC Parsing:
- Load Talent.dbc: talent grid positions, ranks, prerequisites, spell IDs
- Load TalentTab.dbc: talent tree definitions with correct field indices
- Fix localized string field handling (17 fields per string)
- Load Spell.dbc and SpellIcon.dbc for talent icons and tooltips
- Class mask filtering using bitwise operations (1 << (class - 1))

UI Implementation:
- Complete talent tree UI with tabbed interface for specs
- Display talent icons from spell data with proper tinting/borders
- Enhanced tooltips: spell name, rank, current/next descriptions, prereqs
- Visual states: green (maxed), yellow (partial), white (available), gray (locked)
- Tier unlock system (5 points per tier requirement)
- Rank overlay on icons with shadow text
- Click to learn talents with validation

Dual Spec Support:
- Store unspent points and learned talents per spec (0 and 1)
- Track active spec and display its talents
- Spec switching UI with buttons for Spec 1/Spec 2
- Handle both SMSG_TALENTS_INFO packets from server at login
- Display unspent points for both specs in header
- Independent talent trees for each specialization
This commit is contained in:
Kelsi 2026-02-10 02:00:13 -08:00
parent bf03044a63
commit e7556605d7
8 changed files with 860 additions and 29 deletions

View file

@ -1753,6 +1753,43 @@ public:
static network::Packet build(uint64_t trainerGuid, uint32_t spellId);
};
// ============================================================
// Talents
// ============================================================
/** Talent info for a single talent */
struct TalentInfo {
uint32_t talentId = 0; // Talent.dbc ID
uint8_t currentRank = 0; // 0-5 (0 = not learned)
};
/** SMSG_TALENTS_INFO data */
struct TalentsInfoData {
uint8_t talentSpec = 0; // Active spec (0 or 1 for dual-spec)
uint8_t unspentPoints = 0; // Talent points available
std::vector<TalentInfo> talents; // Learned talents
bool isValid() const { return true; }
};
/** SMSG_TALENTS_INFO parser */
class TalentsInfoParser {
public:
static bool parse(network::Packet& packet, TalentsInfoData& data);
};
/** CMSG_LEARN_TALENT packet builder */
class LearnTalentPacket {
public:
static network::Packet build(uint32_t talentId, uint32_t requestedRank);
};
/** MSG_TALENT_WIPE_CONFIRM packet builder */
class TalentWipeConfirmPacket {
public:
static network::Packet build(bool accept);
};
// ============================================================
// Taxi / Flight Paths
// ============================================================