mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-03-26 00:40:15 +00:00
Fix armor stat in character stats panel via UNIT_FIELD_RESISTANCES
The character stats panel was showing Armor: 0 because summing armor from item query responses is fragile (depends on correct BuyCount/damage block parsing). Instead, read the server-authoritative total armor directly from UNIT_FIELD_RESISTANCES (physical resistance, index 0) in the player entity update fields. Added UNIT_FIELD_RESISTANCES to the UF enum and all four expansion JSON files with correct wire indices: WotLK 3.3.5a: 99 (NPC_FLAGS=82 + emotestate + stat×5 + posstat×5 + negstat×5) TBC 2.4.3: 185 (NPC_FLAGS=168 + same relative layout) Classic 1.12: 154 (NPC_FLAGS=147 + emotestate + stat×5, no posstat/negstat) Turtle WoW: 154 (same as Classic) Stats panel uses server armor when > 0, falls back to summed item-query armor otherwise. Armor rating resets to 0 on world entry and is updated from both CREATE_OBJECT and VALUES update blocks.
This commit is contained in:
parent
05e2b37894
commit
20cdff0790
10 changed files with 33 additions and 5 deletions
|
|
@ -2772,6 +2772,7 @@ void GameHandler::selectCharacter(uint64_t characterGuid) {
|
|||
lastPlayerFields_.clear();
|
||||
onlineEquipDirty_ = false;
|
||||
playerMoneyCopper_ = 0;
|
||||
playerArmorRating_ = 0;
|
||||
knownSpells.clear();
|
||||
spellCooldowns.clear();
|
||||
actionBar = {};
|
||||
|
|
@ -4427,6 +4428,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
const uint16_t ufPlayerNextXp = fieldIndex(UF::PLAYER_NEXT_LEVEL_XP);
|
||||
const uint16_t ufPlayerLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
||||
const uint16_t ufCoinage = fieldIndex(UF::PLAYER_FIELD_COINAGE);
|
||||
const uint16_t ufArmor = fieldIndex(UF::UNIT_FIELD_RESISTANCES);
|
||||
for (const auto& [key, val] : block.fields) {
|
||||
if (key == ufPlayerXp) { playerXp_ = val; }
|
||||
else if (key == ufPlayerNextXp) { playerNextLevelXp_ = val; }
|
||||
|
|
@ -4440,6 +4442,10 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
playerMoneyCopper_ = val;
|
||||
LOG_INFO("Money set from update fields: ", val, " copper");
|
||||
}
|
||||
else if (ufArmor != 0xFFFF && key == ufArmor) {
|
||||
playerArmorRating_ = static_cast<int32_t>(val);
|
||||
LOG_INFO("Armor rating from update fields: ", playerArmorRating_);
|
||||
}
|
||||
// Do not synthesize quest-log entries from raw update-field slots.
|
||||
// Slot layouts differ on some classic-family realms and can produce
|
||||
// phantom "already accepted" quests that block quest acceptance.
|
||||
|
|
@ -4684,6 +4690,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
const uint16_t ufPlayerLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
||||
const uint16_t ufCoinage = fieldIndex(UF::PLAYER_FIELD_COINAGE);
|
||||
const uint16_t ufPlayerFlags = fieldIndex(UF::PLAYER_FLAGS);
|
||||
const uint16_t ufArmor = fieldIndex(UF::UNIT_FIELD_RESISTANCES);
|
||||
for (const auto& [key, val] : block.fields) {
|
||||
if (key == ufPlayerXp) {
|
||||
playerXp_ = val;
|
||||
|
|
@ -4711,6 +4718,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
|||
playerMoneyCopper_ = val;
|
||||
LOG_INFO("Money updated via VALUES: ", val, " copper");
|
||||
}
|
||||
else if (ufArmor != 0xFFFF && key == ufArmor) {
|
||||
playerArmorRating_ = static_cast<int32_t>(val);
|
||||
}
|
||||
else if (key == ufPlayerFlags) {
|
||||
constexpr uint32_t PLAYER_FLAGS_GHOST = 0x00000010;
|
||||
bool wasGhost = releasedSpirit_;
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ static const UFNameEntry kUFNames[] = {
|
|||
{"UNIT_FIELD_AURAS", UF::UNIT_FIELD_AURAS},
|
||||
{"UNIT_NPC_FLAGS", UF::UNIT_NPC_FLAGS},
|
||||
{"UNIT_DYNAMIC_FLAGS", UF::UNIT_DYNAMIC_FLAGS},
|
||||
{"UNIT_FIELD_RESISTANCES", UF::UNIT_FIELD_RESISTANCES},
|
||||
{"UNIT_END", UF::UNIT_END},
|
||||
{"PLAYER_FLAGS", UF::PLAYER_FLAGS},
|
||||
{"PLAYER_BYTES", UF::PLAYER_BYTES},
|
||||
|
|
@ -76,6 +77,7 @@ void UpdateFieldTable::loadWotlkDefaults() {
|
|||
{UF::UNIT_FIELD_MOUNTDISPLAYID, 69},
|
||||
{UF::UNIT_NPC_FLAGS, 82},
|
||||
{UF::UNIT_DYNAMIC_FLAGS, 147},
|
||||
{UF::UNIT_FIELD_RESISTANCES, 99},
|
||||
{UF::UNIT_END, 148},
|
||||
{UF::PLAYER_FLAGS, 150},
|
||||
{UF::PLAYER_BYTES, 151},
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,7 @@ void InventoryScreen::renderCharacterScreen(game::GameHandler& gameHandler) {
|
|||
|
||||
if (ImGui::BeginTabItem("Stats")) {
|
||||
ImGui::Spacing();
|
||||
renderStatsPanel(inventory, gameHandler.getPlayerLevel());
|
||||
renderStatsPanel(inventory, gameHandler.getPlayerLevel(), gameHandler.getArmorRating());
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
|
|
@ -1269,15 +1269,13 @@ void InventoryScreen::renderEquipmentPanel(game::Inventory& inventory) {
|
|||
// Stats Panel
|
||||
// ============================================================
|
||||
|
||||
void InventoryScreen::renderStatsPanel(game::Inventory& inventory, uint32_t playerLevel) {
|
||||
void InventoryScreen::renderStatsPanel(game::Inventory& inventory, uint32_t playerLevel, int32_t serverArmor) {
|
||||
// Sum equipment stats
|
||||
int32_t totalArmor = 0;
|
||||
int32_t totalStr = 0, totalAgi = 0, totalSta = 0, totalInt = 0, totalSpi = 0;
|
||||
|
||||
for (int s = 0; s < game::Inventory::NUM_EQUIP_SLOTS; s++) {
|
||||
const auto& slot = inventory.getEquipSlot(static_cast<game::EquipSlot>(s));
|
||||
if (slot.empty()) continue;
|
||||
totalArmor += slot.item.armor;
|
||||
totalStr += slot.item.strength;
|
||||
totalAgi += slot.item.agility;
|
||||
totalSta += slot.item.stamina;
|
||||
|
|
@ -1285,6 +1283,15 @@ void InventoryScreen::renderStatsPanel(game::Inventory& inventory, uint32_t play
|
|||
totalSpi += slot.item.spirit;
|
||||
}
|
||||
|
||||
// Use server-authoritative armor from UNIT_FIELD_RESISTANCES when available.
|
||||
// Falls back to summing item query armors if server armor wasn't received yet.
|
||||
int32_t itemQueryArmor = 0;
|
||||
for (int s = 0; s < game::Inventory::NUM_EQUIP_SLOTS; s++) {
|
||||
const auto& slot = inventory.getEquipSlot(static_cast<game::EquipSlot>(s));
|
||||
if (!slot.empty()) itemQueryArmor += slot.item.armor;
|
||||
}
|
||||
int32_t totalArmor = (serverArmor > 0) ? serverArmor : itemQueryArmor;
|
||||
|
||||
// Base stats: 20 + level
|
||||
int32_t baseStat = 20 + static_cast<int32_t>(playerLevel);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue