Files
healer-man/docs/UTILITY_SPELL_BLOCKING_2026-10-06.md
2026-10-06 22:25:34 -04:00

77 lines
4.4 KiB
Markdown

# Utility spell full-hit blocking — 2026-10-06
## Supported source contract
`src/game/enemyUtilitySpellBlocking.ts` records one complete utility-spell
contract: WoW 3.3.5a Shield Bash, selected spell/rank 72. The local generated
class data has this rank as a physical melee spell with `attributes0=327696`
and `attributes3=8` (`COMPLETELY_BLOCKED`). Its two present Spell.dbc effects
are effect 68 (mechanic 26, hostile target) and effect 64 (hostile target,
triggering spell 29703). Neither is a direct-damage effect in the pinned
AzerothCore `SpellMgr` list. The source helper supplies only the two known
blocking-relevant `AttributesCu` bits and records both as clear; it does not
invent the remainder of that custom word.
The contract requires the selected spell ID and source profile to be exactly
`72` and `wow335`, plus the same DBC defense scalars and a classified
`hit-table` phase. Other Shield Bash ranks, Ascension/Epoch rows, missing
metadata, or different signatures use the caller's current fallback. No
generic inference is made from `COMPLETELY_BLOCKED` alone.
## Runtime disposition contract
`enemyUtilitySpellBlockDisposition` consumes a hit result already resolved by
the caller. It only handles player or party casts against an ordinary enemy
NPC. A resolved `block` suppresses the whole cast-recipient utility effect
list, including interrupt and triggered aura/debuff effects. `miss`, `dodge`,
`parry`, or `resist` also suppress application for this exact hit-table spell;
`hit` or `crit` allows its utility effects. Missing/unresolved outcomes and
unsupported sources return `fallback`, preserving the caller's existing
behavior.
The hit-table path is enabled by melee/ranged damage class, physical school,
the `COMPLETELY_BLOCKED` attribute, and explicit evidence that
`CU_DIRECT_DAMAGE` is absent. `NO_ACTIVE_DEFENSE` and `ALWAYS_HIT` override
blocking. Facing, active non-melee cast, controlled state, no-block template
flag, totem, and skill-adjusted positive chance remain the resolver's gates;
this helper does not roll or bypass them. Shield Bash's source evidence also
shows `CU_REQ_CASTER_BEHIND_TARGET` clear for its aura-facing exception.
The helper is intended for the existing player/party outbound-to-ordinary-NPC
utility writers. NPC outbound casts into player/party targets need the
character defender's separate block model and do not consume this contract.
Native RoM casters/targets, character defenders, summoned actors, and unknown
targets stay on their existing paths. The helper contains no shared runtime
types and does not mutate combat state.
The shared player cast writer and companion `executePartyAbility` resolve one
source-bound block result before their utility effect loops. A full block
skips the entire recipient effect list while retaining the accepted cast's
resource cost and cooldown. Telemetry records a zero-amount `cast` result with
the block flag; it emits no fake damage packet. This bounded runtime stage
rolls block only and preserves existing other utility hit/avoidance behavior.
The helper's avoided-outcome disposition is available for a future sourced
full hit table, but this pass does not add miss/dodge/parry/resist rolls.
## Validation
`src/game/enemyUtilitySpellBlocking.test.ts` covers the exact signature,
block-before-utility suppression, hit-table misses/dodges/parries/resists,
missing rank/source/profile/signature and native/target exclusions. Runtime
integration, including the active-cast gate and an unblocked interrupt, belongs
to the `combatStore.ts` and `partyRuntime.ts` caller changes.
The final `enemyUtilitySpellBlocking.integration.test.ts` passes four tests:
an actual player cast blocks once and retains cost/cooldown; an actively
casting NPC cannot block and receives the six-second interrupted-school
lockout; a synthetic accepted pending companion cast completes through the
real companion executor and blocks; unbound metadata/ranks and native,
summoned, character and unknown source defenders stay excluded. The player's
utility result and existing completed-cast event are separate telemetry;
the block result is not a second completed cast or a damage packet.
The actual parent catalog retains its trigger 29703, but
`triggeredAbilityBySpellId(29703)` is currently null. This pass suppresses
trigger execution under a full block; it does not implement or certify an
imported/live Daze child. That child import remains a separate catalog gap.