From 587c0ef60da97ac6ec522f6dac9f2c68e95ae4ba Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sun, 22 Mar 2026 22:12:17 -0700 Subject: [PATCH] feat: track shapeshift form and fire UPDATE_SHAPESHIFT_FORM events MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add UNIT_FIELD_BYTES_1 to all expansion update field tables (Classic=133, TBC/WotLK=137). Byte 3 of this field contains the shapeshift form ID (Bear=1, Cat=3, Travel=4, Moonkin=31, Tree=36, Battle Stance=17, etc.). Track form changes in the VALUES update handler and fire UPDATE_SHAPESHIFT_FORM + UPDATE_SHAPESHIFT_FORMS events when the form changes. This enables stance bar addons and druid form tracking. New Lua functions: - GetShapeshiftForm() — returns current form ID (0 = no form) - GetNumShapeshiftForms() — returns form count by class (Warrior=3, Druid=6, DK=3, Rogue=1, Priest=1, Paladin=3) --- Data/expansions/classic/update_fields.json | 69 ++++++++-------- Data/expansions/tbc/update_fields.json | 67 ++++++++-------- Data/expansions/turtle/update_fields.json | 71 ++++++++--------- Data/expansions/wotlk/update_fields.json | 91 +++++++++++----------- include/game/game_handler.hpp | 3 + include/game/update_field_table.hpp | 1 + src/addons/lua_engine.cpp | 27 +++++++ src/game/game_handler.cpp | 12 +++ 8 files changed, 194 insertions(+), 147 deletions(-) diff --git a/Data/expansions/classic/update_fields.json b/Data/expansions/classic/update_fields.json index 4f340df5..4a602e91 100644 --- a/Data/expansions/classic/update_fields.json +++ b/Data/expansions/classic/update_fields.json @@ -1,48 +1,49 @@ { + "CONTAINER_FIELD_NUM_SLOTS": 48, + "CONTAINER_FIELD_SLOT_1": 50, + "GAMEOBJECT_DISPLAYID": 8, + "ITEM_FIELD_DURABILITY": 48, + "ITEM_FIELD_MAXDURABILITY": 49, + "ITEM_FIELD_STACK_COUNT": 14, "OBJECT_FIELD_ENTRY": 3, "OBJECT_FIELD_SCALE_X": 4, - "UNIT_FIELD_TARGET_LO": 16, - "UNIT_FIELD_TARGET_HI": 17, + "PLAYER_BYTES": 191, + "PLAYER_BYTES_2": 192, + "PLAYER_END": 1282, + "PLAYER_EXPLORED_ZONES_START": 1111, + "PLAYER_FIELD_BANKBAG_SLOT_1": 612, + "PLAYER_FIELD_BANK_SLOT_1": 564, + "PLAYER_FIELD_COINAGE": 1176, + "PLAYER_FIELD_INV_SLOT_HEAD": 486, + "PLAYER_FIELD_PACK_SLOT_1": 532, + "PLAYER_FLAGS": 190, + "PLAYER_NEXT_LEVEL_XP": 717, + "PLAYER_QUEST_LOG_START": 198, + "PLAYER_REST_STATE_EXPERIENCE": 1175, + "PLAYER_SKILL_INFO_START": 718, + "PLAYER_XP": 716, + "UNIT_DYNAMIC_FLAGS": 143, + "UNIT_END": 188, + "UNIT_FIELD_AURAFLAGS": 98, + "UNIT_FIELD_AURAS": 50, "UNIT_FIELD_BYTES_0": 36, - "UNIT_FIELD_HEALTH": 22, - "UNIT_FIELD_POWER1": 23, - "UNIT_FIELD_MAXHEALTH": 28, - "UNIT_FIELD_MAXPOWER1": 29, - "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_BYTES_1": 133, + "UNIT_FIELD_DISPLAYID": 131, "UNIT_FIELD_FACTIONTEMPLATE": 35, "UNIT_FIELD_FLAGS": 46, - "UNIT_FIELD_DISPLAYID": 131, + "UNIT_FIELD_HEALTH": 22, + "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_MAXHEALTH": 28, + "UNIT_FIELD_MAXPOWER1": 29, "UNIT_FIELD_MOUNTDISPLAYID": 133, - "UNIT_FIELD_AURAS": 50, - "UNIT_FIELD_AURAFLAGS": 98, - "UNIT_NPC_FLAGS": 147, - "UNIT_DYNAMIC_FLAGS": 143, + "UNIT_FIELD_POWER1": 23, "UNIT_FIELD_RESISTANCES": 154, "UNIT_FIELD_STAT0": 138, "UNIT_FIELD_STAT1": 139, "UNIT_FIELD_STAT2": 140, "UNIT_FIELD_STAT3": 141, "UNIT_FIELD_STAT4": 142, - "UNIT_END": 188, - "PLAYER_FLAGS": 190, - "PLAYER_BYTES": 191, - "PLAYER_BYTES_2": 192, - "PLAYER_XP": 716, - "PLAYER_NEXT_LEVEL_XP": 717, - "PLAYER_REST_STATE_EXPERIENCE": 1175, - "PLAYER_FIELD_COINAGE": 1176, - "PLAYER_QUEST_LOG_START": 198, - "PLAYER_FIELD_INV_SLOT_HEAD": 486, - "PLAYER_FIELD_PACK_SLOT_1": 532, - "PLAYER_FIELD_BANK_SLOT_1": 564, - "PLAYER_FIELD_BANKBAG_SLOT_1": 612, - "PLAYER_SKILL_INFO_START": 718, - "PLAYER_EXPLORED_ZONES_START": 1111, - "PLAYER_END": 1282, - "GAMEOBJECT_DISPLAYID": 8, - "ITEM_FIELD_STACK_COUNT": 14, - "ITEM_FIELD_DURABILITY": 48, - "ITEM_FIELD_MAXDURABILITY": 49, - "CONTAINER_FIELD_NUM_SLOTS": 48, - "CONTAINER_FIELD_SLOT_1": 50 + "UNIT_FIELD_TARGET_HI": 17, + "UNIT_FIELD_TARGET_LO": 16, + "UNIT_NPC_FLAGS": 147 } diff --git a/Data/expansions/tbc/update_fields.json b/Data/expansions/tbc/update_fields.json index fa443aa1..471ac235 100644 --- a/Data/expansions/tbc/update_fields.json +++ b/Data/expansions/tbc/update_fields.json @@ -1,48 +1,49 @@ { + "CONTAINER_FIELD_NUM_SLOTS": 64, + "CONTAINER_FIELD_SLOT_1": 66, + "GAMEOBJECT_DISPLAYID": 8, + "ITEM_FIELD_DURABILITY": 60, + "ITEM_FIELD_MAXDURABILITY": 61, + "ITEM_FIELD_STACK_COUNT": 14, "OBJECT_FIELD_ENTRY": 3, "OBJECT_FIELD_SCALE_X": 4, - "UNIT_FIELD_TARGET_LO": 16, - "UNIT_FIELD_TARGET_HI": 17, + "PLAYER_BYTES": 237, + "PLAYER_BYTES_2": 238, + "PLAYER_EXPLORED_ZONES_START": 1312, + "PLAYER_FIELD_ARENA_CURRENCY": 1506, + "PLAYER_FIELD_BANKBAG_SLOT_1": 784, + "PLAYER_FIELD_BANK_SLOT_1": 728, + "PLAYER_FIELD_COINAGE": 1441, + "PLAYER_FIELD_HONOR_CURRENCY": 1505, + "PLAYER_FIELD_INV_SLOT_HEAD": 650, + "PLAYER_FIELD_PACK_SLOT_1": 696, + "PLAYER_FLAGS": 236, + "PLAYER_NEXT_LEVEL_XP": 927, + "PLAYER_QUEST_LOG_START": 244, + "PLAYER_REST_STATE_EXPERIENCE": 1440, + "PLAYER_SKILL_INFO_START": 928, + "PLAYER_XP": 926, + "UNIT_DYNAMIC_FLAGS": 164, + "UNIT_END": 234, "UNIT_FIELD_BYTES_0": 36, - "UNIT_FIELD_HEALTH": 22, - "UNIT_FIELD_POWER1": 23, - "UNIT_FIELD_MAXHEALTH": 28, - "UNIT_FIELD_MAXPOWER1": 29, - "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_BYTES_1": 137, + "UNIT_FIELD_DISPLAYID": 152, "UNIT_FIELD_FACTIONTEMPLATE": 35, "UNIT_FIELD_FLAGS": 46, "UNIT_FIELD_FLAGS_2": 47, - "UNIT_FIELD_DISPLAYID": 152, + "UNIT_FIELD_HEALTH": 22, + "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_MAXHEALTH": 28, + "UNIT_FIELD_MAXPOWER1": 29, "UNIT_FIELD_MOUNTDISPLAYID": 154, - "UNIT_NPC_FLAGS": 168, - "UNIT_DYNAMIC_FLAGS": 164, + "UNIT_FIELD_POWER1": 23, "UNIT_FIELD_RESISTANCES": 185, "UNIT_FIELD_STAT0": 159, "UNIT_FIELD_STAT1": 160, "UNIT_FIELD_STAT2": 161, "UNIT_FIELD_STAT3": 162, "UNIT_FIELD_STAT4": 163, - "UNIT_END": 234, - "PLAYER_FLAGS": 236, - "PLAYER_BYTES": 237, - "PLAYER_BYTES_2": 238, - "PLAYER_XP": 926, - "PLAYER_NEXT_LEVEL_XP": 927, - "PLAYER_REST_STATE_EXPERIENCE": 1440, - "PLAYER_FIELD_COINAGE": 1441, - "PLAYER_QUEST_LOG_START": 244, - "PLAYER_FIELD_INV_SLOT_HEAD": 650, - "PLAYER_FIELD_PACK_SLOT_1": 696, - "PLAYER_FIELD_BANK_SLOT_1": 728, - "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, - "ITEM_FIELD_MAXDURABILITY": 61, - "CONTAINER_FIELD_NUM_SLOTS": 64, - "CONTAINER_FIELD_SLOT_1": 66 + "UNIT_FIELD_TARGET_HI": 17, + "UNIT_FIELD_TARGET_LO": 16, + "UNIT_NPC_FLAGS": 168 } diff --git a/Data/expansions/turtle/update_fields.json b/Data/expansions/turtle/update_fields.json index a27e84f7..4a602e91 100644 --- a/Data/expansions/turtle/update_fields.json +++ b/Data/expansions/turtle/update_fields.json @@ -1,48 +1,49 @@ { + "CONTAINER_FIELD_NUM_SLOTS": 48, + "CONTAINER_FIELD_SLOT_1": 50, + "GAMEOBJECT_DISPLAYID": 8, + "ITEM_FIELD_DURABILITY": 48, + "ITEM_FIELD_MAXDURABILITY": 49, + "ITEM_FIELD_STACK_COUNT": 14, "OBJECT_FIELD_ENTRY": 3, "OBJECT_FIELD_SCALE_X": 4, - "UNIT_FIELD_TARGET_LO": 16, - "UNIT_FIELD_TARGET_HI": 17, + "PLAYER_BYTES": 191, + "PLAYER_BYTES_2": 192, + "PLAYER_END": 1282, + "PLAYER_EXPLORED_ZONES_START": 1111, + "PLAYER_FIELD_BANKBAG_SLOT_1": 612, + "PLAYER_FIELD_BANK_SLOT_1": 564, + "PLAYER_FIELD_COINAGE": 1176, + "PLAYER_FIELD_INV_SLOT_HEAD": 486, + "PLAYER_FIELD_PACK_SLOT_1": 532, + "PLAYER_FLAGS": 190, + "PLAYER_NEXT_LEVEL_XP": 717, + "PLAYER_QUEST_LOG_START": 198, + "PLAYER_REST_STATE_EXPERIENCE": 1175, + "PLAYER_SKILL_INFO_START": 718, + "PLAYER_XP": 716, + "UNIT_DYNAMIC_FLAGS": 143, + "UNIT_END": 188, + "UNIT_FIELD_AURAFLAGS": 98, + "UNIT_FIELD_AURAS": 50, "UNIT_FIELD_BYTES_0": 36, - "UNIT_FIELD_HEALTH": 22, - "UNIT_FIELD_POWER1": 23, - "UNIT_FIELD_MAXHEALTH": 28, - "UNIT_FIELD_MAXPOWER1": 29, - "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_BYTES_1": 133, + "UNIT_FIELD_DISPLAYID": 131, "UNIT_FIELD_FACTIONTEMPLATE": 35, "UNIT_FIELD_FLAGS": 46, - "UNIT_FIELD_DISPLAYID": 131, + "UNIT_FIELD_HEALTH": 22, + "UNIT_FIELD_LEVEL": 34, + "UNIT_FIELD_MAXHEALTH": 28, + "UNIT_FIELD_MAXPOWER1": 29, "UNIT_FIELD_MOUNTDISPLAYID": 133, - "UNIT_FIELD_AURAS": 50, - "UNIT_FIELD_AURAFLAGS": 98, - "UNIT_NPC_FLAGS": 147, - "UNIT_DYNAMIC_FLAGS": 143, + "UNIT_FIELD_POWER1": 23, "UNIT_FIELD_RESISTANCES": 154, "UNIT_FIELD_STAT0": 138, "UNIT_FIELD_STAT1": 139, "UNIT_FIELD_STAT2": 140, "UNIT_FIELD_STAT3": 141, "UNIT_FIELD_STAT4": 142, - "UNIT_END": 188, - "PLAYER_FLAGS": 190, - "PLAYER_BYTES": 191, - "PLAYER_BYTES_2": 192, - "PLAYER_XP": 716, - "PLAYER_NEXT_LEVEL_XP": 717, - "PLAYER_REST_STATE_EXPERIENCE": 1175, - "PLAYER_FIELD_COINAGE": 1176, - "PLAYER_QUEST_LOG_START": 198, - "PLAYER_FIELD_INV_SLOT_HEAD": 486, - "PLAYER_FIELD_PACK_SLOT_1": 532, - "PLAYER_FIELD_BANK_SLOT_1": 564, - "PLAYER_FIELD_BANKBAG_SLOT_1": 612, - "PLAYER_SKILL_INFO_START": 718, - "PLAYER_EXPLORED_ZONES_START": 1111, - "PLAYER_END": 1282, - "GAMEOBJECT_DISPLAYID": 8, - "ITEM_FIELD_STACK_COUNT": 14, - "ITEM_FIELD_DURABILITY": 48, - "ITEM_FIELD_MAXDURABILITY": 49, - "CONTAINER_FIELD_NUM_SLOTS": 48, - "CONTAINER_FIELD_SLOT_1": 50 -} \ No newline at end of file + "UNIT_FIELD_TARGET_HI": 17, + "UNIT_FIELD_TARGET_LO": 16, + "UNIT_NPC_FLAGS": 147 +} diff --git a/Data/expansions/wotlk/update_fields.json b/Data/expansions/wotlk/update_fields.json index 7b5e12e8..06bcbd62 100644 --- a/Data/expansions/wotlk/update_fields.json +++ b/Data/expansions/wotlk/update_fields.json @@ -1,60 +1,61 @@ { + "CONTAINER_FIELD_NUM_SLOTS": 64, + "CONTAINER_FIELD_SLOT_1": 66, + "GAMEOBJECT_DISPLAYID": 8, + "ITEM_FIELD_DURABILITY": 60, + "ITEM_FIELD_MAXDURABILITY": 61, + "ITEM_FIELD_STACK_COUNT": 14, "OBJECT_FIELD_ENTRY": 3, "OBJECT_FIELD_SCALE_X": 4, - "UNIT_FIELD_TARGET_LO": 6, - "UNIT_FIELD_TARGET_HI": 7, + "PLAYER_BLOCK_PERCENTAGE": 1024, + "PLAYER_BYTES": 153, + "PLAYER_BYTES_2": 154, + "PLAYER_CHOSEN_TITLE": 1349, + "PLAYER_CRIT_PERCENTAGE": 1029, + "PLAYER_DODGE_PERCENTAGE": 1025, + "PLAYER_EXPLORED_ZONES_START": 1041, + "PLAYER_FIELD_ARENA_CURRENCY": 1423, + "PLAYER_FIELD_BANKBAG_SLOT_1": 458, + "PLAYER_FIELD_BANK_SLOT_1": 402, + "PLAYER_FIELD_COINAGE": 1170, + "PLAYER_FIELD_COMBAT_RATING_1": 1231, + "PLAYER_FIELD_HONOR_CURRENCY": 1422, + "PLAYER_FIELD_INV_SLOT_HEAD": 324, + "PLAYER_FIELD_MOD_DAMAGE_DONE_POS": 1171, + "PLAYER_FIELD_MOD_HEALING_DONE_POS": 1192, + "PLAYER_FIELD_PACK_SLOT_1": 370, + "PLAYER_FLAGS": 150, + "PLAYER_NEXT_LEVEL_XP": 635, + "PLAYER_PARRY_PERCENTAGE": 1026, + "PLAYER_QUEST_LOG_START": 158, + "PLAYER_RANGED_CRIT_PERCENTAGE": 1030, + "PLAYER_REST_STATE_EXPERIENCE": 1169, + "PLAYER_SKILL_INFO_START": 636, + "PLAYER_SPELL_CRIT_PERCENTAGE1": 1032, + "PLAYER_XP": 634, + "UNIT_DYNAMIC_FLAGS": 147, + "UNIT_END": 148, + "UNIT_FIELD_ATTACK_POWER": 123, "UNIT_FIELD_BYTES_0": 23, - "UNIT_FIELD_HEALTH": 24, - "UNIT_FIELD_POWER1": 25, - "UNIT_FIELD_MAXHEALTH": 32, - "UNIT_FIELD_MAXPOWER1": 33, - "UNIT_FIELD_LEVEL": 54, + "UNIT_FIELD_BYTES_1": 137, + "UNIT_FIELD_DISPLAYID": 67, "UNIT_FIELD_FACTIONTEMPLATE": 55, "UNIT_FIELD_FLAGS": 59, "UNIT_FIELD_FLAGS_2": 60, - "UNIT_FIELD_DISPLAYID": 67, + "UNIT_FIELD_HEALTH": 24, + "UNIT_FIELD_LEVEL": 54, + "UNIT_FIELD_MAXHEALTH": 32, + "UNIT_FIELD_MAXPOWER1": 33, "UNIT_FIELD_MOUNTDISPLAYID": 69, - "UNIT_NPC_FLAGS": 82, - "UNIT_DYNAMIC_FLAGS": 147, + "UNIT_FIELD_POWER1": 25, + "UNIT_FIELD_RANGED_ATTACK_POWER": 126, "UNIT_FIELD_RESISTANCES": 99, "UNIT_FIELD_STAT0": 84, "UNIT_FIELD_STAT1": 85, "UNIT_FIELD_STAT2": 86, "UNIT_FIELD_STAT3": 87, "UNIT_FIELD_STAT4": 88, - "UNIT_END": 148, - "UNIT_FIELD_ATTACK_POWER": 123, - "UNIT_FIELD_RANGED_ATTACK_POWER": 126, - "PLAYER_FLAGS": 150, - "PLAYER_BYTES": 153, - "PLAYER_BYTES_2": 154, - "PLAYER_XP": 634, - "PLAYER_NEXT_LEVEL_XP": 635, - "PLAYER_REST_STATE_EXPERIENCE": 1169, - "PLAYER_FIELD_COINAGE": 1170, - "PLAYER_QUEST_LOG_START": 158, - "PLAYER_FIELD_INV_SLOT_HEAD": 324, - "PLAYER_FIELD_PACK_SLOT_1": 370, - "PLAYER_FIELD_BANK_SLOT_1": 402, - "PLAYER_FIELD_BANKBAG_SLOT_1": 458, - "PLAYER_SKILL_INFO_START": 636, - "PLAYER_EXPLORED_ZONES_START": 1041, - "PLAYER_CHOSEN_TITLE": 1349, - "PLAYER_FIELD_MOD_DAMAGE_DONE_POS": 1171, - "PLAYER_FIELD_MOD_HEALING_DONE_POS": 1192, - "PLAYER_BLOCK_PERCENTAGE": 1024, - "PLAYER_DODGE_PERCENTAGE": 1025, - "PLAYER_PARRY_PERCENTAGE": 1026, - "PLAYER_CRIT_PERCENTAGE": 1029, - "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, - "ITEM_FIELD_MAXDURABILITY": 61, - "CONTAINER_FIELD_NUM_SLOTS": 64, - "CONTAINER_FIELD_SLOT_1": 66 + "UNIT_FIELD_TARGET_HI": 7, + "UNIT_FIELD_TARGET_LO": 6, + "UNIT_NPC_FLAGS": 82 } diff --git a/include/game/game_handler.hpp b/include/game/game_handler.hpp index 523c6561..355b87e6 100644 --- a/include/game/game_handler.hpp +++ b/include/game/game_handler.hpp @@ -1722,6 +1722,7 @@ public: // Combo points uint8_t getComboPoints() const { return comboPoints_; } + uint8_t getShapeshiftFormId() const { return shapeshiftFormId_; } uint64_t getComboTarget() const { return comboTarget_; } // Death Knight rune state (6 runes: 0-1=Blood, 2-3=Unholy, 4-5=Frost; may become Death=3) @@ -2995,6 +2996,8 @@ private: // Mirror timers (0=fatigue, 1=breath, 2=feigndeath) MirrorTimer mirrorTimers_[3]; + // Shapeshift form (from UNIT_FIELD_BYTES_1 byte 3) + uint8_t shapeshiftFormId_ = 0; // Combo points (rogues/druids) uint8_t comboPoints_ = 0; uint64_t comboTarget_ = 0; diff --git a/include/game/update_field_table.hpp b/include/game/update_field_table.hpp index 4cc2a44a..d48065e4 100644 --- a/include/game/update_field_table.hpp +++ b/include/game/update_field_table.hpp @@ -20,6 +20,7 @@ enum class UF : uint16_t { UNIT_FIELD_TARGET_LO, UNIT_FIELD_TARGET_HI, UNIT_FIELD_BYTES_0, + UNIT_FIELD_BYTES_1, // byte3 = shapeshift form ID UNIT_FIELD_HEALTH, UNIT_FIELD_POWER1, UNIT_FIELD_MAXHEALTH, diff --git a/src/addons/lua_engine.cpp b/src/addons/lua_engine.cpp index 99fe2a18..44565116 100644 --- a/src/addons/lua_engine.cpp +++ b/src/addons/lua_engine.cpp @@ -5013,6 +5013,33 @@ void LuaEngine::registerCoreAPI() { {"IsInRaid", lua_IsInRaid}, {"GetPlayerMapPosition", lua_GetPlayerMapPosition}, {"GetPlayerFacing", lua_GetPlayerFacing}, + {"GetShapeshiftForm", [](lua_State* L) -> int { + auto* gh = getGameHandler(L); + lua_pushnumber(L, gh ? gh->getShapeshiftFormId() : 0); + return 1; + }}, + {"GetNumShapeshiftForms", [](lua_State* L) -> int { + // Return count based on player class + auto* gh = getGameHandler(L); + if (!gh) { lua_pushnumber(L, 0); return 1; } + uint8_t classId = gh->getPlayerClass(); + // Druid: Bear(1), Aquatic(2), Cat(3), Travel(4), Moonkin/Tree(5/6) + // Warrior: Battle(1), Defensive(2), Berserker(3) + // Rogue: Stealth(1) + // Priest: Shadowform(1) + // Paladin: varies by level/talents + // DK: Blood Presence, Frost, Unholy (3) + switch (classId) { + case 1: lua_pushnumber(L, 3); break; // Warrior + case 2: lua_pushnumber(L, 3); break; // Paladin (auras) + case 4: lua_pushnumber(L, 1); break; // Rogue + case 5: lua_pushnumber(L, 1); break; // Priest + case 6: lua_pushnumber(L, 3); break; // Death Knight + case 11: lua_pushnumber(L, 6); break; // Druid + default: lua_pushnumber(L, 0); break; + } + return 1; + }}, {"GetMaxPlayerLevel", [](lua_State* L) -> int { auto* reg = core::Application::getInstance().getExpansionRegistry(); auto* prof = reg ? reg->getActive() : nullptr; diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index e38dbfab..06c959bb 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -12500,6 +12500,7 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem const uint16_t ufMountDisplayId = fieldIndex(UF::UNIT_FIELD_MOUNTDISPLAYID); const uint16_t ufNpcFlags = fieldIndex(UF::UNIT_NPC_FLAGS); const uint16_t ufBytes0 = fieldIndex(UF::UNIT_FIELD_BYTES_0); + const uint16_t ufBytes1 = fieldIndex(UF::UNIT_FIELD_BYTES_1); for (const auto& [key, val] : block.fields) { if (key == ufHealth) { uint32_t oldHealth = unit->getHealth(); @@ -12569,6 +12570,17 @@ void GameHandler::applyUpdateObjectBlock(const UpdateBlock& block, bool& newItem addonEventCallback_("UNIT_DISPLAYPOWER", {uid}); } } else if (key == ufFlags) { unit->setUnitFlags(val); } + else if (ufBytes1 != 0xFFFF && key == ufBytes1 && block.guid == playerGuid) { + uint8_t newForm = static_cast((val >> 24) & 0xFF); + if (newForm != shapeshiftFormId_) { + shapeshiftFormId_ = newForm; + LOG_INFO("Shapeshift form changed: ", (int)newForm); + if (addonEventCallback_) { + addonEventCallback_("UPDATE_SHAPESHIFT_FORM", {}); + addonEventCallback_("UPDATE_SHAPESHIFT_FORMS", {}); + } + } + } else if (key == ufDynFlags) { uint32_t oldDyn = unit->getDynamicFlags(); unit->setDynamicFlags(val);