Fix trainer system and add critical spell/quest opcodes

Trainer System Fixes:
- Fix CMSG_TRAINER_BUY_SPELL packet: remove incorrect trainerType field (12 bytes not 16)
- Correct spell state interpretation: 0=available, 1=unavailable, 2=known
- Add dynamic prerequisite re-evaluation in real-time as spells are learned
- Immediately update knownSpells on SMSG_TRAINER_BUY_SUCCEEDED
- Add "Show unavailable spells" checkbox filter to trainer window
- Override server state when prerequisites become met client-side

New Spell Opcodes:
- SMSG_SUPERCEDED_SPELL (0x12C): handle spell rank upgrades
- SMSG_SEND_UNLEARN_SPELLS (0x41F): handle bulk unlearning (respec/dual-spec)
- CMSG_TRAINER_LIST (0x1B0): trainer request opcode

Quest System:
- SMSG_QUESTUPDATE_COMPLETE (0x195): mark quests complete when objectives done
- Show "Quest Complete" message and enable turn-in UI

Detailed logging:
- SMSG_INITIAL_SPELLS now logs packet size and first 10 spell IDs
- Money values logged during trainer purchases
- Trainer spell states and prerequisites logged for debugging

This enables proper spell progression chains, spec changes, and quest completion
notifications matching retail WoW 3.3.5a behavior.
This commit is contained in:
Kelsi 2026-02-10 01:24:37 -08:00
parent 8af895c025
commit a764eea2ec
6 changed files with 632 additions and 36 deletions

View file

@ -495,6 +495,8 @@ public:
std::string title;
std::string objectives;
bool complete = false;
// Objective kill counts: objectiveIndex -> (current, required)
std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> killCounts;
};
const std::vector<QuestLogEntry>& getQuestLog() const { return questLog_; }
void abandonQuest(uint32_t questId);
@ -697,7 +699,9 @@ private:
void handleCooldownEvent(network::Packet& packet);
void handleAuraUpdate(network::Packet& packet, bool isAll);
void handleLearnedSpell(network::Packet& packet);
void handleSupercededSpell(network::Packet& packet);
void handleRemovedSpell(network::Packet& packet);
void handleUnlearnSpells(network::Packet& packet);
// ---- Phase 4 handlers ----
void handleGroupInvite(network::Packet& packet);

View file

@ -159,7 +159,9 @@ enum class Opcode : uint16_t {
SMSG_UPDATE_AURA_DURATION = 0x137,
SMSG_INITIAL_SPELLS = 0x12A,
SMSG_LEARNED_SPELL = 0x12B,
SMSG_SUPERCEDED_SPELL = 0x12C,
SMSG_REMOVED_SPELL = 0x203,
SMSG_SEND_UNLEARN_SPELLS = 0x41F,
SMSG_SPELL_DELAYED = 0x1E2,
SMSG_AURA_UPDATE = 0x3FA,
SMSG_AURA_UPDATE_ALL = 0x495,
@ -223,8 +225,11 @@ enum class Opcode : uint16_t {
SMSG_QUESTGIVER_QUEST_INVALID = 0x18F,
SMSG_QUESTGIVER_QUEST_COMPLETE = 0x191,
CMSG_QUESTLOG_REMOVE_QUEST = 0x194,
SMSG_QUESTUPDATE_ADD_KILL = 0x196, // Quest kill count update
SMSG_QUESTUPDATE_COMPLETE = 0x195, // Quest objectives completed
CMSG_QUEST_QUERY = 0x05C, // Client requests quest data
SMSG_QUEST_QUERY_RESPONSE = 0x05D, // Server sends quest data
SMSG_QUESTLOG_FULL = 0x1A3, // Full quest log on login
// ---- Phase 5: Vendor ----
CMSG_LIST_INVENTORY = 0x19E,
@ -235,8 +240,10 @@ enum class Opcode : uint16_t {
SMSG_BUY_FAILED = 0x1A5,
// ---- Trainer ----
CMSG_TRAINER_LIST = 0x01B0,
SMSG_TRAINER_LIST = 0x01B1,
CMSG_TRAINER_BUY_SPELL = 0x01B2,
SMSG_TRAINER_BUY_FAILED = 0x01B4,
// ---- Phase 5: Item/Equip ----
CMSG_ITEM_QUERY_SINGLE = 0x056,

View file

@ -1750,7 +1750,7 @@ public:
class TrainerBuySpellPacket {
public:
static network::Packet build(uint64_t trainerGuid, uint32_t trainerId, uint32_t spellId);
static network::Packet build(uint64_t trainerGuid, uint32_t spellId);
};
// ============================================================