# Enemy NPC blocking source audit — 2026-10-05 ## Result The historical AzerothCore source supports ordinary Creature block chance, block value, aura, and eligibility without a shield or equipped-item check. Its `Unit::GetUnitBlockChance()` returns zero for Totems; otherwise it starts at 5 percentage points, adds all `SPELL_AURA_MOD_BLOCK_PERCENT` amounts, and floors the result at zero. `Creature::GetShieldBlockValue()` uses `level / 2 + uint32(Strength / 20)`. This checkout's ordinary Creature initialization never populates the Strength unit stat. `Creature::SelectLevel` reads `CreatureBaseStats` but assigns health, mana, base weapon damage, attack power, and ranged attack power only. It does not call `SetCreateStat` or `SetStat` for Strength. `Creature::UpdateStats` is a no-op. `Unit::GetStat` reads the zero-initialized `UNIT_FIELD_STAT0`, and `Object` initializes its unit-value buffer to zero. The core's `CreatureBaseStats.Strength` column is loaded but has no use in the historical server game code. For a regular, unmodified Creature in this source tree, the effective block-value formula is therefore `floor(level / 2)`. The helper keeps that source-specific zero Strength conclusion explicit instead of importing the unused class-level Strength column. The pinned Ascension and Epoch DBC rows for Improved Blocking (3419) both contain aura type 51 (`SPELL_AURA_MOD_BLOCK_PERCENT`), +75 percentage points, and a 6,000 ms duration. Applying that aura to a creature raises its base block chance from 5% to 80% for six seconds. The source spell row does not require a shield. Existing aura contracts remain the source of the profile effect value and duration. ## Eligibility in the historical core - `CREATURE_FLAG_EXTRA_NO_BLOCK` is `0x10`; it prevents block outcomes for creature templates. - A normal melee or ranged weapon attack can block only from the front. A target with an ignore-hit-direction aura bypasses that facing gate. - A target cannot block while performing a non-melee spell cast or while in `UNIT_STATE_CONTROLLED` (which includes the controlled/stunned gate). - The ordinary melee-outcome path starts with integer hundredths of a percentage point, then subtracts `4 * (attackerWeaponSkill - defenderMaxSkill)` and requires a positive remaining chance. This is 0.04 percentage points per skill point: higher attacker weapon skill lowers block chance. `GetMaxSkillValueForLevel` is effective level times five. The helper maps attacker weapon skill to attacker level times five and creature defense maximum to creature level times five. The source path does not exclude ranged weapon attacks from block outcomes. - The spell hit-table full-block phase has a distinct source gate. `SPELL_ATTR3_COMPLETELY_BLOCKED` must be set and `SPELL_ATTR0_CU_DIRECT_DAMAGE` must be absent. `ALWAYS_HIT` and `NO_ACTIVE_DEFENSE` short-circuit the block result. Behind-target, creature no-block, casting, and controlled checks still apply. A ranged damage-class spell disables dodge and parry in this path; it does not by itself disable a source-authorized block. - Direct physical melee/ranged spells have a later independent damage-block phase which can coexist with a crit and does not require `COMPLETELY_BLOCKED`. Its skill modifier has the opposite sign. The continuation imports per-rank source metadata and implements this phase; see [`NPC_SPELL_BLOCKING_2026-10-05.md`](NPC_SPELL_BLOCKING_2026-10-05.md). - `IsTotem()` tests the live UNIT_MASK_TOTEM bit on the runtime object. The Totem constructor sets this bit; it is not the same data as `CREATURE_FLAG_EXTRA_NO_BLOCK` and cannot safely be inferred from a creature template without preserving whether the actor is a runtime Totem. ## Integration data contract The isolated helper in `src/game/enemyBlocking.ts` takes only values that its caller can source or resolve at the point of the attack: - creature level (within the simulator's level-80 boundary); - active block-aura percentage-point total, including 3419 when active; - creature template `flags_extra` and the runtime `isTotem` bit; - whether the party attacker is behind the NPC, whether hit direction is ignored, and the target's active non-melee cast/controlled/evading states; - attack packet kind. This helper supports only melee and ranged auto-attacks; spell and other packets fail closed in this auto-attack helper. The separate `canEnemyNpcBlockSpell` helper handles imported source spell metadata; - attacker and creature level, mapped to weapon skill and max defense skill at level * 5 for the skill adjustment. Use the raw `blockPercent` returned by `resolveEnemyNpcBlockStats` when calling `canEnemyNpcBlock`; it applies the skill adjustment to decide whether a block can occur. Put `enemyNpcBlockChanceAfterSkill`'s result in the shared defender stats so the common resolver uses the adjusted chance exactly once. The integration maps stun/fear/confuse to the core CONTROLLED set. It also treats sleep/blind/knockdown/freeze as unable to defend under HealerMan's incapacitation model; those extra labels are a simulator approximation rather than newly verified core unit states. A plain root does not prevent blocking. Current `MobCombatState` has `level`, `serverEntry`, `activeCast`, status records, and positions, but it does not itself contain the template `flags_extra`, runtime Totem identity, or a direct "attacker is behind" result. This batch's importer now preserves `flags_extra` in `CreatureTemplateReference`; the runtime resolves it through `serverEntry` and takes actual facing from the registered transform/spatial provider. Unknown, summoned, native RoM and character defenders do not inherit this ordinary-creature baseline. Historical core can block a spell only when `SPELL_ATTR3_COMPLETELY_BLOCKED` is set and `SPELL_ATTR0_CU_DIRECT_DAMAGE` is absent; `ALWAYS_HIT`, `NO_ACTIVE_DEFENSE`, facing, template flag, cast, and controlled checks also matter. Shared player/party defenders retain their existing source-provided block stats. ## Historical source locations Read-only reference tree: `../wow-pvt-server-backups-2/azerothcore-wotlk`. | Source path | Relevant code | | --- | --- | | `src/server/game/Entities/Unit/Unit.cpp` | `RollMeleeOutcomeAgainst` checks facing, `NO_BLOCK`, cast/control state, and skill-adjusted chance (around lines 3049–3098); `MeleeSpellHitResult` derives `canBlock` from spell attributes and applies facing/flag/state/skill gates (around lines 3327–3498); `GetUnitBlockChance` implements the 5% + aura creature baseline and Totem exception (around lines 3873–3895). | | `src/server/game/Entities/Creature/Creature.h` | `Creature::GetShieldBlockValue` is `GetLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20)` (around lines 158–161). | | `src/server/game/Entities/Creature/Creature.cpp` | `Creature::SelectLevel` selects level data and initializes health, mana, weapon damage, and AP but not Strength (around lines 1497–1557). | | `src/server/game/Entities/Unit/StatSystem.cpp` | `Creature::UpdateStats` returns without changing stats (around lines 1036–1039). | | `src/server/game/Entities/Unit/Unit.h` | `GetStat` reads `UNIT_FIELD_STAT0`; `GetMaxSkillValueForLevel` returns effective level times five (around lines 1058–1059 and 1204). | | `src/server/game/Entities/Unit/Unit.cpp` | `Unit` initializes its create-stat values to zero (around line 413). | | `src/server/game/Entities/Object/Object.cpp` | Object value fields, including Unit stat fields, start zeroed (around lines 115–116). | | `src/server/game/Entities/Creature/CreatureData.h` | `CREATURE_FLAG_EXTRA_NO_BLOCK = 0x10`; `CreatureBaseStats` includes a Strength column (around lines 50 and 297–305). | | `src/server/game/Entities/Totem/Totem.cpp` | Runtime Totem construction sets `UNIT_MASK_TOTEM` (around lines 27–29). | | `src/server/game/Entities/Unit/Unit.h` | `IsTotem()` checks the live `UNIT_MASK_TOTEM` (around line 799). | The exact pinned spell signatures and hashes for 3419 in both profiles are recorded in [`STOCKADE_ENEMY_BUFFS_2026-10-05.md`](./STOCKADE_ENEMY_BUFFS_2026-10-05.md).