8.0 KiB
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_BLOCKis0x10; 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.GetMaxSkillValueForLevelis 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_BLOCKEDmust be set andSPELL_ATTR0_CU_DIRECT_DAMAGEmust be absent.ALWAYS_HITandNO_ACTIVE_DEFENSEshort-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; seeNPC_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 asCREATURE_FLAG_EXTRA_NO_BLOCKand 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_extraand the runtimeisTotembit; - 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
canEnemyNpcBlockSpellhelper 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.