Files
healer-man/docs/WOW_HUNTER_PET_DEFENSE_INHERITANCE.md
2026-10-02 10:38:12 -04:00

13 KiB
Raw Permalink Blame History

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. This is a server-core implementation, not Blizzard server source:

  • Guardian::UpdateArmor and Guardian::UpdateResistances state the 35% armor and 40% magical-resistance contributions and combine them with the pet's own values.
  • Unit::UpdateAllResistances 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 recalculate the active pet after the owner's effective armor or school resistance is updated.
  • Guardian::InitStatsForLevel 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 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 profile carries level-indexed health and Strength. The verified level-indexed armor and Agility values are stored separately in 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, release commit fbd20a3cd829617a64c27cdf65ed6cfb5f304a8a. Its world database artifact is TDB_full_world_335.26091_2026_09_09.7z, 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:

# 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 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; 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<T>'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 contains entry-1 armor and Agility arrays for levels 1–80, and 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<T> 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.