Add XP tracking with level-up, kill XP formula, and server-compatible SMSG_LOG_XPGAIN support

This commit is contained in:
Kelsi 2026-02-05 12:07:58 -08:00
parent ed5d10ec01
commit 78442f8aea
7 changed files with 249 additions and 0 deletions

View file

@ -219,8 +219,15 @@ public:
localPlayerLevel_ = level;
localPlayerHealth_ = hp;
localPlayerMaxHealth_ = maxHp;
playerNextLevelXp_ = xpForLevel(level);
playerXp_ = 0;
}
// XP tracking (works in both single-player and server modes)
uint32_t getPlayerXp() const { return playerXp_; }
uint32_t getPlayerNextLevelXp() const { return playerNextLevelXp_; }
uint32_t getPlayerLevel() const { return singlePlayerMode_ ? localPlayerLevel_ : serverPlayerLevel_; }
// Hearthstone callback (single-player teleport)
using HearthstoneCallback = std::function<void()>;
void setHearthstoneCallback(HearthstoneCallback cb) { hearthstoneCallback = std::move(cb); }
@ -361,6 +368,9 @@ private:
void handleGroupUninvite(network::Packet& packet);
void handlePartyCommandResult(network::Packet& packet);
// ---- XP handler ----
void handleXpGain(network::Packet& packet);
// ---- Phase 5 handlers ----
void handleLootResponse(network::Packet& packet);
void handleLootReleaseResponse(network::Packet& packet);
@ -486,6 +496,15 @@ private:
WorldConnectSuccessCallback onSuccess;
WorldConnectFailureCallback onFailure;
// ---- XP tracking ----
uint32_t playerXp_ = 0;
uint32_t playerNextLevelXp_ = 0;
uint32_t serverPlayerLevel_ = 1;
void awardLocalXp(uint32_t victimLevel);
void levelUp();
static uint32_t xpForLevel(uint32_t level);
static uint32_t killXp(uint32_t playerLevel, uint32_t victimLevel);
// ---- Single-player combat ----
bool singlePlayerMode_ = false;
float swingTimer_ = 0.0f;

View file

@ -60,6 +60,9 @@ enum class Opcode : uint16_t {
SMSG_GAMEOBJECT_QUERY_RESPONSE = 0x05F,
CMSG_SET_ACTIVE_MOVER = 0x26A,
// ---- XP ----
SMSG_LOG_XPGAIN = 0x1D0,
// ---- Phase 2: Combat Core ----
CMSG_ATTACKSWING = 0x141,
CMSG_ATTACKSTOP = 0x142,

View file

@ -742,6 +742,25 @@ public:
static bool parse(network::Packet& packet, SpellHealLogData& data);
};
// ============================================================
// XP Gain
// ============================================================
/** SMSG_LOG_XPGAIN data */
struct XpGainData {
uint64_t victimGuid = 0; // 0 for non-kill XP (quest, exploration)
uint32_t totalXp = 0;
uint8_t type = 0; // 0 = kill, 1 = non-kill
uint32_t groupBonus = 0;
bool isValid() const { return totalXp > 0; }
};
class XpGainParser {
public:
static bool parse(network::Packet& packet, XpGainData& data);
};
// ============================================================
// Phase 3: Spells, Action Bar, Auras
// ============================================================

View file

@ -110,6 +110,7 @@ private:
// ---- New UI renders ----
void renderActionBar(game::GameHandler& gameHandler);
void renderXpBar(game::GameHandler& gameHandler);
void renderCastBar(game::GameHandler& gameHandler);
void renderCombatText(game::GameHandler& gameHandler);
void renderPartyFrames(game::GameHandler& gameHandler);