Update Healer Man server
This commit is contained in:
1 parent
6114a2295f
commit
69809f7228
593 files changed
+903643
-40774
No files matched your search
@@ -1,8 +1,8 @@
|
||||
# Active Class Mechanics Backlog
|
||||
|
||||
Updated 2026-10-04. This document lists unresolved ability and talent mechanics for all ten WoW 3.3.5a classes and all ten RuneWaker primary classes. It excludes completed fixes and all visual or sound review. Some items need source confirmation or simulator support before they can be implemented; do not guess missing values. For RoM conflicts, prefer clearly matching current Chronicles of Arcadia behavior over the RuneWaker snapshot; verify skill identity and class pairing, and document the source and any simulator approximation. See [the full audit](ACTIVE_CLASS_AUDIT.md) for the supporting findings and source conflicts.
|
||||
Updated 2026-10-06. This document lists unresolved ability and talent mechanics for all ten WoW 3.3.5a classes and all ten RuneWaker primary classes. It excludes completed fixes and all visual or sound review. Some items need source confirmation or simulator support before they can be implemented; do not guess missing values. For RoM conflicts, prefer clearly matching current Chronicles of Arcadia behavior over the RuneWaker snapshot; verify skill identity and class pairing, and document the source and any simulator approximation. See [the full audit](ACTIVE_CLASS_AUDIT.md) for the supporting findings and source conflicts.
|
||||
|
||||
New routine mechanic/browser diagnostics use **Stormwind Stockade** (`stormwind-stockade`), including Hamhock for generic Boss Testing. Import `scripts/playtest-defaults.cjs` and follow [the test policy](TEST_DUNGEON_POLICY.md); historical Wailing findings below do not select future tests.
|
||||
New routine mechanic/browser diagnostics use **Stormwind Stockade: Cellblock Rush** (`bite-sized-stormwind-stockade`). Each run selects one of the five Stockade bosses from its shared run ID, so record the boss actually observed. Import `scripts/playtest-defaults.cjs` and follow [the test policy](TEST_DUNGEON_POLICY.md); full Stockade campaigns require explicit selection. Isolated Boss Testing remains a separate mode that defaults to Hamhock. Historical Wailing findings below do not select future tests.
|
||||
|
||||
## Targeted follow-up (2026-10-04)
|
||||
|
||||
@@ -13,11 +13,28 @@ New routine mechanic/browser diagnostics use **Stormwind Stockade** (`stormwind-
|
||||
- [x] Implement shared timed player/companion Killing Spree: five assaults at application and 500-ms intervals through two seconds, retained cast-time target pools, owner-local cleanup, linked +20% final-pulse ordering, actual player/NPC relocation, and learned companion AI selection. Seeded target selection, estimated weapon-child damage/teleport coordinates and unverified active-control semantics remain simulator limits. See [the parity report](WOW_KILLING_SPREE_PARITY_2026-10-04.md). This Combat Rogue diagnostic does not expand Ready-five.
|
||||
- [x] Audit the five active native RoM identities and correct Knight/Scout Blood Punishment to current CoA's +15% healing received and +5% Holy damage on the actual Blood Arrow aura. Correct companion RoM direct-hit school selection and no-roll outgoing damage-aura consumption; native and compatibility NPC casts are covered separately. See [the five-class report](ROM_FIVE_MECHANIC_GAPS_2026-10-04.md).
|
||||
- [x] Reconcile Blood Arrow for the verified Scout/Rogue and Knight/Scout owners: indefinite owner-local toggle, recast/right-click cancellation, 10-second cooldown after deactivation, and no legacy idle drain. Knight/Scout offensive ranged-weapon skills charge 2% max HP plus 1% max MP; Scout/Rogue damaging ranged skills and owned NPC ranged auto swings charge 2% max HP without the MP surcharge. Base definitions and resolved ranks are scoped to those pairs; unverified owners retain the RuneWaker behavior. See [the implementation report](ROM_BLOOD_ARROW_TOGGLE_2026-10-04.md).
|
||||
- [ ] Add the missing recurring player RoM ranged auto-attack/Auto Shot path before claiming full Scout/Rogue Blood Arrow auto-attack parity. Player ordinary auto attacks currently use the melee path; activating Auto Shot is not a recurring shot event. Source the cap-80 ranged-damage curve separately; the retained local 10% aura is not a verified current CoA rank curve.
|
||||
- [ ] Correct native-five damage-role companion selection so the player's active pairing is excluded when the remaining active identities can fill the seats. The targeted Stockade Scout/Rogue fixture generated another Scout/Rogue and omitted Mage/Warlock; Knight/Scout's tank-role fixture had the exact complement. See [the live evidence](ROM_BLOOD_ARROW_STOCKADE_PLAYTEST_2026-10-04.md). This finding does not promote other RoM builds or expand the companion pool.
|
||||
- [ ] Propagate Group Heal's sourced area radius to its party-heal effect for both player and NPC recipients. `romAbilityCatalog.ts` derives ability radius 12, but its party heal effect omits radius and `healingRecipientIds` defaults to 30. The final Stockade tank death is a separate timing case: Group Heal resolves 701 ms after the inferred lethal hit. Damage arithmetic implies zero HP when the living-recipient filter would exclude him; the casualty is observed later without a recipient-selection event. This does not prove a range/LOS rejection. Preserve other spells' explicit recipient contracts and add boundary coverage before changing the shared fallback. See [the final continuation evidence](STOCKADE_MECHANICS_CONTINUATION_2026-10-04.md).
|
||||
- [x] Implement recurring Scout/Rogue player Auto Shot through the learned primary skill: ranged Physical events, supported native weapon DPS/cadence, automatic Training Gear and compatible custom-item fallback, native/compatibility haste, owner-local Blood Arrow HP cost, stop/retarget/reset/death cleanup and no simultaneous melee swings. Thirteen focused checks pass; see [the implementation report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md) and [the coordinated follow-up](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md).
|
||||
- [ ] Source Auto Shot's contribution from the last offensive skill before implementing it. Current CoA specifies only an unspecified portion, without a coefficient. The implemented player mode uses the sourced 80% ranged weapon DPS term; local range and runtime constraints are documented in [the implementation report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md).
|
||||
- [ ] Establish Blood Arrow's current damage formula through rank 80 before replacing the local 10% aura. Current exact Scout/Rogue and Knight/Scout pages publish only +104.5% at maximum skill rank 105; the historical local component supplies one +10% value. Neither establishes a cap-80 curve. See [the source audit](ROM_BLOOD_ARROW_SCALING_2026-10-04.md).
|
||||
- [x] Correct native-five companion selection to exclude the player's active pairing when the remaining identities can fill all requested role seats. Entry and avatar preloading now pass the exact pair; all five supported player complements and fallbacks pass focused coverage. See [the selection report](ROM_NATIVE_PARTY_SELECTION_2026-10-04.md). The prior Scout/Rogue duplicate is historical evidence; readiness and the native pool remain unchanged.
|
||||
- [x] Propagate Group Heal's sourced 12 m radius to its party-heal effect for player and NPC execution. Focused tests cover the inclusive 12 m boundary, exclusion at 12.01 m, living/LOS rules and both actual cast paths while preserving Soul Source's fallback. See [the radius report](ROM_GROUP_HEAL_RADIUS_2026-10-04.md). The earlier Stockade tank death remains a separate timing inference, not a proven range/LOS rejection.
|
||||
- [x] Prevent the thirteen audited utility/extra-attack NPC spells from falling back to direct hits. Exact Ascension/Epoch signatures preserve each source profile; the second pass removes another 51 false attack rows and corrects 30 real attack/control rows, including hostile melee range, pure Kick interruption, caster-centered fear/stun and Chain Lightning range. Real damage and mixed-damage Shield Slam remain. Catalog regeneration also refreshes the existing damage-school/kind metadata. See [the source audit](STOCKADE_UTILITY_ATTACK_AUDIT_2026-10-04.md).
|
||||
- [ ] Model the audited NPC stance, haste/AP, block, offhand, extra-attack, disarm and flat damage-taken effects before claiming their full source parity. Their false direct-hit fallback is fixed, but their real utility remains unsupported. Chain Lightning fan-out, separate-target shout triggers, sourced Rend ticks and Enrage damage/haste values remain gaps; keep Ascension/Epoch source contracts distinct. See [the source audit](STOCKADE_UTILITY_ATTACK_AUDIT_2026-10-04.md).
|
||||
- [x] Implement enemy Chain Lightning 421's three total targets, nearest visible living jumps within 10 m, no repeated recipient, captured cast victim and profile-specific 0.6/0.7 decay. Preserve the first hit's existing amount policy. See [the Chain Lightning audit](STOCKADE_CHAIN_LIGHTNING_2026-10-05.md).
|
||||
- [x] Implement sourced Rend 6547/16509: five physical bleed ticks at three-second intervals, no initial damage, ordinary refresh restarting the timer, independent casters, armor bypass and no magic dispel. Spell 16509 uses the strict source creature BaseDamage ratio through level 80. See [the Rend audit](STOCKADE_REND_2026-10-05.md).
|
||||
- [x] Implement verified Enrage and Demoralizing/Battle Shout source modifiers and geometry. Enrage uses 120 seconds and physical damage plus melee-auto haste; source percentages multiply and repeated nonperiodic copies do not stack. Keep each Ascension/Epoch contract distinct. See [the enemy buff audit](STOCKADE_ENEMY_BUFFS_2026-10-05.md).
|
||||
- [x] Resolve Chronomancer's pre-existing maximum-mana mismatch by consuming its structured permanent passive resource modifier. Aura 132 preserves its named resource, so Sun Cleric Rage and Necromancer Runic Power do not expand Mana. See [the resource report](CHRONOMANCER_RESOURCE_BASELINE_2026-10-05.md).
|
||||
- [x] Implement sourced exclusive NPC Defensive/Battle Stance and ordinary WoW creature auto-attack blocking, including Improved Blocking's +75 percentage points for six seconds, actual facing/control/cast/NO_BLOCK gates and one level skill adjustment. Stockade Battle applies before combat; Kam's Defensive is one-shot. Native RoM attackers share the ordinary WoW target path. See [the implementation and limits](ENEMY_STANCES_BLOCKING_2026-10-05.md).
|
||||
- [x] Implement source-bound direct physical NPC spell blocking for actual player and party casts, with per-rank WoW/Ascension metadata and an independent post-hit roll that preserves crit-plus-block. See [the source and runtime contract](NPC_SPELL_BLOCKING_2026-10-05.md).
|
||||
- [x] Implement sourced enemy Bloodlust 6742: one engaged friendly creature, thirty-second Magic aura, independent +30% melee haste factor, retained self and missing-buff SmartAI rows, and actual Priest dispel. See [the utility continuation](ENEMY_WEAPON_UTILITIES_2026-10-05.md).
|
||||
- [x] Implement enemy Disarm 6713's profile-specific weapon channels and cast requirements, WoW-ruleset unarmed main-hand autos, and Infected Wound 17230's Disease aura with +6 physical damage before armor/block/absorbs. Equipped items and nonweapon stats remain intact. Source and native amount limits are recorded in [the debuff audit](ENEMY_WEAPON_DEBUFFS_2026-10-05.md).
|
||||
- [x] Implement explicit enemy Dual Wield 674/29651 with a separate half-damage offhand timer, and Thrash 3391's two independent queued main-hand swings. The source set does not establish Targorr's Thrash cadence; the existing template schedule remains simulator policy. See [the extra-attack audit](ENEMY_EXTRA_ATTACKS_2026-10-05.md).
|
||||
- [x] Connect source-bound Disarm weapon aura and permitted selected-hand formula views for players and generated party members. Add verified native active-five main-hand unarmed inputs, hand-specific enemy results and committed combat-time evidence, and pinned flag-driven offhand capability. Keep nonweapon stats and usable hands intact. See [the weapon parity follow-up](WEAPON_PARITY_FOLLOWUP_2026-10-05.md) for source, gear, recorder and native rate boundaries.
|
||||
- [x] Consume source-bound ordinary NPC ignore-hit-direction and critical-block inputs, roll critical block independently after a successful ordinary/direct-spell block, and preserve separate explicit-victim/area recipients for triggered shouts 5246 and 19134. Player/party auto results now include actual hand metadata; QA matches results to committed Disarm windows. Whole Critical Block/Deterrence imports remain gated by unsupported siblings. See [the continuation](ENEMY_SOURCE_PARITY_CONTINUATION_2026-10-06.md).
|
||||
- [x] Audit hostile-NPC outgoing threat against the current target path. The source scales a recipient's threat list; current enemy recipients are playable player/party actors or owned summons. NPC-vs-NPC requires a separate future consumer. See [the source boundary](HOSTILE_NPC_THREAT_BOUNDARY_2026-10-06.md).
|
||||
- [x] Recover the matching pinned enemy equipment table, validate virtual slots against Item.dbc, retain explicit source spawn GUIDs, and enable AUTO offhand attacks for proven ordinary NPC offhand weapons. Selectors and alternate entries fail closed; runtime tests cover independent timing and reset persistence. See [the equipment source mapping](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md).
|
||||
- [x] Add guarded ordinary-Creature self-cast Critical Block 47294–47296 imports, exact WoW335 Shield Bash 72 full utility blocking for player/party writers, and source shout aura 31 +25% speed with whole-spell fear immunity and separate stun-effect immunity. No source NPC Critical Block assignment was found, so no creature cast is invented. The stance/Thrash audit confirms no source meaning for Ascension DUMMY +42 or exact Targorr Thrash cadence; keep both gated. See [the utility/control completion](ENEMY_UTILITY_CONTROL_COMPLETION_2026-10-06.md).
|
||||
- [x] Import exact WoW335 Shield Bash 72's child 29703 as a six-second 50% SNARE, integrate safe source-informed fear routes for local player/party/mobile summons, and bind named-shout immunity purge/escape to exact Berserker Rage 18499 and Bladestorm 46924 source grants. Whole child/rider removal, overlapping generic controls, blocked paths, expiry and accepted grant/cast consumers are covered. Icebound Fortitude has no sourced purge flag; Bladestorm has no controlled-casting bypass. See [the control-runtime follow-up](ENEMY_CONTROL_RUNTIME_FOLLOWUP_2026-10-06.md).
|
||||
- [ ] Extend utility full hit tables/ranks/profiles only with exact source proof. General shout Magic hit/resist/deflect, exact server flee paths/RNG, additional immunity-grant purge rules, Deterrence siblings, private Ascension stance DUMMY consumer, exact source Targorr Thrash timing, native custom equipment/rate and cast prerequisites, and broader weapon/proc formulas remain open. False direct hits stay omitted for unsupported effects. See [the current boundaries](ENEMY_CONTROL_RUNTIME_FOLLOWUP_2026-10-06.md).
|
||||
|
||||
## Native stat input update (2026-10-03)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# Chronomancer resource baseline
|
||||
|
||||
Chronomancer now initializes the expected 414 mana at level 1. The committed baseline initialized 369; both the earlier working-tree run and saved HEAD-source replay reproduced that mismatch, establishing that it predated the recent RoM changes.
|
||||
|
||||
The intended bonus is sourced by Chronomancer's automatic `Chrono Sorcery` passive in `src/game/generated/coaAbilities/chronomancer.json`: its Aura 132 modifier increases maximum `power` by 0.12. Source MiscValue 0 identifies Mana. The human level-1 derived pool is 123 mana before the global 3x pool multiplier, so the expected result is `round(123 × 1.12) × 3 = 414`. The generated description still contains `$s1%`, which the old description-only path could not resolve. The runtime now consumes the structured modifier directly.
|
||||
|
||||
`src/game/classPassiveResourceModifiers.ts` converts structured permanent passive Aura maximum-resource percentage effects into source- and rank-preserving `TalentModifier` entries. Aura 132 uses its source power identity; generic power without that source channel uses the class profile. Explicit resources stay scoped, and matching parsed duplicates are removed. Other-recipient, timed and hit/crit-gated effects stay excluded. This preserves Sun Cleric's Rage and Necromancer's Runic Power as separate resources instead of expanding their Mana.
|
||||
|
||||
The root runtime integration is complete. Nine helper checks and the original selected combat-store resource case pass, including Chronomancer's 414 pool and the unchanged other class/resource expectations. The original case and expectation were preserved. No all-class balance run was used.
|
||||
|
||||
See `docs/STOCKADE_ENEMY_MECHANICS_2026-10-05.md` for the coordinated build and validation totals.
|
||||
@@ -1,6 +1,6 @@
|
||||
# First Conquest of Azeroth party
|
||||
|
||||
Updated: 2026-10-04. The project owner selected these five classes as the first
|
||||
Updated: 2026-10-05. The project owner selected these five classes as the first
|
||||
CoA implementation milestone. Build and refine this party before expanding to
|
||||
other CoA classes. CoA here means Conquest of Azeroth on Vol'Jin; the existing
|
||||
RoM backlog's Chronicles of Arcadia references describe a different game.
|
||||
@@ -88,7 +88,7 @@ and explicitly scoped Balance Lab configurations.
|
||||
active-player configurations, retaining the same party build IDs in each.
|
||||
|
||||
```sh
|
||||
npm run coa:party:prepare -- --list-bosses ragefire-chasm
|
||||
npm run coa:party:prepare -- --list-bosses stormwind-stockade
|
||||
npm run coa:party:prepare -- --level 60 --boss <exact-key-from-list>
|
||||
npm run coa:party:test
|
||||
```
|
||||
@@ -128,9 +128,10 @@ retain their previous action catalogs.
|
||||
|
||||
This fixes action availability, not the complete effect of each spell. Initial
|
||||
Potion Toss checks cover its base targeted heal and mana payment for a player
|
||||
and companion; ingredient riders and its full authored scaling remain work.
|
||||
Decapitate's target-health gate is a separate first mechanic; additional Energy
|
||||
conversion and the Beheader refund remain pending.
|
||||
and companion. The follow-up below adds ingredient state and the Frog Bones
|
||||
rider; other riders and the complete Brewing loop remain work. Decapitate's
|
||||
target-health gate and Beheader's kill refund are separate mechanics;
|
||||
additional Energy conversion remains unresolved.
|
||||
|
||||
Ranger's primary resource is now Focus, matching its spell costs. Player and
|
||||
companion checks cover spending, the displayed/authoritative pool, and recovery.
|
||||
@@ -172,16 +173,391 @@ correction are:
|
||||
|
||||
Raw runs are local ignored artifacts at
|
||||
`artifacts/coa-first-party/level-60/seat-1-runs.json` through `seat-5-runs.json`.
|
||||
Companion action counts are substantially lower than player counts; Ranger and
|
||||
Pyromancer companions each cast only three times in the healer-seat run. That
|
||||
run's Ranger still records 32.3% Focus starvation. The profile correction alone
|
||||
does not resolve their rotations, stateful costs, or generic effect semantics.
|
||||
The large player-seat differences require mechanic and AI investigation before
|
||||
balance changes. This low-pressure encounter also provides limited evidence
|
||||
for tank/healer interactions.
|
||||
The original claim that Ranger and Pyromancer companions each cast only three
|
||||
times was a telemetry error. Damaging companion casts were omitted from the
|
||||
counter despite damage and decision events showing more activity. The corrected
|
||||
collector counts release presentations once per cast, including channel pulses
|
||||
only once. A new Hamhock healer-seat diagnostic records 19 Ranger and 17
|
||||
Pyromancer companion casts. Ranger still records 32.3% Focus starvation; raw
|
||||
cast counts do not establish a coherent resource/state rotation. The large
|
||||
player-seat differences require mechanic investigation before balance changes.
|
||||
These low-pressure encounters provide limited evidence for tank/healer interactions.
|
||||
|
||||
These are explicitly scoped automated diagnostics, with no live browser
|
||||
playtest or balance certification in this kickoff. All five remain Needs
|
||||
Testing. The next implementation pass is Guardian's Vanguard state together
|
||||
with Witch Doctor's cauldron/ingredient loop and reviewed talent allocations,
|
||||
followed by the three damage loops and companion rotation parity.
|
||||
Testing. New routine diagnostics use Stormwind Stockade: Cellblock Rush
|
||||
(`bite-sized-stormwind-stockade`) under `TEST_DUNGEON_POLICY.md`; record the
|
||||
boss selected from the run ID. Full-source Stockade campaigns require explicit
|
||||
selection. The Taragaman records above remain historical evidence.
|
||||
|
||||
## Mechanics and rotation follow-up, 2026-10-05
|
||||
|
||||
- `coaGuardianVanguardRuntime.ts` owns learned node 34417's actor-owned Vanguard
|
||||
state. Source spells 804383/804384 establish one stack per landed normal swing
|
||||
or block, ten maximum, a refreshed 60-second duration, and 2% less damage from
|
||||
each magic school per stack. Direct incoming spells use the current mitigation
|
||||
before consuming one stack. Periodic-tick consumption is unresolved and is
|
||||
excluded. Player and companion event hooks use the same state transition.
|
||||
- `coaWitchDoctorBrewingRuntime.ts` owns persistent ingredient markers and the
|
||||
one-ingredient capacity, raised to two by learned Mixologist node 6645. An
|
||||
ingredient already present may refresh; an additional ingredient at capacity
|
||||
fails before payment. Replacement/removal behavior is not specified by the
|
||||
captured evidence. Frog Bones 801663 no longer creates the importer's bogus
|
||||
one-second caster shield. It retains its 1.5-second cauldron pulse. Potion Toss
|
||||
801661 adds the shield from global spell 802971 to its selected ally only when
|
||||
that caster owns an active Frog Bones marker: eight seconds, base 100, five
|
||||
points per level from level ten, 35% Spirit and 80% bonus healing. Other
|
||||
ingredient markers do not establish their unfinished Potion Toss riders.
|
||||
- `coaBarbarianExecuteRuntime.ts` also owns learned Beheader node 6744's exact
|
||||
Decapitate kill refund: 100% of maximum Energy after an effective killing hit,
|
||||
clamped to the pool maximum. Failed, nonlethal and unrelated hits do not refund.
|
||||
The additional-Energy damage conversion has no verified ratio in this slice.
|
||||
Its generic weapon-damage projection also needs review: separate DBC weapon
|
||||
effects must not be treated as two independent weapon hits.
|
||||
- Pyromancer Ignite's selected-enemy implicit target takes precedence over its
|
||||
DBC radius metadata. Both tree and progression variants use unit targeting;
|
||||
nearby enemies no longer receive the selected enemy's burn.
|
||||
- Chosen-five unit-target periodic maintenance compares ability, caster,
|
||||
recipient and positive remaining duration. A burn or HoT on one actor no
|
||||
longer blocks applying that spell to a different actor. This correction does
|
||||
not author speculative class priority lists or clipping windows. Mojo Beam's
|
||||
incidental caster aura no longer redirects its friendly unit heal to the
|
||||
caster; the scorer selects the injured ally and checks that ally's own HoT.
|
||||
An actual companion channel check verifies Mana payment and the first pulse
|
||||
on the injured Vanguard ally. It does not resolve Mojo Beam's duration conflict.
|
||||
|
||||
The companion Potion Toss rider check primes its actor-owned ingredient marker
|
||||
explicitly. Default healthy companion AI does not prepare its cauldron; authored
|
||||
ingredient preparation and selection remain a rotation gap. Loa's Brew winning
|
||||
one injured-ally fixture does not, by itself, establish a wrong healing priority.
|
||||
|
||||
Formation/Paragon, full Brewing riders and payloads, Decapitate's Energy
|
||||
conversion/Battle Rhythm, Ranger Advantage/Elude, Pyromancer Heat/Embers and
|
||||
reviewed talent allocations remain the next mechanics work. All five remain
|
||||
Needs Testing. Automated checks do not replace live party playtests.
|
||||
|
||||
The follow-up's explicitly scoped Stockade/Hamhock diagnostic retains level 60,
|
||||
seed 1, a 30-second limit and the same five generated builds in each seat:
|
||||
|
||||
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| Guardian | Time limit | 30.0 | 80,815 | 0 |
|
||||
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
|
||||
| Barbarian | Defeated | 13.6 | 0 | 0 |
|
||||
| Ranger | Time limit | 30.0 | 28,443 | 0 |
|
||||
| Pyromancer | Defeated | 27.8 | 0 | 0 |
|
||||
|
||||
Raw runs are ignored local artifacts at
|
||||
`artifacts/coa-first-party/stockade-2026-10-05/seat-1-after.json` through
|
||||
`seat-5-after.json`; seats two/four also retain before runs. The final healer-seat
|
||||
run records 19 Ranger and 16 Pyromancer companion casts, with Ranger still
|
||||
32.3% Focus-starved. Correct source behavior can change damage and timing;
|
||||
these outcomes do not establish balance, authored allocations, or full-class
|
||||
completion. Low encounter pressure limits healer/tank conclusions. No live
|
||||
browser playtest was performed in this mechanics follow-up.
|
||||
|
||||
Focused validation passes 126 tests across 19 directly affected files, including
|
||||
the helper, public scorer and actual player/companion behavior checks. Ready-five
|
||||
compatibility passes seven Vitest and twenty Python tests. The generated runtime
|
||||
and UI changes are limited to two Pyromancer Ignite actions; the other twenty
|
||||
class records, resource profiles and triggered payloads are preserved.
|
||||
The final production build passes TypeScript, asset audits, bundling, static
|
||||
compression and release-bundle verification. `npm run release:check` passes,
|
||||
including untracked files. The canonical CoA vault note is updated separately.
|
||||
|
||||
## Brewing integration, 2026-10-05
|
||||
|
||||
`coaWitchDoctorBrewingAi.ts` owns an authored companion preparation policy.
|
||||
`partyRuntime.ts::choosePartySupportIntent` prepares learned Frog Bones when a
|
||||
Brewing healer has Brewer and Potion Toss, every party member/player is at
|
||||
least 90% healthy, and no resurrection, dispel or engaged-enemy cast is pending.
|
||||
Normal readiness, Mana, target and capacity checks still precede payment. It
|
||||
preserves an existing full cauldron and does not refresh an existing own Frog
|
||||
Bones marker. This is a conservative gameplay policy, not a sourced optimal
|
||||
rotation. Other ingredient selection remains unfinished.
|
||||
|
||||
`partyAbilityAi.ts` projects the caster's current Brewing effects before
|
||||
scoring heals. Ingredient casts are excluded from the ordinary Brewing healer
|
||||
rotation so they cannot displace healing or repeatedly refill the cauldron.
|
||||
Actual idle companion tests prepare through normal selection and payment,
|
||||
then heal and shield an injured player with Potion Toss, without seeding an
|
||||
in-flight cast or priming an ingredient marker.
|
||||
|
||||
Splash Potion node 7128/spell 802710 is now a friendly ground action in source
|
||||
generation and the runtime/UI catalogs. Its DBC destination targets 87/31 and
|
||||
captured tooltip establish a location, 40-yard range, 10-yard radius and up to
|
||||
eight allies. Its base heal centers on that destination. The cast projection
|
||||
suppresses the importer's unconditional flattened ingredient and SLS payloads;
|
||||
only an owned, live Frog Bones marker adds verified 803699's reduced absorb:
|
||||
eight seconds, base 25 and one point per level from level 15. Player and NPC
|
||||
tests check nearby recipients, excluded distant allies, no inactive riders,
|
||||
and destination validation before payment. The player's previous radius shield
|
||||
branch centered on the caster; the Splash-specific path now uses the same
|
||||
effect-scoped ground center as its healing. Existing other spell paths retain
|
||||
their behavior.
|
||||
|
||||
Jungle Shrooms 802973's exact Spirit scaling, Fish Oil 802969's aura decoding,
|
||||
Bloodthistle 802975/803287's proc and 0.5-second internal cooldown, and the
|
||||
803275 SLS ingredient-combination chain remain unresolved. Their raw source
|
||||
records are retained; missing runtime semantics do not grant every rider.
|
||||
|
||||
The Guardian audit identifies the next import boundary. August Vol'Jin node
|
||||
4019/spell 92105 establishes 10% self mitigation while Tower or Line Formation
|
||||
is active, with no numeric threat multiplier. Global spells 800317 and 803130
|
||||
would create self-owned aura identities `coa:800317:effect:0:aura:87` and
|
||||
`coa:803130:effect:0:aura:232`, but neither action is present in the promoted
|
||||
tree/progression/runtime catalog. Mitigation cannot honestly use an assumed
|
||||
formation flag. Paragon 29969/706514 has a description conflict: the August
|
||||
builder changes Heavy Blow to Paragon Smash, while the promoted primary text
|
||||
for 706516 still describes Tower/Bastion. The later formation audit below finds
|
||||
compatible secondary text and child payloads. Import formation actions and
|
||||
preserve the source discrepancy when wiring the conditional mechanics. See the cached Guardian JSON and builder in
|
||||
`data/coa-reference/cache/archive-5078f9ac2254/generation-fa16afec-8f11-4eab-98ab-b6441304fab7/`
|
||||
and global snapshot `e86031775dfac7e336361087c50ca23a0a7a86c36a760c85803bee4bcdb89351`.
|
||||
|
||||
Rotation policy is `playerbots-inspired-v10-coa-brewing-preparation`. The same
|
||||
five level-60 builds, seed 1, Hamhock and 30-second limit produce:
|
||||
|
||||
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| Guardian | Time limit | 30.0 | 80,007 | 0 |
|
||||
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
|
||||
| Barbarian | Defeated | 13.6 | 0 | 0 |
|
||||
| Ranger | Time limit | 30.0 | 28,599 | 0 |
|
||||
| Pyromancer | Defeated | 24.8 | 0 | 0 |
|
||||
|
||||
The Guardian-seat companion records one naturally selected Frog Bones cast.
|
||||
Raw evidence is preserved separately at ignored
|
||||
`artifacts/coa-first-party/stockade-integration-2026-10-05/seat-1.json` through
|
||||
`seat-5.json`. Encounter pressure is low; the healer deals substantial damage,
|
||||
and these results establish neither balance nor a complete healing rotation.
|
||||
All five remain Needs Testing. No live browser playtest was performed.
|
||||
|
||||
Focused validation passes 37 tests across eight directly affected files;
|
||||
Ready-five compatibility passes seven Vitest and twenty Python tests. The new
|
||||
generated catalog change is one Witch Doctor Splash action in each runtime/UI
|
||||
catalog; the other twenty class records, resource profiles and triggered
|
||||
payloads are preserved. No recrawl or download was needed.
|
||||
The final production build passes TypeScript, asset audits, bundling, static
|
||||
compression and release-bundle verification. `npm run release:check` passes,
|
||||
including untracked files; the canonical CoA vault note is updated separately.
|
||||
|
||||
## Decapitate strike integration and Guardian audit, 2026-10-05
|
||||
|
||||
`coaBarbarianWeaponDamageRuntime.ts` projects only tree node 5744/spell 804414
|
||||
as one normalized weapon strike. The imported effects previously emitted two
|
||||
independent damage events. The August Vol'Jin tooltip gives the formula:
|
||||
`27 + 2.2 * (weapon mean + attack power / 14 * normalized speed)`. Explicit
|
||||
equipped-item classification supplies the standard normalized speed: 3.3 seconds
|
||||
for two-handed melee weapons, 1.7 for daggers, and 2.4 for other one-handed
|
||||
melee weapons. Actual swing speed is used only to undo the existing weapon-DPS
|
||||
conversion. An unknown weapon classification retains the imported fallback.
|
||||
|
||||
The helper is used before player execution in `combatStore.ts`, companion
|
||||
execution in `partyRuntime.ts`, companion scoring in `partyAbilityAi.ts`, and
|
||||
active-seat scoring in `benchmark/benchmarkController.ts`. Applying it repeatedly
|
||||
preserves a single strike. It retains identity, cost, targeting, the below-35%
|
||||
health gate, and Beheader's successful-kill refund. The additional Energy
|
||||
conversion ratio remains unknown and is not implemented.
|
||||
|
||||
The historical generic AzerothCore weapon-effect sequence adds the flat bonus
|
||||
before applying the percentage, which would also multiply 27. The custom CoA
|
||||
server script is unavailable; this projection follows the explicit CoA tooltip's
|
||||
flat bonus outside the percentage. This source interpretation remains recorded
|
||||
in the helper and does not claim verification against the live server.
|
||||
|
||||
The Guardian audit now distinguishes acquisition from payload reconciliation.
|
||||
Tower 800317 and Line 803130 carry trainer source 6, levels 4/20, but lack a
|
||||
current tree node or ranked progression chain. They need an explicit rankless
|
||||
trainer import path and formation-specific effect handling. No formation state
|
||||
was seeded. Paragon stack spell 706516's secondary field 187 matches the August
|
||||
Heavy Blow/Paragon Smash description, and children 802629/803432 support its
|
||||
damage and block/Brace effects. The older primary Tower/Bastion description
|
||||
is preserved as a conflict. Exact IDs, raw-field provenance, modifiers and
|
||||
remaining acquisition boundaries are in
|
||||
`docs/COA_GUARDIAN_FORMATION_AUDIT_2026-10-05.md`.
|
||||
|
||||
Rotation policy is `playerbots-inspired-v11-coa-decapitate-strike`. The explicitly
|
||||
selected five builds run at level 60, seed 1, with a 30-second limit against
|
||||
Cellblock Rush's catalog-template boss, Hamhock
|
||||
(`bite-sized-stormwind-stockade/entry-1717`):
|
||||
|
||||
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| Guardian | Time limit | 30.0 | 80,007 | 0 |
|
||||
| Witch Doctor | Time limit | 30.0 | 77,898 | 0 |
|
||||
| Barbarian | Defeated | 12.8 | 0 | 0 |
|
||||
| Ranger | Time limit | 30.0 | 29,396 | 0 |
|
||||
| Pyromancer | Defeated | 24.8 | 0 | 0 |
|
||||
|
||||
These are isolated headless boss-room diagnostics, not a live dungeon clear.
|
||||
The boss identity comes from the registered Cellblock Rush template; a fresh
|
||||
live run can select a different boss. Raw configs/results are ignored local
|
||||
artifacts at `artifacts/coa-first-party/stockade-decapitate-2026-10-05/`.
|
||||
The final Barbarian active-seat scorer chooses other attacks in this run; its
|
||||
Decapitate count is zero. Deterministic regression fixtures separately prove
|
||||
one correctly calculated damage event through actual player and NPC casts.
|
||||
Damage/selection changes do not certify balance, and encounter pressure remains
|
||||
too low to establish tank/healer completeness. All five remain Needs Testing.
|
||||
|
||||
Focused validation passes 22 tests across five directly affected files,
|
||||
including the actual player/NPC strike checks and existing execute/Beheader
|
||||
regressions. Ready-five compatibility passes seven Vitest and twenty Python
|
||||
tests. This pass changes no generated catalog records or readiness pools.
|
||||
The final production build passes TypeScript, asset audits, bundling, static
|
||||
compression and release-bundle verification. `npm run release:check` passes,
|
||||
including untracked files; the canonical CoA vault note is updated separately.
|
||||
|
||||
## Guardian formations and Paragon integration, 2026-10-05
|
||||
|
||||
Tower Formation 800317 and Line Formation 803130 now have an explicit rankless
|
||||
trainer import path in `coaAbilityCatalog.ts`, constrained to the two sourced
|
||||
Guardian/class-18 rows with trainer source 6, valid levels and matching DBC
|
||||
identities. They learn at levels 4 and 20 through the game's existing automatic
|
||||
level-learning model. No tree grant or named trainer is invented. The generated
|
||||
runtime and UI catalog changes are limited to Guardian records.
|
||||
|
||||
`coaGuardianFormationRuntime.ts` replaces the flattened source effects with one
|
||||
owned self aura per cast. Tower gives +10 percentage points of block, adds half
|
||||
of the actual shield item's armor and reduces outgoing damage by 10%. Line
|
||||
adds 15% movement speed and reduces roots by 25%. Aura 232/misc 7 identifies
|
||||
Root; the broader tooltip wording remains a source conflict, so other control
|
||||
types retain their duration. Footman's Calling node 4019 adds 10% taken-damage
|
||||
reduction only while an own live form is active. Projection uses current talent
|
||||
ranks, equipment and health, preventing borrowed/expired markers and recomputing
|
||||
shield armor after equipment changes. No numeric threat grant is assumed.
|
||||
Switching replaces the other form through an authored exclusive group; source
|
||||
categories 708/709 do not prove exclusivity. Toggle-off remains unfinished.
|
||||
|
||||
`coaGuardianParagonRuntime.ts` follows August Vol'Jin node 29969/706514,
|
||||
706516's compatible secondary text and linked payloads. Heavy Blow adds three
|
||||
stacks on successful cast; a block adds one with a 500 ms stack-trigger internal
|
||||
cooldown. Stacks last ten seconds and cap at ten. Readiness 707138 grants no
|
||||
block bonus. While ready, Heavy Blow's existing action slot, identity, cost,
|
||||
talent gate and cooldown project to Paragon Smash: 144 + 37% AP in an 8-yard
|
||||
self circle, confirmed by local SpellRadius.dbc row 14. A successful Smash
|
||||
creates the separate ten-second +10-point block buff with five block charges.
|
||||
Each block during that buff consumes a charge and reduces an active Brace
|
||||
cooldown by two seconds. Companion authority and its mirrored member receive
|
||||
the same reduction. No unverified stack-consumption/reset rule is introduced;
|
||||
a qualifying event can reestablish readiness after its previous window expires.
|
||||
The stale primary Tower/Bastion text remains documented in the source audit.
|
||||
|
||||
Player execution, companion execution/scoring, active-seat benchmarking and HUD
|
||||
use the shared projection. The HUD displays Smash in the Heavy Blow slot during
|
||||
readiness. Both player and companion movement consume owned Line speed.
|
||||
Vanguard companions prepare learned Tower through ordinary readiness, targeting
|
||||
and resource payment and preserve an existing Line. Formation preparation
|
||||
respects `nextActionAt`, so a future preparation decision does not suppress
|
||||
normal attacks. Cast/block fixtures prove player and companion paths; they use
|
||||
explicit block-probability fixtures to make combat outcomes deterministic.
|
||||
|
||||
The ready-Smash priority is an authored rotation policy: priority 7,500 only
|
||||
for a Vanguard tank at or above 55% health; injured, unknown-health and other
|
||||
actors retain the existing fallback preference. The public companion scorer
|
||||
uses ordinary learned, ready candidates and chooses Smash over routine Ballad
|
||||
maintenance. Existing low-health mitigation and urgent reactive taunt/interrupt
|
||||
scores remain ahead of it. This is a gameplay preference, not a source-derived
|
||||
optimal rotation.
|
||||
|
||||
Rotation policy is `playerbots-inspired-v12-coa-guardian-formations-paragon`.
|
||||
The generated five builds at level 60, seed 1, with a 30-second limit against
|
||||
Cellblock Rush's catalog-template Hamhock
|
||||
(`bite-sized-stormwind-stockade/entry-1717`) produce:
|
||||
|
||||
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| Guardian | Time limit | 30.0 | 81,106 | 0 |
|
||||
| Witch Doctor | Time limit | 30.0 | 76,687 | 0 |
|
||||
| Barbarian | Defeated | 12.8 | 0 | 0 |
|
||||
| Ranger | Time limit | 30.0 | 23,870 | 0 |
|
||||
| Pyromancer | Defeated | 24.8 | 0 | 0 |
|
||||
|
||||
Each companion-Guardian seat records one naturally selected Tower cast. The
|
||||
active-player benchmark records no Tower cast; manual player casting is covered
|
||||
by actual cast fixtures and the browser diagnostic. These
|
||||
are isolated headless diagnostics at ignored
|
||||
`artifacts/coa-first-party/stockade-guardian-2026-10-05/`, not live dungeon clears.
|
||||
The role-weighted Guardian allocation does not learn Paragon/Heavy Blow, so
|
||||
these five results do not establish Smash selection. Incoming damage is low;
|
||||
all five remain Needs Testing and no random/readiness pool changed.
|
||||
|
||||
Focused validation passes 66 unique tests across fifteen directly affected CoA
|
||||
and input files, including actual player/companion formation and Paragon casts, incoming
|
||||
root handling, shield armor/Footman's Calling, block charges/Brace reduction,
|
||||
unrestricted companion scoring and prior Brewing/Splash/weapon-strike paths.
|
||||
Ready-five compatibility passes seven Vitest and twenty Python tests. Avatar
|
||||
checks pass 56 tests across eleven files. Narrow compatibility checks for the
|
||||
shared workspace's boss guide, disarm metadata/runtime and extra-attack helper
|
||||
pass seventeen tests; compatibility fixes preserve those existing behaviors.
|
||||
|
||||
The final production build passes TypeScript, asset audits, Vite bundling,
|
||||
static compression and release-bundle verification. During verification,
|
||||
concurrent enemy-runtime changes briefly duplicated/removed their interface
|
||||
fields and concurrent bootstrap runs collided on an exclusive object write;
|
||||
final validation uses the successful completed build. The final creature weapon
|
||||
state declarations share one typed interface, preserving runtime behavior.
|
||||
|
||||
The isolated live harness uses an explicit, runtime-normalized level-60 Guardian
|
||||
variant learning Paragon and Heavy Blow alongside Footman's Calling, Brace and
|
||||
Vanguard's Shield. It resolves the public catalog preloader and resource API's
|
||||
minified export aliases from source-matched bundle AST, loads the five class
|
||||
catalogs before entry, and verifies their resource profiles. Switching characters
|
||||
cannot preload a whole party persistently because the app reloads its memory
|
||||
when the entered character changes. The harness therefore installs a scoped
|
||||
pre-entry PartyBridge initialization fixture, calls the normal initializer and
|
||||
substitutes the prepared companions before actor synchronization. It leaves
|
||||
readiness/random pools unchanged and seeds no combat/proc state. A selectable
|
||||
first-party preset in the game UI remains separate work.
|
||||
|
||||
Live entry exposed two startup gaps and supplied the final regressions.
|
||||
`combatRotation.ts::precombatPreparationEffects` now excludes exact Guardian
|
||||
formation spells from generic free aura preparation: initial entry has no form,
|
||||
player casting pays normally, companion preparation casts normally, and later
|
||||
preparation cannot add a second raw form or replace a chosen Line.
|
||||
`actionBindings.ts::normalizeActionBindings` separates default assignment order
|
||||
from an optional explicit allowlist. `combatStore.ts::initializeCharacter`
|
||||
validates saved slots against all nonpassive class actions, then retains the
|
||||
existing unlearned-talent filter. The learned Heavy Blow talent action survives
|
||||
entry in its saved slot, while unlearned and unknown actions are rejected.
|
||||
|
||||
The shared `dist/assets` directory became locked during rebuild. Final verification
|
||||
uses an isolated output at
|
||||
`artifacts/coa-first-party/stockade-guardian-2026-10-05/dist-final`: prebuild and
|
||||
asset audits passed, then the same npm build command ran with lifecycle hooks
|
||||
skipped and an explicit output override; compression and release-bundle checks
|
||||
ran explicitly against that output. The live harness accepts a confined `--dist`
|
||||
path and records the directory/bundle assets actually tested.
|
||||
|
||||
The final 180-second browser diagnostic completes on the isolated production
|
||||
bundle at `artifacts/playtest/coa-guardian-formations/20261006-011259958/`.
|
||||
Normal offline creation, Button Assignments, Cellblock selection/download and
|
||||
Tank entry are preserved; the exact companion composition is the explicitly
|
||||
recorded pre-entry fixture. Entry verifies level 60, all five catalogs, no seeded
|
||||
formation and the saved Heavy Blow R2 slot. Real action-bar clicks cast Tower,
|
||||
Line and Tower again, each leaving only its own projected form. The first Tower
|
||||
reduces Energy from 100 to 83; this legal build's cost modifiers resolve the
|
||||
base 20 cost to 17, with normal regeneration between later casts.
|
||||
|
||||
The fresh run selects Dextren Ward (`entry-1663`, `creature-79116`), confirmed
|
||||
by its intro card. Screenshot 02 is a countdown overlay because the initial
|
||||
detachment wait raced the intro's appearance; screenshots 03/04/06 provide the
|
||||
actual in-dungeon evidence. The route explores about 8 m near the entrance,
|
||||
with 5.74 m net displacement, full player/party health and no observed boss
|
||||
actor. It records only the three formation casts, no natural Paragon ready/Smash
|
||||
marker and no healing/combat pressure. It does not establish a clear, balanced
|
||||
party, live Smash proc or complete tank/healer rotation. The actual proc/block/
|
||||
Brace and unmasked scorer coverage comes from the focused regression fixtures.
|
||||
|
||||
Reviewed the roster body/shield capture and in-dungeon captures: the player
|
||||
body and equipped shield/weapon silhouettes render, while the clustered party
|
||||
and large temporary gold effects obscure some companions. Heavy Blow remains
|
||||
visible in its saved R2 slot at the endpoint. Browser exceptions are zero;
|
||||
one console 404 is unclassified, with no failed requests or HTTP errors in
|
||||
the harness's recorded request scope. These visual and request limitations
|
||||
remain in the live evidence. All five stay Needs Testing. The source/cast fixes,
|
||||
scoped diagnostic harness, milestone, source audit and canonical CoA vault note
|
||||
are updated together.
|
||||
|
||||
`npm run release:check` passes, including untracked files. The Git index is
|
||||
unchanged; no commit, deployment or readiness promotion was performed.
|
||||
@@ -0,0 +1,139 @@
|
||||
# Guardian formation and Paragon source audit, 2026-10-05
|
||||
|
||||
The original read-only audit below bounded the Vanguard integration. The
|
||||
implementation follow-up records the resulting runtime contracts; the selected
|
||||
five CoA builds remain Needs Testing.
|
||||
|
||||
## Action acquisition
|
||||
|
||||
The August 12, 2026 Vol'Jin builder capture has 161 Guardian nodes and no node
|
||||
for Tower Formation 800317 or Guardian Line Formation 803130. Footman's Calling
|
||||
4019, The Green Tower 30060, Banner Boy 29798, and Press the Line! 6817 reference
|
||||
them in descriptions; references are not learn-spell grants.
|
||||
|
||||
The separate July 25 class-spell metadata in `src/game/coaLiveData.generated.json`
|
||||
marks both spells class 18 with `sourceIds: [6]`. `scripts/sync-ascension-coa.mjs`
|
||||
maps source 6 to the trainer flag when building ranked progression chains.
|
||||
These two spells are rankless, have no progression chain, and are absent from
|
||||
the promoted action catalog. Tower's level is 4 with Talent/tab 7 metadata;
|
||||
Line's level is 20 with no advancement type. This is evidence for a trainer
|
||||
channel, but the current import path needs explicit rankless trainer support.
|
||||
There is no captured named trainer, exact unlock row, or current tree grant.
|
||||
|
||||
## Formation effects
|
||||
|
||||
| Spell | Cost / duration | Self effects | Integration requirement |
|
||||
| --- | --- | --- | --- |
|
||||
| Tower 800317 | 20 Energy / indefinite | Aura 87, base 0; aura 142, +50; aura 79, -10 | Resolve linked +10% block from 803431 effect 3; implement shield armor contribution separately from generic resistance; retain -10% outgoing damage. |
|
||||
| Line 803130 | 20 Energy / indefinite | Aura 232, -25, misc 7; aura 79, 0; aura 31, +15 | Implement the captioned control-duration reduction and movement; apply the conditional Vanguard mitigation through a real owned form. |
|
||||
|
||||
Both have no cast time or individual recovery. Their categories are 708 and
|
||||
709; these do not establish mutual exclusion or toggle-off behavior. The source
|
||||
does not provide a cancellation/grant relationship between them. Tower's armor
|
||||
caption modifies the shield contribution, so applying +50% total armor or
|
||||
physical resistance would be incorrect. Generic aura conversion also leaves
|
||||
Line's aura 232 unsupported.
|
||||
|
||||
Footman's Calling 4019/92105 establishes -10% self damage while Tower or Line is
|
||||
active. A future runtime check must require the caster's own live self aura:
|
||||
`coa:800317:effect:0:aura:87` or `coa:803130:effect:0:aura:232`. Spell 92105 has no
|
||||
trigger grant. Referenced 807728 is a separate tank-stance payload, not a spell
|
||||
granted by that passive; its threat value cannot be assumed active merely from
|
||||
learning Footman's Calling. Do not substitute Tower Stance 803907, visual
|
||||
803941, or Line SLS 803151/803690 for the acquisition of the two real actions.
|
||||
|
||||
## Paragon reconciliation
|
||||
|
||||
The August live node 29969/706514 describes stacks from blocking, a ten-stack
|
||||
Heavy Blow to Paragon Smash transformation, and three stacks from Heavy Blow.
|
||||
The block trigger is limited to once per 0.5 seconds, and stacks last 10 seconds.
|
||||
Smash deals 144 + 37% AP to nearby enemies and adds +10% block; blocking reduces
|
||||
Brace's cooldown by two seconds, for five blocks or ten seconds.
|
||||
|
||||
The linked stack spell 706516 has inconsistent text fields. Its primary field
|
||||
170 still describes the older Tower/Bastion transformation. Field 187 instead
|
||||
describes Heavy Blow to Paragon Smash, matching the live node. Archive children
|
||||
802629 (damage) and 803432 (buff) support the Smash damage and block/cooldown
|
||||
payload. This narrows the discrepancy to the stale primary description rather
|
||||
than proving the old transformation is the intended current behavior. The live
|
||||
node and compatible child payload should guide the next implementation; keep
|
||||
the conflicting primary text as evidence.
|
||||
|
||||
The active sync prefers localized field 170 and falls back to field 187 only
|
||||
when 170 is empty. Its promoted primary-only description therefore loses this
|
||||
useful secondary text. No gameplay behavior changed in this audit.
|
||||
|
||||
## Offline provenance
|
||||
|
||||
- Builder and tree: `data/coa-reference/cache/archive-5078f9ac2254/generation-fa16afec-8f11-4eab-98ab-b6441304fab7/`,
|
||||
`raw/talents/coa-builder-voljin.html`, `raw/talents/_fetch.json`, and
|
||||
`data/talents/coa/Guardian.json`. The fetch record gives capture time
|
||||
`2026-08-12T21:02:51+00:00` and SHA-256
|
||||
`41a6ccd393c0648ae2b1fdc34fe94955d4fd13c0cd59040ad3860e64a8ff6c7a`.
|
||||
- Patch-T raw spell shards: under the same archive's `spell-base/shards/`.
|
||||
Stack spell 706516 is in `00700000-00709999.jsonl.gz`, not a 7-million-ID shard.
|
||||
Formation/helper rows use `00803000-00803999.jsonl.gz`; 802629 uses
|
||||
`00802000-00802999.jsonl.gz`; 807728 uses `00807000-00807999.jsonl.gz`.
|
||||
`spell-base/Spell.colinfo.json` maps the positional fields.
|
||||
- July global snapshot: `data/coa-reference/snapshots/e86031775dfac7e336361087c50ca23a0a7a86c36a760c85803bee4bcdb89351/reference.json`.
|
||||
|
||||
All of the effect and text reconciliation above used cached/local records.
|
||||
It does not require recrawling the class database or downloading the client.
|
||||
|
||||
## Implementation follow-up, 2026-10-05
|
||||
|
||||
`coaAbilityCatalog.ts` now imports only the two evidenced rankless Guardian
|
||||
trainer actions through a class/source/level/DBC-identity allowlist. Tower is
|
||||
learned at level 4 and Line at level 20 under HealerMan's existing automatic
|
||||
level-learning model. A named trainer interaction is not reconstructed. Only
|
||||
Guardian records were regenerated in the runtime and UI catalogs.
|
||||
|
||||
`coaGuardianFormationRuntime.ts` projects each cast into one permanent,
|
||||
caster-owned self aura. Tower adds 10 percentage points of block, 50% of the
|
||||
actual equipped shield item's armor, and -10% outgoing damage. Line adds 15%
|
||||
movement speed and reduces roots by 25%: aura 232's misc value 7 identifies
|
||||
Root, so the caption's broader control wording is not applied to every control
|
||||
type. Footman's Calling adds -10% taken damage only while either own live form
|
||||
is active. Projection recomputes current talent/equipment contributions without
|
||||
requiring a recast; borrowed, expired and other-class markers do not qualify.
|
||||
No numerical threat multiplier is inferred. A shared exclusive group makes
|
||||
switching replace the old form as an explicit authored game policy; the source
|
||||
categories do not prove this behavior. Toggle-off remains unimplemented.
|
||||
|
||||
`coaGuardianParagonRuntime.ts` uses the August live node and compatible secondary
|
||||
text. Actual Heavy Blow successes add three stacks and actual blocks add one,
|
||||
with a 500 ms block-stack internal cooldown and 10-second stack lifetime.
|
||||
At ten stacks, 707138 represents readiness only. Heavy Blow retains its action
|
||||
identity, talent gate, cost and cooldown while projecting to an 8-yard self
|
||||
area strike for 144 + 37% AP. SpellRadius.dbc row 14 in the local patch-S
|
||||
extraction confirms the 8-yard radius. Only a successful Smash creates 803432's
|
||||
10-second +10-point block buff with five block charges. Each actual block while
|
||||
that buff is live consumes one charge and reduces an active Brace cooldown by
|
||||
two seconds for the player or companion authority and its mirrored member.
|
||||
Readiness itself grants no defensive bonus. Stack reset/consumption is not
|
||||
encoded in the inspected source, so no reset rule is invented; a later qualifying
|
||||
event can establish readiness again after its prior window expires.
|
||||
|
||||
The player executor, companion executor/scorer, benchmark selector and HUD use
|
||||
the same cast projection. Player and party movement consume the owned Line
|
||||
modifier. Vanguard companions prepare Tower through normal learned-action,
|
||||
readiness, target and resource checks, preserving an already chosen Line.
|
||||
Actual cast/block integration fixtures and the source conflicts above remain
|
||||
separate from balance certification. Live results and required checks are
|
||||
recorded in `docs/COA_FIRST_PARTY_MILESTONE.md` and `PLAYTEST_NOTES.md`.
|
||||
|
||||
Companion Smash selection is explicitly authored: priority 7,500 for Vanguard
|
||||
tanks at or above 55% health, fallback preference 40 otherwise. Unmasked public
|
||||
scorer checks choose ready Smash over routine Ballad when healthy, retain real
|
||||
mitigation when injured, and preserve urgent taunt/interrupt scores. The exact
|
||||
source optimal rotation remains unknown. Focused Guardian/helper/party checks,
|
||||
Ready-five compatibility and the production build pass; see the milestone for
|
||||
complete validation scope and the bounded live evidence.
|
||||
|
||||
Actual browser entry also exposed generic free preparation of both raw forms
|
||||
and loss of a saved Heavy Blow talent binding. Final regressions cover the
|
||||
source fixes: generic precombat effect selection excludes the two real forms,
|
||||
while character initialization validates saved nonpassive class actions against
|
||||
a separate allowlist before rejecting unlearned talent slots. These fixes retain
|
||||
normal resource payment, the authored exclusive group and the original default
|
||||
bar order. The selected five remain Needs Testing.
|
||||
@@ -0,0 +1,99 @@
|
||||
# Disarm weapon contribution audit — 2026-10-05
|
||||
|
||||
This pass adds reusable character-side projections for item-dependent auras,
|
||||
spell-selected weapon channels, and temporary weapon damage under the
|
||||
source-backed Ascension/Epoch Disarm tags. The helpers are in
|
||||
`src/game/enemyDisarmRuntime.ts`; the checks are in
|
||||
`src/game/enemyDisarmRuntime.test.ts`.
|
||||
|
||||
## Core behavior verified
|
||||
|
||||
In the read-only historical AzerothCore tree, `SpellAuraEffects.cpp` maps Aura
|
||||
67/254/278 to main-hand/off-hand/ranged flags. Applying Disarm recalculates the
|
||||
player's item-dependent auras and weapon damage while retaining equipped item
|
||||
stats. Removing Disarm clears the flag and recalculates the affected channel's
|
||||
weapon auras. Creature spells use `Spell::CheckItems` to reject damage-class
|
||||
melee/ranged spells whose selected attack type is unavailable.
|
||||
|
||||
`Player::HasItemFitToSpellRequirements` searches other usable equipped items
|
||||
for a class/subclass/inventory-mask match. Passive item-requirement auras are
|
||||
removed when Disarm leaves no matching usable weapon. The core keeps an active
|
||||
nonpassive aura spell through the specific aura-cast exception. Separately,
|
||||
`UpdateWeaponDependentAuras` recalculates weapon-aura contributions per attack
|
||||
type, and `CheckAttackFitToAuraRequirement` tests the item in that channel.
|
||||
|
||||
`Spell` selects main-hand for a melee damage-class spell by default and
|
||||
off-hand when AttributesEx3 `0x01000000` is set. A ranged damage-class spell
|
||||
uses ranged when the core classifies it as a ranged-weapon spell; that decision
|
||||
uses AttributesEx `USES_RANGED_SLOT` (`0x00000002`), the ranged weapon subclass
|
||||
mask, or a Hunter-family exception. Other ranged damage-class spells use the
|
||||
main-hand attack type. The player item check does not impose a blanket gate on
|
||||
all physical damage-class casts.
|
||||
|
||||
The source was read from:
|
||||
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/Auras/SpellAuraEffects.cpp`
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Player/Player.cpp`
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/Spell.cpp`
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/SpellInfo.cpp`
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/shared/SharedDefines.h`
|
||||
- `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Item/ItemTemplate.h`
|
||||
|
||||
## Helper contracts
|
||||
|
||||
`enemyDisarmItemDependentAuraSuppressionIds` returns source-caster-owned
|
||||
passive aura instance IDs whose matching equipped weapon slots are all
|
||||
disabled. It preserves nonpassive aura spells and the stored aura state, so a
|
||||
caller can build an effective combat aura view that restores the passive
|
||||
contribution automatically when Disarm expires.
|
||||
|
||||
`enemyDisarmAurasForWeaponChannel` creates the attack-type-specific aura view.
|
||||
It keeps an item-requirement aura contribution only when the selected usable
|
||||
weapon matches the aura requirement, and suppresses it while that channel is
|
||||
disarmed. This allows an enabled matching off-hand contribution to remain
|
||||
available while the main-hand calculation uses the unarmed profile.
|
||||
|
||||
`enemyDisarmAbilityWeaponChannel` mirrors the source spell attack-type choice.
|
||||
`enemyDisarmAdjustedAbilityWeapon` returns the 1–2 damage, 2-second unarmed
|
||||
main-hand profile, no weapon for disabled off-hand/ranged channels, or the
|
||||
unchanged weapon for other channels. Feral main-hand weapon stats remain
|
||||
unchanged. `enemyDisarmBlocksNpcWeaponAbility` exposes the NPC-only selected
|
||||
damage-class channel gate separately from player ability requirement checks.
|
||||
|
||||
## Integration boundary and limits
|
||||
|
||||
The party runtime uses `effectiveActorAuras` for global passive suppression and
|
||||
channel-specific weapon-aura views. Party ability casts retain the player-style
|
||||
equipped-item requirement gate, and generic amount calculations receive the
|
||||
member's active Disarm channel set so source-selected weapon contribution can
|
||||
be adjusted without rejecting unrelated physical casts. Party main-hand autos
|
||||
use the source 1–2 / 2-second WoW punch; the dual-wield integration case confirms
|
||||
an enabled off-hand still contributes. The party auto path also asks the native
|
||||
Runewaker helper for a verified unarmed main-hand profile and cadence, while
|
||||
ranged autos retain their existing channel behavior. Periodic party effects
|
||||
are applied through `CombatStore.applyTimedActorEffect`; its native snapshot
|
||||
path checks the source actor's active main-hand channel before passing the
|
||||
verified profile into the native periodic calculator.
|
||||
|
||||
Generated party characters use the player's class item-requirement rules. The
|
||||
hostile creature `Spell::CheckItems` channel gate remains available as a
|
||||
separate helper and is not imposed on party class builds. The centralized
|
||||
combat store owns the player and party passive-aura projection and generic
|
||||
ability weapon contribution. The simulator still cannot infer item durability
|
||||
or equipment eligibility missing from its resolved loadout.
|
||||
|
||||
Native Runewaker unarmed main-hand damage is implemented only when the active
|
||||
five training profile is source-verifiable. Its sidecar does not model
|
||||
`Main_DMG_Per`, `DMG_AllWeapon`, `DMG_Unarmed`, `AtkSpeed`, `Main_ATKSpeed_Per`,
|
||||
`AttackSpeed_AllWeapon`, or `AttackSpeed_Unarmed`; those rate channels remain an
|
||||
explicit neutral-rate boundary. Unsupported profiles keep their existing
|
||||
fallback behavior rather than borrowing the WoW punch profile.
|
||||
|
||||
## Focused validation
|
||||
|
||||
`npx vitest run src/game/enemyWeaponDebuffs.test.ts
|
||||
src/game/enemyDisarmRuntime.test.ts
|
||||
src/game/enemyDisarmRuntime.integration.test.ts
|
||||
src/game/romNativeDisarm.test.ts` passes: 4 files, 21 tests. The party integration
|
||||
tests cover player and companion cast handling, an enabled party off-hand, native
|
||||
main-hand damage/cadence, and the existing ranged Scout channel behavior.
|
||||
@@ -3,11 +3,13 @@
|
||||
Use this runbook for requests to inspect or fix the current dungeon reports.
|
||||
It is intentionally repo-relative except for the production endpoint.
|
||||
|
||||
Routine mechanic/browser QA defaults to **Stormwind Stockade**
|
||||
(`stormwind-stockade`), including Hamhock for generic Boss Testing. See
|
||||
`docs/TEST_DUNGEON_POLICY.md` and `AGENTS.md`. A report tied to a specific dungeon
|
||||
still requires inspecting that source and the user's authorized reproduction;
|
||||
existing Wailing reports do not make it the default test dungeon.
|
||||
Routine mechanic/browser QA defaults to **Stormwind Stockade: Cellblock Rush**
|
||||
(`bite-sized-stormwind-stockade`). Each run selects one Stockade boss from its
|
||||
shared run ID, so record the boss actually observed. Isolated Boss Testing has
|
||||
its separate Hamhock default; full-source Stockade campaigns require explicit
|
||||
selection. See `docs/TEST_DUNGEON_POLICY.md` and `AGENTS.md`. A report tied to a
|
||||
specific dungeon still requires inspecting that source and the user's authorized
|
||||
reproduction; existing Wailing reports do not make it the default test dungeon.
|
||||
|
||||
## 1. Read the live queue first
|
||||
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
# Automatic enemy offhands — 2026-10-05
|
||||
|
||||
Current source-table recovery supersedes the missing equipment-map limitation
|
||||
recorded below. See [the 2026-10-06 equipment mapping audit](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md)
|
||||
for the pinned SQL, Item.dbc validation, importer output, and runtime helper.
|
||||
|
||||
## Result
|
||||
|
||||
Added narrow helpers for the two historical AzerothCore automatic offhand
|
||||
gates: the creature-template `USE_OFFHAND_ATTACK` flag and the default `AUTO`
|
||||
mode's resolved offhand weapon check. The flag helper binds only the five
|
||||
matching creatures present in HealerMan's imported template-reference subset.
|
||||
The item helper requires a nonzero item ID and an already resolved Item.dbc
|
||||
class of `WEAPON` (2). It does not map an `equipment_id` to an item because
|
||||
that table is absent from the pinned world import.
|
||||
|
||||
The helpers are in [enemyAutomaticOffhand.ts](../src/game/enemyAutomaticOffhand.ts).
|
||||
They do not schedule attacks or mutate combat state. Runtime should treat
|
||||
`enemyFlagDrivenOffhandContract(entry)` as an intrinsic creature capability and
|
||||
feed it into the existing ordinary WoW offhand path. Keep this source flag
|
||||
separate from the simulator's temporary spell-granted capability: core sets the
|
||||
flag mode in creature initialization and entry updates, so evade, death, and
|
||||
encounter reset must not clear it while the creature entry remains the same.
|
||||
The simulator's existing reset policy can continue to clear spell-granted
|
||||
Dual Wield state.
|
||||
|
||||
`enemyAutoEquippedOffhandContract({ entry, name?, offhandItemId,
|
||||
offhandItemClass })` resolves the default `AUTO` item gate only after a caller
|
||||
has loaded the actual offhand virtual item and looked up its class. An absent,
|
||||
zero, unresolved, or non-weapon item returns no contract. Do not use a model,
|
||||
creature appearance, or `equipment_id` alone as a substitute for the missing
|
||||
slot-to-item mapping. Keep both helpers on the source WoW creature path; the
|
||||
existing RuneWaker, summon, and character-defender exclusions remain in force.
|
||||
|
||||
## World source and coverage
|
||||
|
||||
The imported AzerothCore world source is commit
|
||||
`4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`. Its lock pins `creature.sql` at
|
||||
SHA-256 `f54ddfe7ee00080b4b0bc970a809d6f947f6fb2627dbcd67e92b402fb34cb701`
|
||||
and `creature_template.sql` at SHA-256
|
||||
`0066e4fd35b809986dd325487515087f5a95f4ffe50ea03846c8d8bf5196870a`.
|
||||
`creature_template.sql` has 29,947 rows, 43 of which set
|
||||
`flags_extra & 0x00000800`. The imported runtime reference contains 1,671
|
||||
creature templates; five carry that bit:
|
||||
|
||||
| Entry | Creature | `flags_extra` |
|
||||
| ---: | --- | ---: |
|
||||
| 4540 | Scarlet Monk | 2048 |
|
||||
| 10478 | Splintered Skeleton | 2048 |
|
||||
| 10488 | Risen Construct | 2048 |
|
||||
| 16593 | Shattered Hand Brawler | 134219776 |
|
||||
| 16808 | Warchief Kargath Bladefist | 2048 |
|
||||
|
||||
The source lock includes `creature.sql` rows with an `equipment_id` field, but
|
||||
does not include `creature_equip_template.sql`. The pinned spawn table has
|
||||
149,879 rows; 51,248 have a nonzero `equipment_id` value (the distinct values
|
||||
are `-1`, `1`, and `2`). Those values select equipment-set IDs; they do not
|
||||
identify an offhand item by themselves.
|
||||
|
||||
I found `creature_equip_template.sql` in two local AzerothCore backup trees:
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk/data/sql/base/db_world/creature_equip_template.sql`
|
||||
and
|
||||
`../WoW-Pvt-Server-Backups/azerothcore-wotlk/data/sql/base/db_world/creature_equip_template.sql`.
|
||||
The copies are byte-identical at SHA-256
|
||||
`D95423028E4D9CD7068E317BDE66ED847DC8238F4A6AA952D9EA40EF36109A1A`, and their
|
||||
rows include Stockade mappings such as `1696/1 -> 5305, 5305`,
|
||||
`1711/1 -> 2184, 2184`, and `1716/1 -> 2179, 1897`. These are useful leads,
|
||||
but they are not bound to this import: the adjacent archived
|
||||
`creature_template.sql` and `creature.sql` hashes are respectively
|
||||
`e20e921613a02f8a86e997fd0d1d959dbe868bd6886151c8ca5f6c187a549356` and
|
||||
`135c78413da1bbbce0c65ee4ee833c0f19343933b3a0e30f82ff023f37aa6164`, which
|
||||
do not match the pinned inputs. The equipment-table path is also absent from
|
||||
the pinned Git tree. The importer therefore does not bind those mappings.
|
||||
|
||||
The local WotLK client
|
||||
`../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc` and AzerothCore server
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk/data/Item.dbc` have the same
|
||||
SHA-256:
|
||||
`22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f`.
|
||||
`ItemEntry::ClassID` is field 1 in the core DBC structure and the client DBC
|
||||
uses the matching `Class` field. Item class 2 is `ITEM_CLASS_WEAPON`. The core
|
||||
`Creature::HasWeapon(OFF_ATTACK)` checks only that the offhand virtual item
|
||||
resolves and its class is weapon; it does not check subclass or inventory type.
|
||||
This pins the gate logic and the local DBC bytes, but does not supply the
|
||||
missing equipment-set-to-item mapping for the locked world rows.
|
||||
|
||||
## Core behavior reference
|
||||
|
||||
The behavior audit uses the local read-only AzerothCore checkout at HEAD
|
||||
`e822d718322289dd036fb2daf8867ba41283bf9a`. This is a core-behavior reference,
|
||||
not the world-data commit above.
|
||||
|
||||
- `CreatureData.h:57` defines `CREATURE_FLAG_EXTRA_USE_OFFHAND_ATTACK = 0x800`.
|
||||
- `Creature::InitEntry` and `Creature::UpdateEntry` set
|
||||
`DualWieldMode::ENABLED` when the flag is present (`Creature.cpp:565-566,
|
||||
614-615`).
|
||||
- `Creature::HasWeapon(OFF_ATTACK)` returns true in `ENABLED` mode. In `AUTO`
|
||||
mode it resolves virtual item slot 1 and accepts only a valid item whose
|
||||
`ClassID == ITEM_CLASS_WEAPON` (`Creature.cpp:3299-3317`). The core enum is
|
||||
in `Unit.h:587-590`; `ITEM_CLASS_WEAPON` is 2 at `ItemTemplate.h:293`.
|
||||
- `Creature::SelectLevel` initializes both base and offhand from the same
|
||||
generated creature range (`Creature.cpp:1540-1549`).
|
||||
`Creature::CalculateMinMaxDamage` uses the same range, template variance,
|
||||
attack-power contribution, and damage modifier for either hand
|
||||
(`StatSystem.cpp:1119-1167`). `UNIT_MOD_DAMAGE_OFFHAND` applies the default
|
||||
0.5 total damage factor (`Unit.cpp:401`).
|
||||
- Both swing timers use `CreatureTemplate.BaseAttackTime`
|
||||
(`Creature.cpp:617-618`). Ordinary white swings add 19 percentage points to
|
||||
miss chance when an offhand is available (`Unit.cpp:15288-15290`). The
|
||||
existing Dual Wield source contract supplies the half-swing initial offset
|
||||
and 200 ms simultaneous-swing presentation stagger.
|
||||
|
||||
Relevant paths in the reference checkout are `src/server/game/Entities/Creature/CreatureData.h`,
|
||||
`src/server/game/Entities/Creature/Creature.cpp`,
|
||||
`src/server/game/Entities/Unit/StatSystem.cpp`,
|
||||
`src/server/game/Entities/Unit/Unit.cpp`,
|
||||
`src/server/game/Entities/Unit/Unit.h`,
|
||||
`src/server/game/Entities/Item/ItemTemplate.h`, and
|
||||
`src/server/shared/DataStores/DBCStructure.h`.
|
||||
|
||||
## Validation and limits
|
||||
|
||||
`npm test -- --run src/game/enemyAutomaticOffhand.test.ts` passes four focused
|
||||
tests. npm's `pretest` hook also ran the existing loot-catalog generator; it
|
||||
reported the existing 9-boss/23-item catalog, with no loot-file change.
|
||||
|
||||
The flag path is implemented from the locked creature-template data. The AUTO
|
||||
path is implemented as a strict, reusable item-class gate, but no locked world
|
||||
equipment mapping currently supplies it with item IDs. Exact automatic
|
||||
offhand availability for the imported `equipment_id` and template-default
|
||||
cases remains unresolved until a matching equipment-template source is pinned
|
||||
or imported.
|
||||
@@ -0,0 +1,90 @@
|
||||
# Enemy Bloodlust source contract — 2026-10-05
|
||||
|
||||
`src/game/enemyBloodlust.ts` records the sourced NPC contract for spell 6742
|
||||
and exposes the melee swing-interval calculation used when independent
|
||||
Aura 138 haste effects overlap. It models one explicitly selected friendly
|
||||
creature per application. It does not infer Shaman player-party semantics from
|
||||
the similarly named player spell.
|
||||
|
||||
## Pinned client rows
|
||||
|
||||
The active 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`). Both
|
||||
contain the same spell 6742 fields:
|
||||
|
||||
| Spell.dbc field | Value |
|
||||
| --- | ---: |
|
||||
| Range index | 4 |
|
||||
| School mask / damage class | 8 / 1 |
|
||||
| Duration index / resolved duration | 9 / 30,000 ms |
|
||||
| Dispel / stack amount | 1 (Magic) / 0 |
|
||||
| Attributes 0–7 | 0 |
|
||||
| Effect | 6 (`APPLY_AURA`) |
|
||||
| Aura / base points | 138 (`MOD_MELEE_HASTE`) / +30 |
|
||||
| Implicit targets A / B | 21 (`TARGET_UNIT_TARGET_ALLY`) / 0 |
|
||||
| Radius / misc value / period | 0 / 0 / 0 |
|
||||
| Trigger spell | 0 |
|
||||
|
||||
The duration comes from the pinned shared patch-S SpellDuration.dbc
|
||||
(`eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`); the
|
||||
shared SpellRadius.dbc fallback is
|
||||
`dba6ed2f165f75c84dda5f32ae46b1a01fe562efd88fa51fd19365705c3e6a44`. SpellRange
|
||||
index 4 comes from shared patch-S SpellRange.dbc (SHA-256
|
||||
`bb899631818942a7a7100abfb7a970612a79ac99637b1b459561e2b108125ddd`): both
|
||||
friendly and hostile ranges are 0–30 yards, with flags 0. This row and the
|
||||
effect target describe a selected friendly unit, not an area target; the
|
||||
effect has no radius.
|
||||
|
||||
## Historical NPC selection and cast gates
|
||||
|
||||
The read-only AzerothCore world snapshot's `creature_template_spell.sql` lists
|
||||
Hamhock (entry 1717) with spells 6742 and 421. Its `smart_scripts.sql` rows
|
||||
provide two separate Bloodlust paths:
|
||||
|
||||
- Update-in-combat event 0 has a fixed 5,000 ms initial delay, no repeat timer,
|
||||
100% chance, and NOT_REPEATABLE flag 1. It casts spell 6742 with cast flags
|
||||
32 (`SMARTCAST_AURA_NOT_PRESENT`) on target type 1 (self). AzerothCore only
|
||||
processes this event while Hamhock is engaged; the cast flag skips recasting
|
||||
while that target already has Bloodlust.
|
||||
- Friendly-missing-buff event 16 uses spell 6742, radius 30, repeat interval
|
||||
10,000 ms, and `onlyInCombat=0`. It casts spell 6742 with flags 0 on target
|
||||
type 7 (`SMART_TARGET_ACTION_INVOKER`), the selected missing-buff recipient.
|
||||
The event starts active without an initial delay and resets its 10-second
|
||||
repeat timer after it processes a recipient.
|
||||
|
||||
The historical `FriendlyMissingBuffInRange` predicate further requires the
|
||||
candidate creature to be alive, in combat, non-hostile to the caster, within
|
||||
30 yards on the same map and phase, and missing spell 6742. The search uses a
|
||||
creature-list searcher, so this AI path selects creatures rather than the
|
||||
player party. Its predicate has no self-exclusion or line-of-sight check;
|
||||
the normal, untriggered cast still uses ordinary spell validation. Distance
|
||||
checks include the source and target object sizes. These are source gates; the
|
||||
current game entity state has no faction, phase, or collision-radius data and
|
||||
must document its corresponding selection approximation.
|
||||
|
||||
## Haste stacking
|
||||
|
||||
AzerothCore maps Aura 138 to `HandleModMeleeSpeedPct`, which applies a separate
|
||||
percentage attack-speed factor to main-hand and off-hand swing intervals. The
|
||||
same-effect spell-group lookup suppresses weaker members only when the data
|
||||
places them in an exclusive group. The historical `spell_group.sql` does not
|
||||
place either 6742 or Enrage 8599 in its “Melee Haste Buffs” group. Their two
|
||||
+30% effects therefore combine as separate factors: an active Bloodlust and
|
||||
Enrage yield `1 / (1.3 × 1.3)`, or about 0.591716 of the prior swing interval.
|
||||
They do not become one additive +60% modifier (0.625 interval factor).
|
||||
|
||||
`enemyMeleeHasteIntervalMultiplier` applies the sourced positive and negative
|
||||
Aura 138 interval factors to marked source modifiers in the already-filtered
|
||||
active aura list for one enemy, then preserves the existing additive interval
|
||||
calculation for unmarked haste modifiers. It leaves auto-attack ability
|
||||
cooldowns and unrelated haste channels unchanged. The Bloodlust contract
|
||||
itself exposes only melee haste, Magic dispel, a 30-second duration, and the
|
||||
explicit-friendly 30-yard target shape.
|
||||
|
||||
Focused validation is `npx vitest run src/game/enemyBloodlust.test.ts src/game/enemyBloodlust.integration.test.ts`.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Enemy control hit and immunity follow-up — 2026-10-06
|
||||
|
||||
## Finding
|
||||
|
||||
There is no complete, source-bounded generic hit helper to add for shout control. The pinned rows do establish ordinary miss, resist, and deflect gates for the rows whose `DamageClass` is Magic, but AzerothCore computes those outcomes from the live caster, defender, full `Spell`, world miss-rate policy, and random roll. The None-class children take a different branch and do not receive those Magic hit rolls. A fixed miss percentage or a helper that accepts only a spell ID and `CharacterDefender` would not match the source.
|
||||
|
||||
Historical behavior below is pinned to read-only AzerothCore `e822d718322289dd036fb2daf8867ba41283bf9a`. The active HealerMan runtime and generated data remain authoritative for implementation. The earlier [shout speed and immunity audit](ENEMY_SHOUT_SPEED_IMMUNITY_2026-10-06.md) records the client-profile hashes and full eight-word attribute tuples for these four spells.
|
||||
|
||||
## Pinned shout hit branches
|
||||
|
||||
All four spells have `SchoolMask=1` (Normal/physical) and spell-level `Mechanic=5` (Fear). The spell damage classes differ by row and profile:
|
||||
|
||||
| Spell | Ascension | Epoch | Core hit branch |
|
||||
| --- | --- | --- | --- |
|
||||
| 5246 parent | Magic | Magic | `MagicSpellHitResult` in both profiles |
|
||||
| 19134 parent | Magic | Magic | `MagicSpellHitResult` in both profiles |
|
||||
| 20511 child | Magic | None | Magic roll in Ascension; aura-only None handling in Epoch |
|
||||
| 29544 child | None | None | Aura-only None handling in both profiles |
|
||||
|
||||
The `Unit::SpellHitResult(Unit*, Spell const*, bool)` overload first checks whole-spell and effect immunities, then dispatches by `DamageClass` (`Unit.cpp:3706–3790`). A Magic-class shout therefore reaches `MagicSpellHitResult` despite its physical school. That routine (`Unit.cpp:3503–3634`) calculates miss from relative caster/defender levels, configured miss multipliers, caster spell modifiers and hit bonuses, defender hit-taken and area-avoidance bonuses, and player hit-taken rating. It then adds mechanic and eligible debuff resistance. The extra binary-school resistance term does not apply to these Normal-school rows. Deflect is possible when the target is in the caster's front arc (or ignores hit direction), is not stunned, and has a deflect aura. The routines also depend on actor types and state such as vehicles, trigger creatures, and dead non-player targets.
|
||||
|
||||
These are source-representable gates only when the runtime can provide the relevant actors and spell context. The core call receives the original caster as `this`, the actual `Unit*` victim, and the active `Spell*`; `Spell::AddUnitTarget` calls it with `m_originalCaster` (`Spell.cpp:2293–2367`). A faithful integration needs the caster's target-relative level, hit and spell-modifier data, relevant owner/totem/vehicle state, and the defender's level, active immunities, mechanic/debuff resistance, hit-taken and area-avoidance data, facing, stun state, deflect/reflect auras, and evade/death state. It also needs the source row and the configured miss-rate policy. The current shout contract does not carry that information, and area recipients can include actor types outside player/party `CharacterDefender` snapshots.
|
||||
|
||||
For a None-class row, the source first performs its immunity checks, then returns a successful hit for a nonzero spell family or for aura-only effects (`Unit.cpp:3761–3790`). Child 20511 and 29544 are aura-only in both pins, so their None-class profiles have no ordinary Magic miss, resist, or deflect roll. Preserve this difference: a generic roll on every triggered child would add an unsupported Epoch 20511 and 29544 outcome.
|
||||
|
||||
The triggered child remains tied to the parent's explicit victim. The core records the parent's hit result per target, and runs target effects only for a successful hit (`Spell.cpp:2583–2637`); effect 0's trigger therefore runs only for the successful explicit-victim target. The current runtime validates that explicit victim's eligibility, range, and line of sight before selecting the child, then applies it directly in [combatStore.ts](../src/game/combatStore.ts) around the `triggered-shout` branch. Root integration should preserve that victim binding and place any supported parent hit gate before child execution.
|
||||
|
||||
## Whole-spell control immunity and active-aura purge
|
||||
|
||||
The shout rows set spell-level Fear, so the core checks Fear mechanic immunity against the whole spell before per-effect immunity (`Unit.cpp:10032–10120`). This rejects the parent and its riders as a whole. Child 20511 remains a Fear-mechanic spell even though its first aura is stun: fear immunity rejects the whole child; stun-state immunity is narrower and may strip the stun effect while leaving Ascension's separate physical-damage-taken rider. Epoch 20511 has no separate rider. These distinctions match the existing shout audit.
|
||||
|
||||
The local generated WoW 3.3.5a ability JSON was parsed and filtered by spell ID. Its imported Warrior rows identify Berserker Rage 18499 and Bladestorm 46924 as immunity candidates. The generator now preserves raw `attributes1` and `attributes5` alongside the selected spell-defense metadata, and apply-aura effects retain raw base-points, die-sides, and points-per-level scalars. I read the corresponding raw Spell.dbc fields from the local `patch-enUS.MPQ` to establish the purge bit rather than inferring it from tooltips:
|
||||
|
||||
| Imported spell | Relevant generated effect | Raw `Attributes1` | Source result |
|
||||
| --- | --- | ---: | --- |
|
||||
| 18499 Berserker Rage | Aura 77, mechanic immunity value 5 (Fear) | `32768` (`0x00008000`) | Grants Fear immunity and carries the purge flag |
|
||||
| 46924 Bladestorm | Aura 147, mechanic-immunity mask value 1733; calculated amount is zero | `32784` (`0x00008010`) | Carries the purge flag; the pinned core maps this zero-amount mask to Fear and Stun immunity |
|
||||
| 49039 Lichborne | Aura 77, mechanic immunity value 5 (Fear) | `163872` (`0x00028020`) | Grants Fear immunity and carries the purge flag |
|
||||
| 48792 Icebound Fortitude | Aura 77, mechanic immunity value 12 (Stun) | `0` | Stun immunity, but this source row does not prove active-aura purge |
|
||||
|
||||
The selected rows used by the runtime proof also require these exact raw values:
|
||||
|
||||
| Spell | Attributes0 | Attributes1 | Attributes3 | Attributes5 | Raw immunity effect |
|
||||
| --- | ---: | ---: | ---: | ---: | --- |
|
||||
| 18499 Berserker Rage | `327696` | `32768` | `0` | `0` | Effect 0: aura 77, misc 5 (Fear), raw base points -1, die sides 1 |
|
||||
| 46924 Bladestorm | `327696` | `32784` | `1024` | `512` | Effect 1: aura 147, misc 1733, raw base points -1, die sides 1 |
|
||||
|
||||
`SPELL_ATTR1_IMMUNITY_PURGES_EFFECT` is `0x00008000` in `SharedDefines.h:422`. On applying an immunity aura with a mechanic mask, `SpellInfo::ApplyAllSpellImmunitiesTo` removes existing auras matching that mask when the flag is set (`SpellInfo.cpp:2488–2537`). The pinned core maps Bladestorm's 1733 mask with zero calculated amount to a mask that includes both Fear and Stun (`SpellInfo.cpp:2355–2377`). Thus Berserker Rage and Bladestorm are concrete imported examples of active shout removal: Berserker Rage covers Fear; Bladestorm's sourced mask covers Fear and Stun. The shout rows themselves do not set this purge attribute.
|
||||
|
||||
The cast exception is narrower than the aura grant. Berserker Rage has no `Attributes5` allow-while-stunned/fleeing/confused bit, yet its Fear aura and purge flag let the core's `Spell::CheckCasterAuras` ignore active Fear-mechanic auras during its cast check (`Spell.cpp:6830–6978`). That includes the `20511` child: although its effect is stun, its applied aura carries spell-level Mechanic=FEAR, so the core skips that whole aura before the stun-state check. A standalone stun aura remains blocking. Bladestorm has `Attributes5=512` (`EXTRA_INITIAL_PERIOD`), not an allow-while-stunned or allow-while-fleeing flag; it cannot start while feared or stunned in this source path, even though its applied aura later grants both immunities.
|
||||
|
||||
## Evidence and implementation boundary
|
||||
|
||||
The ignored [parsed source audit artifact](../artifacts/enemy-control-followup-2026-10-06/source-audit.json) retains the parsed generated rows, raw Spell.dbc attribute words, and raw effect fields for the cited WoW 3.3.5a spells. The bounded helper in [enemyControlImmunityPurge.ts](../src/game/enemyControlImmunityPurge.ts) accepts only the exact selected WoW rows and fails closed on unknown profiles, IDs, raw flags, or aura scalars. It distinguishes direct Fear from Bladestorm's Fear-and-Stun grant, records that only Berserker Rage is usable while feared, and scopes cleanup to the four named shout source auras. Since each shout has spell-level Mechanic=FEAR, the Fear purge removes the named 20511 child aura as a whole, including any rider bundled into that runtime aura. A separate generic stun remains active and can keep the target controlled; Icebound Fortitude stays outside the purge path because it has no raw purge flag.
|
||||
|
||||
Party AI uses the same selected Berserker Rage proof to escape a named shout Fear, or its Fear-mechanic 20511 stun. It preserves learned-rank selection, target validity, cooldown, GCD, and costs. The context check requires active action-blocking control auras on that companion to be covered by the named source shout proof, so an unrelated generic stun blocks the escape. The broad Magic hit/resist/deflect helper remains unsupported because the full source inputs are absent.
|
||||
|
||||
Focused verification passed: the immunity helper, direct-grant integration, and party escape integration tests (19 tests across 3 files). No build, release check, or live run was performed in this scoped task.
|
||||
@@ -0,0 +1,39 @@
|
||||
# Enemy control runtime follow-up — 2026-10-06
|
||||
|
||||
Shield Bash's missing Daze, safe source-informed fear movement and source-proven immunity escape/purge are integrated. The level-80 cap, Ready-five certification scope and existing loot behavior remain intact. All 126 focused checks across 15 files pass; Ready-five adds seven Vitest and twenty Python checks. The final 8 GB TypeScript/Vite build, asset audits and release-bundle verification pass.
|
||||
|
||||
## Behavior and ownership
|
||||
|
||||
- `wow335ShieldBashDaze.ts` registers child 29703 for the exact selected WoW335 Shield Bash 72 parent and ordinary source NPCs. It applies a 50% movement slow for six seconds. Source mechanic 11 is **SNARE**, despite the Dazed display name. Snare/physical-school immunity rejects the child; parent interruption remains independent. Full parent blocking/avoidance suppresses the trigger. CoA/RoM parents, unbound ranks/procs and excluded defenders cannot borrow it. The generated playable Shield Bash chain has one rank, 72, through level 80.
|
||||
- `enemyFearMovement.ts` and `enemyFearMovementRuntime.ts` implement deterministic destination selection within the pinned core's distance/path/retry ranges, live caster lookup, actor-local goal caching and the five-path-failure fallback. They are source-informed simulator policy, not exact server paths or RNG.
|
||||
- PlayerRig follows accepted waypoints through the existing collision controller and gravity. PartyPopulation follows approved navigation at normal actor speed, including forced movement under Stop. Source fear cannot enable catch-up speed or stuck-recovery relocation. Shorter overlapping stun/confuse/root/sleep auras hold movement even when fear owns the longest timer. Voluntary movement/jumping and ordinary attacks/casts stay blocked.
|
||||
- `enemyFearSummonMovement.ts` moves mobile owned summons only on a loaded graph with approved projection, LOS, path and bounded steps. The real combat tick suppresses actions while source fear remains. Pet Prowl and actor-local source speed are retained; totems/zones remain stationary.
|
||||
- The WoW generator retains raw Attributes1/5 and imported apply-aura scalar signatures. `enemyControlImmunityPurge.ts` proves only exact Berserker Rage 18499 and Bladestorm 46924 grants. Applying the proven grant removes whole named FEAR-mechanic shout auras 5246/19134/20511/29544, including bundled riders, while retaining unrelated controls. Player/party Berserker Rage can escape the covered source fear or 20511's FEAR-mechanic stun. Other stuns, cooldowns and GCD still block it. Bladestorm has no controlled-casting bypass. Icebound Fortitude has no sourced active-purge flag.
|
||||
|
||||
The matching source and limitations are in [the Daze import](WOW335_SHIELD_BASH_DAZE_2026-10-06.md), [fear audit](ENEMY_FEAR_MOVEMENT_2026-10-06.md) and [hit/immunity audit](ENEMY_CONTROL_HIT_IMMUNITY_FOLLOWUP_2026-10-06.md). Historical sources were read only.
|
||||
|
||||
## Verification
|
||||
|
||||
The focused report is `artifacts/enemy-control-followup-2026-10-06/focused-vitest.json`: 126/126 checks, 15 files, zero failures. It covers actual player casts and companion completion/AI, parent blocking and dispatch gates, movement expiry, missing/blocked navigation, overlapping controls, accepted immunity grants and authoritative party control state. The rejection fixtures temporarily perturb the canonical learned catalog and restore it in `finally`; those are synthetic source-gate fixtures, not live casts from another game profile.
|
||||
|
||||
GPT-6 Luna extra-high handled immunity proof/party escape and the read-only runtime review. Both finished; the reviewer found no actionable runtime bugs. The Daze and fear workers hit Luna capacity, so root completed their remaining implementation/integration and verification. No higher-tier subprocess was used. Root also repaired generated TypeScript emission/type declarations needed by concurrent native-lighting edits; the six native-lighting sanity fixtures passed once those inputs settled. This is not a new native balance certification or a claim of ownership over the concurrent lighting feature.
|
||||
|
||||
The final build SHA-256 is `2ded1eedcf7cfb60d53f6c82a33c088c05ff4d881bb258852c035df94770c8d1`. Build output and all referenced content objects were copied and hash-verified before the final one-boss Cellblock Rush run. The earlier content freeze could not be reused because the shared manifest changed.
|
||||
|
||||
## Final Cellblock Rush evidence
|
||||
|
||||
Run `20261006-172609059`, shared run ID `83b375bf-95bd-4afb-8ac1-7438b7a9d13f`, selected Hamhock through normal Bite-Sized selection: entry 1717, actor/spawn `creature-79098`. Native required and killed IDs both contain exactly that boss. The results overlay records **1/1 in 03:09.7**, with zero player/party deaths and four companions alive. The UI-created Discipline Priest used isolated pre-entry level-30 preparation, ordinary controls and read-only telemetry; no combat-state writes or Boss Testing were used. Seven ordinary healing windows were accepted and effective, totaling 2,444 effective player healing with zero recorded overheal. The owned helper, server and browser completed and cleaned up.
|
||||
|
||||
The committed-state recorder retained **797 consecutive events, IDs 9–805**, with zero gaps, errors or discarded events. It records 70 NPC hand results and 161 player/party hand results. Three actual party Shield Bash parent results, IDs **574, 659 and 777**, immediately precede accepted child 29703 aura grants **575, 660 and 778** on Hamhock. This is live dispatch/application evidence; no retained slow-state sample measures the six-second duration or half-speed movement. Those values are established by the actual runtime fixtures. Two Disarm windows contain four actor-hand results; utility snapshots include two Disarm, 38 Wound and nine Bloodlust observations. Offhand, Thrash, block and source-shout applications are unobserved in this seed. Fear locomotion and immunity escape/purge remain focused-runtime evidence, not credited live shout demonstrations.
|
||||
|
||||
Root visually inspected the real roster, equipped-party, route-50 and results PNGs under `campaign/final-build-20261006-172611414/`. Player and companion bodies, robe/shoulders and staff/shield/weapon silhouettes render; close stair clustering limits individual companion gear identification. `bite-sized-stormwind-stockade-boss-arrival.png` shows the native results overlay, despite its historical filename. Nine PNGs actually exist. Camera-drag paths declared by the route are absent from that list and from disk, so this run supplies no live camera-drag proof. The unchanged look behavior has 33 passing input regressions. There are zero page exceptions; the only browser console error is a favicon 404.
|
||||
|
||||
The fresh snapshot is `artifacts/enemy-control-followup-2026-10-06/frozen-20261006-172147833/`. It contains 5,967 build files (118,392,707 bytes) and a complete copied content manifest, version `content-2160be7ff070205b`, SHA-256 `85fc9f1c504c82aa794806b8a634596a07b34ba63e0bf66530243fe76e2d0356`. All 27,587 referenced objects (6,568,369,443 bytes; 21,605 logical entries) were verified before QA. Build and content fingerprints remain unchanged before/after the run. Root's labeled audit rehashes every frozen build file, seven loaded chunks and all 2,124 actually served manifest objects (77,019,550 bytes), then checks event continuity, boss identity and native completion; it passes with zero integrity failures. Recorded successful URLs/status metadata match immutable local sources. Raw network response bodies were not retained, so independent response-body hashing is not claimed.
|
||||
|
||||
The live record, utility events and root integrity audit are under `playtest-artifacts/stockade-weapon-utilities/20261006-172609059/`. Historical full-clear field names certify only the entered one-boss slice. No gameplay source changes or additional live runs followed the freeze.
|
||||
|
||||
The Luna extra-high evidence-review subprocess completed an independent read-only check of the captured run, matching the seeded boss/native result, unchanged fingerprints, root integrity audit, event continuity and three Daze grant pairs. It also confirmed the absent slow-state/camera evidence and the results image's historical filename. One adjacent event timestamp pair, IDs 714/715, runs backward by 1 ms; event IDs remain distinct and consecutive, so timestamp monotonicity is not claimed. Final game release hygiene, including untracked paths, and the task's separate vault diff/text checks pass. Canonical feature/workflow notes are updated and the worklog is closed.
|
||||
|
||||
## Remaining boundaries
|
||||
|
||||
General shout Magic miss/resist/deflect needs fuller original-caster, active-spell, defender and configuration inputs; no guessed roll was added. None-class aura-only children keep their source distinction. Other utility ranks/profiles and immunity grants, remote actor authority, hostile-NPC exact flee behavior, general aura-state immunity, Deterrence siblings, the private Ascension stance DUMMY consumer and exact source Targorr Thrash timing remain gated. Native/CoA builds stay Needs Testing. No full Stockade campaign, Wailing live test, staging, commit or deployment is part of this pass.
|
||||
@@ -0,0 +1,115 @@
|
||||
# Pinned enemy equipment mapping — 2026-10-06
|
||||
|
||||
## Result
|
||||
|
||||
Recovered the exact AzerothCore `creature_equip_template.sql` at the currently
|
||||
pinned world commit and added its hash-checked fixture and importer path. The
|
||||
generated reference now joins imported spawn GUIDs and selectors to equipment
|
||||
sets, then to Item.dbc class and inventory type. The runtime helper resolves
|
||||
only an explicit source spawn GUID and entry; unknown, mismatched, unsupported,
|
||||
or unresolvable assignments produce no equipment contract.
|
||||
|
||||
The recovered SQL is
|
||||
`dungeon-pipeline/source-fixtures/azerothcore-4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3/creature_equip_template.sql`.
|
||||
It hashes to `877205c149fd447b08f0ff2c65976f20c862cd42f068a6fcc294a76c7108936a`
|
||||
and belongs to AzerothCore commit
|
||||
`4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`, matching the active
|
||||
`creature.sql` and `creature_template.sql` pins. Its schema is
|
||||
`CreatureID, ID, ItemID1, ItemID2, ItemID3, VerifiedBuild`; the source contains
|
||||
10,854 SQL rows. The importer checks the full file hash before publishing the
|
||||
equipment mapping and records it in `azerothCoreSourceLock.json`.
|
||||
|
||||
## Imported runtime scope
|
||||
|
||||
`azerothCoreReference.json` stores three related mappings under
|
||||
`creature.equipment*`:
|
||||
|
||||
- `equipmentAssignmentsBySpawnGuid[guid]` records the source `id1`, optional
|
||||
alternate entries `id2`/`id3`, and original `equipment_id` selector.
|
||||
- `equipmentTemplatesByEntry[entry][equipmentId]` records raw source item IDs
|
||||
and the three virtual item IDs retained after core loader validation.
|
||||
- `equipmentItemsById[itemId]` stores the pinned Item.dbc `itemClass` and
|
||||
`inventoryType` for IDs referenced by those equipment rows.
|
||||
|
||||
These assignments cover the source dungeon maps imported by the pipeline, not
|
||||
all 149,879 rows in the world spawn table. The current generated snapshot has
|
||||
13,277 spawn-GUID assignments, 755 equipment entries, 763 equipment sets, and
|
||||
442 referenced item IDs. The spawn selectors are 7,632 zeroes, 5,637 ones, two
|
||||
twos, and six `-1` values. Twenty-three spawn rows have alternate creature
|
||||
entries. All 1,034 nonzero virtual item slots in this imported scope resolve
|
||||
through the pinned Item.dbc and pass its hand-inventory validation.
|
||||
|
||||
The Item.dbc input is the WotLK 3.3.5a client file at
|
||||
`../wow335a/Data/patch-A.MPQ/DBFilesClient/Item.dbc`, SHA-256
|
||||
`22061a811523790ddd2ee95b36ade2ac6e0c79a8b3121324d32a639acf50567f`. Its
|
||||
46,149 rows use eight 4-byte fields per 32-byte record; Class is field 1 and InventoryType is
|
||||
field 6. The importer rejects a different hash or DBC layout. Both pins and
|
||||
field indexes appear in the generated source lock and reference.
|
||||
|
||||
## Source behavior and selectors
|
||||
|
||||
The source behavior was checked against the exact commit-pinned
|
||||
`Creature.cpp` (SHA-256
|
||||
`ea19df5312b632bb7b9faf4323c1612fff8d8104e390d7193bae584318e3e11b`) and
|
||||
`ObjectMgr.cpp` (SHA-256
|
||||
`e4eae029cc30f84c26c258ba806d39eea61200f623aead1ee0813f6adebeed37`).
|
||||
The relevant operations are `ObjectMgr::GetEquipmentInfo`,
|
||||
`ObjectMgr::LoadEquipmentTemplates`, spawn data loading, `Creature::LoadEquipment`,
|
||||
and `Creature::HasWeapon`.
|
||||
|
||||
For a database spawn, selector `0` means no equipment. A positive selector
|
||||
looks up that exact equipment ID. Selector `-1` chooses a random row from the
|
||||
entry's equipment map, then mutates the selector to `distance(begin, row) + 1`.
|
||||
That is an ordinal-based ID, not the selected row's actual key. ObjectMgr checks
|
||||
nonzero alternate entries using the mutated selector and clears the assignment
|
||||
if a required alternate row is absent; the later creature load again looks up
|
||||
the concrete ID. The runtime helper mirrors this sequence with an injected
|
||||
uniform value in `[0, 1)`. It fails closed if the resulting exact lookup or any
|
||||
alternate lookup is absent rather than choosing the row's key as a substitute.
|
||||
|
||||
This distinction matters for sparse IDs. The pinned table has creature 32239
|
||||
with only equipment ID 2. Its one-row `-1` selection rewrites to ID 1, so a
|
||||
later ID-1 lookup has no result; the helper will not grant its ID-2 equipment
|
||||
under a random selector. An explicit selector `2` can resolve that row. The
|
||||
focused test covers this ordinal-plus-one behavior.
|
||||
|
||||
`ObjectMgr::LoadEquipmentTemplates` also removes missing items and item rows
|
||||
whose Item.dbc InventoryType is not one of `13, 14, 15, 17, 21, 22, 23, 25,
|
||||
26` (weapon, shield, ranged, two-handed weapon, main-hand weapon, off-hand
|
||||
weapon, holdable, thrown, or ranged-right). The importer applies this same
|
||||
whitelist to all three virtual slots. After that validation,
|
||||
`Creature::HasWeapon(OFF_ATTACK)` in AUTO mode checks the resolved Item.dbc
|
||||
`ClassID == ITEM_CLASS_WEAPON` (2). No `item_template` lookup is needed for
|
||||
that gate; this import does not claim to model item stats or item damage.
|
||||
|
||||
The helper `enemySpawnEquipmentContract(entry, sourceCreatureGuid, randomUnit?)`
|
||||
returns the resolved virtual item IDs and offhand class, plus the existing
|
||||
`autoOffhand` contract when the offhand item is a weapon. It requires a source
|
||||
GUID whose imported entry list contains the requested creature. Database
|
||||
spawns with selector zero resolve to empty virtual slots. Missing GUIDs,
|
||||
synthetic spawns, entry mismatches, older references without equipment maps,
|
||||
and failed selector lookups return no contract. Core's separate no-spawn-data
|
||||
default `LoadEquipment()` selects ID 1; the GUID-based helper does not infer
|
||||
that creation path for synthetic actors.
|
||||
|
||||
The mapping only supplies source equipment and AUTO offhand capability. It
|
||||
does not schedule attacks, import item stats, change loot, alter the level-80
|
||||
cap, or certify CoA/native balance. Ready-five remains the certification set;
|
||||
CoA and native balance remain Needs Testing.
|
||||
|
||||
## Validation
|
||||
|
||||
- `node --test scripts/dungeon-pipeline/import-azerothcore-world.test.mjs` — 10
|
||||
focused tests passed.
|
||||
- `npx vitest run src/game/enemyEquipment.test.ts` — 7 focused tests passed.
|
||||
- `node scripts/dungeon-pipeline/import-azerothcore-world.mjs --item-dbc
|
||||
"F:\\Projects\\wow335a\\Data\\patch-A.MPQ\\DBFilesClient\\Item.dbc"` —
|
||||
green; 54 imported dungeon snapshots, 13,277 creature spawns, 494 encounters,
|
||||
with the three expected Ascension-only fallback maps.
|
||||
|
||||
The isolated source-data subprocess did not run a production build or live QA.
|
||||
Root's combined continuation subsequently passes the standard build, Ready-five,
|
||||
avatar checks and the one frozen Cellblock Rush clear. Targorr's live source
|
||||
GUID 84027 resolves virtual slots `[5305, 5305, 0]` and weapon Class 2; eight
|
||||
offhand outcomes are observed. Combined evidence and limitations are in
|
||||
[the continuation report](ENEMY_SOURCE_PARITY_CONTINUATION_2026-10-06.md).
|
||||
@@ -0,0 +1,56 @@
|
||||
# Enemy Dual Wield and Thrash source contract — 2026-10-05
|
||||
|
||||
src/game/enemyExtraAttacks.ts owns the pinned Spell.dbc contracts and source-shaped helper behavior for creature Dual Wield (674/29651) and Thrash (3391). It does not schedule enemy abilities or mutate combat state.
|
||||
|
||||
## Client spell rows
|
||||
|
||||
The exact client sources are:
|
||||
|
||||
| Profile | Spell.dbc | SHA-256 |
|
||||
| --- | --- | --- |
|
||||
| Ascension | ../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc | 2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce |
|
||||
| Epoch | ../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc | d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3 |
|
||||
|
||||
Both profiles identify Dual Wield spells 674 and 29651 as effect 40 (SPELL_EFFECT_DUAL_WIELD) with implicit target A = self, raw effect base points 0, no die-side roll, and no damage packet. Spell 674 has Attributes0 336 in Ascension and 80 in Epoch; spell 29651 has Attributes0 80 in both. Spell 674's damage class is 1; 29651's is 0. Both are durationless.
|
||||
|
||||
Spell 3391 Thrash is effect 19 (SPELL_EFFECT_ADD_EXTRA_ATTACKS), implicit target A = self, with raw EffectBasePoints = 1 and EffectDieSides = 1. The compiler's base-point convention stores 2 because it normalizes raw base points by adding one. Historical core SpellEffectInfo::CalcValue instead starts with raw BasePoints = 1 and adds one for DieSides = 1, yielding exactly two extra attacks. The contract preserves raw and normalized values separately; do not interpret the normalized 2 as a second die roll.
|
||||
|
||||
The matching generated compiler descriptors are in scripts/dungeon-pipeline/compile-campaign-catalog.mjs near lines 1167–1183. Generation already classifies these as utilities rather than direct damage.
|
||||
|
||||
## Creature Dual Wield behavior
|
||||
|
||||
The read-only historical AzerothCore reference implements effect 40 in src/server/game/Spells/SpellEffects.cpp (Spell::EffectDualWield): only on HIT_TARGET it calls SetCanDualWield(true) on the effect target. For creature units, that enables the offhand attack channel; it does not itself deliver an attack.
|
||||
|
||||
When Dual Wield is enabled, a creature does not need an equipped offhand item for the core offhand channel to exist: `Creature::HasWeapon(OFF_ATTACK)` returns true in enabled mode (`Creature.cpp:3299`). Core creates the same generated min/max base weapon range for BASE_ATTACK and OFF_ATTACK in `Creature::SelectLevel`, using `CreatureBaseStats::GenerateBaseDamage`. `Creature::CalculateMinMaxDamage` in `Entities/Unit/StatSystem.cpp` then applies the same template variance, AP contribution, damage modifier, and attack-speed math to either hand. Core's default `UNIT_MOD_DAMAGE_OFFHAND` total-percent modifier is 0.5 (`Unit.cpp:401`), so the offhand uses half of its otherwise-equivalent creature damage formula. `Creature::UpdateEntry` assigns `CreatureTemplate.BaseAttackTime` to both hands (`Creature.cpp:617–618`). They have separate swing timers; the creature melee AI can add a 200 ms presentation stagger when both are ready together. The initial offhand timer is offset to half a base swing on attack start.
|
||||
|
||||
Core's ordinary weapon swing miss calculation adds 19 percentage points while dual wielding (`Unit.cpp:15276`, `MeleeSpellMissChance`, when `spellId` is zero and an offhand is available). Enabled creature offhands satisfy that availability check without an item row, so the penalty applies to their mainhand, offhand, and queued mainhand swings. The runtime applies it only to ordinary creature weapon swings, preserving native/player-defender exclusions.
|
||||
|
||||
The source effect only sets the creature capability; it has no aura duration and the core source does not remove it when the caster leaves combat. This simulator clears the capability, timer, and queued swings on its death, navigation/leash, and encounter-reset lifecycle as game policy. That reset behavior is not claimed as an exact spell-expiration rule from the core. RuneWaker actors, summons, and character defenders remain outside this source-creature path. The separate `flags_extra` `USE_OFFHAND_ATTACK` and AUTO virtual-item cases are not modeled here.
|
||||
|
||||
This formula is core-owned and does not justify copying an already rolled mainhand hit as the offhand hit. Runtime damage should apply the offhand modifier to the generated creature range/AP formula before the ordinary hit-table and defense resolution. For creatures that have not entered enabled Dual Wield mode, the historical core's AUTO mode does require a valid offhand weapon. The locked Healer-Man world source includes creature rows with equipment_id but not the equipment-template table, so that missing mapping must not be guessed.
|
||||
|
||||
## Thrash behavior
|
||||
|
||||
Core `Spell::EffectAddExtraAttacks` queues its calculated count only when the effect is handled on HIT_TARGET and the target unit is alive. `Unit::Update` clears `_lastDamagedTargetGuid` before draining already queued swings (`Unit.cpp:561–575`). Ordinary mainhand/offhand updates set it to their victim even when mitigation leaves zero damage (`Unit.cpp:2827`); direct spell damage writes it only when source damage is positive (`Spell.cpp:2774`); periodic aura ticks do not write it in this source. `Unit::AddExtraAttacks` captures that current-update target, or the unit's selected target if there is no last-damaged GUID; with neither it queues nothing. The saved queued target remains fixed through the next update. On the next `Unit::Update` queue-drain phase, `HandleProcExtraAttackFor` issues one BASE_ATTACK (mainhand) melee update per queued count (`Unit.cpp:2934–2945`). Ordinary Thrash swings are discarded if the target is gone or outside melee range when drained. They go through the normal melee attack outcome and mitigation path; they are not offhand swings and do not replace or reset the normal mainhand swing timer.
|
||||
|
||||
Thrash has a fixed count of two, not a random proc chance. The normal melee proc machinery still handles those swings. The core aura proc filter blocks the same ADD_EXTRA_ATTACKS spell from chaining itself while it is the current extra-attack source; other melee effects keep their own source eligibility rules. Runtime should preserve this bounded same-spell recursion behavior without disabling unrelated melee procs.
|
||||
|
||||
## Current Stockade source cases
|
||||
|
||||
The locked creature_template_spell.sql data lists spell 3391 for Targorr the Dread (1696) and spell 29651 for Bazil Thredd (1716). The SmartAI table casts 674 for three Stockade creatures, always targeting self with an initial 1000–1000 ms update interval and zero repeat interval:
|
||||
|
||||
| Entry | Creature | Raw SmartAI event type | Meaning in the core enum | Evidence |
|
||||
| ---: | --- | ---: | --- | --- |
|
||||
| 1696 | Targorr the Dread | 0 | update in combat | SQL comment incorrectly says out of combat |
|
||||
| 1711 | Defias Convict | 1 | update out of combat | SQL comment agrees |
|
||||
| 1716 | Bazil Thredd | 1 | update out of combat | SQL comment incorrectly says in combat |
|
||||
|
||||
SMART_EVENT_UPDATE_IC = 0 and SMART_EVENT_UPDATE_OOC = 1 are defined in the historical SmartScriptMgr.h. Prefer these raw event types over the inconsistent Targorr/Bazil SQL comments. Targorr's template lists Thrash, but the locked Stockade SmartAI rows contain no cast action for spell 3391. That source establishes availability, not a Thrash cadence; do not invent one.
|
||||
|
||||
The source lock for the world import pins creature.sql, creature_template.sql, creature_template_spell.sql, and smart_scripts.sql, but not an equipment-template mapping. The historical AzerothCore checkout used for behavior references has HEAD e822d718322289dd036fb2daf8867ba41283bf9a; it is read-only reference material and is not represented as the exact server-code revision named by the world source lock.
|
||||
|
||||
## Runtime integration surface
|
||||
|
||||
Import `enemyDualWieldContract(spellId, sourceProfile)` to validate a 674 or 29651 effect and obtain the explicit offhand formula/timing contract. `enemyThrashContract(sourceProfile)` supplies the exact two-swing, queued mainhand semantics; `resolveEnemyThrashTarget(lastDamagedId, selectedId)` implements core target precedence and returns null when neither target is known. Unknown spell/profile pins fail closed. `trackEnemyLastDamagedTarget` models the current-update source target writers and deliberately ignores periodic ticks.
|
||||
|
||||
Runtime integration in `combatStore.ts` keeps the offhand timer independent of the mainhand's cooldown, drains each saved Thrash target/count before selecting the next cast, gives every hand/swing a distinct deterministic seed, and routes each packet through ordinary hit, mitigation, and proc handling. The offhand starts at half the base swing after engagement; Bloodlust retimes in-flight weapon clocks without changing queued extra attacks or spell cooldowns. Preserve the same-spell extra-attack recursion guard. Do not promote unsupported enemy data into loot, readiness, or all-class balance coverage.
|
||||
@@ -0,0 +1,141 @@
|
||||
# Enemy fear movement follow-up — 2026-10-06
|
||||
|
||||
This pass integrates source-informed movement for the pinned enemy shout fear
|
||||
auras into player, party and mobile owned-summon consumers. Voluntary movement,
|
||||
jumping, attacks and casts remain suppressed while fear controls the actor.
|
||||
Movement requires reviewed navigation and collision/LOS approval. Missing or
|
||||
blocked spatial support safely holds the actor. Other controls retain their
|
||||
existing policy; this does not claim exact historical-server path or RNG parity.
|
||||
|
||||
## Historical core behavior
|
||||
|
||||
The read-only historical source is AzerothCore commit
|
||||
`e822d718322289dd036fb2daf8867ba41283bf9a`, specifically
|
||||
`src/server/game/Movement/MovementGenerators/FleeingMovementGenerator.cpp`,
|
||||
`src/server/game/Movement/MotionMaster.cpp`,
|
||||
`src/server/game/Entities/Unit/Unit.cpp`, and
|
||||
`src/server/game/Spells/Auras/SpellAuraEffects.cpp` under
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk`.
|
||||
|
||||
`HandleModFear` passes the live aura caster to `Unit::SetControlled`; that
|
||||
passes it to `SetFeared`, then `MotionMaster::MoveFleeing`. The generator looks
|
||||
up the caster GUID when it chooses each new destination. It does not preserve
|
||||
the caster's cast-time position. If that lookup fails, it picks a random angle
|
||||
and follows its near-source distance branch with a source distance of zero. A
|
||||
dead caster can still resolve while its unit remains in-world; after removal,
|
||||
the source-less fallback applies.
|
||||
|
||||
The source's exact movement bounds and retries are:
|
||||
|
||||
| Core rule | Source value |
|
||||
| --- | ---: |
|
||||
| Quiet-range lower bound | 28 yd |
|
||||
| Quiet-range upper bound | 43 yd |
|
||||
| Minimum accepted path | 2 yd |
|
||||
| Path length limit | 30 yd |
|
||||
| Retry after destination LOS failure | 200 ms |
|
||||
| Retry after failed, short, or invalid path | 100 ms |
|
||||
| Repath wait after spline travel | random 800–1500 ms |
|
||||
|
||||
Below 28 yards, the server picks a distance between `0.4` and `1.3` times the
|
||||
remaining distance to 28 yards and a heading within ±π/8 of the direction away
|
||||
from the source. Above 43 yards, it picks `0.4`–`1.0` times the 15-yard band
|
||||
width and heads partly back toward the source, within ±π/4. Inside the quiet
|
||||
band, it picks `0.6`–`1.2` times the band width in a random direction. A source
|
||||
distance at or below 0.2 yards uses a random base angle. The core constrains the
|
||||
candidate with `MovePositionToFirstCollision`, checks LOS to the resulting
|
||||
point, then asks `PathGenerator` for a path and rejects shortcuts, no-path,
|
||||
far-from-poly, paths shorter than 2 yards, and paths beyond the 30-yard limit.
|
||||
After five failed paths it stops looking up the source and uses the
|
||||
source-less random fallback.
|
||||
|
||||
`SetControlled` does not start fear while stun or confusion already owns the
|
||||
unit. When the higher-priority control ends, it rechecks active fear auras and
|
||||
resolves their caster GUID. This helper accepts the actor's active stun end time
|
||||
and holds fear movement until that higher-priority control expires.
|
||||
|
||||
## Planner boundary
|
||||
|
||||
[`src/game/enemyFearMovement.ts`](../src/game/enemyFearMovement.ts) carries the
|
||||
source distance bands, steering ranges, LOS/path retries, and path length
|
||||
limits. Its hash-based choices are simulator decisions: they reproduce the
|
||||
source's ranges with stable values derived from actor ID, source ID, aura
|
||||
application time, and decision index. They do not reproduce the core's global
|
||||
random-number stream. `worldUnitsPerYard` is required input because imported map
|
||||
coordinates can have a different scale. The estimated time to the next choice
|
||||
uses approved path length divided by this actor's current effective speed,
|
||||
then adds a seeded wait from the core's 800–1500 ms range.
|
||||
|
||||
Each actor supplies its own fear expiry, stun expiry, base movement speed, and
|
||||
source speed multiplier. The shout's +25% speed is therefore applied only when
|
||||
that target has the still-active source speed aura. The current adapters are
|
||||
limited to tagged source fear. `getSourcePosition` runs once per repath so
|
||||
the goal uses the live caster location at that decision; the caller should
|
||||
cache the resulting goal until `nextDecisionAtMs` instead of recomputing it
|
||||
every frame.
|
||||
|
||||
The planner requires three map adapters: a projection that rejects excessive
|
||||
snaps and floor changes, an LOS test, and a complete actor-safe path-length
|
||||
query. Missing map support, an unsafe projection, blocked LOS, or an invalid
|
||||
route yields a hold with the source retry timing. The destination is a route
|
||||
goal only. The caller must move through actor collision and approved navigation
|
||||
waypoints; it must never assign the destination directly to an actor position.
|
||||
`stepEnemyFearTowardDestination` only computes a bounded request and does not
|
||||
replace those checks.
|
||||
|
||||
## Integration seams before this pass
|
||||
|
||||
- `PlayerRig` resolves the player's shout control near its frame movement step.
|
||||
`enemyControlPreventsMovement` currently blocks all fear before movement, and
|
||||
`Rapier`'s character controller checks the player's capsule against terrain.
|
||||
For a tagged source fear with no active stun, the frame can use the cached
|
||||
flee goal to set the autonomous world movement vector, then submit its bounded
|
||||
delta through the existing character controller. The goal must not be
|
||||
derived from camera input or change camera yaw.
|
||||
- `PartyPopulation` similarly blocks fear before companion route planning. It
|
||||
already has the reviewed navigation graph, `planPartyRoute`, direct-segment
|
||||
collision checks, and route-segment clearance validation. A fear goal should
|
||||
use those route helpers and hold when no safe route exists.
|
||||
- The summon loop in `combatStore.ts` returns early when `controlledUntil` is
|
||||
active, before movement and actions. `CombatSummon` currently keeps a control
|
||||
expiry but no control mechanic. A source fear adapter needs to preserve the
|
||||
per-summon fear and stun state, move only when fear is the active control,
|
||||
and continue to suppress actions. `CombatSpatialProvider` provides live actor
|
||||
positions, LOS, ground projection, and the reviewed navigation graph; the
|
||||
adapter still needs to validate a complete route before advancing a summon.
|
||||
- The shout control resolver currently returns only mechanic and expiry. The
|
||||
integration must identify the active tagged `ActiveAura` per actor to retain
|
||||
its source ID and `appliedAt` for live source lookup and deterministic seeding.
|
||||
That lookup can use the mob runtime position while the caster exists; when
|
||||
the source ID no longer resolves, pass `null` and use the source-less branch.
|
||||
|
||||
The existing hostile NPC fear path is separate. `MobPopulation` already calls
|
||||
`stepFearedMobAway` and clamps that direct step to the home leash, using the
|
||||
current aggro target as the threat. That helper does not perform LOS or route
|
||||
validation for the flee step. This follow-up leaves it unchanged and does not
|
||||
claim it matches the historical generator.
|
||||
|
||||
## Integrated consumers and verification
|
||||
|
||||
`enemyFearMovementRuntime.ts` retains the selected aura's source/application,
|
||||
caches each goal and implements the five-failure source fallback. Concurrent
|
||||
tagged stun and generic stun/confuse/root/sleep auras hold movement even when
|
||||
the actor's longest control timer belongs to fear. Expiry or purge clears the
|
||||
per-actor goal; a refreshed aura starts a new decision sequence.
|
||||
|
||||
PlayerRig follows approved route waypoints through its existing Rapier character
|
||||
controller, including gravity. Keyboard movement and jumping do not steer fear.
|
||||
PartyPopulation uses its reviewed graph and capsule route validators, normal
|
||||
party speed with actor-local source modifiers, and follows forced fear even
|
||||
under Stop. Fear never enables catch-up speed or stuck-recovery relocation.
|
||||
Camera look retains its ordinary hold-and-drag behavior.
|
||||
|
||||
`enemyFearSummonMovement.ts` requires a loaded graph and validates projection,
|
||||
LOS, path segments and each bounded step. The actual combat tick consumes it
|
||||
before summon actions, holds concurrent controls, and preserves the pet's Prowl
|
||||
movement modifier. Totems and stationary zones remain stationary. Remote actor
|
||||
authority and hostile-NPC flee policy remain outside this bounded integration.
|
||||
|
||||
Focused planner/cache/summon verification passes 20 tests, including actual pet
|
||||
ticks, blocked/missing navigation and simultaneous stun expiry. Input regressions
|
||||
pass 33 tests. Final build/live evidence is recorded in the combined follow-up report.
|
||||
@@ -0,0 +1,139 @@
|
||||
# Enemy shout speed and immunity audit — 2026-10-06
|
||||
|
||||
This follow-up pins the parent movement-speed effect and the immunity-related
|
||||
source scalars for Intimidating Shout `5246 -> 20511` and Frightening Shout
|
||||
`19134 -> 29544`. The earlier
|
||||
[`ENEMY_TRIGGERED_SHOUTS_2026-10-06.md`](ENEMY_TRIGGERED_SHOUTS_2026-10-06.md)
|
||||
remains the targeting and timed-control reference. The runtime attaches the
|
||||
sourced speed modifier and tag to the existing parent control aura, and both
|
||||
player and party movement consume that target-local multiplier. Shout target
|
||||
selection also includes eligible owned summons, but the current summon action
|
||||
loop holds a controlled summon before its movement step. The +25% speed is
|
||||
therefore sourced on that recipient without changing its movement during the
|
||||
shared fear/control lifetime; no fear-flee behavior is claimed.
|
||||
|
||||
## Client source rows
|
||||
|
||||
The Ascension input is
|
||||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
|
||||
SHA-256
|
||||
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`. The
|
||||
Epoch input is
|
||||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
|
||||
SHA-256
|
||||
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. Both
|
||||
use the shared patch-S `SpellDuration.dbc` and `SpellRadius.dbc` fallbacks
|
||||
recorded in `enemySourceAuras.ts`.
|
||||
|
||||
Raw `Spell.dbc` field 3 (`Mechanic`) is 5 on all four rows, which the selected
|
||||
core defines as `MECHANIC_FEAR`. Effect-level `EffectMechanic` is 0 on every
|
||||
effect. `DamageClass` is field 213; `Dispel` is field 2. The attribute tuple
|
||||
below lists raw fields 4 through 11 in order (`Attributes0` through
|
||||
`Attributes7`):
|
||||
|
||||
| Spell | Profile | Spell mechanic | Damage class | Dispel | Attributes0–7 |
|
||||
| --- | --- | ---: | ---: | ---: | --- |
|
||||
| 5246 parent | Ascension | 5 | 1 (Magic) | 0 | `[0, 0, 0, 0, 0, 0, 0x02000000, 0]` |
|
||||
| 20511 child | Ascension | 5 | 1 (Magic) | 0 | `[0, 0, 0, 0x00090000, 0x00800000, 0, 0, 0]` |
|
||||
| 19134 parent | Ascension | 5 | 1 (Magic) | 0 | `[0x00050010, 0, 0, 0, 0, 0, 0, 0]` |
|
||||
| 29544 child | Ascension | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
|
||||
| 5246 parent | Epoch | 5 | 1 (Magic) | 0 | `[0x00050010, 136, 0, 0, 0, 0, 0x00800000, 0]` |
|
||||
| 20511 child | Epoch | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
|
||||
| 19134 parent | Epoch | 5 | 1 (Magic) | 0 | `[0x00050010, 0, 0, 0, 0, 0, 0, 0]` |
|
||||
| 29544 child | Epoch | 5 | 0 (None) | 0 | `[0, 0, 0, 0, 0, 0, 0, 0]` |
|
||||
|
||||
None of these rows sets `ATTR0_NO_IMMUNITIES`, `ATTR2_NO_SCHOOL_IMMUNITIES`,
|
||||
`ATTR3_ALWAYS_HIT`, `ATTR4_NO_PARTIAL_IMMUNITY`, or
|
||||
`ATTR7_NO_ATTACK_MISS`. The source does not mark a spell as always hitting or
|
||||
as bypassing immunity. Both parent casts are Magic-class rows. Child 20511 is
|
||||
Magic class only in Ascension; 20511 in Epoch and child 29544 in both profiles
|
||||
are `DamageClass=None` aura-only rows. The historical core routes Magic-class
|
||||
spells through its magic hit calculation and applies its ordinary aura-only
|
||||
handling to None-class rows. The HealerMan runtime does not implement the
|
||||
general hit, resist, or deflect calculation in this pass.
|
||||
|
||||
## Parent speed effect
|
||||
|
||||
Both parents have effect 2 `APPLY_AURA` (`effectType=6`) with aura 31
|
||||
`MOD_INCREASE_SPEED`, base points 25, target A 22 (`TARGET_SRC_CASTER`),
|
||||
target B 15 (`TARGET_UNIT_SRC_AREA_ENEMY`), and radius index 14 (8 yd). Thus
|
||||
the aura grants +25% movement speed to eligible hostile recipients in the
|
||||
same caster-centered 8-yard area as parent fear. Its duration follows the
|
||||
parent row:
|
||||
|
||||
| Parent | Ascension | Epoch |
|
||||
| --- | ---: | ---: |
|
||||
| 5246 Intimidating Shout | 5 s | 8 s |
|
||||
| 19134 Frightening Shout | 4 s | 6 s |
|
||||
|
||||
`enemyTriggeredShoutMovementSpeedEffect` exposes this only when effect 2 still
|
||||
matches the source aura, amount, target pair, radius, and area contract. Its
|
||||
modifier uses the ActiveAura fraction (`0.25`) and the tag
|
||||
`enemy-triggered-shout:parent-movement-speed`. The target-local multiplier
|
||||
helper ignores expired, permanent, differently targeted, and untagged auras;
|
||||
if multiple shout speed effects are active it returns the strongest positive
|
||||
bonus, matching the historical core's `GetMaxPositiveAuraModifier` handling
|
||||
for `SPELL_AURA_MOD_INCREASE_SPEED`.
|
||||
|
||||
The runtime stores the speed modifier on the existing per-target parent
|
||||
`enemy-control:source-spell-5246` or
|
||||
`enemy-control:source-spell-19134` aura. This keeps same-caster refresh,
|
||||
different-caster preserve-existing behavior, and caster-removal persistence
|
||||
with the parent control record. PlayerRig and PartyPopulation movement consume
|
||||
the target-local multiplier. The summon loop currently returns for the
|
||||
parent's active control before moving, so this pass does not introduce summon
|
||||
movement or fear-flee AI. The control and speed effects share one duration. The
|
||||
table gives the DBC duration baseline; historical core
|
||||
`Spell::DoSpellHitOnUnit` computes one duration for the shared aura, then
|
||||
`Unit::ModSpellDuration` derives mechanic duration modifiers from the complete
|
||||
spell, including its spell-level fear mechanic. A fear-duration modifier can
|
||||
therefore shorten the combined fear and speed aura together.
|
||||
|
||||
The runtime attaches the speed modifier only when it accepts the parent spell
|
||||
application. This is important for fear immunity: the source rows have
|
||||
spell-level `Mechanic=5`, and the historical core checks that mechanic in
|
||||
`Unit::IsImmunedToSpell` before resolving the per-effect aura immunities.
|
||||
`Unit::SpellHitResult` calls that whole-spell check. Under the runtime's
|
||||
whole-spell fear-immunity policy, a fear-immune recipient does not receive the
|
||||
parent's fear or +25% speed effect. While fear is active, the existing player
|
||||
and party locomotion policy blocks movement; the speed multiplier is tracked
|
||||
on the shared aura but does not override that fear movement policy.
|
||||
|
||||
## Child control and immunity behavior
|
||||
|
||||
Child 20511 has aura 12 (`MOD_STUN`) for 5 seconds in Ascension and 8 seconds
|
||||
in Epoch. Ascension also has a separate aura 87 effect that increases physical
|
||||
damage taken by 15% for 5 seconds; Epoch has no such rider. Child 29544 has
|
||||
only fear aura 7, for 3 seconds in Ascension and 6 seconds in Epoch.
|
||||
|
||||
The whole-spell fear mechanic applies to all four rows. A fear mechanic
|
||||
immunity therefore rejects the parent or triggered child as a whole in the
|
||||
selected core. A stun-state immunity is narrower: it filters child 20511's
|
||||
aura-12 effect. In Ascension the separate aura-87 physical damage-taken rider
|
||||
can remain; Epoch's 20511 row has no remaining child effect. The source
|
||||
children have `Dispel=0`, so neither is dispellable by category. The same
|
||||
source-caster refresh and different-caster preserve-existing policy remains in
|
||||
`applyEnemySourceAura`; the shared parent control aura IDs already survive
|
||||
caster removal. Recipient removal removes the combined fear and speed aura.
|
||||
|
||||
## Targeting and implementation boundary
|
||||
|
||||
The parent effect-0 trigger remains a separate cast on its explicit victim;
|
||||
the child is not selected from the area list. Effects 1 and 2 remain the
|
||||
independent caster-centered area pair at 8 yards, with the existing cap of 5
|
||||
for 5246 and unlimited (`MaxAffectedTargets=0`) for 19134. A qualifying
|
||||
explicit victim may also receive the area effects. The prior targeting report
|
||||
documents the separate LOS rules, overlap, and random-ordering boundary.
|
||||
|
||||
Historical AzerothCore sources were read-only under
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/` and
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Entities/Unit/`.
|
||||
The relevant paths are `Spell::EffectTriggerSpell`,
|
||||
`Spell::AddUnitTarget`, `Unit::IsImmunedToSpell`,
|
||||
`Unit::IsImmunedToSpellEffect`, `Unit::SpellHitResult`,
|
||||
`Unit::MagicSpellHitResult`, and `Unit::UpdateSpeed`. The current simulation
|
||||
still does not model general magic hit/resist/deflect rolls or creature-specific
|
||||
exceptions. The level-80 cap, loot, readiness, and publication scope are
|
||||
unchanged.
|
||||
|
||||
Focused verification passed: `npx vitest run src/game/enemyTriggeredShouts.test.ts src/game/enemySourceAuras.test.ts` (2 files, 12 tests). The root-owned shout integration suite also passed during integration; the owner runs final repository checks after shared changes settle.
|
||||
@@ -0,0 +1,157 @@
|
||||
# Enemy source parity continuation — 2026-10-06
|
||||
|
||||
## Result
|
||||
|
||||
Ordinary source NPC defense consumes target-local block chance, ignore-hit-direction,
|
||||
and critical-block aura inputs. Successful ordinary and post-hit blocks roll the
|
||||
source integer critical-block chance independently, doubling block value on success.
|
||||
Player/party auto damage events carry their actual weapon hand, and the QA recorder
|
||||
projects those results onto committed Disarm windows.
|
||||
|
||||
Imported Intimidating Shout 5246 and Frightening Shout 19134 now use separate
|
||||
explicit-victim child and caster-centered area targeting. The parent cast retains
|
||||
its captured victim through threat changes and rechecks eligibility, range and LOS
|
||||
at release. The area uses an inclusive 8m 3D radius without a separate LOS check,
|
||||
and 5246 caps its shared area selection at five. The eligible explicit victim can
|
||||
also receive the area aura. The child/parent controls remain independently stored;
|
||||
their longest active timer governs control, with stun winning equal expiry ties.
|
||||
All four source rows have Dispel 0. A different caster preserves an existing copy;
|
||||
same-caster recasts refresh it. Timed recipient auras survive caster removal.
|
||||
|
||||
The Ascension 20511 child also applies its sourced +15% physical damage taken.
|
||||
Epoch has no such rider. The compiler checks parent and child DBC signatures,
|
||||
trigger links, cap, attributes and Dispel before emitting the new descriptor.
|
||||
Catalog regeneration changes six attack effect descriptors across four dungeons
|
||||
and adds 11,095 explicit source GUIDs to static spawns and patrol members. All
|
||||
other catalog data, geometry, health and populations compare equal to the
|
||||
pre-generation snapshot. `artifacts/enemy-source-parity-2026-10-06/catalog-diff.json`
|
||||
and `catalog-equipment-audit.json` retain both checks; the compressed catalog
|
||||
matches the JSON output.
|
||||
The boss guide describes the distinct victim and area effects.
|
||||
|
||||
The exact pinned equipment table is recovered and hash-checked. Its imported
|
||||
13,277 spawn assignments join source selectors to sanitized virtual item IDs
|
||||
using the pinned Item.dbc inventory whitelist. An ordinary NPC with a validated
|
||||
offhand weapon gains AUTO offhand capability, keeps its independent half-delay
|
||||
timer, and restores that capability after evade/death resets. Source GUIDs travel
|
||||
from the compiler through population/scene registration and the selected
|
||||
Cellblock Rush boss clone. Missing or mismatched GUIDs, empty hands, shields,
|
||||
unsupported selectors and native actors do not acquire AUTO offhand attacks.
|
||||
Item stats, model attachments and loot are outside this mapping.
|
||||
|
||||
## Source boundaries
|
||||
|
||||
- Improved Blocking 3419 is a complete supported source import. Critical Block
|
||||
47294–47296 and Deterrence variants supply reviewed block-input contracts but
|
||||
remain gated as complete automatic spell imports: their sibling effects are
|
||||
unsupported. The runtime tests explicitly use block-input fixtures.
|
||||
- Non-direct full-hit blocking has a bounded source proof for WoW Shield Bash 72.
|
||||
Its helper proves only the relevant custom-attribute bits for one pinned core
|
||||
and database snapshot. Utility/status application consumers and other source
|
||||
profiles remain open; a client DBC alone does not establish absent custom bits.
|
||||
- Equipment selector zero, exact positive IDs, ordinal-plus-one random selection,
|
||||
and alternate entry validation use the recovered matching source. Synthetic
|
||||
actors lack an explicit source GUID and remain unbound; no-spawn-data ID-1
|
||||
defaults are not inferred. This mapping does not import item damage or stats.
|
||||
- Hostile-NPC outgoing threat is source-inapplicable to the current enemy target
|
||||
path. Current eligible recipients are playable player/party actors or owned
|
||||
summons; a future NPC-vs-NPC path requires a recipient-side threat-list model.
|
||||
- Parent shout aura 31's movement-speed rider, additional server hit/immunity
|
||||
exceptions, Ascension stance DUMMY behavior, exact Thrash source cast timing,
|
||||
native custom gear/rates/prerequisites and wider proc formulas remain open.
|
||||
|
||||
Source audits:
|
||||
[block auras](NPC_BLOCK_AURA_PARITY_2026-10-06.md),
|
||||
[triggered shouts](ENEMY_TRIGGERED_SHOUTS_2026-10-06.md),
|
||||
[equipment mappings](ENEMY_EQUIPMENT_MAPPING_2026-10-06.md), and
|
||||
[threat boundary](HOSTILE_NPC_THREAT_BOUNDARY_2026-10-06.md).
|
||||
|
||||
## Validation
|
||||
|
||||
- Initial source/hand checks: 90 tests across 17 focused files passed. After
|
||||
equipment integration, 73 affected helper/runtime/population tests across 10
|
||||
files passed; these groups overlap and are not additive.
|
||||
- Importer, compiler pin, actor Disarm evidence and committed recorder checks:
|
||||
20 Node tests passed. The wrapper's `--prepare-only --bite-sized-stockade`
|
||||
syntax check passed without starting a server or browser.
|
||||
- Ready-five: 7 Vitest and 20 Python tests passed. Avatar checks: 56 passed.
|
||||
No full-suite or all-class sweep was run.
|
||||
- Independent Luna reviews found no confirmed issue in shared block/shout
|
||||
integration or source GUID/equipment registration/reset behavior. The new
|
||||
equipment runtime fixture explicitly requires pinned flags before reading
|
||||
them, fixing two optional-value errors caught by the first TypeScript build.
|
||||
- Standard `npm run build` passed after that fix: TypeScript, Vite, environment
|
||||
audits, static compression and release-bundle verification. The asset audit
|
||||
has its existing 60 budget exceptions and no regressions. Existing build
|
||||
prehooks regenerate the same 9-boss/23-item catalog; no loot is wired here.
|
||||
- Catalog metadata audit: 11,095 source GUID additions, 30 leaf changes within
|
||||
six reviewed shout descriptors, zero other changes, matching compressed JSON.
|
||||
|
||||
The reviewed build is frozen at
|
||||
`artifacts/enemy-source-parity-2026-10-06/corrected-build-20261006-054606946/`.
|
||||
All 5,967 build files are verified, aggregate SHA-256
|
||||
`50f723e4737f01fe82973c1a9c8259a4358179c1df74373b587fa76fb69b44a7`.
|
||||
The unchanged isolated content copy is reused from the earlier fully verified
|
||||
freeze: manifest SHA-256
|
||||
`ac0fa2a867ba0a495c172de2b89532d69b32d56d032482b26020ce2d189f074b`,
|
||||
27,571 objects, 6,489,632,021 bytes. This freeze rehashes both content manifests
|
||||
and the complete new build; it does not recopy those unchanged objects.
|
||||
|
||||
All subprocesses use GPT-6 Luna with extra-high reasoning. The workspace includes
|
||||
concurrent changes; no stage, commit or deployment is part of this task. Level
|
||||
cap 80, existing loot scope and readiness policy remain unchanged.
|
||||
|
||||
## One final live check
|
||||
|
||||
Run `playtest-artifacts/stockade-weapon-utilities/20261006-054628643/` uses the
|
||||
frozen build and normal Cellblock Rush entry. The UI-created Discipline Priest
|
||||
profile receives isolated pre-entry level-30 preparation; four companions are
|
||||
asserted against the Ready-five set. Gameplay uses ordinary movement, target,
|
||||
party-command and healing inputs with read-only committed telemetry. No Boss
|
||||
Testing, combat-state writes, enemy/aura seeding or teleports are used.
|
||||
|
||||
The seeded boss is **Targorr the Dread**, entry 1696, source/live actor
|
||||
`creature-84027`, from source dungeon `stormwind-stockade`. Native killed-boss
|
||||
progress and the results overlay agree on **1/1** in **03:10.3**. No player or
|
||||
party deaths are recorded; effective player healing is 2,845.8. This certifies
|
||||
the entered bite-sized slice, not the five-boss full campaign.
|
||||
|
||||
The recorder retains 794 consecutive post-baseline events with zero ID gaps,
|
||||
sampling errors or capacity loss. Actual NPC weapon results comprise 60
|
||||
mainhand, eight offhand and four Thrash extra-mainhand outcomes. The latter
|
||||
retain source spell 3391. Three queued-extra-attack state observations and 89
|
||||
positive offhand timer observations are also retained; snapshots are not
|
||||
activation counts. Player/party auto results contribute 162 actual hand events.
|
||||
Targorr's committed source-equipment snapshot retains GUID 84027, selector/set
|
||||
1, virtual items `[5305, 5305, 0]`, offhand Class 2 and AUTO capability, including
|
||||
a pre-engagement state with no armed offhand timer.
|
||||
Three committed actor Disarm windows contain four such results; their presence
|
||||
does not independently prove contribution formulas or cast gates. Runtime
|
||||
regressions provide that bounded coverage.
|
||||
|
||||
The seed records three Disarm and 39 Wound aura snapshots. Bloodlust, block and
|
||||
triggered-shout aura applications are unobserved in this seed; source/helper and
|
||||
runtime fixtures cover the newly implemented block/shout behavior. These absent
|
||||
live observations do not certify all spells or encounter variants.
|
||||
|
||||
Root visually inspects the desktop roster, dungeon equipment silhouette,
|
||||
mid-route images and `bite-sized-stormwind-stockade-boss-arrival.png` (which
|
||||
captures the native results overlay). Player/companion bodies and staff,
|
||||
shield, sword and dagger silhouettes are visible. Overlap/occlusion limits a
|
||||
complete per-companion gear inspection. Results clearly show Targorr and 1/1.
|
||||
No page exceptions occur; the sole outer console item is a favicon 404.
|
||||
|
||||
Both build and content manifest fingerprints remain unchanged before/after.
|
||||
The harness verifies 2,124 actually served hash-addressed, manifest-referenced
|
||||
content objects with zero integrity failures. Independent Luna audit rehashes
|
||||
all 5,967 frozen build files, the seven recorded loaded build chunks and all
|
||||
2,124 served content objects (77,019,550 bytes), with zero failures. Recorded
|
||||
URLs and successful response metadata agree with those immutable sources; raw
|
||||
network response bodies were not persisted. Recorder IDs 9–802 are independently
|
||||
checked as consecutive. Evidence:
|
||||
`playtest-artifacts/stockade-weapon-utilities/20261006-054628643/independent-evidence-audit.json`.
|
||||
|
||||
`npm run release:check` passes 399 changed paths including untracked files.
|
||||
Game/vault diffs are reviewed separately, and all six task vault notes pass EOF
|
||||
and trailing-whitespace checks. The worklog is closed; the one owned live helper,
|
||||
server and browser are cleaned up. No source changes follow the frozen live run.
|
||||
@@ -0,0 +1,145 @@
|
||||
# Enemy Defensive and Battle Stance audit — 2026-10-05
|
||||
|
||||
This audit covers the Stockade enemy stance casts Defensive Stance 7164 and
|
||||
Battle Stance 7165. Their form auras are state, not direct damage. The reviewed
|
||||
profile-specific rows and the ActiveAura-supported subset are in
|
||||
[`src/game/enemyStances.ts`](../src/game/enemyStances.ts).
|
||||
|
||||
## Pinned client rows
|
||||
|
||||
The Ascension source is the recipe compiler's pinned 3.3.5a patch-D table:
|
||||
|
||||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`
|
||||
|
||||
SHA-256: `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
|
||||
|
||||
Epoch uses the compiler's pinned table:
|
||||
|
||||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`
|
||||
|
||||
SHA-256: `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`.
|
||||
Both profiles use the compiler's shared patch-S `SpellDuration.dbc` fallback
|
||||
for duration indices because neither client folder contains that table. Its
|
||||
SHA-256 is `eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`.
|
||||
|
||||
The two NPC casts have the same Spell.dbc behavior in both profiles:
|
||||
|
||||
| Spell | Effect row (`effect/aura/base/misc/trigger`) | Duration | Stance masks |
|
||||
| --- | --- | --- | --- |
|
||||
| 7164 Defensive Stance | `6/36/0/18/0` | 180,000 ms | required `0/0`, excluded `0/0` |
|
||||
| 7165 Battle Stance | `6/36/0/17/0` | permanent (`-1`) | required `0/0`, excluded `0/0` |
|
||||
|
||||
Both have range index 1, school mask 1, damage class 0 for 7164 and 2 for
|
||||
7165, dispel 0, stack amount 0, and Attribute0 327696. Their equipped-item
|
||||
class is -1 with subclass and inventory masks 0. The direct effects target self
|
||||
(`targetA=1`, `targetB=0`), use radius index/value 0, mechanic 0, and period 0.
|
||||
That attribute value does not include AzerothCore's `SPELL_ATTR0_NOT_SHAPESHIFT`
|
||||
bit (`0x00010000`). The casts themselves therefore have no source stance mask
|
||||
or “not while shapeshifted” restriction in these rows. This statement applies
|
||||
to 7164 and 7165 only; it does not infer restrictions for unrelated abilities.
|
||||
|
||||
## Server-linked passive rows
|
||||
|
||||
The historical AzerothCore form handler links the forms to passive spells in
|
||||
`src/server/game/Spells/Auras/SpellAuraEffects.cpp`:
|
||||
|
||||
- form 18 → Defensive Stance Passive 7376;
|
||||
- form 17 → Battle Stance Passive 21156.
|
||||
|
||||
This is a server-side mapping. Neither stance cast has a nonzero
|
||||
`EffectTriggerSpell` in either profile. Both child rows have Attribute0 327888,
|
||||
the passive flag, and zero required/excluded stance masks. Their actual effect
|
||||
rows differ by client profile:
|
||||
|
||||
| Child passive | Ascension patch-D | Epoch client |
|
||||
| --- | --- | --- |
|
||||
| 7376 Defensive Stance Passive | `6/87/-10/127/0`, `6/79/-5/127/0`, `6/4/+42/127/0` | `6/87/-10/127/0`, `6/79/-5/127/0`, `6/10/+45/127/0` |
|
||||
| 21156 Battle Stance Passive | `6/10/0/127/0`, `6/280/0/0/0` | `6/10/-20/127/0` |
|
||||
|
||||
Rows use `effect/aura/base points/misc/trigger`. The final value in each row is
|
||||
zero: these passive rows also have no triggered child spell. A separate player
|
||||
stance spell such as 2457 is not a substitute for these NPC rows; its own
|
||||
profile rows contain additional effects and are not the source cast IDs here.
|
||||
|
||||
The passive scalar fields are identical in both profiles: dispel 0, duration
|
||||
index 0, range index 1, school mask 1, damage class 0, stack amount 0,
|
||||
equipped-item class -1 with subclass and inventory masks 0, and required and
|
||||
excluded stance masks 0/0. Each active effect is type 6, targets self
|
||||
(`targetA=1`, `targetB=0`), has mechanic 0, radius index/value 0, period 0, and
|
||||
trigger spell 0. The helper pins these scalar fields alongside each profile's
|
||||
effect rows so the campaign compiler can compare the complete child source.
|
||||
|
||||
For compiler drift checks, the WDBC scalar field indices are: `Dispel=2`,
|
||||
`Attribute0=4`, `ShapeshiftMask=12..13`, `ShapeshiftExclude=14..15`,
|
||||
`DurationIndex=40`, `RangeIndex=46`, `StackAmount=49`,
|
||||
`EquippedItemClass=68`, `EquippedItemSubclassMask=69`,
|
||||
`EquippedItemInventoryMask=70`, `DamageClass=213`, and `SchoolMask=225`.
|
||||
The three per-effect `EffectTriggerSpell` fields are `116..118`; active effect
|
||||
rows also use `Effect=71+j`, `BasePoints=80+j`, `Mechanic=83+j`,
|
||||
`ImplicitTargetA=86+j`, `ImplicitTargetB=89+j`, `RadiusIndex=92+j`,
|
||||
`Aura=95+j`, `Period=98+j`, and `MiscValue=110+j`. In the campaign compiler,
|
||||
array fields at index 77 or greater shift by six only when a Spell.dbc has at
|
||||
least 239 fields. Both pinned client tables have 234 fields, so none of these
|
||||
indices shift for the current Ascension or Epoch data; stance and equipped-item
|
||||
fields are below 77 and never use that localized-string adjustment.
|
||||
|
||||
Aura 79 is percent damage done, aura 87 is percent damage taken, and aura 10
|
||||
modifies threat. Their `miscValue` 127 covers all schools. The runtime can
|
||||
therefore apply Defensive Stance's shared `-10%` damage taken and `-5%` damage
|
||||
dealt in both profiles. Epoch's passive rows additionally supply `+45%` threat
|
||||
in Defensive Stance and `-20%` threat in Battle Stance. HealerMan already has a
|
||||
generic `stat: "threat"` resolver used by party and summon threat generation,
|
||||
so these profile-specific scalars are retained in the helper. Current combat
|
||||
threat tables record party and summon threat against hostile mobs; hostile NPCs
|
||||
have no outgoing-threat consumer in the current combat runtime. The two threat
|
||||
modifiers therefore do not change direct enemy hits, party threat, or the
|
||||
current threat tables.
|
||||
|
||||
Ascension's aura 4 row on 7376 is `DUMMY` with base points +42. No
|
||||
spell-specific `HandleAuraDummy` case, server script registration, linked spell,
|
||||
or triggered child was found for 7376, so its meaning is not guessed. Aura 280
|
||||
on Ascension's 21156 row has base points 0; it has no numerical delta and is
|
||||
kept as source metadata without an unsupported-effect warning. Aura 10 with
|
||||
base points 0 on that same row is also a sourced zero. No defensive or battle
|
||||
stance row is treated as an NPC direct hit.
|
||||
|
||||
## Apply, replacement, expiry, and removal
|
||||
|
||||
In `SpellAuraEffects.cpp`, applying a new shapeshift removes an existing
|
||||
shapeshift aura before setting the new form. The form boost handler applies the
|
||||
mapped passive only when the form changes and removes that owned passive when
|
||||
the stance aura is removed. The two stances are therefore mutually exclusive;
|
||||
the helper uses the `enemy-warrior-stance` exclusive group to preserve that
|
||||
state. Reapplying 7164 refreshes its timed form aura; 7165 remains until another
|
||||
form replaces it or it is explicitly removed.
|
||||
|
||||
When a warrior stance aura is removed, AzerothCore caps Rage to its computed
|
||||
stance removal value. Player-only spellbook bonuses contribute to that value;
|
||||
an ordinary NPC has no player spellbook contribution, so the default cap is
|
||||
zero. On expiry or removal with no replacement stance, the server also clears
|
||||
the form. The current enemy helper records the sourced form and duration; it
|
||||
does not invent a creature Rage baseline or treat the passive DUMMY row as
|
||||
resource regeneration. Its aura uses the shared `enemy-source-spell-<id>` ID
|
||||
format and carries utility tags for the form and linked passive ID, allowing
|
||||
existing source-aura cleanup and telemetry to identify it.
|
||||
|
||||
## Historical source checked
|
||||
|
||||
Read-only reference: `../wow-pvt-server-backups-2/azerothcore-wotlk`.
|
||||
|
||||
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp`: form-to-passive mapping,
|
||||
child aura cleanup, replacement of existing shapeshift auras, and stance Rage
|
||||
reset on removal.
|
||||
- `src/server/game/Spells/SpellInfo.cpp`: `CheckShapeshift` reads
|
||||
`ShapeshiftMask`, `ShapeshiftExclude`, and `NOT_SHAPESHIFT`.
|
||||
- `src/server/game/Spells/Auras/SpellAuraDefines.h`: aura IDs 4, 10, 79, 87,
|
||||
and 280.
|
||||
- `src/server/game/Combat/ThreatManager.cpp`: aura 10 is consumed as a
|
||||
multiplicative threat modifier by school mask.
|
||||
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp` and the server scripts
|
||||
plus SQL update tree: no 7376-specific dummy effect or linked-spell consumer
|
||||
was found.
|
||||
|
||||
The targeted helper tests check both profile rows, exclusivity, supported
|
||||
damage/threat modifiers, and the permanent versus timed duration. No full test
|
||||
suite, build, or live combat run is part of this source audit.
|
||||
@@ -0,0 +1,112 @@
|
||||
# Enemy stances and NPC blocking — 2026-10-05
|
||||
|
||||
The approved continuation implements NPC Defensive/Battle Stance and Improved
|
||||
Blocking for ordinary source-backed WoW creatures. Separate GPT-6 Luna workers
|
||||
with extra-high reasoning supplied source helpers, integration tests and live
|
||||
QA. The level cap remains 80; loot and readiness promotion are outside scope.
|
||||
|
||||
`enemyStances.ts` binds NPC forms 18/17 to core-owned passives 7376/21156 using
|
||||
the selected Ascension/Epoch client. The shared source aura is the only owner
|
||||
of its stance modifiers. Defensive lasts 180 seconds and multiplies all-school
|
||||
damage taken by 0.9 and dealt by 0.95. Battle is permanent until replacement or
|
||||
removal. The exclusive group prevents both forms remaining active. Reset,
|
||||
evade and expiry remove the owned modifiers. Ascension Battle has zero numeric
|
||||
child effects but retains its form identity. Epoch threat modifiers are stored
|
||||
without altering the incoming party threat table; this runtime has no hostile
|
||||
NPC outgoing-threat consumer. Ascension Defensive's DUMMY +42 remains
|
||||
unsupported because no source handler was established.
|
||||
|
||||
`enemyBlocking.ts` provides an ordinary Creature baseline of 5% plus block aura
|
||||
percentage points, and block value `floor(level / 2)`. Historical Creature
|
||||
Strength stays zero; the loaded class-level Strength column is not assigned
|
||||
to ordinary creatures. This baseline has no equipment/shield requirement.
|
||||
The shared player/companion damage resolver applies the level-based skill
|
||||
adjustment once, real target facing, active cast/control and evade gates, and
|
||||
the pinned template `flags_extra` NO_BLOCK bit. Improved Blocking adds 75
|
||||
percentage points for six seconds. Its effect expires exactly at the aura
|
||||
boundary. Native RoM attackers use the same ordinary WoW target defense path;
|
||||
native RoM defenders and character/summoned defenders retain their own models.
|
||||
|
||||
This initial stance pass enables the sourced auto-attack block baseline. The
|
||||
subsequent [spell continuation](NPC_SPELL_BLOCKING_2026-10-05.md) imports per-rank
|
||||
defense attributes and enables direct physical spell mitigation for player and
|
||||
party casts, including crit-plus-block. Periodic and non-direct full-hit spell
|
||||
blocks remain excluded. Missing source flags, levels outside 1–80 or missing
|
||||
spatial evidence disable this block baseline. Runtime Totems/Guardians are
|
||||
outside ordinary-creature scope; template type is not a safe Totem identifier.
|
||||
Ignore-hit-direction auras are not newly imported by this batch.
|
||||
The source CONTROLLED set is stun/fear/confuse. The runtime additionally treats
|
||||
sleep/blind/knockdown/freeze as unable to defend, matching its incapacitation
|
||||
model; this is a simulator approximation. A plain root still permits blocking.
|
||||
|
||||
The world importer now preserves `flags_extra` without changing any other
|
||||
reference fields: all 1,671 selected templates have an exact mask.
|
||||
None of the selected masks sets NO_BLOCK; that gate is verified through the
|
||||
importer fixture and pure helper, rather than claimed as a live Stockade case.
|
||||
The campaign
|
||||
compiler validates form and profile-specific child signatures, including raw
|
||||
duration indices, attributes, equipped-item masks, targets, school masks,
|
||||
triggers and effect amounts before enabling the three reviewed parent spells.
|
||||
Both source profiles must be present; fallback cannot substitute one for the
|
||||
other. Generated JSON and compressed TypeScript are refreshed together.
|
||||
|
||||
Reviewed SmartAI self auras preserve one-shot flags and combat timing.
|
||||
Stockade Inmates apply Battle Stance after one idle second, before the pull;
|
||||
it is excluded from in-combat selection. Kam Deepfury applies Defensive once
|
||||
and repeats Improved Blocking on its source schedule. Reset re-arms the idle
|
||||
schedule. Non-boss SmartAI expansion is restricted to these three self auras.
|
||||
Catalog comparison against the preserved working baseline changes 14 entities
|
||||
in seven dungeons, with unrelated attacks, health and placements unchanged.
|
||||
|
||||
Focused checks, production build and live evidence are recorded below.
|
||||
Source details: [stances](ENEMY_STANCES_2026-10-05.md),
|
||||
[blocking](NPC_BLOCKING_2026-10-05.md). Live report:
|
||||
[full Stockade](STOCKADE_STANCES_BLOCKING_PLAYTEST_2026-10-05.md).
|
||||
|
||||
## Validation
|
||||
|
||||
- All 102 checks across the twelve affected Vitest files pass, including actual
|
||||
imported aura casts, idle preparation, player/companion block results,
|
||||
exact-boundary expiry, geometry, unsupported packets and source exclusions.
|
||||
- Ready-five passes seven Vitest and twenty Python checks. The world importer
|
||||
tests pass seven cases; compiler regeneration passes both strict profiles.
|
||||
- Independent Luna review confirms formulas, source boundaries, skill applied
|
||||
once, stance pins and idle timing. Its control-label precision finding is
|
||||
recorded as the explicit simulator approximation above.
|
||||
- Production build passes with its content/asset prechecks, 8GB TypeScript/Vite
|
||||
and compression/release-bundle hooks. An incorrect test type import and a
|
||||
separate concurrent test's ClassId annotation were corrected before the final
|
||||
passing build; no runtime behavior changed in those corrections.
|
||||
- Pre-live release check passes (211 changed paths including unrelated work).
|
||||
One unrelated file's mixed CRLF/LF was normalized to LF for required hygiene.
|
||||
Final release check passes 240 changed paths, including concurrent unrelated
|
||||
work; the count is not a claim that every path belongs to this continuation.
|
||||
- Frozen full Stockade live validation passes on 5,964 files / 116,405,610 bytes,
|
||||
aggregate SHA-256
|
||||
`1fcd021af0ef90c8d994cf1ab853ef0e62f4d4767fa3acaab698b14121194310`.
|
||||
Mutable dist stayed unchanged during the verified copy; the frozen aggregate
|
||||
stayed identical before and after live QA.
|
||||
- Run `20261005-184333429` enters the normal full dungeon as a level-30
|
||||
Discipline Priest with four Ready companions. The native results screen
|
||||
confirms all five exact boss IDs, Easy/Normal, at 24:25.4. No observed player
|
||||
or party deaths or resurrection recoveries occurred; all finish alive.
|
||||
Natural progression ends at player level 40 / companions 39, within cap 80.
|
||||
- Live state contains Defensive/Battle and Improved Blocking auras, plus eight
|
||||
party attacks blocked by hostile NPCs and 141 hostile attacks blocked by the
|
||||
party. Blocked amounts are retained only for the 33 samples matching the
|
||||
latest damage event's outcome/raw amount; this is sampled correlation, not
|
||||
a stronger actor-and-event-linked packet assertion. Remaining outcomes keep
|
||||
their amount unknown. Deterministic tests supply unobserved boundaries and
|
||||
melee/player/native-RoM attacker cases.
|
||||
Reconstruction keys aura applications by instance ID plus application time:
|
||||
one Defensive, 34 Battle and one preserved Improved Blocking application.
|
||||
Additional short Improved Blocking applications remain unverified by live
|
||||
sampling. The corrected wrapper and prepare-only syntax checks pass.
|
||||
- Root reviewed the 25/50/75-percent scene captures and native full-clear image.
|
||||
Bodies and weapon/shield silhouettes render; existing overlap/edge occlusion
|
||||
remains. There are zero page errors and one missing-favicon console 404.
|
||||
All 2,124 fetched hash-addressed content objects verify. The overall content
|
||||
manifest changed during the run, so whole-content immutability is not claimed.
|
||||
The live report records source-provenance and sampling limits, along with the
|
||||
preserved superseded first attempt.
|
||||
The run-owned runner/browser have exited and temporary harnesses are removed.
|
||||
@@ -0,0 +1,121 @@
|
||||
# Enemy triggered shout audit — 2026-10-06
|
||||
|
||||
This report covers only separate-victim child spells from Intimidating Shout
|
||||
5246 and Frightening Shout 19134. It preserves the existing caster-centered
|
||||
fear source contract and keeps unsupported source effects explicit.
|
||||
|
||||
## Pinned client evidence
|
||||
|
||||
The Ascension input is
|
||||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
|
||||
SHA-256
|
||||
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`. The
|
||||
Epoch input is
|
||||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
|
||||
SHA-256
|
||||
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. Both
|
||||
use the existing shared patch-S `SpellDuration.dbc` and `SpellRadius.dbc`
|
||||
fallbacks; Epoch is not represented as carrying untouched sibling support
|
||||
tables. The matching source pins also live in `enemySourceAuras.ts`.
|
||||
|
||||
Direct reads from both `WDBC` inputs confirm raw Spell.dbc field 212 is
|
||||
`MaxAffectedTargets` (5246 = 5; 19134 = 0) and field 2 is `Dispel` (0 for
|
||||
both parents and both children). `DamageClass` is field 213; `Attributes2` is
|
||||
field 6 and is zero on all four rows. The profile signatures below are kept
|
||||
separate, including Epoch 5246's Attributes1 value 136.
|
||||
|
||||
| Parent cast | Explicit child spell | Parent range | Parent area | Area target cap | Parent fear duration: Asc / Epoch | Child control duration: Asc / Epoch |
|
||||
| --- | --- | ---: | --- | ---: | ---: | ---: |
|
||||
| 5246 Intimidating Shout | 20511 Intimidating Shout | 8 yd | Caster-centered hostile radius 8 yd | 5 | 5 s / 8 s | Stun 5 s / 8 s |
|
||||
| 19134 Frightening Shout | 29544 Frightening Shout | 10 yd | Caster-centered hostile radius 8 yd | 0 (unlimited) | 4 s / 6 s | Fear 3 s / 6 s |
|
||||
|
||||
Each parent has effect 0 `TRIGGER_SPELL` (effect type 64), target A 6
|
||||
(`TARGET_UNIT_TARGET_ENEMY`), and the exact child ID shown above. Each child
|
||||
has target A 6, target B 0. Parent effects 1 and 2 use target A 22
|
||||
(`TARGET_SRC_CASTER`) plus target B 15 (`TARGET_UNIT_SRC_AREA_ENEMY`) at
|
||||
radius index 14 (8 yd). The first area aura is fear, aura 7. Effect 2 is aura
|
||||
31 (`MOD_INCREASE_SPEED`, +25%) and remains unsupported.
|
||||
|
||||
Child 20511 is stun aura 12 on both profiles. Ascension also has aura 87
|
||||
(`MOD_DAMAGE_PERCENT_TAKEN`) for +15% physical damage taken over 5 seconds;
|
||||
it has no direct damage effect. Epoch 20511 contains only the 8-second stun.
|
||||
Child 29544 is fear aura 7 only: 3 seconds in Ascension and 6 seconds in
|
||||
Epoch. It likewise has no direct damage effect. Battle Shout 9128 and
|
||||
Demoralizing Shouts 16244/13730 have no DBC trigger ID in either selected
|
||||
profile, so their names do not qualify them for this triggered-child path.
|
||||
|
||||
The existing direct aura baseline remains owned by `enemySourceAuras.ts` and
|
||||
its existing attack-catalog contract. This report does not replace those rows
|
||||
with the triggered-shout child contracts or claim full implementation of
|
||||
parent effect 2.
|
||||
|
||||
## Targeting and core behavior
|
||||
|
||||
The read-only historical source used for the targeting audit is under
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/`.
|
||||
`SpellEffects.cpp` `Spell::EffectTriggerSpell` supplies the parent effect's
|
||||
`unitTarget` to the child when `NeedsToBeTriggeredByCaster` is true;
|
||||
`SpellInfo.cpp` returns true when the child requires an explicit unit target.
|
||||
That establishes one child victim: the parent's explicit hostile victim.
|
||||
The runtime helper therefore accepts that victim only if the caller's
|
||||
hostile/range/LOS recheck still considers it eligible. It never chooses a
|
||||
different secondary target for the child.
|
||||
|
||||
The same source's `Spell::SelectEffectImplicitTargets` combines area effects
|
||||
whose target A/B, implicit conditions and calculated radius match. Here
|
||||
effects 1 and 2 share the same pair and radius, so one caster-centered area
|
||||
recipient selection receives their effect mask. `SelectImplicitAreaTargets`
|
||||
limits that set using `MaxAffectedTargets` when nonzero, then
|
||||
`AddUnitTarget` merges effect masks when a target GUID already exists. There
|
||||
is no exclusion of the explicit cast victim from the area result: if it is
|
||||
also a valid hostile within 8 yards, it can receive both the child and the
|
||||
parent area aura. Accordingly `planEnemyTriggeredShoutTargets` returns the
|
||||
eligible explicit child victim separately and preserves the area list
|
||||
unchanged.
|
||||
|
||||
`WorldObjectSpellAreaTargetCheck` applies 3D radius and the base spell target
|
||||
check; `WorldObjectSpellTargetCheck` applies hostile eligibility. These area
|
||||
checks do not add a per-recipient line-of-sight test. The parent explicit
|
||||
victim still follows ordinary explicit-cast checks. Spell.dbc has no
|
||||
`Attributes2` ignore-LOS flag for these parents. The caller remains
|
||||
responsible for game-specific visibility/LOS eligibility when forming each
|
||||
input list; the pure targeting helper does not perform spatial queries.
|
||||
|
||||
The area cap applies to the parent area recipients only: 5 for 5246 and no
|
||||
cap for 19134. The child is a separate triggered cast with one explicit unit
|
||||
target. No extra max-target cap is applied to the parent's area list, and no
|
||||
synthetic damage packet is introduced for either child.
|
||||
|
||||
## Overlap and lifecycle contract
|
||||
|
||||
Parent and child control remain separate named timed auras so control-removal
|
||||
paths, expiry and caster refresh can retain each sourced timer. The shared utility tag is
|
||||
`enemy-control-source:<fear|stun>`. Effective shout control is resolved from
|
||||
currently active tagged auras on the requested target: the aura with the
|
||||
latest expiry supplies the runtime mechanic/timer, with stun winning an exact
|
||||
expiry tie. Thus an Ascension 19134 overlap resolves to parent fear through
|
||||
4 seconds after its child fear expires at 3 seconds; a 5246 child stun wins
|
||||
when its expiry ties the parent fear. Epoch 19134 ties are both fear, while
|
||||
Epoch 5246 ties resolve to stun.
|
||||
|
||||
All four DBC rows have Dispel 0, so the source does not mark these control
|
||||
auras as dispellable. The source children have stack amount zero and no
|
||||
`AURA_UNIQUE` bit in either profile. The project aura policy refreshes an existing same-caster copy and
|
||||
preserves a different caster's active same-spell application. Removal of a
|
||||
shout caster retains these four timed control aura IDs on other targets:
|
||||
`enemy-control:source-spell-20511`, `enemy-control:source-spell-29544`,
|
||||
`enemy-control:source-spell-5246`, and `enemy-control:source-spell-19134`.
|
||||
Removing the recipient still removes its auras.
|
||||
|
||||
## Boundaries
|
||||
|
||||
This source pass does not model parent aura 31's +25% movement speed, immune
|
||||
target exceptions, creature-specific AoE immunity, random selection ordering
|
||||
when 5246 has more than five area recipients, or every server/database script
|
||||
override. Historical SmartAI rows establish source NPC casts but do not change
|
||||
the DBC target geometry. The runtime's incoming eligible target snapshots
|
||||
remain authoritative. A client/core difference or changed source pin must
|
||||
fail the exact signature check rather than broaden behavior by spell name.
|
||||
|
||||
Focused verification: `npx vitest run src/game/enemyTriggeredShouts.test.ts
|
||||
src/game/enemySourceAuras.test.ts`.
|
||||
@@ -0,0 +1,153 @@
|
||||
# Enemy utility and control completion — 2026-10-06
|
||||
|
||||
## Implemented behavior
|
||||
|
||||
Ordinary source Creature self-casts can import Critical Block 47294–47296
|
||||
through a separate guarded path. The known template, identical caster/target,
|
||||
complete profile/rank signature and default-core aura 107 applicability proof
|
||||
are required. Aura107 spell modifiers are no-ops for non-player targets on
|
||||
that audited default path; aura 253 supplies critical-block chance. The generic
|
||||
importer and Deterrence remain gated. No source creature assignment was found,
|
||||
so this pass assigns no new NPC cast. A labeled synthetic runtime fixture
|
||||
proves permanent application, critical blocking, no damage and reset cleanup.
|
||||
|
||||
Exact WoW335 Shield Bash 72 now rolls one ordinary-NPC block stage before the
|
||||
player and companion utility effect loops. Full blocking cancels the entire
|
||||
recipient effect list while retaining the accepted cast's cost and cooldown.
|
||||
A zero-amount cast result carries the block flag; no damage packet is
|
||||
fabricated. Existing facing, casting, control, no-block, native, summon and
|
||||
character-defender gates remain authoritative. An actively casting NPC cannot
|
||||
block, so an unblocked interrupt still uses the existing interruption path.
|
||||
This stage adds block only; other utility hit/avoidance behavior is unchanged.
|
||||
Additional ranks, profiles and unknown custom attributes are not inferred.
|
||||
|
||||
Source shouts 5246/19134 apply parent aura 31's +25% movement speed alongside
|
||||
their caster-centered fear. Player and companion movement consume the
|
||||
strongest active target-local tagged bonus. Fear and speed share the parent
|
||||
aura's adjusted lifetime, source-caster refresh and caster-removal persistence.
|
||||
Baseline durations remain 5/4 seconds in Ascension and 8/6 seconds in Epoch.
|
||||
The source core adjusts one shared parent aura duration; a fear-duration
|
||||
modifier therefore shortens its speed rider too.
|
||||
|
||||
All four parent/child rows carry spell-level MECHANIC_FEAR. Whole-spell fear
|
||||
immunity rejects their controls and riders before per-effect immunity checks.
|
||||
Stun immunity alone strips 20511's stun effect while preserving Ascension's
|
||||
separate +15% physical-damage-taken rider. Epoch has no such physical rider.
|
||||
Compiler pins now include spell mechanic and all eight raw attribute words;
|
||||
regenerated campaign JSON is byte-for-byte identical to the starting snapshot.
|
||||
|
||||
## Source boundaries
|
||||
|
||||
The stance/Thrash audit rechecks four active world tables against both locks
|
||||
at world commit 4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3, separately from the
|
||||
read-only historical core e822d718 behavior reference. Ascension passive 7376's
|
||||
third effect is fixed DUMMY +42, with no recovered handler/registration; the
|
||||
core correction only suppresses caster procs. It remains metadata-only.
|
||||
Targorr 1696 is SmartAI. Its three source rows cast 674, cast 8599 at low health,
|
||||
and talk; no row schedules 3391. The template spell list establishes Thrash
|
||||
availability, and CombatAI's separate scheduler cannot supply SmartAI timing.
|
||||
The existing simulator cadence is retained and remains explicitly approximate.
|
||||
|
||||
The existing player/party/summon fear policy immobilizes rather than reproducing
|
||||
source fleeing AI. Eligible summons can receive the source aura, but their
|
||||
control loop returns before movement for that shared lifetime. General Magic hit/resist/deflect, already-active aura purge
|
||||
on an unidentified immunity grant, wider utility full hit tables, Deterrence
|
||||
siblings, native custom equipment/rates/prerequisites and broader weapon/proc
|
||||
formulas remain separate gaps. The shout rows alone do not prove an immunity
|
||||
grant's `IMMUNITY_PURGES_EFFECT` flag. Shield Bash retains trigger 29703 in its
|
||||
parent descriptor, but the Daze child is absent from the runtime catalog;
|
||||
this pass cancels trigger execution on full block without claiming a live
|
||||
child application.
|
||||
|
||||
Source reports:
|
||||
[Critical Block imports](NPC_CRITICAL_BLOCK_IMPORTS_2026-10-06.md),
|
||||
[utility blocking](UTILITY_SPELL_BLOCKING_2026-10-06.md),
|
||||
[shout speed/immunity](ENEMY_SHOUT_SPEED_IMMUNITY_2026-10-06.md), and
|
||||
[stance/Thrash audit](STANCE_THRASH_SOURCE_AUDIT_2026-10-06.md).
|
||||
|
||||
## Validation
|
||||
|
||||
The directly affected helper/runtime selection covers 96 passing tests across
|
||||
15 files, including the final 15-test shout file and four new actual utility
|
||||
runtime tests. Runs overlap and are not additive. The player utility fixture
|
||||
proves one block result, normal completion telemetry, retained cost/cooldown
|
||||
and no damage. The companion fixture is a synthetic accepted pending cast
|
||||
completed through the real executor. Casting-defender interruption and all
|
||||
excluded defender types are covered. Six compiler source-pin Node tests pass,
|
||||
including all shout attribute words and Critical Block sibling drift.
|
||||
Ready-five passes 7 Vitest and
|
||||
20 Python tests, and avatar checks pass 56 tests. The production build passes
|
||||
TypeScript with 8GB memory, Vite, environment audits, compression and release
|
||||
bundle verification. Existing prehooks regenerate the same 9-boss/23-item loot
|
||||
catalog; this task adds no loot wiring. No full suite or all-class sweep runs.
|
||||
|
||||
Luna's read-only review finds no confirmed defect in the shared block,
|
||||
Critical Block, shout or compiler integration. Final utility tests and an
|
||||
8GB TypeScript check pass after adding their fixtures. No production source
|
||||
changes follow the final build/freeze.
|
||||
|
||||
## One final live check
|
||||
|
||||
Run `playtest-artifacts/stockade-weapon-utilities/20261006-141251022/` enters
|
||||
Cellblock Rush normally with a UI-created Discipline Priest and four Ready
|
||||
companions. Isolated pre-entry preparation sets level 30; gameplay uses ordinary
|
||||
movement, targeting, healing and party commands with read-only telemetry.
|
||||
No Boss Testing, teleports, combat-state writes or enemy/aura seeding occur.
|
||||
|
||||
The seeded boss is **Targorr the Dread**, entry 1696, source/live
|
||||
`creature-84027`. Native killed-boss progress and the visible results overlay
|
||||
agree on **1/1** in **03:09.2**. No player or party deaths occur. Seven effective
|
||||
player healing events total 2,337, with 95 overheal. The result certifies this
|
||||
one-boss slice; the harness's historical full-clear field names do not mean
|
||||
the five-boss full Stockade campaign was tested.
|
||||
|
||||
The committed recorder retains 749 consecutive events, IDs 9–757, with no gaps,
|
||||
errors, discarded events/states or coverage issues. Source NPC hand results
|
||||
include 56 mainhand, four offhand and two Thrash extra-mainhand outcomes; the
|
||||
extra swings retain source 3391. They demonstrate the existing simulator
|
||||
schedule/effect, not a source-proven Targorr cadence. Player/party hand results
|
||||
total 172. Three committed Disarm windows contain seven hand results; this
|
||||
overlap is evidence of actual events, not independent proof of contribution
|
||||
formulas. Three Disarm and 42 Wound snapshots are observed. Block/shout and
|
||||
Bloodlust aura applications are unobserved; no live claim is made for them.
|
||||
Critical Block has no real source creature assignment in this catalog.
|
||||
|
||||
Root inspects roster, dungeon equipment silhouette, mid-route and the native
|
||||
results image (`bite-sized-stormwind-stockade-boss-arrival.png`). Player/party
|
||||
bodies and staff, shield and blade silhouettes are visible. Overlap and HUD
|
||||
occlusion prevent a complete per-companion gear inspection. There are no page
|
||||
exceptions; the sole outer console item is a favicon 404.
|
||||
|
||||
The build freeze is
|
||||
`artifacts/enemy-utility-control-2026-10-06/corrected-build-20261006-140236745/`:
|
||||
5,967 files, 118,061,079 bytes, aggregate SHA-256
|
||||
`8cf9513613aa3ef6a0a64de392e90521b0349d85311f930ba8808e868d6867d9`.
|
||||
The unchanged isolated content copy is reused from the earlier fully verified
|
||||
freeze: 27,571 objects, 6,489,632,021 bytes, manifest SHA-256
|
||||
`ac0fa2a867ba0a495c172de2b89532d69b32d56d032482b26020ce2d189f074b`.
|
||||
The new freeze rehashes the complete build and both content manifests; it does
|
||||
not recopy unchanged content objects. Before/after fingerprints agree. The
|
||||
harness verifies 2,124 actually served manifest-referenced hash-addressed
|
||||
objects with zero integrity failures. Raw network bodies are not retained;
|
||||
evidence joins recorded URLs/status with the immutable local source files.
|
||||
|
||||
The independent evidence-audit follow-up also fails with Luna capacity. Root
|
||||
runs `root-evidence-audit.cjs` in the current live evidence folder, rehashing
|
||||
all 5,967 frozen files, seven recorded loaded chunks and all 2,124 served
|
||||
manifest objects (77,019,550 bytes), with zero failures. It independently
|
||||
recomputes consecutive event IDs, native one-boss completion, zero deaths and
|
||||
the error boundary from retained artifacts. `root-evidence-audit.json` labels
|
||||
this root fallback explicitly; it is not presented as a completed subprocess
|
||||
audit. No higher-tier subprocess is selected.
|
||||
|
||||
All subprocesses use GPT-6 Luna with extra-high reasoning. The utility runtime
|
||||
follow-up failed because that model was at capacity; root completed its four
|
||||
tests directly without upgrading a subprocess. Level cap 80,
|
||||
Ready-five certification and loot scope remain unchanged. The shared workspace
|
||||
contains concurrent edits; no staging, commit or deployment is part of this
|
||||
pass. Historical source trees remain read-only.
|
||||
|
||||
Final `npm run release:check` passes 478 changed paths, including untracked
|
||||
files. Game and vault diffs are checked separately; all 13 task documents
|
||||
pass EOF and trailing-whitespace checks. Canonical notes and the closed
|
||||
worklog record the implemented behavior and remaining boundaries.
|
||||
@@ -0,0 +1,128 @@
|
||||
# Enemy weapon debuffs source audit — 2026-10-05
|
||||
|
||||
This note records the source contract for enemy Disarm (6713) and Infected
|
||||
Wound (17230). The active game uses the selected Ascension or Epoch `Spell.dbc`
|
||||
profile; the repository compiler's source rows are in
|
||||
`scripts/dungeon-pipeline/compile-campaign-catalog.mjs`, and the pure contracts
|
||||
and channel predicates are in `src/game/enemyWeaponDebuffs.ts`.
|
||||
Character-side Disarm checks are in `src/game/enemyDisarmRuntime.ts`.
|
||||
|
||||
## Pinned client rows
|
||||
|
||||
The Ascension source is
|
||||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`,
|
||||
SHA-256 `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
|
||||
The Epoch source is
|
||||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`,
|
||||
SHA-256 `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`.
|
||||
The pinned duration and radius fallback tables are the shared patch-S tables
|
||||
recorded in `src/game/enemySourceAuras.ts`.
|
||||
|
||||
Both profiles define Disarm 6713 as range index 2, physical school mask 1,
|
||||
melee damage class 2, mechanic 3, duration 5 seconds, zero stacks, no dispel,
|
||||
and `EquippedItemClass = -1` (no caster weapon requirement). Ascension has
|
||||
Aura 67 (main-hand) and Aura 278 (ranged); Epoch has Aura 67 only. Aura 254
|
||||
(off-hand) is absent from both rows. These effects disable only the named
|
||||
weapon attack channels; they do not silence spell casts. The profile helper
|
||||
requires the target to have at least one affected usable weapon slot before
|
||||
application. For a player, an already-disarmed slot is no longer usable for
|
||||
this check, so a repeated cast may fail before refreshing that slot; a creature
|
||||
target is checked by the presence of its virtual item slot instead. When a cast
|
||||
is accepted, the zero-stack aura refreshes its duration. The source-derived
|
||||
Disarm spell itself applies only after its melee hit result lands.
|
||||
|
||||
Both profiles define Infected Wound 17230 as range index 2, Nature school mask
|
||||
8, damage class 0, duration 300 seconds, zero stacks, Disease dispel type 3,
|
||||
and no caster weapon requirement. Its single Aura 14 effect has amount +6 and
|
||||
misc value 1 (physical school mask). Aura 14 adds six flat damage to matching
|
||||
physical packets; it is not a six-percent modifier. The aura refreshes without
|
||||
stacking and can be removed by a friendly Disease dispel. As a damage-class
|
||||
NONE aura-only spell, the AzerothCore hit-result path has no miss/dodge roll
|
||||
for it after its ordinary immunity/evade checks. A caller modeling it as part
|
||||
of a separate landed weapon attack must use that attack result as its own gate.
|
||||
|
||||
## Historical core behavior
|
||||
|
||||
The sibling `../wow-pvt-server-backups-2/azerothcore-wotlk` tree is used only
|
||||
as read-only behavior evidence:
|
||||
|
||||
- `src/server/game/Spells/SpellInfo.cpp` checks the target's matching weapon
|
||||
channels for mechanic Disarm. Players use a usable equipped weapon; creatures
|
||||
use virtual item slots. Main-hand, off-hand, and ranged channels are checked
|
||||
independently.
|
||||
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp` maps Aura 67 to main-hand,
|
||||
Aura 254 to off-hand, and Aura 278 to ranged. Applying a channel removes the
|
||||
player's item-dependent aura and damage contribution, keeps the item
|
||||
equipped, then sets the corresponding unit flag. Creatures with configured
|
||||
equipment recalculate their physical damage. Clearing the aura reverses the
|
||||
temporary weapon changes.
|
||||
- `src/server/game/Entities/Unit/Unit.h` maps those flags through
|
||||
`CanUseAttackType`. `Unit::AttackerStateUpdate` does not gate ordinary main-hand
|
||||
swings on that flag, so the character still makes an unarmed main-hand swing.
|
||||
`Player::_ApplyWeaponDamage` clears disarmed ranged weapon damage and resets
|
||||
its delay; for a non-feral main hand it sets base damage to 1–2 and attack
|
||||
time to 2000 ms while preserving equipped item stats. Feral forms return
|
||||
before that weapon reset. `Spell.cpp` chooses
|
||||
melee `m_attackType` as main-hand by default or off-hand when the spell has
|
||||
`REQUIRES_OFF_HAND_WEAPON`; ranged spells use the ranged channel only when
|
||||
marked as ranged-weapon spells. The source flags for strict main-hand and
|
||||
off-hand requirements are Spell AttributesEx3 bits `0x00000400` and
|
||||
`0x01000000`. NPC `CheckItems` rejects a damage-class melee/ranged spell when
|
||||
its selected attack channel is unavailable. Player `CheckItems` checks
|
||||
explicit item requirements through `GetUseableItemByPos`; class `-1` passes
|
||||
without an equipment gate, while class-2 requirements scan usable matching
|
||||
weapons across main-hand, off-hand, and ranged slots. A matching off-hand
|
||||
weapon therefore keeps a generic class-2 requirement usable under Ascension
|
||||
or Epoch Disarm. For a nonpassive aura spell, the core also preserves casting
|
||||
when the matching item remains equipped but Disarm made it unusable; the
|
||||
explicit strict main/off-hand attribute checks still require that slot's
|
||||
weapon. `Item::IsFitToSpellRequirements` applies class, subclass, and
|
||||
inventory-type masks.
|
||||
- `Unit.cpp` applies Aura 14 through `MeleeDamageBonusTaken` for weapon damage,
|
||||
before armor mitigation. Non-direct spell packets, including periodic packets,
|
||||
reach `SpellBaseDamageBonusTaken` through `SpellDamageBonusTaken` and get the
|
||||
flat amount when the aura's misc school mask overlaps. The direct spell
|
||||
damage path returns before `SpellBaseDamageBonusTaken`, so this audit does not
|
||||
claim a bonus for ordinary direct magic spells. This aura has no charges, so the core's special
|
||||
charged-aura DoT exclusion does not apply. The bonus enters before armor
|
||||
mitigation; melee/ranged spell block follows armor, and damage absorbs resolve
|
||||
after the damage calculation.
|
||||
- `Unit::SpellHitResult` sends Disarm's melee damage class through melee miss,
|
||||
dodge, and parry resolution. Infected Wound's damage class is NONE and its
|
||||
only effect is an aura, so it does not take that melee result path.
|
||||
|
||||
The contract deliberately does not turn Disarm into root, stun, silence, or a
|
||||
general physical-action lock. Runtime callers own weapon-specific equipment
|
||||
state, resolved spell hit outcomes, armor/block/absorb ordering, and aura
|
||||
application/removal.
|
||||
|
||||
The player Disarm handler removes weapon-dependent auras and recalculates the
|
||||
weapon damage contribution while the item remains equipped. It does not call
|
||||
the item-stat removal routine, so the weapon's equipped STR/AP/stamina
|
||||
modifiers remain. The helper `enemyDisarmInvalidatesAbilityRequirement` models
|
||||
explicit spell item class and subclass gates from currently usable equipped
|
||||
items; it leaves requirements with item class `-1` unblocked and only reports a
|
||||
Disarm-caused failure when every matching item is in a channel this source row
|
||||
disables. `enemyDisarmBlocksAbilityCast` adds the core exception for
|
||||
nonpassive aura casts and the strict main/off-hand flags. Runtime attack checks
|
||||
derive channels from the unexpired exact `enemy-disarm:<profile>:<slot>` tags;
|
||||
they never mutate saved equipment or nonweapon stats. Ascension item-requirement
|
||||
metadata uses the corrected WotLK Spell.dbc fields 68/69/70 (class, subclass
|
||||
mask, inventory mask). The previous generator read 67/68, which incorrectly
|
||||
exported class 0 and a subclass value from the class column; regeneration
|
||||
changed only those three equipped-item fields and the generated timestamp.
|
||||
WoW-ruleset main-hand auto damage uses the source unarmed 1–2 base and 2-second
|
||||
delay while retaining character AP and other equipped stats; an unaffected
|
||||
off-hand remains active, and feral forms keep their form profile. Ranged auto
|
||||
channels named by the active source profile are suppressed. Native RoM unarmed
|
||||
damage is left to its existing amount path because no bound core formula was
|
||||
verified. This pass also does not claim complete removal of all weapon-dependent
|
||||
item aura bonuses or generic ability formulas that derive damage from raw weapon
|
||||
stats.
|
||||
|
||||
## Focused validation
|
||||
|
||||
Run `npx vitest run src/game/enemyWeaponDebuffs.test.ts src/game/enemyDisarmRuntime.test.ts src/game/enemyDisarmRuntime.integration.test.ts`
|
||||
for profile signatures, target/channel eligibility, refresh/dispel, cast gates,
|
||||
metadata projection, and pre-mitigation school matching. Player and companion
|
||||
execution are additionally covered by their focused integration tests.
|
||||
@@ -0,0 +1,154 @@
|
||||
# Enemy weapon utilities — 2026-10-05
|
||||
|
||||
## Scope
|
||||
|
||||
This continuation implements the authorized Bloodlust, Disarm/Infected Wound
|
||||
and Dual Wield/Thrash groups. Separate GPT-6 Luna extra-high subprocesses own
|
||||
their source helpers and tests; shared runtime and catalog integration preserve
|
||||
the existing level-80 cap, loot scope and Ready-five certification.
|
||||
Routine browser proof uses Stormwind Stockade: Cellblock Rush and records the
|
||||
actual seeded boss. Full Stockade campaigns remain separately selected.
|
||||
|
||||
## Source contracts
|
||||
|
||||
| Mechanic | Verified behavior |
|
||||
| --- | --- |
|
||||
| Bloodlust 6742 | One selected friendly creature, 30 seconds, +30% melee haste, Magic dispel. No party-wide aura radius. Separate source haste factors multiply: Bloodlust and Enrage give interval factor 100/169. |
|
||||
| Disarm 6713, Ascension | Five seconds; main-hand and ranged channels. Offhand and casting remain available subject to exact equipped-item requirements. |
|
||||
| Disarm 6713, Epoch | Five seconds; main-hand channel only. |
|
||||
| Infected Wound 17230 | Five minutes; Disease dispel; +6 flat physical damage taken before armor, block and absorbs. Its own Nature school does not determine the damage modifier's school. |
|
||||
| Dual Wield 674/29651 | Non-damaging persistent creature capability. Explicit enabled mode uses the source creature baseline for an independent offhand, with the core's 0.5 damage factor. |
|
||||
| Thrash 3391 | Two queued main-hand extra swings on the next unit update, separate ordinary hit/mitigation results. The spell itself is not a direct-damage packet. |
|
||||
|
||||
The pinned Ascension and Epoch rows, shared support tables, core consumers and
|
||||
source limitations are in the subprocess audits:
|
||||
|
||||
- [Bloodlust](ENEMY_BLOODLUST_2026-10-05.md)
|
||||
- [Disarm and Infected Wound](ENEMY_WEAPON_DEBUFFS_2026-10-05.md)
|
||||
- [Dual Wield and Thrash](ENEMY_EXTRA_ATTACKS_2026-10-05.md)
|
||||
|
||||
Hamhock's raw SmartAI has a five-second, one-time self Bloodlust event with
|
||||
`SMARTCAST_AURA_NOT_PRESENT`, plus an independent event-16 missing-buff check
|
||||
within 30 yards and ten-second repeat. The latter selects one engaged living
|
||||
friendly creature. Targorr's raw Dual Wield event is in combat; Bazil's is out
|
||||
of combat, despite conflicting SQL comments. Numeric event IDs are authoritative.
|
||||
Targorr's template lists Thrash but this source set does not supply a SmartAI
|
||||
Thrash cast schedule. Any retained generic template cadence is simulator policy,
|
||||
not a recovered source schedule.
|
||||
|
||||
## Integration
|
||||
|
||||
The compiler emits source-bound utility effects instead of false direct hits.
|
||||
It retains both sourced Hamhock Bloodlust rules while suppressing the duplicate
|
||||
template fallback. Ordinary source auras use the shared authoritative aura
|
||||
array. Disarm state uses explicit channel tags; it does not become a blanket
|
||||
crowd-control state or remove equipped items. Weapon damage masking is temporary;
|
||||
non-weapon item stats and persisted equipment remain intact.
|
||||
|
||||
The WotLK ability importer had exported equipment metadata from fields 67/68.
|
||||
Independent raw Spell.dbc probes establish fields 68/69/70 for item class,
|
||||
subclass mask and inventory mask. The scoped refresh must preserve all other
|
||||
rank fields, including costs, effects, progression and spell-defense metadata.
|
||||
Classic Ascension equipment metadata requires the same field correction.
|
||||
|
||||
The metadata-only CoA refresh compares parsed current input/output before its
|
||||
write, allowing only the three equipment fields and synchronization timestamp.
|
||||
No persistent pre-refresh snapshot was retained; the former dirty working tree
|
||||
cannot now be independently reconstructed from HEAD. The final formatting-only
|
||||
rewrite was separately checked for parsed equality.
|
||||
|
||||
Timed direct Bloodlust, Disarm and Infected Wound auras on another actor survive
|
||||
caster death/removal or return-home cleanup. Removing the recipient and resetting
|
||||
the encounter still clears them. Existing cleanup for other aura families stays
|
||||
outside this change. Disarm target eligibility uses currently usable resolved
|
||||
weapons, so an unavailable weapon cannot refresh the debuff.
|
||||
|
||||
WoW-ruleset unarmed main-hand autos retain the core's 1–2 base, two-second delay,
|
||||
AP and other item stats. This includes RoM characters using WoW compatibility.
|
||||
Native RoM unarmed amounts, complete weapon-dependent aura removal and permitted
|
||||
generic weapon formulas remain source/runtime limits. Explicit source utility
|
||||
support does not supply missing automatic/flag-driven virtual equipment.
|
||||
|
||||
The existing enemy-team simulation does not model core faction hostility,
|
||||
map phase or object-size-expanded range. Selected friendly recipients therefore
|
||||
use the represented enemy team, engaged/living state, point distance and LOS.
|
||||
This is an explicit simulator boundary rather than an exact faction search.
|
||||
|
||||
## Validation
|
||||
|
||||
Completed focused checks cover 360 distinct Vitest cases, five Node cases and
|
||||
twenty Python cases. Repeated regression runs do not inflate these totals.
|
||||
|
||||
| Scope | Result |
|
||||
| --- | --- |
|
||||
| Shared aura/source contracts, imported aura execution and Bloodlust (six files) | 32 Vitest |
|
||||
| Selected source/Stockade campaign assertions | 11 Vitest; 22 unrelated cases skipped |
|
||||
| Avatar and equipment rendering invariants | 56 Vitest |
|
||||
| Shared combat results, stance/block/spell metadata and native exclusions (eight files) | 57 Vitest |
|
||||
| Actual imported Disarm application, unusable reapplication and expiry | 2 Vitest |
|
||||
| Dual Wield/Thrash helpers and imported runtime | 14 Vitest |
|
||||
| Disarm contracts/runtime/player-party execution plus affected party/combat files | 171 Vitest |
|
||||
| Actual imported Wound, physical packet kinds, mitigation, Cure Disease and caster removal | 10 Vitest |
|
||||
| Ready-five | 7 Vitest + 20 Python |
|
||||
| Equipment-column parser and pinned utility drift | 5 Node |
|
||||
|
||||
The standard 8GB TypeScript compilation passes. A default-output build reached
|
||||
Vite but hit Windows `EPERM` clearing the shared `dist/assets` folder. The same
|
||||
8GB TypeScript/Vite pipeline succeeds with the isolated output
|
||||
`artifacts/enemy-weapon-utilities-2026-10-05/production-dist`; standard prebuild
|
||||
asset audits, precompression and release-bundle verification pass. The shared
|
||||
build already had a restored index when checked and was preserved.
|
||||
Earlier test-fixture seed/timestamp type errors were corrected before this build.
|
||||
|
||||
The validated output is copied and checked before/after freezing. Its 5,964-file
|
||||
aggregate SHA-256 is
|
||||
`58dfe50765b0635caeae50bd3eca2fd079cd69cce0e571ff6cb2dd5aeec77b39`.
|
||||
Entry is `index-nDB7zewy.js`; combat is `combatStore-NW7YcPHP.js`.
|
||||
Frozen build/content live under
|
||||
`artifacts/enemy-weapon-utilities-2026-10-05/frozen-20261006-011726964/`.
|
||||
Content version is `content-62324661bc5f7a0e`, manifest SHA-256
|
||||
`36614a23f3b98b4289bc3726c8a9bdb075445ada50dfce6504ade4e36325be1f`.
|
||||
All 27,571 referenced objects (6,489,458,993 bytes; 21,597 logical files) were
|
||||
copied and independently verified against their manifest hashes.
|
||||
|
||||
The final Luna review found missing attribute pins for 674/29651/3391. The
|
||||
compiler now rejects profile-specific attribute drift and Thrash die-roll drift;
|
||||
its three tests pass. Regeneration validates both clients and leaves campaign
|
||||
JSON and compressed TypeScript byte-identical. Source spell availability does
|
||||
not establish missing Thrash timing.
|
||||
|
||||
Frozen Cellblock Rush run `20261006-012123000` selects Hamhock
|
||||
(`entry-1717`, `creature-79098`) and verifies its native 1/1 clear in 3:14.6.
|
||||
The level-30 Discipline player and four Ready companions enter normally; there
|
||||
are no observed player or party deaths. The build and content manifest remain
|
||||
unchanged, and all 2,124 served manifest-referenced objects were independently
|
||||
rehashed by root. The roster, dungeon equipment silhouettes and results capture
|
||||
were visually inspected. There are no page exceptions; the console records one
|
||||
`favicon.ico` 404.
|
||||
|
||||
This first run's checkpoint projection omits the new weapon fields even though
|
||||
the live-state reader captures them. All-null summarized weapon state therefore
|
||||
establishes a harness gap, not an absent game mechanic. The recorder now retains
|
||||
those fields through the checkpoint reducer and captures the three direct
|
||||
utility aura IDs globally, including player and party recipients.
|
||||
|
||||
Corrected run `20261006-013934624` uses the same frozen inputs and selects
|
||||
Bazil Thredd (`entry-1716`, `creature-79124`). It verifies the native 1/1 clear
|
||||
in 3:20.7 without player or party deaths. All 328 mob snapshots retain weapon
|
||||
fields; 35 show Bazil's Dual Wield capability enabled. All captured offhand
|
||||
timers are zero, no hand-specific swing is captured, and no nonempty extra
|
||||
queue is observed. Capability evidence does not establish an offhand hit.
|
||||
The global aura store supplies 26 snapshots of the tank's single Wound instance,
|
||||
with four distinct source/application-time tuples. Each is one stack, Disease,
|
||||
and exactly 300,000 ms; these are four observed applications/refreshes, not
|
||||
26 applications. Bloodlust and Disarm auras remain unobserved in this retest.
|
||||
Deterministic imported-runtime tests cover those mechanics and queued Thrash.
|
||||
|
||||
Root independently verifies unchanged build/content inputs, all 2,124 served
|
||||
objects and the actual entry/combat/runtime chunks again, and inspects the
|
||||
new roster, dungeon and native results captures. No page exceptions; one
|
||||
favicon 404. Both runs' `root-evidence-audit.json` files retain the audit scope.
|
||||
Final release hygiene passes, including untracked files; game and vault
|
||||
changes are reviewed separately. No full-source campaign or readiness promotion
|
||||
is inferred from these two ordinary one-boss routes.
|
||||
See [the scoped live report](STOCKADE_WEAPON_UTILITIES_PLAYTEST_2026-10-05.md).
|
||||
@@ -0,0 +1,84 @@
|
||||
# Hostile NPC threat boundary audit — 2026-10-06
|
||||
|
||||
## Decision
|
||||
|
||||
The `hostile-NPC outgoing threat` item in
|
||||
[`ACTIVE_CLASS_MECHANICS_BACKLOG.md`](ACTIVE_CLASS_MECHANICS_BACKLOG.md) is not
|
||||
a missing consumer for the current hostile-mob combat path. HealerMan stores
|
||||
each hostile mob's incoming target threat on that mob, keyed by the player,
|
||||
party, online-player, or summon actors that the mob can currently attack. Its
|
||||
enemy target selector has no hostile mob candidates, and the enemy-hit path
|
||||
does not write threat into the attacking mob's table. The current model has no
|
||||
NPC-versus-NPC target boundary to port.
|
||||
|
||||
Keep this source-parity item scoped as a future boundary. If hostile creatures
|
||||
later attack other threat-list-capable creatures, record the attacker in the
|
||||
recipient creature's threat list after checking that recipient's eligibility.
|
||||
Do not add outgoing threat to the source mob's own target table.
|
||||
|
||||
## AzerothCore holder and direction rules
|
||||
|
||||
The read-only behavior reference is AzerothCore HEAD
|
||||
`e822d718322289dd036fb2daf8867ba41283bf9a`. Its `ThreatManager.cpp` SHA-256 is
|
||||
`5f8ee4d9c8d9e6d41896b29769f0df315f62d789f2defa29df0a9912002f537b`; its
|
||||
`Unit.cpp` SHA-256 is
|
||||
`b7c0c68daee09ec1f863f9a8d6c4972c1adbe35fa5ec230a8887399395db1ed5`.
|
||||
|
||||
`ThreatManager::CanHaveThreatList` requires a creature. It excludes pets,
|
||||
totems, triggers, and player-summoned minions or guardians. `Unit::CanHaveThreatList`
|
||||
also rejects dead units and vehicles in battlegrounds or arenas. Players
|
||||
therefore do not own creature threat lists. These are rules about the **list
|
||||
holder**, not about who may appear as a target in a creature's list: a hostile
|
||||
creature can still track threat against a player or pet.
|
||||
|
||||
In `Unit.cpp:1276`, damage to a non-player victim calls
|
||||
`victim->AddThreat(attacker, damage, ...)`. `Unit::AddThreat` checks the
|
||||
recipient (`victim`) with `CanHaveThreatList()` and adds the attacker to that
|
||||
recipient's threat manager. `ThreatManager::CalculateModifiedThreat` applies
|
||||
the threat aura multiplier from the threat target passed to that manager,
|
||||
which is the damage source in this call. Thus damage threat belongs to the
|
||||
recipient list and is scaled by source-side threat modifiers.
|
||||
|
||||
## Current HealerMan path
|
||||
|
||||
`MobCombatState` carries `threatByActor`, `targetActorId`, and `forcedTarget`.
|
||||
`eligibleAggroActorIds` builds candidates from the living local player, living
|
||||
`PartyMember` records, live online-player actors, and living combat summons;
|
||||
each must have a position within the hostile mob's leash. `actorPosition`
|
||||
resolves positions from those same actor sources. The candidate builder does
|
||||
not enumerate other `MobCombatState` records.
|
||||
|
||||
Party records are playable-character builds with class, specialization, role,
|
||||
level, gear, and talent data. `companionActorFromMember` projects them as
|
||||
`kind: "companion"`, and `advanceDungeonPartyCombat` runs their combat actions.
|
||||
They are managed party actors, not unowned AzerothCore creature AI instances.
|
||||
`CombatSummon` records likewise carry an `ownerActorId` and a pet, totem, or
|
||||
summon kind. They are valid hostile-mob targets here; that does not make them
|
||||
threat-list holders.
|
||||
|
||||
When a party actor damages a mob, `damageMobInWork` adds threat under the
|
||||
source actor ID to that damaged mob's `threatByActor`. Healing adds source
|
||||
threat to each engaged living mob's table. The local threat aura lookup uses
|
||||
the source actor's aura set before the value is added. `advanceMobCombat`
|
||||
prunes each mob table to the eligible actors above and resolves that mob's
|
||||
target from those entries. Enemy attacks then resolve against that selected
|
||||
actor. The hit handling updates damage, health, and presentation state; it
|
||||
does not add threat to the attacking mob's own table.
|
||||
|
||||
Hostile NPC helpers are also stored as `MobCombatState` entries, distinct from
|
||||
player or party `CombatSummon` entries. A helper spawn records `summonedBy`;
|
||||
call-for-help seeds the helper's own table with the same selected party target.
|
||||
This preserves the current party-versus-hostile-mob model without adding a
|
||||
mob-to-mob target path.
|
||||
|
||||
## Backlog boundary
|
||||
|
||||
The current backlog phrase should remain future-facing or be narrowed when the
|
||||
backlog is next edited: source-side outgoing threat is only relevant to an
|
||||
enemy-versus-enemy consumer if that consumer models a living recipient creature
|
||||
with a threat list and a real target relationship. At that point, threat goes
|
||||
on the recipient and the holder gate applies there. Do not model it by
|
||||
inverting signs, mutating the attacker mob's table, or treating a playable
|
||||
party build as an ordinary unowned creature.
|
||||
|
||||
No runtime code, catalog, or backlog file was changed for this audit.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Mechanic parity and campaign boss pass - 2026-10-04
|
||||
|
||||
> **Future QA default (2026-10-04):** Use Stormwind Stockade for new routine live tests. The Wailing captures and commands in this dated report are historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
|
||||
## Outcome
|
||||
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
# 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).
|
||||
@@ -0,0 +1,152 @@
|
||||
# Ordinary enemy block aura parity — 2026-10-06
|
||||
|
||||
## Implemented contract
|
||||
|
||||
[`src/game/enemyBlockAuras.ts`](../src/game/enemyBlockAuras.ts) records the
|
||||
source-backed aura inputs used by ordinary AzerothCore Creature blocking:
|
||||
|
||||
- Aura 51 (`SPELL_AURA_MOD_BLOCK_PERCENT`) adds its percentage-point amount to
|
||||
the ordinary creature's 5% block chance.
|
||||
- Aura 253 (`SPELL_AURA_MOD_BLOCK_CRIT_CHANCE`) contributes to the separate
|
||||
critical-block roll after a block succeeds. The summed amount is truncated
|
||||
to an integer for `roll_chance_i`; a successful critical block doubles the
|
||||
block value, then the ordinary damage cap applies.
|
||||
- Aura 288 (`SPELL_AURA_IGNORE_HIT_DIRECTION`) bypasses the facing check. It
|
||||
does not bypass the independent eligibility gates. The hit-table full-block
|
||||
spell path still honors `CU_REQ_CASTER_BEHIND_TARGET`; the post-hit direct
|
||||
spell path does not add that separate attribute check.
|
||||
|
||||
`resolveEnemyNpcBlockAuraInputs` returns target-local active values as
|
||||
`blockChanceAuraPercent`, `criticalBlockChancePercent`, and
|
||||
`ignoresHitDirection`. It sums aura amounts and ignores expired or other-
|
||||
target auras. `enemyNpcCriticalBlockChanceForRoll` and
|
||||
`enemyNpcBlockValueAfterCritical` expose the integer roll argument and the
|
||||
post-roll multiplier as pure helpers. The caller must first resolve a block,
|
||||
then make the independent critical-block roll.
|
||||
|
||||
`supportedEnemyBlockAuraDefinition` returns an importable full-spell aura only
|
||||
when every DBC effect is represented. On these source rows, only Improved
|
||||
Blocking (3419) meets that rule. Critical Block (47294–47296) and Deterrence
|
||||
rows retain their full source signatures and explicit unsupported-sibling
|
||||
lists; `enemyBlockAuraInputDefinition` is only for a block-input fixture or a
|
||||
deliberately modeled passive. It must not be treated as an imported complete
|
||||
spell definition.
|
||||
|
||||
## Raw source rows
|
||||
|
||||
The three Spell.dbc files below each have 234 fields. The parser's localized
|
||||
field shift applies only at 239 fields, so these rows use shift 0. Aura effects
|
||||
below are effect type 6, implicit targets 1/0, mechanic 0, radius 0, and period
|
||||
0 unless otherwise stated. Base points are the parsed client amount
|
||||
(`basePoints` field plus one). Duration index 0 means permanent; the runtime
|
||||
contract represents that as `durationMs: null`.
|
||||
|
||||
| Spell | Profile | Duration | Present effects (`auraType:basePoints:miscValue`) |
|
||||
| --- | --- | ---: | --- |
|
||||
| 3419 Improved Blocking | WoW 3.3.5a, Ascension, Epoch | 6,000 ms | `51:75:0` |
|
||||
| 47294 Critical Block | WoW 3.3.5a | permanent | `253:20:0`, `107:5:7` |
|
||||
| 47295 Critical Block | WoW 3.3.5a | permanent | `253:40:0`, `107:10:7` |
|
||||
| 47296 Critical Block | WoW 3.3.5a | permanent | `253:60:0`, `107:15:7` |
|
||||
| 47294 Critical Block | Ascension | permanent | `253:100:0`, `107:4:7`, `107:8:3` |
|
||||
| 47295 Critical Block | Ascension | permanent | `253:100:0`, `107:7:7`, `107:16:3` |
|
||||
| 47296 Critical Block | Ascension | permanent | `253:100:0`, `107:10:7`, `107:25:3` |
|
||||
| 47294–47296 Critical Block | Epoch | permanent | Same as the corresponding WoW 3.3.5a row |
|
||||
| 67801 Deterrence | WoW 3.3.5a, Epoch | 5,000 ms | `288:100:0`, `185:-100:0` |
|
||||
| 67801 Deterrence | Ascension | 60,000 ms | `288:100:0`, `4:0:0`, `27:0:0` |
|
||||
| 667801 Deterrence | Ascension | 5,000 ms | `288:100:0`, `185:-100:0`, `27:0:0` |
|
||||
| 1167801 Deterrence | Ascension | 5,000 ms | `288:100:0`, `185:-100:0` |
|
||||
|
||||
This preserves an important profile difference: the stock and Epoch Critical
|
||||
Block rows contain one aura-107 sibling; Ascension contains two. No effect 2
|
||||
is present on the stock or Epoch rows. Aura 107 effects are preserved as
|
||||
unsupported effects because this contract implements critical-block chance,
|
||||
not their separate flat spell modifiers (`SPELLMOD_CRITICAL_CHANCE`, misc 7,
|
||||
and Ascension `SPELLMOD_EFFECT1`, misc 3). Deterrence's effects besides aura
|
||||
288 are also preserved, not silently dropped.
|
||||
|
||||
A bounded follow-up found that the pinned core's `ApplySpellMod` returns for
|
||||
non-player targets (`SpellAuraEffects.cpp:813–816`), after aura 107 reaches the
|
||||
spell-modifier path. These siblings are therefore no-ops on that ordinary
|
||||
Creature self-buff path. This pass retains the complete-import gate because the
|
||||
shared definition API does not enforce that actor/target restriction; a future
|
||||
NPC-only importer can use an explicit ordinary-Creature self-target guard. This
|
||||
is not evidence for player/party handling or external custom script overrides.
|
||||
The source file SHA-256 is
|
||||
`107369aa671a26d68081fc65b0066cb00b2cd80dfa2174ddf55bd5919d5db772`;
|
||||
`SpellDefines.h` is
|
||||
`635a025f615e16b6f10f39aa32d523f9b3d6df3959fdd0e4b49a8250da1db48f`.
|
||||
|
||||
The local inputs and SHA-256 pins are:
|
||||
|
||||
| Profile | Spell.dbc path | SHA-256 |
|
||||
| --- | --- | --- |
|
||||
| WoW 3.3.5a | `../wow-pvt-server-backups-2/wow335a/Data/patch-A.MPQ/DBFilesClient/Spell.dbc` | `57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c` |
|
||||
| Ascension | `../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc` | `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce` |
|
||||
| Epoch | `../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc` | `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3` |
|
||||
|
||||
All duration indexes use
|
||||
`../LadiksMPQEditor/client-current/patch-S/DBFilesClient/SpellDuration.dbc`,
|
||||
SHA-256 `eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`.
|
||||
The parsed durations are index 32 = 6,000 ms, index 28 = 5,000 ms, and index
|
||||
3 = 60,000 ms.
|
||||
|
||||
## Non-direct full-hit block boundary
|
||||
|
||||
One non-direct row is source-proven for a bounded WoW 3.3.5a helper:
|
||||
Shield Bash (spell 72) has damage class 2, school mask 1, `attributes0=327696`,
|
||||
`attributes3=8` (`COMPLETELY_BLOCKED`), and present effects 68 and 64. Neither
|
||||
effect is in the pinned core's direct-damage effect list. The pinned
|
||||
`creature_template_spell.sql` assigns spell 72 to creature entries 1540 and
|
||||
3739 (rows 582 and 1442).
|
||||
|
||||
The AzerothCore checkout is pinned at commit
|
||||
`e822d718322289dd036fb2daf8867ba41283bf9a`. `SpellMgr.cpp:3214–3222` derives
|
||||
`CU_DIRECT_DAMAGE` from its explicit direct/heal effect list;
|
||||
`SpellMgr.cpp:3440–3470` sets `CU_REQ_CASTER_BEHIND_TARGET` from an explicit
|
||||
spell-ID list that does not include 72. The shipped
|
||||
`data/sql/base/db_world/spell_custom_attr.sql` and the checked active world SQL
|
||||
updates contain no spell-72 override. The source correction path has no
|
||||
spell-72 custom-attribute correction, and no loaded module replaces the
|
||||
custom-attribute hook in this checkout. These checks prove only the two
|
||||
blocking-relevant bits for this exact source snapshot. The helper records a
|
||||
known-bit mask and zero value for those bits; it does not claim that the full
|
||||
computed `AttributesCu` word is zero.
|
||||
|
||||
This contract is available only for spell 72 with the `wow335` source profile.
|
||||
It is not an Ascension/Epoch assertion and is not a generic inference from a
|
||||
DBC row. Other non-direct candidates remain gated until their exact server
|
||||
custom-attribute evidence is imported. A database or core correction outside
|
||||
the pinned checkout can change this result.
|
||||
|
||||
`enemyNpcSourceSpellBlockMetadata(72, "wow335")` returns the metadata used by
|
||||
the pure phase classifier. It proves only the two block-relevant
|
||||
`AttributesCu` bits through `customAttributeEvidence.knownMask/value`; it never
|
||||
fills the unknown remainder of the custom word. The helper returns no row for
|
||||
other IDs or source profiles. Its phase and facing-gate behavior has focused
|
||||
unit coverage, but no source NPC non-direct spell importer/application has
|
||||
been wired in this pass, so this is not runtime Shield Bash coverage.
|
||||
|
||||
## Historical core pins
|
||||
|
||||
Read-only source: `../wow-pvt-server-backups-2/azerothcore-wotlk`, commit
|
||||
`e822d718322289dd036fb2daf8867ba41283bf9a`.
|
||||
|
||||
| Source | Verified behavior |
|
||||
| --- | --- |
|
||||
| `src/server/game/Spells/Auras/SpellAuraDefines.h:114,316,351` | Aura IDs 51, 253, and 288. |
|
||||
| `src/server/game/Entities/Unit/Unit.cpp:3276–3307` | Post-hit spell block checks front-or-aura and the critical-block roll uses `roll_chance_i(GetTotalAuraModifier(...253))`. |
|
||||
| `src/server/game/Entities/Unit/Unit.cpp:1579–1590,1879–1887` | Successful block removes block value; a successful critical-block roll doubles it. The direct spell packet can already be critical. |
|
||||
| `src/server/game/Entities/Unit/Unit.cpp:3364–3396` | Hit-table full block requires the blockable attribute and absence of the direct-damage custom bit; the behind-required custom bit limits the aura-facing exception. |
|
||||
| `src/common/Utilities/Random.h:63–66` | `roll_chance_i` compares an integer chance with an inclusive 0–99 roll. |
|
||||
| `src/server/game/Spells/SpellMgr.cpp:3214–3222,3440–3470` | Direct-damage effect derivation and the explicit caster-behind spell list. |
|
||||
| `data/sql/base/db_world/creature_template_spell.sql:582,1442` | Source NPC spell assignments for Shield Bash spell 72. |
|
||||
|
||||
## Validation
|
||||
|
||||
Focused source-aura, block-helper, and `damageMob` integration tests are
|
||||
`src/game/enemyBlockAuras.test.ts`, `src/game/enemyBlocking.test.ts`, and
|
||||
`src/game/enemyBlockAuraRuntime.integration.test.ts`. They verify profile rows,
|
||||
unsupported siblings, target-local duration behavior, behind-facing aura
|
||||
input for player and party attacks, the separate critical-block result, and
|
||||
the native RoM exclusion. The no-block flag is covered in the pure source gate
|
||||
tests in `enemyBlocking.test.ts`.
|
||||
@@ -0,0 +1,94 @@
|
||||
# Ordinary Creature Critical Block imports — 2026-10-06
|
||||
|
||||
## Import boundary
|
||||
|
||||
`src/game/enemyBlockAuras.ts` keeps
|
||||
`supportedEnemyBlockAuraDefinition` fail-closed for Critical Block
|
||||
(47294–47296) and Deterrence. The separate
|
||||
`ordinaryCreatureSelfTargetCriticalBlockAuraDefinition` guard admits only
|
||||
Critical Block after the caller supplies an
|
||||
`EnemyNpcCriticalBlockImportProof` for one ordinary Creature self-cast. The
|
||||
defender, caster, and target IDs must be the same nonempty ID; the proof must
|
||||
explicitly identify an ordinary Creature and exclude a native defender, a
|
||||
summon, and a character defender. It also carries the bounded applicability
|
||||
token `azerothcore-e822d718-default-spellmod-path`.
|
||||
|
||||
The guard validates the complete raw spell signature, runtime contract, block
|
||||
chance, and the exact aura-107 sibling list against the reviewed profile/rank
|
||||
row before returning an aura-253 runtime definition. Aura 107 stays present in
|
||||
the source signature and unsupported-effect metadata. Its no-op behavior is
|
||||
specific to the reviewed default core path; a custom aura script/module or a
|
||||
private server override invalidates that applicability proof. The WoW,
|
||||
Ascension, and Epoch labels identify client DBC rows. They do not certify
|
||||
private server overrides for those clients. Player and party casts must never
|
||||
use this full-import guard.
|
||||
|
||||
## Reviewed Spell.dbc signatures
|
||||
|
||||
Each listed effect is type 6, mechanic 0, target A/B 1/0, radius 0, period 0;
|
||||
spell range index is 1, school mask is 1, damage class is 0, duration is
|
||||
permanent (`-1` in the raw signature), and stack amount is 0. The parsed
|
||||
`basePoints` below are the client amount (`Spell.dbc` base-points field plus
|
||||
one). The Spell.dbc hashes and source paths are pinned in
|
||||
`NPC_BLOCK_AURA_PARITY_2026-10-06.md`.
|
||||
|
||||
| Profile | Spell | Aura effects (`auraType:basePoints:miscValue`) |
|
||||
| --- | ---: | --- |
|
||||
| WoW 3.3.5a | 47294 | `253:20:0`, `107:5:7` |
|
||||
| WoW 3.3.5a | 47295 | `253:40:0`, `107:10:7` |
|
||||
| WoW 3.3.5a | 47296 | `253:60:0`, `107:15:7` |
|
||||
| Ascension | 47294 | `253:100:0`, `107:4:7`, `107:8:3` |
|
||||
| Ascension | 47295 | `253:100:0`, `107:7:7`, `107:16:3` |
|
||||
| Ascension | 47296 | `253:100:0`, `107:10:7`, `107:25:3` |
|
||||
| Epoch | 47294 | `253:20:0`, `107:5:7` |
|
||||
| Epoch | 47295 | `253:40:0`, `107:10:7` |
|
||||
| Epoch | 47296 | `253:60:0`, `107:15:7` |
|
||||
|
||||
Aura 253 supplies the modeled critical-block chance. Aura 107 is
|
||||
`SPELL_AURA_ADD_FLAT_MODIFIER`; misc 7 is the spell critical-chance modifier,
|
||||
and Ascension also has misc 3 (`SPELLMOD_EFFECT1`). In the pinned AzerothCore
|
||||
checkout at commit `e822d718322289dd036fb2daf8867ba41283bf9a`,
|
||||
`SpellAuraEffects.cpp:780` sends aura spell modifiers through `ApplySpellMod`.
|
||||
`ApplySpellMod` returns at lines 813–816 when the target is not a player, so
|
||||
these aura-107 spell modifiers do not apply to an ordinary Creature on that
|
||||
default path. This evidence does not cover custom aura scripts, custom modules,
|
||||
or external server changes.
|
||||
|
||||
## Source assignment availability
|
||||
|
||||
The pinned AzerothCore base `creature_template_spell.sql` dump and checked
|
||||
`db_world` SQL updates contain no `Spell` assignment for 47294, 47295, or
|
||||
47296. This pass adds an importer guard and its evidence only; it does not
|
||||
assign Critical Block to a creature. A real source creature assignment is
|
||||
still required before any NPC receives the buff. Do not infer or fabricate one
|
||||
from the player talent spell rows.
|
||||
|
||||
Deterrence remains outside the full importer because its source signatures
|
||||
also contain effects (including aura 185 or aura 27) that are not represented
|
||||
by ordinary NPC block inputs.
|
||||
|
||||
## Focused coverage
|
||||
|
||||
`src/game/enemyBlockAuras.test.ts` covers all three ranks in all three client
|
||||
profiles, missing and malformed proof, mismatched self-target IDs, native,
|
||||
summoned, and character-defender exclusions, the pinned applicability token,
|
||||
generic importer fail-closed behavior, Deterrence exclusion, and raw signature
|
||||
drift. The focused command is:
|
||||
|
||||
```text
|
||||
npx vitest run src/game/enemyBlockAuras.test.ts
|
||||
```
|
||||
|
||||
`combatStore.ts` uses this guard only for an ordinary source Creature's
|
||||
self-target descriptor with a known template entry. The compiler pins all
|
||||
three rank signatures in Ascension/Epoch, including aura-107 siblings, and
|
||||
validates them even when no source NPC assignment uses them. Its duration-index
|
||||
0 parser sentinel is 0; the guarded runtime definition normalizes the source
|
||||
permanent aura to an `expiresAt=null` lifetime.
|
||||
|
||||
`enemyCriticalBlockImport.integration.test.ts` passes two actual runtime tests:
|
||||
a clearly labeled synthetic self-cast applies the permanent aura without
|
||||
damage, produces a deterministic critical block, and clears on reset; native,
|
||||
summoned, character and non-self fixtures are excluded. This synthetic fixture
|
||||
does not establish a real creature assignment. Regenerated campaign data is
|
||||
byte-for-byte unchanged from this pass's starting snapshot.
|
||||
@@ -0,0 +1,229 @@
|
||||
# Ordinary WoW NPC spell blocking — 2026-10-05
|
||||
|
||||
## Result
|
||||
|
||||
The historical AzerothCore source has two spell-block phases. They use
|
||||
different eligibility rules and different skill signs, so the pure helpers in
|
||||
[`src/game/enemyBlocking.ts`](../src/game/enemyBlocking.ts) keep them separate.
|
||||
The existing melee/ranged auto-attack baseline is unchanged. Native RoM NPCs,
|
||||
unknown sources, and character defenders do not use this ordinary-Creature
|
||||
spell path.
|
||||
|
||||
The current imported spell metadata supports the post-hit direct-damage phase
|
||||
when source effects positively establish AzerothCore's `DIRECT_DAMAGE`
|
||||
custom flag. It does not infer that custom flag is absent from a Spell.dbc row.
|
||||
The separate hit-table full-block phase therefore requires an explicit
|
||||
AzerothCore-computed custom-attribute word and remains unavailable where that
|
||||
word has not been imported.
|
||||
|
||||
## Runtime implementation
|
||||
|
||||
`scripts/generate-wow335-abilities.mjs` now retains the exact defense metadata
|
||||
on every imported rank. Its 239-field WoW client records use the existing
|
||||
six-column shift: damage class is field 219 and school mask is field 231.
|
||||
Raw Heroic Strike, Steady Shot and Arcane Shot records independently confirm
|
||||
those columns. Regeneration changed only this metadata and the generation
|
||||
timestamp; all previous spell effects, progression and costs remain identical.
|
||||
`wow335AbilityCatalog.ts` and the classic Ascension builder in
|
||||
`coaAbilityCatalog.ts` preserve those scalars. `abilityAtLevel` selects the
|
||||
rank's own metadata and clears it when that rank is unbound.
|
||||
|
||||
`combatStore.ts` routes source-bound direct physical melee/ranged packets from
|
||||
both the player and real party companions through the ordinary NPC defender.
|
||||
`partyRuntime.ts` supplies the exact source damage class and selected spell
|
||||
rank to that resolver for blockable physical casts against ordinary source
|
||||
NPCs; those casts previously used a damage path without a hit-result context.
|
||||
The damage API uses the explicitly selected spell ID to look up that rank's
|
||||
defense metadata and leaves unknown IDs unbound.
|
||||
It resolves current NPC facing, active non-melee casts, control, source
|
||||
`flags_extra`, block auras and returning/evading state. Weapon skill uses the
|
||||
simulator's existing level-times-five abstraction; no weapon-skill progression
|
||||
or equipment requirement is introduced. Native RoM targets, guardians and
|
||||
character defenders retain their separate paths. Native RoM spells never
|
||||
acquire WoW metadata through their stat-ruleset choice.
|
||||
|
||||
`combatResults.ts` adds an explicit `blockMode: post-hit`. The common hit/crit
|
||||
table contains no block entry for this mode. An independent `block` roll runs
|
||||
only after a physical melee/ranged hit lands, subtracting NPC block value after
|
||||
critical and armor mitigation. Crit-plus-block retains `outcome: crit`,
|
||||
`critical: true` and `blocked: true`; a regular blocked hit reports `block`.
|
||||
Structured outgoing damage events retain `blocked` and `blockedAmount`, so
|
||||
recorders can observe both properties without guessing from the latest result.
|
||||
Ordinary autoattacks retain their single table roll.
|
||||
|
||||
Unknown source packets, periodic ticks, magical schools, source damage-class
|
||||
mismatches and defense-exception spells do not enter this new phase. Runtime
|
||||
full-hit blocking of non-direct spells, ignore-hit-direction aura imports and
|
||||
critical-block aura doubling remain source-integration boundaries. This pass
|
||||
does not implement the other spell-specific dodge/parry attribute exceptions.
|
||||
The level-80 cap, Ready-five policy and loot scope remain unchanged.
|
||||
|
||||
## Validation
|
||||
|
||||
The ten directly affected Vitest files pass 134 checks: source helper gates,
|
||||
shared combat results, post-hit block distribution/order, per-rank metadata,
|
||||
stance/autoattack regression, native RoM exclusion, actual player and generated
|
||||
party spell casts, party AI/runtime and stat-ruleset regressions. The six new
|
||||
store integration cases prove Heroic Strike and a real Hunter companion's
|
||||
Steady Shot can critically hit and block simultaneously. They preserve exact
|
||||
event flags/amounts, source flags=0, actual selected rank versus unknown rank
|
||||
IDs, magical spell exclusion and rear/cast/control gates. Guaranteed crit and
|
||||
one-damage companion engagement are labeled synthetic fixtures; creature and
|
||||
spell fields remain real. NO_BLOCK is covered by the pure helper because no
|
||||
current reference template carries that flag.
|
||||
|
||||
Ready-five passes seven additional Vitest and twenty Python checks. The final
|
||||
8 GB TypeScript/Vite production build, pre/postbuild audits, compression and
|
||||
release-bundle verification pass; the subsequent TypeScript check includes
|
||||
the final integration test file. Independent Luna review found no concrete
|
||||
defect. Ordinary runtime callers have no modeled unsummoned Totem identity;
|
||||
that subtype must be exposed if such static dungeon actors are added.
|
||||
|
||||
The frozen production copy has 5,964 files, 116,755,437 bytes and aggregate
|
||||
SHA-256 `864781d16c3c0a26457b6acd7a9bd31357116f856e6b27258b5b633d2f224fac`.
|
||||
Mutable dist stayed identical before/after the verified copy. The scoped
|
||||
one-boss browser run `20261005-202545227` clears Cellblock Rush in 03:18.0,
|
||||
Easy/Normal, with Hamhock (`creature-79098`) as its actual seeded objective.
|
||||
Required and killed IDs agree 1/1, all five actors finish alive and no death or
|
||||
resurrection recovery is observed. Nine effective heals total 2,801.9 HP.
|
||||
Six party-to-hostile blocks include two Revenge and two Sinister Strike spell
|
||||
hits, with event-level block amounts; one correlated Revenge result explicitly
|
||||
records the independent post-hit roll. No live crit-plus-block was captured;
|
||||
that behavior remains deterministic integration evidence. Snapshots sample the
|
||||
latest 200-event ring and are not a lossless stream.
|
||||
|
||||
The frozen build and complete content manifest stay unchanged. All 2,124
|
||||
served content objects match their hash addresses and manifest references.
|
||||
Root reviewed roster, entrance, route and native results screenshots: bodies
|
||||
and equipped silhouettes render, while close-party overlap, edge occlusion and
|
||||
compact-roster name clipping remain visible. Page errors are zero; the only
|
||||
console item is a favicon 404. Exact provenance, preserved failed entrance
|
||||
attempt and cleanup are in
|
||||
`docs/STOCKADE_SPELL_BLOCKING_PLAYTEST_2026-10-05.md`.
|
||||
|
||||
## Core spell gates
|
||||
|
||||
`Unit::SpellHitResult` dispatches melee and ranged damage-class spells through
|
||||
`Unit::MeleeSpellHitResult`; magic and unclassified damage spells use another
|
||||
path. The spell damage-class values are 0 (none), 1 (magic), 2 (melee), and 3
|
||||
(ranged). The normal physical school mask is bit `0x1`.
|
||||
|
||||
The hit-table phase can return a full `SPELL_MISS_BLOCK` only when all of these
|
||||
source gates allow it:
|
||||
|
||||
- Damage class is melee or ranged, so the spell uses `MeleeSpellHitResult`.
|
||||
- `SPELL_ATTR3_COMPLETELY_BLOCKED` is set (`attributes[3] & 0x8`).
|
||||
- AzerothCore's computed `SPELL_ATTR0_CU_DIRECT_DAMAGE` is absent
|
||||
(`customAttributes & 0x100` is zero).
|
||||
- Neither `SPELL_ATTR3_ALWAYS_HIT` (`attributes[3] & 0x40000`) nor
|
||||
`SPELL_ATTR0_NO_ACTIVE_DEFENSE` (`attributes[0] & 0x200000`) is set.
|
||||
- An attack from behind disables block unless the victim has
|
||||
`SPELL_AURA_IGNORE_HIT_DIRECTION`. If the spell has the core custom flag
|
||||
`SPELL_ATTR0_CU_REQ_CASTER_BEHIND_TARGET` (`customAttributes & 0x20000`),
|
||||
that aura does not bypass the hit-table facing check.
|
||||
- Creature template `flags_extra` does not include
|
||||
`CREATURE_FLAG_EXTRA_NO_BLOCK` (`0x10`), and the victim is not a Totem.
|
||||
- The skill-adjusted block chance remains positive, and the victim is not
|
||||
performing a non-melee spell cast or in `UNIT_STATE_CONTROLLED`.
|
||||
|
||||
The hit-table roll runs after miss and mechanic-resist checks. Its block chance
|
||||
is truncated to integer hundredths before applying skill difference:
|
||||
`int32(blockChance * 100) - skillDiff * 4`, where
|
||||
`skillDiff = attackerWeaponSkill - defenderMaxSkill`. This subtracts 0.04
|
||||
percentage points per skill point. AzerothCore uses level times five for the
|
||||
defender's max skill; ranged non-weapon spells also use attacker level times
|
||||
five, while other cases use the attacker's actual attack-type weapon skill.
|
||||
Apply the adjustment before checking whether chance is positive: a raw chance
|
||||
of zero can become positive when attacker skill is below defender maximum.
|
||||
|
||||
The post-hit phase handles direct physical spell packets after they have landed.
|
||||
`SpellMgr` marks direct effects with `SPELL_ATTR0_CU_DIRECT_DAMAGE`; its effect
|
||||
list includes school damage (2), weapon damage without school (17), weapon
|
||||
percent damage (31), weapon damage (58), normalized weapon damage (121), and
|
||||
healing (10). For an incoming damage packet, `Unit::CalculateSpellDamageTaken`
|
||||
attempts this later block only when damage class is melee or ranged and the
|
||||
packet school includes physical bit `0x1`. It does not require
|
||||
`SPELL_ATTR3_COMPLETELY_BLOCKED`.
|
||||
|
||||
The later `Unit::isSpellBlocked` path bypasses block for `NO_ACTIVE_DEFENSE` or
|
||||
`ALWAYS_HIT`; otherwise it requires a front-facing victim or an active
|
||||
ignore-hit-direction aura, no `NO_BLOCK` creature flag, a positive chance, and
|
||||
no non-melee cast or controlled state. It does not independently inspect
|
||||
`CU_REQ_CASTER_BEHIND_TARGET`. Its chance formula is the float expression
|
||||
`blockChance + (attackerWeaponSkill - defenderMaxSkill) * 0.04`, so higher
|
||||
attacker skill raises this post-hit block chance. A successful block subtracts
|
||||
the creature's block value from damage and can coexist with a critical hit.
|
||||
If the block consumes all damage, Spell.cpp can report the result as
|
||||
`SPELL_MISS_BLOCK`.
|
||||
Apply the skill adjustment before checking positivity here as well; a zero raw
|
||||
chance can become positive when attacker skill exceeds defender maximum.
|
||||
|
||||
`SPELL_ATTR7_NO_ATTACK_DODGE` (`attributes[7] & 0x00800000`) and
|
||||
`SPELL_ATTR7_NO_ATTACK_PARRY` (`attributes[7] & 0x01000000`) suppress those
|
||||
avoidance results only; they do not disable block. School alone does not make
|
||||
a magic-class spell blockable, and ranged damage class does not by itself
|
||||
disable a source-authorized block.
|
||||
|
||||
## Spell metadata and helper contract
|
||||
|
||||
`EnemyNpcSpellDefenseMetadata` mirrors the exact metadata fields added to
|
||||
source-backed ability ranks: `damageClass`, `schoolMask`, `attributes0`,
|
||||
`attributes3`, `directDamageFromEffects`, and `sourceProfile`. The helper also
|
||||
accepts optional `customAttributes` for callers that have a sourced or
|
||||
reconstructed AzerothCore custom word. Without that word, a non-direct spell
|
||||
classifies as `none`; a client DBC row alone cannot prove that SQL or server
|
||||
corrections did not set a custom flag.
|
||||
|
||||
- `classifyEnemyNpcSpellBlockPhase` returns `direct-damage` only with positive
|
||||
direct-effect evidence, a melee/ranged class, and physical school bit; it
|
||||
returns `hit-table` only when explicit custom attributes show the direct
|
||||
flag is absent and the blockable-spell attribute is present.
|
||||
- `enemyNpcSpellBlockChanceAfterSkill` takes the attacker's actual weapon skill
|
||||
and defender level. This avoids inventing a weapon requirement or guessing
|
||||
skill from spell DBC equipment masks.
|
||||
- `canEnemyNpcBlockSpell` applies Totem, `NO_BLOCK`, direction, cast/control,
|
||||
and positive skill-adjusted chance gates for either phase.
|
||||
|
||||
The source-profile type currently accepts `wow335` and `ascension`, matching
|
||||
the imported spell-rank metadata contract. The pinned Epoch Spell.dbc is
|
||||
available for adjacent aura and stance contracts, but this helper does not
|
||||
accept Epoch rank metadata until that profile is included in the importer
|
||||
contract.
|
||||
|
||||
Two direct-effect candidates have exact local profile rows:
|
||||
|
||||
| Spell | WoW 3.3.5a | Ascension patch-D | Epoch |
|
||||
| --- | --- | --- | --- |
|
||||
| Heroic Strike (78) | class 2, school 1, attrs0 327700, attrs3 1024, weapon damage effect 58 | class 2, school 1, attrs0 327700, attrs3 1024, weapon damage effect 58 | same as WoW 3.3.5a |
|
||||
| Steady Shot (56641) | class 3, school 1, attrs0 4259858, attrs3 0, direct effect 2 | class 3, school 1, attrs0 65554, attrs3 0, direct effects 2 and 31 | same as WoW 3.3.5a |
|
||||
|
||||
These effects positively establish the direct custom flag under the historical
|
||||
core's SpellMgr effect rules. Ascension's Steady Shot has a different set of
|
||||
attribute words and a weapon-percent-damage effect, but retains ranged
|
||||
class and physical school. The helper does not hard-code these spell IDs.
|
||||
|
||||
## Pinned source locations
|
||||
|
||||
Read-only historical core: `../wow-pvt-server-backups-2/azerothcore-wotlk`.
|
||||
|
||||
| Source | Relevant code |
|
||||
| --- | --- |
|
||||
| `src/server/game/Entities/Unit/Unit.cpp` | `MeleeSpellHitResult` at 3330–3500; `isSpellBlocked` at 3276–3299; `CalculateSpellDamageTaken` at 1508–1640; dispatch by damage class at 3680–3770; `GetUnitBlockChance` at 3873–3895. |
|
||||
| `src/server/game/Spells/SpellInfo.h` | Core custom flags including `CU_DIRECT_DAMAGE = 0x100` and `CU_REQ_CASTER_BEHIND_TARGET = 0x20000` near 185–194. |
|
||||
| `src/server/shared/SharedDefines.h` | `NO_ACTIVE_DEFENSE = 0x200000`, `COMPLETELY_BLOCKED = 0x8`, `ALWAYS_HIT = 0x40000`, and damage-class values near lines 391, 484, 499, and 1552; no-dodge/no-parry attributes near 652–653. |
|
||||
| `src/server/game/Spells/SpellMgr.cpp` | Computes `CU_DIRECT_DAMAGE` for the listed effect types near 3210–3230. |
|
||||
| `src/server/game/Spells/Spell.cpp` | Applies post-hit block output after spell damage calculation near 2760–2820. |
|
||||
|
||||
The source profile pins are already recorded by
|
||||
[`enemySourceAuras.ts`](../src/game/enemySourceAuras.ts) and
|
||||
[`enemyStances.ts`](../src/game/enemyStances.ts): Ascension patch-D Spell.dbc
|
||||
SHA-256 `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`,
|
||||
and Epoch Spell.dbc SHA-256
|
||||
`d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`. The WoW
|
||||
3.3.5a candidate rows above came from
|
||||
`../wow335a/Data/enUS/patch-enUS.MPQ` Spell.dbc. Their raw row fields are
|
||||
parsed by `scripts/generate-wow335-abilities.mjs` at DBC fields 4–11
|
||||
(attributes), 213 (damage class), 225 (school), and 71–73 (effects), including
|
||||
the six-field schema shift for newer DBC records.
|
||||
The extracted stock Spell.dbc is 46,699,377 bytes, 46,583 rows and 239 fields,
|
||||
SHA-256 `9f0088da35c5ed0b5106cd20e422611489e435b74043e520e02221e0ce1b1af1`.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Performance check — 2026-10-04
|
||||
|
||||
> **Future QA default (2026-10-04):** Use Stormwind Stockade for new routine live tests. The Wailing captures and commands in this dated report are historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
|
||||
## Findings and changes
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Barren Caves tank death investigation (2026-10-04)
|
||||
|
||||
This is historical incident analysis only. Barren Caves was not replayed. The current default for live dungeon diagnostics is Stormwind Stockade; use a future Stockade run to verify healer behavior after the active fixes land.
|
||||
This is historical incident analysis only. Barren Caves was not replayed. The current default for live dungeon diagnostics is Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record its run-selected boss. Use an explicitly requested full-source route only when the mechanic requires it.
|
||||
|
||||
## Evidence reviewed
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Blood Arrow scaling source audit — 2026-10-04
|
||||
|
||||
## Result
|
||||
|
||||
The current Chronicles of Arcadia sources do not establish Blood Arrow's
|
||||
damage bonus at skill level 80. Keep the imported 10% modifier as the existing
|
||||
simulator value until current rank data or an explicit formula is available.
|
||||
Do not derive the cap-80 value from the published level-105 tooltip.
|
||||
|
||||
## Current source evidence
|
||||
|
||||
- [Current Scout/Rogue skill list](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en)
|
||||
identifies Scout General Blood Arrow as skill `490434`. Its tooltip shows
|
||||
`+105`, says the skill's maximum level is 105, and reports a 104.5% ranged
|
||||
damage increase at that rank. It also describes the 2% HP ranged-attack cost
|
||||
and 10-second cooldown after deactivation.
|
||||
- [Current Knight/Scout skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=en)
|
||||
identifies Blood Arrow as the distinct skill `499924`. Its `+105` tooltip
|
||||
likewise reports 104.5% ranged damage and a maximum skill level of 105; it
|
||||
additionally reports 2% HP and 1% MP per offensive ranged-weapon skill, +5%
|
||||
Light Damage, and +15% received healing.
|
||||
|
||||
These current pages provide one numeric endpoint per identity: skill level 105.
|
||||
They expose no lower-rank points, rank table, progression formula, API payload,
|
||||
or raw current CoA source record. The game's level-80 character cap does not
|
||||
identify what Blood Arrow value belongs at that cap. One level-105 endpoint
|
||||
cannot establish a level-80 value or curve.
|
||||
|
||||
## Local RuneWaker boundary
|
||||
|
||||
The checked-in `src/game/romPlayerCatalog.generated.json` maps the imported
|
||||
Scout General row `490434` to `rom-scout-general-4`. It contains one rank,
|
||||
learned at character level 12. Its source component `500871` has ability
|
||||
modifier type 52 (`ranged-damage`) with value 10. The row also retains the old
|
||||
30-second duration and 3% per-second HP loss. The exporter
|
||||
`scripts/runewaker-pipeline/export-player-catalog.mjs` resolves these
|
||||
`MagicCollect` / `MagicObject` records from the local RuneWaker client
|
||||
snapshot. This is evidence for the legacy imported 10% value and its stale
|
||||
behavior, not a current CoA lower-rank curve.
|
||||
|
||||
Current verified pair mapping is owner-scoped in code: Scout/Rogue uses CoA
|
||||
source skill `490434`; Knight/Scout uses CoA source skill `499924`, which the
|
||||
local imported row represents as `490434`. Other owners retain the local
|
||||
legacy import. Since no current CoA level-80 curve is available, this audit
|
||||
does not change the catalog's existing 10% ranged-damage modifier for any
|
||||
owner.
|
||||
|
||||
## Evidence still needed
|
||||
|
||||
To replace the retained value safely, obtain at least one independently
|
||||
verifiable current CoA rank point at or below level 80 plus enough matching
|
||||
rank points or an explicit formula to determine the progression. The evidence
|
||||
must distinguish Scout/Rogue `490434` from Knight/Scout `499924`, or explicitly
|
||||
show that their rank curves are shared. A current raw source/API record is
|
||||
preferred; historical RuneWaker data and the level-105 tooltip alone are
|
||||
insufficient.
|
||||
|
||||
The direct official `/wiki/...?...locale=en` skill-list URLs above resolve.
|
||||
The alternate `/en/wiki/...` path may fail and is not the citation used here.
|
||||
@@ -22,4 +22,4 @@ The current source tooltips state percentage HP/MP costs without distinguishing
|
||||
|
||||
npx vitest run src/game/romKnightScoutBloodPunishment.integration.test.ts src/ui/AuraStrip.test.ts src/ui/PlayerStatusPanel.test.ts src/ui/partyResurrection.test.ts passes all 32 tests. Coverage includes ROM and WoW player costs and no-idle-drain checks, owned Knight/Scout activation and affordability in both rulesets, player recast/cooldown, Blood Punishment lifetime, and an owned Scout/Rogue ranged auto swing that charges once, keeps party and actor health synchronized, and receives Blood Arrow's ranged damage modifier. It also checks rank-resolved toggle behavior for verified owners, unchanged legacy behavior for an unverified Scout/Warrior, rejection of another buff's right-click, and rendered visibility of an NPC's tagged indefinite aura while unrelated long-term buffs remain filtered.
|
||||
|
||||
No dungeon playtest was run in this slice. Future live QA uses Stormwind Stockade (`stormwind-stockade`) as the default test dungeon; no Wailing Caverns route or test was added.
|
||||
No dungeon playtest was run in this slice. Routine live QA now uses Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit selection. No Wailing Caverns route or test was added.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Campaign boss-route playtest — 2026-10-04
|
||||
|
||||
> **Future QA default (2026-10-04):** Use Stormwind Stockade for new routine live tests. The Wailing captures and commands in this dated report are historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
|
||||
## Scope and method
|
||||
|
||||
|
||||
@@ -0,0 +1,308 @@
|
||||
# RoM dungeon texture, lighting, and route review — 2026-10-06
|
||||
|
||||
This continuation reviews all 30 base RoM dungeons. Luna subprocesses handled
|
||||
source-material inspection, original lighting recovery, and independent runtime
|
||||
review. Screenshots from an isolated asset camera establish visual coverage;
|
||||
ordinary production UI and keyboard input establish entry and walking evidence.
|
||||
Neither method certifies every corridor, a full clear, or combat balance.
|
||||
|
||||
## Texture and material changes
|
||||
|
||||
The all-dungeon room review covers 30 entrances, 66 boss anchors, 74 diagnostic
|
||||
corridor samples, and 36 mapping-hotspot views. The corridor cameras are samples
|
||||
between authored anchors, not proof of connected walking routes. Large low-rank
|
||||
UV metrics require source/material attribution before applying repeat tiling:
|
||||
waterfall sheets and flow effects must not be treated as stone floors.
|
||||
|
||||
Six dungeons had exact native `gate_waterfall` materials exported as opaque,
|
||||
with the compressed image losing its alpha: Cave of the Water Dragon, Kulech
|
||||
Bones Nest, Mystic Altar, Raksha Temple, Sardo Castle, and Tomb of Seven Heroes.
|
||||
The source-pinned material patch covers 40 native bindings (38 normal blends,
|
||||
two additive bindings). Native prelit metadata also retains its verified unlit
|
||||
semantics. The JSON-only alpha patch retains identical BIN bytes. The subsequent
|
||||
unlit semantics pass can repack BIN layout; a final decoded-layout proof verifies
|
||||
identical positions, normals, indices, every UV stream, morph targets, node
|
||||
hierarchy/transforms, and exact PNG image bytes across all six candidates.
|
||||
Optimization disables simplification and automatic texture resizing; the KTX2
|
||||
decode proof demonstrates retained partial alpha, not lossless codec equality.
|
||||
Mystic Altar's reviewed support-floor texture remains part of the canonical
|
||||
input and its metadata is preserved.
|
||||
|
||||
The durable converter reads native alpha parameters and exact diffuse-channel
|
||||
joins. `lib/native-alpha-cache-validation.mjs` rejects old resource caches unless
|
||||
source hashes, exporter/converter/alpha-policy hashes, and raw/prepared native
|
||||
material reports agree. `stage-native-waterfall-alpha.mjs` produces guarded
|
||||
review candidates; `promote-native-waterfall-alpha.mjs` verifies identities and
|
||||
creates exclusive baseline backups before updating canonical/shipping assets
|
||||
and their current hashes. Historical proofs remain historical.
|
||||
|
||||
The Lair of the Demon Dragon's `magic_magma_02` sheets had the same provenance
|
||||
gap. All three exact source rows (2, 3, 9) are prelit cutouts, with native alpha
|
||||
test value 192. They now retain MASK cutoff 192/255 and unlit semantics, replacing
|
||||
the opaque black slab with the source orange flow strips. The 512×128 UASTC
|
||||
image retains alpha 0–255; source and decoded image each have 37,654 pixels
|
||||
passing `>192`. Mean alpha error is 0.000244, so codec equality is not claimed.
|
||||
The final canonical proof preserves all geometry, UVs, hierarchy/transforms, and
|
||||
all 17 exact source PNG images. These are native flow-effect sheets, not stone
|
||||
floor atlas mappings, so no repeat tiling was guessed. Its stage, response-body
|
||||
SHA checks, first-hit material proof and screenshots live in
|
||||
`artifacts/playtest/rom-room-coverage/lair-magma-alpha-stage/`.
|
||||
|
||||
The six waterfall acceptance pairs require the exact target texture to be the
|
||||
nearest ray hit in both shipping baseline and compressed candidate. The served
|
||||
candidate identity and native BLEND provenance are verified. Four-metre Kulech
|
||||
and Tomb pairs supply additional surroundings; Kulech's additive effect is very
|
||||
bright and is not credited as a complete scene-quality pass. Early bounding-box
|
||||
views and the first misrouted comparison are diagnostic failures, superseded by
|
||||
`gate-waterfall-triangle-pairs-report.json` and
|
||||
`gate-waterfall-context-pairs-report.json`. Synchronous camera scans explicitly
|
||||
refresh the camera matrix before raycasting; otherwise they can inspect the
|
||||
previous pose between rendered frames.
|
||||
|
||||
The final Barren policy replaces whole-atlas repeats with four exact 256×256
|
||||
native floor islands. Only triangle corners contained in one reviewed island
|
||||
receive the ×4 presentation UV1; source UV0, geometry and original atlas remain.
|
||||
Its walls use a fifth exact 256×256 crop from the native central wall region at
|
||||
[256,0], sampled at two metres with mirrored edges and rotated phase blending.
|
||||
Wall base contrast is 0.25 around the source atlas mean, with detail strength
|
||||
0.85; floor detail strength is zero. This explicit browser treatment reduces
|
||||
oversized smearing and obvious tile repetition without generating replacement
|
||||
pixels. The original 47,084 triangles and eight native PNG images are retained.
|
||||
Its exact crop RGBA proofs are separate from lossy compressed-texture metrics.
|
||||
|
||||
HOTO keeps its native non-repeating cliff artwork and UV0. Its revised v2 policy
|
||||
samples the original full stone/moss tiles directly at two metres on floor faces
|
||||
of materials 26 and 18. Those floors use base strength 1 and modulation strength
|
||||
0; material 18 samples its own moss tile. Cliff materials 96 and 53 retain their
|
||||
base artwork, with floor/wall detail strength 0.85, wall contrast 0.6 around each
|
||||
source atlas mean, and rotated detail variation 1. Material 26 retains wall
|
||||
strength 0; material 18 retains 0.45. These settings correct presentation scale,
|
||||
not native texture resolution. The v1-to-v2 patch changes only approved material
|
||||
metadata; all non-JSON chunks remain byte-identical in canonical and optimized
|
||||
GLBs. All 189,855 source triangles and 17 native PNG images are retained. Source-detail
|
||||
carriers require joining/pruning protections during optimization. HOTO adds no
|
||||
cropped images; its decoded source-layout proofs are separate from lossy
|
||||
compressed-texture metrics. The fixed-camera compressed comparisons use verified served hashes and
|
||||
report no browser errors. Evidence is under
|
||||
`artifacts/playtest/rom-deep-review/uv-stretch-review/`.
|
||||
The v2 continuation is promoted through `promote-hoto-surface-v2.mjs`, with a
|
||||
new exclusive recovery backup and `hoto-surface-v2-promotion-proof.json`.
|
||||
Shipping SHA-256 is `b80b60cba6e5a0eb3e13bd7e048f9408f21bf870c0c81fc8de5c195d3a3eaee3`.
|
||||
The unique v2 screenshots have pinned hashes in `hoto-surface-v2-visual-proof.json`.
|
||||
The earlier shared HOTO v1 final screenshot names were overwritten during the
|
||||
v2 comparison and are explicitly marked unavailable in its stage/promotion
|
||||
reports. Their historical asset hashes remain recorded; those image paths must
|
||||
not be treated as preserved v1 captures. Earlier diagnostic captures remain
|
||||
separate evidence. The current unique v2 proof supersedes that comparison.
|
||||
|
||||
## Source lighting and shadows
|
||||
|
||||
The native zone exporter recovers environment settings and oriented zone
|
||||
triggers from all 30 source WDBs. Generated data retains source hashes, native
|
||||
ambient/primary/two secondary colors and directions, fog, time/weather groups,
|
||||
and priority/parent relationships. The resolver converts runtime positions back
|
||||
into source space and follows native trigger selection and setting inheritance.
|
||||
Time/weather groups default to 0/0; this does not implement a live weather clock.
|
||||
|
||||
`DungeonLighting.tsx` supplies these settings to production RoM environments.
|
||||
Rune colors are linear byte/255 values. Rune's unoccluded SH constant band is
|
||||
supplied as ambient fill (4/17 of the weighted directional colors), with the
|
||||
complementary 13/17 in Three.js directionals. This preserves readability in
|
||||
roofed rooms without adding a guessed white light. Three.js angular diffuse and
|
||||
PBR specular remain an adaptation; the original separately authored specular
|
||||
path and full SH shader are not reproduced. Standard's source-primary shadow
|
||||
follows the player's footing; High follows the camera. Missing native zones use
|
||||
the reviewed presentation profile. WoW uses its existing profile lighting path.
|
||||
|
||||
The final adapted-source entrance check covers all 30 dungeons: 29 native-zone
|
||||
selections and Grafu Castle's entrance profile fallback, with zero browser
|
||||
errors. The broader source-lighting camera review covers 96 entrance/boss
|
||||
anchors, 95 native-zone selections and the same one fallback. Four same-camera
|
||||
profile comparisons establish that SH fill keeps Forsaken Keeper 3 and Ystra's
|
||||
Raichika room readable; source-dark Sardo and Kulech remain dark interiors.
|
||||
Barren's pale source lighting retains rock/sand detail without clipped whites.
|
||||
|
||||
## Origin water
|
||||
|
||||
All 126 source water layers retain their native GUID joins, visibility,
|
||||
vertex RGBA, source tile coordinates and 30-frame normal sequence. Metadata now
|
||||
also retains the first source vertex's split-plane height and exact serialized
|
||||
full-model enable flag. Raw effect value 4 keeps its original value and unknown
|
||||
enum name; Rune's non-DIRECT full-enable branch establishes its rendering policy.
|
||||
|
||||
The browser reflects the camera across that native plane, clips below it, and
|
||||
captures the pre-water scene for refraction. It uses Rune's shared projected UV,
|
||||
0.025 bump perturbation, and 0.02037/0.97963 Fresnel coefficients. Per tagged
|
||||
asset root, four active 512-pixel target pairs share at most ten two-pass
|
||||
captures per second. Oldest-request scheduling avoids render-order starvation;
|
||||
inactive pairs release their slots when a later plane needs them. Materials
|
||||
dispose shared targets once. Additional active planes and below-plane views use
|
||||
the lit animated fallback. Reflect-class filtering and the native water SH
|
||||
shader remain unsupported. Water stays visual-only.
|
||||
|
||||
Same-camera final water captures record visible glancing reflections, zero
|
||||
browser errors, and approximately 60 FPS. Metadata-only promotion preserves
|
||||
both canonical and optimized BIN hashes. Original-source water colors remain
|
||||
unchanged. Evidence: `artifacts/playtest/rom-deep-review/water-screen-effects/`.
|
||||
|
||||
## Walking evidence and remaining route issues
|
||||
|
||||
Before this lighting/material continuation, ordinary UI walking covered all 30
|
||||
current source environments: 489 attempted legs, 487 reached, 882/882 grounded
|
||||
samples, 1,010.312 m travelled, and zero browser errors. Twenty-eight planned
|
||||
walks completed. Raksha's first forward probe blocked while grounded; Dalanis's
|
||||
second waypoint exhausted the movement time budget while grounded. These are
|
||||
retained failures, not successful clears. See
|
||||
`artifacts/playtest/rom-deep-review/ordinary-walking-baseline/results.json`.
|
||||
|
||||
The complete Origin source review still finds no supported entry-to-Falynum
|
||||
connection. Full 256-chunk terrain and current options-aware collision/navigation
|
||||
leave the Falynum platform disconnected. Its visible ROS platform is 7.23 m
|
||||
above the ground below, and the native path component is separate. The referenced
|
||||
boss Lua teleport is a combat catch-up action after acquiring an attack target,
|
||||
not an approach transport. No bridge or approach teleport was inferred. The
|
||||
entry-to-Life connection remains in the current Recast navigation and ordinary
|
||||
walking proof. Detailed verdict:
|
||||
`artifacts/playtest/origin-route-diagnostic/origin-falynum-source-connectivity-verdict.md`.
|
||||
|
||||
## Evidence and validation
|
||||
|
||||
- Room cameras: `artifacts/playtest/rom-room-coverage/`.
|
||||
- Compressed alpha candidates and guarded promotion:
|
||||
`artifacts/playtest/rom-room-coverage/native-alpha-stage/`.
|
||||
- Adapted lighting: `artifacts/playtest/rom-source-lighting-adapted-entry-qa/`;
|
||||
comparisons: `artifacts/playtest/rom-source-lighting-profile-compare/`.
|
||||
- Native lighting resolver, linear runtime colors, source shadow pose,
|
||||
terrain/water materials, water resource lifecycle/scheduling, native alpha
|
||||
cache/staging/converter semantics, source UV exceptions, and optimizer policy
|
||||
have focused passing tests. TypeScript checks pass.
|
||||
|
||||
The pre-v2 reviewed build is `artifacts/playtest/rom-deep-review/build-reviewed-20261006/`.
|
||||
Its frozen manifest is `reviewed-content-manifest-20261006.json`, version
|
||||
`content-fcd09f7c0f8f10be`, SHA-256
|
||||
`f1a7ab2dc9a3d05513f3601ed5142011f71aa58155a7ec1d34bdc42e4f9309af`.
|
||||
TypeScript, Vite production build, static precompression and release-bundle
|
||||
verification pass: 1,328 modules, 126 chunks and 5,569 bootstrap objects.
|
||||
Its all-30 quality audit matches 1,620/1,620 images to source resolution,
|
||||
including five exact pixel crops, with zero downsizing, 2048-cap hits or issues.
|
||||
This audit skips general pixel decoding; targeted codec/alpha proofs described
|
||||
above cover the changed material families. All 162 dungeon GLBs validate with
|
||||
zero actionable errors/warnings. KTX2 audit covers 106 visual assets and 12,897
|
||||
compressed images with zero fallbacks; the existing performance budgets have
|
||||
zero regressions. Focused runtime tests pass 83/83 and focused pipeline tests
|
||||
pass 17/17. No readiness promotion, full balance sweep, commit, or external
|
||||
deployment is part of this review.
|
||||
|
||||
The refreshed v5 build is `artifacts/playtest/rom-deep-review/build-surface-v5-20261006/`,
|
||||
with index SHA-256 `ab46b9c47a0ba27b0b1c2e0a2c65ff02c613b7b87c54d37fe5ec9a7a41707e27`.
|
||||
Its frozen manifest is `surface-v5-content-manifest-20261006.json`, version
|
||||
`content-d1ec6f1f858f21c1`, SHA-256
|
||||
`e102c30cc47a4130fff88809ce53453929e86e6f766b0afbbae8a8ad4a52fd7c`.
|
||||
TypeScript, production build, 129-source static precompression (258 outputs) and
|
||||
release-bundle verification pass. It retains 126 chunks and 5,569 bootstrap
|
||||
objects. The refreshed all-30 quality audit again matches 1,620/1,620 textures,
|
||||
including five verified crops, with zero downsizing, cap hits or issues. All 162
|
||||
dungeon GLBs validate with zero errors/warnings. Focused checks pass 83 runtime
|
||||
and 17 pipeline tests. See `environment-quality-surface-v5-20261006.{json,md}`.
|
||||
|
||||
The v5 ordinary walking checks reached 48/48 legs across Barren (27), HOTO (2)
|
||||
and Origin (19), with 89/89 grounded samples, 101.826 m travelled and zero errors.
|
||||
HOTO remains a six-metre probe; Origin follows Life. Root inspected Barren leg 11,
|
||||
HOTO leg 1 and Origin leg 18 High frames: corrected detail is present, bodies and
|
||||
equipment render, and Origin's documented opaque root cards remain. Evidence is
|
||||
in `production-targeted-routes-surface-v5-20261006/`. Stockade's v5 fallback
|
||||
selected **Bazil Thredd**, passed default/High settings and recorded zero browser
|
||||
errors; root inspected the High frame. Its evidence is in
|
||||
`graphics-fallback-surface-v5-20261006/`.
|
||||
|
||||
The final v5 entry pass reaches all 30/30 registered dungeons with ready assets
|
||||
and grounded players in both Standard and High (150% render scale, 16× filtering,
|
||||
authored ambient). It records 60 screenshots and zero browser errors. Independent
|
||||
and root contact-sheet review found no actionable new entry regression; the
|
||||
documented Raksha/source-panel framing limits remain, and Kulech's maroon
|
||||
obstruction did not recur. See `production-entry-surface-v5-20261006/`.
|
||||
`validation-summary.json` independently checks the frozen build/manifest, all 30
|
||||
unique dungeon IDs, settings, movement outcomes and the three changed visual
|
||||
assets against both shipping files and immutable content objects.
|
||||
The local `dist` now contains that reviewed build: all 5,967 files match byte for
|
||||
byte. The previous build is preserved at `pre-surface-v5-dist-backup/`; installation
|
||||
proof is `local-build-install-proof.json`. This is a local installation, not an
|
||||
external deployment. Final release hygiene is recorded after note updates in
|
||||
`release-check-final.log`.
|
||||
|
||||
The pre-v5 intermediate frozen production pass rendered all 30 entrances through the
|
||||
normal UI, with ready assets and grounded players in both Standard and High,
|
||||
60 screenshots, and zero browser errors. The eight changed material/water
|
||||
environments also received ordinary keyboard walking: 150/151 legs reached,
|
||||
277/277 grounded samples, 325.037 m travelled, and zero browser errors. Raksha's
|
||||
blocked first leg is retained. Stockade's graphics fallback selected Hamhock and
|
||||
passed default/High rendering checks. Evidence is under
|
||||
`artifacts/playtest/rom-deep-review/production-entry-final/`,
|
||||
`production-walking-final/`, and `graphics-fallback-final/`.
|
||||
|
||||
The pre-v2 targeted routes use the reviewed build and frozen manifest above:
|
||||
Barren reached 27/27 legs, HOTO 2/2 and Origin 19/19. All 95 sampled positions
|
||||
were grounded, with 103.622 m travelled and zero browser errors. HOTO remains
|
||||
only a six-metre collision probe; Origin targets the connected Life route,
|
||||
not Falynum. Standard/High walking frames are in
|
||||
`production-targeted-routes-reviewed-20261006/`. That Stockade fallback
|
||||
selected **Kam Deepfury** and passed default/High settings, with zero errors;
|
||||
its evidence is in `graphics-fallback-reviewed-20261006/`.
|
||||
|
||||
The pre-v2 all-30 entry pass also reached ready, grounded entries in Standard
|
||||
and High with 60 screenshots and zero browser errors. Visual review flagged
|
||||
remaining HOTO scale issues, addressed by the v2 policy above. Barren retains
|
||||
broad source-painted striations despite the corrected fine detail. Raksha's
|
||||
entry camera clips inside architecture and its first route leg remains blocked;
|
||||
this is not a complete scene-quality acceptance. Wider source-anchor views
|
||||
provide separate material/lighting coverage. Kulech's High entry frame contained
|
||||
a maroon obstruction during combat. It did not recur in 25 consecutive High
|
||||
frames in an ordinary-UI follow-up. The original Standard/High pair compares
|
||||
changing combat states, so exact object attribution remains unproven; no lighting
|
||||
defect was demonstrated. Read-only rays in the clear frames identify the static
|
||||
source wall/stone behind it. See `kulech-obstruction/findings.md` and `frames/`.
|
||||
|
||||
Those intermediate production screenshots found further issues even though the
|
||||
historical pre-crop audit's 1,615 matched textures retained their dimensions. Resolution checks do
|
||||
not establish good surface mapping. Barren's whole-atlas repeat mixes floor and
|
||||
wall regions; restoring UV0 removes the added bands but leaves oversized detail.
|
||||
The promoted atlas-safe floor/wall correction and HOTO source-detail policies
|
||||
above supersede those intermediate mappings.
|
||||
Origin's giant-tree family also retained alpha pixels but lacked native MASK on
|
||||
six canonical materials merged into one optimized material. Its source-pinned
|
||||
JSON-only correction is now promoted, preserving every non-JSON GLB chunk and
|
||||
all terrain/water settings. Seven freshly exported ROS resources prove standard
|
||||
lighting and MASK cutoff 192/255; cache/converter smoke passes all seven. The
|
||||
same-camera 3.5 m leaf close-up has matching served hashes, exact first hits,
|
||||
unchanged lighting and zero errors. A separate leg-18 diagnostic context uses
|
||||
the recorded walking position, but is not itself ordinary input evidence.
|
||||
The separate `elves_vine` card also lost cutout semantics and compressed alpha.
|
||||
Fresh exports independently prove that `elves_vine.ros` material 1 and
|
||||
`act_green_tower.ros` material 3 use the same DDS with standard lighting and
|
||||
MASK cutoff 170/255. Both canonical bindings and their optimized merged material
|
||||
now retain that policy. The replacement 256×256 UASTC image retains nine mip
|
||||
levels and all 10,407 source pixels passing the cutoff, with zero threshold-mask
|
||||
mismatches; alpha bytes are not claimed lossless. The canonical BIN is unchanged,
|
||||
and the optimized patch preserves all non-target buffer views, mesh streams,
|
||||
terrain and water metadata. Same-camera served-hash proof removes the black
|
||||
vine panel with zero browser errors. Its exclusive backup and proof live under
|
||||
`artifacts/playtest/rom-deep-review/origin-root-card-attribution/`.
|
||||
The residual leg-18 card is `Object01_1_mesh_0_10`, native material 1 from
|
||||
`gaint_tree_a.ros`, using `elves_gaint_roots_village`. Fresh source flags request
|
||||
alpha test 192, but all eight native DXT1 mips, the prepared PNG, and all ten
|
||||
shipping KTX mips are fully opaque. This is not a lost-alpha regression. The
|
||||
exporter supplies neither vertex-color/alpha nor face-culling channels, so the
|
||||
complete native behavior remains unverified. No black-keyed mask or forced
|
||||
cutout was invented. The card remains a visual limitation, documented in
|
||||
`origin-root-card-attribution/residual-roots-village/roots-village-alpha-proof.json`.
|
||||
Evidence and exclusive promotion backup:
|
||||
`artifacts/playtest/rom-deep-review/origin-tree-alpha/`.
|
||||
|
||||
Mystic's crimson entry panel is the source-authored opaque
|
||||
`cowcowcowcow01_164_mesh_0`; the source atlas is entirely opaque. Sardo's close
|
||||
column is the authored `channel_pillar_01_52_mesh_0`, likewise opaque. Sardo's
|
||||
first ordinary walking leg opens the room; Mystic's panel still occupies much
|
||||
of some walking frames, so those frames do not establish whole-room lighting.
|
||||
The source-anchor camera review supplies wider material/lighting coverage.
|
||||
Exact source identities and framing evidence are in
|
||||
`production-entry-final/entry-framing-attribution.md` and its JSON companion.
|
||||
@@ -0,0 +1,25 @@
|
||||
# RoM Group Heal radius — 2026-10-04
|
||||
|
||||
The generated RuneWaker row for Group Heal (`490281`) says it restores HP to
|
||||
"all party members within range of 120." `src/game/romAbilityCatalog.ts`
|
||||
already translates that local source distance into `ability.radius: 12` through
|
||||
`areaRadius`'s `/ 10` conversion. Its party-scoped heal effect did not carry that
|
||||
radius, so `healingRecipientIds` applied its existing 30 m fallback.
|
||||
|
||||
The catalog now copies Group Heal's derived ability radius onto only its
|
||||
party-scoped heal effect. Player casts in `combatStore.ts` and companion casts
|
||||
in `partyRuntime.ts` both pass this effect through the shared
|
||||
`healingRecipientIds` resolver. The resolver still requires a living recipient
|
||||
and line of sight, and its shared fallback remains unchanged for other spells.
|
||||
|
||||
`src/game/romGroupHealRadius.integration.test.ts` checks the catalog mapping,
|
||||
the 12 m inclusive boundary and 12.01 m exclusion, living and LOS filtering,
|
||||
player and companion execution, and Soul Source's unchanged party-heal
|
||||
fallback.
|
||||
|
||||
Focused validation passed: `npm test -- --run
|
||||
src/game/romGroupHealRadius.integration.test.ts` (3 tests). The npm `pretest`
|
||||
hook also ran `loot:generate` and reported 9 bosses, 23 items, and 23 table
|
||||
entries. No build or full suite was run by this subprocess. The coordinated
|
||||
final build, regression selection and bounded Stockade evidence are recorded
|
||||
in [the parent report](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md).
|
||||
@@ -0,0 +1,119 @@
|
||||
# RoM healing, party selection and ranged follow-up (2026-10-04)
|
||||
|
||||
The owner approved four follow-ups to the Stockade continuation: Group Heal's
|
||||
recipient radius, the active native-five party complement, recurring player
|
||||
Auto Shot, and source verification of Blood Arrow's damage curve through the
|
||||
level-80 cap. Independent GPT-6 Luna extra-high subprocesses implement and
|
||||
audit the mechanics; the parent coordinates shared files, build and live QA.
|
||||
|
||||
## Current implementation and source boundary
|
||||
|
||||
Group Heal source 490281 already supplied an ability radius of 12 metres, but
|
||||
its party-heal effect omitted that field and the shared resolver used its
|
||||
30-metre fallback. The catalog now copies the sourced radius onto only that
|
||||
spell's party-heal effect. Player and companion execution share the living,
|
||||
distance and line-of-sight recipient rules. Other spells keep their existing
|
||||
recipient contracts. See [the radius report](ROM_GROUP_HEAL_RADIUS_2026-10-04.md).
|
||||
|
||||
Party generation now receives the player's exact ordered RoM class pair from
|
||||
ordinary entry and avatar preloading. If the other active identities can fill
|
||||
the requested roles, generation excludes the player's identity. The full
|
||||
five-person party therefore uses the other four canonical identities around
|
||||
each supported player. Unsupported pairs and unfillable compositions keep the
|
||||
prior role-pool fallback. Actor stat rulesets and readiness remain independent.
|
||||
See [the selection report](ROM_NATIVE_PARTY_SELECTION_2026-10-04.md).
|
||||
|
||||
Scout/Rogue player Auto Shot now uses learned primary skill 492589 through
|
||||
ordinary ability bindings. Its independent timer produces recurring ranged
|
||||
Physical attacks at 80% ranged weapon DPS. Supported native actors use the
|
||||
source ranged damage and interval; unsupported/custom gear falls back to the
|
||||
resolved item's shared DPS and speed. The existing automatic Training Gear
|
||||
bow is valid with an empty inventory; compatible assigned gear overrides it
|
||||
and unequipping that gear restores the training bow. Haste is resolved once in
|
||||
both stat modes. The active mode suppresses melee/off-hand swings, follows
|
||||
target selection, can always be stopped and clears on target loss, missing resolved gear,
|
||||
death and reset. Owned Blood Arrow charges its 2% maximum-HP cost once per
|
||||
committed shot attempt and skips unaffordable attempts. The source does not
|
||||
quantify its contribution from the last offensive skill; that bonus remains
|
||||
omitted. Local range and other runtime constraints are documented in
|
||||
[the Auto Shot report](ROM_PLAYER_RANGED_AUTOSHOT_2026-10-04.md).
|
||||
|
||||
The Blood Arrow audit has not established a current skill-rank formula through
|
||||
80. Current Scout/Rogue and Knight/Scout pages each publish only the maximum
|
||||
skill-rank-105 value of +104.5%; that single point does not establish rank 80.
|
||||
The local RuneWaker snapshot supplies one historical +10% component. Retain
|
||||
the current 10% approximation until additional matching source evidence is
|
||||
available. See [the source audit](ROM_BLOOD_ARROW_SCALING_2026-10-04.md).
|
||||
|
||||
## Validation and evidence
|
||||
|
||||
The final seven-file mechanic regression selection passes 96 checks: Auto
|
||||
Shot 13, native auto attacks 5, Blood Arrow/Blood Punishment integration 15,
|
||||
Group Heal radius 3, party selection 32, Blood Arrow evidence boundary 1 and
|
||||
catalog semantics 27. Ready-five passes seven Vitest and twenty Python checks,
|
||||
for 103 distinct Vitest and twenty Python checks in the required selection.
|
||||
The shared production build passes TypeScript/Vite, prebuild asset audits,
|
||||
static compression and release-bundle verification. Its frozen entry is
|
||||
`index-CLGdfcYj.js` for the initial probe. The initial live run exposed an
|
||||
explicit-assignment-only guard that rejected the automatically supplied bow.
|
||||
The authoritative resolved-loadout correction now passes its fresh-profile
|
||||
and custom-item fallback checks. The replacement production build passes all
|
||||
hooks with entry `index-Cvmh-YKE.js`; its recursive 123-JavaScript manifest
|
||||
SHA-256 is `ed3cb65752426810c84be15184306114fdf36d3804a23f917213fc854f4651d4`.
|
||||
Bounded full Stormwind Stockade run `20261005-042203897` passes its three
|
||||
required live criteria in 61.051 seconds on that unchanged freeze. Both
|
||||
normally generated parties are the player's exact four-identity native-stat
|
||||
complement. Normal Attack order supplies natural injuries; a completed player
|
||||
Group Heal gives Caelan 92 effective HP. Its full-health self event is entirely
|
||||
overheal. Two sourced Auto Shot Physical hits deal 37 effective damage each,
|
||||
2,612 ms apart. Normal stop input clears the mode and produces no Auto Shot
|
||||
hit during the observed stop window. The captured restart is not attempted
|
||||
after target death, so restart remains inconclusive live. The focused recurring
|
||||
test verifies stop-window silence/no cost, reactivation without an immediate
|
||||
or catch-up hit, and a fresh full-interval deadline followed by one shot.
|
||||
|
||||
Blood Arrow is already owned and active at the Scout entry. Its raw HP windows
|
||||
overlap combat and recovery; exact HP-only cost is integration-test evidence,
|
||||
not inferred from aggregate live deltas. NPC recipient position is unavailable
|
||||
in the Group Heal snapshot, so the 12 m boundary remains deterministic test
|
||||
proof. Actual screenshots show loaded bodies, equipped silhouettes and HUD,
|
||||
with doorway/party overlap and camera occlusion. There are no page or asset
|
||||
HTTP errors; the console records a favicon 404. Raw JSON and images are in
|
||||
`playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/` and details
|
||||
are in [the live report](ROM_HEALING_RANGED_STOCKADE_PLAYTEST_2026-10-04.md).
|
||||
|
||||
Initial run `20261005-040846797` preserves the fixture name-casing failure.
|
||||
Run `20261005-040932648` preserves the rejected automatic bow and unengaged
|
||||
Defend/selection-only encounter. Neither is relabeled as successful. This
|
||||
follow-up proves bounded mechanics, not another full clear or balance pass.
|
||||
Supplemental same-build run `20261005-042845955` passes the same criteria in
|
||||
61.658 seconds: Caelan again receives 92 effective Group Heal HP and two
|
||||
Physical Auto Shot hits deal 36 each. Normal Stop party order preserves the
|
||||
target briefly, then Auto Shot cancellation clears its state with no shot in
|
||||
the observed stop window. The target still dies before restart; the original
|
||||
Defend order is restored. Root also inspects that run's stopped-party and
|
||||
cancel/restart screenshots. No further live run is required for this scope.
|
||||
|
||||
A supplemental generic `combatStore.test.ts` run passes 110 of 111 checks and
|
||||
reports a Chronomancer resource expectation mismatch (414 expected, 369
|
||||
observed). The same exact test fails with committed HEAD versions of the
|
||||
changed production modules, so this mismatch predates the follow-up. The
|
||||
[baseline replay report](../artifacts/rom-healing-ranged-baseline/README.md)
|
||||
records its source-only scope and both logs. It is not hidden inside the
|
||||
passing required selection.
|
||||
|
||||
Final validation also passes the standalone TypeScript check after the new
|
||||
restart assertions, using the project's 8 GB Node heap setting. A preceding
|
||||
check with Node's smaller default heap exhausted memory. `npm run release:check`
|
||||
passes for all 20 changed game paths, including untracked files. Exact EOF
|
||||
newline/trailing-whitespace checks pass for 26 changed game and relevant vault
|
||||
text files; both Git diffs are reviewed and the real index remains unstaged.
|
||||
|
||||
Earlier Stockade full-clear and Vow captures remain evidence for their recorded
|
||||
builds. They do not verify this new code. New live checks use ordinary entry,
|
||||
bindings, movement and casts, with read-only runtime telemetry. Any isolated
|
||||
level-30 profile preparation must be identified in the live report.
|
||||
|
||||
The baseline is clean game commit `6114a229`; pre-existing vault changes are
|
||||
preserved. This task does not add loot or ammunition, raise the level cap,
|
||||
promote a Needs Testing build, commit or deploy.
|
||||
@@ -0,0 +1,56 @@
|
||||
# RoM healing and ranged Stockade diagnostic — 2026-10-05
|
||||
|
||||
**Outcome: complete for the focused live criteria.** Two bounded ordinary-UI runs verified an effective Group Heal, two source-attributed recurring Auto Shot hits, and the generated native-five party complement at both normal Stockade entries. This is not a full Stockade clear, readiness promotion, or balance certification. The report filename remains the date originally assigned; the browser runs occurred on October 5.
|
||||
|
||||
## Runner and fixtures
|
||||
|
||||
The reusable runner is [`scripts/playtest-rom-healing-ranged.cjs`](../scripts/playtest-rom-healing-ranged.cjs). It opens the full Stormwind Stockade (`stormwind-stockade`) through Dungeons → WoW and the ordinary content-download/role flow. It creates two disposable level-30 profiles through the visible character UI. Level and secondary-class preparation occurs only in isolated pre-entry progression.
|
||||
|
||||
| Player fixture | Exact companions checked at normal entry | Live focus |
|
||||
| --- | --- | --- |
|
||||
| Priest/Knight healer, `Romhealpk` | Knight/Scout tank; Mage/Warlock damage; Rogue/Warrior damage; Scout/Rogue damage | Learned Group Heal, normal action-bar cast, healing events and available recipient distances |
|
||||
| Scout/Rogue damage, `Romrangesr` | Knight/Scout tank; Mage/Warlock damage; Priest/Knight healer; Rogue/Warrior damage | Learned Auto Shot, ordinary action-bar activation/cancellation, and descriptive Blood Arrow HP/resource windows |
|
||||
|
||||
At both entries, all four companions matched the exact native-five complement for the player's ordered identity pair; each had level 30 and the RoM stat ruleset. The runner recorded all action-binding layers and used normal UI assignment where needed. It did not inject or prescribe companions. Movement, facing, targeting, rendered UI orders, and ability casts were ordinary inputs. Store snapshots were read-only; there were no in-combat HP, resource, cooldown, position, cast, target, or party mutations.
|
||||
|
||||
## Frozen build and browser health
|
||||
|
||||
The approved frozen build used 123 recursively fingerprinted JavaScript assets. Both successful runs started and ended with the same manifest SHA-256, `ed3cb65752426810c84be15184306114fdf36d3804a23f917213fc854f4651d4`. `dist/index.html` was 812 bytes with SHA-256 `786875f7ca8e26df9d896810ecc7820e1b68f9a46b799d5922fd5cf61b638175`. Key served bundles were:
|
||||
|
||||
| Asset | Bytes | SHA-256 |
|
||||
| --- | ---: | --- |
|
||||
| `index-Cvmh-YKE.js` | 5,476,357 | `f7346f993f9dde4f23c5678513413dd7a5cba9e6fbf6b942b280f472c72b8c8f` |
|
||||
| `GameRuntime-Bvkmd8ZT.js` | 354,351 | `517f0c6d4d2a753b6aee8852c546aa213205ca276816f8444fb135960a531a1a` |
|
||||
| `combatStore-Q2hxVe7P.js` | 5,373,025 | `d8ca4427d693f24111a84ff55ce454b0ef0f2e0bcc51615018083231e746e6d6` |
|
||||
| `PartyFrames-Cy8eifsT.js` | 2,293,069 | `821ceea9ac9cdc7b94e9e4248a8e39f6ff1a6cf48c9a907dea904cf8e196bce0` |
|
||||
| `romAbilityCatalog-CD84SmiY.js` | 1,797,034 | `b66428b14f2fd5055344129f436d14a9a52e14b04a527ee689ceac8f5302f574` |
|
||||
|
||||
The primary run recorded 145 JavaScript response events and all returned HTTP 200; the required fingerprinted bundles were served successfully. Four repeated `basis/basis_transcoder.js` responses are outside the 123-asset fingerprint manifest and had no response hash. Across both successful runs there were no page errors and no HTTP errors. The only console error was a local `favicon.ico` 404.
|
||||
|
||||
## Preserved attempts
|
||||
|
||||
The first attempt, [`20261005-040846797`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-040846797/), stopped before dungeon entry when the character UI normalized fixture names to initial-cap plus lowercase. Its `failure.png` and `failure.json` are preserved; the harness now uses canonical names.
|
||||
|
||||
The next attempt, [`20261005-040932648`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-040932648/), reached both normal entries and verified both complements, but remained inconclusive: Defend/selection-only input did not create a natural Group Heal opportunity, and Auto Shot could not start with empty explicit inventory under the then-current equipment guard. The source was corrected to use the existing automatic Training Gear loadout. This run remains preserved and is not counted as success evidence.
|
||||
|
||||
## Primary complete run
|
||||
|
||||
[`20261005-042203897`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/) completed in 61.051 seconds with all three required evidence flags true and an unchanged frozen manifest. Its roster, normal-entry, Group Heal, encounter-stop, Scout action, and cancellation images were inspected.
|
||||
|
||||
- **Group Heal:** The Priest/Knight's learned source 490281 (`rom-priest-primary-8`, radius 12, 3-second cast) was normally bound and cast from the action bar while a rendered Attack party order was active. A player-sourced healing event (ID 104) restored 92 effective HP to a Scout/Rogue companion (1,679 raw; 1,587 overheal). The self-recipient event (ID 105) was entirely overheal. The companion's runtime position was unavailable, so the event does not establish a live 12 m boundary measurement.
|
||||
- **Auto Shot:** After ordinary movement/targeting/facing and a rendered action-bar start, scheduler state selected a real Defias Inmate at 4.78 m. Two distinct player-to-enemy physical hits tagged `rom-scout-primary-57` / source 492589 landed for 37 effective damage each (event IDs 102 and 117). Auto Shot cancellation cleared its scheduler target and next-shot state. Restart was not attempted because the live target died during the post-cancel window.
|
||||
- **Blood Arrow:** The owned aura was already active before direct test input. The raw snapshots show HP `2293.53 → 2247.53 → 2247.53 → 2201.53` from a `2293.53` maximum and resource remaining at 100. No player incoming-damage or healing events appeared in the recorded windows. The frozen source contract intentionally emits no separate self-cost event; these snapshots are descriptive and are not used to prove the exact two-percent cost.
|
||||
|
||||
Primary screenshots include [`priest-knight-roster.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-roster.png), [`priest-knight-stockade-entrance-party.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-stockade-entrance-party.png), [`priest-knight-group-heal-attempt-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/priest-knight-group-heal-attempt-1.png), [`scout-rogue-roster.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-roster.png), [`scout-rogue-stockade-entrance-party.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-stockade-entrance-party.png), [`scout-rogue-blood-arrow-state.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-blood-arrow-state.png), [`scout-rogue-auto-shot-target-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-auto-shot-target-1.png), and [`scout-rogue-auto-shot-cancel-restart.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042203897/scout-rogue-auto-shot-cancel-restart.png). The rendered bodies, equipment and HUD are present, though doorway/party overlap and close-camera occlusion remain visible.
|
||||
|
||||
## Supplemental stop-before-cancel run
|
||||
|
||||
[`20261005-042845955`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/) also completed the required criteria in 61.658 seconds with the same unchanged asset manifest. It independently observed a 92-effective-HP Group Heal and two positive Auto Shot physical hits (IDs 100 and 115, 36 effective damage each) against a real target at 4.24 m. The runner sent the normal party order `Defend → Stop → Defend`, and the Stop button's pressed state and restored Defend state were captured. Auto Shot cancellation cleared scheduler state, but the target died before a restart attempt; restart remains inconclusive. Blood Arrow snapshots were the same descriptive values and provide no standalone cost proof.
|
||||
|
||||
Inspected supplemental images include [`priest-knight-group-heal-attempt-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/priest-knight-group-heal-attempt-1.png), [`priest-knight-group-heal-encounter-stopped.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/priest-knight-group-heal-encounter-stopped.png), [`scout-rogue-auto-shot-target-1.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-target-1.png), [`scout-rogue-auto-shot-cancel-party-stopped.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-cancel-party-stopped.png), and [`scout-rogue-auto-shot-cancel-restart.png`](../playtest-artifacts/rom-healing-ranged-stockade/20261005-042845955/scout-rogue-auto-shot-cancel-restart.png). These images show the same doorway and camera occlusion noted above.
|
||||
|
||||
## Limits
|
||||
|
||||
This was a bounded encounter at the Stockade entrance, not a clear or broad party-balance evaluation. The live Group Heal observation proves an effective event on one generated companion but cannot validate the 12 m cutoff because the companion position was null. Deterministic focused integration coverage owns the exact-radius, living-recipient and line-of-sight checks for player and companion casts. Likewise, Auto Shot cancellation was verified, while a successful restart could not be observed before the natural target's death. Blood Arrow's exact two-percent max-HP debit remains source/integration evidence: this live report records the owned aura and HP/resource/event windows without attributing ambiguous HP deltas to the cost.
|
||||
|
||||
Raw JSON, all screenshots, build hashes, party-complement assertions, scheduler snapshots, event IDs, and run diagnostics are preserved in each linked run directory.
|
||||
@@ -0,0 +1,63 @@
|
||||
# RuneWaker Native Disarm Main-Hand Audit (2026-10-05)
|
||||
|
||||
## Finding and scope
|
||||
|
||||
The local RuneWaker RoleAttr source initializes a missing main hand as `EM_Weapon_Unarmed` with speed 30, and its unarmed Main_DMG path supplies `Level * 2` when the main-hand base damage is zero. This is enough to replace the training weapon inputs for native Main_DMG-dependent formulas. It does not justify a WoW punch constant or a blanket multiplier. The implementation is opt-in through the native amount adapters; the separate WoW compatibility formula is not changed here.
|
||||
|
||||
The verified profile applies to the five active native player-build identities and their generated party-NPC derived-stat snapshots: Knight/Scout, Priest/Knight, Rogue/Warrior, Scout/Rogue, and Mage/Warlock. It retains the existing training-profile `residualFlatDamage` bridge and tracked generic physical-damage multiplier. The native stat model does not represent all weapon-category damage/speed rates, so the profile records a neutral-rate boundary rather than claiming exactness for those channels.
|
||||
|
||||
## Primary local source evidence
|
||||
|
||||
Paths below are relative to `F:\Projects\Runewaker`. Hashes are SHA-256 of the audited local files.
|
||||
|
||||
| Source | SHA-256 | Relevant evidence |
|
||||
| --- | --- | --- |
|
||||
| `SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` | `8143A90CE826BF3152551A4508D212F186012CBC054E505E426551CB62369C1F` | `Init_BaseEQValue` lines 178–203 initializes unarmed main hand, speed 30, and main DMG/speed factors 1. `_Main_ATKSpeed` lines 533–580 applies generic `AtkSpeed`, main-hand speed factor, all-weapon speed rate, unarmed speed rate, and the weapon's base speed, clamped to 5. `_MainDMG` lines 713–758 applies main-hand DMG factor, all-weapon DMG rate, `DMG_Per`, and unarmed DMG rate; if `BaseEQ.Main_DMG == 0`, it assigns `Level * 2`, then returns `max(1, (Fin.DMG + BaseEQ.Main_DMG) * DmgRate)`. `AddAbility` line 1323 routes type 25 into `BaseEQ.Main_DMG`; lines 1327–1374 route typed main damage and speed rates by weapon category. `MainAtkDamage` line 963 applies source weapon variance after `Fin.Main_DMG`. |
|
||||
| `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` | `708F2D087F2654B97D149AB7124D9CDFFC915CF8BF18108FEFF3F1A45F124C20` | Defines `EM_Weapon_Unarmed` (line 1047) and the typed body-rate fields consumed by RoleAttr. |
|
||||
| `SourceCodeVS2019/Libraries/Union/RoleData/RoleBaseDef.h` | `BAE1014F3628B4AD05C2E0F08CDCAE14D5F13A0981DAD4D592F2F0A10BFAAB18` | `_BASE_ATTACK_SPEED_` is 40; that default is not the unarmed main-hand value, which RoleAttr sets explicitly to 30. |
|
||||
| `SourceCodeVS2019/Server/NetGameServer/MainProc/Global_SimpleSchedular.cpp` | `5DCDBDD69EEFE1086E2087AB167270D580884929A083E4E69032C773F7F941AC` | Main-hand auto scheduling adds `int(Fin.Main_ATKSpeed)` to the server clock (line 445), so this source speed unit is milliseconds. The source auto-hit then calls `MainAtkDamage` (line 633). |
|
||||
| `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp` | `B2EEE402FDF9AC488ABE62DC8D2EC9C52B312542EF06D95A6B6FF594711CA7C3` | Physics damage uses `Main_DMG * 10 * SpellTime / Main_ATKSpeed` (line 2327). Physics_Point subtracts `Main_DMG * Dmg_MagArg` once for fixed effects or times SpellTime otherwise (lines 2384–2386). These are native ability branches that must see the unarmed main-hand inputs after Disarm. |
|
||||
| `SourceCodeVS2019/Libraries/Union/RoleData/RD_Normal.cxx` | `5C0C726F469A7BE63D76114015BF169193A88F545209D4A4DEB5E090443C2692` | `CalAddDotMagicLv` lines 2423 onward applies rank correction; its negative physical DotMagic branch reads `Fin.Main_DMG` and `Fin.Main_ATKSpeed` (line 2507). |
|
||||
| `SourceCodeVS2019/Libraries/Union/RoleData/RD_ValueCal.cxx` | `D7F00AD9E760EC2263F81F231113F165D0D9F29EB2C329593C66F4C6288A69A9` | Confirms the native `Main_DMG` accessor and unarmed category logic in the value-calculation path (lines 2529, 3642–3646). |
|
||||
|
||||
The active ability bindings are `src/game/generated/romNativeHolyHealBindings.generated.json` (SHA-256 `CE2F39D602296686382CDC424F9FEA4EFA8DE384093443311E9C8FB6C97AAA04`) and `src/game/generated/romNativePeriodicDamageBindings.generated.json` (SHA-256 `C01E17C4DF2ADB3B3A196D9EE1F84EA752BE94DBA81FB47E23A889599CB63D33`). Their source metadata pins `magiccollectobject.db` (`4aae19865cb07b30f99945aa7319a0096db244ff5e5b4b5d902fc6889474f501`) and `magicobject.db` (`52af13a2d8cfa9a66d4caa2d3c38832edc232f058995a64ef8135a6b82e43691`) for player attack/periodic rows. The native stat-rule artifact pins `racetable.db`, `sextable.db`, `voctable.db`, and `fixtable.db`; `romNativeStatRules.generated.json` SHA-256 is `6DA531D6D56642013155438B93BB55C120A6421C7C12858CAD8C1B934E1E4E99`.
|
||||
|
||||
The training item curve used for the bridge is `src/game/generated/romNativeDamageTrainingProfiles.generated.json` (SHA-256 `A3E064F536F4E1EFAFA076D13755DE5DC62C23B20A496AE572F783126DBE3BCB`). It records `romHeirloomReference.json` SHA-256 `4E5194A28C2764838C5862C1F3DB505F5BE3CE99143A4440BAECF5E38C3099BF` and the source item-database hashes: `armorobject.db` `A2F0017C4772165D562EBB08CA0AC51625CDC4453E3670A1501DF7D741D2BAD3`, `weaponobject.db` `2BC28EEBBE413BD6118F027E3FEC1A3953CEF371476937D0B65622C542971A67`, `addpowerobject.db` `D651861FC5918BAC937D726D754D17A92DA34DB5059F9C70AC9F6B2C15711432`, and `string_enus.db` `4FCE021BA9ED110A213E08D3228B2DE57CEC66DDBBC8DCF5753204874D9AB75`. These are the pins recorded by the generated reference, not a claim that the separate active `Runewaker/Resource/data` directory has those same hashes.
|
||||
|
||||
## Implemented formula and adapter contract
|
||||
|
||||
For a verified active-five native training profile, the source-shaped unarmed main-hand amount is:
|
||||
|
||||
```text
|
||||
Main_DMG_unarmed = max(1, (residualFlatDamage + Level * 2) * physicalDamageRateFactor)
|
||||
Main_ATKSpeed_unarmed = 30
|
||||
Main_attack_interval = 30 * 100 ms = 3000 ms
|
||||
```
|
||||
|
||||
`residualFlatDamage` is the existing native training-weapon bridge remainder after the generated profile's weapon contribution is removed. The `physicalDamageRateFactor` remains applied. Main-hand-only rate channels that this stats bridge cannot supply are held neutral and explicitly surfaced as `unmodeledRateChannels`: `Main_DMG_Per`, `DMG_AllWeapon`, `DMG_Unarmed`, `AtkSpeed`, `Main_ATKSpeed_Per`, `AttackSpeed_AllWeapon`, and `AttackSpeed_Unarmed`.
|
||||
|
||||
`nativeDisarmedMainHandAutoAttackProfile(caster)` only returns a profile when the current native derived stats match the canonical active-five training-gear profile. It identifies the main source as `runewaker-roleattr-unarmed-main-hand`, has no training weapon item IDs, and leaves `physicalAttack` intact. This profile is the prepared optional override for:
|
||||
|
||||
- `nativeDamageCasterAmount(..., targetContext?, mainHandOverride?)`: when the bound native component is calculation type 0 or 9, or has a nonzero fixed contribution of type 2, the adapter validates the override and feeds the lower native resolver a copied training profile whose main hand is `Level * 2`, speed 30, and `sourceItemIds: []`. The residual, generic rates, off-hand, and ranged entries are retained. Other components do not consume the substituted main-hand fields; a ranged branch therefore keeps its existing ranged inputs.
|
||||
- `nativePeriodicDamageCasterSnapshot(..., magicResistance?, effectiveMagicPower?, mainHandOverride?)`: only the physical negative HP DotMagic rank-correction branch consumes the override. Other periodic branches keep their current source behavior.
|
||||
|
||||
In both APIs an omitted override preserves the pre-existing native calculation. A stale or invalid supplied override fails closed for a branch that consumes Main_DMG/Main_ATKSpeed (`null` for direct damage, `undefined` for a periodic snapshot). Custom/unverified gear returns no disarmed profile; callers must keep their existing explicit fallback behavior. This does not grant spell usability or certify native weapon/category prerequisites for every ability.
|
||||
|
||||
## Known limits
|
||||
|
||||
- This is the source main-hand input before `MainAtkDamage` variance, hit, target defense, crit, and other downstream combat resolution. It is not a complete auto-hit result.
|
||||
- The native rules sidecar models generic physical damage rate, not all seven unarmed/main/all-weapon rate channels listed above. Their neutral values are a boundary of this implementation, not a source claim that the rates are always 1.
|
||||
- The profile is verified against canonical generated training gear's tracked aggregate stats. A custom set whose tracked totals differ fails the gate, but a custom set with identical aggregates cannot be distinguished because the native gear payload has no item provenance. Equipment-specific `BaseEQ.Main_DMG` effects and unidentified weapon/category rate modifiers remain unmodeled.
|
||||
- Existing ability cast/equipment prerequisites remain unchanged and unverified by this amount adapter. Direct abilities continue through their existing shared status/availability checks.
|
||||
- The active-five generated party-NPC profile test establishes the stats preparation and formula input shape; it does not certify all classes, every NPC type, every ability, or native combat readiness.
|
||||
|
||||
## Verification
|
||||
|
||||
Focused source tests passed:
|
||||
|
||||
```text
|
||||
npx vitest run src/game/romNativeDisarm.test.ts src/game/romNativeCombatAmount.integration.test.ts src/game/romNativePeriodicDamage.test.ts src/game/romNativeDamage.test.ts
|
||||
4 files passed; 25 tests passed.
|
||||
```
|
||||
|
||||
The Disarm tests cover all five active identities as player and configured party-NPC derived stats, preserve the residual and tracked multiplier, reject custom gear and stale override values, confirm native main-hand-consuming basic-attack branches change while the ranged Scout Shot remains unchanged, and verify a physical DotMagic rank correction responds to the unarmed inputs. This was a scoped source/runtime test run, not a full balance/readiness pass.
|
||||
@@ -0,0 +1,19 @@
|
||||
# RoM native party selection (2026-10-04)
|
||||
|
||||
## Finding and owner
|
||||
|
||||
`src/game/partyStore.ts` owns live companion selection. It previously shuffled the fixed native-five pools by role without receiving the player's active class pair. In a full Stockade party with Scout/Rogue in the damage seat, the three-candidate damage pool could therefore select Scout/Rogue again and omit Mage/Warlock. The Knight/Scout tank fixture happened to be valid because the fixed role pools did not repeat its tank identity.
|
||||
|
||||
`src/game/PartyBridge.tsx` now passes the active profile's ordered RoM pair into generation. `src/ui/ManastormSelectScreen.tsx` passes the same pair to avatar preloading so its preview uses the same party as entry.
|
||||
|
||||
## Selection contract
|
||||
|
||||
When the player pair exactly matches one of the five canonical identities, generation excludes that identity only if the remaining identities can satisfy every requested NPC role seat. This preserves the exact native complement for all five supported player pairs and keeps role assignment intact. If the pair is outside the active five, lacks a secondary class, or cannot satisfy the requested role counts, generation uses its prior per-role shuffled pool.
|
||||
|
||||
The option is read only for `categoryId === "rom"`. It does not alter any member's stat ruleset, expand the native pool, affect WoW specialization readiness, or change explicitly configured companions. Party resets retain the same option through the existing `PartyState.companionOptions` lifecycle. RoM identities remain separate from WoW eligibility and online specialization filters.
|
||||
|
||||
## Focused validation
|
||||
|
||||
`npm test -- --run src/game/partyStore.test.ts` passed: 32 tests in one file. New checks verify the exact unique four-identity complement, canonical names and roles, and native RoM stats for each of the five player pairs. Fallback checks cover an unsupported pair, a role composition the complement cannot fill, and WoW generation with a RoM pair option.
|
||||
|
||||
The parent task completed the shared build and bounded Stockade checks of both normally generated entry complements; see [the coordinated report](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md). No other repository tests, balance sweeps, full-suite run, build, staging, or commit were performed by this subtask. Work stayed in the existing `main` checkout.
|
||||
@@ -1,6 +1,6 @@
|
||||
# RoM Native Party Campaign Route Playtest — 2026-10-04
|
||||
|
||||
> **Future QA default (2026-10-04):** Use Stormwind Stockade for new routine live tests. The Wailing captures and commands in this dated report are historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
|
||||
## Scope and build
|
||||
|
||||
@@ -54,4 +54,4 @@ Both route runs reported zero browser page exceptions. Each recorded one console
|
||||
|
||||
## Harness
|
||||
|
||||
The current `node scripts/playtest-native-routes.cjs --route-seconds=90` default runs an independent UI-created profile and one bounded **Stormwind Stockade** segment. An explicitly requested Barren reproduction uses `--route=barren-caves`. Historical Wailing reproduction requires the owner's explicit request and `--historical-wailing --route=wailing-caverns`; it is no longer the default. The captures above used the older two-route harness. Run and review each authorized route independently to control its starting profile at level 30.
|
||||
The current `node scripts/playtest-native-routes.cjs --route-seconds=90` default runs an independent UI-created profile and one bounded **Stormwind Stockade: Cellblock Rush** segment; its boss is selected from the run ID and should be recorded. An explicitly requested full-source Stockade route uses `--route=stormwind-stockade`; Barren uses `--route=barren-caves`. Historical Wailing reproduction requires the owner's explicit request and `--historical-wailing --route=wailing-caverns`; it is not a default. The captures above used the older two-route harness. Run and review each authorized route independently to control its starting profile at level 30.
|
||||
@@ -0,0 +1,23 @@
|
||||
# RoM Scout/Rogue player Auto Shot — 2026-10-04
|
||||
|
||||
## Source contract
|
||||
|
||||
The current Chronicles of Arcadia [Scout/Rogue skills list](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en) lists **Autoshot** under **Scout Primary Only**, source skill ID `492589`. It requires a ranged weapon, is instant and Physical, activates continuous shooting, deals 80.0% ranged weapon DPS per shot, and uses Physical Attack Speed for shot frequency. The row also says to use one piece of ammunition per shot. Its last-offensive-skill bonus is described only as “some portion”; the coefficient is not published and is not simulated. The source row does not specify a range value.
|
||||
|
||||
The local learned ability is `rom-scout-primary-57`. It is available to the verified Scout/Rogue build and retains the source primary-only identity, so Knight/Scout does not receive the skill. The ability bar uses the normal learned-ability catalog path. Its tooltip explains activation and reuse to stop the mode without presenting an unknown coefficient.
|
||||
|
||||
## Runtime behavior
|
||||
|
||||
The player’s Auto Shot state is `autoShotTargetId` plus `nextAutoShotAt`. Activation checks the living hostile target, owner, learned skill, and current resolved ranged slot. Scout Training Gear supplies a bow automatically, so an empty inventory and no explicit ranged assignment still have a valid weapon. A valid assigned ranged item overrides that baseline; unequipping it resolves back to the Training Gear bow. Activation itself does not deal damage or spend focus. Selecting another mob retargets an active mode without restarting its current timer; clearing the target, losing the target, death, or encounter reset clears the mode. Using Auto Shot again stops it even while another cast is active or target geometry blocks firing.
|
||||
|
||||
The source row does not state a numeric range, facing, line-of-sight, control, casting, or movement restriction. The runtime uses a six-unit interaction limit as a local constraint and the existing hostile cast geometry checks, which require facing and line of sight. Control that prevents actions and an active cast pause scheduled shots. A blocked shot does not charge Blood Arrow or advance its deadline. Auto Shot continues while moving because the source gives no movement restriction and the player runtime has no separate movement lock for this instant toggle.
|
||||
|
||||
For source-supported RoM training gear, damage and base cadence come from `nativeTrainingAutoAttackProfile` for the resolved ranged slot. The per-shot base is 80% of native ranged DPS (`source damage / source interval`), and cadence uses the native ranged interval followed by the represented `haste`, `ranged-haste`, and `attack-speed` modifiers and the current race-affix timing. If native training gear is unsupported or the resolved item is custom, the runtime falls back to that resolved item’s shared ranged DPS and speed. It never takes compatibility damage values as the native source profile.
|
||||
|
||||
Each committed shot is an ordinary ranged Physical combat event with ability ID `rom-scout-primary-57`. Active melee and off-hand Auto Attack timers are cleared and suppressed while Auto Shot is active; firing does not start parallel melee swings. Each committed attempt costs the verified Scout/Rogue Blood Arrow owner 2% of maximum health while the aura is active, with no additional mana. The cost is charged once before the damage roll and mirrored to player actor health when present; it is not contingent on landing a hit. The shot is skipped when paying would reduce the player to zero or less, and idle or blocked intervals cost nothing. No separate self-damage event is emitted for this cost.
|
||||
|
||||
The source’s ammunition use is not consumed by this runtime because there is no player ammunition inventory system. The unknown last-offensive-skill bonus is intentionally omitted rather than assigned an invented value.
|
||||
|
||||
## Verification
|
||||
|
||||
`src/game/romScoutAutoShot.integration.test.ts` covers source identity and learnability, automatic Training Gear with empty inventory, custom-item precedence and fallback after unequip, owner gating, native source damage and cadence distinct from compatibility budget, WoW compatibility fallback, custom native fallback with semantic haste, repeated scheduled shots, no activation hit or parallel melee/off-hand event, Blood Arrow cost and lethal-affordability skip, range/line-of-sight/facing/control/cast blocking without idle cost, unrestricted movement, target switching and clearing, reset, and same-tick death cleanup. The recurring test also verifies a stopped window without shots or HP drain, then reactivation with a fresh full-interval deadline and no immediate/catch-up hit. All thirteen checks pass.
|
||||
@@ -1,6 +1,6 @@
|
||||
# RoM Vow of Silence live Boss Testing evidence — 2026-10-04
|
||||
|
||||
> **Future QA default (2026-10-04):** Use Stormwind Stockade for new routine live tests. The Wailing captures and commands in this dated report are historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
> **Current QA policy (2026-10-05):** Routine live tests use Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`); record the boss selected from the run ID. Full-source Stockade campaigns require explicit route selection. The Wailing captures and commands in this dated report remain historical; follow [the current test policy](TEST_DUNGEON_POLICY.md) and root `AGENTS.md`. A new Wailing reproduction needs an explicit owner request.
|
||||
|
||||
## Corrected final-build replay
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
# Ascension stance and Targorr Thrash source audit — 2026-10-06
|
||||
|
||||
This follow-up checks only the unsupported Ascension Defensive Stance Passive
|
||||
7376 DUMMY amount and whether the exact pinned Targorr source supplies a Thrash
|
||||
cast cadence. It does not change runtime behavior.
|
||||
|
||||
## Source pins
|
||||
|
||||
The active world SQL snapshot is AzerothCore commit
|
||||
`4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`. The four input files used here
|
||||
match both `source.lock.json` in the active pipeline workspace and
|
||||
`src/game/generated/azerothCoreSourceLock.json` by SHA-256 and row count:
|
||||
|
||||
| Active table | Rows | SHA-256 |
|
||||
| --- | ---: | --- |
|
||||
| `creature_template` | 29,947 | `0066e4fd35b809986dd325487515087f5a95f4ffe50ea03846c8d8bf5196870a` |
|
||||
| `creature_template_spell` | 9,556 | `faf36f9ad1936470b545383e68db44d58b11fd51191f2fed3237971b12d8e86d` |
|
||||
| `smart_scripts` | 52,768 | `622b5865f171b0b7a4dd93ecba55afd673c393c579485c17f827b31cb6e47dd2` |
|
||||
| `creature` | 149,879 | `f54ddfe7ee00080b4b0bc970a809d6f947f6fb2627dbcd67e92b402fb34cb701` |
|
||||
|
||||
The Ascension client source is the pinned `patch-D` `Spell.dbc`, SHA-256
|
||||
`2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`. The
|
||||
read-only historical core checkout is at `e822d718322289dd036fb2daf8867ba41283bf9a`.
|
||||
That core commit is a behavior reference; it is not the world SQL commit.
|
||||
|
||||
## Ascension DUMMY +42
|
||||
|
||||
The client row for spell 7376 has three self-targeted Apply Aura effects. The
|
||||
third uses aura type 4 (`DUMMY`), raw `BasePoints=41`, and `DieSides=1`. The
|
||||
pinned core's `SpellEffectInfo::CalcValue` turns the one-sided die into +1, so
|
||||
the applied amount is exactly +42. Its trigger spell is zero.
|
||||
|
||||
The core's shapeshift handler links Defensive Stance form to passive 7376 at
|
||||
`SpellAuraEffects.cpp:1378-1379`. That establishes why the passive is present,
|
||||
but it does not assign meaning to the DUMMY amount. The pinned
|
||||
`AuraEffect::HandleAuraDummy` has no `case 7376`; the base
|
||||
`spell_script_names.sql` has no 7376 registration. `SpellInfoCorrections.cpp`
|
||||
includes 7376 in the warrior-stance group at line 4745, then only adds
|
||||
`SPELL_ATTR3_SUPPRESS_CASTER_PROCS` at line 4748. None of these is a +42
|
||||
stat/effect consumer.
|
||||
|
||||
Keep the DUMMY effect as source metadata and leave its behavior gated. Do not
|
||||
apply +42 to a stat or invent another mechanic without the custom-server
|
||||
consumer that defines it.
|
||||
|
||||
Private Ascension server patches or data overlays were not available in this
|
||||
source set, so any private override of the DUMMY row remains unknown.
|
||||
|
||||
## Targorr Thrash timing
|
||||
|
||||
The pinned `creature_template.sql:1485` row names entry 1696 as Targorr the
|
||||
Dread and sets `AIName='SmartAI'`. The spell-list rows at
|
||||
`creature_template_spell.sql:618-619` list 8599 in slot 0 and 3391 in slot 1.
|
||||
They establish spell availability in the template list, not when 3391 is cast.
|
||||
|
||||
Targorr has exactly three active SmartAI rows at `smart_scripts.sql:5784-5786`:
|
||||
|
||||
- Row 5784 casts 674 on raw event type 0 with a 1,000 ms initial update; the
|
||||
SQL comment calls this out-of-combat, while the pinned SmartScript enum maps
|
||||
event 0 to update-in-combat.
|
||||
- Row 5785 casts 8599 for the 0–30% health event and links to row 5786.
|
||||
- Row 5786 is the linked talk action. No Targorr SmartAI row casts 3391.
|
||||
|
||||
In the pinned core, `SmartAI::UpdateAI` calls the SmartScript update and then
|
||||
melee at `SmartAI.cpp:562`; it has no generic creature-template spell
|
||||
scheduler. `CombatAI` is a separate AI path: it loads template spells and
|
||||
schedules them through its event map in `CombatAI.cpp:50-100`. Targorr's
|
||||
explicit `AIName='SmartAI'` does not establish the CombatAI path or its
|
||||
cooldown behavior. No exact Targorr source row supplies a Thrash cadence.
|
||||
|
||||
Preserve the existing simulator timing policy. Spell 3391's separately
|
||||
verified effect remains two queued main-hand attacks when cast; that effect
|
||||
contract does not prove a cast time or repeat interval for Targorr. Do not
|
||||
borrow another creature's 3391 schedule or apply generic CombatAI timing.
|
||||
Any private Targorr script or override not present in the pinned world snapshot
|
||||
also remains unknown.
|
||||
|
||||
## Reproduction
|
||||
|
||||
Run `node artifacts/enemy-utility-control-2026-10-06/audit-stance-thrash-source.mjs`
|
||||
to recheck the pinned world hashes and row counts, extract the Targorr rows,
|
||||
and inspect the Ascension DBC effect. It writes
|
||||
[`audit-stance-thrash-source.json`](../artifacts/enemy-utility-control-2026-10-06/audit-stance-thrash-source.json).
|
||||
The script and JSON are audit artifacts only; no runtime or generated content
|
||||
was changed and no build, test suite, or live run was performed.
|
||||
@@ -0,0 +1,28 @@
|
||||
# Stockade Chain Lightning fan-out — 2026-10-05
|
||||
|
||||
## Verified source contract
|
||||
|
||||
The Stockade attack is Hamhock (creature entry 1717), SmartAI row 0, spell 421. The imported row in `src/game/generated/azerothCoreWorldAi.json` casts spell 421 on `target_type=2` (`SMART_TARGET_VICTIM`); the campaign import preserves it as `target: "primary"`, range 30, nature school, and its existing 1.35 attack damage multiplier. Its cast timing remains the imported 1-second initial delay and 4–7-second repeat interval. No source row targets the whole party as the initial hit.
|
||||
|
||||
Both pinned Spell.dbc profiles were read directly and match their recorded SHA-256 values:
|
||||
|
||||
| Profile | SHA-256 | Spell 421 effect 0 | Total targets | Chain damage multiplier |
|
||||
| --- | --- | --- | ---: | ---: |
|
||||
| Ascension patch-D | `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce` | `SCHOOL_DAMAGE` (effect 2), `TARGET_UNIT_TARGET_ENEMY` (target A 6), range index 4, nature school mask 8, magic damage class 1 | `EffectChainTarget[0]` (field 104) = 3 | `EffectDamageMultiplier[0]` (field 216) = 0.6 |
|
||||
| Epoch pinned client | `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3` | Same target, range index, school, and damage class; source base points differ | `EffectChainTarget[0]` (field 104) = 3 | `EffectDamageMultiplier[0]` (field 216) = 0.7 |
|
||||
|
||||
Field 216 is named `EffectDamageMultiplier` in the matching AzerothCore `DBCStructure.h` and is exposed as `SpellEffectInfo::DamageMultiplier`; the comment identifies the DBC field as `m_effectChainAmplitude`. AzerothCore's spell resolver applies the factor after each successive chain hit. The resulting damage factors are `1.0, 0.6, 0.36` for Ascension and `1.0, 0.7, 0.49` for Epoch. The currently imported Stockade record uses the Ascension profile. `EffectChainTarget=3` means three total hits, including the explicit primary target: core requests two additional chain targets.
|
||||
|
||||
The source range index is 4; the existing compiler pin resolves it to 30 yards. Spell.dbc stores the range index, while this task's chain jump distance comes from the matching core behavior. `Spell.cpp::SearchChainTargets` uses a 10-yard jump radius for magic spells. It searches a candidate pool centered on the primary with radius `jumpRange × total target count` (30 yards here), then selects the nearest eligible target within 10 yards of the previous hit at each hop. The chain starts from the primary target because neither pinned profile has `SPELL_ATTR2_CHAIN_FROM_CASTER` (0x1000). It removes the primary from the candidate pool and removes every chosen candidate, so a target cannot be hit twice. Each bounce must have line of sight from the previous hit. In AzerothCore, the ordinary hostile-target cast path validates the primary's cast range and line of sight before chain selection; HealerMan integration must preserve that primary-target contract. A dead primary at resolution ends the attack instead of choosing a replacement.
|
||||
|
||||
These runtime rules were checked against the read-only matching core source at `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/game/Spells/Spell.cpp` (`SelectImplicitChainTargets`, `SearchChainTargets`, and damage multiplier application), `SpellInfo.cpp` (`ChainTarget` and damage multiplier mapping), and `src/server/shared/DataStores/DBCStructure.h` (field names). The imported database snapshot is pinned to commit `4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3` by `azerothCoreWorldAi.json`.
|
||||
|
||||
## Helper and runtime integration
|
||||
|
||||
`src/game/enemyChainTargeting.ts` provides pure ordered target selection. It accepts a primary target, current living candidates with positions, target count, jump range, per-bounce damage multiplier, and a line-of-sight function. It returns the primary first and each reachable hop with its cumulative damage factor. The focused tests cover nearest-hop traversal, both source decay profiles, living filtering, LOS filtering, no repeats, search-pool range, and the primary-target contract.
|
||||
|
||||
For the compiler/runtime integration, keep these sourced values together on the imported attack as `chain: { targetCount, jumpRange, damageMultiplier }`. Parse `EffectChainTarget[0]` from field 104 and `EffectDamageMultiplier[0]` from field 216 (using the parser's localized-field shift helper when applicable); pin only spell 421's chain signature so unrelated source signatures do not change. Emit target count 3 and jump range 10 for the verified Ascension and Epoch signatures, with profile-specific multipliers 0.6 and 0.7. Keep the existing primary-target attack, 30-yard cast range, cooldowns, and attack scalar.
|
||||
|
||||
At resolution, validate the cast's primary target through the existing hostile-target range/LOS path, then pass that target and current living registered party actors to `selectEnemyChainTargets`. For each returned hit, multiply the existing attack damage by that hit's `damageMultiplier` and resolve the hit through the existing per-target damage, mitigation, resistance, and event path. This keeps each hit in normal combat accounting while the primary receives factor 1 and subsequent hits receive the source decay. Keep chain metadata absent on attacks without a verified chain signature. This subtask does not change the shared compiler, attack schema, combat runtime, generated catalogs, loot, ammo, level cap, or readiness policy; the integrating worker owns those reserved files.
|
||||
|
||||
The parent integration is complete in the shared compiler, attack schema and combat runtime. The three helper checks and five runtime cases pass, including actor-local player/NPC defenses in both stat modes, hop LOS/range, the original cast victim after a threat change and a secondary target outside the caster's home leash. Primary aggro eligibility remains unchanged. Final build and full Stormwind Stockade evidence are recorded in `STOCKADE_ENEMY_MECHANICS_2026-10-05.md` and its linked playtest report.
|
||||
@@ -0,0 +1,196 @@
|
||||
# Stockade enemy buff and debuff audit — 2026-10-05
|
||||
|
||||
Later continuation: NPC stance and ordinary-creature blocking omissions in this
|
||||
original investigation are superseded by
|
||||
[the stance/blocking implementation](ENEMY_STANCES_BLOCKING_2026-10-05.md).
|
||||
The dated investigation below remains source history.
|
||||
|
||||
This pass records source-backed aura behavior for Enrage 8599, Defensive Stance
|
||||
7164, Battle Stance 7165, Demoralizing Shout 16244 and 13730, Battle Shout
|
||||
9128, and Improved Blocking 3419. The purpose is to keep these effects from
|
||||
becoming direct damage and to expose only the modifiers the current ActiveAura
|
||||
runtime can apply without inventing baselines. The profile-specific contracts
|
||||
and the supported ActiveAura subset are in
|
||||
[`src/game/enemySourceAuras.ts`](../src/game/enemySourceAuras.ts).
|
||||
|
||||
## Source pins and interpretation
|
||||
|
||||
Ascension uses the recipe compiler's pinned 3.3.5a patch-D source:
|
||||
|
||||
`../LadiksMPQEditor/client-current/area-52/patch-D/DBFilesClient/Spell.dbc`
|
||||
|
||||
SHA-256: `2f77f18b91ffbae32a19568e4bc05ec78ee384b6ba8dd2a6e05f0e97abbb2dce`.
|
||||
|
||||
Epoch uses the compiler's pinned
|
||||
`../HealerMan-Storage/pipeline-work/dungeons/epoch-client/DBFilesClient/Spell.dbc`
|
||||
(SHA-256 `d5cce1a83550dcfa9eb2f0251dbb11fd24c272534b2b1a9b230924a44d817ab3`).
|
||||
Neither client directory has `SpellDuration.dbc` or `SpellRadius.dbc`, so both
|
||||
duration and radius lookups use the shared patch-S fallbacks in the
|
||||
compiler: `SpellDuration.dbc` SHA-256
|
||||
`eeae44ef0185924f3d6ec57ab2701c66566db86e51ab0bae017a9449126eb3a0`, and
|
||||
`SpellRadius.dbc` SHA-256
|
||||
`dba6ed2f165f75c84dda5f32ae46b1a01fe562efd88fa51fd19365705c3e6a44`. These
|
||||
are compiler support inputs, not claims that Epoch shipped those support
|
||||
tables.
|
||||
|
||||
The six already pinned signatures (7164, 7165, 16244, 13730, 9128, and 3419)
|
||||
match the compiler's profile-specific `PINNED_SOURCE_SPELLS` entries in
|
||||
`scripts/dungeon-pipeline/compile-campaign-catalog.mjs`. Enrage 8599 was read
|
||||
directly from both pinned DBCs because it did not have an entry in that pin map.
|
||||
In the table below, every spell has range index 1 and school mask 1; the damage
|
||||
class and effect rows are shown where the profiles or target type matter.
|
||||
Effect rows use `effect/aura/base/A/B/radius/misc`, with the DBC's base-points
|
||||
value (`raw base points + 1`). The inspected `EffectTriggerSpell` fields are
|
||||
zero for every row.
|
||||
|
||||
| Spell | Ascension patch-D signature; duration | Epoch DBC signature; duration |
|
||||
| --- | --- | --- |
|
||||
| 8599 Enrage | damage class 0; `6/79/+30/1/0/0/1`, `6/138/+30/1/0/0/0`; 120,000 ms | damage class 0; `6/79/+10/1/0/0/1`, `6/138/+30/1/0/0/0`; 120,000 ms |
|
||||
| 7164 Defensive Stance | damage class 0; `6/36/0/1/0/0/18`; 180,000 ms | same; 180,000 ms |
|
||||
| 7165 Battle Stance | damage class 2; `6/36/0/1/0/0/17`; permanent (`-1`) | same; permanent (`-1`) |
|
||||
| 16244 Demoralizing Shout | damage class 1; `6/79/-10/22/15/10/1`; 15,000 ms | damage class 1; `6/99/-20/22/15/10/0`; 30,000 ms |
|
||||
| 13730 Demoralizing Shout | damage class 1; `6/166/-15/22/15/10/0`; 30,000 ms | damage class 1; `6/99/-10/22/15/10/0`; 30,000 ms |
|
||||
| 9128 Battle Shout | damage class 1; `6/79/+15/20/0/20/1`; 120,000 ms | damage class 1; `6/99/+4/20/0/20/0`; 120,000 ms |
|
||||
| 3419 Improved Blocking | damage class 0; `6/51/+75/1/0/0/0`; 6,000 ms | same; 6,000 ms |
|
||||
|
||||
The numeric target IDs are confirmed against the historical AzerothCore target
|
||||
table in `src/server/game/Spells/SpellInfo.cpp`: 1 is caster, 15 is source-area
|
||||
enemy, 20 is caster-area party, and 22 is caster source. Therefore 16244 and
|
||||
13730 are centered on the caster and select enemies within radius 10; 9128
|
||||
selects the caster's party within radius 20; 8599, 7164, 7165, and 3419 target
|
||||
the caster. The applicable profile radius is sourced from its DBC or the
|
||||
compiler's pinned Epoch fallback.
|
||||
|
||||
The DBC `Dispel` field is 9 (Enrage) for 8599 and 0 (no dispel category) for the
|
||||
other six spells. The DBC `stackAmount` field is 0 for all seven, so no
|
||||
multi-stack count is imported. That field does not describe cross-spell
|
||||
exclusivity. In historical AzerothCore, `Aura::CanStackWith` rejects another
|
||||
copy in the same spell-rank chain, including a copy from a different caster.
|
||||
For an already-affected area-aura recipient, a second caster's non-stackable
|
||||
application is skipped and does not refresh the first aura; a caster applying
|
||||
to itself removes its prior non-stackable copy before adding the new one. The
|
||||
runtime uses that same-spell-only rule: repeated casts by the same source
|
||||
refresh, another caster cannot refresh an existing recipient, and an owner may
|
||||
replace its own application. It adds no exclusivity across 16244 and 13730 just
|
||||
because both are named Demoralizing Shout. AzerothCore's shapeshift aura handler
|
||||
removes an existing shapeshift aura when a new shapeshift applies, so stance
|
||||
form exclusivity is verified; the stance mechanics themselves remain outside
|
||||
the current supported subset.
|
||||
|
||||
No child spell IDs appear in these effect rows. The historical AzerothCore
|
||||
`spell_linked_spell.sql`, `spell_proc.sql`, and `spell_script_names.sql` base
|
||||
tables also have no rows keyed by these seven IDs. Enrage's second DBC effect
|
||||
is melee haste, not a triggered spell.
|
||||
|
||||
## Exact behavior and runtime boundary
|
||||
|
||||
Aura types map through AzerothCore's `SpellAuraDefines.h`: 36 is shapeshift,
|
||||
51 block chance, 79 damage percent done, 99 flat attack power, 138 melee haste,
|
||||
and 166 attack-power percent. Its damage calculation filters aura 79 using
|
||||
the aura's school mask; the three aura-79 effects here have `miscValue=1`, so
|
||||
they affect physical damage. The descriptor helper maps this mask only when it
|
||||
is exactly 1 and returns unsupported for other masks; it does not treat every
|
||||
damage-percent aura as physical. AzerothCore resolves aura-99 and aura-166 in
|
||||
attack-power recalculation, while aura-51 contributes to block chance. Its
|
||||
shapeshift handler owns form replacement.
|
||||
|
||||
The source-backed modifiers that fit existing ActiveAura stat and damage
|
||||
modifiers are:
|
||||
|
||||
| Spell/profile | Recipient and duration | Modifier |
|
||||
| --- | --- | --- |
|
||||
| 8599, Ascension | caster, 120 s, Enrage dispel | +30% physical damage dealt; +30 melee-haste percentage points |
|
||||
| 8599, Epoch | caster, 120 s, Enrage dispel | +10% physical damage dealt; +30 melee-haste percentage points |
|
||||
| 16244, Ascension | caster-area enemies, 10 yd, 15 s | -10% physical damage dealt |
|
||||
| 16244, Epoch | caster-area enemies, 10 yd, 30 s | -20 flat attack power |
|
||||
| 13730, Ascension | caster-area enemies, 10 yd, 30 s | -15% attack power |
|
||||
| 13730, Epoch | caster-area enemies, 10 yd, 30 s | -10 flat attack power |
|
||||
| 9128, Ascension | caster-area party, 20 yd, 120 s | +15% physical damage dealt |
|
||||
| 9128, Epoch | caster-area party, 20 yd, 120 s | +4 flat attack power |
|
||||
|
||||
Enrage's melee-haste modifier is in the contract so the combat owner can apply
|
||||
it to the source's basic-attack cadence. Spell casts and other ability
|
||||
cooldowns must remain unchanged. For Battle Shout, the supported area must
|
||||
include the caster and nearby friendly NPCs from the caster's party; applying
|
||||
it only to the caster would be an incomplete representation. Debuffs from
|
||||
16244 and 13730 apply to each eligible party actor inside the sourced enemy
|
||||
area. Effects attach to the resulting aura targets, so `damage dealt` modifiers
|
||||
reduce the debuffed actor's outgoing physical damage and stat modifiers adjust
|
||||
that actor's attack power.
|
||||
|
||||
The following are deliberately not materialized as ActiveAura modifiers yet:
|
||||
|
||||
- 7164 and 7165 select form 18 and 17. They have no direct damage effect or
|
||||
child spell; their stance-specific consequences are not encoded by the
|
||||
current modifier runtime.
|
||||
- 3419 supplies +75 block percentage points, but `npcCombatDefender` currently
|
||||
sets NPC `blockPercent` and `blockValue` to zero and the source rows do not
|
||||
establish a target block value. Applying the chance alone could report blocks
|
||||
without reducing damage, so it is not enabled.
|
||||
- Enrage's aura 138 changes melee speed. The current enemy cooldown path does
|
||||
not apply haste; only the basic-auto cadence may use this modifier, as stated
|
||||
above.
|
||||
|
||||
The old generated Enrage 8599 effect in Stockade uses a 12,000 ms duration and
|
||||
`magnitude: 0.25`. Both conflict with the pinned profile rows: the duration is
|
||||
120,000 ms, and its physical damage modifier is +30% in Ascension or +10% in
|
||||
Epoch, alongside +30% melee haste. Integrations must take duration and
|
||||
modifiers from `enemySourceAuraContract(spellId, profile)`, not preserve those
|
||||
legacy approximations. The imported campaign now contains five source-tagged
|
||||
Stockade casts (8599 ×1, 16244 ×1, 13730 ×1, 9128 ×2) and one Epoch Enrage cast
|
||||
in the Nexus. The remaining verified non-damage rows are no longer represented
|
||||
as false direct-hit attacks.
|
||||
|
||||
## Runtime integration and stacking
|
||||
|
||||
The current integration routes the supported source modifiers through
|
||||
`ActiveAura`. Enrage adjusts only the basic auto-attack cadence, scaling the
|
||||
remaining swing phase when it starts or expires; spell and other ability
|
||||
cooldowns keep their scheduled times. The Ascension and Epoch profiles stay
|
||||
distinct in their damage modifiers. Battle Shout's area includes its caster
|
||||
and eligible friendly mobs within 20 yards and line of sight; Demoralizing
|
||||
Shout's enemy area includes only eligible player/party actors within 10 yards
|
||||
and line of sight. Auras attach to each recipient, so source damage and attack
|
||||
power modifiers apply through the recipient's shared actor stats. These
|
||||
source-tagged area spells do not create a direct damage packet.
|
||||
|
||||
Historical AzerothCore's `Unit::GetTotalAuraMultiplier` starts at 1 and applies
|
||||
each aura 79 percentage with `AddPct`, multiplying distinct effects. For
|
||||
example, Enrage +30% and Battle Shout +15% resolve as `1.30 × 1.15 = 1.495`
|
||||
(100 physical damage becomes 149.5 before later rounding), not as a single
|
||||
additive +45% bonus. Source-backed percentage modifiers opt into this
|
||||
multiplicative behavior; ordinary ActiveAura percentages retain their existing
|
||||
summed behavior. Aura 79 is also filtered by the source school mask, which is
|
||||
physical-only for these imported rows.
|
||||
|
||||
The focused runtime and contract checks passed: `npx vitest run
|
||||
src/game/enemySourceAuras.integration.test.ts src/game/enemySourceAuras.test.ts`
|
||||
(10 tests after the parent added the home-leash boundary regression). The integration cases verify both Enrage profiles, basic-auto phase
|
||||
preservation on haste application and expiry, untouched spell cooldowns,
|
||||
navigation reset and clean re-engagement, physical-only damage, the two target
|
||||
geometries, source-aura non-stacking across Battle Shout casters, and the
|
||||
Ascension attack-power reduction on the shared player stat resolver. No full
|
||||
suite, build, or live-combat run was part of this audit.
|
||||
|
||||
## Historical AzerothCore behavior consulted
|
||||
|
||||
The read-only historical reference is
|
||||
`../wow-pvt-server-backups-2/azerothcore-wotlk`:
|
||||
|
||||
- `src/server/game/Spells/SpellInfo.cpp` defines implicit target reference,
|
||||
party/enemy check, and area-selection behavior for IDs 1, 15, 20, and 22.
|
||||
- `src/server/game/Spells/Auras/SpellAuraDefines.h` names the aura opcodes;
|
||||
`src/server/game/Entities/Unit/Unit.cpp` applies aura 79 to damage and aura
|
||||
51 to block chance; `src/server/game/Entities/Unit/StatSystem.cpp` recalculates
|
||||
attack power and block chance.
|
||||
- `src/server/game/Spells/Auras/SpellAuraEffects.cpp` applies aura 36 and
|
||||
removes the old shapeshift form when another form is added.
|
||||
- The SQL lookup found no linked-spell, proc, or script-name rows for these
|
||||
IDs. The imported Stockade Enrage row is Targorr the Dread (entry 1696). Its
|
||||
former generated `durationMs: 12000` and `magnitude: 0.25` values were
|
||||
replaced by the source contract and supported modifiers above.
|
||||
|
||||
No creature baseline, AP value, block value, or unknown stance modifier was
|
||||
filled from a guess. The imported supported subset is routed through
|
||||
`ActiveAura`; stance and blocking effects remain absent until their required
|
||||
runtime behavior and baselines are available.
|
||||
@@ -0,0 +1,154 @@
|
||||
# Stockade enemy mechanics and Chronomancer — 2026-10-05
|
||||
|
||||
The later [stance/blocking continuation](ENEMY_STANCES_BLOCKING_2026-10-05.md)
|
||||
supersedes this batch's remaining NPC stance and ordinary auto-block omissions.
|
||||
|
||||
The approved batch implements source-backed Chain Lightning jumps, Rend pulses,
|
||||
Enrage and supported shouts, and the existing Chronomancer mana mismatch.
|
||||
Independent workers use GPT-6 Luna with extra-high reasoning. The level cap,
|
||||
loot wiring and readiness policy remain unchanged. Full Stormwind Stockade is
|
||||
the explicit full-source fixture in this report; routine live QA now defaults to
|
||||
Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`). Record its
|
||||
run-selected boss. Future full-campaign wrapper runs require `--full-stockade`.
|
||||
|
||||
## Behavior and ownership
|
||||
|
||||
`enemyChainTargeting.ts` selects the explicit Chain Lightning victim followed
|
||||
by up to two nearest visible living targets within 10 m of the previous hit.
|
||||
No recipient repeats. Secondary selection uses spell geometry independently
|
||||
of the caster's home leash; primary aggro eligibility remains unchanged.
|
||||
Ascension uses damage factors 1/0.6/0.36; Epoch uses
|
||||
1/0.7/0.49. Threat changes during a cast preserve its explicit victim. The
|
||||
first packet retains the established enemy amount policy; this change does
|
||||
not claim that its baseline amount is an exact DBC damage calculation.
|
||||
|
||||
`enemyPeriodicDamage.ts` owns profile-specific Rend 6547/16509 source data.
|
||||
The compiler serializes source identity; `combatStore.ts` resolves the verified
|
||||
amount and five three-second bleed pulses through actor-local defenses.
|
||||
Application uses the shared hit gate. There is no immediate packet. Ordinary
|
||||
same-caster recasts replace the schedule with a fresh full three-second delay;
|
||||
different casters remain independent. Bleeds bypass armor and have no magic
|
||||
dispel category. Caster damage-done modifiers snapshot at application while
|
||||
target damage-taken modifiers remain dynamic. The 16509 level ratio uses strict pinned creature BaseDamage
|
||||
rows, excluding template attack scaling/AP/swing time; missing required inputs
|
||||
fail closed. Outer enemy damage scaling remains a separate game layer.
|
||||
|
||||
`enemySourceAuras.ts` owns the exact source profiles for Enrage, stances,
|
||||
shouts and blocking. Supported Enrage lasts 120 seconds, boosts physical damage
|
||||
by 30% Ascension / 10% Epoch and speeds melee autos by 30%; the scheduler
|
||||
rescales remaining swing time on gain/removal and leaves ability cooldowns
|
||||
unchanged. Demoralizing Shout affects living visible hostile actors within
|
||||
10 m; Battle Shout affects the caster and living visible enemy allies within
|
||||
20 m. Physical damage and flat/percent AP remain distinct. Reviewed percentage
|
||||
modifiers opt into multiplication in `combatAuras.ts`; other existing modifiers
|
||||
retain their sum. Same-spell nonperiodic source copies cannot stack across
|
||||
casters. Another area caster preserves an existing recipient's aura/timer;
|
||||
self-owned replacement and same-caster refresh remain explicit.
|
||||
|
||||
`classPassiveResourceModifiers.ts` adds structured permanent automatic-passive
|
||||
resource percentages and removes matching parsed duplicates. Aura 132's
|
||||
MiscValue identifies Mana/Rage/Energy/Focus/Runic Power independently from the
|
||||
class primary resource. Chrono Sorcery's +12% Mana gives the expected 414 at
|
||||
level 1. Timed, other-recipient or hit/crit-gated riders remain excluded.
|
||||
|
||||
`compile-campaign-catalog.mjs` pins source signatures before enabling these
|
||||
effects. Regeneration changes 37 spell rows across 34 creature definitions,
|
||||
all restricted to the seven approved spell IDs, and adds three corresponding
|
||||
SmartAI mechanic links. Structural comparison against the working baseline
|
||||
confirms no health pools, placements, unrelated attack rows or other dungeon
|
||||
fields changed. The report is in the ignored task artifact directory.
|
||||
|
||||
## Source limits
|
||||
|
||||
Both client profiles use the established patch-S duration/radius support-table
|
||||
fallback; neither is described as an untouched client-table set. This report
|
||||
records the earlier Chain/Rend/buff pass. The later
|
||||
[stance and blocking pass](ENEMY_STANCES_BLOCKING_2026-10-05.md) implements the
|
||||
verified forms and ordinary creature block baseline. The
|
||||
[weapon utility continuation](ENEMY_WEAPON_UTILITIES_2026-10-05.md) owns
|
||||
Bloodlust, Disarm, Infected Wound, explicit Dual Wield and queued Thrash.
|
||||
Ascension stance DUMMY behavior, unbound automatic offhand equipment and
|
||||
separate-target triggered shouts still require source support. Unsupported
|
||||
effects remain omitted instead of producing damage.
|
||||
|
||||
See the individual [Chain](STOCKADE_CHAIN_LIGHTNING_2026-10-05.md),
|
||||
[Rend](STOCKADE_REND_2026-10-05.md), [buff](STOCKADE_ENEMY_BUFFS_2026-10-05.md)
|
||||
and [Chronomancer](CHRONOMANCER_RESOURCE_BASELINE_2026-10-05.md) reports.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused enemy and resource checks plus Ready-five pass. The final production
|
||||
build passes its prebuild, TypeScript, Vite and postbuild checks. Its frozen copy
|
||||
contains 5,964 files with aggregate SHA-256
|
||||
`296f26c1a58d096b925977f8a0f4aebc5a2de20ba4ce804592188a87102f99e0`.
|
||||
Loaded-build entry is `index-D-xYtSuF.js`; enemy combat is
|
||||
`combatStore-BmIrp-s1.js`. The immutable copy is
|
||||
`artifacts/stockade-enemy-mechanics-2026-10-05/frozen-dist-20261005-153220`.
|
||||
The 15-file affected selection passes 135 checks; the exact resource and
|
||||
Vindication cases pass two more. Ready-five passes seven Vitest and twenty
|
||||
Python checks: 144 distinct required Vitest checks plus twenty Python checks.
|
||||
|
||||
| Focused files under `src/game/` | Checks |
|
||||
| --- | ---: |
|
||||
| `enemyChainTargeting.test.ts`, `stockadeEnemyMechanics.integration.test.ts` | 8 |
|
||||
| `enemyPeriodicDamage.test.ts`, `enemyPeriodicDamage.integration.test.ts` | 23 |
|
||||
| `enemySourceAuras.test.ts`, `enemySourceAuras.integration.test.ts` | 10 |
|
||||
| `classPassiveResourceModifiers.test.ts` | 9 |
|
||||
| `combatAuras.test.ts` | 10 |
|
||||
| `dungeonCampaignCatalog.test.ts` | 33 |
|
||||
| `enemyCasting.test.ts` | 15 |
|
||||
| `enemyDamageTypes.integration.test.ts` | 3 |
|
||||
| `bossGuide.test.ts` | 3 |
|
||||
| `romScoutAutoShot.integration.test.ts`, `romNativeAutoAttack.integration.test.ts`, `romGroupHealRadius.integration.test.ts` | 21 |
|
||||
|
||||
The two selected `combatStore.test.ts` cases are "starts with attribute-derived
|
||||
pools including racial and automatic class passives" and "procs Vindication
|
||||
from a Paladin Holy hit with the generated rank chance, amount, duration, and
|
||||
owner"; the other 109 cases were skipped. No full suite or expanded balance
|
||||
sweep was run. A final standalone 8 GiB TypeScript check also passes after the
|
||||
test-file additions.
|
||||
|
||||
Final release hygiene passes for 162 changed paths including untracked files.
|
||||
Game and vault Git diff checks pass and their working trees are reviewed
|
||||
separately. All eleven recorded production/compiler/catalog fingerprints still
|
||||
match the inputs tested in the final frozen build.
|
||||
|
||||
The final normal Stockade run `20261005-160913676` verifies all five native
|
||||
boss IDs and the visible full-clear results screen in 21:32.5. The native RoM
|
||||
Priest/Knight player and four active-class NPCs finish alive; the tank has three
|
||||
observed casualty/recovery sequences through the normal resurrection UI, and
|
||||
the player has no observed death. This Easy/Normal diagnostic is not balance
|
||||
certification. Route inputs stop at checkpoint 462/481 when the native results
|
||||
overlay opens; remaining movement is unnecessary after the verified clear.
|
||||
|
||||
Hamhock has four unique sampled Chain Lightning cast windows. One raw Nature
|
||||
damage group hits three distinct recipients with amounts 579/347/208, matching
|
||||
the imported Ascension decay after rounding. The event stream includes 359
|
||||
Rend damage events across both source IDs. Authoritative combat-aura samples
|
||||
show Targorr's 120-second Enrage and Battle Shout applications to hostile
|
||||
allies. Demoralizing Shout has 44 unique sampled cast windows across spells
|
||||
13730/16244; recipient aura effects remain unconfirmed live and use focused
|
||||
integration proof. The run does not prove every supported profile,
|
||||
refresh/snapshot boundary or aura expiry.
|
||||
|
||||
Before/after fingerprints match the final frozen distribution and read-only
|
||||
content manifest. All 2,124 served content objects match their hash addresses.
|
||||
There are no page errors; the only console error is the optional favicon 404.
|
||||
Root visually reviews the equipped-entry, 50%, 75% and final-results captures:
|
||||
bodies, HUD and results render; actor overlap and partial occlusion persist.
|
||||
No visual fix is claimed.
|
||||
|
||||
Earlier attempts remain preserved: the first copy was superseded before entry
|
||||
for the leash correction; another had a harness content-source 404; one reached
|
||||
only Targorr before keyboard timing caused checkpoint overshoot; and another
|
||||
lost its route JSON to a harness serializer ReferenceError. The final wrapper
|
||||
corrects those harness issues without changing the frozen game build. Legacy
|
||||
`mob.auras` snapshots can be empty while the authoritative shared combat-aura
|
||||
telemetry contains source auras; coverage uses the latter as well.
|
||||
The [scoped playtest report](STOCKADE_ENEMY_MECHANICS_PLAYTEST_2026-10-05.md)
|
||||
owns screenshot, event-stream and build-fingerprint evidence. Earlier Stockade
|
||||
captures retain their original build identities.
|
||||
|
||||
Unrelated concurrent RoM environment/shadow work is preserved. Final live QA
|
||||
uses an immutable copied build to prevent another task's build from changing
|
||||
the assets being tested. No changes are staged or committed by this task.
|
||||
@@ -0,0 +1,160 @@
|
||||
# Stormwind Stockade enemy-mechanics playtest — 2026-10-05
|
||||
|
||||
**Outcome: verified full Stockade clear with live Chain Lightning, Rend, hostile
|
||||
buff, and Demoralizing Shout cast evidence.** The successful run used the
|
||||
normal dungeon UI and ordinary movement, targeting, attacks, party commands,
|
||||
and healing. It was a focused browser playtest, not a balance certification.
|
||||
|
||||
## Final run and immutable build
|
||||
|
||||
The successful run is preserved under
|
||||
[`playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/`](../playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/).
|
||||
It ran from `2026-10-05T16:09:15.713Z` to `2026-10-05T16:31:15.761Z` and
|
||||
completed with child exit code 0. The profile was created through the normal
|
||||
offline character UI as a Priest, then prepared in the isolated profile as a
|
||||
native-stat level-30 Priest/Knight before entering Stockade through the normal
|
||||
picker and healer-role flow. Four
|
||||
NPC companions filled the party. No enemy, damage, health, aura, cast, or combat
|
||||
store state was seeded; there was no teleport, collision bypass, boss-test
|
||||
entry, loot interaction, or readiness promotion.
|
||||
|
||||
The frozen distribution was
|
||||
`artifacts/stockade-enemy-mechanics-2026-10-05/frozen-dist-20261005-153220`
|
||||
with aggregate SHA-256
|
||||
`296f26c1a58d096b925977f8a0f4aebc5a2de20ba4ce804592188a87102f99e0` over
|
||||
5,964 files. The before and after manifests match that exact fingerprint. The
|
||||
read-only `content/` source manifest also stayed unchanged at SHA-256
|
||||
`d3d553aa7443bf444c87b0c0e923357df02756d0822db2e1a0a908d3f257fdb8`; all
|
||||
2,124 distinct requested hash-addressed objects returned HTTP 200 and their
|
||||
local bytes matched their object-address hashes. See
|
||||
[`run-record.json`](../playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/run-record.json),
|
||||
[`content-source-evidence.json`](../playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/content-source-evidence.json),
|
||||
and the before/after manifests in the same run folder.
|
||||
|
||||
The game loaded these production modules:
|
||||
|
||||
`index-D-xYtSuF.js`, `combatStore-BmIrp-s1.js`, `GameRuntime-DJd285mw.js`,
|
||||
`dungeonSession-Bzyqicra.js`, `PartyFrames-DU0sDQaZ.js`,
|
||||
`romAbilityCatalog-CBkQytej.js`, and `dungeonWorldInteraction-4rtL_sSb.js`.
|
||||
|
||||
The native result UI reported **FULL DUNGEON CLEAR**, `21:32.5` to final boss,
|
||||
and 5/5 defeated: Targorr the Dread (`creature-84027`), Kam Deepfury
|
||||
(`creature-79088`), Hamhock (`creature-79098`), Bazil Thredd (`creature-79124`),
|
||||
and Dextren Ward (`creature-79116`). The player finished at level 40 with all
|
||||
four level-39 NPCs alive. This was not a no-casualty run: Rorik had three
|
||||
casualty/recovery observations and the party issued three ordinary “Rez dead
|
||||
members” actions. The player death count was zero. The native result text and
|
||||
boss IDs are recorded in `run-record.json` and the campaign `results.json`.
|
||||
|
||||
## Enemy mechanics observed
|
||||
|
||||
The preserved read-only evidence contains 41,116 mob samples, 5,622 raw combat
|
||||
events, 761 source-attributed enemy damage events, and 175 combat-aura samples.
|
||||
The full raw evidence is in
|
||||
[`enemy-mechanics-evidence.json`](../playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/enemy-mechanics-evidence.json).
|
||||
|
||||
**Hamhock Chain Lightning, spell 421.** Four unique active-cast windows were
|
||||
captured on Hamhock, source `creature-79098`, each interruptible and 1,500 ms
|
||||
long. There are five cast samples because the first window was sampled twice.
|
||||
The event stream attributes ten damage events to Hamhock’s
|
||||
`smart-1717-0-chain-lightning` attack ID:
|
||||
|
||||
| Target | Hits | Raw damage | Effective damage | Event times (ms) |
|
||||
| --- | ---: | ---: | ---: | --- |
|
||||
| Mage `party-damage-3-rom-mage` | 1 | 579 | 512 | 1791217137627 |
|
||||
| Scout `party-damage-2-rom-scout` | 1 | 347 | 347 | 1791217137627 |
|
||||
| Player `__player__` | 1 | 208 | 208 | 1791217137627 |
|
||||
| Tank `party-tank-0-rom-knight` | 3 | 1,737 | 1,348 | 1791217143836–1791217170624 |
|
||||
| Rogue `party-damage-1-rom-rogue` | 3 | 1,041 | 1,041 | 1791217143836–1791217170624 |
|
||||
| Mage summon `party-damage-3-rom-mage:summon-4` | 1 | 208 | 208 | 1791217143836 |
|
||||
|
||||
Cast windows (`startedAt`–`completesAt`, ms): `1791217136023–1791217137523`,
|
||||
`1791217142234–1791217143734`, `1791217152437–1791217153937`, and
|
||||
`1791217169029–1791217170529`.
|
||||
|
||||
**Rend, spells 6547 and 16509.** The raw stream contains 359 source-attributed
|
||||
enemy damage events. Spell 6547 produced 153 pulses, 2,172 raw / 2,060
|
||||
effective damage, with individual raw hits of 14–16 from Defias Inmates. Spell
|
||||
16509 produced 206 pulses, 8,823 raw / 8,331 effective damage, with individual
|
||||
raw hits of 38–52 from Defias Prisoners, Captives, and Convicts. Spell 6547
|
||||
events targeted the tank (112), mage (24), scout (12), and rogue (5). Spell
|
||||
16509 events targeted the tank (196), mage (5), and scout (5). No Rend active
|
||||
cast state was sampled; the live raw damage events establish the pulses without
|
||||
depending on cast-state sampling.
|
||||
|
||||
**Enemy-source buffs.** The legacy `mob.auras` projection was empty, but the
|
||||
separate combat-aura stream records eight unique applications whose source and
|
||||
target are both sampled enemies. The initial run summary incorrectly equated
|
||||
the empty legacy projection with no enemy buffs; the evidence summary and
|
||||
status note have been corrected without changing the raw route file.
|
||||
|
||||
| Aura instance / spell | Source → target | Applied (ms) |
|
||||
| --- | --- | ---: |
|
||||
| `creature-84027:enemy-source-spell-8599:creature-84027` — Enrage | Targorr `creature-84027` → Targorr | 1791216791350 |
|
||||
| `creature-79040:enemy-source-spell-9128:creature-79040` — Battle Shout | Insurgent `creature-79040` → self | 1791217027326 |
|
||||
| `creature-79045:enemy-source-spell-9128:creature-79040` — Battle Shout | Insurgent `creature-79040` → Captive `creature-79045` | 1791217027326 |
|
||||
| `creature-79070:enemy-source-spell-9128:creature-79049` — Battle Shout | Insurgent `creature-79049` → Convict `creature-79070` | 1791216941320 |
|
||||
| `creature-79074:enemy-source-spell-9128:creature-79049` — Battle Shout | Insurgent `creature-79049` → Convict `creature-79074` | 1791216950039 |
|
||||
| `creature-79097:enemy-source-spell-9128:creature-79085` — Battle Shout | Insurgent `creature-79085` → Inmate `creature-79097` | 1791216972232 |
|
||||
| `creature-79100:enemy-source-spell-9128:creature-79085` — Battle Shout | Insurgent `creature-79085` → Inmate `creature-79100` | 1791216963628 |
|
||||
| `creature-79101:enemy-source-spell-9128:creature-79101` — Battle Shout | Insurgent `creature-79101` → self | 1791217182924 |
|
||||
|
||||
**Demoralizing Shout (“Demo”).** Live active-cast telemetry captured 44 unique
|
||||
cast windows: 20 for spell 13730 from six Defias Insurgent actor IDs, and 24
|
||||
for spell 16244 from nine Defias Convict actor IDs. The sampled casts were
|
||||
interruptible. This harness captured combat aura instances only when the
|
||||
target was an enemy, so it does not independently establish the party-side
|
||||
Demoralizing Shout effect. The cast state itself was observed live.
|
||||
|
||||
## Visual and runtime review
|
||||
|
||||
Screenshots are in
|
||||
[`campaign/final-build-20261005-160915922/`](../playtest-artifacts/stockade-enemy-mechanics/20261005-160913676/campaign/final-build-20261005-160915922/).
|
||||
The entry, equipped-player/native-party, route 25/50/75%, and boss-arrival
|
||||
screens show loaded native characters, full party frames, buffs, ability HUD,
|
||||
and the changing level HUD. Root also reviewed the 50% and 75% captures. Scene
|
||||
and HUD rendering appeared normal, while bodies and name labels overlapped or
|
||||
were partly occluded; this playtest did not attempt a visual fix. The
|
||||
`stormwind-stockade-boss-arrival.png` filename is historical: its pixels show
|
||||
the native “Stormwind Stockade complete” results overlay, `21:32.5`, all five
|
||||
named bosses defeated, and the level-40 player/four level-39 NPC party. The
|
||||
same result text is recorded in `results.json`.
|
||||
|
||||
There were no page errors. The only console error was a local `/favicon.ico`
|
||||
404. Three Rorik recoveries were recorded as described above. The ordinary
|
||||
native UI accepted the configured party and completed the full route.
|
||||
|
||||
## Preserved failed and superseded attempts
|
||||
|
||||
These attempts remain intact and are not counted as the final result:
|
||||
|
||||
1. `20261005-152510407` used the earlier authorized frozen copy, which was
|
||||
superseded after the owner found a Chain leash-edge bug. The owner stopped it
|
||||
during roster/picker setup before dungeon entry.
|
||||
2. `20261005-153314575` used the replacement hash but had an isolated content
|
||||
source setup error: `/content/manifest.json` returned 404, and role selection
|
||||
timed out before entry. The owner clarified that `contentDir` is read-only
|
||||
catalog/object input. The corrected run used the project content directory
|
||||
with the disposable profile/data directory kept separate.
|
||||
3. `20261005-154226103` reached checkpoint 88 after defeating only Targorr
|
||||
(1/5 bosses). Ordinary movement inputs overshot and reversed around the
|
||||
checkpoint tolerance; the route stopped there. The attempt is preserved as
|
||||
incomplete, not a full clear.
|
||||
4. `20261005-155657325` reached the dungeon route but failed while serializing
|
||||
evidence because the wrapper referenced `contentSourceResponses` outside
|
||||
its scope. Its `failure.json` retains the error and browser diagnostics; no
|
||||
campaign route JSON was written, so its endpoint and boss count are
|
||||
inconclusive.
|
||||
|
||||
The final successful retry used adaptive short movement inputs near route
|
||||
checkpoints while retaining the authored checkpoint sequence and tolerance.
|
||||
No further run or source/build change was needed.
|
||||
|
||||
## Harness checks
|
||||
|
||||
The scoped wrapper is
|
||||
[`scripts/playtest-stockade-enemy-mechanics.cjs`](../scripts/playtest-stockade-enemy-mechanics.cjs).
|
||||
`node --check scripts/playtest-stockade-enemy-mechanics.cjs` passed, and
|
||||
`node scripts/playtest-stockade-enemy-mechanics.cjs --prepare-only` validated
|
||||
the source and transformed harness syntax without launching a server or
|
||||
browser. No full suite or build was run by this playtest agent.
|
||||
@@ -1,10 +1,14 @@
|
||||
# Stockade mechanics continuation — 2026-10-04
|
||||
|
||||
The later [enemy mechanics follow-up](STOCKADE_ENEMY_MECHANICS_2026-10-05.md)
|
||||
implements supported Chain/Rend/shout effects and records the final 5/5 clear.
|
||||
The captures below retain their original implementation and evidence limits.
|
||||
|
||||
The owner replaced Wailing Caverns with Stormwind Stockade for new routine QA while authorizing the pending Blood Arrow and Barren tank-death work. Independent GPT-6 Luna extra-high subprocesses cover the mechanic, full Stockade route, separate live toggle proof, historical incident analysis and read-only reviews.
|
||||
|
||||
## Scope and documentation
|
||||
|
||||
Root `AGENTS.md`, `README.md`, `docs/TEST_DUNGEON_POLICY.md`, report triage, dungeon-pipeline guidance, the mechanics backlog and canonical Obsidian workflows now direct future agents to the full `stormwind-stockade` dungeon. Shared constants/UI download helpers live in `scripts/playtest-defaults.cjs`. Reusable UI, camera, performance, party, healing, native-stat, Hunter and generic Boss Testing harness defaults use Stockade/Hamhock. Dedicated Lady/Vow and old native-combat live reproductions require an explicit historical flag; their old results keep their original labels. No-selector native routes now use Stockade.
|
||||
On 2026-10-04, the owner selected full `stormwind-stockade` for routine QA; the current policy as of 2026-10-05 uses Stormwind Stockade: Cellblock Rush (`bite-sized-stormwind-stockade`). Reusable constants and UI/download helpers live in `scripts/playtest-defaults.cjs`, and generic harnesses now use the seeded one-boss slice. Full-source campaign wrappers require explicit opt-in and route selection. Dedicated Lady/Vow and old native-combat live reproductions keep their historical labels. No-selector native route checks now use Cellblock Rush.
|
||||
|
||||
Existing Wailing import assets, source unit fixtures, bundled starter content and dated evidence remain valid in their original scope. No new Wailing live run is part of this task. Level cap 80, existing-save WoW compatibility, actor-local stat mode, Needs Testing policy and no-new-loot-wiring remain in force.
|
||||
|
||||
@@ -20,7 +24,12 @@ Existing Wailing import assets, source unit fixtures, bundled starter content an
|
||||
|
||||
Blood Arrow's current contract applies only to the verified Knight/Scout and Scout/Rogue owners, including every rank selected by `abilityAtLevel`. Its aura stays active until removed, has no legacy idle self-drain, and recast or right-click deactivation starts an owner-local ten-second cooldown. Knight/Scout offensive ranged-weapon skills cost 2% max HP plus 1% max MP; Scout/Rogue damaging ranged skills and owned NPC ranged auto swings cost 2% max HP. The Blood Punishment rider ends with its aura. Unverified pairings retain their previous imported behavior.
|
||||
|
||||
Player recurring ranged Auto Shot is still absent, and the retained local 10% ranged damage aura is not a sourced current cap-80 curve. These remain explicit backlog items. No new loot system, level-cap change or readiness promotion was introduced.
|
||||
At this capture's build, player recurring ranged Auto Shot was absent, and the
|
||||
retained local 10% ranged damage aura was not a sourced current cap-80 curve.
|
||||
The subsequent [healing/ranged follow-up](ROM_HEALING_PARTY_RANGED_FOLLOWUP_2026-10-04.md)
|
||||
owns new code and validation for Auto Shot, the Group Heal radius and party
|
||||
selection. The captures below retain their original build identity. No new
|
||||
loot system, level-cap change or readiness promotion was introduced.
|
||||
|
||||
The separate live run `20261004-194732821` passed both owners' ordinary buff cancellation, cooldown rejection/reactivation/reuse and unrelated-buff protection, plus owner-only NPC cancellation. Scout/Rogue's isolated Shot lost 46 HP with no MP cost; Knight/Scout's HP sample overlapped an enemy hit and its resource sample included natural updates, so that live window does not prove exact cost amounts. Focused integration covers those amounts, scheduled NPC auto costs and the level-70 rider. Root inspected the actual final screenshots and raw roster telemetry. The Knight/Scout fixture has the exact native-five complement; the optional Scout/Rogue fixture duplicates Scout/Rogue and omits Mage/Warlock, now recorded as an open companion-selection gap.
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,22 @@
|
||||
# Bite-Sized Stockade spell-blocking playtest — 2026-10-05
|
||||
|
||||
The frozen production build completed **Stormwind Stockade: Cellblock Rush** through the ordinary dungeon picker and live movement/healing UI. The harness created a Discipline Priest through the ordinary offline UI, then advanced the isolated profile to level 30 using `shell.saveActiveProgression(30, 0, talentRanks)` before dungeon entry. It used four Ready companions. During the run, it recorded the seeded boss selected by dungeon progress, Hamhock (source `entityId: entry-1717` and sampled runtime actor `creature-79098`); runtime `serverEntry` was unavailable and remains null. The native full-clear result verified at **03:18.0** with 1/1 boss defeated. No combat-state, enemy, health, aura, cast, teleport, or collision-bypass writes were used during play.
|
||||
|
||||
The recorded invocation was:
|
||||
|
||||
```powershell
|
||||
$env:HEALER_MAN_STOCKADE_DIST = 'F:\Projects\HealerMan\artifacts\npc-spell-blocking-2026-10-05\frozen-dist-2026-10-05T20-15-58-183Z'
|
||||
node scripts/playtest-stockade-spell-blocking.cjs --bite-sized-stockade --frozen-build-authorized --expected-build-sha256=864781d16c3c0a26457b6acd7a9bd31357116f856e6b27258b5b633d2f224fac
|
||||
```
|
||||
|
||||
The successful run is `playtest-artifacts/stockade-spell-blocking/20261005-202545227/`. Build fingerprint `864781d16c3c0a26457b6acd7a9bd31357116f856e6b27258b5b633d2f224fac` matched before and after. The full content manifest SHA-256 remained `c946bbd7dd15c1508a2d8f0bf26491c8f63d2b533bbaba366f63413ce0f8f5c8`. One manifest and all 2,124 served hash-addressed content objects were verified against their addresses and manifest entries; there were no integrity failures.
|
||||
|
||||
Across 830 sampled combat events, 29 damage events indicated a block. Six were party attacks blocked by hostiles: two party auto-attacks, two Rogue Sinister Strikes, and two Warrior Revenges. Twenty-three were hostile attacks blocked by party members: 19 basic attacks and four `spell-15657` events. The `spell-15657` events are hostile-source attacks against the party tank; this record does not attribute them as outgoing party casts. Fourteen of the 29 events had a numeric blocked amount; 15 did not, and their amounts remain unknown. No critical event with block was observed. Correlated Revenge event 322 recorded `postHitBlockRoll=0.04820474120788276`, a 5% post-hit block chance, and 15 blocked damage.
|
||||
|
||||
The player produced nine healing events totaling 2,801.9 effective healing. No party deaths or recovery actions were observed. The result screen showed the player at level 32 and companions at level 31. Page errors were zero; the only console error was a missing local `/favicon.ico` (404).
|
||||
|
||||
Combat telemetry is sampled from read-only snapshots of a 200-event store ring. Polling and event-ID deduplication can miss events that age out between snapshots, so the counts describe observed evidence rather than exhaustive run totals. In the screenshot review, equipment and character bodies were visible; close party spacing still caused some overlap and edge occlusion, and the compact roster clipped a name while its Continue control remained clickable. The screenshots and raw event, NPC aura, source ability, content manifest, and build manifest evidence are in the run directory.
|
||||
|
||||
An initial preserved attempt (`20261005-201756813`) stopped because the selected boss was not loaded in the first entry snapshot. The harness now reads the seeded selection from dungeon-run progress and confirms the live objective during normal traversal; it does not wait at the entry for a distant boss. The completed run record’s inherited stance-playtest notes were replaced with spell-blocking counts and an explicit sampled-telemetry caveat.
|
||||
|
||||
Both wrapper syntax and static prepare-only checks pass. Temporary harness files are removed and the owned server port 55740 has no listener. Windows denied process-command-line inspection; unrelated shared Node processes were left untouched. Root independently rehashed all 5,964 frozen build files with zero mismatches and reviewed the roster, entrance, route and native-results screenshots.
|
||||
@@ -0,0 +1,50 @@
|
||||
# Stormwind Stockade Stances and Blocking Live Playtest — 2026-10-05
|
||||
|
||||
## Run and clear result
|
||||
|
||||
The successful normal Stockade run is `playtest-artifacts/stockade-stances-blocking/20261005-184333429/`. It used the immutable distribution at `artifacts/enemy-stances-blocking-2026-10-05/frozen-dist-2026-10-05T18-27-09-285Z`, whose aggregate SHA-256 was `1fcd021af0ef90c8d994cf1ab853ef0e62f4d4767fa3acaab698b14121194310` both before and after the run.
|
||||
|
||||
The UI showed **FULL DUNGEON CLEAR** for Stormwind Stockade at 24:25.4, with all five required IDs recorded: `creature-84027` (Targorr the Dread), `creature-79088` (Kam Deepfury), `creature-79098` (Hamhock), `creature-79124` (Bazil Thredd), and `creature-79116` (Dextren Ward). The player entered at level 30 as a WoW Discipline Priest and naturally reached level 40; all four Ready companions reached level 39. The level-80 cap stayed in force, and loot was not tested. No player or companion deaths were recorded.
|
||||
|
||||
The first attempt, `20261005-182757796`, is preserved as `superseded-observability-limited`. It reached the 25% route screenshot but was stopped when no periodic in-run state was available; it produced no route result and is not counted as a clear. The retry added read-only 30-second `progress.json` snapshots and completed the route.
|
||||
|
||||
Root visually reviewed the roster and 25%, 50%, 75%, and boss-arrival screenshots. The native HUD, character bodies, equipment, and party silhouettes were visible. Existing actor overlap and edge occlusion remained; this playtest makes no visual or race-model fix claim.
|
||||
|
||||
## Stance applications
|
||||
|
||||
The corrected reconstruction combines live collector observations with route-sample aura telemetry and keys application identity by `instanceId + appliedAt`:
|
||||
|
||||
| Source spell | Observed applications | Source |
|
||||
|---|---:|---|
|
||||
| 7164 Defensive Stance | 1 | Kam Deepfury |
|
||||
| 7165 Battle Stance | 34 | Hostile mobs |
|
||||
| 3419 Improved Blocking | 1 preserved application | Kam Deepfury |
|
||||
|
||||
Kam’s preserved Improved Blocking application had a six-second active window. Its sampled route telemetry contains 101 Kam snapshots, but `abilityCastCounts` was `{}` in every snapshot, no active cast window was sampled, and the preserved Kam-source combat events were damage events only. The historical collector keyed by stable aura instance ID and could conflate repeat applications. The wrapper now keys by instance ID plus application time; reanalysis of the saved route samples still found no additional 3419 application. Therefore the observed application is confirmed, while any repeated short applications remain unverified because they may have fallen between reads. See `playtest-artifacts/stockade-stances-blocking/20261005-184333429/aura-application-reanalysis.json`.
|
||||
|
||||
## Block outcomes
|
||||
|
||||
The route evidence contains 149 raw damage events with `outcome=block`:
|
||||
|
||||
- 141 hostile attacks were blocked by the party; 30 have a matching sampled `lastCombatResult` amount.
|
||||
- 8 party attacks were blocked by hostiles; 3 have a matching sampled amount.
|
||||
- Actor direction was unresolved for 0 events.
|
||||
- 116 block events have no matching sampled blocked amount. Another 14 sampled `lastCombatResult` observations had no matching latest damage event. Unmatched outcomes remain recorded without inferring an amount.
|
||||
|
||||
This establishes both party defense blocks and NPC defense blocks. The uncorrelated amounts and the Improved Blocking repeat count remain subject to intermittent sampling.
|
||||
|
||||
## Build and content provenance
|
||||
|
||||
The frozen distribution fingerprint matched before and after. The global content manifest changed during the run from SHA-256 `d3d553aa7443bf444c87b0c0e923357df02756d0822db2e1a0a908d3f257fdb8` to `5dc3143362f206b90debaeb26e7703d74b84d9838266f99f1b2a7d49fc859c1e`; its file count rose from 21,592 to 21,594. The initial snapshot retained summary metadata rather than a copy of the original manifest, so the changed entries cannot be isolated and whole-tree content immutability is not claimed.
|
||||
|
||||
During the run, 2,124 hash-addressed content objects returned successfully and all 2,124 matched their hash-addressed paths; no object-integrity failures were recorded. This verifies the fetched objects, while the manifest-level change remains a provenance limitation. See `content-source-evidence.json`, `content-manifest-before.json`, and `content-manifest-after.json` in the run directory.
|
||||
|
||||
The browser recorded zero page errors. Its only console error was a 404 for `/favicon.ico`.
|
||||
|
||||
## Preparation
|
||||
|
||||
`node --check scripts/playtest-stockade-stances-blocking.cjs` and `node scripts/playtest-stockade-stances-blocking.cjs --prepare-only` passed after the aura application identity correction. Preparation did not scan a distribution or start a server/browser. The full clear, five native result IDs, frozen-build equality, and content-object integrity are recorded in `run-record.json` and the adjacent evidence files.
|
||||
|
||||
The run exited with code 0. Run-owned runner/server and browser processes have
|
||||
exited, and generated helper scripts are removed. The stale helper from the
|
||||
superseded first attempt was removed after verifying its exact owned path.
|
||||
@@ -1,5 +1,11 @@
|
||||
# Stockade utility attack source audit — 2026-10-04
|
||||
|
||||
Later continuations enable sourced shouts, Enrage, NPC stances and ordinary
|
||||
creature auto-attack blocking as utility effects, with no fabricated direct hit.
|
||||
See [enemy mechanics](STOCKADE_ENEMY_MECHANICS_2026-10-05.md) and
|
||||
[stances/blocking](ENEMY_STANCES_BLOCKING_2026-10-05.md). The dated omissions and
|
||||
failed-route evidence below describe the earlier correction.
|
||||
|
||||
**Finding:** The flagged entries were real NPC damage packets in the failed route artifact, not damage caused by the adjacent player actions. The route’s old generated attacks lacked explicit effects, so the runtime treated them as direct damage. Two source corrections now omit thirteen audited utility/extra-attack IDs and preserve supported damage/control with verified delivery, targets and ranges; no runtime aura values or encounter damage were guessed.
|
||||
|
||||
## First correction and failed-route evidence
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# Stockade Weapon Utilities Playtest — 2026-10-05
|
||||
|
||||
## Outcome
|
||||
|
||||
Two normal offline Bite-Sized Stockade / Cellblock Rush runs completed with a level-30 Discipline Priest profile and four Ready NPC companions. Each run seeded and defeated exactly one real Stockade boss through ordinary UI play. The same frozen build and content snapshot were used both times. The first run's boss clear is valid, but its live weapon telemetry was lost in the route-sample projection; one corrected run was performed and retained as a separate run record. No further gameplay run was made.
|
||||
|
||||
Both runs used build SHA-256 `58dfe50765b0635caeae50bd3eca2fd079cd69cce0e571ff6cb2dd5aeec77b39` and content-manifest SHA-256 `36614a23f3b98b4289bc3726c8a9bdb075445ada50dfce6504ade4e36325be1f`. The before/after build and content hashes matched on both runs. Each run served and verified 2,124 manifest-referenced hash-addressed content objects, with zero integrity failures and no page errors. Parent audit also confirmed the frozen inputs and sampled assets were unchanged.
|
||||
|
||||
| Run | Seeded boss | Native result | Player effective healing | Deaths |
|
||||
| --- | --- | --- | ---: | ---: |
|
||||
| `20261006-012123000` | Hamhock, entry 1717, actor `creature-79098` | 1/1 clear, 03:14.6 | 3,057.6 | 0 player, 0 party |
|
||||
| `20261006-013934624` | Bazil Thredd, entry 1716, actor `creature-79124` | 1/1 clear, 03:20.7 | 1,504.5 | 0 player, 0 party |
|
||||
|
||||
The route result is recorded in each run's `run-record.json`, including the visible native dungeon-results text and required boss ID. The `boss-arrival.png` capture also shows the post-clear results panel with the single boss marked defeated.
|
||||
|
||||
## Corrected live telemetry
|
||||
|
||||
The corrected run retained 328 source NPC snapshots and 764 sampled combat events. Each mob snapshot now carries `dualWieldEnabled`, `nextEnemyOffhandAttackAt`, `pendingExtraAttacks`, and `lastDamagedActorId` through to the final route evidence. Bazil Thredd's `dualWieldEnabled` was true in 35 samples. No sampled mob had a positive offhand timer: all 328 `nextEnemyOffhandAttackAt` values were zero. No nonempty pending-extra-attack queue, non-null `lastDamagedActorId`, or non-null `attackHand` on source attack definitions or retained combat events was observed. These are ordinary snapshots, so short-lived states or events may fall between polls.
|
||||
|
||||
The captured run's original summary field `samplesWithOffhandSchedule` counted 328 non-null timer fields, including zero. It must not be read as 328 scheduled attacks. The raw rows show 328 zero values and zero positive timers. The harness counter has since been corrected to report timer-field presence separately from positive scheduled timestamps; this source-only counter fix was syntax/preparation checked and was not used to run another dungeon.
|
||||
|
||||
Global combat-store telemetry captured 26 snapshots of the Disease aura **Infected Wound** on the party tank. All snapshots share one stable aura instance and one stack. Four distinct source/application/expiry tuples were observed, each with a 300,000 ms duration:
|
||||
|
||||
- `creature-79035`, applied at `1791250853253`
|
||||
- `creature-79042`, applied at `1791250872255`
|
||||
- `creature-79065`, applied at `1791250898558`
|
||||
- `creature-79062`, applied at `1791250928053`
|
||||
|
||||
No active aura snapshots for Bloodlust (`6742`) or Disarm (`6713`) were recorded. The first run's Hamhock checkpoint had `smart-1717-2-bloodlust: 1` in its ability-cast counter while unengaged; that counter alone does not prove the aura landed. No live outcome claim is made for Bloodlust, Disarm, or Thrash. Aura snapshots and combat events are sampled, so zero observations cannot establish that an effect never occurred.
|
||||
|
||||
## First-run telemetry limitation
|
||||
|
||||
The first run's route result contains 327 source NPC samples, but a later sample-projection whitelist dropped all four requested weapon fields. Its 327 null summaries describe the harness projection gap, not evidence that the runtime lacked weapon state. That run also filtered global aura telemetry to older unrelated IDs, so it cannot establish whether the new utility auras reached party targets. The first run's raw route and screenshots were preserved without rewriting; the corrected run above supplies the usable measurements.
|
||||
|
||||
The second run's mob route samples and global source-aura snapshots are available in `playtest-artifacts/stockade-weapon-utilities/20261006-013934624/weapon-utilities-evidence.json` and `campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-campaign-boss-route.json`. The first run's matching artifacts remain under `playtest-artifacts/stockade-weapon-utilities/20261006-012123000/`.
|
||||
|
||||
## Screenshots
|
||||
|
||||
Both runs saved the Priest roster preview, compact roster preview, campaign picker, dungeon entrance, equipped party silhouettes, three route checkpoints, and a results capture named `boss-arrival.png`. The player robe/shoulders/staff and several companion bodies with staff/club/shield silhouettes are visible in the route captures. Party clustering and overlap prevent a complete per-companion gear audit from these screenshots.
|
||||
|
||||
Corrected run captures:
|
||||
|
||||
- [Discipline Priest roster](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/roster-discipline-priest-level-30.png)
|
||||
- [Compact roster](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/roster-compact-discipline-priest-level-30.png)
|
||||
- [Campaign picker](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-campaign-picker.png)
|
||||
- [Dungeon entrance](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-entrance.png)
|
||||
- [Equipped player and Ready NPC party silhouettes](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-player-equipped-silhouette-native-party.png)
|
||||
- [Route 25%](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-boss-route-25.png), [route 50%](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-boss-route-50.png), [route 75%](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-boss-route-75.png)
|
||||
- [Bazil Thredd native clear/results](../playtest-artifacts/stockade-weapon-utilities/20261006-013934624/campaign/final-build-20261006-013937115/bite-sized-stormwind-stockade-boss-arrival.png)
|
||||
|
||||
The same capture set is in `playtest-artifacts/stockade-weapon-utilities/20261006-012123000/campaign/final-build-20261006-012126038/`. Parent review found the player and party silhouettes visible there as well, with the same overlap limit.
|
||||
|
||||
## Scope and cleanup
|
||||
|
||||
The harness used normal UI character creation, dungeon selection, movement, targeting, attacks, support healing, and party commands. It did not use Boss Testing, teleports, collision bypass, combat-state writes, manual aura or health seeding, loot claims, or readiness promotion. The corrected run exited successfully; the wrapper's cleanup path closed its browser and server and removed its generated temporary campaign wrapper.
|
||||
|
||||
After this run, only the new harness and this report were updated. The post-run counter change affects future evidence summaries only; no gameplay state, build, content snapshot, or prior run evidence was modified.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
The final source-aware build completed a normal five-boss Stormwind Stockade campaign route and displayed the native **FULL DUNGEON CLEAR** result with all five required boss IDs present. The successful route used the ordinary level-30 Priest/Knight test identity and the native five-member party; the player leveled to 39 during the run. A separate bounded Vow of Silence diagnostic is being prepared because Hamhock's Chain Lightning was observed during the full clear, but the boss was killed before the route reached its Vow handler.
|
||||
|
||||
Stormwind Stockade (`stormwind-stockade`) is the routine testing fixture for this campaign route. The generated definition has five required bosses, ending at Dextren Ward. The route harness uses the shared exact-title Stockade picker helper when no route selector is supplied. Wailing Caverns is guarded as historical-only and requires both `--route=wailing-caverns` and `--historical-wailing`; this run does not use that path.
|
||||
This dated run explicitly selected full Stormwind Stockade (`stormwind-stockade`) and completed its five-boss campaign. The generated definition ends at Dextren Ward. The route harness now defaults to Cellblock Rush for routine checks; use `--route=stormwind-stockade` for an explicit full-source route. Wailing Caverns remains historical-only and requires both `--route=wailing-caverns` and `--historical-wailing`; this run did not use that path.
|
||||
|
||||
## Generated route and geometry
|
||||
|
||||
@@ -28,7 +28,7 @@ From the repository root, regenerate the guide and start the full-route attempt
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force playtest-artifacts/campaign-boss-pass | Out-Null
|
||||
node_modules/.bin/vite-node --script scripts/campaign-boss-route-probe.ts > playtest-artifacts/campaign-boss-pass/navigation-guidance.jsonl
|
||||
node_modules/.bin/vite-node --script scripts/campaign-boss-route-probe.ts stormwind-stockade > playtest-artifacts/campaign-boss-pass/navigation-guidance.jsonl
|
||||
node scripts/playtest-campaign-boss-pass.cjs --campaign-boss-route --route=stormwind-stockade --camera-diagnostic --max-campaign-seconds=2400
|
||||
```
|
||||
|
||||
|
||||
+70
-55
@@ -1,82 +1,97 @@
|
||||
# Default test dungeon — Stormwind Stockade
|
||||
# Default test dungeon — Stormwind Stockade: Cellblock Rush
|
||||
|
||||
The project owner selected **Stormwind Stockade** on 2026-10-04 as the default
|
||||
for new routine gameplay, mechanics, healing, party, camera, input, performance
|
||||
and browser diagnostics. The runtime ID is `stormwind-stockade`; the UI title is
|
||||
`Stormwind Stockade`. This replaces Wailing Caverns as the routine test dungeon.
|
||||
As of 2026-10-05, the project owner's default for new routine live gameplay,
|
||||
mechanics, healing, party, camera, input, performance and browser diagnostics is
|
||||
**Stormwind Stockade: Cellblock Rush** (`bite-sized-stormwind-stockade`). In the
|
||||
Dungeons picker, choose the **Bite-Sized** category and the exact
|
||||
**Stormwind Stockade: Cellblock Rush** row. The derived run shares Stormwind
|
||||
Stockade's environment and content pack, seals both side wings and keeps its
|
||||
central corridor. It completes after one boss.
|
||||
|
||||
Mode-specific Bite-Sized spawn/Race diagnostics use `bite-sized-stormwind-stockade`
|
||||
as their default Stockade fixture. They remain distinct from the full dungeon
|
||||
required for ordinary mechanics and campaign-route proof.
|
||||
Each fresh run selects one of five source bosses from the persisted/shared run
|
||||
ID: Targorr the Dread, Kam Deepfury, Hamhock, Bazil Thredd, or Dextren Ward. A
|
||||
resume or party member reconstructs the same boss. Reusable live harnesses must
|
||||
record the boss actually observed in the entered run; do not assume the seeded
|
||||
choice is Hamhock. The exact authored selection and route are in
|
||||
`src/game/dungeons/biteSizedStockades.ts`.
|
||||
|
||||
## Agent workflow
|
||||
|
||||
1. Read `AGENTS.md` and the relevant canonical vault notes.
|
||||
2. Use the full Stockade dungeon from **Dungeons → WoW → Stormwind Stockade**.
|
||||
Install and verify its content through the normal entry/download flow when
|
||||
required. Do not fall back to bundled Wailing content.
|
||||
3. For reusable harnesses, import `scripts/playtest-defaults.cjs`. Its exports
|
||||
are `DEFAULT_TEST_DUNGEON_ID`, `DEFAULT_TEST_DUNGEON_TITLE`, and
|
||||
`DEFAULT_TEST_DUNGEON_BOSS` (Hamhock for generic Boss Testing).
|
||||
`selectDefaultTestDungeon(page)` selects the exact full-dungeon row;
|
||||
`openSelectedDungeonRoles(page)` handles both installed content and the normal
|
||||
download confirmation before waiting for role selection.
|
||||
4. Use ordinary movement/casting for live mechanic and route proof. Read-only
|
||||
2. Enter the **Bite-Sized → Stormwind Stockade: Cellblock Rush** row through
|
||||
the normal Dungeons picker. It may use the installed Stockade content pack;
|
||||
follow the normal download confirmation and role-selection flow when needed.
|
||||
3. For reusable harnesses, import `scripts/playtest-defaults.cjs`. Its default
|
||||
ID/title/category are `bite-sized-stormwind-stockade`,
|
||||
`Stormwind Stockade: Cellblock Rush`, and `Bite-Sized`.
|
||||
`selectDefaultTestDungeon(page)` selects that exact row, and
|
||||
`openSelectedDungeonRoles(page)` handles the ordinary installed/download
|
||||
flow before waiting for role selection.
|
||||
4. For an explicitly requested full-source campaign, use the exported
|
||||
`FULL_STOCKADE_DUNGEON_ID`, `FULL_STOCKADE_DUNGEON_TITLE`, and
|
||||
`FULL_STOCKADE_BOSS` constants. `selectFullStockadeDungeon(page)` selects
|
||||
the full **WoW → Stormwind Stockade** row. The campaign harness requires an
|
||||
explicit `--route=stormwind-stockade` when `--campaign-boss-route` is used;
|
||||
the source-specific full-campaign wrappers require `--full-stockade` for a
|
||||
live run. Static `--prepare-only` checks do not enter a dungeon.
|
||||
5. Use ordinary movement/casting for live mechanic and route proof. Read-only
|
||||
telemetry may inspect casts, resources, actor positions and run progress.
|
||||
Label any isolated pre-entry profile preparation or synthetic unit fixture.
|
||||
5. Record loaded build assets, source boss identity, actual mechanic outcome,
|
||||
screenshots, runtime errors and limitations in `PLAYTEST_NOTES.md` and the
|
||||
scoped report. Inspect the screenshots before claiming a visual fix.
|
||||
6. Record loaded build assets, actual dungeon ID and selected boss, source
|
||||
identity, mechanic outcome, screenshots, runtime errors and limitations in
|
||||
`PLAYTEST_NOTES.md` and the scoped report. Inspect screenshots before claiming
|
||||
a visual fix.
|
||||
|
||||
## Source and completion
|
||||
|
||||
The authored recipe is `dungeon-pipeline/recipes/stormwind-stockade.json`;
|
||||
The authored full-dungeon recipe is `dungeon-pipeline/recipes/stormwind-stockade.json`;
|
||||
`dungeon-pipeline/runtime-overrides/stormwind-stockade.json` owns runtime
|
||||
overrides. The catalog is generated by the dungeon pipeline; do not hand-edit
|
||||
its JSON or compressed TypeScript. The existing Stockade navigation regressions
|
||||
are in `src/game/stockadesNavigation.test.ts`.
|
||||
overrides. `src/game/dungeons/biteSizedStockades.ts` derives Cellblock Rush
|
||||
without mutating the generated full source definition. Both variants resolve to
|
||||
the Stockade content pack. The catalog is generated by the dungeon pipeline;
|
||||
do not hand-edit its JSON or compressed TypeScript. Existing full-Stockade
|
||||
navigation regressions are in `src/game/stockadesNavigation.test.ts`.
|
||||
|
||||
The current full-dungeon objective order is Targorr the Dread, Kam Deepfury,
|
||||
Hamhock, Bazil Thredd and Dextren Ward. Dextren Ward is the final objective.
|
||||
A normal full-clear claim requires all five objectives and the native results
|
||||
screen; reaching an anchor or clearing a Bite-Sized variant is separate proof.
|
||||
Record persistent killed-boss/run progress so natural earlier kills survive
|
||||
endpoint despawning. A zero-engaged pack attempt does not establish a pack kill.
|
||||
The full Stockade objective order is Targorr the Dread, Kam Deepfury, Hamhock,
|
||||
Bazil Thredd and Dextren Ward. Dextren Ward is the final objective. A full-source
|
||||
clear claim requires all five native objective IDs and the native full-clear
|
||||
results screen. Cellblock Rush completes after its one selected boss and is
|
||||
evidence for that slice only. Record persistent killed-boss/run progress so
|
||||
natural earlier kills survive endpoint despawning. A zero-engaged pack attempt
|
||||
does not establish a pack kill.
|
||||
|
||||
Hamhock's source list includes Nature Chain Lightning 421 and Bloodlust 6742.
|
||||
Chain Lightning is a real damaging cast with sourced range 30; its chain fan-out
|
||||
remains unsupported. Bloodlust is a haste buff, and its unsupported utility
|
||||
effect is omitted rather than emitted as damage. Use the actual imported
|
||||
timing/control/immunity data for live interrupt proof; do not carry Lady
|
||||
Anacondra's IDs or casts into a Stockade test.
|
||||
|
||||
For a focused ordinary-campaign Vow check, use
|
||||
Chain Lightning has sourced range 30 and three total targets, with nearest
|
||||
visible living jumps within 10 m and profile-specific damage decay. Bloodlust
|
||||
is a haste buff, and its unsupported utility effect is omitted rather than
|
||||
emitted as damage. Use the full Stockade route only when that campaign evidence
|
||||
is explicitly requested. For the focused Vow check, use
|
||||
`node scripts/playtest-campaign-boss-pass.cjs --campaign-boss-route --route=stormwind-stockade --stockade-vow-diagnostic`.
|
||||
This bounded diagnostic is separate from full-clear proof. Tab selection does
|
||||
not face the target: player combat facing follows `cameraYaw`. Use ordinary
|
||||
right-mouse drag, verify the actual facing arc and keep pointer lock null.
|
||||
Pace large turns across frames to respect the input manager's delta limits.
|
||||
Hit-test a clear canvas path; boss notifications can cover a fixed starting
|
||||
point even when the game canvas fills the viewport.
|
||||
Credit cancellation only from the same watched live cast, a completed player
|
||||
Vow cast, its owned target aura and disappearance before scheduled release
|
||||
without matching Chain Lightning damage while the target remains alive.
|
||||
Stop gameplay inputs and retain read-only samples through scheduled release
|
||||
plus 100 ms to check that interval directly.
|
||||
This bounded source-specific diagnostic is an explicit full-dungeon entry and
|
||||
is separate from routine Cellblock Rush checks. Tab selection does not face the
|
||||
target: player combat facing follows `cameraYaw`. Use ordinary right-mouse drag,
|
||||
verify the actual facing arc and keep pointer lock null. Pace large turns across
|
||||
frames to respect the input manager's delta limits. Hit-test a clear canvas
|
||||
path; boss notifications can cover a fixed starting point even when the game
|
||||
canvas fills the viewport. Credit cancellation only from the same watched live
|
||||
cast, a completed player Vow cast, its owned target aura and disappearance
|
||||
before scheduled release without matching Chain Lightning damage while the
|
||||
target remains alive. Stop gameplay inputs and retain read-only samples through
|
||||
scheduled release plus 100 ms to check that interval directly.
|
||||
|
||||
## Earlier fixtures and scope
|
||||
|
||||
Keep Wailing's existing import/source regressions and dated reports as historical
|
||||
evidence. They do not select the dungeon for future routine live QA. Dedicated
|
||||
legacy Wailing/Lady harnesses are historical reproductions, and a new live run
|
||||
requires the owner's explicit request for that dungeon. Do not relabel their
|
||||
old screenshots or results as Stockade evidence.
|
||||
requires the owner's explicit request for that dungeon. Do not relabel their old
|
||||
screenshots or results as Stockade evidence.
|
||||
|
||||
Incident analysis may read Barren or another dungeon's captured evidence and
|
||||
source. Generic follow-up validation uses Stockade; encounter-specific live
|
||||
reproduction follows the user's explicitly requested dungeon. This policy
|
||||
replaces the previously proposed additional Wailing clear with a Stockade
|
||||
full-route/full-clear attempt.
|
||||
source. Generic follow-up validation uses Cellblock Rush; encounter-specific
|
||||
live reproduction follows the user's explicitly requested dungeon. Preserve
|
||||
dated full-Stockade clear reports as historical results; they do not make the
|
||||
full campaign the future default.
|
||||
|
||||
Ready-five balance scope, RoM Needs Testing status, saved-profile compatibility,
|
||||
level cap 80 and the no-new-loot-wiring constraint continue to apply. The test
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,148 @@
|
||||
# Weapon parity follow-up — 2026-10-05
|
||||
|
||||
This pass connects source-bound Disarm contributions for players and generated
|
||||
party members, adds verified native RoM unarmed inputs, imports intrinsic enemy
|
||||
offhand flags, and records actual hand results between route checkpoints.
|
||||
The level cap remains 80. Loot and readiness policies are unchanged.
|
||||
|
||||
## Runtime ownership
|
||||
|
||||
- `enemyDisarmRuntime.ts` selects source spell weapon channels and projects
|
||||
equipped-weapon aura and damage contributions. `combatStore.ts` exposes
|
||||
`effectiveActorAuras`; the player and party paths consume that view. Passive
|
||||
weapon auras stay in authoritative storage and resume when Disarm expires.
|
||||
Nonpassive aura storage and other usable hands remain intact. Feral forms
|
||||
retain their weapon-independent behavior. Original gear and nonweapon stats
|
||||
remain available to attribute/AP derivation.
|
||||
- `romNativeCombatAmount.ts` supplies the verified native main-hand profile:
|
||||
source base `Level * 2`, native speed 30 (3 seconds), residual nonweapon damage,
|
||||
and the tracked physical damage multiplier. Main-hand-consuming direct and
|
||||
periodic formulas accept this profile; ranged fields remain independent.
|
||||
Player and party schedulers consume the actor's native snapshot. See
|
||||
[the native source audit](ROM_NATIVE_DISARM_2026-10-05.md) for source hashes,
|
||||
neutral unmodeled rate channels, custom-gear limits, and cast prerequisites.
|
||||
- `enemyAutomaticOffhand.ts` reads the pinned creature `flags_extra` 0x800.
|
||||
Five generated templates carry the flag; their capability survives encounter
|
||||
lifecycle resets and their hand clocks rearm on engagement. Native enemies,
|
||||
summons, and character defenders stay outside this creature contract.
|
||||
The item-class AUTO predicate is available, but equipment mappings are not
|
||||
bound: the backup tables do not match the pinned world source. See
|
||||
[the offhand audit](ENEMY_AUTOMATIC_OFFHAND_2026-10-05.md).
|
||||
- `combatEvents.ts` retains `attackHand` and `extraAttackSourceSpellId` on actual
|
||||
supported enemy swing results. Ordinary main-hand, offhand, and queued Thrash
|
||||
results are distinguishable; unrelated special melee abilities and periodic
|
||||
ticks do not receive invented hand labels. Player, party, summon, and online
|
||||
recipient event writers share the same source classifier.
|
||||
- `scripts/weapon-evidence-recorder.cjs` subscribes read-only to committed combat
|
||||
state. It copies events, weapon state changes, and global source utility aura
|
||||
changes, including party debuffs. It audits event-ID gaps and capacity loss.
|
||||
This is a committed-state recorder, not a guarantee that uncommitted transient
|
||||
state is visible. The existing bounded HUD history remains unchanged.
|
||||
|
||||
## Source limits
|
||||
|
||||
The WoW source contract does not invent native item eligibility or unknown
|
||||
ability channels. Native custom equipment provenance, seven unmodeled weapon
|
||||
rate channels, broader proc-specific formulas, and unsourced cast prerequisites
|
||||
remain explicit boundaries. The source Thrash fallback cadence remains
|
||||
simulator policy. The mismatched equipment backup is evidence for an unresolved
|
||||
import requirement, not an equipment mapping used by combat.
|
||||
|
||||
## Validation
|
||||
|
||||
The final 17-file focused run passes 102 Vitest checks, covering the source
|
||||
helpers, actual player and party Disarm paths, aura projection, weapon AP/DPS
|
||||
contributions, native direct/periodic resolution, enemy hands/queues, and event
|
||||
subscriptions. The selected files are `enemyWeaponEvents.integration`,
|
||||
`enemyExtraAttacks.integration`, `enemyAutomaticOffhand`,
|
||||
`enemyAutomaticOffhand.integration`, `enemyDisarmRuntime`,
|
||||
`enemyDisarmRuntime.integration`, `enemyDisarmApplication.integration`,
|
||||
`enemyWeaponDebuffs`, `playerDisarmContributions.integration`, `romNativeDisarm`,
|
||||
`romNativeCombatAmount.integration`, `romNativeDamage`, `romNativePeriodicDamage`,
|
||||
`romNativeCombatResolution.integration`, `partyAbilityAi`, `combatAuras`, and
|
||||
`combatEventsSubscription`, all under `src/game` with `.test.ts` suffixes.
|
||||
|
||||
`npm run test:ready-five` passes 7 Vitest and 20 Python checks. Avatar validation
|
||||
passes all 56 checks. The recorder's Node tests pass 3 checks; syntax and the
|
||||
transformed wrapper's `--prepare-only` check pass. No full suite or all-class
|
||||
balance sweep was run. The non-Ready shaman/feral fixtures are isolated source
|
||||
exception checks; native active-five diagnostics do not promote readiness.
|
||||
|
||||
The final `npm run build` passes the standard prebuild, 8GB TypeScript, Vite,
|
||||
precompression and release-bundle verification. Existing chunk-size and mixed
|
||||
static/dynamic-import warnings remain. Review found and corrected a disabled
|
||||
offhand/ranged default-speed AP contribution before this final build; its new
|
||||
regression preserves independent scripted AP while removing that speed term.
|
||||
|
||||
The corrected build freeze is
|
||||
`artifacts/weapon-parity-followup-2026-10-05/corrected-build-20261006-035420760`:
|
||||
build SHA-256 `fcdde36bbd63ac711453a57562a38d7a1aa7ff2e8cafd4acb0e65a7a4dc27efe`.
|
||||
It reuses the unchanged isolated content copy from
|
||||
`frozen-20261006-034444784/content`, manifest SHA-256
|
||||
`ac0fa2a867ba0a495c172de2b89532d69b32d56d032482b26020ce2d189f074b`.
|
||||
That original freeze copied and verified all 27,571 referenced objects
|
||||
(6,489,632,021 bytes; 21,597 logical files). The corrected freeze rechecked both
|
||||
content manifests and hashed the complete source/copied build before and after;
|
||||
it records the original object-verification evidence rather than claiming to
|
||||
rehash every unchanged object a second time. The live wrapper separately
|
||||
verifies the objects actually served.
|
||||
|
||||
The first-build route `playtest-artifacts/stockade-weapon-utilities/20261006-034834217`
|
||||
cleared Bazil Thredd (1716) and recorded 740 post-baseline events, 44 source
|
||||
main-hand results, one offhand result, positive hand timers, party Disarm and
|
||||
Infected Wound. The recorder had zero gaps, errors, or capacity loss. This is
|
||||
historical first-build evidence: the corrected build receives a separate final
|
||||
run below. Source/helper diagnostics are recorded in the linked worker audits.
|
||||
|
||||
## Corrected-build Cellblock Rush
|
||||
|
||||
`playtest-artifacts/stockade-weapon-utilities/20261006-035524177` completes the
|
||||
one-boss variant with seeded Hamhock, entry 1717, live actor `creature-79098`,
|
||||
run ID `b40105fb-bf4e-435b-9c08-00d3f9feda75`. The native results screenshot
|
||||
shows Hamhock defeated, 1/1 bosses and 03:15.1. This is Cellblock Rush completion,
|
||||
not a five-boss Stockade campaign. The route uses a normal offline Discipline
|
||||
Priest and four Ready NPCs. The UI-created profile receives isolated pre-entry
|
||||
level-30 progression preparation; gameplay uses ordinary controls and read-only
|
||||
telemetry, with no combat state seeding or forced utility casts.
|
||||
|
||||
The recorder retains 842 consecutive post-baseline events (IDs 9–850), with zero
|
||||
gaps, sampling errors or retention loss. It identifies 73 actual source NPC
|
||||
main-hand results, 528 combined weapon-state observations, and source Bloodlust,
|
||||
Disarm and Infected Wound aura snapshots (15, 3 and 49 respectively). Targets
|
||||
include player-party NPCs and source enemies. No offhand or queued Thrash result
|
||||
is observed in this seeded route. Those paths have deterministic runtime tests;
|
||||
the earlier Bazil first-build route additionally contains one blocked offhand
|
||||
result. Absence here does not establish that the capability never operates.
|
||||
Coverage describes committed post-baseline state, not every uncommitted instant.
|
||||
The route has no player/party hand-tagged events, so it does not directly prove
|
||||
outgoing Disarm suppression; focused player/party runtime tests establish that
|
||||
consumer behavior separately.
|
||||
|
||||
The run record verifies unchanged complete build/content fingerprints and
|
||||
manifest-backed objects actually loaded. Page/route console error arrays are
|
||||
empty; the outer browser log contains only a favicon 404. Root inspected the
|
||||
final-build roster, entrance/equipment, mid-route and results screenshots:
|
||||
player and several party bodies and staff/shield/weapon silhouettes are visible.
|
||||
Clustering limits a complete per-companion equipment audit. The results UI is
|
||||
readable and agrees with the seeded boss identity.
|
||||
|
||||
The independent audit rehashes all 2,124 loaded content object paths
|
||||
(77,019,550 bytes), all 185 observed asset URLs (69 frozen build files and 116
|
||||
manifest-backed logical assets), and all seven critical loaded build chunks,
|
||||
with zero failures. It verifies backing immutable source bytes; complete HTTP
|
||||
response body digests were not captured for every asset request.
|
||||
|
||||
Evidence:
|
||||
|
||||
- [Final run record](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/run-record.json)
|
||||
- [Weapon evidence](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/weapon-utilities-evidence.json)
|
||||
- [Independent audit](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/root-weapon-recorder-review.json)
|
||||
- [Roster](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/campaign/final-build-20261006-035526744/roster-discipline-priest-level-30.png)
|
||||
- [Party silhouettes](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/campaign/final-build-20261006-035526744/bite-sized-stormwind-stockade-boss-route-50.png)
|
||||
- [Native results](../playtest-artifacts/stockade-weapon-utilities/20261006-035524177/campaign/final-build-20261006-035526744/bite-sized-stormwind-stockade-boss-arrival.png)
|
||||
|
||||
The final `npm run release:check` passes, including untracked files. Separate
|
||||
game/vault diffs and vault text hygiene are reviewed; no stage, commit or deploy.
|
||||
The root audit is retained with the run. The task began October 5 and completed
|
||||
October 6 local time. Source equipment mappings and native limits above remain open;
|
||||
this pass makes no loot, level-cap or readiness promotion.
|
||||
@@ -0,0 +1,13 @@
|
||||
# Shield Bash's triggered Daze
|
||||
|
||||
The selected WoW 3.3.5a Shield Bash 72 now dispatches its missing child 29703 through the real player and companion effect paths. The child applies a 50% movement slow for 6,000 ms, without damage or an ordinary dispel category. A full parent block or avoidance suppresses the entire trigger; the child does not roll a second block result. The parent's interrupt and six-second school lockout remain independent of the child's snare immunity.
|
||||
|
||||
The authoritative local source is `../wow335a/Data/enUS/patch-enUS.MPQ`, read without mutation. Spell.dbc SHA-256 is `9f0088da35c5ed0b5106cd20e422611489e435b74043e520e02221e0ce1b1af1`; SpellDuration.dbc is `b4809a47228b341da4cafe1b37f75c1445015d3a816ee73e47dbf3374b85bc78`; SpellRange.dbc is `d10afdee19dc04474c8be15878011a8807f5df29d8267d170b1de347585d2985`. The ignored extraction script and parsed rows live under `artifacts/enemy-control-followup-2026-10-06/`.
|
||||
|
||||
Parent 72 has effect 68/interrupt mechanic 26, followed by effect 64 triggering 29703. Child 29703 has spell mechanic **11/SNARE**, despite its display name Dazed, and a single effect 6/apply-aura, aura 33/decrease-speed, raw base points -51 and die sides 1. Its duration index 32 resolves to six seconds. Its damage class is None and school mask is Normal. The child range of 50,000 yards does not widen parent targeting: only the accepted parent's selected recipient is dispatched.
|
||||
|
||||
`wow335ShieldBashDaze.ts` binds dispatch to the exact selected parent, source profile and effect signature. Unknown ranks, CoA/RoM profiles and unbound procs cannot borrow the child. Target support is bounded to ordinary source WoW NPCs; summoned creatures, character defenders and native RoM defenders remain outside this import. Source SNARE immunity and physical-school immunity prevent the child's aura and slow. General aura-state immunity is not imported as part of this change.
|
||||
|
||||
Focused verification passed: 18 tests across source-parent guards, raw defense metadata, real player/companion blocked and successful casts, casting-target interruption, snare/physical immunity, real dispatch rejection and the actual movement multiplier before/after expiry. The generated playable Shield Bash chain retains only rank 72 through level 80; older unbound IDs do not borrow this child. These fixtures use synthetic ordinary NPC encounters.
|
||||
|
||||
Final frozen Cellblock Rush run `20261006-172609059` separately records three actual companion Shield Bash results on Hamhock, event IDs 574/659/777, immediately followed by accepted child 29703 aura grants 575/660/778. This proves live dispatch/application only: no retained slow-state sample measures duration or movement speed. The combined report records the final 126-check set, one-boss clear and integrity/visual evidence.
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
This is a first-pass design audit of the 51 standard WoW dungeons already imported by Healer Man (Classic through Wrath of the Lich King). The map atlas and campaign catalog are the project source of truth for the layouts and encounter names. Three additional imported definitions are Healer Man / Ascension custom dungeons, so they are not part of this WoW pass.
|
||||
|
||||
The owner's current routine test default is the full **Stormwind Stockade**
|
||||
(`stormwind-stockade`); see [the test policy](TEST_DUNGEON_POLICY.md). The
|
||||
Wailing-specific slice questions below remain deferred until the owner explicitly
|
||||
requests that dungeon. They do not authorize a new routine Wailing playtest.
|
||||
The owner's current routine test default is **Stormwind Stockade: Cellblock
|
||||
Rush** (`bite-sized-stormwind-stockade`); see [the test policy](TEST_DUNGEON_POLICY.md).
|
||||
Each run selects one Stockade boss from its shared run ID, so record the boss
|
||||
actually observed. Full-source Stockade campaigns require explicit selection.
|
||||
The Wailing-specific slice questions below remain deferred until the owner
|
||||
explicitly requests that dungeon. They do not authorize a new routine Wailing
|
||||
playtest.
|
||||
|
||||
A good slice should feel like a complete short outing: a clear reason to enter, one strong visual space or route, a handful of combat beats, and one satisfying final encounter. The closest existing model is **Stormwind Stockade: Cellblock Rush**: keep the original environment, retain one route, wall off the side wings, and finish on one seeded boss. Some source dungeons have a scripted event that makes an even better slice, but that event also raises implementation cost.
|
||||
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
# WoW dungeon texture and lighting review — 2026-10-06
|
||||
|
||||
## Coverage and player access
|
||||
|
||||
Three GPT-6 Luna agents at extra-high reasoning reviewed texture imports,
|
||||
lighting inheritance, and shared graphics access. WoW and RoM both use
|
||||
`ProductionDungeon`, `prepareDungeonMaterial`, `applyDungeonMeshGraphics`, and
|
||||
the renderer-scoped KTX2 loader. The Options panel exposes render resolution,
|
||||
1×/4×/16× filtering, Off/Standard/High shadows, and ambient fill for both sources.
|
||||
High follows the camera and enables imported environment/creature shadow casters;
|
||||
Standard retains the lighter explicit scene-object caster policy. Original
|
||||
client lighting/lightmaps are not reconstructed by these controls.
|
||||
|
||||
The isolated asset review loaded all 54 WoW source environments and the default
|
||||
Cellblock Rush slice, using shipped GLB/KTX2 data and production material,
|
||||
filtering, asset-resolution, and directional-light helpers. All 55 entries
|
||||
loaded without runtime errors; every inspected texture received the supported
|
||||
16× filtering level, and High light targets followed the camera. The run
|
||||
generated 271 captures and ten review sheets under
|
||||
`artifacts/playtest/wow-environment-quality/`. Entrance, reverse-entrance,
|
||||
midpoint and final boss positions are asset QA; they do not establish traversal,
|
||||
combat, collision, or full room-by-room coverage.
|
||||
|
||||
## Lighting correction
|
||||
|
||||
`materializeBiteSizedLayout` previously inherited presentation from its fallback
|
||||
baseline even when a randomized/custom selection used a different dungeon.
|
||||
It now uses the selected source's complete presentation, including local point
|
||||
lights, when that baseline belongs elsewhere. Matching baselines retain their
|
||||
deliberate tuning. Explicit `contentSourceDungeonId` takes precedence over the
|
||||
ID-based fallback. The existing six WoW palettes and reviewed Stockade lighting
|
||||
remain the full-source policy.
|
||||
|
||||
## Texture and geometry safeguards
|
||||
|
||||
The WoW optimizer used the default automatic texture/simplification pass and
|
||||
an explicit 2048-pixel texture cap. It now disables both mesh simplification
|
||||
and automatic texture compression/resizing before the separate KTX2 encoder,
|
||||
matching the source-preservation boundary established for RoM. Meshopt and
|
||||
instancing remain enabled. A final packing pass after texture encoding retains
|
||||
`EXT_meshopt_compression`, which the texture CLI otherwise removes. An actual
|
||||
CLI fixture retains a 4096×8 image and
|
||||
1,152 atlas triangles; its simplification control demonstrates topology loss.
|
||||
|
||||
`scripts/dungeon-pipeline/audit-wow-visual-quality.mjs` compares shipped visuals
|
||||
with canonical staged conversion inputs. Its report records image dimensions,
|
||||
codec/role/sampler inventory, source-to-shipped UV metrics, and textured versus
|
||||
untextured material coverage. The authored Wailing Caverns runtime visual is
|
||||
separate from its generated campaign package and must be audited at
|
||||
`src/assets/game/dungeons/wailing-caverns/wailing-caverns-visual.glb`.
|
||||
|
||||
Shadowfang Keep was the substantial source-to-shipped topology regression:
|
||||
397,882 textured triangles versus 465,796 in the conversion input, with 445
|
||||
additional UV-degenerate and 616 additional rank-collapsed triangles. Its
|
||||
bounded repair restores 465,649 measured textured triangles and reduces those
|
||||
added defects to 23 and one, respectively. Remaining differences include
|
||||
packing/quantization tolerances and source-authored UV issues. All 287 texture
|
||||
payloads and dimensions are retained. The final repair is 8,566,408 bytes versus
|
||||
15,987,464 before (about 46% smaller), with the same 103 GPU-instancing nodes.
|
||||
The source-pinned recipe simplifies only untextured `ADT_Terrain` and
|
||||
`ADT_Liquid_B2` fallback primitives, enforcing a 380,000-triangle ceiling.
|
||||
It retains 370,077 such triangles versus 360,207 previously; every textured
|
||||
primitive accessor and source image hash remains unchanged before optimization.
|
||||
Normal Shadowfang regeneration uses this same preprocessor. Collision and
|
||||
navigation are outside this visual fix.
|
||||
|
||||
The installed local visual and regenerated descriptors agree on SHA-256
|
||||
`2c562fb61596a536d728385c4f2bdfdc3230f4f84ef40875b9a568e18a82ef9d`.
|
||||
All 26 collision GLBs and navigation retained identical hashes across the
|
||||
publication step. The asset review then reloaded that installed visual.
|
||||
|
||||
The fully restored source candidate remains a diagnostic artifact: although
|
||||
smaller after packing, it restored unnecessary untextured terrain and increased
|
||||
the sampled rendered triangle count nearly fourfold. The accepted bounded
|
||||
version draws only 7.5–9.8% more triangles than before at the reviewed entrance,
|
||||
Springvale and Arugal viewpoints, with unchanged draw calls (188/131/208) and
|
||||
about 60 FPS in 3-second Edge samples. This is a capped desktop asset-renderer
|
||||
sample, not evidence for actors, physics, sustained gameplay or mobile headroom.
|
||||
The comparison lives under
|
||||
`artifacts/playtest/wow-environment-quality/shadowfang-performance/`.
|
||||
|
||||
## Remaining visual limits
|
||||
|
||||
The audit resolves all 54 actual runtime visuals, including authored Wailing
|
||||
Caverns, with 8,099 KTX2 image entries and no fallback images. Canonical
|
||||
pre-optimization inputs are available for 53 environments; Wailing lacks that
|
||||
matching recovery input. All 7,980 source-matched image dimensions are retained,
|
||||
with no downsized image or 2048-cap hit. These measurements compare conversion
|
||||
inputs, not the raw client image pixels.
|
||||
|
||||
The source comparison found no fleet-wide texture downsize. The current WoW
|
||||
base-color inventory uses ETC1S KTX2; RoM's selective UASTC exceptions are
|
||||
source-specific and have not been indiscriminately applied to WoW. Preserving
|
||||
dimensions does not establish lossless compression or restore native detail
|
||||
that was absent from a conversion input.
|
||||
|
||||
Zul'Farrak, Ahn'kahet, Pit of Saron, and parts of the Caverns of Time captures
|
||||
show broad flat or incomplete-looking terrain. Zul'Farrak's source and shipped
|
||||
images retain all 382 dimensions, with matching textured-triangle counts.
|
||||
Both contain 1,374,820 untextured triangles, dominated by `ADT_Terrain` and
|
||||
`ADT_Liquid_B2` materials. This is a pre-existing conversion/terrain-material
|
||||
gap rather than a texture-resolution failure in the optimizer. Some boss
|
||||
viewpoints face nearby geometry or show empty space, so those captures cannot
|
||||
certify the surrounding room. Preserve the earlier findings in
|
||||
`dungeon-pipeline/WOW_ENVIRONMENT_REVIEW.md`.
|
||||
|
||||
## Verification and reproduction
|
||||
|
||||
The combined focused scene, graphics, lighting, water and bite-sized suite
|
||||
passed 118 tests. The pipeline fixtures passed five checks covering source
|
||||
dimension/topology preservation, safe material coverage, selective fallback
|
||||
simplification and descriptor preflight. The water loader includes a type-only
|
||||
clarification of GLTFLoader's primitive association index, which the installed
|
||||
`GLTFReference` declaration omits.
|
||||
|
||||
The normal Options smoke used a frozen copy of the last available production
|
||||
bundle. It entered Cellblock Rush, observed Bazil Thredd's intro, selected 200%
|
||||
resolution, 16× filtering and High shadows/fill, and carried the settings into
|
||||
Forsaken Abbey. Canvas scales were 1.5 by default and 2.0 for both High entries,
|
||||
with no page errors. Evidence and exact bundle identities are in
|
||||
`artifacts/playtest/graphics-options/run-wow-access-2026-10-06/`. That bundle is
|
||||
not proof of this task's new source lighting correction.
|
||||
|
||||
The final freshly built bundle was then frozen and checked separately in
|
||||
`artifacts/playtest/graphics-options/run-wow-current-build-2026-10-06/`.
|
||||
Its entry is `index-BvFyaleo.js`, built at `2026-10-06T17:39:29.274Z`.
|
||||
It also selected Bazil Thredd, verified the four quality controls and carried
|
||||
200% resolution into Forsaken Abbey with zero page errors. Root inspected the
|
||||
Options, WoW High and RoM High captures; textured surfaces and actor silhouettes
|
||||
are visible. This is an entry/settings smoke rather than encounter validation.
|
||||
|
||||
The final normal production build passes TypeScript, Vite, precompression and
|
||||
release-bundle verification. Texture/performance prebuild audits pass, including
|
||||
106 visuals, 12,892 KTX2 images, zero fallback textures, and no performance-audit
|
||||
regressions. The release candidate hygiene check passes including untracked
|
||||
files. Earlier concurrent source errors were resolved before this final build.
|
||||
This pass does not deploy a production build.
|
||||
|
||||
```text
|
||||
node scripts/dungeon-pipeline/audit-wow-visual-quality.mjs
|
||||
node --test scripts/dungeon-pipeline/optimize-environment.test.mjs scripts/dungeon-pipeline/audit-wow-visual-quality.test.mjs scripts/dungeon-pipeline/build-shadowfang-selective-visual.test.mjs scripts/dungeon-pipeline/apply-wow-visual-optimization.test.mjs
|
||||
node scripts/dungeon-pipeline/serve-environment-preview.mjs
|
||||
node scripts/playtest-wow-environments.cjs
|
||||
node scripts/dungeon-pipeline/make-environment-review-sheets.mjs
|
||||
node scripts/playtest-wow-visual-performance.cjs
|
||||
node scripts/playtest-graphics-options.cjs --output-dir artifacts/playtest/graphics-options/<new-run>
|
||||
npm run release:check
|
||||
```
|
||||
|
||||
The preview server disables file watching so unrelated native build outputs
|
||||
cannot terminate it. `--resume` continues incomplete asset captures; specifying
|
||||
dungeon IDs refreshes those entries while preserving the other results.
|
||||
Reference in new issue
Block a user