110 lines
6.3 KiB
Markdown
110 lines
6.3 KiB
Markdown
# Stockade Rend periodic damage source audit — 2026-10-05
|
||
|
||
This adds a source-backed timing and amount descriptor for Stockade Rend spells
|
||
6547 and 16509. The active Stockade catalog uses the Ascension patch-D profile;
|
||
the distinct Epoch profile is retained in the helper so imports cannot silently
|
||
reuse the wrong 6547 amount.
|
||
|
||
## Spell rows
|
||
|
||
| Profile | Spell | Stockade users | Duration | Tick interval/count | BasePoints / DieSides | Raw tick before core scaling | Creature-level scaling |
|
||
| --- | ---: | --- | ---: | ---: | ---: | ---: | --- |
|
||
| Ascension patch-D | 6547 | Defias Inmate (1708) | 15 s | 3 s / 5 | 13 / 1 | 14 | No |
|
||
| Ascension patch-D | 16509 | Captive (1707), Prisoner (1706), Convict (1711) | 15 s | 3 s / 5 | 26 / 1 | 27 | Yes |
|
||
| Epoch client | 6547 | Separate Epoch profile | 15 s | 3 s / 5 | 9 / 1 | 10 | No |
|
||
| Epoch client | 16509 | Separate Epoch profile | 15 s | 3 s / 5 | 26 / 1 | 27 | Yes |
|
||
|
||
Each row has effect 6 (`APPLY_AURA`) with aura 3 (`PERIODIC_DAMAGE`), effect
|
||
mechanic 15 (`BLEED`), implicit target A 6 and no secondary target. The shared
|
||
SpellDuration row 8 is `[8, 15000, 0, 15000]`; the Spell.dbc rows use duration
|
||
index 8 and period 3000 ms. School mask 1 is physical, damage class 2 is melee,
|
||
and Spell.dbc `StackAmount` is 0 (one active stack).
|
||
|
||
`EffectRealPointsPerLevel` is 0 on all four rows. `BasePoints` is stored one
|
||
below its effective value; AzerothCore `SpellEffectInfo::CalcValue` adds the
|
||
1..DieSides roll, so DieSides 1 yields the raw amounts above. These are inputs
|
||
before core damage modifiers. Spell 16509 also carries
|
||
`SPELL_ATTR0_SCALES_WITH_CREATURE_LEVEL` in both DBC profiles, with
|
||
`BaseLevel=SpellLevel=20` and `MaxLevel=0`. For a non-player caster whose level
|
||
differs from 20, the referenced core scales that raw amount by
|
||
`CreatureBaseStats.BaseDamage[caster level][creature expansion] /
|
||
CreatureBaseStats.BaseDamage[spell level 20][creature expansion]`, then truncates
|
||
to `int32`. Spell 6547 has no such attribute. No `spell_bonus_data` row exists
|
||
for either spell in the inspected core SQL snapshot.
|
||
|
||
The new helper resolves that 16509 ratio only when both exact class-level rows
|
||
and the creature template are present. It reads `BaseDamage` directly; it does
|
||
not fold in `CreatureTemplate.damageModifier`, attack power, weapon variance,
|
||
or swing time. A missing template or stats row returns an explicit unsupported
|
||
result; the source-tagged runtime fails closed instead of inventing a scale.
|
||
Caster damage-done modifiers are snapshotted at aura application. Target
|
||
damage-taken modifiers remain dynamic at each pulse.
|
||
|
||
## Runtime contract
|
||
|
||
The source effect is periodic-only, so a cast must not create an immediate
|
||
direct-damage packet. For a fresh aura, schedule the first pulse after 3000 ms
|
||
and the fifth pulse at 15000 ms. Same-caster recasts keep at most one stack and
|
||
refresh the duration and tick count. An ordinary recast restarts the tick phase,
|
||
so its next pulse is three seconds later. The core preserves the old phase only
|
||
for casts marked `TRIGGERED_NO_PERIODIC_RESET`. Separate casters may retain
|
||
independent bleed auras on the same target.
|
||
|
||
Core applies DOT done/taken modifiers, then checks armor. Its
|
||
`Unit::IsDamageReducedByArmor` explicitly exempts periodic effects whose
|
||
mechanic mask includes `BLEED`; therefore the runtime needs an armor-only bypass
|
||
for these pulses. Do not use `targetMitigationSnapshotted` for this purpose,
|
||
because that also skips resistance. The attack remains physical/melee typed for
|
||
the sourced cast and hit table; the periodic pulses use the existing common
|
||
periodic damage resolution.
|
||
|
||
The generated catalog currently has authored attack `damageMultiplier` values
|
||
for the Rend cast rows. Those are not DBC periodic tick amounts. Keep any
|
||
source-level cast scalar separate from the periodic amount. The game may still
|
||
apply its outer entity `mob.damageMultiplier` after resolving the source tick.
|
||
|
||
## Integration points
|
||
|
||
- `src/game/enemyPeriodicDamage.ts` provides the exact Ascension patch-D and
|
||
Epoch source profiles, five-tick schedule helper, armor and stack metadata,
|
||
and NPC core scaling calculation for 6547/16509.
|
||
- `src/game/azerothCoreReference.ts` exposes the pinned template/class-level
|
||
`BaseDamage` input with no template multiplier. The strict helper rejects
|
||
levels outside 1–80, missing templates, invalid expansion indices, and absent
|
||
class-level rows.
|
||
- The campaign compiler/runtime adapter should select `ascension-patch-d` for
|
||
the active Stockade catalog and preserve the `epoch-client` variant only for
|
||
Epoch imports. Serialize the source identity (`spellId` plus profile) and let
|
||
runtime resolve it through this helper. Emit no direct damage effect; carry
|
||
`periodicIgnoresArmor` to tick resolution. If 16509 lacks a source template or
|
||
class-level base-damage row, omit that source effect instead of inventing
|
||
a ratio or substituting the old attack scalar.
|
||
|
||
The runtime integration tests cover player and party NPC defenders in both
|
||
WoW-compatible and native RoM stat modes, the application hit gate, five full
|
||
pulses, armor bypass, refresh, independent casters and magic-dispel exclusion.
|
||
The fourteen integration checks also verify caster bonus expiry/gain after
|
||
application and changing target-side damage-taken modifiers. Nine pure source
|
||
contract/amount checks pass separately.
|
||
|
||
## Source pins
|
||
|
||
The Ascension Spell.dbc is
|
||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
|
||
SHA-256 `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
|
||
The Epoch Spell.dbc is
|
||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
|
||
SHA-256 `D5CCE1A83550DCFA9EB2F0251DBB11FD24C272534B2B1A9B230924A44D817AB3`.
|
||
Neither profile has a sibling SpellDuration.dbc; both use the established
|
||
patch-S duration fallback, SHA-256
|
||
`EEAE44EF0185924F3D6EC57AB2701C66566DB86E51AB0BAE017A9449126EB3A0`.
|
||
|
||
Core behavior was checked in the read-only historical AzerothCore reference:
|
||
`src/server/game/Spells/SpellInfo.cpp` (`SpellEffectInfo::CalcValue`),
|
||
`src/server/game/Spells/Spell.cpp` (the ordinary-cast periodic-reset flag),
|
||
`src/server/game/Spells/Auras/SpellAuraEffects.cpp` (periodic setup, ticks, and
|
||
damage mitigation), `src/server/game/Spells/Auras/SpellAuras.cpp` (refresh and
|
||
stack behavior), and `src/server/game/Entities/Unit/Unit.cpp`
|
||
(`_TryStackingOrRefreshingExistingAura` and `IsDamageReducedByArmor`). These
|
||
files are source references, not HealerMan runtime dependencies.
|