From f88d90ee889702cd9a5ea367e277d4bcf2984372 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Fri, 20 Mar 2026 04:36:30 -0700 Subject: [PATCH] feat: track and display honor/arena points from update fields Add PLAYER_FIELD_HONOR_CURRENCY and PLAYER_FIELD_ARENA_CURRENCY to the update field system for WotLK (indices 1422/1423) and TBC (1505/1506). Parse values from both CREATE_OBJECT and VALUES update paths, and show them in the character Stats tab under a PvP Currency section. --- Data/expansions/tbc/update_fields.json | 2 ++ Data/expansions/wotlk/update_fields.json | 2 ++ include/game/game_handler.hpp | 6 ++++++ include/game/update_field_table.hpp | 4 ++++ src/game/game_handler.cpp | 20 ++++++++++++++++++++ src/ui/inventory_screen.cpp | 16 ++++++++++++++++ 6 files changed, 50 insertions(+) diff --git a/Data/expansions/tbc/update_fields.json b/Data/expansions/tbc/update_fields.json index 05e37180..fa443aa1 100644 --- a/Data/expansions/tbc/update_fields.json +++ b/Data/expansions/tbc/update_fields.json @@ -37,6 +37,8 @@ "PLAYER_FIELD_BANKBAG_SLOT_1": 784, "PLAYER_SKILL_INFO_START": 928, "PLAYER_EXPLORED_ZONES_START": 1312, + "PLAYER_FIELD_HONOR_CURRENCY": 1505, + "PLAYER_FIELD_ARENA_CURRENCY": 1506, "GAMEOBJECT_DISPLAYID": 8, "ITEM_FIELD_STACK_COUNT": 14, "ITEM_FIELD_DURABILITY": 60, diff --git a/Data/expansions/wotlk/update_fields.json b/Data/expansions/wotlk/update_fields.json index 1628b94c..7b5e12e8 100644 --- a/Data/expansions/wotlk/update_fields.json +++ b/Data/expansions/wotlk/update_fields.json @@ -49,6 +49,8 @@ "PLAYER_RANGED_CRIT_PERCENTAGE": 1030, "PLAYER_SPELL_CRIT_PERCENTAGE1": 1032, "PLAYER_FIELD_COMBAT_RATING_1": 1231, + "PLAYER_FIELD_HONOR_CURRENCY": 1422, + "PLAYER_FIELD_ARENA_CURRENCY": 1423, "GAMEOBJECT_DISPLAYID": 8, "ITEM_FIELD_STACK_COUNT": 14, "ITEM_FIELD_DURABILITY": 60, diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 569261b2..cb34d462 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -299,6 +299,10 @@ public: // Money (copper) uint64_t getMoneyCopper() const { return playerMoneyCopper_; } + // PvP currency (TBC/WotLK only) + uint32_t getHonorPoints() const { return playerHonorPoints_; } + uint32_t getArenaPoints() const { return playerArenaPoints_; } + // Server-authoritative armor (UNIT_FIELD_RESISTANCES[0]) int32_t getArmorRating() const { return playerArmorRating_; } @@ -3067,6 +3071,8 @@ private: float pendingLootMoneyNotifyTimer_ = 0.0f; std::unordered_map recentLootMoneyAnnounceCooldowns_; uint64_t playerMoneyCopper_ = 0; + uint32_t playerHonorPoints_ = 0; + uint32_t playerArenaPoints_ = 0; int32_t playerArmorRating_ = 0; int32_t playerResistances_[6] = {}; // [0]=Holy,[1]=Fire,[2]=Nature,[3]=Frost,[4]=Shadow,[5]=Arcane // Server-authoritative primary stats: [0]=STR [1]=AGI [2]=STA [3]=INT [4]=SPI; -1 = not received yet diff --git a/include/game/update_field_table.hpp b/include/game/update_field_table.hpp index e4687352..4cc2a44a 100644 --- a/include/game/update_field_table.hpp +++ b/include/game/update_field_table.hpp @@ -77,6 +77,10 @@ enum class UF : uint16_t { PLAYER_SPELL_CRIT_PERCENTAGE1, // Spell crit chance % (first school; 7 consecutive float fields) PLAYER_FIELD_COMBAT_RATING_1, // First of 25 int32 combat rating slots (CR_* indices) + // Player PvP currency (TBC/WotLK only — Classic uses the old weekly honor system) + PLAYER_FIELD_HONOR_CURRENCY, // Accumulated honor points (uint32) + PLAYER_FIELD_ARENA_CURRENCY, // Accumulated arena points (uint32) + // GameObject fields GAMEOBJECT_DISPLAYID, diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 16666085..89002564 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -11781,6 +11781,8 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem const uint16_t ufPlayerRestedXp = fieldIndex(UF::PLAYER_REST_STATE_EXPERIENCE); const uint16_t ufPlayerLevel = fieldIndex(UF::UNIT_FIELD_LEVEL); const uint16_t ufCoinage = fieldIndex(UF::PLAYER_FIELD_COINAGE); + const uint16_t ufHonor = fieldIndex(UF::PLAYER_FIELD_HONOR_CURRENCY); + const uint16_t ufArena = fieldIndex(UF::PLAYER_FIELD_ARENA_CURRENCY); const uint16_t ufArmor = fieldIndex(UF::UNIT_FIELD_RESISTANCES); const uint16_t ufPBytes2 = fieldIndex(UF::PLAYER_BYTES_2); const uint16_t ufChosenTitle = fieldIndex(UF::PLAYER_CHOSEN_TITLE); @@ -11814,6 +11816,14 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem playerMoneyCopper_ = val; LOG_DEBUG("Money set from update fields: ", val, " copper"); } + else if (ufHonor != 0xFFFF && key == ufHonor) { + playerHonorPoints_ = val; + LOG_DEBUG("Honor points from update fields: ", val); + } + else if (ufArena != 0xFFFF && key == ufArena) { + playerArenaPoints_ = val; + LOG_DEBUG("Arena points from update fields: ", val); + } else if (ufArmor != 0xFFFF && key == ufArmor) { playerArmorRating_ = static_cast(val); LOG_DEBUG("Armor rating from update fields: ", playerArmorRating_); @@ -12207,6 +12217,8 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem const uint16_t ufPlayerRestedXpV = fieldIndex(UF::PLAYER_REST_STATE_EXPERIENCE); const uint16_t ufPlayerLevel = fieldIndex(UF::UNIT_FIELD_LEVEL); const uint16_t ufCoinage = fieldIndex(UF::PLAYER_FIELD_COINAGE); + const uint16_t ufHonorV = fieldIndex(UF::PLAYER_FIELD_HONOR_CURRENCY); + const uint16_t ufArenaV = fieldIndex(UF::PLAYER_FIELD_ARENA_CURRENCY); const uint16_t ufPlayerFlags = fieldIndex(UF::PLAYER_FLAGS); const uint16_t ufArmor = fieldIndex(UF::UNIT_FIELD_RESISTANCES); const uint16_t ufPBytesV = fieldIndex(UF::PLAYER_BYTES); @@ -12254,6 +12266,14 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem playerMoneyCopper_ = val; LOG_DEBUG("Money updated via VALUES: ", val, " copper"); } + else if (ufHonorV != 0xFFFF && key == ufHonorV) { + playerHonorPoints_ = val; + LOG_DEBUG("Honor points updated: ", val); + } + else if (ufArenaV != 0xFFFF && key == ufArenaV) { + playerArenaPoints_ = val; + LOG_DEBUG("Arena points updated: ", val); + } else if (ufArmor != 0xFFFF && key == ufArmor) { playerArmorRating_ = static_cast(val); } diff --git a/src/ui/inventory_screen.cpp b/src/ui/inventory_screen.cpp index 366e9fa0..bee298c9 100644 --- a/src/ui/inventory_screen.cpp +++ b/src/ui/inventory_screen.cpp @@ -1249,6 +1249,22 @@ void InventoryScreen::renderCharacterScreen(game::GameHandler& gameHandler) { ImGui::Text("%s", fmtTime(levelSec).c_str()); ImGui::NextColumn(); ImGui::Columns(1); } + + // PvP Currency (TBC/WotLK only) + uint32_t honor = gameHandler.getHonorPoints(); + uint32_t arena = gameHandler.getArenaPoints(); + if (honor > 0 || arena > 0) { + ImGui::Separator(); + ImGui::TextDisabled("PvP Currency"); + ImGui::Columns(2, "##pvpcurrency", false); + ImGui::SetColumnWidth(0, 130); + ImGui::Text("Honor Points:"); ImGui::NextColumn(); + ImGui::TextColored(ImVec4(0.9f, 0.75f, 0.2f, 1.0f), "%u", honor); ImGui::NextColumn(); + ImGui::Text("Arena Points:"); ImGui::NextColumn(); + ImGui::TextColored(ImVec4(0.9f, 0.75f, 0.2f, 1.0f), "%u", arena); ImGui::NextColumn(); + ImGui::Columns(1); + } + ImGui::EndTabItem(); }