# WoW Hunter Pet Defensive Inheritance ## Status Source-audited against the pinned TrinityCore TDB 335.26091 release and matching TrinityCore source commit. The generic Hunter-pet armor/Agility baseline and source-order armor helper are implemented, and both player Hunter pets and generated-companion Hunter pets now use the profile in their shared incoming-hit path. Physical armor and the five locally modeled magical resistances are applied before pet damage-taken auras and absorbs. Holy resistance remains a documented model limit. ## Selected behavior For WoW 3.3.5a Hunter pets, the selected stock-compatible core behavior is: - Add 35% of the Hunter's effective armor to the pet's own armor calculation. - The upstream core adds 40% of the Hunter's effective resistance for every non-physical school: Holy, Fire, Nature, Frost, Shadow, and Arcane. This project currently models only Arcane, Fire, Frost, Nature, and Shadow resistance; the pet's Holy resistance is kept at zero because `ItemStats` and `CharacterStats` have no Holy-resistance field. - Do not inherit physical resistance; armor handles physical mitigation separately. - Recompute the pet values when the owner's armor or school resistance changes. The source implementation uses the owner's calculated armor/resistance, not only item stats. Thus owner-side buffs and other modifiers already reflected in those values participate in the inherited portion. The pet also has its own baseline armor, Agility-derived armor, and pet aura modifiers. `wow335HunterPetInheritedDefenses` returns only the owner-derived contributions; `wow335HunterPetArmorForProfile` and `wow335HunterPetArmorForLevel` compose the complete armor value from the pet profile and those source-ordered modifiers. ## Source and precedence The primary local data did not specify owner armor or resistance inheritance. The implementation reference is the TrinityCore 3.3.5a server source at the TDB release commit [`fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a`](https://github.com/TrinityCore/TrinityCore/commit/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a). This is a server-core implementation, not Blizzard server source: - [`Guardian::UpdateArmor` and `Guardian::UpdateResistances`](https://github.com/TrinityCore/TrinityCore/blob/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a/src/server/game/Entities/Unit/StatSystem.cpp#L1344-L1376) state the 35% armor and 40% magical-resistance contributions and combine them with the pet's own values. - [`Unit::UpdateAllResistances`](https://github.com/TrinityCore/TrinityCore/blob/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a/src/server/game/Entities/Unit/StatSystem.cpp) iterates school IDs from `SPELL_SCHOOL_NORMAL` up to, but not including, `MAX_SPELL_SCHOOL`. `Guardian::UpdateResistances` skips only the physical school, so the core path includes Holy as well as the five resistance stats this project represents. The Holy formula is source-backed; supplying a nonzero owner Holy value is not possible in the current local stats contract. - [`Player::UpdateArmor` and `Player::UpdateResistances`](https://github.com/TrinityCore/TrinityCore/blob/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a/src/server/game/Entities/Unit/StatSystem.cpp#L248-L286) recalculate the active pet after the owner's effective armor or school resistance is updated. - [`Guardian::InitStatsForLevel`](https://github.com/TrinityCore/TrinityCore/blob/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a/src/server/game/Entities/Pet/Pet.cpp#L890-L924) selects `pet_levelstats` entry 1 for Hunter pets, initially seeds base armor as pet level × 50, and then uses that row's armor (when positive) and level stats. It also says Hunter pet resistance does not come from `creature_template`; pet auras and inherited resistance are the relevant inputs. - [`CalculatePct`](https://github.com/TrinityCore/TrinityCore/blob/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a/src/common/Utilities/Util.h#L62-L67) returns the percentage result in the input base type after calculating `float(base) * float(percent) / 100.0f`. Since owner armor and resistance getters return integers, the float32 result is converted back to that integer type (truncating toward zero) before being promoted into the pet's float formula. `Guardian::UpdateArmor` then passes the completed float value to `SetArmor(int32(value))`, also truncating toward zero. The isolated helper reproduces both conversions and preserves this operation order; it does not claim to model the entire core modifier system. - `Guardian::UpdateArmor` composes pet base armor × BASE_PCT, 2 × effective pet Agility, total flat pet armor, and the integer 35% owner-armor contribution, then applies TOTAL_PCT and passes the result to `SetArmor(int32(value))`. This final cast truncates toward zero. The pet's BASE_VALUE is loaded from its `pet_levelstats` armor row when positive rather than the level × 50 initializer. No WotLKDB fallback was needed for these formulas. The available WotLKDB pages are spell entries and do not define these derived pet stats. ## Local baseline-data audit The repository's existing [`wow335HunterPetRuntime.ts`](../src/game/wow335HunterPetRuntime.ts#L129-L169) profile carries level-indexed health and Strength. The verified level-indexed armor and Agility values are stored separately in [`wow335HunterPetDefenseData.ts`](../src/game/wow335HunterPetDefenseData.ts). The defense helper is consumed at the shared player/companion summon incoming-hit resolver; this avoids adding derived armor or resistance to persisted pet state. TrinityCore's source documents the fallback used only when a `pet_levelstats` row is absent: it leaves the level × 50 armor seed in place and assigns fixed Strength 22, Agility 22, Stamina 25, Intellect 28, and Spirit 27. That fallback is not evidence for the normal entry-1 row values. Using it as if it were the actual Hunter pet table would risk misrepresenting the stock baseline. ## Verified pet-level-stat data and revision A complete, pinned dataset is present in the TrinityCore [TDB 335.26091 release](https://github.com/TrinityCore/TrinityCore/releases/tag/TDB335.26091), release commit [`fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a`](https://github.com/TrinityCore/TrinityCore/commit/fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a). Its world database artifact is [`TDB_full_world_335.26091_2026_09_09.7z`](https://sourceforge.net/projects/trinitycore.mirror/files/TDB335.26091/TDB_full_world_335.26091_2026_09_09.7z/download), with published SHA-256 `ed0c50177da912b50c9f386ba8a26254cecfb997ca7fd2e992c25b344e11274f`. The downloaded archive hash matched; its inner SQL file is `TDB_full_world_335.26091_2026_09_09.sql`. The pinned TDB schema stores `creature_entry` as `int unsigned`, `level` as `tinyint unsigned`, `hp` and `mana` as `smallint unsigned`, `armor` as `int unsigned`, and the five stats plus min/max damage as `smallint unsigned`. The entry-1 rows for levels 1–80 are contiguous. Their example values are level 1: armor 20 / Agility 20; level 60: armor 3,814 / Agility 100; level 80: armor 9,784 / Agility 158. For direct integration, these arrays contain the verified armor and Agility values in level order (index 0 is level 1). They were extracted from the pinned TDB SQL after the artifact hash check: ```text # Levels 1–20 armor = [20, 21, 46, 82, 126, 180, 245, 322, 412, 518, 545, 580, 615, 650, 685, 721, 756, 791, 826, 861] agi = [20, 21, 21, 22, 23, 24, 24, 25, 26, 26, 27, 28, 30, 31, 32, 33, 34, 36, 37, 39] # Levels 21–40 armor = [897, 932, 967, 1002, 1037, 1072, 1108, 1142, 1177, 1212, 1247, 1283, 1317, 1353, 1387, 1494, 1607, 1724, 1849, 1980] agi = [39, 40, 42, 43, 45, 46, 47, 49, 50, 52, 53, 54, 56, 57, 59, 60, 61, 63, 64, 66] # Levels 41–60 armor = [2117, 2262, 2414, 2574, 2742, 2798, 2853, 2907, 2963, 3018, 3072, 3128, 3183, 3237, 3292, 3348, 3402, 3457, 3512, 3814] agi = [68, 69, 71, 72, 74, 75, 77, 79, 80, 82, 84, 85, 87, 89, 91, 92, 94, 96, 98, 100] # Levels 61–80 armor = [4113, 4410, 4708, 5006, 5303, 5601, 5900, 6197, 6495, 6794, 7093, 7392, 7691, 7990, 8289, 8588, 8887, 9186, 9485, 9784] agi = [102, 105, 107, 110, 113, 116, 119, 122, 125, 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158] ``` The AzerothCore `master` [`pet_levelstats.sql`](https://github.com/azerothcore/azerothcore-wotlk/blob/master/data/sql/base/db_world/pet_levelstats.sql) was compared with the pinned TDB SQL. Both contain exactly 80 entry-1 rows, and every one of the 12 stored values matches for each level 1–80. AzerothCore's dump schema uses `int unsigned` for the stat fields where this TDB schema uses `smallint unsigned`; the values themselves match exactly. The AzerothCore URL remains a moving branch, but it is no longer the data authority for this profile. The pinned TDB is a TrinityCore world-database release paired with the 3.3.5a server source, not a Blizzard database dump. The source/data revision is therefore exact for the selected TrinityCore baseline, while direct Blizzard-server provenance is not claimed. **Integration status: implemented for the modeled defense fields.** The pinned TDB entry-1 Agility and armor values for levels 1–80 are in [`wow335HunterPetDefenseData.ts`](../src/game/wow335HunterPetDefenseData.ts); the moving ACore export was verified as an exact 12-column match but is not treated as the revision source. `Guardian::InitStatsForLevel` assigns `creature_ID = 1` for any Hunter pet, regardless of family, so a Wolf uses these generic Hunter-pet rows rather than Wolf-specific stats. It loads row armor and Agility when present; the fake fallback branch is not used for these rows. At each incoming pet hit, the integration derives the current owner's effective armor and five native resistances, combines those values with the pet's baseline and pet-owned aura modifiers, and passes them through the shared combat resolver. The helper mirrors `CalculatePct`'s float32 calculation and integer conversion, then composes BASE_PCT, 2 × effective Agility, TOTAL_VALUE, owner armor, and TOTAL_PCT in source order before truncating the final armor like `SetArmor(int32(value))`. The source behavior remains a TrinityCore-compatible baseline, not direct proof of Blizzard server internals. ## Runtime preparation [`wow335HunterPetDefenseData.ts`](../src/game/wow335HunterPetDefenseData.ts) contains entry-1 armor and Agility arrays for levels 1–80, and [`wow335HunterPetInheritedDefenseRuntime.ts`](../src/game/wow335HunterPetInheritedDefenseRuntime.ts) provides the base-profile lookup, integer owner-inheritance calculation, and pure armor composition helper. The composition accepts current effective pet Agility and optional pet armor multipliers/flat modifiers so callers can preserve aura-derived values. Non-finite inputs are sanitized; the helper does not calculate incoming-damage mitigation. The focused tests check both coefficients and their integer conversion, the helper's six-school arithmetic, no physical-school inheritance, the entry-1 array bounds and representative rows, baseline-level clamping, source-order armor composition, negative synthetic resistance input, and invalid numeric input. Combat-store integration regressions cover physical armor and Fire resistance for both player and generated-companion Hunter pets, a player-owner armor aura, and an unchanged non-Hunter summon path. Owner defenses are re-derived at incoming-hit time, so current owner auras participate; pet Agility, armor, and resistance aura aliases are also applied before mitigation. ## Boundaries and open questions - The integration runs only for summons with a Hunter-pet profile. Other summons retain the existing incoming-damage behavior. - Holy resistance is not inherited in combat because there is no owner Holy-resistance value to read. Upstream TrinityCore's school loop would inherit 40% if such a value were present; the current simulator supplies zero and does not invent a synthetic stat. - The pet defender disables new miss, crit, dodge, parry, and block outcomes in the mitigation resolver so this change preserves the summon path's existing critical-charge, avoidance, and absorption behavior. Physical armor and modeled-school partial resistance are added to that path. - Negative owner resistance is covered as defensive input handling; TrinityCore's owner getter returns an integer resistance value and the source formula converts `CalculatePct` back to that integer type. - This profile models inherited defenses, not Stable slots, Feed Pet happiness, loyalty, pet training points, or family-specific abilities. - Keep pet critical inheritance unresolved. This armor/resistance source does not supply an owner-crit formula. - The percentages are supported by the upstream 3.3.5 server implementation. If later direct evidence from Blizzard 3.3.5a or the project's target server conflicts, revisit this source choice before claiming exact stock parity.