Update Healer Man server
This commit is contained in:
1 parent
39458d5de6
commit
6cc1b9217f
203 files changed
+133929
-31271
No files matched your search
@@ -228,3 +228,10 @@ The earlier fresh-dist Turtle UI checkpoint passed in a loaded scene at 390×844
|
||||
Final Cat UI QA on the exact final production build passed for native family/reaction selectors, mouse Stay/Follow, Growl, encounter lock, and Cat persistence after reload while a second character remained Wolf. In the final narrow view, the party row ended at y=269 and the selector card spanned y=306–420 (37px clearance); there was no top-right overlap or horizontal overflow, and the canvas was loaded. Escape opened pause, Spellbook opened, the actual Call Pet entry was clicked, and the overlay closed with Cat still present. This verifies that activation route, not summoning after the pet is absent. Revive was untested because the pet did not die. No live Rake/Prowl cast or Cat model appearance was verified; the only console error was favicon 404, with no page or HTTP errors.
|
||||
|
||||
The initial clean-baseline check reproduced four assertions: Divine Punishment produced an extra catalog entry, God's Vengeance lacked its expected proc, the Mage/Druid elite milestone repeated 25 instead of advancing to 30, and Speed Catalysis restored no Energy. All four assertions now pass in the current aggregate, as do the catalog/count assertions. The initial outcomes remain historical; the current status is in [the follow-up report](MECHANICS_BACKLOG_FOLLOWUP_2026-10-02.md). The full `npm test` suite and all-class balance sweeps were not run. Focused tests validate only their named paths and do not certify every ability or talent.
|
||||
|
||||
|
||||
## 2026-10-03 — Native RoM combat follow-up
|
||||
|
||||
The requested five identities now share native source amount dispatch and exact-pair rotation policies across the active player and party NPCs. Ordinary RoM NPC pools contain only those five classes; explicit configured factories retain the broader catalog for targeted work. Native-mode health budgets are independent of the preserved WoW-stat RoM curve. The fixed full-player diagnostic completed 80 pulls with no deaths or invalid casts; this does not certify scene encounters or promote readiness.
|
||||
|
||||
Focused native integration, stat-mode compatibility, party, source catalog, Ready-five, and avatar checks passed. The separate `combatRotation.test.ts` still has one existing unsupported-only Rogue Killing Spree signature assertion failure (30/31 pass); this RoM pass does not implement Combat Rogue. The full suite/all-class balance sweeps were not run. Source boundaries and final build/browser evidence are recorded in [the combat report](ROM_NATIVE_COMBAT_PASS_2026-10-03.md) and `PLAYTEST_NOTES.md`.
|
||||
@@ -1,6 +1,16 @@
|
||||
# Active Class Mechanics Backlog
|
||||
|
||||
Updated 2026-10-03. 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-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.
|
||||
|
||||
## Targeted follow-up (2026-10-04)
|
||||
|
||||
- [x] Correct pinned AzerothCore creature-immunity foreign-key decoding. Lady Anacondra is Fear/Horror immune, not Silence/Interrupt immune; the source-registered Lightning Bolt regression now cancels under Vow of Silence. Actual Silence/Interrupt-immune creatures retain protection. See [the audit](VOW_OF_SILENCE_AUDIT_2026-10-04.md).
|
||||
- [x] Verify Vow against Lady's actual scheduled Lightning Bolt and the full 8.4-second silence window. The live check exposed Nature Thorns bypassing spell-kind-only selection because its source delivery is melee; the corrected school/kind gate suppresses new magic casts while preserving physical attacks. Final-build replay confirms cancellation, no nonphysical cast during the status and natural Nature cast resumption after expiry. See [the live report](ROM_VOW_LIVE_FINAL_2026-10-04.md) and [cast-gate source note](ENEMY_SILENCE_CAST_GATE_2026-10-04.md). Boss Testing proof is separate from normal campaign/full-clear coverage.
|
||||
- [x] Diagnose owned native Priest sustain at levels 60/80 across six consecutive-pull/rest scenarios. All clear without deaths or empty healer Mana; effective healing, overheal and actor attribution are recorded separately. No recovery or healing-AI tuning was justified. See [the audit](ROM_NATIVE_SUSTAIN_AUDIT_2026-10-04.md).
|
||||
- [x] Audit the Killing Spree representative-signature failure. Spell 51690 is a source periodic-dummy selector with a dedicated player `class-script` handler; the test now checks that exact mechanism while preserving the ten-strike runtime regression. Correct the player damage aura from 1% to the linked DBC child 61851's 20% for two seconds. See [the audit](WOW_KILLING_SPREE_AUDIT_2026-10-04.md).
|
||||
- [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).
|
||||
- [ ] Reconcile Blood Arrow's current CoA base toggle and per-offensive-ranged-skill cost contract with local 490434. The passive rider is current; the base aura still uses the local 30-second/periodic-HP-cost behavior. Current general and Knight/Scout active identities differ, so do not silently replace one with the other. See the five-class report's remaining base-contract section.
|
||||
|
||||
## Native stat input update (2026-10-03)
|
||||
|
||||
@@ -221,3 +231,20 @@ RoM characters now retain an independent stat ruleset: existing saved characters
|
||||
- [ ] Keep the next-Curse instant-cast rider and full Shield Form/Rune Overload target behavior open until their transform, child-state, and target-processing contracts are complete.
|
||||
- [x] Confirm Rune Overload's RuneWaker identity before comparing it with current CoA: the local generated catalog maps 498572 to Rune Overload and 498571 to Remodeled Body, while the [current CoA Champion/Rogue list](https://chroniclesofarcadia.com/en/wiki/skills/list/10-3) maps 498571 to Rune Overload and 498572 to Runecraft - Haste. The current page and patch history describe a later skill revision; preserve the local RuneWaker names, costs, and values rather than crossing the ID collision.
|
||||
- [ ] Wire local Rune Overload (498572)'s one-second on-time child tick into player and companion runtime. Catalog work now resolves hidden MagicCollect 498574 from component 621243 as a 0.6 physical-damage coefficient and removes the unsupported 10-yard radius heuristic; the isolated catalog/resolver tests pass (16 tests across the hidden-child and Champion runtime files). RuneWaker component 621241 supplies the one-second `onTimeMagicId` link, but runtime has no autonomous consumer for it; the periodic proc path only receives existing DoT/HoT ticks. The local tooltip says the child hits nearby targets, but the source has no numeric radius or target cap, so target selection remains unresolved and must not be guessed.
|
||||
|
||||
|
||||
## 2026-10-03 — Native RoM five combat and rotations
|
||||
|
||||
- [x] Route source-bound native HolyHeal and supported positive magical DotMagic healing through player and companion consumers, including effective Holy Blessing Wisdom and recipient absorption once. Actual player/NPC Heal, Urgent Heal, and Regenerate regressions pass.
|
||||
- [x] Use verified source attack and automatic training-weapon channels for the five active native builds, with explicit unsupported-component/custom-gear fallback. The resolution follow-up adds native source defense, hit/avoidance and critical consumers for exact imported NPCs; unsupported source inputs retain the shared fallback.
|
||||
- [x] Add exact-pair native rotations, emergency/group triage, actor/target-owned periodic refresh, and conditional setup/AoE decisions. Public KittyCombo/CoA research informs clean-room policies; the add-on archive was blocked by a Cloudflare challenge, so no imported presets are claimed.
|
||||
- [x] Run the requested fixed full-player/four-NPC cohort at levels 1/10/30/60/65/66/79/80 against Barren Caves trash and Anglo. All 80 pulls finish without player/NPC deaths or invalid casts. Native-only health budgets give 4.5–9-second trash and 39–53.4-second Anglo pulls in this static diagnostic. Scene mechanics and movement are outside the diagnostic.
|
||||
- [x] Restrict ordinary RoM companion generation to Knight, Priest, Rogue, Scout, and Mage; explicit configured builds remain constructible for targeted work.
|
||||
- [x] Add source-negative HP/HP_Per DotMagic application snapshots and ticks for native player, native companion and imported enemy consumers. Source tick defense/resistance is snapshotted once; current MaxHP is read for HP_Per ticks.
|
||||
- [x] Add native source target-defense/hit/critical consumers, exact per-actor mode dispatch, active-five Throw/ShieldDef inputs and real target-count/ordinal falloff. Keep unsupported source/gear branches explicit.
|
||||
- [x] Retain enemy damage calculation, attack kind and elemental school independently for WoW and RoM, with source-ID namespaces, DBC school masks and authored fallbacks for missing/non-damaging source rows.
|
||||
- [x] Resolve supported native NPC equipment and exact fixed/recipient-MaxHP enemy packets; test Anglo movement, interruption, control targeting and player/NPC dispels. Measure enemy damage separately from ability health costs and calibrate the native shared-damage budget through level 80. Source/manual packets bypass that budget. The recovery/equipment follow-up implements source ReHP/ReMP and resolves all 440 imported NPC defaults; unsupported formula shapes and broader sustain certification remain open. See [the enemy/encounter pass](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md), [recovery source audit](ROM_NATIVE_RECOVERY_SOURCE_2026-10-03.md), and [equipment completion](ROM_NATIVE_NPC_EQUIPMENT_COMPLETION_2026-10-03.md).
|
||||
- [x] Implement native source ReHP/ReMP for player/owned NPC actors, resolve all 440 imported NPC equipment defaults, preserve compatibility boss mechanic windows, and correct early native weapon-start/Mana-spending decisions and training budgets. The final fixed 80-pull cohort passes without deaths/invalid casts; see [the recovery/equipment/pacing follow-up](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md).
|
||||
- [ ] Complete remaining unsupported source shapes and broader native combat parity before any readiness promotion. RoM builds remain Needs Testing. Level cap stays 80; no loot wiring or readiness promotion.
|
||||
|
||||
See [the original implementation report](ROM_NATIVE_COMBAT_PASS_2026-10-03.md) and [the native resolution and damage-type follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md). The earlier pacing numbers above describe the historical amount-only diagnostic; the follow-up records the final native-resolution run.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Character equipment appearance
|
||||
|
||||
The shared `src/avatar/CharacterModel.tsx` renders the player, party NPCs,
|
||||
roster, and creator. Equipment appearance is presentation-only; it never
|
||||
changes item ownership, stats, or progression.
|
||||
|
||||
## WoW and Ascension
|
||||
|
||||
`src/avatar/equipmentAppearance.ts` keeps exact appearances for the packaged
|
||||
Wailing Caverns drops. Unmapped armor, including synthetic heirlooms, gets a
|
||||
representative native WoW appearance by equipment slot and armor type. Empty
|
||||
preview slots receive starter clothing: chest, legs, boots, gloves, shoulders,
|
||||
and cloak. Cloth uses a robe, leather uses leather armor, and heavy armor uses
|
||||
the packaged mail breastplate. These are visual defaults, not exact item skins
|
||||
for every entry in the loot catalog.
|
||||
|
||||
Real equipped appearances override the starter appearance in their slot.
|
||||
The body atlas layers remain ordered so robes override the trouser geoset.
|
||||
Appearance cache keys include class, item slot, and armor type.
|
||||
`src/ui/CharacterPreview3D.tsx` passes the saved player's equipped inventory
|
||||
items into the same renderer used in the dungeon.
|
||||
Loaded preview attachments request a bounds refit when their optional models
|
||||
finish loading, so larger native staffs stay inside the roster preview.
|
||||
|
||||
## RoM
|
||||
|
||||
The native shared-skeleton character GLBs contain original RoM starter
|
||||
garments. `scripts/runewaker-pipeline/recipes/player-starter-appearance.tsv`
|
||||
selects `cloth010-001` for torso, hands, legs, and feet instead of the bare
|
||||
`body000-001` defaults. This common starter outfit is currently shared across
|
||||
classes; individual RoM armor drops do not yet replace those modular parts.
|
||||
Rebuild all five supported race/gender rigs with
|
||||
`npm run runewaker:players:avatars`.
|
||||
|
||||
`src/avatar/runewakerEquipment.ts` resolves original RoM starter sword, mace,
|
||||
shield, staff, bow, and dagger props from
|
||||
`public/assets/equipment/runewaker-v1/`. Equipped weapon types select the
|
||||
appropriate representative source prop. Exact skins for arbitrary equipped
|
||||
RoM weapons are not implemented. WoW texture atlases and WoW item models must
|
||||
not be applied to the native RoM rigs.
|
||||
|
||||
Rebuild the props with:
|
||||
|
||||
```text
|
||||
node scripts/runewaker-pipeline/build-population.mjs --recipe scripts/runewaker-pipeline/recipes/runewaker-starter-weapons.json --actors-only
|
||||
```
|
||||
|
||||
The generated import manifest records the source ROS path, source SHA-256,
|
||||
output SHA-256, bounds, and triangle count for each prop. Converted source
|
||||
props retain the RoM socket frame; the WoW-to-RoM procedural fallback rotation
|
||||
must not be applied to them.
|
||||
|
||||
## Packaging and validation
|
||||
|
||||
All equipment files belong to the bundled `core:equipment` content pack.
|
||||
RoM character rigs belong to the optional `characters:runewaker-v1` pack.
|
||||
Refresh local content with `npm run content:publish` after regenerating assets.
|
||||
Existing installations must refresh their content packs to receive changed rigs.
|
||||
|
||||
Each optional item retains its own Suspense/error boundary and procedural hand
|
||||
fallback. Missing item assets cannot hide the body or other equipment.
|
||||
|
||||
- `npm test -- --run src/avatar`
|
||||
- `npm run build`
|
||||
- `node scripts/playtest-party-equipment.cjs` after building and refreshing content
|
||||
- Review roster and dungeon screenshots in `playtest-artifacts/party-equipment/`
|
||||
- Record visual findings in `PLAYTEST_NOTES.md`
|
||||
- `npm run release:check`
|
||||
@@ -22,9 +22,13 @@ Native derived calculations are sourced from the local RuneWaker `RoleAttr.cpp`
|
||||
|
||||
Equipped native items carry `ItemStats.romNative`. Their common WoW projection is not counted again. Foreign items without that payload bridge only direct Strength, Stamina, Intellect, Agility, and flat health/mana under an explicit simulator policy. Spirit does not become Wisdom; WoW armor, attack/spell power, weapons, and ratings do not become native channels. The five existing source-reference heirloom classes supply native gear curves; other classes retain the direct-stat fallback until native gear profiles are sourced. Reference item selection and intermediate-level interpolation remain synthetic simulator policies.
|
||||
|
||||
The existing dungeon combat resolver remains a shared simulator. Adapting a verified native stat into a common combat field does not establish that the WoW damage, hit, armor, or critical formulas reproduce RoM combat. Native healing inputs alone also do not certify every RoM healing spell's amount, rank, or coefficient.
|
||||
The RoM automatic fallback is displayed as Training gear, not an authentic heirloom system. Player and NPC training gear scales through level 79; character base growth continues through level 80. See `docs/ROM_FIVE_NATIVE_SCALING_2026-10-03.md` for the five-class follow-up, owner parity, enemy health policy, and validation. This does not introduce loot progression.
|
||||
|
||||
The explicit common adapter uses native ATK as attack/ranged attack power, MDMG as spell power, and DEF as armor. Physical mitigation uses the existing shared WoW armor curve. MATK, MDEF, DMG, native recovery values, and hit/critical/dodge/parry points remain source-semantic sidecar/display fields; native point values are not converted into common percentages. Native common hit/critical/avoidance percentages start at zero. Existing primary resource types and regeneration policy remain part of the shared dungeon simulation; native MP derivation also supplies supported secondary mana pools. The Equipment panel identifies the shared combat boundary, labels point fields explicitly, and shows active native aura effects for its selected owner. Shared HUD counters display whole HP/MP values while their accessible maxima and runtime pools retain source precision.
|
||||
The follow-up's exact-dist check supersedes the browser artifacts at the shared `playtest-artifacts/stat-rulesets` path. Its final chunks and eleven screenshots are recorded in that follow-up; the validation totals below describe the original stat-ruleset implementation.
|
||||
|
||||
The dungeon combat system selects native source resolution for supported canonical RoM builds against exact imported RuneWaker NPCs, in either direction. Unsupported source inputs and WoW-mode actors retain the shared compatibility resolver. Adapting a native stat into a common field alone is not evidence of native formula parity. The latest [native resolution follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md) records supported channels and remaining source boundaries.
|
||||
|
||||
The common fallback adapter uses native ATK as attack/ranged attack power, MDMG as spell power and DEF as armor, with shared WoW mitigation only on that fallback. The supported native resolver directly consumes source ATK/DEF or MATK/MDEF and native hit/critical/dodge/parry/block points without converting them into common percentages. Existing primary resources and regeneration policy remain part of the shared simulation; native MP also supplies supported secondary mana pools. The Equipment panel labels native points explicitly and shows active native aura effects for its selected owner. DEF displays its source value without presenting a WoW armor percentage as native mitigation. Shared HUD counters display whole HP/MP values while runtime pools retain precision.
|
||||
|
||||
Player FIX record 303001 sets `DmgAtkArg` and `MDmgMAtkArg` to zero, so this source version derives DMG/MDMG from flat gear channels rather than ATK/MATK. Its `Dmg_HealArg` is **0.5**. Wisdom/MND, MDMG, MPow, HealPowerRate, HealPoint, and target heal-modifier inputs now have explicit source channels. Per-spell OrgPower, rank/skill-level evaluation, timing, flags, and the complete native healing consumer remain separate work. These local RuneWaker records do not certify current-CoA formulas or balance.
|
||||
|
||||
@@ -44,3 +48,13 @@ The character, party member, and combat actor retain their own ruleset. No globa
|
||||
- Browser evidence: `playtest-artifacts/stat-rulesets/results.json` and its ten referenced screenshots. The checked chunks were `index-CGkT8hBz.js`, `combatStore-CVXgxk1Z.js`, and `PartyFrames-BeW5_TCA.js`. Synthetic engaged-mob and online-activity fixtures verify the menu guards, not a real multiplayer session.
|
||||
- Final `npm run release:check` passed for 157 changed paths, including untracked files and concurrent unrelated work. Final documentation and owned vault notes satisfy text-file hygiene.
|
||||
- No full repository suite, all-class balance sweep, RoM readiness promotion, matchmaking, or deployment was performed.
|
||||
|
||||
## Native combat amount follow-up (2026-10-03)
|
||||
|
||||
This section records the original amount-only pass. Its open native hit/defense/periodic and target-context boundaries are superseded by [the native resolution and damage-type follow-up](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md), which also records the newest pacing and browser evidence.
|
||||
|
||||
`romAbilityCatalog.ts` now carries explicit `romNativeSource` skill/component identities into bound effect amounts. `romNativeCombatAmount.ts` dispatches supported native direct damage, direct HolyHeal, and periodic HolyHeal snapshots from `equipmentAdjustedCombatAmount`; an unsupported source binding or required gear profile leaves the existing shared HealerMan amount fallback in place. Native `MagicProc.MagicLv` currently uses character level clamped to 1–80 as a simulator rule. Active five-build companion casts use the player-build source branch even when the owner is a party NPC.
|
||||
|
||||
Direct HolyHeal now uses the source OrgPower/MND/MDMG/MPow/HealPowerRate/HealPoint path with mean variance. Recipient HealAbsorbRate and flat HealAbsorb are applied once at the actual target, then existing generic combat-result stages resolve criticals and overheal. Periodic HolyHeal uses its separate source DotMagic rank correction and snapshots the integer tick amount when applied; player and NPC targets reuse that fixed tick snapshot. Source auto profiles cover player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks, with NPC Rogue offhand. Player Rogue offhand handling requires an explicitly present equipped inventory item. Player Scout Shot uses the native direct-damage route for its actual bound Shoot hit, not a continuous native bow-auto profile. Caster ambient basic attacks retain generic timing and MDMG policy. Player melee haste explicitly reads the existing common aura because native stat re-derivation does not populate common haste fields. Element-specific MPow/BodyRate, unsupported source components, native hit/avoidance point consumption, complete native defense/variance resolution, and full source combat parity remain open. The damage consumer declines share-damage and target-ordinal decrease branches until runtime supplies exact target-count context. Custom/unverified gear cannot enter the source direct-damage training-weapon route and keeps the shared fallback.
|
||||
|
||||
The five exact-pair rotation and final full-player diagnostic are tracked in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md). The post-haste-retention report covers 80 fixed pulls at levels 1/10/30/60/65/66/79/80: all cleared with zero player/NPC deaths and zero invalid casts; trash took 4.5–9 seconds and Anglo 39–53.4 seconds. The scoped health factor applies only to native-stat RoM and leaves legacy WoW-stat RoM, WoW/CoA-origin health, enemy damage, and the level-80 cap unchanged. Source-damage follow-up passed 13 cases: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and four actual auto/source-action cases for player Knight main hand, NPC Scout bow, NPC Rogue offhand, and player Scout Shot. Player Rogue offhand handling requires an explicitly equipped inventory item. Player Scout Shot uses the native direct-damage route for its bound Shoot hit. Caster ambient basics keep generic timing/MDMG policy. Final production build and TypeScript project check passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed with 11 screenshots captured and four representative roster, dungeon, NPC-stat, and mobile screenshots visually reviewed. Current chunks were `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`; there were no page/server errors and the network response-errors list was empty, with only the optional existing favicon 404 in the console. A release check passed on 249 paths; the final docs update requires the final hygiene/release check. The earlier 60-sample, six-level report is retained as a historical baseline. The ordinary randomized companion pool is now restricted to the active five identities while the configured factory is broader; no pool/readiness promotion is included. No loot wiring, level-cap increase, or legacy/global enemy-HP retune is included.
|
||||
@@ -0,0 +1,187 @@
|
||||
# First Conquest of Azeroth party
|
||||
|
||||
Updated: 2026-10-04. 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.
|
||||
|
||||
| Seat | Class | Initial specialization | Responsibility |
|
||||
| --- | --- | --- | --- |
|
||||
| 1 | Guardian | Vanguard | Tank |
|
||||
| 2 | Witch Doctor | Brewing | Healer |
|
||||
| 3 | Barbarian | Brutality | Melee damage |
|
||||
| 4 | Ranger | Archery | Ranged damage |
|
||||
| 5 | Pyromancer | Incineration | Caster damage |
|
||||
|
||||
Begin with each class's core kit and the selected specialization so the full
|
||||
party can enter targeted playtests early. Finish the remaining trees within
|
||||
these five classes before expanding to the other classes. This selects work;
|
||||
it does not certify the current implementations.
|
||||
|
||||
## Implementation order and acceptance
|
||||
|
||||
1. Freeze the five class/spec identities and reproducible diagnostic inputs.
|
||||
Inventory every node, rank, source spell, and current runtime mapping. Author
|
||||
reviewed talent allocations instead of treating generated role-weighted
|
||||
allocations as an intended CoA build.
|
||||
2. Establish the tank and healer loops together, including their resource and
|
||||
persistent state. Check damage, mitigation, threat, healing recipients,
|
||||
periodic effects, and party utility against the captured evidence.
|
||||
3. Implement the three distinct damage loops and their talent interactions.
|
||||
Share combat primitives where their semantics match, while keeping class
|
||||
state and learned-rank ownership on the correct actor.
|
||||
4. Test the same party against explicitly selected encounters. Repeat with
|
||||
each class as the active player and the other four as companions. Include
|
||||
single-target and multiple-target pulls, incoming party damage, interrupts,
|
||||
dispels, cooldown use, resource exhaustion, death, and resurrection where
|
||||
the selected kits provide them.
|
||||
5. Fix observed mechanic and AI defects, then inspect live dungeon play and
|
||||
record evidence in `PLAYTEST_NOTES.md`. Compare balance only after mechanic
|
||||
correctness. Expand the selected classes' other trees before other classes.
|
||||
|
||||
The completion gate is verified behavior for the reviewed core/initial-tree
|
||||
builds on players and companions, a coherent 1-tank/1-healer/3-damage party in
|
||||
live playtests, and an explicit record of any unresolved source limitations.
|
||||
Catalog counts, a boss kill, or passing preparation tests are insufficient.
|
||||
|
||||
## Source-backed priorities
|
||||
|
||||
The following anchors are from the August Vol'Jin capture in
|
||||
`src/game/coaLiveData.generated.json`. They identify work to verify; they are
|
||||
not claims that these mechanics are implemented.
|
||||
|
||||
- Guardian: Footman's Calling (node 4019, spell 92105) establishes formation
|
||||
behavior; Vanguard's Shield (34417, 804383) builds stacks through blocks and
|
||||
auto attacks; Paragon (29969, 706514) transforms Heavy Blow at 10 stacks and
|
||||
interacts with Brace. Audit formation gates, actor-owned stacks, block events,
|
||||
threat, and defensive sequencing together.
|
||||
- Witch Doctor: Cauldron Brewer (4005, 92085), Ingredient: Jungle Shrooms
|
||||
(12645, 801660), Potion Toss (12646, 801661), and Mixologist (6645, 561069)
|
||||
establish cauldron/ingredient state, nearby ally effects, and ingredient-based
|
||||
changes to a targeted heal. Verify recipient, radius, periodic cadence,
|
||||
ingredient exclusivity/capacity, and healing formulas before adding interactions.
|
||||
- Barbarian: Decapitate (5744, 804414) requires a target below 35% health and
|
||||
converts additional Energy into damage; Beheader (6744, 705222) refunds Energy
|
||||
after an eligible kill; Battle Rhythm (14303, 800193) generates Energy on
|
||||
ability critical hits. Verify event origin and payment/refund ordering.
|
||||
- Ranger: Precision Shot (31178, 500075), Hunting Shot (29660, 801191), and
|
||||
Masterful Archery (7794, 680469) depend on Advantage, Elude, ricochet hits,
|
||||
and stacking effects. Audit the state and target selection before AI priorities.
|
||||
- Pyromancer: Ignite (6985, 800791), Combustion (29854, 520884), and Pyroclasm
|
||||
(7174, 520019) depend on Heat, Embers, and the caster's burning effects on a
|
||||
specific target. Verify periodic generation, spending, effect counting, and
|
||||
effect consumption. The August Agonizing Burns/Timed Attacks payload exchange
|
||||
also requires explicit saved-build review.
|
||||
|
||||
Current generated resource profiles and generic effects do not prove these
|
||||
stateful loops are supported. Unspecified proc timing, missing coefficients,
|
||||
and unknown server rules remain evidence gaps; never invent their values.
|
||||
Use the cached Vol'Jin capture and global Spell data described in
|
||||
[COA_REFERENCE_PIPELINE.md](COA_REFERENCE_PIPELINE.md).
|
||||
|
||||
## Repeatable preparation and targeted diagnostics
|
||||
|
||||
`src/game/coaFirstPartyRoster.ts` owns the exact roster. The benchmark helper at
|
||||
`src/game/benchmark/coaFirstParty.ts` owns build selection, companion construction,
|
||||
and explicitly scoped Balance Lab configurations.
|
||||
`scripts/coa-first-party/prepare.ts` produces the review inventory and five
|
||||
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 -- --level 60 --boss <exact-key-from-list>
|
||||
npm run coa:party:test
|
||||
```
|
||||
|
||||
Preparation writes ignored local artifacts to
|
||||
`artifacts/coa-first-party/level-60/`: `audit.json`, `audit.md`, `config.json`,
|
||||
and `seat-1.json` through `seat-5.json`. It records the source capture/hash,
|
||||
legal generated talent allocations, source gaps, and runtime representations.
|
||||
Every mechanic begins as `needs-review`; mapping is not verification.
|
||||
It downloads nothing and runs no encounter simulations.
|
||||
|
||||
Once an explicit diagnostic is appropriate, the existing runtime consumes a
|
||||
prepared configuration without changing the ordinary companion pool:
|
||||
|
||||
```sh
|
||||
npx vite-node --mode balance-lab scripts/balance-lab/runtime.ts simulate --config artifacts/coa-first-party/level-60/seat-2.json --output artifacts/coa-first-party/level-60/seat-2-runs.json
|
||||
```
|
||||
|
||||
Only the selected five and explicitly named bosses belong to this milestone's
|
||||
diagnostics. All five remain **Needs Testing**. Do not change Ready policy,
|
||||
random/eligible pools, default regression scope, or all-class sweep coverage.
|
||||
Ordinary live party generation currently uses the Ready WoW pool, including
|
||||
for a CoA player; a complete CoA party must be configured explicitly.
|
||||
|
||||
For implementation changes, run the smallest affected tests plus the existing
|
||||
Ready-five checks, build, and `npm run release:check`. Record each mechanic's
|
||||
source, player/companion checks, and live evidence as it is completed.
|
||||
|
||||
## Initial implementation and evidence limits
|
||||
|
||||
The first catalog fix exposes sourced active Talent entries for these five
|
||||
classes. Talent Essence purchase type no longer prevents an active spell from
|
||||
becoming a usable action. The action retains its talent-node/rank gate. DBC
|
||||
passive flags and rank metadata keep passive Talent nodes on the existing
|
||||
modifier path; missing DBC rows cannot create a new action. The other 16 classes
|
||||
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.
|
||||
|
||||
Ranger's primary resource is now Focus, matching its spell costs. Player and
|
||||
companion checks cover spending, the displayed/authoritative pool, and recovery.
|
||||
The existing authored 100-point pool and 10-per-second recovery are retained;
|
||||
this correction does not establish source-verified regeneration or implement
|
||||
Advantage/Elude.
|
||||
|
||||
Brewing has specific evidence limits beyond the node-rank source inventory:
|
||||
Mojo Beam's capture describes eight seconds while the selected DBC says four;
|
||||
Spirit Link Idol's tooltip says fourteen seconds while its DBC says 8.5. The
|
||||
current promoted catalog omits the Loa's Blessing empowerment payloads
|
||||
802207/802208/802215/802216 and Spirit in a Bottle's referenced
|
||||
504606/707172 payloads. Resolve those exact references against the local/raw
|
||||
cache before implementing their full behavior. Zero missing node-rank DBC rows
|
||||
does not establish that every mentioned payload or server rule is known.
|
||||
|
||||
## Kickoff validation and diagnostic baseline
|
||||
|
||||
On 2026-10-04, 87 focused tests across 15 files pass, including the exact roster,
|
||||
learned Talent actions, Potion Toss delivery, Decapitate's health restriction,
|
||||
Ranger Focus, source scope, and classic catalog preservation. Ready-five checks
|
||||
pass seven game tests and twenty Python tests. The production build passes
|
||||
TypeScript, asset audits, bundling, compression, and bundle verification.
|
||||
`npm run release:check` passes, including untracked files. A before/after digest
|
||||
also confirms the other 16 CoA action catalogs are unchanged.
|
||||
|
||||
The targeted automated baseline uses the same five generated level-60 builds,
|
||||
seed 1, and Taragaman the Hungerer (`ragefire-chasm/entry-11520`). Each run has a
|
||||
30-second limit and moves only the active player seat. Results after the Focus
|
||||
correction are:
|
||||
|
||||
| Active player | Outcome | Elapsed seconds | Boss health remaining | Deaths |
|
||||
| --- | --- | ---: | ---: | ---: |
|
||||
| Guardian | Time limit | 30.0 | 80,065 | 0 |
|
||||
| Witch Doctor | Time limit | 30.0 | 79,292 | 0 |
|
||||
| Barbarian | Defeated | 12.6 | 0 | 0 |
|
||||
| Ranger | Time limit | 30.0 | 12,782 | 0 |
|
||||
| Pyromancer | Time limit | 30.0 | 14,724 | 0 |
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Enemy Damage Types Audit — 2026-10-03
|
||||
|
||||
## Scope
|
||||
|
||||
This audit follows imported enemy attack damage type data from the WoW 3.3.5a and RuneWaker source catalogs into `EnemyAttackDefinition`, normalization, and combat hit resolution. It records verified source channels separately from HealerMan's single-school runtime representation. It does not claim complete native damage formula coverage.
|
||||
|
||||
## Findings
|
||||
|
||||
The two games use separate numeric spell namespaces. Runtime source lookup is therefore keyed by `(damageOrigin, spellId)`: `wow335` is matched only against the WoW Spell.dbc export, and `runewaker` only against the RuneWaker spell catalog. RuneWaker NPC identity is the imported template/NPC ID (`runewakerNpcId`); it must not be confused with a WoW `serverEntry`.
|
||||
|
||||
For WoW, `scripts/dungeon-pipeline/compile-campaign-catalog.mjs` now retains Spell.dbc `DmgClass` (field 213) and `SchoolMask` (field 225) on parsed source rows and generated enemy attacks. Runtime `attackKind` follows DmgClass where known: 1 → spell, 2 → melee, 3 → ranged. The compact source exporter reads only spell IDs referenced by compiled campaign attacks and WoW boss mechanics, and retains rows with a recognized harmful damage effect. The effect set currently includes 1, 2, 7, 9, 17, 31, 58, 62, and 121. It excludes non-damaging script records even when their DBC school is populated; for example, Call Flames (48258) and Ritual of the Sword (48331) keep authored runtime typing.
|
||||
|
||||
`src/game/mobDamageTypes.ts` converts the seven recognized WoW SchoolMask bits into an ordered list without selecting a “strongest” school. A singleton mask can supply `school`; a composite or unknown mask retains the authored school fallback because combat mitigation still resolves one school per event. Two generated composite examples are Crystalfire Breath (48096, fire + frost) and Death's Bite (67808, frost + shadow). The source list preserves both values, but current combat does not apply two simultaneous school-mitigation passes.
|
||||
|
||||
For RuneWaker, packet class, hit-gate type, and resistance channel are separate source values. `MagicProcess.cpp` branches on `MagicBase.Attack.CalType` for direct damage at line 2322 and again for hit/critical handling around lines 3478–3757. The verified direct packet mapping is CalType 0/3/9 → physical and 1/10 → magical; runtime delivery is 0/9 melee, 3 ranged, and 1/10 spell. Other types (including Throw 2, Fix 4, SpecialAction 7, and FixPer 8) remain unclassified by this compact damage-type layer. They keep raw source metadata and are not guessed into a physical/magical packet class. `MagicCollect.EffectType` is inspected separately for the physical-vs-magic hit gate (`MagicProcess.cpp` around line 1648), while raw `MagicObject.EffectType` is retained for effect semantics; neither is used as the direct packet-class field.
|
||||
|
||||
`MagicResistENUM` in `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` identifies `MagicType` -1 as physical and values 0–5 as Earth, Water, Fire, Wind, Light, and Darkness. The compact catalog keeps this exact `sourceChannel`, independently of `calculationType`: physical remains physical, Earth/Wind → nature, Water → frost, Fire → fire, Light → holy, and Darkness → shadow. The seven-school runtime values are compatibility approximations; the original channel and component ID remain available. Component-specific resolution requires `componentId` whenever a source spell has mixed component classes or channels.
|
||||
|
||||
Two imported counterexamples demonstrate why the old `MagicObject.EffectType` interpretation was wrong. Holy Seal (spell 490149, component 500142) has CalType 0, raw EffectType 0, and MagicType Light (4): it is a physical melee packet on the Light/holy channel. Dark Energy Strikes (spell 498602, component 621306) has CalType 1, raw EffectType 1, and MagicType Darkness (5): it is a magical spell packet on the Darkness/shadow channel. Deadly Water Pressure (490045, component 500056) has unsupported CalType 8; it retains Water/frost, but its packet class is left unclassified. The standard spell catalog now applies the same source-derived class, school, attack kind, and normalized `runewakerEffectType` (0 magic, 1 physical) policy; raw component effect types remain in source metadata.
|
||||
|
||||
`scripts/runewaker-pipeline/build-population.mjs` stamps imported attacks with `damageOrigin: "runewaker"`, the source runtime `attackKind`, and `runewakerEffectType`. Classification is not inferred from the mapped school: a magical projectile can still be ranged. WoW attacks are stamped `damageOrigin: "wow335"` with raw DmgClass and SchoolMask. `normalizeEnemyAttack` uses source records only when the source row contains recognized damage components, so script/control placeholders do not replace manually-authored schools.
|
||||
|
||||
## Periodic damage coverage
|
||||
|
||||
The enemy combat runtime now supports authored `kind: "dot"` attack effects. Application creates a dispellable magic debuff, schedules the first pulse at one interval after cast resolution, and resolves each pulse through the ordinary school mitigation and absorb path. Pulses do not roll a fresh hit, miss, crit, dodge, parry, or block. The final pulse may occur at the aura's exact natural-expiry timestamp. A magic dispel removes future scheduled pulses for that target.
|
||||
|
||||
The focused integration test exercises an enemy Frost DoT against both the player and a party NPC: no damage at cast start or application, one-second pulses, exact-expiry final tick, and cancellation of the player's remaining ticks after a magic dispel. This verifies the scheduler and event school path. It does not claim that source-native RuneWaker DoT amount snapshots are wired to every NPC yet; those require an exact imported NPC/source-skill/component binding and the native formula's additional source/target inputs.
|
||||
|
||||
## Source provenance and generated data
|
||||
|
||||
- Current compact export contains 1,653 WoW candidate IDs, 671 WoW damage-spell rows, and 471 rows with direct-damage effect 2. It also contains 3,199 RuneWaker catalog spells and 1,342 exported source spells with 1,398 direct-HP-damage components. Of those components, 512 map to physical packet class, 284 to magical packet class, and 602 have an unsupported/unclassified CalType (including types 2, 4, 7, and 8). The WoW exporter excludes RuneWaker-origin boss mechanics before looking up numeric IDs in the DBC.
|
||||
- WoW binary source: local WotLK 3.3.5a `Spell.dbc` at `../wow-pvt-server-backups-2/wow335a/Data/patch-A.MPQ/DBFilesClient/Spell.dbc`; SHA-256 `57011d528fd66cf39f5ab6fb168e389ab9e4cc1b8050f7201a54239d489b415c`, 234 fields and 936-byte rows.
|
||||
- WoW field layout reference in the exporter: AzerothCore `DBCStructure.h`; fields consumed are DmgClass 213, SchoolMask 225, and Effects 71–73.
|
||||
- RuneWaker source enum: `SourceCodeVS2019/Libraries/Union/RoleData/ObjectStruct.h` (`EM_MagicAttackCalBase` around line 3967 and `MagicResistENUM`). Direct packet and hit/critical dispatch are in `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp` (direct formula around line 2322, hit/crit dispatch around lines 3478–3757; `MagicCollect.EffectType` hit gate around line 1648). The generated spell snapshot and compact catalog preserve the source calculation type, raw effect type, channel, and component identity.
|
||||
- RuneWaker spell source catalog: `scripts/runewaker-pipeline/snapshots/runewaker-npc-spell-catalog.json`; current SHA-256 `8a6a5a1629db66dd8df02a559ed01c0f5f746a5bb2112093b5223474be5997ed`.
|
||||
- Regenerate compact source metadata with `node scripts/dungeon-pipeline/export-enemy-damage-types.mjs` after refreshing source spell catalogs.
|
||||
|
||||
## Focused verification
|
||||
|
||||
The focused run passed 26 tests across `mobDamageTypes.test.ts`, `enemyDamageTypes.integration.test.ts`, `enemyAttacks.test.ts`, and `enemyCasting.test.ts`. The tests include actual RuneWaker catalog counterexamples and confirm that exact component metadata replaces stale imported attack kind/school during normalization; the integration suite also records Frostbolt and RuneWaker physical-hit events plus the authored periodic lifecycle described above.
|
||||
|
||||
## Formula-specific follow-up
|
||||
|
||||
The compact exporter also preserves `directFormula` and `formulaMitigation` separately from packet class, raw component EffectType and resistance channel. Exact NPC-bound CalType 4/8 direct packets now use `romNativeEnemyDamage.ts`; the formula's source absorber does not imply a physical/magical packet class or generic DEF/resistance pass. CalType 2 remains source-audited but has no exact imported NPC binding or post-combat-table completion hook. See [the manual enemy formula audit](ROM_NATIVE_ENEMY_DAMAGE_SOURCE_2026-10-03.md) and [the encounter/pressure report](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md).
|
||||
|
||||
## Remaining limits
|
||||
|
||||
- Runtime mitigation still stores one school per damage event. Composite WoW masks are source-preserved and currently use the catalog's authored single-school fallback in combat.
|
||||
- RuneWaker CalType 2/4/7/8 and any other unmapped calculation type do not receive a packet class in this exporter. Exact manual CalType 4/8 consumers use the separate formula metadata; unsupported formula/source branches retain their authored fallback.
|
||||
- RuneWaker channel-to-runtime-school translation is approximate by design; retain raw channel/effect type for future exact resistance work.
|
||||
- Native RuneWaker enemy DoT amount resolution is source-bound, not name-derived. Until the matching binding and required inputs exist for an NPC spell, its authored generic periodic amount remains the documented fallback.
|
||||
- Unclassified DBC effect IDs, non-damage/script effects, unknown school-mask bits, source rows absent from the local databases, and effect/component interactions outside the importer scope remain authored or unsupported rather than guessed.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Enemy Silence Cast Gate — 2026-10-04
|
||||
|
||||
## Finding
|
||||
|
||||
Lady Anacondra's imported spell 8148 is Thorns. The generated Wailing Caverns reference records it as a cast-targeted Nature aura from SmartAI row 4 (`Lady Anacondra - In Combat - Cast Thorns`): `school: nature`, `delivery: melee`, `animation: cast`, and `effect.kind: aura`. The source entry has no `attackKind` or `damageClass`. Since `enemyAttackKind` falls back to `melee` for `delivery: melee`, the previous selection rule (`silenced && attackKind === "spell"`) allowed Thorns to start while Silence was active.
|
||||
|
||||
The same Lady Anacondra reference contains spell 9532 Lightning Bolt as a Nature projectile cast from SmartAI row 1 (`Lady Anacondra - In Combat - Cast Lightning Bolt`). Existing active-cast handling already cancels nonphysical casts when Silence takes effect.
|
||||
|
||||
## Runtime change
|
||||
|
||||
Enemy attack selection now rejects an attack during Silence when its school is nonphysical or its resolved attack kind is `spell`. This uses school and attack kind only for silence eligibility. It leaves shared attack-kind and damage-roll classification unchanged, allows physical melee and ranged attacks, and still suppresses a physical-school attack explicitly classified as a spell.
|
||||
|
||||
## Focused coverage
|
||||
|
||||
`src/game/enemyCasting.test.ts` uses Lady Anacondra's generated source entries for Thorns 8148 and Lightning Bolt 9532, plus the imported physical melee Tendon Rip. It checks that Lightning Bolt cancels when Silence lands, Thorns neither starts nor resolves over repeated advances in the 8.4-second window, Thorns starts and resolves after Silence expires, physical melee and ranged attacks remain eligible, and physical spells remain blocked. The imported NPC ability data has no separate silence-prevention field; for Thorns it also carries no `attackKind` or `damageClass`, so the test exercises the exact school/delivery ambiguity from source.
|
||||
|
||||
The selection test stages a Silence status directly to isolate NPC cast behavior. The separate full Vow of Silence scenario remains the end-to-end validation path for applying the actual player ability and observing its combat result.
|
||||
|
||||
## Validation
|
||||
|
||||
`node_modules/.bin/vitest run src/game/enemyCasting.test.ts src/game/romPriestChampionRuntime.test.ts src/game/wailingCavernsParity.test.ts` passed: 3 files, 30 tests. Use the direct Vitest binary for this focused workflow; `npm test` invokes the `pretest` loot-generation hook. No build or repository-wide test suite is part of this narrow change.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Legacy Boss Pacing Fix — 2026-10-03
|
||||
|
||||
## Change
|
||||
|
||||
The existing 25-second ordinary-boss and 45-second final-boss minimums now hold for the measured legacy cohorts without changing those assertions or reducing encounter timing thresholds.
|
||||
|
||||
The Stockades WoW starter health anchors are now 1,800 at enemy level 2 and 2,600 at enemy level 4. Those replace 1,050 and 1,500, respectively. At level 1, the measured Priest plus four Ready companions now clear the ordinary and final bosses in 25.3 and 45.7 seconds. At level 3, they clear in 25.6 and 48.1 seconds.
|
||||
|
||||
The compatibility retune documented here uses a separate player-level multiplier only when `characterSource === "rom"` and `statRuleset === "wow"`: 1.0 through level 7, 1.12 at level 8 through 70, then a linear increase to 2.3 at level 80. This applies to boss health floors only. This compatibility retune did not change trash health, the native RoM health bands, native damage-budget bands, enemy damage, loot, cap 80, actor mode defaults, or Ready policy.
|
||||
|
||||
## Why the RoM compatibility branch stays separate
|
||||
|
||||
The pacing harness calls `dungeonEnemyScaling` for RoM parties without passing `statRuleset`, so it intentionally exercises the legacy `wow` ruleset default for those RoM characters. Generated RoM NPCs still use their native snapshots by default. This is a supported mixed-mode cohort; the harness calls and actor mode defaults remain unchanged.
|
||||
|
||||
The compatibility multiplier is gated on that existing legacy `statRuleset: "wow"` path. At the time of this compatibility retune, native-mode RoM boss health remained exactly 8,330.293333 at player level 8 and 1,312,656 at level 80 for the Stockades regression fixture; `nativeDamageBudgetScale` remained 1 and 40. A later, independently measured native level-one boss calibration changes the interpolated level-8 value to 7,983.197778 while preserving the level-80 value and both damage-budget values. See [the native level-one boss pacing addendum](ROM_NATIVE_LEVEL_ONE_BOSS_PACING_2026-10-03.md). The compatibility retune did not edit either native table; the later calibration changes only the level-1 boss-health anchor and leaves `ROM_NATIVE_DAMAGE_BANDS` untouched.
|
||||
|
||||
The equipment completion added optional off-hand and bow damage/speed/range values to native NPC snapshots. Those snapshot fields are available to future consumers; they do not make the shared enemy action scheduler emit additional off-hand or bow swings, and they do not automatically increase its shared enemy damage budget. This pacing change does not add extra enemy attacks or claim that the live swing path consumes those channels.
|
||||
|
||||
## Before and after evidence
|
||||
|
||||
The untouched baseline was captured with `BOSS_BALANCE_REPORT=1` and `NODE_OPTIONS=--max-old-space-size=8192` before retuning. Its 65 samples are archived at `artifacts/rom-enemy-followup/before-compatibility-pacing.json`. The test suite stopped at the first failing assertion within each affected test, so the baseline has only the first seed for the failures below.
|
||||
|
||||
| Cohort and level | Before ordinary / final (health) | After ordinary / final (health) |
|
||||
| --- | --- | --- |
|
||||
| WoW Stockades, level 1 | 14.6s / 27.1s (1,050 / 1,995) | 25.3s / 45.7s (1,800 / 3,420) |
|
||||
| WoW Stockades, level 3 | 15.1s / 28.6s (1,500 / 2,850) | 25.6s / 48.1s (2,600 / 4,940) |
|
||||
| RoM damage Mage, level 8 | 23.6s / 46.3s (15,619 / 29,677) | 26.8s / 52.9s (17,494 / 33,238) |
|
||||
| RoM party, level 80 | 11.3s / 23.6s (273,470 / 519,593) | 27.1–28.1s / 53.3–57.1s (628,981 / 1,195,064) |
|
||||
|
||||
After retuning, the report contains 83 samples: all three WoW seeds at levels 1, 3, 8, 20, 40, and 80; all five damage-Mage levels; and all 12 standard RoM party seeds at levels 1, 8, 20, 40, and 80. The complete report is archived at `artifacts/rom-enemy-followup/after-compatibility-pacing.json`.
|
||||
|
||||
Across the post-change samples, ordinary/final clear-time ranges were:
|
||||
|
||||
| Cohort | Level | Ordinary boss | Final boss |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| WoW party | 1 | 25.3s | 45.7s |
|
||||
| WoW party | 3 | 25.6s | 48.1s |
|
||||
| WoW party | 8 | 33.1s | 61.0s |
|
||||
| WoW party | 20 | 48.1–49.0s | 93.8–97.0s |
|
||||
| WoW party | 40 | 40.8–45.4s | 78.4–81.3s |
|
||||
| WoW party | 80 | 95.3–100.1s | 191.7–193.7s |
|
||||
| RoM damage Mage | 1 | 42.1s | 109.3s |
|
||||
| RoM damage Mage | 8 | 26.8s | 52.9s |
|
||||
| RoM damage Mage | 20 | 30.1s | 62.6s |
|
||||
| RoM damage Mage | 40 | 35.1s | 69.1s |
|
||||
| RoM damage Mage | 80 | 27.1s | 57.1s |
|
||||
| RoM party | 1 | 81.1–92.5s | 191.2–199.4s |
|
||||
| RoM party | 8 | 41.2–42.6s | 103.7–106.9s |
|
||||
| RoM party | 20 | 36.6–40.3s | 73.6–75.1s |
|
||||
| RoM party | 40 | 38.1–42.1s | 78.1–79.6s |
|
||||
| RoM party | 80 | 27.1–28.1s | 53.3–57.1s |
|
||||
|
||||
The full `dungeonBossScaling.test.ts` suite passed all 18 tests. The additional focused regressions passed all 6 tests across `romNativeDungeonPacing.test.ts` and `biteSizedBossBalance.test.ts`. The real-mechanics Priest test also passed its boss-attack, incoming-damage, healing, and survival assertions; its helper does not add that run to the timing report.
|
||||
@@ -0,0 +1,78 @@
|
||||
# Mechanic parity and campaign boss pass - 2026-10-04
|
||||
|
||||
## Outcome
|
||||
|
||||
Timed player/NPC Killing Spree and source-confirmed active-five RoM fixes are implemented. Vow's live counter and full 8.4-second silence pass after correcting the source Nature Thorns cast gate. Normal Barren fully clears in 13:36.9 with one casualty; strict Wailing reaches and defeats Lady with all five actors alive, while full Wailing completion remains unverified. Sampled camera visibility/right-drag checks pass. The final build, 296 focused assertions, Ready-five checks and repository/vault hygiene pass. Blood Arrow's separate base toggle/cost migration remains open.
|
||||
|
||||
## Authorized scope
|
||||
|
||||
Complete Killing Spree's timed player/owned-NPC mechanism; verify Vow of Silence in an actual Lady Anacondra fight; extend normal Barren Caves and Wailing Caverns routes to bosses and attempt full clears; audit and implement source-confirmed gaps for the five active native RoM identities. Independent work runs through GPT-6 Luna with extra-high reasoning.
|
||||
|
||||
The native set is Knight/Scout tank, Priest/Knight healer, Rogue/Warrior damage, Scout/Rogue damage, and Mage/Warlock damage. This is a targeted diagnostic and implementation pass, not an all-class balance sweep or a readiness promotion. The five WoW Ready builds retain the routine certification scope.
|
||||
|
||||
Level cap 80, automatic Training gear, saved-profile stat compatibility and loot scope are preserved. No commit, deployment or live-report status mutation is included. Existing shared-workspace changes are preserved.
|
||||
|
||||
## Evidence ownership
|
||||
|
||||
- `docs/WOW_KILLING_SPREE_PARITY_2026-10-04.md`: source-timed player/NPC mechanism, cleanup and focused tests.
|
||||
- `docs/ROM_FIVE_MECHANIC_GAPS_2026-10-04.md`: exact active identities, confirmed fixes and unresolved source/runtime contracts.
|
||||
- `docs/ROM_CAMPAIGN_BOSS_PASS_2026-10-04.md`: normal campaign traversal, boss/full-clear attempts, live Vow evidence and screenshots.
|
||||
- `docs/ROM_BARREN_FINAL_CLEAR_2026-10-04.md`: independent final-build normal Barren rerun.
|
||||
- `docs/ROM_VOW_LIVE_FINAL_2026-10-04.md`: independent final-build ordinary Boss Testing Lady/Vow fight, separate from campaign completion.
|
||||
- `docs/ENEMY_SILENCE_CAST_GATE_2026-10-04.md`: source-confirmed Thorns silence-selection correction discovered during the full live observation window.
|
||||
|
||||
## Validation boundaries
|
||||
|
||||
Exploratory current-dist captures are labeled separately from final-build checks. Normal campaign movement and casting use ordinary inputs; staged casts, teleports and edited combat state cannot establish live-route proof. Browser screenshots require visual inspection. A completed harness recording does not establish a successful clear, survivor count or counter cancellation without matching telemetry.
|
||||
|
||||
## Camera implementation
|
||||
|
||||
Normal Wailing traversal reproduced a foreground pillar obscuring the player and companions while HTML labels remained visible (`playtest-artifacts/native-routes/baseline-20261004-134537874/wailing-caverns-segment-end.png`). The player follow camera queried physical terrain only; the spectator follow camera already included the dedicated visible wall/pillar layer. `src/scene/dungeonCameraObstruction.ts` now shares that combined query, preserving the physical sphere sweep, actor exclusion and immediate pull-in/eased pull-out behavior. Sight-only sensor proxies now shorten the player boom as well.
|
||||
|
||||
Real Rapier obstruction tests plus existing line-of-sight and input tests pass 41 assertions across four files. Final-build live camera/route evidence is recorded in the campaign report; this static result alone does not certify every cave viewpoint.
|
||||
|
||||
## Mechanic implementation
|
||||
|
||||
Killing Spree now executes five scheduled owner-local assaults through the two-second window for players and generated Rogue companions. The learned companion action enters its existing Combat rotation; damage/aura ordering, retained targets, actual scene relocation and death/reset/roster-removal cleanup have focused coverage (71 tests). Seeded target choice and estimated weapon-child/teleport details remain simulator approximations.
|
||||
|
||||
The active-five audit corrects Knight/Scout Blood Punishment to +15% received healing and +5% Holy damage on the live Blood Arrow aura. Actual companion casts exposed and corrected presentation-derived RoM combat schools and missing outgoing aura handling on the compatibility no-roll direct path; native roll-based damage must not apply those modifiers twice. The audit retains unresolved source values and the separate Blood Arrow base-toggle/cost migration explicitly.
|
||||
|
||||
Routine Ready-five certification passes seven game and twenty Python tests. Final production build and browser evidence are required separately below.
|
||||
|
||||
## Campaign build and integration checks
|
||||
|
||||
- Focused suites: 71 Killing Spree/runtime/registry, 154 active-five pair/integration, and 41 camera/line-of-sight/input assertions pass (266 total across eleven files).
|
||||
- Ready-five: seven game assertions and twenty Python tests pass. No all-class balance sweep or readiness promotion.
|
||||
- `npm run build` passes application/project TypeScript, Vite, prebuild texture/performance audits, postbuild compression and release-bundle verification. The existing prebuild loot-catalog generation runs unchanged; this task adds no loot wiring.
|
||||
- Campaign assets: `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, `index-499eecpe.css`.
|
||||
- Recorded browser scope: independent normal campaign Barren/Wailing attempts and a separate ordinary Boss Testing Lady/Vow fight. The later silence-correction replay identifies its rebuilt assets below; failed exploration is retained separately.
|
||||
|
||||
## Verified live outcomes
|
||||
|
||||
Barren Caves clears through normal campaign movement and combat on the final asset set. The native result overlay reads **FULL DUNGEON CLEAR**, Anglo defeated 1/1, at **13:36.9**; the boss record independently shows dead with zero HP. The initial level-30 Priest/Knight naturally finishes at level 36. Rorik dies; the player, Caelan, Durnik and Veyra survive (four of five actors). Effective healing totals 46,328.47. This establishes one full clear, not a death-free balance certification. Maximum sampled player-to-living-companion distance is 12.52 m during the route and 15.56 m in post-pack snapshots. No loot action was taken. See the independent Barren report and `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/`.
|
||||
|
||||
The initial independent ordinary Boss Testing Lady fight confirms Vow cancels a real source Lightning Bolt (9532), without staging the cast or changing combat state. Before Vow, source creature 3671 has an interruptible Nature bolt and only Fear/Horror mechanic immunities. The completed Vow event targets Lady; immediately afterward the cast is null and her actual Silence status lasts 8,400 ms. The aura applies before the explicit interrupt effect, so it cancels the cast before that effect can set a Nature school lock. A zero school-lock value is not failure when the silence and cast cancellation are verified. Before/after screenshots show the bolt bar disappear; no presentation-event capture is claimed. The fight defeats Lady with all five actors alive and no XP/loot. Evidence: `playtest-artifacts/vow-live-final/final-build-20261004-151254152/`; the scoped report distinguishes the original harness false-negative from successful cancellation. Longer observation in `final-build-20261004-151736260/` finds Nature Thorns starting during silence, leading to the enemy selector correction and successful rebuilt replay below.
|
||||
|
||||
Normal Wailing movement has revisited the vicinity of the previously clipped view on the final build. The screenshot triplet shows loaded bodies and equipped silhouettes, right-drag rotation, and a stable released view. The foreground rock that obscured the earlier sampled view is absent in this nearby pose. The campaign report records the exact pose/input telemetry and final route outcome; this is a sampled camera improvement, not universal cave visibility certification.
|
||||
|
||||
Wailing's strict route reaches Lady's authored anchor without the earlier fall: 433.96 m actual travel against 432.42 m guidance, all 284 checked movement vertices reached, no route block and five actors surviving. Effective healing totals 28,587.81. Lady engages and is defeated during ordinary pack stabilization before the endpoint. Real source Lightning Bolt damage, repeated player Rising Tide casts, a final clipped companion hit and the captured feedback **That target is already defeated** establish the fight/defeat. The original endpoint-only `boss-not-reached-or-not-loaded` classifier misses this natural midroute fight after the boss leaves active state; it is not evidence of a spawn defect. The run does not defeat the other seven required bosses or complete the Naralex/Mutanus event, so **full Wailing clear remains unverified**. Empty guard-attempt records do not prove those living packs cleared. Evidence: `playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/`.
|
||||
|
||||
The Wailing camera probes rotate yaw by -0.378 radians while right mouse is held, with `document.pointerLockElement` null. After release, an unheld pointer move changes yaw by zero. Player displacement during either drag is less than 0.001 m. The earlier clipped-position probe is 5.18 m from that old pose; the improvement is a nearby sample, not an exact-position comparison or a measured rendered-camera boom extraction. Character bodies and staff/bow/shield silhouettes were visually inspected at route checkpoints and both probe triplets.
|
||||
|
||||
## Silence correction and final replay
|
||||
|
||||
The full live observation exposes the actual pinned Thorns 8148 row: Nature school, self aura, `delivery: melee`, and no explicit damage class/kind. The old new-cast selector inferred melee from delivery and let it start during silence; active-cast cleanup then canceled it on the next advance, producing repeated starts without resolution. Enemy selection now checks nonphysical school **or** explicit spell kind for silence eligibility. Physical melee/ranged remain available and the damage-roll classifier is unchanged. The imported attack contract has no prevention-type field, so this remains the simulator's explicit school/kind control policy. The separate source report and actual-source regressions cover repeated silence advances, expiry and resumed Thorns release. A coordinated rebuild and independent live replay follow this correction; the earlier campaign/camera evidence retains its recorded asset identities.
|
||||
|
||||
After the correction, `npx vitest run src/game/enemyCasting.test.ts src/game/romPriestChampionRuntime.test.ts src/game/wailingCavernsParity.test.ts` passes 30/30. The combined scoped validation is **296 assertions across fourteen files** (266 mechanic/camera assertions plus these thirty); Ready-five is rechecked at seven game/twenty Python passes. The final `npm run build` passes project TypeScript, Vite, pre/post audits, compression and bundle verification. Corrected assets are `index-Cm7Olrd2.js`, `combatStore-1B4KOVhS.js`, `GameRuntime-hM1AaOYR.js`, `PartyFrames-BfZEkXH5.js`, `romAbilityCatalog-DjRUCJbs.js`, and `index-499eecpe.css`. The independent Vow replay uses this corrected set; the completed campaign routes were recorded on the preceding set.
|
||||
|
||||
The corrected live replay **passes** in `playtest-artifacts/vow-live-final/final-build-20261004-153859692/`. The ordinary Vow input cancels Lady's real source 9532 before scheduled completion and applies silence from 1791128371374 to 1791128379774 (8,400 ms). No nonphysical active cast is observed during that actual status window, including Thorns. Lady naturally begins the next source Nature Lightning Bolt at 1791128379835, 61 ms after expiry. The fight then defeats Lady with all five actors alive, no XP/loot and no readiness change. Parent and subprocess visually inspect before/after cast screenshots and the boss-defeated panel; loaded character bodies and equipped silhouettes remain visible. No cast-cancel presentation-event capture is claimed. This supersedes the earlier Thorns suppression failure without replacing its historical evidence.
|
||||
|
||||
## Remaining limits
|
||||
|
||||
- Full Barren clear and Wailing's first-boss route/defeat are verified; full Wailing completion remains unverified.
|
||||
- Blood Arrow's current CoA base-toggle/cost identity migration, unquantified pair values and Killing Spree's documented simulator approximations remain open in their scoped audits.
|
||||
- The camera improvement and ordinary right-drag policy are verified at sampled Wailing views; every dungeon viewpoint and compact gameplay layout are not certified by this pass.
|
||||
|
||||
## Final hygiene
|
||||
|
||||
`npm run release:check` passes 391 changed paths including untracked files in the shared workspace; that count includes preserved work outside this task. The separate vault passes `git diff --check`, and all five owned canonical/worklog/index notes pass trailing-whitespace and exact-one-EOF-newline checks. Scoped harness syntax checks pass. No files are staged or committed by this task.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Performance check — 2026-10-04
|
||||
|
||||
## Findings and changes
|
||||
|
||||
- **CPU:** The production CPU profile spent about 925 ms of an eight-second sample inside `filesForContentPack`, which repeatedly scanned and sorted the asset catalog. `src/content/contentManifest.ts` now indexes each immutable file map once through a WeakMap. `src/content/contentManager.ts` caches usable/unavailable pack results until the next content publication; install, removal, validation, and catalog changes invalidate those results.
|
||||
- **Idle CPU/rendering:** `src/ui/usePresentationClock.ts` stops HUD, aura, and periodic-effect clocks while locally paused, viewing the map/companion, or hidden. Visible shared-online timers still run behind menus. `DungeonRaceHud.tsx` no longer starts its two clocks during ordinary dungeon play. Aura and periodic strips use shallow target-filtered subscriptions, and aura timer effects no longer restart on every new filtered array.
|
||||
- **Retained RAM:** `src/game/combatAudio.ts` previously retained every decoded cue for the tab lifetime. Its least-recently-used cache now holds at most 64 entries or 32 MiB of decoded PCM. Active playback keeps its own buffer, failed requests can retry, and simultaneous requests share a decode. This limits cache retention, not total browser memory or all in-flight audio allocations.
|
||||
- **GPU:** Local pause and hidden-page handling already switch the scene to demand rendering and stop physics. The checked stable pause/background samples made zero WebGL draw calls. No rendering-resolution, texture-quality, lighting, or culling reductions were applied.
|
||||
|
||||
## Measurements
|
||||
|
||||
Production builds were exercised in headless Edge on the AMD Radeon RX 9070 XT, at a 1280 × 800 viewport with a 1920 × 1200 drawing buffer. `scripts/playtest-performance.cjs` creates a temporary local account/database, enters Wailing Caverns, samples entry combat and movement, pauses/resumes, exercises synthetic page visibility, and repeats entry/exit three times. The historical label `active-idle` means no player input; companions may fight during that sample.
|
||||
|
||||
| Sample | Before | After | Confirmation |
|
||||
|---|---:|---:|---:|
|
||||
| Entry main-thread busy time | 77.7% | 44.2% | 61.7% |
|
||||
| Movement-following main-thread busy time | 79.2% | 69.0% | 55.6% |
|
||||
| Stable 20-second pause busy time | 5.41% | 0.49% | 0.46% |
|
||||
| Stable pause draw calls/second | 0 | 0 | 0 |
|
||||
| Stable pause JavaScript heap | 192.57 MiB | 173.26 MiB | 173.06 MiB |
|
||||
| Third menu return JavaScript heap | 59.88 MiB | 59.59 MiB | 59.71 MiB |
|
||||
|
||||
These are individual route samples, not a deterministic combat benchmark. NPC appearances, combat progression, loaded effects, and concurrent project work vary. The heap difference and active draw-call difference must not be attributed entirely to these fixes. The CPU profile confirms removal of the catalog-scan hotspot; the stable pause results reproduce.
|
||||
|
||||
A separate lookup benchmark used the same 21,585-file manifest and 2,181-file combat-media pack for both algorithms: 100 old scan/sort lookups took 746.06 ms; building the new index took 14.91 ms once; 100 cached lookups took 0.023 ms. This isolates the catalog work, not total game speed.
|
||||
|
||||
The after run's synthetic hidden sample used 0.43% main-thread busy time and zero draw calls; resume restored continuous rendering. JavaScript heap changed only 0.024 MiB over its stable paused 20-second window. Menu returns released most scene heap and backing storage across three cycles. No page errors occurred.
|
||||
|
||||
One third-cycle pause window still showed a transient workload (12.3% main-thread busy time and 226 draw calls/second) despite demand mode. The confirmation run adds a paused CPU profile and an additional 20-second settled sample: both its initial third-cycle pause and settled window had zero draws and no layouts. The settled window used 0.50% main-thread busy time; the paused profile was overwhelmingly idle. This transient was not reproduced or conclusively attributed, so pause is not certified draw-free during every asynchronous transition.
|
||||
|
||||
## Validation and evidence
|
||||
|
||||
- 59 focused tests passed across content validation/persistence, audio, aura/periodic displays, scene lifecycle, and disposal. Audio regressions specifically cover byte/count eviction, concurrent reuse, failure retry, and active playback.
|
||||
- `npm run build` passed TypeScript, Vite, KTX2 and environment-performance audits, compression, and release-bundle verification. The environment audit reported zero regressions across 106 assets, with 60 existing budget exceptions.
|
||||
- `npm run release:check` passed. An initial attempt raced another task writing a document; the subsequent check passed without changing unrelated work.
|
||||
- Visually inspected active and resumed gameplay and pause screenshots: character bodies, starter gear, enemies, effects, and HUD remained visible. This is not an equipment or character-rendering change.
|
||||
- Raw measurements/screenshots/profiles: `artifacts/playtest/performance/before/`, `after/`, and `confirmation/`. Each run contains `results.json`, `renderer.json`, active/pause screenshots, and `active.cpuprofile`; confirmation also contains `paused.cpuprofile`.
|
||||
- Repeat with `node scripts/playtest-performance.cjs`; set `PERFORMANCE_LABEL` for a separate evidence directory. `PERFORMANCE_URL` can point the same UI route at a local preview, but production mode is necessary to exercise installed-content checks.
|
||||
|
||||
## Limits and remaining targets
|
||||
|
||||
Main-thread busy percentage is one browser thread's occupied wall time, not whole-system CPU utilization. Forced-GC JavaScript heap and backing storage are not total process RAM, GPU memory, or VRAM. Draw calls measure submitted rendering work, not device GPU utilization. Hidden-page handling is a synthetic lifecycle test, not an OS background-throttling measurement.
|
||||
|
||||
This pass covers one desktop dungeon route, not every dungeon, mobile/Android, high-shadow/resolution settings, shared-online play, or a long combat soak. Original-effect graph and texture caches still retain distinct media for the tab lifetime; safe eviction needs a separate varied-spell/resource-ownership check. Remaining active profile cost is primarily rendering, transforms, and layout; larger scene and device-level GPU profiles should guide any further visual changes.
|
||||
@@ -0,0 +1,33 @@
|
||||
# RoM Barren Caves final-build clear — 2026-10-04
|
||||
|
||||
## Outcome
|
||||
|
||||
The final build completed Barren Caves through ordinary WASD movement and combat inputs. The native results overlay displayed **FULL DUNGEON CLEAR**, “Barren Caves complete,” and **Anglo — Defeated**, with **Bosses defeated 1/1** and a displayed time to final boss of **13:36.9**. The overlay screenshot and route telemetry agree: Anglo is recorded as a level-36 boss at 0/152,256 health and dead. The overlay appeared during movement at checkpoint 358/376, after 697.18 m of 717.47 m expected route distance; native completion ended movement, so the clear claim is based on the result UI and dead-boss state, not arrival at the guide endpoint.
|
||||
|
||||
## Run and build
|
||||
|
||||
- Harness: `node scripts/playtest-campaign-boss-pass.cjs --route=barren-caves --campaign-boss-route --max-campaign-seconds=1200`. Source confirms `--max-campaign-seconds` sets the campaign route deadline; `--route-seconds` applies to the non-campaign route path.
|
||||
- Final-build assets reported by the build: `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, and `index-499eecpe.css`. The harness result manifest confirms it loaded the final `index`, `combatStore`, `GameRuntime`, and `PartyFrames` JavaScript modules.
|
||||
- The harness created an isolated level-30 UI profile, Routepriestq (RoM Priest / Knight, healer), and isolated temporary browser/server data. Level gains to 36 were natural XP. No readiness promotion or loot action occurred.
|
||||
- Navigation used normal WASD inputs for 728 movement steps. 358 of 376 checkpoints were verified before the native result overlay stopped input. The final overlay remained visible in the captured boss-arrival screenshot.
|
||||
|
||||
## Party, healing, and combat
|
||||
|
||||
The player survived at level 36 with 2,629.45/2,629.45 health. Caelan survived at 1,190.57/2,909.79, Durnik at 2,289.97/2,289.97, and Veyra at 2,343.25/3,081.81. Rorik was the sole party death at 0/3,679.16. The healer produced **46,328.47 effective healing** across 79 healing actions with a positive healing event (97 healing inputs were recorded). The harness observed 41 distinct dead mobs, including Anglo.
|
||||
|
||||
The largest player-to-living-party-member separation in periodic route samples was 12.52 m. The largest recorded after-pack-consolidation separation was 15.56 m. The boss was killed by natural party combat; the harness’s direct boss-fight handler did not run because the native full-clear overlay had already appeared.
|
||||
|
||||
## Visual and error review
|
||||
|
||||
Inspected the roster desktop and compact screenshots, entrance, 25%, 50%, 75%, and boss-arrival screenshots. Character bodies and held starter weapon silhouettes (staff, shield, and other weapons) remain visible in the roster and dungeon. Clothing is sparse on the displayed avatars. The full-clear panel is legible over the dimmed dungeon and names Anglo as defeated.
|
||||
|
||||
The route record has no page or console errors. The aggregate run manifest contains one `favicon.ico` 404 request from the local server; no gameplay or rendering error was recorded.
|
||||
|
||||
## Evidence
|
||||
|
||||
All evidence is under `playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/`:
|
||||
|
||||
- `barren-caves-campaign-boss-route.json` — native overlay state, dead-boss record, navigation, party health, healing, and observed combat events.
|
||||
- `results.json` — final build module list, profile, and run-level browser errors.
|
||||
- `barren-caves-boss-arrival.png` — visible FULL DUNGEON CLEAR panel and Anglo 1/1 result.
|
||||
- `roster-priest-knight-level-30.png`, `roster-compact-priest-knight-level-30.png`, `barren-caves-entrance.png`, `barren-caves-boss-route-25.png`, `barren-caves-boss-route-50.png`, and `barren-caves-boss-route-75.png` — roster/body/gear and dungeon visual checks.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Campaign boss-route playtest — 2026-10-04
|
||||
|
||||
## Scope and method
|
||||
|
||||
This pass extends ordinary campaign routes in Barren Caves and Wailing Caverns through their normal boss encounters. The scoped Playwright harness creates an isolated Priest through the UI, prepares the permitted level-30/Knight-secondary fixture before entry, enters the normal Dungeons picker as healer, and uses ordinary WASD, Tab, F1/F2, party-frame selection, learned bound abilities, and the visible resurrection control. Source navigation paths are movement guidance only. During the live campaign, game position, health, mana, cooldowns, combat targets, party positions, and dungeon results are read-only telemetry; no loot was taken and no level-cap or readiness setting was changed.
|
||||
|
||||
The final build was produced by the parent task after Killing Spree and native-combat implementation. Its asset names were `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, `PartyFrames-5jlxKxxK.js`, `romAbilityCatalog-CHjYfHkT.js`, and `index-499eecpe.css`. Earlier route observations are explicitly labeled current-dist exploration and are not substituted for final-build verification.
|
||||
|
||||
## Barren Caves: final-build full clear
|
||||
|
||||
The final-build ordinary campaign run completed the dungeon. The native result screen reads **FULL DUNGEON CLEAR**, **Barren Caves complete**, **Anglo — Defeated**, and **Bosses defeated 1/1**; time to the final boss was **13:36.9**. The visual proof is [barren-caves-boss-arrival.png](../playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/barren-caves-boss-arrival.png), and the read-only route/result record is [barren-caves-campaign-boss-route.json](../playtest-artifacts/campaign-boss-pass/final-build-20261004-150021873/barren-caves-campaign-boss-route.json). Build assets observed by this route harness were `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, and `PartyFrames-5jlxKxxK.js`.
|
||||
|
||||
The run followed normal source-geometry checkpoints for 697.18 m of the 717.47 m guide and verified 358 of 376 vertices. The final boss and party defeated the encounter before the next checkpoint, which opened the native results screen; the driver then stopped without crossing the overlay. The character advanced from level 30 to 36 through normal encounter experience. Rorik was dead at the result screen; the healer and the other three companions were alive. No loot or results-screen action was taken.
|
||||
|
||||
## Barren Caves: current-dist exploration clear
|
||||
|
||||
An ordinary, navigation-guided Barren Caves run advanced through the cave and reached the native dungeon-results screen. The screen states **FULL DUNGEON CLEAR**, **Barren Caves complete**, and **Anglo — Defeated** with **Bosses defeated 1/1**; it reports **10:45.8** to the final boss. The run had explored 625 m. The visible result screen is [failure.png](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/failure.png); the captured page text and Playwright error are in [failure.json](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/failure.json). The 25%, 50%, and 75% ordinary-traversal images are [route 25](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-25.png), [route 50](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-50.png), and [route 75](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-boss-route-75.png). The normal profile and entry images are [roster](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/roster-priest-knight-level-30.png) and [entrance](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-144223345/barren-caves-entrance.png).
|
||||
|
||||
The harness process exited with a locator timeout after the game had opened the result overlay: a follow-up heal tried to click Caelan's party frame, and the overlay correctly intercepted it. That is a post-clear harness error; it does not negate the visible native clear result. Rorik was dead in the result-screen party snapshot, while the other three companions and the healer were alive. The run received normal combat experience and the character advanced to level 36. No result-screen button was clicked and no loot was collected.
|
||||
|
||||
This exploratory result is not a final-build clearance claim. A separate final-build rerun uses the corrected overlay guard and stricter navigation driver.
|
||||
|
||||
## Wailing Caverns: exploration and route-driver correction
|
||||
|
||||
The earlier current-dist source-guided attempt covered 539.9 m against a 432.4 m planned path and reached 107 of 120 coarse checkpoints. Between checkpoints 106 and 107 the player dropped from about y=-90 to y=-106, ended in Kresh's Grotto, and remained 46.3 m from Lady Anacondra. The party remained together and alive, but the boss was not reached and Vow was not attempted. [The endpoint image](../playtest-artifacts/campaign-boss-pass/exploration-current-dist-20261004-143155433/wailing-caverns-boss-arrival.png) shows the lower water channel below the intended upper route.
|
||||
|
||||
This result is classified as a route-driver divergence, not a demonstrated dungeon navigation defect. The earlier driver used 3.8 m checkpoint spacing, a 4.4 m acceptance radius, 850 ms movement pulses, and could skip a blocked nearby guide point. Those tolerances could cut narrow corners or cross a ledge. The scoped harness now preserves each source-path vertex, accepts a checkpoint only within 0.65 m, scales short ordinary-input pulses from observed movement speed, records a large live downward displacement, and stops instead of skipping a geometry or elevation point. A tight source-navigation path is required before the Wailing conclusion can be updated.
|
||||
|
||||
The current profile exposes Vow of Silence (DBC spell 490275) at level 30. The final campaign identity had Vow assigned through the in-game Ability Controls UI to the secondary R1 input (Shift+5); the final-build binding image is [wailing-caverns-vow-binding-ui.png](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-vow-binding-ui.png). The route did not press Vow. The separate live Boss Testing result is recorded below. The corrected pinned source says Lady's listed Fear/Horror immunity does not imply Silence or Interrupt immunity.
|
||||
|
||||
## Wailing Caverns: final-build route and Lady encounter
|
||||
|
||||
The strict final-build route reached Lady Anacondra's Lair through ordinary movement input. It covered 433.96 m in the game and 430.14 m from input-step measurements against a 432.42 m navigation guide, verifying all 284 source vertices in 505 movement steps. No route block, downward-drop stop, player death, or party death was recorded; the endpoint snapshot and screenshots show all five party members alive. The route images are [route 100](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-boss-route-100.png) and [arrival](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-boss-arrival.png). They show the party, equipped staff/bow/shield silhouettes, and live Deviate Guardians in the lair.
|
||||
|
||||
Lady Anacondra did spawn and fight during approach combat. The event stream records her source-scheduled `spell-9532` damage against the party. A normal player Rising Tide action selected `lady-anacondra-spawn` at 1791127452078 with 2,942 HP remaining. While that cast was resolving, captured party damage events landed for 346, 166, and 2,430 effective damage, totaling exactly the remaining 2,942 HP. The action then returned **“That target is already defeated.”** This confirms the first-boss fight and its defeat during route stabilization. No Vow input was attempted in this campaign run.
|
||||
|
||||
The captured JSON's endpoint-only `bossFight` classifier says `boss-not-reached-or-not-loaded`; Lady is absent from `sceneMobsAtEndpoint`. Earlier periodic snapshots showed her full HP but did not sample her death during the blocking pack handler. The absence-only classifier misses the selected-target error and matching combat sequence, so it is not used as defeat evidence. The run did not capture `dungeonRunStore` objective progress or open the native full-clear overlay, so Wailing Caverns full clear is **unverified**. After Lady, the listed objectives include Kresh, Lord Cobrahn, Lord Pythas, Skum, Lord Serpentis, Verdan the Everliving, and event-only Mutanus; these were not covered. The five nearby-pack records also have empty initial engagement and zero heals/damage, so their `pack-cleared` labels are invalid and are not credited as kills.
|
||||
|
||||
At the original clipped-camera reference position, the live route reached a nearby pose 5.18 m away. Held right-drag changed yaw by -0.378 rad; after release and a further unheld mouse move yaw changed by 0 rad. Pointer lock remained null throughout and player movement stayed under 0.001 m per probe. The three inspected images are [before drag](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-before-right-drag.png), [after drag](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-after-right-drag.png), and [after unheld move](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-original-clipped-endpoint-after-unheld-move.png). This reproduces camera input recovery at a nearby pose; it does not establish visibility from every cave angle. A second check at the Lady route endpoint also rotated by -0.378 rad and remained stable after release.
|
||||
|
||||
The route used final production assets `index-DHQInfBp.js`, `combatStore-Cx06rFzG.js`, `GameRuntime-D87YWi4Q.js`, and `PartyFrames-5jlxKxxK.js`. The full capture is [wailing-caverns-campaign-boss-route.json](../playtest-artifacts/campaign-boss-pass/final-build-20261004-151549020/wailing-caverns-campaign-boss-route.json). A follow-on harness edit now probes the loaded Zustand exports for read-only `dungeonRunStore` progress and records it when exposed. That addition was not exercised by this completed capture; the next route record must confirm whether the current bundle exposes that store to the harness.
|
||||
|
||||
## Separate pre-correction live Vow of Silence diagnostic
|
||||
|
||||
The normal Boss Testing run in [ROM_VOW_LIVE_FINAL_2026-10-04.md](ROM_VOW_LIVE_FINAL_2026-10-04.md) is separate from campaign coverage. A UI-bound Priest used Vow on Lady's actual scheduled `spell-9532` Lightning Bolt; the cast ended before its scheduled completion and an 8.4-second Silence status applied. Nature Thorns (`spell-8148`) nevertheless became active during that status window, so Vow's full spell suppression is not certified. Lady was defeated in that diagnostic and all five party members survived, but it is not evidence of a Wailing campaign clear. The report includes the cast-timeline screenshots, raw event details, and the precise silence-gating limitation.
|
||||
|
||||
That pre-correction result is preserved under `playtest-artifacts/vow-live-final/final-build-20261004-151736260/`. The parent subsequently corrects the source-driven silence selector and rebuilds. The independent replay in `final-build-20261004-153859692/` on `index-Cm7Olrd2.js` / `combatStore-1B4KOVhS.js` passes real Bolt cancellation, no nonphysical cast during the full 8,400-ms status, and natural Nature Bolt resumption 61 ms after expiry. Lady is defeated with five actors alive. This later counter check supersedes the suppression failure; it does not replace the campaign route's earlier asset set or certify a full Wailing clear.
|
||||
|
||||
The campaign harness and report use the final production assets without building or changing game runtime source. No loot was taken and no readiness or level-cap setting was changed.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Native RoM five mechanics gap audit — 2026-10-04
|
||||
|
||||
## Scope and finding
|
||||
|
||||
This targeted audit covers the five active native identities in `src/game/romFiveIdentities.ts`: Knight/Scout Rorik, Priest/Knight Serenna, Rogue/Warrior Veyra, Scout/Rogue Caelan, and Mage/Warlock Durnik. It checks the current source inputs and translated effects that reach player and owned-NPC casts, including pair skills actually learnable in each selected build. RoM remains **Needs Testing**; this is not a readiness or balance promotion.
|
||||
|
||||
The native stat and combat-input route already contains the active-five source channels audited in the recent native passes, including HolyHeal and supported DotMagic healing, player/owned-NPC source bindings, training weapons, Throw, ShieldDef, native target resolution, and target-count falloff. This review found one concrete pair-effect mismatch: the Knight/Scout Blood Punishment rider still used RuneWaker's old 50% healing-received child and omitted current CoA's Light damage bonus. It now modifies the caster's existing Blood Arrow aura with current CoA's 15% healing-received and 5% Light/Holy damage benefits. No separate passive timer is created.
|
||||
|
||||
The owned-party direct-damage adapter also had two gaps that hid this rider in NPC play: it inferred native RoM damage school from presentation text, and its deterministic no-roll direct path did not resolve generic caster damage auras. The party path now uses `abilityDamageSchool` for Runewaker spells and prefers an explicit direct effect school when the translated source component supplies one; the ability-level school remains the fallback. This preserves source-described mixed packets without inferring from presentation text, while WoW school selection is unchanged. Active actor-owned damage modifiers are also applied to no-roll Runewaker direct hits. The dedicated Holy Blessing modifier is excluded from that generic pass because Priest already resolves it through its source-specific path. Native `statRuleset: "rom"` hits continue through the existing combat-roll resolver.
|
||||
|
||||
## Blood Punishment source and identity
|
||||
|
||||
The generated RuneWaker catalog identifies `499923` as the learnable level-70 Knight/Scout passive Blood Punishment, with prerequisite Blood Arrow `490420`; the source general active is Scout Blood Arrow `490434` (the current CoA corresponding active is `499924`). The local `learnmagic.db`, `magiccollectobject.db`, and `magicobject.db` SHA-256 values match the generated catalog's recorded hashes. Local component `623167` links its one-second `onTimeMagicId` to `499910` for 30 seconds. `Resource/luascript/02708.lua`'s `lua_bico_kni_sco_es_70_blood` checks owner buff `500871` and cancels `623167` when that Blood Arrow marker is absent; this is the old child-timer behavior.
|
||||
|
||||
The [current CoA Knight/Scout skill list](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=ar) still identifies Blood Punishment as Knight/Scout `499923`, Blood Arrow as Scout-general `499924`, and says Blood Arrow increases received healing by 15% and Light damage by 5% while active. The [10.2.1 patch history](https://chroniclesofarcadia.com/ru/patch/10-2-1-1000) records the 15% healing-received reduction for Knight/Scout Blood Punishment. The exact skill IDs and pairing match the local rows, so the current CoA rider replaces the stale local 50%/30-second child. The current page's level-105 examples do not change Healer Man's level-80 cap.
|
||||
|
||||
The runtime attaches both modifiers directly to the existing caster aura tagged `rom-self-health-drain` for source skill `490434`. That keeps the rider actor-local and ties its lifetime to the active Blood Arrow aura already modeled by the simulator. The simulator still models the local Blood Arrow 30-second lifetime and 3%-of-maximum-HP periodic cost; this change does not claim full CoA toggle, deactivation cooldown, or per-ranged-skill HP/MP cost parity. The local 623167/499910 timer is intentionally not layered onto the current CoA rider.
|
||||
|
||||
### Remaining Blood Arrow base-contract work
|
||||
|
||||
This is source-confirmed but intentionally not implemented by the passive-rider fix. The [current CoA Scout general-skill page](https://chroniclesofarcadia.com/en/wiki/skills/list/1-2) documents Blood Arrow as a toggle that can be deactivated from its buff, with a ten-second cooldown on deactivation and an HP cost on physical attacks. The [10.7.0 patch notes](https://chroniclesofarcadia.com/en/patch/10-7-0-1000) also describe Blood Arrow's per-tick Mana cost. Healer Man's local `490434` instead remains a 30-second aura with a 3%-maximum-HP periodic drain and has no player toggle, deactivation cooldown, or per-offensive-attack HP/Mana charge. The general page's Blood Arrow row is `499998`, while the Knight/Scout page identifies the passive's active as `499924`; this audit does not assume those rows have an identical current cost contract. Keep these base-skill differences open and do not describe the pair as fully CoA-parity complete.
|
||||
|
||||
## Other active identities
|
||||
|
||||
| Identity | Audit result |
|
||||
|---|---|
|
||||
| Priest/Knight | The selected pair rows and Devotion Halo are covered by the pair catalog/runtime checks, and the native healing bindings cover supported direct and periodic HolyHeal for player and owned-NPC casts. The source-only Holy Chains child has no measurable player-facing payload; no runtime value is inferred. No comparable source-confirmed player/NPC effect mismatch was found. |
|
||||
| Rogue/Warrior | The selected pair effects are covered by the pair tests, including Throwing Mastery, Whirlwind Mastery, Poison Spray, Toxic Splash, and Poison Battle Technique. One-Hand Axe Mastery is inapplicable to the canonical dual-dagger loadout. The source does not supply usable values for remaining Reclaim Energy/Toxic Splash chance clauses, so they remain source-blocked instead of guessed. No comparable confirmed mismatch was established. |
|
||||
| Scout/Rogue | The pair and Poison Powder routes are covered by helper/runtime tests. `docs/ROM_SCOUT_REMAINING_PASSIVES_AUDIT.md` keeps Exploiting Shot's unspecified stack cap and Deadly Counterattack's missing critical amount/buff duration separate from existing hybrid estimates. These are unresolved source values, not confirmed values that this pass could implement. |
|
||||
| Mage/Warlock | The ten exact pair skills and source-selected cast/proc branches are covered by pair tests. The Flame Follower identity conflict concerns Mage/Warden, outside Durnik's pairing; it is not mapped by ID alone. No comparable source-confirmed player/owned-NPC mismatch was found for this selected pair. |
|
||||
| Knight/Scout | Current CoA Blood Punishment was the concrete confirmed mismatch fixed here. Its stale local child timer is not layered onto the current aura rider. The separate base Blood Arrow toggle/cost contract above remains open. |
|
||||
|
||||
The old Knight/Scout Lua callback is source-confirmed, but current CoA reuses the exact passive identity and publishes replacement benefits. The replacement is attached to the real caster aura, so cancellation and natural expiry remove it with Blood Arrow rather than waiting for a one-second child-timer poll. Unquantified or absent source behaviors remain open rather than receiving guessed values.
|
||||
|
||||
## Ownership and verification
|
||||
|
||||
- `src/game/romKnightScoutBloodPunishment.ts` owns the exact caster-aura attachment rule.
|
||||
- `src/game/romPriestKnightOverrides.ts` owns the learned Knight/Scout passive marker and routes Blood Arrow activation through the helper.
|
||||
- `src/game/partyRuntime.ts` resolves RoM direct-hit schools from source ability effects and applies active actor-owned damage modifiers in the no-roll Runewaker compatibility path, excluding Holy Blessing from its dedicated resolver. Native stat-mode hits use the existing roll-based outgoing-aura path.
|
||||
- `src/game/romPriestKnightPairValidation.test.ts` covers the exact passive marker, effect values, aura attachment, and player cast. `src/game/romKnightScoutBloodPunishment.integration.test.ts` exercises player Holy and physical damage, healing taken, immediate cancellation, owned-NPC healing and damage, natural expiry, owner isolation, and both native and compatibility stat rulesets. It also checks Earth Chain's explicit Nature school and Wind Arrows' explicit Physical school.
|
||||
- Focused validation passed: `npx vitest run src/game/romKnightScoutBloodPunishment.integration.test.ts src/game/romPriestKnightPairValidation.test.ts src/game/romScoutRoguePairValidation.test.ts src/game/romMageWarlockPairValidation.test.ts` (154 tests across four files).
|
||||
|
||||
No identity, stat input, health, loot, recovery, level-cap, or readiness scope changed.
|
||||
@@ -0,0 +1,107 @@
|
||||
# RoM five-class native scaling and automatic training gear
|
||||
|
||||
This targeted check covers Knight/Scout, Priest/Knight, Rogue/Warrior, Scout/Rogue, and Mage/Warlock using the named, race-legal identities in `src/game/romFiveIdentities.ts`. It does not promote RoM builds to Ready or introduce loot progression.
|
||||
|
||||
Other RoM classes remain available in the existing generated companion pools; this diagnostic verifies the five requested active identities and does not certify the other classes.
|
||||
|
||||
## Character and NPC growth
|
||||
|
||||
Player and companion native stats use `deriveCharacterStats(..., "rom")`, dispatched to `romNativeStats.ts`. Class-specific source growth starts from the level-one attributes and repeats `value = value * (1 + percentGrowth) + flatGrowth` for each additional level. Native HP/MP and attack/defense then use the source coefficients for the primary class, equipment, and active modifiers. Wisdom is a distinct attribute rather than WoW Spirit.
|
||||
|
||||
The shared simulator activates each named identity's secondary class at level 10 and treats its level as the primary level. The secondary contributes one tenth of its base growth; it does not supply a second complete equipment set. Native secondary Mana pools retain sourced MP, while the primary kit keeps its existing Mana/Energy/Focus resource behavior.
|
||||
|
||||
Generated RoM companions explicitly select native stats. A configured companion must explicitly pass `statRuleset: "rom"`; omission deliberately retains legacy WoW compatibility. Existing saved RoM players also retain WoW compatibility unless switched. A player's selector does not overwrite every NPC's independently owned mode.
|
||||
|
||||
The follow-up fixed two real NPC inconsistencies. `partyStore.ts` now normalizes creation and level synchronization to the shared finite 1–80 range before deriving gear, talents, resources, and secondary unlocks. Native full HP/MP remain equal to their precise caps after creation, leveling, and gear rescaling; wounded pools stay bounded and defeated actors remain at zero. `combatActorAuthority.ts` now refreshes a native companion's health cap when its source changes, preserving the live actor's precise health fraction. Previously a level-up could calculate the new member cap correctly, then actor synchronization could overwrite it with the old cap. Unchanged source/caps retain the authoritative live actor values.
|
||||
|
||||
## Gear without loot progression
|
||||
|
||||
RoM has no authentic heirloom item system. The simulator's shared equipment fallback supplies **automatic training gear** for the player and party, using compact ordinary RoM source-item references for these five classes. It fills eligible empty slots and recalculates the reference values with level, class, role, and applicable secondary weapon unlocks. Reference selection and interpolation are simulator policies, not the original game's acquisition or item-upgrade rules.
|
||||
|
||||
The existing player and NPC reference curve caps at level 79. At level 80, character base growth continues but automatic gear retains its level-79 values. This avoids inventing unsupported endgame gear. The same cap applies to both owners. Native item payloads are counted once; their accompanying WoW projection is ignored in native derivation.
|
||||
|
||||
Training references are not a smooth linear curve: source-item tiers/package anchors and weapon-slot unlocks cause step changes. An exact levels-1–80 audit found byte-identical player/NPC payloads; one example is Rogue's 65→66 increase of 912 DMG and 362 MDMG. At 79→80 all five classes' gear DMG/MDMG stay unchanged while base ATK/MATK grow. In this source version both attack-to-damage coefficients are zero, so gearless native DMG/MDMG are zero; the current shared adapter and ability resolver are still separate from complete native combat.
|
||||
|
||||
RoM fallback item names, source labels, and Equipment slot labels now say Training rather than Heirloom. Stable item IDs, internal quality, stat budgets, saved inventory, and assignment behavior are unchanged. The panel explains the level-79 cap. No loot source, drop table, boss reward, card reward, or loot distribution behavior is changed by this work.
|
||||
|
||||
## Enemy health
|
||||
|
||||
`src/scene/MobPopulation.tsx` passes both `contentCategoryForClass(player.classId)` and the player's selected ruleset to `dungeonEnemyScaling`. The original curve below follows character origin. The later native-only factor applies only to RoM-origin characters using native `rom` stats; RoM characters in legacy WoW-stat mode continue to use the original curve. Dungeon source, NPC composition, and party size do not select the health policy.
|
||||
|
||||
Ordinary enemy level follows player level, clamped to 1–80. Bosses have a one-level edge, also capped at 80. Before authored multipliers, RoM trash HP is:
|
||||
|
||||
```text
|
||||
round((1000 + 100 * L + 8 * L²) * (1 - max(0, L - 70) * 0.006))
|
||||
```
|
||||
|
||||
Campaign bosses use the larger of authored baseline HP and a separate durability floor:
|
||||
|
||||
```text
|
||||
max(trashBaseline(L) * authoredHealthMultiplier,
|
||||
(1000 + 1200 * L + 22 * L²) * 1.15 * finaleOrSliceFactor)
|
||||
```
|
||||
|
||||
Normal campaign finales use a 1.9 floor factor unless explicitly marked standard. Boss difficulty and any per-boss balance override then multiply the result. Bite-Sized bosses instead use their existing interpolated floor/ceiling bands. Boss Testing has its own reduced floor and may use source creature health. Manastorm follows its separate enemy modifiers. Dungeon difficulty chooses encounter/population variants; it is not an extra generic HP multiplier in this helper.
|
||||
|
||||
| Player level | RoM trash baseline HP | Boss level | Standard campaign boss floor HP |
|
||||
|---|---:|---:|---:|
|
||||
| 1 | 1,108 | 2 | 4,011.2 |
|
||||
| 10 | 2,800 | 11 | 19,391.3 |
|
||||
| 30 | 11,200 | 31 | 68,243.3 |
|
||||
| 60 | 35,800 | 61 | 179,471.3 |
|
||||
| 79 | 55,651 | 80 | 273,470 |
|
||||
| 80 | 56,588 | 80 | 273,470 |
|
||||
|
||||
These are the legacy WoW-stat baseline/floor examples, not every creature's final HP. The historical curve predates native character stats; the current native-only adjustment is separately anchored and measured below. Neither calculation claims a RuneWaker source mob-HP formula.
|
||||
|
||||
Anglo in full Barren Caves has an authored health multiplier of 7.5 and is the default finale, so its 1.9 finale floor dominates from level 10 onward. Its actual registered legacy-mode HP at player levels 1/10/30/60/79/80 is **9,240 / 36,843 / 129,662 / 340,995 / 519,593 / 519,593**; native-stat RoM multiplies those results by the separate boss anchor below. The older `romDungeonHealth.test.ts` boss sample manually used baseline × 7.5 rather than the actual finale floor, and initialized a compatibility-mode player with seed-selected native NPCs. That older sample is not evidence for a complete native five-identity party or the current real boss pool.
|
||||
|
||||
The earlier fixed-cohort diagnostic is historical: it rotates five identities into the player seat, explicitly creates four native companions, and samples one real Barren Caves trash spawn and Anglo at six levels (60 samples) while omitting active player damage except Priest healing. It predates exact-pair active player rotations and native-only HP pacing, so its timings and defeats are not current outcomes.
|
||||
|
||||
| Player level | Trash kill-time range | Anglo kill-time range |
|
||||
|---|---:|---:|
|
||||
| 1 | 15–18 s | 148.2–232.3 s |
|
||||
| 10 | 4.5–7 s | 82–105 s |
|
||||
| 30 | 10.5–12 s | 78–118.3 s |
|
||||
| 60 | 7.6–11 s | 49.5–72 s |
|
||||
| 79–80 | 2.5–5.4 s | 25–37.5 s |
|
||||
|
||||
The saved earlier report records that all 60 samples completed; trash had no companion defeats, while level-one Anglo caused companion defeats in four of five variants. This was a conservative diagnostic because active player damage was omitted, not a balance certification or automatic tuning target. Its 240-second level-one boss limit and 120-second limit elsewhere differ from the current fixed-rotation report.
|
||||
|
||||
## Evidence
|
||||
|
||||
- `src/game/romFiveNativeDungeonHealth.test.ts`: three targeted checks passed, including the actual RoM/WoW dungeon HP helper, all 60 fixed-cohort samples, and boss difficulty/finale behavior. Diagnostic report: `artifacts/rom-five-native-dungeon-health/report.json` (ignored local artifact).
|
||||
- Exact gear audit: player/NPC owner contexts match for all five identities; reference payloads were inspected across levels 1–80, including weapon unlocks, source tier jumps, and the 79→80 plateau.
|
||||
- The final focused selection passed 176 tests across 12 files. The new parity suite contributes 13 cases covering the five native player/generated/configured identities at levels 1/9/10/30/60/79/80, explicit-versus-omitted rulesets, secondary unlock, level bounds, owner gear parity, and full/wounded/defeated pools. Existing native aura/channel/periodic integration and legacy compatibility regression tests also passed.
|
||||
- Ready-five passed seven Vitest and twenty Python checks. Avatar validation passed 47 tests across ten files before the subsequent party-only fixes; avatar and numerical gear code were not changed afterward.
|
||||
- Final full production build passed: 8 GB TypeScript project compilation, Vite (1,266 modules), asset audits, compression, and release-bundle verification (5,562 objects, 123 chunks). Final chunks: `index-Ba_szGct.js`, `combatStore-BGky6YlB.js`, and `PartyFrames-CcpsvWIi.js`.
|
||||
- Exact-final-dist Edge QA passed through `scripts/playtest-stat-rulesets.cjs` using an isolated temporary account/server. Native player tabs, a native Mage NPC owner panel, Training gear labels/cap note, legacy migration, independent saved mode choices, switching locks, build/checkpoint preservation, both native/compatibility dungeon runs, and desktop/390-pixel layouts passed. Visual review confirmed roster and both dungeon character bodies with held starter staffs and closed overlays/loading intro.
|
||||
- Browser report: `playtest-artifacts/stat-rulesets/results.json` and its eleven referenced screenshots, including `05-native-npc-stats-attributes-desktop.png`. Diagnostics had zero page errors, HTTP failures, or failed application-resource responses; the only console response error was the optional favicon 404. Synthetic legacy/combat/online fixtures remain guard checks, not a live multiplayer certification.
|
||||
- Final `npm run release:check` and `git diff --check` passed, including untracked files and concurrent unrelated work. The four owned vault notes passed whitespace/EOF checks. The prior stat-ruleset validation remains in `docs/CHARACTER_STAT_RULESETS_2026-10-03.md`; its 219-test result is historical and is not added again to this task's totals. This follow-up supersedes the browser artifacts stored at the shared stat-rulesets path.
|
||||
|
||||
## Player-rotation combat follow-up (2026-10-03)
|
||||
|
||||
The final diagnostic in `src/game/romFiveNativeRotation.integration.test.ts` uses the shared `BenchmarkController` rotation and damage path, turns each requested identity into the player in turn, explicitly constructs the other four native identities as companions, and samples one real Barren Caves trash spawn plus Anglo at levels 1/10/30/60/65/66/79/80. This is 80 fixed samples with static actors, not a scene-driven dungeon run; navigation and authored encounter mechanics remain outside its scope.
|
||||
|
||||
The post-haste-retention report records 80/80 cleared pulls, zero player or companion deaths, and zero invalid cast failures. Trash took 4.5–9 seconds; Anglo took 39–53.4 seconds. The harness checks for a dead target before making another controller decision. Actors remain fixed in place; no navigation or authored encounter mechanics run.
|
||||
|
||||
## Native-only enemy health pacing (2026-10-03)
|
||||
|
||||
`dungeonEnemyScaling` accepts a selected character stat ruleset with a backwards-compatible default of `"wow"`. Live `MobPopulation` passes the active player ruleset. The added piecewise-linear factor is active only for RoM-origin characters using native `"rom"` stats; it leaves the legacy RoM curve, WoW/CoA-origin results, enemy damage, level, boss difficulty, authored multipliers, and level-80 cap unchanged.
|
||||
|
||||
| Character level | Trash scale | Boss scale |
|
||||
|---:|---:|---:|
|
||||
| 1 | 0.9 | 0.45 |
|
||||
| 10 | 1.4 | 0.85 |
|
||||
| 30 | 1.4 | 0.95 |
|
||||
| 60 | 1.5 | 1.25 |
|
||||
| 65 | 1.8 | 1.5 |
|
||||
| 66 | 2.1 | 1.9 |
|
||||
| 79 | 3.6 | 2.8 |
|
||||
| 80 | 3.6 | 2.8 |
|
||||
|
||||
Values between anchors interpolate linearly against the clamped 1–80 character level. This is a simulator health budget measured against the five canonical training builds, not a source RuneWaker mob-health formula. The general generated companion pool and RoM readiness state are unchanged.
|
||||
|
||||
`artifacts/rom-five-native-rotation/before-native-combat.json` is the earlier 60-sample, six-level comparator; it predates the current native-only health policy and the final eight-level active-rotation matrix. Do not treat it as a paired health-curve experiment. Native amount routing, supported auto-attack channels, limitations, and current verification state are summarized in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md).
|
||||
|
||||
The final production build passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed against `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`; 11 screenshots were captured and four representative roster, dungeon, NPC-stat, and 390×844 mobile screenshots were visually reviewed. No page/server errors occurred and the network response-errors list was empty; the only console error was the optional existing favicon 404. A release check passed on 249 paths; the final documentation update requires the final hygiene/release check. The full source hit/defense model and RoM readiness certification remain outside this follow-up.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Interrupt, sustain, route and Killing Spree follow-up — 2026-10-04
|
||||
|
||||
## Scope
|
||||
|
||||
The authorized follow-up checks Vow of Silence against Lady Anacondra, repeated native RoM level-60/80 healing sustain, real Barren Caves/Wailing Caverns route play, and the separate Killing Spree catalog assertion. Work uses Luna subprocesses with extra-high reasoning. The five active native identities remain Needs Testing; the WoW Ready five remain the routine certification scope.
|
||||
|
||||
Recovery formulas, automatic Training gear, the level-80 cap, saved-profile compatibility defaults and loot scope are preserved. No readiness promotion, commit or deployment is included.
|
||||
|
||||
## Interrupt source correction
|
||||
|
||||
The previous Lady Anacondra Vow attempt resolved while the same Lightning Bolt cast remained active. The pinned AzerothCore source uses `CreatureImmunitiesId` as a foreign key, but the importer treated it as a literal signed mechanic mask. Row -93 resolves to Fear and Horror only. The importer now loads the exact pinned immunity table, normalizes its enum-indexed mask into the existing runtime representation, and preserves legacy literal-mask sources. Missing nonzero foreign keys fail closed. Generated Lady creature 3671 now has legacy mask 8388624 and no Silence/Interrupt immunity. The table fixture and SHA-256 make regeneration reproducible; no Vow duration or recovery formula changed.
|
||||
|
||||
## Repeated NPC healing sustain
|
||||
|
||||
The native Knight player and owned Priest/Rogue/Scout/Mage party complete three consecutive source Anglo pulls at each of levels 60 and 80, with a 10-second rest followed by a 90-second rest. Actor health, Mana, effects and cooldowns continue between pulls. All six pulls clear with no deaths or empty Priest Mana pools.
|
||||
|
||||
The owned Priest's level-60 delivered healing is 39,753 effective plus 70,327 overheal (63.9% overheal); level 80 is 183,396 effective plus 80,845 overheal (30.6%). Telemetry separates raw event amounts, delivered healing, actual Mana pools, starting Mana capacity and estimated cast costs. Every observed direct Heal begins on an injured party/player snapshot, even though Regenerate is active. A HoT-only suppression rule was not justified, so healing AI and sourced recovery remain unchanged. This is a six-pull diagnostic rather than every-encounter sustain certification.
|
||||
|
||||
## Killing Spree audit
|
||||
|
||||
The old representative-signature failure came from requiring a generic non-utility effect for a source periodic-dummy selector. The test now requires Killing Spree's exact `class-script` shape while preserving its dedicated ten-strike player regression. The independently verified child 61851 provides a 20% all-school damage buff for two seconds; the player aura previously used 1% and now uses 20%. All 81 focused Rogue/catalog/rotation tests pass.
|
||||
|
||||
Companions still lack the Killing Spree script handler. The player's immediate assaults and deterministic target selection remain approximations. This targeted audit does not promote Combat Rogue or establish full timing/targeting parity.
|
||||
|
||||
## Campaign route review
|
||||
|
||||
The ordinary roster-to-dungeon entry baseline found the floating Roster details toggle covering Continue at 1440×900. Single-screen roster spacing now reserves a strip below the footer for that toggle; dual-display layouts retain their own spacing. Final normal-click checks at 1440x900 and 390x844 show no overlap; no force click is used in final evidence.
|
||||
|
||||
Both original campaign dungeons receive 90-second entrance/encounter segments through normal selection and inputs. Barren Caves records 69.34 units of accumulated travel, 41 keyboard steps, 15 effective player heals (~6,155 healing), seven player damage events (549 damage), and no party deaths. It naturally levels the UI-created Priest/Knight from 30 to 31. The subsequent fixed-level harness assertion stopped that cross-route session; its completed Barren phase remains valid. Wailing Caverns is replayed independently from a fresh level-30 profile and records 23.76 units of travel, 15 keyboard steps, 11 effective player heals (~6,831 healing), three observed entrance enemy deaths, and no party deaths. Wailing records zero player damage, so that segment establishes targeting/healing and companion combat rather than player DPS. Both final phases have no page errors; the logged 404 is identified as favicon.ico.
|
||||
|
||||
The first longer Wailing attempt lost its tank after repeated out-of-range heals while the automated healer fell behind. Its trace is preserved. The corrected harness prefers the available ranged spell, reads actual companion positions, follows wounded allies into healing range, waits for casts, and uses normal Attack/Defend inputs to contain the entrance encounter. No game balance or recovery formula was changed to obtain the rerun.
|
||||
|
||||
Evidence is in `playtest-artifacts/native-routes/final-20261004-051413627/` (completed Barren phase), `final-20261004-051737171/` (failed Wailing positioning diagnostic), and `final-20261004-052623521/` (corrected Wailing phase). Midpoint and endpoint screenshots were visually inspected. Cave geometry partially occludes endpoint views; these are bounded input/combat checks, not full route, boss-clear, navigation-guide, camera or compact-layout certification.
|
||||
|
||||
## Detailed evidence
|
||||
|
||||
- `docs/VOW_OF_SILENCE_AUDIT_2026-10-04.md`: source identity, immunity and interrupt investigation.
|
||||
- `docs/ROM_NATIVE_SUSTAIN_AUDIT_2026-10-04.md`: actor-attributed repeated-pull Mana and healing diagnostics.
|
||||
- `docs/WOW_KILLING_SPREE_AUDIT_2026-10-04.md`: catalog assertion and dedicated runtime audit.
|
||||
- `docs/ROM_NATIVE_ROUTE_PLAYTEST_2026-10-04.md`: normal campaign entry, movement, targeting and healing segments, roster hit checks, screenshots and telemetry.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused checks pass: 40 interrupt/enemy integration cases, five importer cases, 81 Rogue/catalog/rotation cases, and the six-pull sustain diagnostic. The final Vow-only rerun passes eight cases. Ready-five certification remains green with seven Vitest and twenty Python cases. App TypeScript and the production build pass, including asset audits, compression and bundle verification.
|
||||
|
||||
The coordinated build contains `index-CAMDJqEC.js`, `combatStore-t7bO4yKt.js`, `GameRuntime-otPnJCWI.js`, `PartyFrames-BsBsesPR.js`, and `index-499eecpe.css`. The CSS includes the roster footer clearance fix. Existing chunk-size/import warnings remain; the asset performance audit reports no new regressions.
|
||||
|
||||
Vault diff checks and owned-text hygiene pass for 26 files. The repository release check initially found an extra EOF blank line in the concurrently edited `src/game/benchmark/coaFirstParty.ts`; only that final newline was normalized, preserving its code. Final release hygiene is checked after these documentation edits.
|
||||
@@ -18,7 +18,7 @@ Generated player source IDs and component payloads are in `src/game/romPlayerCat
|
||||
| 492935 → 493094 | Component 503192 triggers every 3 seconds for 15 seconds. Child RunPlot is `lua_star_ParryState` in `01129.lua:120`: it checks `EM_RoleValue_ParryState == 1`, checks buff 503192, then adds buff 503200 (Lua argument 20); if 503192 is absent it cancels 503200. Component 503200 carries +5000 Parry and a 15-second lifetime in the local object data. | Current runtime applies +5000 Parry for 15 seconds and consumes it after two blocks; the hidden periodic aura is also kept for 15 seconds. The `EM_RoleValue_ParryState` set/reset condition and the distinct conditional 503200 application are not represented. Prerequisite: map that role-state value and its event lifecycle before wiring the child; do not turn the Lua argument into a duration by assumption. |
|
||||
| 492939 → 493246 | Component 503207 triggers on timeout after 15 seconds. Child RunPlot calls `lua_Dy_DELAnother(503207, 506236)` in `01129.lua:518`; the helper cancels 506236 only when 503207 is absent. Both local effects are 15 seconds. | No distinct numeric combat payload is added by the child. Natural expiry aligns; early removal of 503207 and the resulting cleanup of 506236 are not represented. Prerequisite: source-backed buff-removal/timeout event semantics if early cancellation is intended to be observable. |
|
||||
| 493273 → 491614 | Component 502056 triggers on hit. `lua_star_ProtectAlly` in `01129.lua:313` reads last damage, the buff owner, and `BuffInfoType_Power` (`PLV`), removes 502056, then computes `p = 0.40 + 0.008 × PLV`; it casts child 491612 on the original buff owner with `floor(abs(lastDamage × p / (1 − p))) × 2`. | `romPriestKnightOverrides.ts` currently uses a fixed 40% one-hit redirect and +20 Parry. This is an active approximation: it does not preserve the buff's `PLV` or apply the rank-dependent split formula. Prerequisite for a correct shared player/companion implementation: define the source value stored as `BuffInfoType_Power` for 502056, then carry it through the application and incoming-hit paths in `combatStore.ts`/`partyRuntime.ts`; cover it in `romPriestKnightPairValidation.test.ts`. |
|
||||
| 499923 → 499910 | Component 623167 triggers every second for 30 seconds. `lua_bico_kni_sco_es_70_blood` in `02708.lua:257` cancels 623167 whenever owner buff 500871 is absent. | Knight/Scout passive marker and Blood Arrow's 50% healing-received/30-second effect are represented. The source's early-cancel check when 500871 is removed is not. Prerequisite: observe source-marker removal and cancel the associated aura on player and companion paths; ordinary matching 30-second expiry is already compatible. |
|
||||
| 499923 → 499910 | Component 623167 triggers every second for 30 seconds. `lua_bico_kni_sco_es_70_blood` in `02708.lua:257` cancels 623167 whenever owner buff 500871 is absent. | Superseded by current CoA's matching Knight/Scout passive: +15% received healing and +5% Light/Holy damage while Blood Arrow is active. `romKnightScoutBloodPunishment.ts` attaches both modifiers to the actual owner Blood Arrow aura, so removal/expiry ends the rider without a separate child timer. The base Blood Arrow still uses the local 30-second, periodic-HP-cost model; CoA toggle/per-ranged-skill cost parity remains open. See `docs/ROM_FIVE_MECHANIC_GAPS_2026-10-04.md`. |
|
||||
| 495402 → 497924, 497926 | These are timeout children of the old Leopard Instinct active effects. The local `un_495402_cancelbuff` RunPlot in `02383.lua:182` cancels old buffs 620144/620141/620142/620143. | Superseded by current CoA's passive stack behavior. Existing pair handling suppresses the old active effects; do not restore these timeout children. |
|
||||
| 493047 → 493183 | The local RuneWaker 493183 child is a MagicFunc1 on-hit self-reference. Its tooltip conditions a chance-based +2 Dodge aura on being attacked while Shield of Valor or Shield of Discipline is active, but the numeric chance and required-shield check are absent. | Current CoA's [Knight/Rogue row](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) identifies 493047 as Panther's Blessing, a level-45 passive that restores 10% HP and 1% MP on dodge. The exact learned Knight/Rogue passive now triggers from the actual resolved incoming dodge result for the player and generated companions. Because CoA does not publish the percentage bases or a rounding rule, the simulator uses the owner's maximum HP and mana pools and rounds to whole points; each restore is capped to its current pool. The published current row has no rank curve, so these percentages are flat and no scaling is inferred. The legacy 493183 shield-conditioned +2 Dodge child stays suppressed. God's Vengeance is the separate passive 499934. See `docs/ROM_KNIGHT_PANTHER_DODGE_PROC_2026-10-02.md`. |
|
||||
| 499934 → 499909 | Current CoA's [Knight/Rogue list](https://chroniclesofarcadia.com/wiki/skills/list/6-3?locale=ru) identifies God's Vengeance as passive 499934, level 50: when Punishment hits a target with exactly four Holy Seal stacks, reset Shadow Step. The local LearnMagic row independently makes child 499909 learnable by Knight/Rogue at level 50 with key item 542123 and prerequisite 499934. Its MagicCollect components match general Punishment 490151's payload; 499909 remains a separate child row rather than an alias of general 490151. | The exporter emits this exact linked child as a second level-50 row. It keeps Punishment's direct damage and ordinary Seal consumption, scales the one hit by the pre-spend Seal count, and removes the retired Seal DoT. Player and generated-companion casts reset only the casting actor's learned Shadow Step (490344) when the exact child lands against its own target with four of that target's Seals. A landed combat event is the runtime's “hits” boundary, including full absorbs; miss/dodge, wrong pair, missing passive/Shadow Step, general 490151, and three/five-stack cases do not reset. Companion AI selects 499909 when it is ready and usable, otherwise retaining its general Punishment fallback. |
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# RoM native combat pass — 2026-10-03
|
||||
|
||||
The later [native resolution and enemy damage-type pass](ROM_NATIVE_COMBAT_RESOLUTION_PASS_2026-10-03.md) supersedes the open defense/hit/critical, negative DotMagic and special/multi-target input boundaries below. This report preserves the original amount/rotation pass and its historical validation.
|
||||
|
||||
## Scope and status
|
||||
|
||||
This pass connects source-derived native amount bindings to the existing combat runtime for the five targeted identities: Knight/Scout tank, Priest/Knight healer, Rogue/Warrior damage, Scout/Rogue damage, and Mage/Warlock damage. `romFiveIdentities.ts` remains the identity owner. The new shared-rotation profiles are exact-pair and role gated; they are clean-room heuristics informed by local active catalog data and the add-on source research in [`ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md`](ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md). No add-on code was retrieved or installed. CurseForge's archive request reached a Cloudflare JavaScript/cookie challenge, so the profile priorities are not copied presets.
|
||||
|
||||
The native amount routes improve source fidelity, but this is not a full RoM combat port or balance certification. Formula outputs still pass through HealerMan's shared target and combat-state machinery. Unsupported source shapes and gear intentionally retain the documented simulator fallback. The five identities remain targeted-test builds; no readiness or random-pool promotion is included.
|
||||
|
||||
## Binding and amount routing
|
||||
|
||||
`romAbilityCatalog.ts` attaches `romNativeSource` skill/component identities to supported active RuneWaker ability effects. `romNativeCombatAmount.ts` resolves those identities against the generated source binding catalog. The native route runs from `equipmentAdjustedCombatAmount` only for a RoM stat ruleset and a nonnumeric, source-bound ability amount. It tries the specific direct HolyHeal branch, the supported direct damage branch, and the periodic HolyHeal snapshot. If a source binding or required profile is unsupported, it returns no native amount and the existing shared HealerMan coefficient/scaling path continues.
|
||||
|
||||
`romNativeMagicLevel(level)` uses the active character level clamped to the project's 1–80 range as the simulator's effective `MagicProc.MagicLv`; it does not infer skill rank or a separate skill-level curve. The active player-build companion amount routes use the source `player` classification for the native player ExRate branch even though the runtime owner is an NPC actor. This is an explicit simulator choice for the five playable builds, not a claim about every ordinary RoM NPC.
|
||||
|
||||
Direct native damage requires a supported source attack component and the active five-class training-weapon profile. Since the stat sidecar has no item provenance or weapon speed, the adapter compares the complete native gear payload with the canonical automatic training profile before reversing its weapon contribution. Unverified/custom gear, unsupported class pairs, missing weapons or component bindings, unsupported calculation types, and unavailable school rates return an unsupported result; the generic shared amount path then remains in force. These gates prevent inferred weapon values from being presented as source-derived.
|
||||
|
||||
The direct damage helper returns a positive mean source power after its source target-count factor, before source random range/critical handling and target defenses. Its checked `MagicAttackCalENUM` fixed-type branches support 0, 1, 2, 3, and 5–9; throw, prior-hit, and shield-category inputs remain unsupported because the stat sidecar lacks those exact source values. The consumer also declines components marked `isShareDamage`, or nonzero `decreaseArg` on nonzero `rangeType`, until it receives the runtime target count and ordinal; the pure amount helper can represent those fields but the current consumer does not claim area-damage exactness. Reflected Shot has a regression check for this fail-closed behavior. Supported single-target ability amounts pass to the shared target-resolution path for modeled hit/critical rules, resistance/armor, target auras, absorbs, and damage application. It does not yet resolve every RoM source hit/avoidance point, native defense channel, ability random roll, or source critical-rate field.
|
||||
|
||||
`nativeTrainingAutoAttackProfile` provides native physical weapon damage and intervals for player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks; NPC Rogue offhand is also covered. Player Rogue offhand handling requires an explicitly present equipped inventory item. It does not claim a player Scout bow auto profile: player Scout Shot instead uses the native direct-damage route for its actual bound Shoot hit. Caster ambient basic-spell attacks retain their generic interval and MDMG policy. Player melee timing explicitly reads the existing common haste aura via `resolveAuraStatValue` because native stat re-derivation does not populate the shared haste fields; race-affix timing is retained as well. Four focused auto/source-action cases passed: player Knight Main_DMG/source interval with semantic 50% haste, NPC Scout Bow/source clock with ranged haste, NPC Rogue offhand Sec_DMG/offhand clock with melee haste, and a player Scout Shot resolving an actual bound hit. These are source-backed channels, not complete native hit/avoidance, armor, variance, or critical models.
|
||||
|
||||
Outgoing damage-over-time still uses native stat inputs through the shared simulator amount path. The source DotMagic snapshot implemented in this pass covers healing; source-native periodic damage remains future work.
|
||||
|
||||
## Direct HolyHeal
|
||||
|
||||
`romNativeHealing.ts` resolves only source-bound calculation type 5 components. It applies the source MagicLv-adjusted `OrgPower`, clamped `SpellTime`, Wisdom/MND contribution and cap, MDMG coefficient, MPow, HealPowerRate, and HealPoint. The amount adapter samples `RandomRange` at its midpoint (`randomUnit = 0.5`), producing mean source power; the common healing resolver still handles its critical and overheal behavior.
|
||||
|
||||
The caster amount is computed without recipient-specific HealAbsorb modifiers. At each real recipient, `nativeHolyHealTargetAmount` applies that target's HealAbsorbRate and HealAbsorb once, unless the component says to ignore absorption. Normal aura/talent and healing-result stages then run through the shared resolver. This prevents the recipient's native absorption stats from being folded into caster power and applied a second time. Group heals resolve each recipient independently.
|
||||
|
||||
## Periodic HolyHeal snapshot
|
||||
|
||||
Source DotMagic healing is separate from direct HolyHeal. `nativePeriodicHealSnapshot` resolves the supported positive-HP DotMagic component when the buff is applied, using the caster/recipient native stats and the source rank, duration, tick interval, and effective MagicLv. The source rank correction computes a `Buff.Power` snapshot with MND, MDMG, HealPowerRate, HealPoint, the available MPow input, and the target absorption inputs, then stores the integer tick amount. Later ticks reuse the stored value; they do not rerun the caster formula or apply target absorption again.
|
||||
|
||||
This follows the observed Runewaker `CalAddDotMagicLv`/`BuffProc` ordering for bound components. The current sidecar exposes neutral all-magic MPow but not every element-specific `BodyRate`, so callers must not read the current default as proof that all elemental healing rates are 1. Unsupported DotMagic shapes return no native snapshot and continue through the existing fallback.
|
||||
|
||||
## Rotation and validation boundary
|
||||
|
||||
`romFiveRotation.ts` selects only the exact ordered `(statRuleset, primary, secondary, role)` tuple at level 10 or above. It retains learned catalog damage actions as low-priority fillers, while pair-specific guards cover cooldown/setup priority, useful target lifetime, AoE target minimums, emergency healing, current DoT ownership, and near-expiry refresh. The shared evaluator and its party/benchmark callers continue to enforce learned ability, cooldown, resource, range, target, and movement readiness. Pre-secondary levels and unsupported pairs stay on the existing semantic path. WoW keeps its existing specialization selector and is not filtered by the native RoM guards.
|
||||
|
||||
`romFiveRotation.integration.test.ts` covers all five exact pairs against active learned catalog abilities, a healthy Priest/Knight using Group Heal for injured allies, Urgent Heal before throughput when an ally is critical, actor/target-owned DoT refresh timing, and the unchanged WoW profile selector. The focused module and integration suites pass together (17 tests).
|
||||
|
||||
The fixed full-player diagnostic in `romFiveNativeRotation.integration.test.ts` rotates each of the five identities into the player seat, creates the other four native party members explicitly, and uses the shared BenchmarkController against a real Barren Caves trash spawn and Anglo at levels 1/10/30/60/65/66/79/80. This is 80 fixed samples, not a scene-driven encounter: actor positions are static and encounter mechanics/navigation are not simulated. The test writes `artifacts/rom-five-native-rotation/report.json`. `artifacts/rom-five-native-rotation/before-native-combat.json` preserves the earlier 60-sample, six-level pre-native-combat baseline. The final post-haste-retention report records 80/80 pulls completed, no player or companion deaths, and zero invalid casts. Trash kills were 4.5–9 seconds and Anglo was 39–53.4 seconds. The harness now checks for a dead target before requesting another player decision, so post-kill no-target attempts are not counted.
|
||||
|
||||
## Native-only health pacing
|
||||
|
||||
`dungeonEnemyScaling` now accepts the selected character stat ruleset, defaulting to `"wow"` for existing callers. Live `MobPopulation` passes the active character's ruleset. A piecewise-linear enemy-health factor applies only when the character source is RoM and the selected ruleset is native `"rom"`; legacy WoW-stat RoM characters retain their prior curve, and WoW/CoA-origin characters are unchanged. The factor changes neither damage nor enemy level, boss difficulty, authored multipliers, or the level-80 cap.
|
||||
|
||||
The anchors are indexed by clamped character level and each row is [trash health scale, boss health scale]:
|
||||
|
||||
| Level | Trash | Boss |
|
||||
|---:|---:|---:|
|
||||
| 1 | 0.9 | 0.45 |
|
||||
| 10 | 1.4 | 0.85 |
|
||||
| 30 | 1.4 | 0.95 |
|
||||
| 60 | 1.5 | 1.25 |
|
||||
| 65 | 1.8 | 1.5 |
|
||||
| 66 | 2.1 | 1.9 |
|
||||
| 79 | 3.6 | 2.8 |
|
||||
| 80 | 3.6 | 2.8 |
|
||||
|
||||
This is a targeted native RoM simulator pacing policy measured against the five requested builds, not a claim about RuneWaker monster-health formulas or full balance. It does not alter loot, progression, source enemy damage, or readiness. The ordinary randomized companion pool is now restricted to the active five identities; the broader configured factory remains available for explicit party construction. This diagnostic's five fixed identities do not promote readiness or broaden the general pool.
|
||||
|
||||
## Current verification status
|
||||
|
||||
The focused 15-file selection passed 210 tests. Direct and periodic native healing coverage passed 14 player/NPC cases. The source-damage follow-up passed 13 focused tests: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and the four actual auto-attack cases above. Ready-five passed seven Vitest and twenty Python checks, avatar validation passed 47 tests, and the final TypeScript project check passed. One separate `combatRotation.test.ts` case still fails its existing unsupported-only `Killing Spree` expectation; that unrelated behavior is unchanged here. The final production build passed with asset audits, compression, and bundle verification. Browser QA passed on the current `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js` chunks; 11 screenshots were captured and four representative roster, dungeon, NPC-stat, and mobile screenshots were visually reviewed. There were no page/server errors and the network response-errors list was empty; the only console error was the optional existing favicon 404. `npm run release:check` passed on the final 249 changed paths, including untracked files; `git diff --check` passed. The worklog is closed; the unrelated Killing Spree test and remaining source-formula boundaries are documented above.
|
||||
|
||||
The fixed diagnostic instantiates only the five requested identities. The ordinary randomized companion pool is now restricted to those five, while the configured factory remains broader for explicit compositions. The pass does not alter the loot path, raise the level cap, change enemy damage, or promote RoM readiness.
|
||||
|
||||
## Source and validation references
|
||||
|
||||
- Source formulas and archived boundaries: [`ROM_NATIVE_STATS_SOURCE_2026-10-03.md`](ROM_NATIVE_STATS_SOURCE_2026-10-03.md), [`CHARACTER_STAT_RULESETS_2026-10-03.md`](CHARACTER_STAT_RULESETS_2026-10-03.md)
|
||||
- Exact-pair add-on research and clean-room policy: [`ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md`](ROM_ROTATION_ADDON_REFERENCE_2026-10-03.md)
|
||||
- Native amount code: `src/game/romNativeCombatAmount.ts`, `src/game/romNativeHealing.ts`, `src/game/romNativeDamage.ts`
|
||||
- Native rotation code and focused coverage: `src/game/romFiveRotation.ts`, `src/game/romFiveRotation.test.ts`, `src/game/romFiveRotation.integration.test.ts`
|
||||
- Targeted fixed-cohort diagnostics: `src/game/romFiveNativeDungeonHealth.test.ts`, `src/game/romFiveNativeRotation.integration.test.ts`
|
||||
|
||||
No loot/progression, legacy/global enemy-HP curve, gear-cap, or readiness-promotion change is part of this pass. A separate native-stat RoM health budget was added and leaves the compatibility curve unchanged.
|
||||
@@ -0,0 +1,43 @@
|
||||
# Native RoM combat resolution and enemy damage types — 2026-10-03
|
||||
|
||||
This follow-up implements the requested native defense, hit/avoidance/critical, outgoing periodic-damage, special-input and multi-target consumers, and checks enemy damage classifications for both WoW and RoM. It supersedes the open native-combat boundaries in `ROM_NATIVE_COMBAT_PASS_2026-10-03.md`; the earlier report remains historical evidence.
|
||||
|
||||
The later [enemy equipment, encounter and pressure pass](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md) supersedes this report's equipment/manual-enemy-formula limitations and final damage-budget/browser evidence. The measurements below describe this earlier resolution pass; the native health anchors remain current.
|
||||
|
||||
## Actor and source boundaries
|
||||
|
||||
Every player and party member retains their own stat ruleset. Supported canonical active-five native builds resolve against an exact imported RuneWaker NPC using `romNativeCombatResolution.ts`. The incoming path derives the recipient's own secondary class, gender and ruleset before choosing native resolution. WoW-mode recipients keep their compatibility resolver even when another party member uses native stats. Native points are never converted into WoW ratings.
|
||||
|
||||
`export-rom-native-combat-data.mjs` owns the compact source growth, FIX, skill, spell-binding and population-entity mapping data. `runewakerNpcId` is carried from population registration to combat state independently of WoW creature/server entry IDs. Player level remains capped at 80. The source provider accepts an explicit NPC level 81 in its tests; this does not raise the live scaling cap, and the final diagnostic's enemy levels stay at or below 80.
|
||||
|
||||
Canonical training gear and the five exact active class pairs are the supported player source scope. Missing source NPCs, custom/unverified gear, ambiguous source equipment or unsupported source calculations retain a declared shared fallback. NPC source derivation does not replace the game's authored/scaled encounter health pools or damage budgets. No loot, matchmaking or readiness promotion is included.
|
||||
|
||||
## Damage calculation, hit gate and school
|
||||
|
||||
These source fields have independent meanings. MagicCollect `EffectType` selects the hit gate. MagicObject `Attack.CalType` selects the direct physical or magical calculation and critical path. MagicBase `MagicType` identifies the native elemental resistance channel. A physical calculation can therefore deal Light damage; classifying every physical calculation as Physical school loses source information. DotMagic retains its own MagicBase `EffectType` semantics.
|
||||
|
||||
The compact enemy classifier keeps the WoW and RuneWaker spell-ID namespaces separate. WoW packets retain DBC `DmgClass` and the complete `SchoolMask`; the seven single schools map directly, while composite masks retain the existing authored single-school mitigation policy. Missing source spells and non-damaging script placeholders preserve authored packet types. RuneWaker stores the raw six channels separately from their simulator aliases: Earth/Wind → Nature, Water → Frost, Fire → Fire, Light → Holy and Darkness → Shadow. Exact native resistance lookup continues to distinguish Earth from Wind.
|
||||
|
||||
Source-qualified packets feed the existing structured combat events, immunity checks, absorbs and health application. Enemy ranged attacks no longer depend on a delivery-shape guess to select their hit kind. Classification coverage and source gaps are recorded in `ENEMY_DAMAGE_TYPES_AUDIT_2026-10-03.md`.
|
||||
|
||||
## Periodic damage and special inputs
|
||||
|
||||
`romNativePeriodicDamage.ts` owns source-negative HP/HP_Per DotMagic rank correction and application snapshots. Player casts and companion casts bind the exact skill/component. NPC casts also retain their assigned source MagicLv. Source target defense/resistance and caster power are evaluated at application; ticks reuse stored Buff.Power without new critical, hit, armor or resistance rolls. HP_Per reads the recipient's current maximum HP on every tick.
|
||||
|
||||
Enemy periodic effects have their own scheduler and are removed by dispels and encounter resets. Natural expiry preserves the final due tick; the source caster can die while an already-applied periodic effect remains. Native tick amounts then pass through ordinary generic dealt/taken modifiers and shields once. Unsupported snapshots retain the existing path. The exact source/runtime cases and unsupported reapplication/resource shapes are documented in `ROM_NATIVE_PERIODIC_DAMAGE_SOURCE_2026-10-03.md`.
|
||||
|
||||
The direct and periodic components of one source MagicCollect share the per-target application hit gate. Native hit/dodge/miss seeds therefore use a common cast-target key; critical/block/parry rolls retain their individual packet keys. Incoming periodic application also retains the actual attack revision. An exact native gate remains valid even when an unsupported direct calculation needs the shared amount/mitigation adapter: a passed gate disables the adapter's additional miss/dodge roll. The imported Big Ripper CalcType 4 regression covers this boundary. Cross-system WoW `incoming-*-hit` aura adjustments are not mapped into the native source gate; that mixed-aura bridge remains outside the active-five source scope.
|
||||
|
||||
The active-five source audit found Throw fixed inputs and raw ShieldDef inputs, with no prior-hit fixed types. Canonical training Throw derives the source Fin.Throw_DMG channel, including the second DMG_Per factor; shield calculations use raw BaseEQ shield defense, excluding fixed WearEq DEF. Prior-hit inputs remain explicit unsupported values until a real source consumer needs them. Multi-target source power receives actual recipient count and ordinal in both player and companion loops. Source sharing and ordinal falloff are applied once; the generic AoE falloff does not multiply the native result again.
|
||||
|
||||
## Validation
|
||||
|
||||
The source-resolution diagnostic before the health adjustment cleared all 80 fixed pulls with no deaths or invalid casts, with both selected NPCs source-supported. Trash took 4.5–17.7 seconds and Anglo 24–85.5 seconds. Those measurements justified changing only the native RoM health factors; the compatibility curve, damage budgets, difficulty multipliers and cap remain intact. `before-native-resolution-pacing.json` preserves this distinct baseline.
|
||||
|
||||
The final native health anchors are [trash, boss]: level 1 [0.4, 0.3], 10 [1.0, 0.6], 30 [1.1, 0.85], 60 [1.5, 1.5], 65 [1.8, 1.9], 66 [2.6, 2.8], and both 79/80 [4.5, 4.8]. Intermediate levels interpolate linearly. These are measured simulator training-party budgets, not RuneWaker monster-health formulas. The static cohort is diagnostic evidence for these five requested builds, not an all-class balance certification.
|
||||
|
||||
The final report clears all 80 pulls at levels 1/10/30/60/65/66/79/80, with zero invalid casts, player deaths or companion deaths. Both the actual trash NPC and Anglo are native-supported in every sample. Trash is 4.9–8.7 seconds and Anglo 40.5–58.5 seconds. The harness asserts source support, successful kills and absence of invalid casts/deaths; positions remain fixed, so this does not certify encounter movement or every dungeon.
|
||||
|
||||
Focused validation passed 140 tests across 18 files, followed by six shared-gate/periodic checks after the final result-field cleanup. Native HP/pacing checks passed 7/7. Ready-five checks passed 7 Vitest and 20 Python cases; avatar/equipment checks passed 47 cases during this follow-up. The final production build stages passed: bootstrap and asset audits, TypeScript, Vite, compression and release-bundle verification.
|
||||
|
||||
The final production browser checks use `index-DyCSc4Cz.js` and `combatStore-nQykOmDD.js`. Stat-ruleset QA covers native defaults, legacy WoW-mode saves, independent player/companion modes, switching guards, equipment panels and a 390×844 viewport. The targeted Boss Testing check covers Anglo's Gulp control effect and Lady Anacondra's Nature-school Lightning Bolt against a native RoM party, with no page errors. It does not cover every boss mechanic or dungeon. Evidence is in `playtest-artifacts/stat-rulesets/results.json` and `playtest-artifacts/native-combat/results.json`; screenshots verify roster/dungeon bodies, staff/shield/weapon silhouettes, native stats and encounter feedback.
|
||||
@@ -0,0 +1,41 @@
|
||||
# RoM native combat resolution and source boundary — 2026-10-03
|
||||
|
||||
This note documents the narrow native combat resolver in `src/game/romNativeCombatResolution.ts`. It supplies Runewaker hit, avoidance, critical, typed resistance, and ATK/DEF or MATK/MDEF stages to the shared `CombatResult` shape. The resolver accepts only `ruleset: "rom"`; WoW and CoA requests return an explicit unsupported result and never reinterpret WoW ratings as Runewaker points.
|
||||
|
||||
## Source inputs and identity
|
||||
|
||||
`scripts/runewaker-pipeline/export-rom-native-combat-data.mjs` reads local `npcobject.db`, `magiccollectobject.db`, `magicobject.db`, vocation/race/sex growth, FixTable, and SkillValueBase/JobSkillValue records. It exports a compact `entityIdToNpcId` map from generated population entity IDs to raw Runewaker NPC IDs. `romNativeNpcIdForEntity` only resolves that map. The raw ID is not an AzerothCore `serverEntry` and must not be passed to server-entry registration.
|
||||
|
||||
Player hit profiles are bound to exact imported `(sourceSkillId, componentId)` pairs. NPC hit profiles are bound to the NPC's exact source spell row and component. The profile keeps `MagicCollect.EffectType`, `HitRateFunc`, and its two raw arguments separate from `MagicObject.Attack.CalType`, `AttackType`, and `MagicType`: the collect effect selects the source hit gate, calculation type selects physical/magical damage and critical handling, and MagicType selects one of the six elemental resistance channels (Earth, Water, Fire, Wind, Light, Darkness). An elemental school is therefore not inferred from the physical/magical calculation channel.
|
||||
|
||||
NPC derived attributes use authored NPC attributes plus the source vocation, race, and sex growth tables at the explicit runtime level. NPC runtime levels accept the source's 1–200 range; the level-80 player cap is not applied to scaled NPCs. Combat snapshots additionally require an available skill-table row (currently through level 100). No source hit/avoidance table is silently extrapolated past its exported rows.
|
||||
|
||||
`romNativeNpcEquipment.generated.json` preserves all five main/off-hand candidate IDs (empty entries and duplicates at 20% each), fixed BowEQ/OrnamentEQ IDs, item WearEQ values, refinement and explicitly separate drop metadata. `romNativeNpcEquipment.ts` resolves deterministic source candidate selection, durability/power-quality wear power and verified refine sequences. Supported channels feed native attributes, attack/defense, healing, resistance and main-hand speed/range/damage. Live callers use the NPC-id seed; actor-specific seeds and explicit candidate overrides are available. DropItemAbility metadata is not worn affix data and is not applied. The default selection supports 398/440 imported NPCs, including Barren 101459–101461 and Anglo. Remaining off-hand weapon damage, bow/ornament channels, unknown effects and vocation mismatches fail closed. See [the equipment pass](ROM_NATIVE_NPC_EQUIPMENT_PASS_2026-10-03.md). NPC periodic target/caster data may be present for inspection on an unsupported profile, but callers must gate native combat use on `combatStatus === "supported"` / `nativeCombatant`.
|
||||
|
||||
Exact enemy manual fixed/MaxHP packets now use `romNativeEnemyDamage.ts`; their source stages differ from ordinary physical/magical attack formulas and skip those generic power stages. Source absorption/AoE inputs require verified neutral canonical training gear and aura state. Exact source amounts retain authored encounter multipliers and bypass the native shared-damage calibration. Unbound Throw and unknown fixed inputs remain explicit gaps. [The encounter follow-up](ROM_NATIVE_ENEMY_ENCOUNTER_PASS_2026-10-03.md) records the updated runtime boundaries and pressure evidence.
|
||||
|
||||
## Combat stages
|
||||
|
||||
The positive damage amount arrives with fixed-value and supported ability-power inputs already resolved by the native amount helper. Unless `sourcePowerStagesAlreadyApplied` is explicitly set, the resolver applies the source level-difference multiplier, the attacker's exact typed native magic-power rate, and the defender's exact typed resistance to magical channels. The source resistance routine works on signed negative damage: it adds raw integer resistance when the damage magnitude is large enough, halves damage when resistance exceeds half of the damage, then multiplies by the typed resistance rate. Missing school inputs return unsupported rather than using a guessed school or WoW Nature mapping.
|
||||
|
||||
For NPC attackers, source `Global::DLvRate` uses the verified level-difference table, whose result bottoms at 1 and caps at 2. Player attackers use 1. Native mitigation then uses `max(0.2, 1 + ((ATK or MATK)+100 - ((DEF or MDEF)+200)) / max((ATK or MATK)+100, (DEF or MDEF)+200))`. Auto attacks also retain the source 0.3 minimum. The critical or parry multiplier is applied before this defense ratio, and the final amount is truncated once, at the end of those multipliers.
|
||||
|
||||
Auto-attack physical avoidance follows the source dodge-then-miss order. Physical miss compares native weapon and Define skill points; a player weapon skill receives the source `+10`, while an NPC uses `level * 2.3` directly. Define skill receives `+10`. Physical hit/dodge uses the source FIX hit base/range and raw point ratio, source body hit/dodge channels, and the non-player-versus-player level adjustment. Spell hit checks use the exact imported MagicCollect function: base, linear level, signed-square level, per-target ordinal, or Shoot. For a physical-effect spell with a non-base function, source physical skill miss is rolled first; integer physical hit rate then modifies the collect hit check, whose failure is reported as dodge. Spells do not use a separate auto-attack dodge roll. Unavailable Shoot skill or invalid source arguments fail closed.
|
||||
|
||||
The source physical avoidance table checks block, then parry, then critical. Block and parry rates come from native point-vs-resist point formulas with FIX base and level terms; they are not percentages. Parry also consumes the source ParryRate body-rate adjustment, halves the landed damage, and prevents a critical. A block prevents damage. Imported HP attack types gate block/parry, and callers can disable individual outcomes through `CombatResultRules` for source components or mechanics that disallow them.
|
||||
|
||||
Critical profiles use the actual physical or magical `CalType`, not the collect effect or elemental school. Critical points are compared against the target's native `ResistCriticalHit` points and source FIX base/level terms. Direct magic critical uses the source integer threshold and ±10 level adjustment; auto physical critical uses the source floating threshold and ±20 adjustment. The resulting `CombatResult` retains the shared outcome/table fields while source metadata records the selected channel, applied source rates, and defense ratio.
|
||||
|
||||
At DoT tick time, `targetMitigationSnapshotted` (also accepted from `CombatResultRules`) bypasses hit, critical, resistance, and DEF/MDEF because application-time native DoT snapshots already contain those stages. Immunity is checked before that bypass. This keeps snapshot damage from being mitigated twice.
|
||||
|
||||
## Snapshot factories and explicit simulator policies
|
||||
|
||||
`romNativeNpcCombatant(npcId, runtimeLevel?)` is the NPC snapshot factory; `romNativeNpcIdForEntity(entityId)` supplies its raw source ID for imported populations. NPC snapshots are cached by source ID and exact runtime level.
|
||||
|
||||
`romNativeTrainingCombatant(stats, trainingGearProfileMatches, weaponSlot)` creates a player/party snapshot only after the caller confirms the complete canonical training gear profile. It reads the compact generated training profile and verified neutral training-item body defaults. Weapon/Define skills use the source SkillValueBase/JobSkillValue maximum at the current player level; this is an explicit simulator auto-training policy, not a claim about an individual character's training history. Custom or unverified gear returns unsupported. Typed magic rates and resistances retain six source channels.
|
||||
|
||||
`nativeMagicInputsForType(snapshot, magicType)` exposes the exact typed power rate and resistance for periodic snapshot callers. `romNativePlayerHitProfile` and `romNativeNpcHitProfile` expose only the exact exported binding pairs. `resolveRomNativeCombatResult` returns a full shared `CombatResult` or an explicit unsupported reason; a caller must preserve its damage school and ruleset rather than relabeling a fallback result as native.
|
||||
|
||||
## Verification
|
||||
|
||||
`src/game/romNativeCombatResolution.test.ts` covers native ATK/DEF and MATK/MDEF ratios, hit ordering, the NPC weapon-skill exception, block/parry, bound hit/calculation channel separation, typed MPow and resistance, NPC level 81, the supported Anglo neutral off-hand, fail-closed non-neutral equipment, neutral verified training supplements, immunity, and snapshotted mitigation. Source-level claims were checked against the local read-only `Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp`, `RD_ValueCal.cxx`, `RD_ValueCal.inl`, `RD_Normal.cxx`, `RD_Setting.cxx`, `ObjectStruct.h`, and the referenced binary DB layouts. This is a source-derived subset; unresolved equipment, beyond-table skills, unsupported calculation types, missing supplements, and cross-ruleset inputs remain explicit unsupported cases rather than certified native combat.
|
||||
@@ -0,0 +1,34 @@
|
||||
# Native RuneWaker enemy direct damage — 2026-10-03
|
||||
|
||||
## Scope and runtime contract
|
||||
|
||||
`src/game/romNativeEnemyDamage.ts` resolves a direct enemy packet only from an exact imported `(NPC ID, source skill ID, component ID)` binding in `romNativeCombatData.generated.json`. `scripts/runewaker-pipeline/export-rom-native-combat-data.mjs` owns that generated binding data. The helper keeps the three source meanings independent: `MagicCollect.EffectType` selects the hit gate, `MagicObject.Attack.CalType` selects this formula, `MagicObject.EffectType` selects the CalType 8 absorber, and `MagicObject.MagicType` remains the native resistance channel. A formula packet reports `sourceHitEffectType`, `componentEffectType`, and `magicType` separately.
|
||||
|
||||
The helper implements negative direct-HP CalType 4 (fixed points) and CalType 8 (recipient MaxHP percentage) rows when all source inputs are present. It returns `unsupported` for positive/healing rows, unsupported component shapes, missing exact bindings, missing MaxHP, missing fixed-attribute values, unverified target absorption, or missing non-target AoE rates. It never guesses an NPC from a skill name. The source catalog has 440 NPC rows and currently contains 22 direct CalType 4 components, 11 direct CalType 8 components, and zero direct CalType 2 NPC-bound components. Day of Rain's CalType 2 skill 491183/component 501278 is catalogued, but this snapshot does not attach it to an imported NPC; the helper rejects that unbound pair.
|
||||
|
||||
For CalType 4, source power is `DmgPower * (1 + DmgPower_SkillLVArg * MagicLv / 100)`, plus `FixValue * GetValue(FixType) * (1 + MagicLv * FixDmg_SkillLVArg / 100)`. A nonzero fixed term with a nonzero FixType needs an explicit source attribute value. The known None FixType contributes 1. Negative power goes through target `CalMagicDMG` unless `IgnoreMagicAbsorb` is set. A non-target cast then applies source `AEMagicPowerRate * AEMagicDefRate`. The source share factor is multiplied into the absorbed/AoE-adjusted power before integer damage; unshared recipient ordinal attenuation modifies the base-power term before fixed power and target absorption.
|
||||
|
||||
For CalType 8, the target's current native MaxHP multiplies the source percentage before absorption. With absorption enabled, CalWeaponDMG or CalMagicDMG is evaluated against that HP-scaled value first and divided by 100 afterward, matching the source expression's order and truncation. Raw MagicObject `EffectType` 1 selects weapon absorption; 0 selects magic absorption. `IgnoreMagicAbsorb` and `FixDotPower` bypass that absorption. Non-target magical rows apply the AoE magic power/defense rates in the ordinary CalMagicDMG branch; `FixDotPower` takes the source's early raw-MaxHP branch and skips those rates. The share factor is applied after integer damage; unshared recipient ordinal attenuation modifies the source percentage before target MaxHP and absorption.
|
||||
|
||||
The supported direct point formulas set `resolverDamageChannel: "none"` and mark applicable source power stages as resolved or not applicable. The shared native resolver therefore retains only the independent collect hit gate and does not reapply level damage rate, typed power/resistance, generic DEF/MDEF, criticals, block, or parry. Ordinary damage auras and shields remain later simulator stages. Target source `AB/Abr/MAbr` is a separate formula input: `romNativeTrainingEnemyAbsorbInputs` supplies the verified canonical training profile's neutral values only when gear matches and the caller explicitly confirms no native absorb-channel aura is active. Custom gear or unverified auras fail closed.
|
||||
|
||||
The helper explicitly skips `nativeDamageBudgetScale` for exact source formulas because their source points or target-HP percentage already determine the native magnitude. Imported `mob.damageMultiplier` still applies after the formula. Authored encounter health and the simulator's health curve remain independent of native damage calculation.
|
||||
|
||||
CalType 2 Throw remains explicitly unsupported by the runtime helper. Its source path uses `Fin.Throw_DMG`, then `CalPhyDamage` applies NPC damage rate, `Global::DLvRate`, and typed resistance before the source combat table; target `CalWeaponDMG` and share damage happen after critical/block/parry. The current runtime has no completion hook at that exact post-table stage, so the helper returns `native-enemy-throw-post-table-absorption-runtime-unwired` instead of a partial amount. This source catalog has zero direct CalType 2 NPC-bound components; Day of Rain (491183/501278) has no exact imported NPC association and is never inferred.
|
||||
|
||||
## Source evidence
|
||||
|
||||
- `SourceCodeVS2019/Server/NetGameServer/MainProc/MagicProc/MagicProcess.cpp`, `Magic00_AddHP` around lines 2286–2980: direct `AtkCalType` dispatch, fixed/percentage formulas, recipient iteration, share/ordinal behavior, and final integer damage.
|
||||
- `MagicProcess.cpp` around lines 2532–2610: CalType 4 `OrgPower`, `AddFixPower`, target CalMagicDMG, AoE rates, and share factor.
|
||||
- `MagicProcess.cpp` around lines 2751–2840: CalType 8 recipient MaxHP calculation, raw component EffectType selection, FixDot/IgnoreMagicAbsorb bypass, AoE rates, and final integer damage.
|
||||
- `MagicProcess.cpp` around lines 2477–2515: CalType 2 uses `Fin.Throw_DMG`; `CalPhyDamage` around lines 3366–3398 adds its fixed term, applies NPC damage rate, `Global::DLvRate`, and typed resistance. Its target weapon absorption occurs after block/parry/critical handling around lines 3478–3560.
|
||||
- `SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` around lines 178–209: `Init_BaseEQValue` zeroes `Body` and initializes all `BodyRate` entries to 1. `CalWeaponDMG` and `CalMagicDMG` around lines 941–958 define the flat/rate absorption and minimum one-point damage behavior.
|
||||
- `SourceCodeVS2019/Server/NetGameServer/MainProc/Global.cpp` around lines 8928–8964 defines the recursive source level-difference rate table, including its NPC lower-bound behavior.
|
||||
- `src/game/generated/romNativeDamageTrainingProfiles.generated.json` is owned by the native training profile exporter. Its 999 selected training items and affixes have resolved source channels; no selected profile supplies AB/Abr/MAbr/AEMagicDefRate. NPC accepted WearEQ types are separately fail-closed when an unhandled nonzero ability appears, so the supported NPC subset has neutral `AEMagicPowerRate` from source BodyRate initialization plus its resolved equipment projection.
|
||||
- `src/game/generated/enemyDamageTypeSources.generated.json` is owned by `scripts/dungeon-pipeline/export-enemy-damage-types.mjs`; the compact classifier now exports formula names and absorber policy independently of packet class, raw effect type, and MagicType.
|
||||
|
||||
## Verification and limits
|
||||
|
||||
`src/game/romNativeEnemyDamage.test.ts` covers exact Barren Axe Throw CalType 4 (NPC 101255, skill 492857/component 503019), Snow's Dance CalType 8 (NPC 101535, skill 492438/component 501098), target absorption, target order, AoE source rates, missing inputs, unbound Day of Rain, and canonical/custom training gear gates. Hall of Survivors NPC 102476/skill 493985/component 503044 is the only current non-target, magical-absorb CalType 4 direct NPC row, but its NPC equipment snapshot is unsupported; its AoE arithmetic is unit-tested with explicit source/target BodyRates, while live runtime correctly stays on the fallback. `src/game/mobDamageTypes.test.ts` verifies exported formula metadata and keeps hit-gate, absorber and resistance fields distinct. `src/game/romNativeEnemyDamage.integration.test.ts` covers the actual Treasure Trove packets against canonical active-five player/companion targets at levels 30 and 80.
|
||||
|
||||
CalType 2 target absorption remains pending after the shared combat table and is not integrated for current imported encounters because there are no exact NPC bindings. Non-target magical source packets require a verified source AoE-power multiplier; active source auras that may change that channel must remain fail-closed until represented. CalType 4 fixed types outside None require a caller-provided source attribute. The fixed and MaxHP branches intentionally do not claim support for buffs, healing, periodic damage, MP damage, extra PvP-only behavior, or source shapes beyond their direct HP branch.
|
||||
@@ -0,0 +1,67 @@
|
||||
# Native RoM enemy equipment, encounter packets and healing pressure — 2026-10-03
|
||||
|
||||
This pass completes the requested follow-up to native combat resolution: source NPC equipment, supported fixed/percentage enemy damage, targeted encounter reactions, and measured healing pressure. The level cap remains 80. Existing saved RoM characters retain WoW stats until switched; each player/companion selects its own resolver. No loot, matchmaking, difficulty-slider change or readiness promotion is included.
|
||||
|
||||
This report preserves the earlier pass and its shared-regeneration measurements. The subsequent [recovery, equipment and pacing follow-up](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md) supersedes the 398/440 equipment count and native HP/Mana recovery limitation below.
|
||||
|
||||
## Equipment and source damage
|
||||
|
||||
`export-rom-native-npc-equipment.mjs` owns the compact NPC candidate/item/refine snapshot. `romNativeNpcEquipment.ts` resolves actual source candidate slots, wear power and known WearEQ channels rather than averaging candidate stats. Main-hand speed/range/damage and supported attributes, attack, defense, healing and resistance feed `romNativeNpcCombatant`. Current live callers use the stable NPC-id default seed; the provider also accepts an actor seed and explicit candidate overrides. Separate copies therefore currently select the same equipment for the same source NPC. Equipment drops/affixes are not attached to loot.
|
||||
|
||||
Under that default selection, 398 of 440 imported NPCs have supported native snapshots. The remaining 42 retain explicit fallback: 26 selected off-hand weapon-DMG cases, ten bow/ornament cases, two unknown item effect cases, and four preexisting vocation-sub-ID mismatches. See [the equipment source report](ROM_NATIVE_NPC_EQUIPMENT_PASS_2026-10-03.md) for exact source paths, item coverage and hashes.
|
||||
|
||||
`romNativeEnemyDamage.ts` binds exact NPC/skill/component and source MagicLv for manual fixed damage (CalType 4) and recipient-MaxHP percentage damage (CalType 8). These branches preserve their source absorption, integer, sharing and ordinal order; they do not acquire generic ATK/DEF, elemental resistance or critical multipliers. Native target absorption is accepted only for verified canonical training gear and represented neutral aura channels. Non-target magical packets additionally require a supported NPC body/equipment snapshot and verified neutral source AoE power; an NPC with active unverified auras falls back. Generic dealt/taken modifiers and ordinary shields remain in the existing application path.
|
||||
|
||||
Source Throw (CalType 2) is audited separately: no exact imported NPC binding currently uses that calculation. An unbound source spell is not attached to an enemy merely to exercise the branch. Missing fixed attributes, unknown equipment or source effects remain unsupported rather than borrowing WoW inputs. See [the enemy formula source report](ROM_NATIVE_ENEMY_DAMAGE_SOURCE_2026-10-03.md).
|
||||
|
||||
The live direct-damage consumer uses the source formula amount with the existing authored `mob.damageMultiplier`. It bypasses the new native training-party damage budget for exact CalType 2/4/8 amounts. This prevents multiplying an already sourced fixed or maximum-HP packet by the high-level shared-damage calibration. Source skill rank stays on the NPC binding; this pass does not claim every fixed-damage encounter is balanced when scaled to every player level. Encounter health continues to use authored/scaled pools.
|
||||
|
||||
## Encounter behavior
|
||||
|
||||
The headless encounter checks use actual Anglo Trample/Bash/Gulp definitions with only initial cooldown accelerated for isolated mechanic tests. Trample and Bash retain their source 1.8-second warning and five-unit range. Moving the player and Mage outside the radius during the warning excludes them while the remaining nearby companions receive the physical packets. Gulp applies to actual nearby recipients; manual player/NPC dispels and a real native NPC Priest cleanse remove control before natural expiry. A real companion interrupt cancels Trample without damage.
|
||||
|
||||
An interrupted/stunned/silenced enemy cast now emits its cast-cancel presentation event when clearing the active cast. Previously the simulation cancelled the cast while its telegraph/presentation could remain active. Self-target Regenerate ticks now enter the structured healing ledger with raw/effective/overheal fields; healing itself is unchanged. Both fixes have direct regression coverage.
|
||||
|
||||
The pressure harness uses the actual mob/party tick pipeline with scripted stacked/spread positions. It is not a scene-navigation certification. Its 16 pulls cover levels 10/30/60/80 with an active or idle player Priest and the four other exact native builds. A separate 40-case damage integration selection covers fixed and MaxHP packets against all five builds in both player/NPC seats at levels 30/80. These are explicitly requested diagnostics for Needs Testing builds, outside randomized/all-class certification.
|
||||
|
||||
## Measured calibration
|
||||
|
||||
`before-pressure-tuning.json` preserves the post-equipment, pre-pressure-adjustment baseline. Before tuning, level-80 Anglo dealt only 335–402 effective enemy damage over roughly 40–57 seconds against a 49,210-HP tank. Large spread-party healing totals were chiefly native Vampire Arrows health costs, not boss damage. The report now separates enemy damage from self/other ability damage so those costs cannot masquerade as encounter pressure.
|
||||
|
||||
`dungeonBossScaling.ts` exposes `nativeDamageBudgetScale` separately from authored/difficulty damage multipliers. It applies only to a RoM-origin native-stat party's shared enemy-damage budget. Anchors are level 1:1, 10:1, 30:3, 60:10, 65:12, 66:20, 79:40 and 80:40; intermediate values interpolate. `MobPopulation.tsx` passes it into live registration. `combatStore.ts` scales shared attack damage and its attack-power contribution together and handles repeated registration without compounding. The compatibility curve, native health anchors and difficulty controls stay intact.
|
||||
|
||||
| Level-80 pressure sample | Enemy damage | Player effective healing | Lowest party HP | Clear time |
|
||||
| --- | ---: | ---: | ---: | ---: |
|
||||
| Active Priest, spread | 13,415 | 54,258 | 82.0% | 49.1 s |
|
||||
| Active Priest, stacked | 13,415 | 13,415 | 82.0% | 41.1 s |
|
||||
| Idle Priest, spread | 16,098 | 0 | 13.0% | 57.1 s |
|
||||
| Idle Priest, stacked | 13,415 | 0 | 48.7% | 52.0 s |
|
||||
|
||||
The spread sample still includes substantial Scout health costs, recorded separately in `otherDamage`. All 16 pulls cleared without deaths or invalid controller casts. Active healing remains comfortable; idle stacked health falls materially below the baseline. This is a first measured normal-mode training budget, not a difficult-mode or every-dungeon guarantee. Mana minima remain approximately 95–99% for the active samples under the shared regeneration policy. Native MP regeneration, resource sustain and mana-pressure balance remain open; this pass does not imply mana challenge parity.
|
||||
|
||||
The regenerated fixed full-player/four-NPC cohort clears all 80 requested pulls at levels 1/10/30/60/65/66/79/80, with no player/NPC deaths or invalid casts. Trash takes 4.9–8.7 seconds and Anglo 42.0–58.5 seconds. Both exact enemy snapshots are source-supported. Static positions omit navigation; the separate mechanic fixtures cover selected movement and reactions.
|
||||
|
||||
## Evidence and validation
|
||||
|
||||
- `artifacts/rom-enemy-followup/before-enemy-source-expansion.json`: preserved previous native-resolution cohort.
|
||||
- `artifacts/rom-enemy-followup/before-pressure-tuning.json`: complete 16-pull pressure baseline.
|
||||
- `artifacts/rom-enemy-followup/pressure.json`: final pressure ledger and ability-level self/other damage.
|
||||
- `artifacts/rom-five-native-rotation/report.json`: final 80-pull cohort.
|
||||
- `src/game/romNativeEncounterPressure.integration.test.ts`: six encounter/pressure checks.
|
||||
- `src/game/romNativeEnemyDamage.integration.test.ts`: player/NPC formula and fallback coverage.
|
||||
|
||||
Focused native/source validation passes 141 distinct tests across 22 files, including the 40 exact packet cases and six encounter/pressure checks. The repeat-registration/mode-switch regression also verifies that pressure does not compound or survive a switch to compatibility scaling. The separate 80-pull cohort passes its diagnostic test. Avatar checks pass 47/47; Ready-five checks pass seven Vitest and twenty Python cases. The app TypeScript check passes with the repository's required larger Node heap.
|
||||
|
||||
The final `npm run build` passes bootstrap generation, texture/performance audits, TypeScript, Vite, static compression and release-bundle verification. The tested production chunks are `index-pDR2PGJY.js`, `combatStore-7m63VWbc.js` and `GameRuntime-CGZMQPoV.js`. The asset audit has no new regressions; existing chunk-size/static-dynamic-import warnings remain.
|
||||
|
||||
Exact production Edge QA passes with no page errors. The UI-created level-30 native Knight/Scout and four native companions enter real Boss Testing scenes for Anglo and Lady Anacondra. Both normal snapshots record native damage budget 3; Anglo attack damage is 289 with authored multiplier 1.3, and Lady's is 354. These are live population-registration checks, not injected mob-stat assertions. Roster and in-dungeon screenshots visibly retain player/party bodies and starter shield/sword/staff silhouettes.
|
||||
|
||||
The final `--fixtures-only` run reuses those successful normal-scene snapshots from the same production chunks (`normalScenesReran: false`) and stages actual Anglo Trample, Bash and Gulp individually. Only cooldown/readiness, attack-list selection, threat and positioning are fixture setup; Trample companion actions are paused to keep its warning observable. Each actual source attack keeps its 1.8-second cast, range, effects and telegraph and releases once. Moving out of Trample's hit area produces zero player damage events; Bash retains its five-unit range. Gulp controls a nearby Rogue and clears at/after source expiry; this browser sample has no Priest cleanse evidence. The separate headless test proves NPC cleansing with the Priest outside Gulp's radius. Test setup was corrected to reset position/source attack lists between fixtures; no runtime change was needed.
|
||||
|
||||
Evidence is in `playtest-artifacts/native-combat/results.json`, the two normal sample JSON files, roster/normal scene images and six `anglo-*-fixture.png` images. Representative roster, party/dungeon, Trample warning/movement, Bash and Gulp screenshots were visually inspected. This selected production QA does not certify a normal full clear, full navigation, mobile UI or every encounter. Harness syntax checks and repository/vault text hygiene pass; no readiness reviews or dungeon reports were submitted.
|
||||
|
||||
The additional `dungeonBossScaling.test.ts` run passes 13 checks and fails four compatibility-pacing expectations: WoW Stockades at levels 1/3 (14.6/15.1 seconds versus a 24.5-second floor), legacy RoM Mage at level 8 (23.6 versus 25 seconds), and legacy RoM at level 80 (11.3 versus 25 seconds). A Luna subprocess copied the committed pre-native scaler from `b16821e` into ignored scratch files and reproduced the two WoW starter failures and the RoM Mage level-eight failure with the current surrounding runtime. It did not replay the exact level-80 healer case; an additional level-80 Mage diagnostic is a different cohort. Committed/current legacy scaling outputs match for all four original inputs, and these omitted-ruleset calls use native damage budget 1. This isolates the new native scaling branch from the health/damage outputs; it does not certify the entire committed runtime or establish an exact four-case committed replay. Scratch files were removed. Compatibility pacing was not retuned and the failed expectations remain visible.
|
||||
|
||||
## Remaining scope
|
||||
|
||||
Off-hand weapon damage, bow/ornament equipment, unknown item effects, unbound Throw, unknown fixed attributes, unrepresented absorb/AoE aura channels and custom gear continue to fail closed. Cross-system incoming-hit aura translation into native source gates, native resource regeneration, full scene navigation and broader encounter balance remain outside this pass. RoM classes remain Needs Testing.
|
||||
@@ -0,0 +1,111 @@
|
||||
# RoM native Priest healing source adapter
|
||||
|
||||
This is a local RuneWaker source implementation for native RoM healing. It is
|
||||
not a Chronicles of Arcadia formula, and it does not infer a spell rank from a
|
||||
source catalog value. `MagicProc.MagicLv` is a required runtime input. The
|
||||
simulator may explicitly map its trained skill level to
|
||||
`clamp(characterLevel, 1, 80)`; that is simulator policy, not a claim about the
|
||||
source database's configured `MagicLV` field.
|
||||
|
||||
## Direct HolyHeal
|
||||
|
||||
`romNativeHealing.ts` resolves the `MagicProcess.cpp` `AtkCalType::HolyHeal`
|
||||
branch. The source equation is:
|
||||
|
||||
```text
|
||||
OrgPower = DmgPower + DmgPower * DmgPower_SkillLVArg * MagicLv / 100
|
||||
SpellTime = MagicCol.SpellTime; use 1 when below 1 or IsFixDmgEffect is true
|
||||
MNDPart = MND * 0.3 * SpellTime
|
||||
Power = OrgPower * 6 when OrgPower * 5 < MNDPart; otherwise OrgPower + MNDPart
|
||||
unless IsIgnoreDmgEffect:
|
||||
add MDMG * FIX.Dmg_HealArg, once when fixed or multiplied by SpellTime otherwise
|
||||
Power = Power * MPow * HealPowerRate + HealPoint * SpellTime
|
||||
per target, apply Atk.Rand variation
|
||||
unless MagicBase.SettingEx.IgnoreMagicAbsorb:
|
||||
Power = Power * (1 + HealAbsorbRate / 100) + HealAbsorb
|
||||
clamp Power below zero; reverse sign for undead; suppress negative undead output out of combat
|
||||
```
|
||||
|
||||
The generated source map binds ability and rank identity to raw `MagicCollect`
|
||||
rows and direct HP `MagicObject` components. It preserves source component IDs,
|
||||
`AtkCalType`, signed `DmgPower`, its skill-level argument, fixed fields,
|
||||
random range, critical rate, `SpellTime`, range/sharing data, and the distinct
|
||||
`MagicCollect` timing flags and mode flags. `holyHealBindings` is the 18-row
|
||||
subset with `AtkCalType == 5`; `attackBindings` retains all 225 direct HP
|
||||
ability rows for shared combat integrations.
|
||||
|
||||
The Priest bindings include Heal (`490261`, `DmgPower 90`, argument `30`,
|
||||
`SpellTime 2`), Group Heal (`490281`, `DmgPower 65`, argument `20`,
|
||||
`SpellTime 3`), and Urgent Heal (`491147`, `DmgPower 35`, argument `20`,
|
||||
`SpellTime 1`). Their exact component and rank records are in the generated
|
||||
metadata. The helper expects already-effective native caster and recipient
|
||||
channels; callers must not run generic healing modifiers a second time when
|
||||
those modifiers were included in the effective inputs.
|
||||
|
||||
## Periodic HP healing
|
||||
|
||||
Runewaker has a separate native HoT path. It is not a HolyHeal cast repeated
|
||||
each tick. `MagicProcess.cpp` computes the applied buff duration and invokes
|
||||
`CalAddDotMagicLv`; `RD_Normal.cxx` calculates the buff's source rank
|
||||
correction; `RD_ValueCal.cxx::BuffProc` uses the frozen `Buff.Power` at each
|
||||
tick. The helper supports active positive magical `DotMagic` with HP type 0,
|
||||
including Priest's Regenerate (`490269`). It deliberately returns no result
|
||||
for unsupported `DotMagic` types, including percentage HP type 5.
|
||||
|
||||
At application, the source first derives actual buff duration from
|
||||
`EffectTime`, `EffectTime_SkillLVArg`, `DLV_EffectTime`, and owner/target
|
||||
levels, then uses `DotTimes = max(1, int(EffectTime / Dot.Time))`. For a
|
||||
positive magic HP dot, the source calculates:
|
||||
|
||||
```text
|
||||
DotBase = Dot.Base * (1 + MagicLv * DotSkillLVArg / 100)
|
||||
ExRate = 0.6 + abs(DotBase) / 600 for an IsPlayer owner; otherwise 1
|
||||
Power = DotBase + ExRate * MDMG * int(SpellTime) * FIX.Dmg_HealDotArg / DotTimes
|
||||
MNDPart = MND * 0.3 * int(SpellTime) / DotTimes
|
||||
Power = Power * 6 when Power * 5 < MNDPart; otherwise Power + MNDPart
|
||||
Power = Power * HealPowerRate + HealPoint * int(SpellTime) / DotTimes
|
||||
unless IgnoreMagicAbsorb:
|
||||
Power = Power * (1 + HealAbsorbRate / 100) + HealAbsorb / DotTimes
|
||||
clamp Power below zero; Power *= MagicPow(MagicType)
|
||||
MagicLvAdjustment = int((Power - Dot.Base) / (Dot.Base * DotSkillLVArg / 100) - MagicLv)
|
||||
Buff.Power = MagicLvAdjustment + MagicLv
|
||||
```
|
||||
|
||||
`FixDotPower` or a zero `DotSkillLVArg` bypasses the rank correction, leaving
|
||||
`Buff.Power = MagicLv`. The source tick then computes
|
||||
`Damage = int(-Dot.Base * (100 + DotSkillLVArg * Buff.Power) / 100)` and applies
|
||||
`AddHP(-Damage)`. C++ integer conversion truncates toward zero. Recipient
|
||||
absorb and caster channels are captured through the buff-rank correction at
|
||||
application; the source does not reapply them on each tick. The helper returns
|
||||
the resulting integer tick amount and the `DotTimes` interval count so the
|
||||
runtime can preserve that application snapshot.
|
||||
|
||||
The live helper requires an explicit effective
|
||||
`MagicPow(MagicType)` value. The existing native stat sidecar has an all-magic
|
||||
neutral MPow channel but does not expose all six element-specific MPow
|
||||
`BodyRate` channels. The caller must supply an effective source value when
|
||||
element-specific modifiers are modeled. For this simulator's active
|
||||
player-build identities, `sourceIsPlayer=true` is an explicit policy applied
|
||||
to both the active player and party companions; the original `IsPlayer()` test
|
||||
itself distinguishes actual server player roles.
|
||||
|
||||
The current Priest Regenerate source row contains positive HP DotMagic
|
||||
components `500469` (argument 18), `621318` (argument 18), and `621548`
|
||||
(argument 25). They share `Dot.Time 2`, `Dot.Base 20`, and duration 20 seconds.
|
||||
The generated map retains each component ID so the runtime can use the
|
||||
component selected by its own source semantics instead of guessing which raw
|
||||
component is active.
|
||||
|
||||
## Source snapshot and limits
|
||||
|
||||
The generated artifact is
|
||||
`src/game/generated/romNativeHolyHealBindings.generated.json`; regenerate it
|
||||
with `scripts/runewaker-pipeline/export-rom-native-healing.mjs`. It is tied to
|
||||
the current hashes of `magiccollectobject.db`, `magicobject.db`, the local
|
||||
server formula files, the player catalog, and generated native stat rules.
|
||||
The output includes 225 direct-attack ability rows, 18 HolyHeal ability rows,
|
||||
and 8 positive magical HP DotMagic ability rows across the catalog.
|
||||
|
||||
The data and formula boundary is the local RuneWaker source version hashed in
|
||||
that artifact. This work does not add CoA rank data, model percentage HP
|
||||
periodics, or infer unavailable source skill levels from `configuredCollectMagicLevel`.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Native RoM level-one boss pacing — 2026-10-03
|
||||
|
||||
## Adjustment
|
||||
|
||||
The native RoM health policy now uses a `0.20` boss-health scale at character level 1, down from `0.30`. The level-1 trash scale remains `0.40`. Every health anchor at level 10 and above is unchanged, as are all `nativeDamageBudgetScale` anchors. The level-1 boss value interpolates linearly to the existing level-10 boss value, so native bosses at levels 2–9 also receive the corresponding smooth interpolation. This is a simulator health budget for the targeted five-build cohort, not a RuneWaker source monster-health formula.
|
||||
|
||||
The adjustment followed source recovery and the separately implemented level-one Priest mana reserve. With the previous `0.30` boss value, the level-one native Knight diagnostic still ended with actor deaths; the reported pull had 391.2 incoming damage and 56 healing. The authorized retune changed only the level-one boss-health anchor.
|
||||
|
||||
## Five-build result
|
||||
|
||||
The unchanged 80-pull native rotation diagnostic passed at the `0.20` anchor. It covers each of the five identities as the active character and four native companions against Barren Caves trash and Anglo at levels 1, 10, 30, 60, 65, 66, 79, and 80. All 80 targets died; every player survived, no companion died, every native combatant was supported, and there were no invalid cast failures. This is a fixed-position simulator diagnostic, not scene navigation or a readiness promotion.
|
||||
|
||||
The pair names below identify each configured build; at level 1, secondary classes are inactive, so these five samples all use pre-secondary snapshots. They all used the same 1,848-HP budget and had no player or companion deaths:
|
||||
|
||||
| Active build | Clear after first party hit | Player HP remaining |
|
||||
| --- | ---: | ---: |
|
||||
| Knight/Scout | 42.1s | 95.6 |
|
||||
| Priest/Knight | 34.1s | 152.4 |
|
||||
| Rogue/Warrior | 36.9s | 129.6 |
|
||||
| Scout/Rogue | 39.7s | 120.4 |
|
||||
| Mage/Warlock | 34.1s | 142 |
|
||||
|
||||
The complete generated diagnostic is `artifacts/rom-five-native-rotation/report.json`. `romNativeDungeonPacing.test.ts` now locks the level-one Anglo value at 1,848, verifies that level-one native trash remains at the unchanged 0.40 ratio, and checks the unchanged damage budget. The level-80 native health plateau/cap assertion remains exact and unchanged.
|
||||
|
||||
## Interpolation and boundaries
|
||||
|
||||
The new level-1 boss anchor changes the interpolated native level-8 Stockades regression from 8,330.293333 to 7,983.197778. Its expectation was updated to the computed interpolation; the native level-80 Stockades health remains 1,312,656 with damage-budget scale 40. The legacy WoW-stat RoM pacing curve and its mixed-mode harness are unchanged.
|
||||
|
||||
No trash-health anchor, level-10-or-higher health anchor, native damage-budget anchor, authored damage multiplier, source enemy damage, equipment, loot, level cap, actor mode, or Ready-party policy changed. This calibration does not claim a complete early-level balance pass or readiness status.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused verification passed `romNativeDungeonPacing.test.ts` and the unchanged `romFiveNativeRotation.integration.test.ts`: 6 tests total, including 80 pulls. The level-one five-build results and full diagnostic metadata are archived in `artifacts/rom-five-native-rotation/report.json`. The post-recovery legacy boss pacing suite passed 18/18 tests; its 83-sample report is archived at `artifacts/rom-enemy-followup/after-compatibility-pacing-post-recovery.json`.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Native RoM NPC Equipment Coverage Completion — 2026-10-03
|
||||
|
||||
## Result
|
||||
|
||||
The native NPC equipment resolver now supports all 440 generated source NPCs under the default deterministic selection and every explicit main-hand/off-hand candidate pair: 440 defaults plus 11,000 candidate-pair snapshots (25 per NPC). The five source candidates and their 20% weights are preserved; the resolver still chooses one reproducible candidate rather than averaging equipment.
|
||||
|
||||
The pre-change audit reported 398/440 supported default selections. Its remaining unresolved groups were off-hand weapon DMG, fixed BowEQ channels, two nonzero values tagged `EM_WearEqType_None` on item 211800, and four valid but mismatched vocation/sub-vocation IDs. Some of the gear reasons overlapped on the same NPC. After the changes, those 42 default fallbacks are resolved.
|
||||
|
||||
## Source-backed channels
|
||||
|
||||
`RoleAttr.cpp::AddAbility` routes type 25 to `BaseEQ.Main_DMG`, `BaseEQ.Sec_DMG`, or `BaseEQ.Bow_DMG` according to the main-hand, second-hand, or bow position (lines 1323, 1479, 1627). Type 25 on armor remains a generic body DMG contribution. The resolver now preserves the three weapon-position amounts independently and applies the NPC second-hand `Dmg_SecHand` coefficient when it produces `offHandDamage`. `RoleAttr.cpp::_SecDMG` defines that coefficient and its damage inputs (lines 766–806); `_Bow_DMG` defines the bow amount (lines 1124–1139). The generated NPC FixTable value for `Dmg_SecHand` is 0.7.
|
||||
|
||||
Selected off-hand and bow weapons also expose their source attack speed and range. Recognized armor type-23 attack-speed effects are applied to each weapon speed channel. A type-23 effect on an off-hand or bow weapon remains fail-closed because its position-specific behavior has not been established. Type 191 continues through the existing generic MDMG channel. No current imported NPC has an ornament item; any future non-empty ornament remains fail-closed until its slot-specific path is verified.
|
||||
|
||||
The source enum identifies wear index 0 as `EM_WearEqType_None` (`ObjectStruct.h:1427`). The two value-35 pairs on item 211800 are therefore treated as no-op channels, while the item's type-25 and type-191 rows continue to contribute normally. Its drop-ability metadata remains metadata and is not applied as an equipment affix.
|
||||
|
||||
Across all five choices for all 440 NPC records, the active effects are type 0, 3, 5, 8, 12, 13, 14, 22, 25, 150, and 191. No current NPC equipment record has an ornament item. Ten records have BowEQ, all now supported. Unknown nonzero wear types remain fail-closed; the resolver does not infer future effects from these present-day counts.
|
||||
|
||||
## NPC sub-vocation growth
|
||||
|
||||
The four corrected source identities are NPCs 100074 (vocation 4/sub 6), 100594 (6/1), 100611 (0/6), and 100614 (0/6). `RD_ValueCal.cxx::InitCal` clears a duplicate primary/secondary vocation (lines 114–118), then assigns a valid NPC `Level_Sub` from its primary level (lines 154–161). `RoleAttr.cpp` adds one tenth of the secondary vocation's full race/vocation/sex base curve for each base attribute and for HP/MP (lines 96–124). The resolver now applies that one-tenth curve to the five exposed attributes and derived HP. Primary vocation coefficients and damage rate stay primary-vocation values, matching the source's separate primary `Arg` path. Sub-vocation mana is not exposed by this NPC combat snapshot.
|
||||
|
||||
The regression test locks each corrected NPC's resulting five attributes and health to its source-derived values. NPC recovery inputs are not part of this change.
|
||||
|
||||
## Resolver API and limits
|
||||
|
||||
`romNativeNpcCombatant(npcId, runtimeLevel, equipmentSelection)` remains the integration entry point. Its result includes the exact `equipment` choice and selected candidate indexes. The outer result now has optional `offHandDamage`, `offHandAttackSpeed`, `offHandAttackRange`, `bowDamage`, `bowAttackSpeed`, and `bowAttackRange` fields when those source weapons are present. The embedded `nativeCombatant` and periodic snapshot stay separate from encounter health/damage budgets.
|
||||
|
||||
The fixed-bow rows currently have neutral source rate factors for all non-target bow modifiers. Rate effects that are not represented by the current equipment catalog remain unsupported and fail-closed if they occur. This pass does not wire equipment fields into combat scheduling, change authored loot, or alter player-stat resolution.
|
||||
|
||||
## Validation
|
||||
|
||||
Focused validation: `npx vitest run src/game/romNativeCombatResolution.test.ts src/game/romNativeNpcEquipment.test.ts` — 2 files and 18 tests passed. The population regression checks all 440 default records and all 11,000 explicit candidate-pair selections.
|
||||
|
||||
Read-only source references are under `F:\Projects\Runewaker\SourceCodeVS2019\Libraries\Union\RoleData`: `ObjectStruct.h`, `RD_Setting.cxx`, `RoleAttr.cpp`, and `RD_ValueCal.cxx`. The generated NPC equipment catalog already contains the required source candidate and item rows, so this completion needed no exporter or generated-data change.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Native RoM NPC equipment pass — 2026-10-03
|
||||
|
||||
## Scope and behavior
|
||||
|
||||
This pass adds source-backed NPC WearEQ effects to the native Runewaker combatant path, capped at the repository's existing supported level 80. It does not connect equipment drops or loot. The WoW path and per-actor combat modes are unchanged.
|
||||
|
||||
The `export-rom-native-npc-equipment.mjs` exporter reads the NPC candidate lists and fixed BowEQ/OrnamentEQ values from `npcobject.db`, referenced rows from `weaponobject.db`/`armorobject.db`, and refine rows from `eqrefineabilityobject.db`. It preserves all five NPC main-hand/off-hand candidate slots at 20% each, including duplicate and empty choices. Runtime resolution is deterministic and does not average candidate stats:
|
||||
|
||||
```ts
|
||||
romNativeNpcCombatant(npcId, runtimeLevel, {
|
||||
selectionSeed: stableActorOrEntityId,
|
||||
// Optional source candidate overrides:
|
||||
mainHandCandidateIndex,
|
||||
offHandCandidateIndex,
|
||||
});
|
||||
```
|
||||
|
||||
Use an actor-unique stable seed when separate live copies of one NPC should roll independently but reproducibly. Omitting the seed defaults to `npcId`; supplying a candidate index pins that source slot. The resolved equipment and selected candidate indices are included in the combatant result.
|
||||
|
||||
The source NPC spawn initialization sets item count to one, durability to 10000, quality to 100, power quality to 10, rare to zero, and item level to `min(RefineLv, 20)`, while selecting the main-hand candidate with `rand() % _MAX_NPC_EQSEL_COUNT_` (`RD_Setting.cxx:2671–2681`). `WearEQ` computes durability power tiers and applies power quality (`RD_ValueCal.cxx:1138–1167`), reads weapon attack range/speed and main-hand values (`1186–1194`), then applies refine rows and the rare-dependent extra-equipment rate (`1212–1272`). Refine lookup is item refine-table ID plus level minus one (`3743+`). These source paths drive the exported defaults, equipment choice, wear power, item weapon speed/range, and refine contributions.
|
||||
|
||||
Known nonzero `WearEqType` values are translated only where the existing native snapshot has a source channel: attributes and rates, max HP, physical/magical attack and defense, hit/dodge/critical/parry, main-hand attack speed and damage, body physical damage, magic damage, healing, resistance amounts/rates, and typed magic-power rates. The enum identifiers/order are in `ObjectStruct.h:1425+`; `RoleAttr.cpp` verifies base main-hand speed 30, final DMG/MDMG/main damage, and the separate Throw_DMG calculation (`184`, `288–314`, `645`, `655`, `713`, `1201–1204`). `nativeCombatant.throwDamage` carries the derived neutral Throw_DMG input for exact source skill formulas that require it. Unknown nonzero types fail closed. Drop ability IDs/rates are kept as explicitly named drop metadata and are not applied as wearable stats.
|
||||
|
||||
## Coverage and limits
|
||||
|
||||
The imported population has 440 NPC rows. Under the stable default NPC-id seed, 398 resolve to a supported native snapshot. The remaining 42 do not silently receive neutral equipment: 26 selected off-hand weapon damage cases lack a modeled secondary-weapon damage channel; 10 rows have BowEQ/OrnamentEQ channels not represented by the current snapshot; two rows select item 211800 with unknown nonzero WearEqType 0/value 35; and four NPCs (100074, 100594, 100611, 100614) have a vocation-sub-ID mismatch that prevents deriving the existing native stats snapshot.
|
||||
|
||||
Across the 112 distinct referenced equipment items, no item ID is missing. There are 96 items with nonzero WearEQ ability entries; 95 have fully mapped active entries, while one has the unresolved type 0 entry above. Referenced source item effect types are 3 (STA), 5 (MND), 8 (MaxHP), 12 (ATK), 13 (DEF), 14 (MDEF), 22 (parry), 25 (DMG), 150 (HealPoint), and 191 (MDMG), in addition to zero/empty slots. The resolver also implements the additional enum channels listed above for source completeness, but does not claim every enum has been validated against a currently equipped item. Twenty-two items have nonzero `DropItemAbility` metadata; those records are not WearEQ affixes and are not wired here.
|
||||
|
||||
The exporter captures refine metadata and the resolver applies a verified refine row sequence when an imported item has a refine level. Current referenced NPC gear has no item with a positive refine level, so the refine application branch is source-implemented but not exercised by present population data. Inherent attributes and runes are empty in the source NPC spawn defaults. Bow/ornament wearable effects and off-hand weapon DMG/speed remain unsupported at combatant construction; no unknown effects are discarded. The source factory's four vocation-sub-ID mismatches remain unchanged by this equipment pass.
|
||||
|
||||
The Barren Caves targets are supported with their exact source equipment outcomes:
|
||||
|
||||
| NPC | Source equipment | Source durable / attack speed | Resolved wear power |
|
||||
| --- | --- | --- | ---: |
|
||||
| 101459 | Main hand 210056 | 70 / 20 | 1.2 |
|
||||
| 101460 | Main hand 210061 | 55 / 20 | 1.2 |
|
||||
| 101461 | Off hand 210666 | 1426 / 20 | 0.2 |
|
||||
|
||||
These items have no active WearEQ ability entries, so they preserve the source neutral combat stats while replacing the previous neutral main-hand speed fallback of 30 only when a real source weapon provides its own speed. An independent positive-effect check covers item 210048 (NPC 100606, main-hand candidate 0): source DMG 213 and MDMG 167 contribute at the source 1.2 wear power. NPC 106315/item 213019 also verifies STA, parry and low durability power (0.2).
|
||||
|
||||
## Generated source snapshot
|
||||
|
||||
`src/game/generated/romNativeNpcEquipment.generated.json` is tied to these local source hashes:
|
||||
|
||||
| File | SHA-256 |
|
||||
| --- | --- |
|
||||
| `npcobject.db` | `b627b6eb269c30576a6558000a31abe2db472689ef9a60cc1c1e20207abd69f1` |
|
||||
| `armorobject.db` | `ccdd438219b801680e4f7c8354171d5347dcab5fcf581f554c39eba3543d961a` |
|
||||
| `weaponobject.db` | `ca58aa607388c4df2fc1a5c6030b1552c2eecb90082fe381cd836aabf6fe467b` |
|
||||
| `eqrefineabilityobject.db` | `724a469d095466df55eb72264ee746a9c6fca866eb76fcb500270cfee3d02f43` |
|
||||
|
||||
## Validation
|
||||
|
||||
Focused tests run:
|
||||
|
||||
```text
|
||||
npx vitest run src/game/romNativeNpcEquipment.test.ts src/game/romNativeCombatResolution.test.ts
|
||||
16 tests passed
|
||||
```
|
||||
|
||||
The tests preserve the Barren candidate arrays and weights, check deterministic and explicit candidate selection, check exact item WearEQ power, verify mapped nonzero DMG/MDMG and attributes/parry effects, ensure unknown effects fail closed, and assert that bow/ornament and invalid candidate paths remain unsupported. Broader app validation is handled by the parent integration task.
|
||||
@@ -0,0 +1,31 @@
|
||||
# RoM native periodic damage source pass — 2026-10-03
|
||||
|
||||
This pass adds a source-bound first-application snapshot and per-tick amount helper for negative HP `DotMagic` effects. It covers the active five RoM builds and deliberately leaves resource drains, healing-over-time, positive-base effects, unsupported refresh behavior, and unverified NPC stat derivation to their separate paths.
|
||||
|
||||
The exporter reads the sibling `Runewaker` tree without modifying it. `scripts/runewaker-pipeline/export-rom-native-periodic-damage.mjs` binds exact `MagicCollect` skill IDs to the active player catalog and imported NPC combat profiles, then emits `src/game/generated/romNativePeriodicDamageBindings.generated.json`. The active five contribute 18 ability rows, 18 source-rank rows, and 14 unique negative HP/HP_Per DotMagic components. The imported NPC source table has 440 NPC rows and 446 population-entity mappings; 50 NPCs currently have bound negative HP/HP_Per DotMagic, with 50 source-rank rows and 42 unique components. The union has 56 unique component IDs. NPC tick sources preserve the assigned slot MagicLv and use the verified native NPC growth upper bound of 200; this does not imply that every NPC stat profile is ready for native resolution. The JSON records the raw source IDs, selected fields, filter, record offsets, and SHA-256 hashes for the source databases/code and local catalogs.
|
||||
|
||||
## Application and tick order
|
||||
|
||||
`MagicProcess.cpp` passes the effective cast `SpellTime` and `MagicProc.MagicLv` to `CalAddDotMagicLv` when applying an assist effect. The rank helper uses `DotTimes = max(1, int(MagicBase.EffectTime / Dot.Time))` from the raw MagicBase duration; this is distinct from the effect duration later computed for the applied buff. For a negative HP DotMagic row, the correction first builds `DotBasePower = Dot.Base * (1 + MagicLv * DotSkillLVArg / 100)`. `FixDotPower` returns no correction, and a zero `DotSkillLVArg` also returns no correction.
|
||||
|
||||
For magical effects the source adds or subtracts caster MDMG scaled by the player/NPC `ExRate`, cast `SpellTime`, `FIX.MDmg_DotArg`, and `DotTimes`. If the resulting power is negative, the source applies the target's `CalResistDMG` to the aggregate power across `DotTimes`, divides back by `DotTimes`, then applies the source `(MATK + 100)/(MDEF + 200)` power rate. If it becomes nonnegative, it enters the source heal-power branch and multiplies by `MagicPow(MagicType)`. Physical effects instead use `Main_DMG`, `Main_ATKSpeed`, `FIX.MDmg_DotArg`, and `(ATK + 100)/(DEF + 200)`; they do not call magical resistance. The returned correction is `int((FinDmg - Dot.Base) / (Dot.Base * DotSkillLVArg / 100) - OrgMagicLv)`.
|
||||
|
||||
`MagicProcess` adds this correction to the cast's `MagicLv`, then forces it to zero when `ShowPowerLv` is set. It computes applied duration from the base effect time, effect-time skill argument, and caster-target level difference. `AssistMagic` then applies the source maximum-skill-level and `BuffMaxLv` caps. The helper requires the actual effective `MagicLv`, caster and target levels, and exact source-derived combatant inputs instead of guessing a spell rank or a missing weapon/resistance value.
|
||||
|
||||
`RD_ValueCal.cxx::BuffProc` emits a tick when elapsed buff time is divisible by `Dot.Time`. Each tick starts with `int(-Dot.Base * (100 + DotSkillLVArg * Buff.Power) / 100)`. `HP_Per` then multiplies by the target's current `Fin.MaxHP / 100` and truncates again. The source dispatches its periodic special-attack event before the PK adjustment and HP shield/HP application; magical DoTs use the `magic` event and physical DoTs use the `skill` event. `MagicShieldAbsorbProc` runs before HP application. `DotMagicNoKill` keeps the target at 1 HP when applicable. The tick reuses stored `Buff.Power`: it does not reroll a critical hit or reapply armor/resistance. The pure tick helper returns the integer amount and event/no-kill metadata; the shared combat runtime remains responsible for shields, health application, and side effects.
|
||||
|
||||
The runtime API in `src/game/romNativePeriodicDamage.ts` separates application snapshot inputs from tick inputs. Elemental magical rank correction requires the target's exact resistance channels and caster's effective `MagicPow(MagicType)`. Physical rank correction requires exact `Main_DMG` and `Main_ATKSpeed`. NPC callers must provide the NPC's exact `FIX.MDmg_DotArg` and source-bounded caster/MagicLv limits; only the source player value is taken from generated verified rules. Player builds remain capped at level 80. Enemy lookup accepts the MagicCollect `spellId` and exact component ID, and the NPC source list is limited to imported encounter NPC spell bindings. An existing-stack reapplication is unsupported because `AssistMagic` can retain or raise the existing buff power. Unsupported inputs return a reason rather than a substitute amount.
|
||||
|
||||
## Active-five special fixed inputs
|
||||
|
||||
The active-five direct-damage binding audit found 66 negative `Attack.DmgPower` components. Of these, four use fixed type 4 (`Throw`): Rogue source skills 490338 and 490309, components 502578 and 620283, each with `FixValue=-3`. Three use fixed type 12 (`ShieldDef`): Knight skill 490175/component 500175 and skill 490186/components 500177 and 500185, each with `FixValue=-0.1`. No active-five negative direct component uses type 10 (`LastSkillDmg`), type 11 (`LastPhyDmg`), or the separate calculation-type Throw branch.
|
||||
|
||||
`MagicProcess.cpp` evaluates each fixed input as `Owner->GetValue(FixType)`, so the fixed source belongs to the caster. `RD_ValueCal.cxx::GetValue` resolves type 4 to caster `Fin.Throw_DMG`, type 10 to caster `BackInfo.LastSkillHitPoint`, type 11 to caster `BackInfo.LastPhyHitPoint`, and type 12 to caster raw `BaseEQ.Def[EM_Armor_Shield]` (not the target's shield or total defense).
|
||||
|
||||
`RoleAttr.cpp::_Throw_DMG()` is `max(0, (Fin.DMG + BaseEQ.Throw_DMG) * BaseEQ.Throw_DMG_Per * BodyRate.DMG_AllRange * BodyRate.DMG_Per)`. Without throw equipment, source initialization leaves `BaseEQ.Throw_DMG=0` and `Throw_DMG_Per=1`, but `Fin.DMG` itself already applies its DMG_Per factor, and `_Throw_DMG` applies DMG_Per once more plus the AllRange factor. A single generic physical-damage stat is therefore not enough to derive this input. Runtime should supply verified caster `Fin.Throw_DMG` explicitly or leave these four components unsupported.
|
||||
|
||||
Last-hit channels are per caster. `MagicProcess` clears `LastSkillHitPoint` at cast start and sets it from signed `int(Temp.Value)` after supported skill effects. The auto-attack scheduler clears `LastPhyHitPoint` before the attack sequence and stores `Damage * -1` after each attack. Since neither type occurs in the active-five negative direct bindings, no persistent prior-hit channel is needed for those current rows.
|
||||
|
||||
## Focused validation
|
||||
|
||||
`src/game/romNativePeriodicDamage.test.ts` checks source lookup, magical and physical rank correction, cast duration versus raw rank-correction duration, fixed/show-power rows, HP_Per tick scaling, no tick-time critical reroll, fail-closed inputs, and reapplication handling. `src/game/romNativePeriodicCombat.integration.test.ts` exercises a real player Vampire Arrows application, an active-five Priest/Knight Bone Chill companion application with native magical defense/resistance and the required typed MagicPower inputs, per-actor RoM versus WoW fallback, and an imported NPC HP_Per DoT whose later tick reads the target's current MaxHP. The focused helper/integration command passed all five tests.
|
||||
@@ -0,0 +1,68 @@
|
||||
# Native RoM recovery, equipment and pacing follow-up — 2026-10-03
|
||||
|
||||
## Source recovery
|
||||
|
||||
Native player and owned-party NPC HP/Mana now use the verified RuneWaker ReHP/ReMP inputs. Each actor keeps its own ruleset, attributes, gear and secondary class; saved WoW-mode RoM profiles keep compatibility behavior. Player pulses occur every two seconds, owned NPC pulses every six. Combat recovers no HP and ReMP/24 Mana per pulse; idle standing players use ReHP/ReMP divided by three and idle owned NPCs use 0.66 times those values. Source aura effects are sampled at each pulse, including expiry boundaries. Explicit periodic Mana effects remain separate.
|
||||
|
||||
The source audit and limitations are in [the recovery report](ROM_NATIVE_RECOVERY_SOURCE_2026-10-03.md). There is no sitting control or simulator StopOntimeCure state, and combat detection approximates the source attack-mode flag. Stopping companions while an enemy remains engaged does not grant idle recovery.
|
||||
|
||||
All five active native companion identities, secondary Mana, and WoW compatibility are covered by `romNativeRecoveryParity.integration.test.ts`. The original focused recovery selection passed nine tests; the additional parity selection passed three.
|
||||
|
||||
## Imported NPC equipment
|
||||
|
||||
All 440 imported NPC defaults and 11,000 explicit main-hand/off-hand candidate pairs now resolve supported native snapshots. This closes the previous 42 default fallbacks with source position-specific weapon channels, the explicit type-zero no-op, and valid secondary vocation growth. Unknown effects and future non-empty ornaments remain fail-closed.
|
||||
|
||||
Off-hand and bow damage/speed/range are available in snapshots; this does not schedule extra enemy swings. No exporter changes or loot wiring were needed. See [equipment completion](ROM_NATIVE_NPC_EQUIPMENT_COMPLETION_2026-10-03.md).
|
||||
|
||||
## Compatibility pacing
|
||||
|
||||
The four legacy failures are resolved with boss health budgets while retaining the original 25-second ordinary and 45-second final minimum checks. WoW starter health floors are 1,800 at enemy level 2 and 2,600 at level 4. RoM-origin WoW-mode boss health has a separate compatibility multiplier. Native source amounts and actor defaults remain independent.
|
||||
|
||||
All 83 targeted compatibility timing samples now pass, including all 12 level-80 RoM seeds. The focused scaling selection passed 18 tests and the additional native/bite-sized pacing selection passed six. Exact native level-8 and level-80 health/damage-budget assertions guard separation. Full pre/post timing evidence is in [the pacing report](LEGACY_BOSS_PACING_FIX_2026-10-03.md).
|
||||
|
||||
## Source recovery pressure measurements
|
||||
|
||||
Six focused pressure tests passed, including 16 real-source Anglo pulls at levels 10/30/60/80 with scripted spread/stack positions, active/idle healer comparisons, movement, interrupts and player/NPC dispels. All sixteen pulls clear without deaths. Native source recovery lowers minimum active-healer Mana at level 10 from approximately 95–97% to 77–85%, and at level 30 from 96% to 87–90%. Levels 60/80 still retain approximately 98–99% Mana. This records the remaining high-level sustain limitation instead of claiming a challenging Mana budget across all levels.
|
||||
|
||||
Reports are preserved under `artifacts/rom-enemy-followup/`; these artifacts are diagnostics rather than readiness certification. The historical 80-pull cohort used shared regeneration. Its clear times cannot establish current native source sustain.
|
||||
|
||||
## Early-level sustain correction
|
||||
|
||||
The source-recovery rerun exposed a real early-level regression: the level-one Knight/Anglo sample took 141 seconds with a player and Rogue NPC death, compared with the preserved 54-second shared-regeneration baseline. Holy Strike's manual effect rewrite had lost its weapon delivery classification, so its Holy school prevented starting free auto-attacks. Explicit source attack-kind metadata now preserves the same 16-point Holy direct hit while starting the 22-point physical training swing. The focused cast-to-auto regression passes; no weapon-hand amount override or source recovery multiplier is used to hide the issue.
|
||||
|
||||
The level-one NPC Priest has 123 Mana and ReMP 4.8, recovering only 0.2 Mana per six-second combat pulse. Its shared fallback initially chooses 12-Mana Rising Tide while Urgent Heal costs 25. The early native-healer decision policy reserves one learned direct heal before spending Mana on hostile damage. This is a clean-room simulator rotation policy, separate from source recovery and spell amounts.
|
||||
|
||||
The reserve preserves its spending boundary; it does not by itself resolve the failed fight. After both runtime fixes, the 0.30 native level-one boss factor still kills the Knight and Rogue NPC. The measured training budget is now 0.20 at level one, leaving trash at 0.40 and every anchor from level 10 onward unchanged. Levels 2–9 interpolate smoothly to the unchanged level-10 factor. Anglo's level-one pool becomes 1,848 HP; the Knight clears in 42.1 seconds with 95.6 HP and no companion deaths. The five level-one player seats clear Anglo in 34.1–42.1 seconds. Source recovery, damage formulas and damage-budget anchors remain unchanged.
|
||||
|
||||
The unchanged fixed diagnostic now passes all 80 player/four-NPC pulls at levels 1/10/30/60/65/66/79/80: zero player/NPC deaths and zero invalid casts. Trash takes 4.9–8.7 seconds and Anglo 34.1–58.5 seconds. Static positions do not establish full scene navigation.
|
||||
|
||||
## Focused verification
|
||||
|
||||
The final source/recovery/resource/damage-type selection passes 156 tests across 24 files, including all 40 fixed/MaxHP actor cases and the 16-pull pressure report. The separate 80-pull diagnostic and five native pacing checks pass. The exact legacy suite passes all 18 checks again after the source-recovery and reserve changes; its 83-sample final report is `artifacts/rom-enemy-followup/after-compatibility-pacing-post-recovery.json`. Ready-five passes seven Vitest and twenty Python cases; avatar checks pass 47 tests. These selections overlap and should not be added as unique test counts.
|
||||
|
||||
An additional `combatRotation.test.ts` run passes 30 of 31 checks. Its existing representative-signature assertion fails for Rogue Killing Spree because that catalog entry has only unsupported/scripted/utility effects. The assertion does not exercise the new native reserve; this unrelated mechanic was not implemented or its check weakened. The four new reserve checks pass, including the real benchmark fallback gate, exact 36/37-Mana boundary, effective-cost override and valid/invalid heal targets.
|
||||
|
||||
The 8 GB app TypeScript check and final `npm run build` pass, including bootstrap generation, texture/performance audits, TypeScript/Vite, static compression and release-bundle verification. The performance audit reports no new regressions; existing chunk-size and static/dynamic-import warnings remain. Final chunks are `index-DzLgXnx0.js`, `combatStore-Dh-12M9R.js`, `GameRuntime-C95Du8PI.js` and `PartyFrames-Cf7FSiBA.js`.
|
||||
|
||||
## Full selected production encounters
|
||||
|
||||
`scripts/playtest-native-combat.cjs --full-fights` uses an isolated local account and the exact final production build. A UI-created level-30 native Priest/Knight healer joins the four other native identities. The selected Boss Testing scenes keep original attack lists/cooldowns; level and class pairing are test setup. Keyboard action bindings perform healing, cleanses and counters without direct damage, HP/Mana or healing edits during fights. These reduced testing-room budgets are separate from campaign durability.
|
||||
|
||||
| Selected scene | Clear time | Player Mana minimum / end | Survival |
|
||||
| --- | ---: | ---: | --- |
|
||||
| Anglo, RuneWaker NPC 101462 | 39.9s | 88.7% / 88.9% | Player and all four NPCs alive |
|
||||
| Lady Anacondra, WoW creature 3671 | 16.5s | 91.0% / 91.0% | Player and all four NPCs alive |
|
||||
|
||||
There are no page errors. Anglo retains Physical Trample/Bash and its magic-dispellable Gulp control; Lady retains Nature-school spell Lightning Bolt and her original Druid's Slumber. Source-ID namespaces remain separate. Both Anglo cast cancellations were observed before their scheduled completion alongside real healer counter inputs. Gulp clears from the tank 1.85 seconds before source expiry after a cleanse input; the Rogue's separate Gulp expires naturally. Lady's Mage sleep clears 4.74 seconds before expiry after a cleanse input. Lady's single Vow of Silence attempt did not show a Lightning Bolt cancellation, so this run does not establish that particular cross-source interrupt behavior.
|
||||
|
||||
The full fights record zero movement inputs; the ranged healer remains outside the melee warning. Movement is checked separately in a labeled staged source-warning fixture, rather than being attributed to those full fights.
|
||||
|
||||
The same-final-build staged Anglo selection passes all three source fixtures, each releasing once, with no page errors. Trample spell 492292 retains its 1.8-second cast, five-unit radius, Physical school, effect and warning. Fixture setup selects one source attack, resets readiness/positions/threat and sets repeat cooldown to 60 seconds; companion actions are paused for the movement warning. Real W-key movement covers 2.75 units while the cast remains live, from 3.93 inside the radius to 6.69 outside. The player receives zero Trample damage while a nearby Rogue receives 262, proving recipient exclusion rather than suppressing the entire packet. Bash and Gulp also release once. Telemetry is `playtest-artifacts/native-combat/results.json`; the warning and movement images are `anglo-trample-warning-fixture.png` and `anglo-trample-movement-fixture.png`. Both were visually reviewed.
|
||||
|
||||
Full-fight telemetry and screenshots are in `playtest-artifacts/native-combat/full-fights-20261004-024033763/`. Root visual review confirms the roster player's body/staff, loaded player and party bodies with held weapon/shield/staff/bow silhouettes in the mid-fight capture, readable native recovery/Training gear equipment UI, and the defeated-boss result. Initial NPC loading placeholders resolve by mid-fight; they are not claimed as the loaded visual proof. No readiness review or dungeon report was submitted.
|
||||
|
||||
The harness syntax check, repository release check (including untracked files), repository/vault diff checks and edited-vault-note EOF/whitespace checks pass. These selected desktop Boss Testing scenes and scripted diagnostics do not certify every encounter, mobile UI, campaign traversal or readiness.
|
||||
|
||||
## Validation boundary
|
||||
|
||||
This is targeted work on the five active RoM builds and the current WoW Ready five. RoM builds remain Needs Testing. Cap 80, actor-local compatibility switching, automatic Training gear and the current loot scope remain unchanged. No all-class sweep, readiness promotion, commit or deployment is part of this task.
|
||||
@@ -0,0 +1,40 @@
|
||||
# Native RoM recovery source audit
|
||||
|
||||
## Implemented scope
|
||||
|
||||
Native RoM recovery now uses RuneWaker's ReHP/ReMP values and actor-specific pulse cadence for exact RoM-mode player builds and owned party NPCs. Player and companion stats remain actor-local: a companion uses its own class, secondary class, level, race, gear, and `statRuleset`. The native path only activates for a RoM class whose actor ruleset is `rom`; saved WoW-mode RoM characters and ordinary WoW actors keep the existing shared resource behavior.
|
||||
|
||||
The source-derived stat snapshot is already generated by `scripts/runewaker-pipeline/export-rom-native-stat-rules.mjs` into `src/game/generated/romNativeStatRules.generated.json`. `src/game/romNativeStats.ts` computes ReHP from its source base, stamina coefficient, and mapped gear/aura channel; ReMP uses its source base, wisdom coefficient, and mapped gear/aura channel. The five active build stat profiles use BaseReHP 2, ReHpArg 0.15, BaseReMP 0, and ReMpArg 0.3. The character's supported Mana eligibility is preserved, including a Mana secondary pool when the selected primary resource is not Mana.
|
||||
|
||||
## Source behavior
|
||||
|
||||
`F:/Projects/Runewaker/SourceCodeVS2019/Server/NetGameServer/MainProc/Global.cpp` contains the source player update at lines 1956–1984 and owned-NPC update at lines 2335–2363. Player recovery checks every `ClockMod(20)` and owned NPC recovery every `ClockMod(60)`, corresponding to 2-second and 6-second pulses in the source server clock. Dead actors and actors with `StopOntimeCure` set are skipped. Recovery only runs when integer current HP or MP differs from its maximum.
|
||||
|
||||
For players, `IsAttackMode()` restores no HP and restores `ReMP / 24` Mana per pulse. Out of attack mode, standing recovery restores `ReHP / 3` and `ReMP / 3`; sitting uses `0.66 * ReHP` and `0.66 * ReMP`. For owned NPCs, attack mode likewise restores only `ReMP / 24`; idle recovery restores `0.66 * ReHP` and `0.66 * ReMP`. The separate unowned-NPC branch uses max-resource fractions and is not the source behavior for party companions.
|
||||
|
||||
`F:/Projects/Runewaker/SourceCodeVS2019/Libraries/Union/RoleData/RoleAttr.cpp` lines 525–531 defines:
|
||||
|
||||
```text
|
||||
ReHP = max(0, BaseReHP + Fin.STA * ReHpArg + Mid.Body[ReHP])
|
||||
ReMP = max(0, BaseReMP + Fin.MND * ReMpArg + Mid.Body[ReMP])
|
||||
```
|
||||
|
||||
The resulting values are copied to `Fin.ReHP` and `Fin.ReMP` in the same file at lines 279–280. `RD_ValueCal.cxx` lines 1512–1552 (`AddHP`) and 1584 onward (`AddMP`) apply float amounts to the stored resources and clamp to their maxima, so simulator pulse values remain fractional instead of being rounded to whole points.
|
||||
|
||||
RoM Aura components mapped to source ReHP/ReMP channels are included in the per-pulse source stat snapshot. Other generic or unmarked regeneration modifiers do not enter the native recovery calculation. Explicit `rom-resource-over-time-*` Mana effects remain a separate simulator flow and are integrated over the effect's actual active interval; they are not added to ReMP. WoW's five-second mana spending rule and out-of-combat minimum do not apply to the native ReMP path.
|
||||
|
||||
## Runtime ownership and validation
|
||||
|
||||
`src/game/romNativeRecovery.ts` owns the 2-second player and 6-second owned-NPC pulse clocks, fractional source formulas, sitting coefficient, and separate explicit periodic-Mana interval integration. The clocks preserve fractional elapsed time across update partitioning and clear when actor kind/ruleset changes. `src/game/combatStore.ts` owns the player pulse consumer; `src/game/partyRuntime.ts` owns the companion consumer; `src/game/partyStore.ts` clears companion recovery timing on lethal damage, revive, and combat reset. Aura records are sampled at each pulse timestamp, so an aura expiring after a pulse still contributes to that pulse.
|
||||
|
||||
On the player path, source attack mode is approximated by the existing engaged-combat signal. For owned party NPCs, the source gate includes an active party target or a live engaged/threatened enemy, so the party's Stop command alone does not switch a companion to idle recovery. Native HP/Mana bypass shared HP5/Spirit, passive generic Mana, and the shared out-of-combat Mana floor. Other resource types continue through their existing resource model.
|
||||
|
||||
Focused validation is `npx vitest run src/game/romNativeRecovery.test.ts src/game/romNativeRecovery.integration.test.ts`; the parent task adds active-five NPC, secondary-Mana, and WoW-mode compatibility integration cases. Source and simulator limits remain: there is no sitting UI/state, no simulator equivalent for source `StopOntimeCure`, and player/party combat-mode detection is an approximation of source `IsAttackMode`. Native rates are source-derived; this audit does not certify sustained encounter pressure or change encounter budgets/readiness.
|
||||
|
||||
## Early level-one sustain diagnostic
|
||||
|
||||
The first native Knight level-one pull against Anglo ended after 141 seconds with the player and Rogue companion dead: Anglo's 2,772-HP pool was depleted, but incoming damage was 391.2, healing was 56, player damage was 118 across 6 casts, and 44 rotation decisions were resource-blocked. The pre-recovery/equipment baseline cleared the same pull in 54 seconds with 157.6 player HP remaining, 375 player damage across 19 casts, 262 healing, and 276 incoming damage. These two observations identified an additional attack-start and resource-rotation gap; they do not justify changing the source ReHP/ReMP formulas, and are not a full-cohort result.
|
||||
|
||||
Source Holy Strike `490148` is documented as a main-hand attack with Physical Light Damage. The imported direct hit was already level-one 16 holy damage, but its nonphysical damage school caused the generic attack-kind classifier to treat it as a spell; a cast therefore did not start the player's auto-attack. A separate `sourceAttackKind: "melee"` annotation now represents source delivery without changing effect school or amount. The focused regression confirms the cast remains 16 holy damage and is followed by a positive 22 physical auto-attack.
|
||||
|
||||
The level-one Priest observation showed max Mana 123 and ReMP 4.8, which gives an owned-NPC combat recovery pulse of 0.2 Mana every six seconds. At full party health its chooser selected 12-Mana Rising Tide despite having the 25-Mana Urgent Heal, confirming a finite-Mana rotation concern independent of recovery-rate math. A separate clean-room pre-level-10 healer policy reserves one learned direct heal before hostile Mana spending; it keeps source recovery unchanged. That reserve alone did not resolve the failed early encounter, so the native level-one boss training budget was separately reduced from 0.30 to 0.20. The unchanged final 80-pull cohort passes with zero player/NPC deaths and invalid casts. See [the aggregate verification and limits](ROM_NATIVE_RECOVERY_EQUIPMENT_PACING_PASS_2026-10-03.md).
|
||||
@@ -0,0 +1,55 @@
|
||||
# RoM Native Party Campaign Route Playtest — 2026-10-04
|
||||
|
||||
## Scope and build
|
||||
|
||||
Tested bounded entrance-to-encounter segments in Barren Caves and Wailing Caverns using the ordinary campaign picker. Each run used a UI-created level-30 RoM Priest / Knight healer and four active RoM NPC companions. Both dungeons entered in healer role with `gameMode=dungeon`, `gmTestMode=false`, and no Boss Testing state. Only initial profile level and secondary class were prepared for the isolated test profile. Dungeon entry, WASD movement, Tab targeting, party commands, ability keys, and ally selection used the game UI and normal inputs. Combat health, mana, damage, positions, cooldowns, enemy health, and targets were not changed by the harness.
|
||||
|
||||
The confirmed final production build used `index-CAMDJqEC.js`, `combatStore-t7bO4yKt.js`, `GameRuntime-otPnJCWI.js`, `PartyFrames-BsBsesPR.js`, and `index-499eecpe.css`.
|
||||
|
||||
## Roster Continue hit test
|
||||
|
||||
On the final build, the actual Continue button was clickable normally at both tested sizes. The 1440×900 layout and the 390×844 compact layout had no overlap with the floating toggle, and `elementFromPoint` at the button center hit Continue in each. The run recorded `forceClickUsed=false`.
|
||||
|
||||
- [Desktop Priest/Knight roster](../playtest-artifacts/native-routes/final-20261004-052623521/roster-priest-knight-level-30.png)
|
||||
- [Compact Priest/Knight roster](../playtest-artifacts/native-routes/final-20261004-052623521/roster-compact-priest-knight-level-30.png)
|
||||
- [Hit-test measurements and full run result](../playtest-artifacts/native-routes/final-20261004-052623521/results.json)
|
||||
|
||||
## Route results
|
||||
|
||||
| Campaign segment | Input and endpoint | Support and combat outcome |
|
||||
| --- | --- | --- |
|
||||
| Barren Caves, 90-second segment | 41 WASD movement steps; 68.13 m summed keyboard displacement and 69.34 m game distance; ended at “Uncharted Barren Caves.” | 15 effective player heals (6,154.63 total) and 7 effective player damage events (549 total); no party deaths. The level-30 profile naturally reached level 31. The endpoint view is partly blocked by a cave pillar, so this run demonstrates bounded movement and combat, not camera visibility or full navigation. |
|
||||
| Wailing Caverns, fresh level-30 profile, 90-second segment | F1 Attack then F2 Defend; 15 WASD movement steps; 23.12 m summed keyboard displacement and 23.76 m game distance; ended at “The Winding Chasm - Entrance.” | 11 effective player heals (6,831.49 total), zero effective player damage events, and no party deaths. Three distinct entrance mob records were observed dead across snapshots: Deviate Guardian, Deviate Ravager, and Druid of the Fang. This does not claim a full route or total dungeon kill count. |
|
||||
|
||||
The Wailing run selected the longest-range bound hostile ability, Rising Tide (21.7 m), and used Urgent Heal (25 m). The first Wailing diagnostic had kept the party and healer too far apart and lost Rorik; that trace is preserved at `final-20261004-051737171` as a harness-policy diagnostic. The final run sampled live NPC positions, waited for healing casts to resolve, and issued F2 Defend after the initial F1 pull. Rorik survived this bounded segment, but the run produced no effective player damage, so it provides no player-DPS coverage.
|
||||
|
||||
The observed school list is from the combined combat event stream, including player and NPC activity; it does not establish that each enemy used every listed school. `killedMobNames` describes dead mobs still present in the endpoint snapshot. Wailing's three names above are the distinct dead records sampled during the segment, not a complete kill ledger.
|
||||
|
||||
## Evidence
|
||||
|
||||
**Barren Caves** — completed route record and screenshots:
|
||||
|
||||
- [Route JSON](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-route.json)
|
||||
- [Campaign picker](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-campaign-picker.png)
|
||||
- [Entrance](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-entrance.png)
|
||||
- [Keyboard traversal](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-keyboard-traversal.png)
|
||||
- [Encounter midpoint](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-encounter-midpoint.png)
|
||||
- [Segment endpoint](../playtest-artifacts/native-routes/final-20261004-051413627/barren-caves-segment-end.png)
|
||||
|
||||
The combined Barren/Wailing attempt has a follow-on `failure.json`: after Barren naturally advanced the profile to level 31, a harness assertion expected level 30 before starting the second route. The Barren route JSON and its screenshots are complete and are reported independently. Wailing was then run in a fresh level-30 profile.
|
||||
|
||||
**Wailing Caverns** — independent final route record and screenshots:
|
||||
|
||||
- [Run summary](../playtest-artifacts/native-routes/final-20261004-052623521/results.json)
|
||||
- [Route JSON and detailed movement/heal records](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-route.json)
|
||||
- [Campaign picker](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-campaign-picker.png)
|
||||
- [Entrance](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-entrance.png)
|
||||
- [Keyboard traversal](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-keyboard-traversal.png)
|
||||
- [Encounter midpoint](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-encounter-midpoint.png)
|
||||
- [Segment endpoint](../playtest-artifacts/native-routes/final-20261004-052623521/wailing-caverns-segment-end.png)
|
||||
|
||||
Both route runs reported zero browser page exceptions. Each recorded one console-level 404 for the local `/favicon.ico` request. The Wailing run also records normal keyboard events, party positions, health and mana at entry and endpoint, cast outcomes, and sampled enemy deaths.
|
||||
|
||||
## Harness
|
||||
|
||||
`node scripts/playtest-native-routes.cjs --route=<barren-caves|wailing-caverns> --route-seconds=90` runs an independent UI-created profile and one bounded segment. The default records both routes sequentially and carries natural level progression into later entry. Run and review each route independently to control its starting profile at level 30.
|
||||
@@ -53,3 +53,15 @@ At the shared combat boundary, runtime may use numeric native ATK as common atta
|
||||
## Focused verification
|
||||
|
||||
`romNativeStats.test.ts` checks every class/race/gender primary curve, player-derived level-1 channels, MP gating, source healing coefficients, the 148/191 conversion boundary, a real level-70 Mage reference curve, rate-preserving aura recomputation, and gear aggregation. `equipment.test.ts` checks per-item payload precedence, foreign direct-stat bridging, mixed-loadout behavior, and native equip/unequip impact. `itemStats.test.ts` checks that native payload persistence does not change the existing WotLK numeric fields.
|
||||
|
||||
## Combat amount follow-up (2026-10-03)
|
||||
|
||||
The earlier per-spell boundary above is now partially bridged by `src/game/romNativeCombatAmount.ts`, `romNativeHealing.ts`, and `romNativeDamage.ts`. `romAbilityCatalog.ts` attaches a source skill/component key to supported native effect amounts; the runtime resolves that key against generated RuneWaker binding data. Direct HolyHeal calculation type 5 uses the source OrgPower/MagicLv and caster MND, MDMG, MPow, HealPowerRate, HealPoint inputs. The currently selected MagicLv is the character level clamped to 1–80, an explicit simulator policy rather than a source rank curve. This amount uses mean variance; the ordinary shared healing resolver continues to handle the common critical and overheal result.
|
||||
|
||||
The direct HolyHeal caster amount excludes target absorption fields; the source HealAbsorbRate and flat HealAbsorb are applied once for each actual recipient. DotMagic healing has its own source rank correction at application and stores its integer buff/tick amount for later pulses; player and NPC recipients reuse that same snapshot rather than reapplying the amount formula. It is not routed through the direct HolyHeal equation. The present all-magic MPow value does not establish missing element-specific BodyRate values. Unbound or unsupported components still use the shared simulator fallback.
|
||||
|
||||
The current direct-damage route accepts only supported active-five source components with a matching canonical training-weapon payload. `MagicAttackCalENUM` fixed types 0, 1, 2, 3, and 5–9 are implemented from the checked source enum; throw, prior-hit, and shield-category branches remain unsupported because the sidecar lacks their exact inputs. The consumer also declines `isShareDamage` components and components with nonzero `decreaseArg` on nonzero `rangeType` until exact runtime target-count and target-ordinal context is wired; the pure helper's support for these fields is not end-to-end area-damage support. Reflected Shot has a regression for this fail-closed boundary. Custom/unverified native equipment, missing source items/components, and unavailable school inputs keep the shared fallback. The returned ability amount stops at mean outgoing source power before source weapon variance, native hit/avoidance, and native target-defense handling; the existing shared target resolver remains the simulator bridge.
|
||||
|
||||
`nativeTrainingAutoAttackProfile` provides native physical weapon damage and intervals for player Knight main-hand attacks and NPC Knight/Rogue melee plus Scout Bow attacks; NPC Rogue offhand is also covered. Player Rogue offhand handling requires an explicitly present equipped inventory item. Player Scout Shot uses the native direct-damage route for its actual bound Shoot hit, not a continuous native bow-auto profile. Caster ambient basic-spell attacks keep the generic clock and MDMG policy. Player melee timing reads the existing common haste aura through `resolveAuraStatValue`, since native stat re-derivation does not populate the shared haste fields; the existing race-affix timing is retained. The final source-damage selection passed 13 tests: seven helper cases, two player/companion amount-parity and Reflected Shot fail-closed cases, and four actual auto/source-action cases. Native direct/periodic healing passed 14 player/NPC cases. These routes do not complete native hit/avoidance, armor categories, weapon variance, or critical resolution.
|
||||
|
||||
The final fixed player-rotation/native-companion diagnostic covers 80 pulls across the five requested builds at levels 1/10/30/60/65/66/79/80. All 80 targets died, with zero player/NPC deaths and zero invalid cast failures; trash took 4.5–9 seconds and Anglo 39–53.4 seconds. Native-only enemy health pacing is scoped separately from legacy WoW-stat RoM and other character origins; details and the exact bands are in [`ROM_NATIVE_COMBAT_PASS_2026-10-03.md`](ROM_NATIVE_COMBAT_PASS_2026-10-03.md). The ordinary randomized companion pool is now restricted to the active five identities; the configured factory remains broader for explicit party construction. Final production build passed with asset audits, compression, and bundle verification. Exact-dist browser QA passed with 11 screenshots captured and four representative roster, dungeon, NPC-stat, and mobile screenshots visually reviewed; current chunks were `index-D_h9IRuA.js` and `combatStore-BiA9BOQG.js`. There were no page, server, or HTTP errors and the network response-errors list was empty; the only console error was the optional existing favicon 404. A release check passed on 249 paths; the final documentation update requires the final hygiene/release check. The remaining limits are not a readiness promotion or complete balance certification.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Targeted native RoM healing sustain audit — 2026-10-04
|
||||
|
||||
## Scope
|
||||
|
||||
This diagnostic runs three consecutive Barren Caves Anglo pulls at levels 60 and 80. Each pull uses the original RuneWaker NPC 101462 attack list and the existing boss health budget. The active five are the native RoM Knight player in the tank seat and owned Priest, Rogue, Scout, and Mage NPCs. The Priest is measured as the owned party actor `party-healer-0-rom-priest`; its healing events are selected by that exact `sourceActorId`, independently of player healing.
|
||||
|
||||
The test preserves party HP, Mana, effects, and cooldowns between pulls. The first interval has no enemy for 10 seconds; the second has no enemy for 90 seconds. It does not reset the party between encounters. The focused test writes its measurements to `artifacts/rom-enemy-followup/native-sustain-2026-10-04.json` when `ROM_NATIVE_SUSTAIN_REPORT=1`.
|
||||
|
||||
Heal-event `rawAmount` is reported separately because it can be affected by source modifiers. Event publication occurs synchronously inside the heal state update, so the test reads pre-heal actor HP in the event callback and derives post-heal HP from `effectiveAmount`. Delivered healing is the conserved `effectiveAmount + overheal`; the waste share below uses that delivered amount. Cast-time Mana cost is an estimate reconstructed from the actor's ability-cost calculation at release. Starting, minimum, and ending Mana are actual NPC resource-pool readings. The capacity shown in the table is the NPC's resource maximum captured at pull start; temporary effects may change capacity during a pull.
|
||||
|
||||
## Results
|
||||
|
||||
All six pulls cleared with the player and all four NPCs alive. The Priest never ran out of Mana. Pull time and boss damage vary by level and pull:
|
||||
|
||||
| Level | Pull | Clear | Boss damage to party | Priest minimum Mana / starting capacity | Minimum / starting capacity | Estimated Priest Mana cost |
|
||||
| --- | ---: | ---: | ---: | ---: | ---: | ---: |
|
||||
| 60 | 1 | 79.1 s | 3,233 | 6,138 / 6,904 | 88.9% | 979 |
|
||||
| 60 | 2 | 90.4 s | 7,344 | 5,711 / 8,077 | 70.7% | 911 |
|
||||
| 60 | 3 | 80.6 s | 5,588 | 7,521 / 8,077 | 93.1% | 746 |
|
||||
| 80 | 1 | 124.1 s | 47,618 | 17,286 / 17,924 | 96.4% | 1,255 |
|
||||
| 80 | 2 | 123.3 s | 27,704 | 17,683 / 19,736 | 89.6% | 1,265 |
|
||||
| 80 | 3 | 118.7 s | 24,385 | 19,123 / 19,736 | 96.9% | 1,178 |
|
||||
|
||||
Across level 60, the NPC Priest delivered 110,080 healing: 39,753 effective and 70,327 overheal (63.9%). At level 80 it delivered 264,241: 183,396 effective and 80,845 overheal (30.6%). The raw event-amount sums were 110,080 and 264,241 in these samples. The Priest released 15 `Heal` and 12 `Regenerate` casts at level 60, and 19 `Heal` and 13 `Regenerate` casts at level 80. Regenerate tick overheal accounts for 32,718 at level 60 and 51,936 at level 80; direct Heal packets account for 37,609 and 28,909 respectively. Periodic ticks after a paid cast do not each spend Mana.
|
||||
|
||||
Mana at the second pull shows what a short break restores without resetting actors. At level 60, the Priest had 6,154 Mana after pull 1 and 6,403 after 10 seconds; at level 80 it had 17,327 and 18,305. The 90-second breaks restored 2,366 at level 60 and 2,053 at level 80, taking the Priest to full of its pull-3 starting capacity.
|
||||
|
||||
The measured Priest remained at full health through all four breaks: 7,935/7,935 at level 60 and 29,286/29,286 at level 80. Cooldowns continued to run instead of being reset. For example, `rom-priest-general-3` had 50.9 seconds remaining before the level-60 short break and 40.9 afterward; at level 80, a 113.2-second cooldown became 23.2 seconds over the long break.
|
||||
|
||||
## Healing decision observation
|
||||
|
||||
The owned NPC attribution showed substantial overheal but not a safe direct-heal suppression rule. All observed Priest `Heal` cast starts had a pending `rom-priest-general-2` Regenerate, with the target's party/player health snapshot between 58% and 90%; the mirrored combat-actor HP is recorded separately to expose state differences. The casts take two seconds while Anglo continues attacking, and the lowest observed target snapshot was in that pressure window. Merely detecting a HoT would therefore suppress some direct heals during active damage. No full-health direct Heal appeared in the party/player health snapshot at cast start, and at least one direct heal remained observable with an active HoT at 60% health or below. The focused test guards both observations.
|
||||
|
||||
No healing AI or source recovery change was made. The audit records meaningful level-60 overheal and tests the emergency path, but it does not establish that changing the native source rates, direct-heal threshold, or HoT timing would improve survival across encounters. This remains a targeted sustain diagnostic, not a balance or readiness certification.
|
||||
|
||||
## Validation limits
|
||||
|
||||
The result covers one selected source boss, one active-five seating, and six deterministic local pulls. It does not establish campaign traversal, all RoM healer pairings, different boss attack mixes, mobile scene behavior, or class readiness. Run only the focused test for this diagnostic:
|
||||
|
||||
```powershell
|
||||
$env:NODE_OPTIONS='--max-old-space-size=8192'
|
||||
$env:ROM_NATIVE_SUSTAIN_REPORT='1'
|
||||
npx vitest run src/game/romNativeSustain.integration.test.ts
|
||||
```
|
||||
@@ -0,0 +1,195 @@
|
||||
# RoM rotation add-on reference and clean-room profiles — 2026-10-03
|
||||
|
||||
## Scope and conclusion
|
||||
|
||||
This note records source research for the five exact Chronicles of Arcadia (CoA) class pairs used by the native five-character roster:
|
||||
|
||||
| Main / secondary class | Roster identity | Role |
|
||||
| --- | --- | --- |
|
||||
| Knight / Scout | Rorik | Tank |
|
||||
| Priest / Knight | Serenna | Healer |
|
||||
| Rogue / Warrior | Veyra | Damage |
|
||||
| Scout / Rogue | Caelan | Damage |
|
||||
| Mage / Warlock | Durnik | Damage |
|
||||
|
||||
The mapping is defined in [`romFiveIdentities.ts`](../src/game/romFiveIdentities.ts). The current CoA add-on source I could verify is **KittyCombo**, a user-configurable priority engine, rather than a set of published, maintained rotations for these five pairs. The only detailed DIYCE rotation material located for an exact target pair is a **2018 Scout/Rogue example**; it is historical and cannot be treated as a current CoA rotation. No source found verifies a complete, current, exact-pair rotation for any of the five builds. The priority sketches below are clean-room proposals informed by current CoA skill references and local runtime features; they are not copied add-on rotations.
|
||||
|
||||
## Add-on source provenance
|
||||
|
||||
### KittyCombo — current CoA add-on, engine rather than preset source
|
||||
|
||||
CurseForge identifies KittyCombo as a customizable combat engine for class combinations. Users create ordered actions and conditions, then can import or export rotation configurations. The project page names mdnss as author and devikaria as contributor; it lists GPLv3, version 2.4.1003 / file 8487473, uploaded 2026-07-22, with game version 11.0.0.0000. The listing and its source page do not publish a current rotation package or a verified skill priority for any target pair.
|
||||
|
||||
- [KittyCombo project page](https://www.curseforge.com/chronicles-of-arcadia/addons/kittycombo)
|
||||
- [KittyCombo source page](https://www.curseforge.com/chronicles-of-arcadia/addons/kittycombo/source)
|
||||
- [KittyCombo 2.4.1003 file record](https://www.curseforge.com/chronicles-of-arcadia/addons/kittycombo/files/8487473)
|
||||
- [CoA help: add-on installation](https://chroniclesofarcadia.com/en/help/900178)
|
||||
|
||||
The source page advertises source availability, but did not expose a repository URL in the browser view. A read-only archive fetch was attempted for file 8487473 to the ignored `artifacts/rom-rotation-reference/` directory. The ordinary network sandbox blocked the first request; an authorized retry reached a Cloudflare JavaScript/cookie challenge instead of an archive, so no file was created. No add-on code was executed or installed. Public metadata and source-page references remain available above.
|
||||
|
||||
### DIYCE — historical priority-engine ideas, not current-pair guidance
|
||||
|
||||
The official CoA forum has a 2016 DIYCE post describing a skill-discovery/readiness loop and a 2018 DIYCE post describing an ordered, button-triggered priority evaluation. They illustrate durable ideas—evaluate learned skills, check cooldown/resource/use predicates, then choose the first eligible action—but the post code is historical and has no stated license. I did not copy or adapt its code.
|
||||
|
||||
- [Nadaná's DIYCE introduction (2016)](https://forum.chroniclesofarcadia.com/thread/640-diyce-ingame-macros-and-more/)
|
||||
- [GhostWolf's DIYCE thread (2018)](https://forum.chroniclesofarcadia.com/thread/1649-do-it-yourself-combat-engine-diyce/)
|
||||
|
||||
The 2018 thread includes a Scout/Rogue-oriented example with resource thresholds, a silence condition, control, and damage priorities. That is an exact pair and orientation match for Caelan, but it is an eight-year-old reference; its priorities, spell names, timings, or API assumptions should not be carried into present-day CoA. It also shows a Warrior/Rogue branch, the reverse of Veyra's Rogue/Warrior, so it is not a pair match for Veyra.
|
||||
|
||||
CurseForge also retains [DIY Combat Engine v2](https://www.curseforge.com/rom/addons/diy-combat-engine-v2), an old RoM project (project 55223, updated 2013-04-18, game version 5.0.9) by `_ForgeUser10895305`. Its “Just give credit” terms do not make it a current CoA source, and its description says users supply/build class-combination scripts. I treated it as historical context only.
|
||||
|
||||
## Current CoA class-pair references
|
||||
|
||||
The official CoA skill pages below were used to confirm pair orientation and selected skill prerequisites or mechanics. Pair lists are live references and may change; in particular, the Priest/Knight pair page could not be retrieved in the browser session. That profile proposal therefore uses the current general Priest list, the current special-skills index, and current CoA patch notes, and requires runtime checks against the actual learned catalog before a skill can be selected.
|
||||
|
||||
- [Knight/Scout skills](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=en): Holy Seal, Whirlwind Shield, ranged Arrow of Vengeance, shield-dependent abilities, mitigation, and control-break skills.
|
||||
- [Priest/Knight skills](https://chroniclesofarcadia.com/en/wiki/skills/list/5-6) (page fetch unavailable in this research); [Priest common skills](https://chroniclesofarcadia.com/wiki/skills/list/5-12?locale=en) and the [special-skills index](https://chroniclesofarcadia.com/en/wiki/basic-information/special-skills) were accessible.
|
||||
- [Rogue/Warrior skills](https://chroniclesofarcadia.com/en/wiki/skills/list/3-1): Rogue Energy plus Warrior Rage, weapon-dependent attacks, Rotten application, and bleed-sensitive damage.
|
||||
- [Scout/Rogue skills](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en): ranged attacks and ammunition, Focus and Energy costs, poison effects, and Vampire Arrows-dependent attacks.
|
||||
- [Mage/Warlock skills](https://chroniclesofarcadia.com/en/wiki/skills/list/4-9): shared mana/focus decisions, curse and damage-over-time mechanics, channels, and cooldown alignment.
|
||||
- [Current special-skills index (revision 2026-08-31)](https://chroniclesofarcadia.com/en/wiki/basic-information/special-skills).
|
||||
- [CoA patch 11.1.5 notes](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000), which document current Priest/Knight changes: Calm Heart radius, Life Link becoming active, and Sacrificial Cure changing to MP cost with an MP-based shield.
|
||||
|
||||
One practical versioning warning: the local [`romPlayerCatalog.generated.json`](../src/game/romPlayerCatalog.generated.json) contains a RuneWaker-derived source snapshot with CoA overrides. It is useful as the project's runtime candidate catalog, but it is not itself proof that every base skill value matches the current CoA live pages. Rotations must select only skills present in the active ruleset catalog, then respect that catalog's learned-level, weapon, range, resource, cooldown, and target gates. In particular, historical Priest/Knight behavior must not be used to infer today's Sacrificial Cure cost.
|
||||
|
||||
## Clean-room selection contract
|
||||
|
||||
`combatRotation.ts` retains the WoW specialization profiles; `rotationProfileFor` selects on primary class and specialization and does not discriminate a secondary class or role. The companion [`romFiveRotation.ts`](../src/game/romFiveRotation.ts) resolves native RoM profiles separately by the exact tuple `(ruleset, primaryClassId, secondaryClassId, role)` and returns no profile when the tuple does not match. The five pairs above are ordered pairs: `rom-scout/rom-rogue` does not imply `rom-rogue/rom-scout`.
|
||||
|
||||
The existing rotation context already carries most useful decisions: learned abilities, readiness/cooldown, resource and maximum resource maps, health, hostile target/cast, enemy count, threat state, defensive-mechanic signals, party health/role/status, movement, maintained effects, and pets. Runtime availability (`learned`, `ready`, `canUse`, in-range, valid weapon, sufficient resource, legal target) must be a hard gate, not merely a score penalty. Every profile is an ordered set of predicates, with emergency overrides before ordinary damage priorities.
|
||||
|
||||
Use actor-owned, target-owned status state when tracking a DoT. Refresh a DoT only when it is absent or close to expiry; do not reapply it on every priority evaluation. Existing Death Knight disease tracking in [`partyRuntime.ts`](../src/game/partyRuntime.ts) is a local model for source/target ownership and tick timing. Buffs, marks, and setup effects should likewise refresh only when missing or expiring. A class-specific predicate may add weapon, ammunition, status, resource, enemy-count, movement, cast, or threat requirements, but it cannot bypass the shared runtime gates.
|
||||
|
||||
Generic pseudocode:
|
||||
|
||||
```text
|
||||
profile = exactProfile(ruleset, primaryClass, secondaryClass, role)
|
||||
if profile is absent: use no RoM rotation
|
||||
|
||||
for action in profile.emergencyOverrides followed by profile.priorityList:
|
||||
if not learned(action) or not ready(action) or not canUse(action): continue
|
||||
if weapon/ammo/status/resource/range/target gates fail: continue
|
||||
if action applies a maintained effect and that effect is healthy: continue
|
||||
if action is a damage-over-time effect and own effect expires later than refreshWindow:
|
||||
continue
|
||||
if action.predicate(context): cast action; stop this evaluation
|
||||
```
|
||||
|
||||
`refreshWindow` should be derived from the active effect duration / tick schedule and evaluated using effect ownership in runtime state, not guessed from an old macro's timer.
|
||||
|
||||
## Proposed exact-pair priority sketches
|
||||
|
||||
These sketches define decision order and use conditions, not mandatory button rotations. Every action is conditional on being learned and unlocked at that character's level, existing in the active CoA ability catalog, and passing runtime use checks.
|
||||
|
||||
### Knight / Scout — Rorik, tank
|
||||
|
||||
```text
|
||||
if a dangerous cast/mechanic is incoming and an applicable mitigation is ready:
|
||||
use the narrowest effective group/personal mitigation
|
||||
if control is active or imminent and the learned break is ready:
|
||||
use control break
|
||||
if an enemy is loose from the tank or the assigned target is outside threat control:
|
||||
use a legal taunt (ranged Arrow of Vengeance only with a ranged weapon)
|
||||
if multiple enemies are engaged and shield is equipped and threat needs building:
|
||||
use Whirlwind Shield
|
||||
if Holy Seal stacks are absent/low:
|
||||
build Holy Seal with a legal builder
|
||||
if a defensive hit is imminent or self-survival needs a shield:
|
||||
spend Holy Seal through Truth Shield Bash when learned/usable
|
||||
else if a control/interrupt use is required and Shock's seal cost is acceptable:
|
||||
spend Holy Seal through Shock
|
||||
else:
|
||||
preserve useful seal stacks; use the best legal single-target threat/damage action
|
||||
use Heavenly Arrows only when its channel is safe and multiple targets justify it
|
||||
use non-urgent long cooldowns only for a dangerous encounter window
|
||||
```
|
||||
|
||||
Holy Seal's current pair page lists a ten-second effect and stack generation; Truth Shield Bash consumes it to create a defensive shield, while Shock is a damage/control spender. Do not spend those stacks automatically when a dangerous mechanic is near. Whirlwind Shield is shield-gated and provides area threat. Arrow of Vengeance is ranged-weapon gated and should respond to real threat loss, not be a routine damage action. Sacred Protection and other long cooldowns belong to incoming group damage or a defensive threshold, not a fixed timer. These candidate mechanics are from the [current Knight/Scout page](https://chroniclesofarcadia.com/wiki/skills/list/6-2?locale=en); use current catalog data for unlocks and costs.
|
||||
|
||||
### Priest / Knight — Serenna, healer
|
||||
|
||||
```text
|
||||
if an ally has an actionable harmful effect and a matching dispel is learned/ready:
|
||||
dispel
|
||||
if a living ally is at emergency health or a lethal mechanic is landing:
|
||||
use the fastest safe direct heal / emergency shield
|
||||
if several allies are hurt and group healing is efficient, affordable, and not exhausted:
|
||||
use Group Heal
|
||||
if one ally has a meaningful deficit and a safe cast window:
|
||||
use Heal
|
||||
if a target needs sustained healing and its own Regenerate is absent/near expiry:
|
||||
apply Regenerate
|
||||
if a major damage window is imminent and a learned mitigation/absorption can prevent it:
|
||||
apply it before impact
|
||||
if Calm Heart's current condition is met (fear/status or boss warning):
|
||||
use Calm Heart
|
||||
if an ally is dead and combat has ended:
|
||||
resurrect
|
||||
```
|
||||
|
||||
Keep urgent single-target healing ahead of cast-time healing when an ally may die before the cast completes. Do not heal a full target, repeatedly overwrite an active HoT, or use Group Heal into its Exhaustion penalty when only one party member needs help. Use party deficits and expected incoming damage to decide whether a group heal is worth its mana cost. Patch 11.1.5 makes Life Link an active skill and changes Sacrificial Cure to MP cost with an MP-based shield; the logic must inspect the live active skill metadata and should use Sacrificial Cure as an emergency action only when the current resource and shield conditions justify it. Do not apply the old HP-cost interpretation. Calm Heart is a conditional fear response, not routine healing. References: the [Priest common skill page](https://chroniclesofarcadia.com/wiki/skills/list/5-12?locale=en), [special-skills index](https://chroniclesofarcadia.com/en/wiki/basic-information/special-skills), and [11.1.5 notes](https://chroniclesofarcadia.com/tr/patch/11-1-5-3000). Exact current Priest/Knight pair-page values remain unverified because that page could not be fetched.
|
||||
|
||||
### Rogue / Warrior — Veyra, damage
|
||||
|
||||
```text
|
||||
if target is durable enough for setup and a useful bleed/poison is absent or near expiry:
|
||||
apply one legal setup effect, respecting weapon and resource requirements
|
||||
if target has a bleed / Rotten condition and Wound Attack is learned, ready, affordable:
|
||||
use Wound Attack
|
||||
if axe is equipped and Rotten is absent/near expiry and Death's Touch is legal:
|
||||
apply Death's Touch
|
||||
else if Poison Stab is legal, affordable, and Rotten is absent/near expiry:
|
||||
apply Poison Stab
|
||||
if burst cooldown is ready and target will survive the burst window:
|
||||
use Assassin's Rage / other learned burst action
|
||||
use the best legal direct attack while setup effects tick
|
||||
```
|
||||
|
||||
Rogue Energy and Warrior Rage are separate resources; verify the specific cost rather than assuming one shared pool. Rotten/bleed effects should be tracked by source and target and refreshed near their actual expiration, so repeated Poison Stab or Death's Touch does not clip remaining damage. Death's Touch is axe-dependent, and other attacks may also be weapon-gated. Wound Attack benefits from existing bleed/grievous conditions, so it should not outrank establishing those conditions. Save major burst for an encounter window that will last long enough to realize it. See the [current Rogue/Warrior page](https://chroniclesofarcadia.com/en/wiki/skills/list/3-1); do not import the historical reverse Warrior/Rogue branch from DIYCE.
|
||||
|
||||
### Scout / Rogue — Caelan, damage
|
||||
|
||||
```text
|
||||
if the target is worth a control effect and control is needed to interrupt/prevent danger:
|
||||
use the least disruptive learned control; avoid breaking it with casual damage
|
||||
if target is durable and poison is missing/near expiry:
|
||||
apply the legal poison setup (respect ammunition/status prerequisites)
|
||||
if Vampire Arrows' required effect is missing and Deadly Poison Bite is a planned follow-up:
|
||||
establish Vampire Arrows; then use Bite only when its own effect is absent/near expiry
|
||||
if own poison effects are healthy:
|
||||
do not refresh them early
|
||||
if a multi-target pack is present and poison spread is useful:
|
||||
use an ammunition-legal spread action
|
||||
otherwise:
|
||||
use the best legal ranged/rogue direct action without starving its required resource
|
||||
```
|
||||
|
||||
This exact pair has both Focus and Energy decisions, ranged ammunition constraints, and setup-dependent poison attacks. Vampire Arrows is a prerequisite for Deadly Poison Bite in the current pair reference; the attack should not be attempted until that current status gate is satisfied. Combo Shot / Reflected Shot can be ammunition-gated and can contribute poison spread when the poison setup is present, so spreading is justified only when there are enough durable targets. Lasso or Blinding Powder should be reserved for a control need because subsequent damage can break control. Weak Spot is an affordable-enough-only decision, not an unconditional cast. These are the current [Scout/Rogue page](https://chroniclesofarcadia.com/wiki/skills/list/2-3?locale=en) mechanics; the old DIYCE branch is only a historical example.
|
||||
|
||||
### Mage / Warlock — Durnik, damage
|
||||
|
||||
```text
|
||||
if a useful curse is missing/near expiry and no active channel will apply it:
|
||||
apply the curse
|
||||
if a useful Soul Pain effect is missing/near expiry and no active channel will apply it:
|
||||
apply Soul Pain
|
||||
if Cast Shadow is learned and enemies are in its area and channeling is safe:
|
||||
channel Cast Shadow instead of duplicating its automatically applied effects
|
||||
if Shadow Beam is learned, resources support the channel, and target uptime is good:
|
||||
channel Shadow Beam; do not overwrite effects it reapplies
|
||||
if Elemental Catalysis is ready and a good sustained/channel damage window exists:
|
||||
align it with the channel/burst window
|
||||
if Will of Light's stack threshold is met and mana recovery is useful:
|
||||
convert stacks for mana / its current effect
|
||||
use legal direct damage while preserving sufficient mana/focus to finish a valuable channel
|
||||
```
|
||||
|
||||
Cast Shadow and Shadow Beam have channel-specific side effects, so the ordinary curse/DoT refresh branch must stand down when that channel will refresh them. Avoid moving or interrupting a channel unless an encounter mechanic requires it. Elemental Catalysis is a burst window; align it with useful channel uptime instead of spending it on an empty or soon-to-die target. Will of Light is a stack-gated recovery choice, not a routine priority. Soul Pain also interacts with Focus; preserve enough resources for useful follow-ups. Confirm the exact active unlock/cost metadata at runtime. References: the [current Mage/Warlock page](https://chroniclesofarcadia.com/en/wiki/skills/list/4-9).
|
||||
|
||||
## Fit with current HealerMan runtime and validation
|
||||
|
||||
[`combatRotation.ts`](../src/game/combatRotation.ts) keeps the shared evaluator and WoW profile registry. The exact RoM profiles and their native-only action guards are implemented in [`romFiveRotation.ts`](../src/game/romFiveRotation.ts); [`partyAbilityAi.ts`](../src/game/partyAbilityAi.ts) and [`benchmarkController.ts`](../src/game/benchmark/benchmarkController.ts) pass learned, cooldown/resource-ready actions and runtime target/effect state into that evaluator. The evaluator still applies `canUseAbility`, target, and movement gates. `partyRuntime.ts` owns actor/target periodic-effect bookkeeping; refresh decisions use the source actor, target, and remaining duration when those records are present.
|
||||
|
||||
The focused [`romFiveRotation.integration.test.ts`](../src/game/romFiveRotation.integration.test.ts) runs the five exact profiles against active learned catalog abilities and checks Serenna's Group Heal and urgent direct-heal ordering, owned/foreign and near-expiry DoTs, and the unchanged WoW profile selector. The existing [`romFiveNativeDungeonHealth.test.ts`](../src/game/romFiveNativeDungeonHealth.test.ts) remains the targeted player/companion diagnostic across its selected native dungeon and level cases. Keep follow-up runtime comparisons restricted to the five listed identities and existing diagnostic cases; this work does not authorize a broad RoM sweep or readiness promotion.
|
||||
|
||||
This file records source research; the resulting clean-room profile and native/shared-evaluator coverage live separately in [`romFiveRotation.ts`](../src/game/romFiveRotation.ts), [`romFiveRotation.test.ts`](../src/game/romFiveRotation.test.ts), and [`romFiveRotation.integration.test.ts`](../src/game/romFiveRotation.integration.test.ts). The focused unit and integration files currently pass together (17 tests).
|
||||
@@ -0,0 +1,54 @@
|
||||
# RoM Vow of Silence live Boss Testing evidence — 2026-10-04
|
||||
|
||||
## Corrected final-build replay
|
||||
|
||||
The corrected production build passed the dedicated live Boss Testing replay. A UI-bound RoM Priest/Knight used Vow of Silence on Lady Anacondra's actual source-scheduled Lightning Bolt. The Bolt ended before its scheduled completion, the boss held the 8.4-second silence status for its full duration, and no nonphysical active cast or cast start was observed while that status was active. Lady naturally resumed casting Nature Lightning Bolt 61 ms after the status expired. The final harness recorded 39 active-status samples.
|
||||
|
||||
The run used `playtest-artifacts/vow-live-final/final-build-20261004-153859692/results.json`. At script start it hashed all six requested final production assets:
|
||||
|
||||
| Asset | SHA-256 |
|
||||
| --- | --- |
|
||||
| `index-Cm7Olrd2.js` | `590a12db36de688cd0b8ffddc0a9c0a2102a93bbf9fc3c72d60f4a712d1e9c93` |
|
||||
| `combatStore-1B4KOVhS.js` | `58296b0213524f7a3822dfdde78739c8bf918f15149abb85401a05bb1b8b3341` |
|
||||
| `GameRuntime-hM1AaOYR.js` | `b307db151ff4a6601bfecb9aa8f2860cdcb1b5097798185c10b77300ad0f0f30` |
|
||||
| `PartyFrames-BfZEkXH5.js` | `4d3a06c8906c5c3f6c4e9fc4131637cf21e8ee828eea7e4f651d8f6ffc07cf2d` |
|
||||
| `romAbilityCatalog-DjRUCJbs.js` | `88fb48add6b2411011861ba4e6c4465e31be997b3d5d4a6e18a8a69fd116dce3` |
|
||||
| `index-499eecpe.css` | `c8569a67e221f96ebf7c68c32b2c057854f702ffe497250b96273fde89bf12d9` |
|
||||
|
||||
The fight used the dedicated Boss Testing UI, a newly UI-created level-30 RoM Priest with RoM Knight as secondary class, and the four owned native RoM companions Rorik (Knight/Scout), Durnik (Mage/Warlock), Caelan (Scout/Rogue), and Veyra (Rogue/Warrior). Vow (DBC 490275) was bound through Ability controls to Shift+Digit5. Combat used ordinary keyboard commands and read-only snapshots; no enemy cast, target, position, cooldown, HP, or resource was staged or changed by the harness. The isolated character's level and secondary class were the only setup changes.
|
||||
|
||||
- Lady Anacondra was the live target `lady-anacondra-spawn`, source entry 3671. Her source mechanic immunities were `fear` and `horror`; she had no school immunities. Vow metadata was hostile target, range 0–150, with no radius or targeting shape.
|
||||
- The observed Lightning Bolt was interruptible Nature `spell-9532`, started at 1791128371234 and scheduled to finish at 1791128372734. The player's Vow completed on Lady at 1791128371374. The immediate target snapshot had no active cast, and the completed player Vow event targeted Lady. The applied status `silence` expired at 1791128379774—exactly 8,400 ms after the Vow event.
|
||||
- Player position was approximately `[-15.3401, -87.6799, 314.1800]`; Lady was `[-15.34, -87.70, 297.18]`, within Vow's 150-unit range. The full status window contained 39/39 active silence samples, zero nonphysical active casts, and zero nonphysical cast starts. Lightning Bolt's cast count stayed at 1 during silence.
|
||||
- With the party on its ordinary Defend command during the observation interval, Lady's source-scheduled Nature Lightning Bolt resumed at 1791128379835, 61 ms after silence expired. The encounter then continued normally and Lady was defeated.
|
||||
- The presentation callback did not expose a usable named subscription in this production bundle, so no `cast-cancel` presentation event is claimed. Cancellation is supported by the read-only state transition from the observed live Bolt to no active cast before its scheduled end, together with the successful player Vow event and the boss's applied silence status.
|
||||
|
||||
The Boss Testing encounter ended with Lady defeated, the player and all companions alive, 0 XP awarded, no loot created, and readiness still “Needs testing.” Final vitals were:
|
||||
|
||||
| Actor | Health | Resource |
|
||||
| --- | --- | --- |
|
||||
| Player | 2,163 / 2,163 | 2,901.9 / 3,030.9 mana |
|
||||
| Rorik | 1,830.4 / 3,038.4 | 1,104.3 / 1,315.0 mana |
|
||||
| Durnik | 1,891.0 / 1,891.0 | 1,866.1 / 1,866.1 mana |
|
||||
| Caelan | 1,930.5 / 2,293.5 | 75.8 / 100 focus |
|
||||
| Veyra | 2,384.3 / 2,384.3 | 36.0 / 100 energy |
|
||||
|
||||
I inspected the pre-Vow, post-Vow, and fight-end screenshots. The first shows Lady's active Lightning Bolt bar; the second shows the cast gone; the end screen shows Lady defeated with readiness unchanged.
|
||||
|
||||
- [Boss Testing Lady Anacondra selection](../playtest-artifacts/vow-live-final/final-build-20261004-153859692/boss-testing-lady-selection.png)
|
||||
- [Vow UI binding](../playtest-artifacts/vow-live-final/final-build-20261004-153859692/vow-binding-ui.png)
|
||||
- [Live Lightning Bolt before Vow](../playtest-artifacts/vow-live-final/final-build-20261004-153859692/lightning-bolt-pre-vow-1.png)
|
||||
- [Live cast immediately after Vow](../playtest-artifacts/vow-live-final/final-build-20261004-153859692/lightning-bolt-post-vow-1.png)
|
||||
- [Fight end](../playtest-artifacts/vow-live-final/final-build-20261004-153859692/fight-end.png)
|
||||
|
||||
## Historical pre-fix diagnostic
|
||||
|
||||
The earlier final-build snapshot in `playtest-artifacts/vow-live-final/final-build-20261004-151736260` showed that an active Nature Thorns cast could appear during the Vow silence window. Its timeline recorded 53 Thorns active-cast snapshots. Parent-side source review traced this to Thorns 8148 being Nature with self/aura behavior but melee delivery and no explicit attack kind or damage class, which let the previous selector bypass silence. That pre-fix evidence is retained here for comparison; the corrected replay above covers the rebuilt assets.
|
||||
|
||||
An even earlier assertion treated `schoolLockedUntil.nature === 0` as proof that Vow failed. That was a harness false negative: Vow's aura applies the silence status and cancels the cast before its separate interrupt effect can establish the school lock. The corrected replay checks the applied status and the active-cast state through the entire duration instead.
|
||||
|
||||
## Harness and validation
|
||||
|
||||
The dedicated, bounded browser harness is [scripts/playtest-vow-live-final.cjs](../scripts/playtest-vow-live-final.cjs). It snapshots and hashes the production assets, creates a disposable isolated profile/database and Edge session, and uses ordinary UI inputs during combat. It samples the actual silence status, detects nonphysical active casts while that status is live, checks Lightning Bolt cast counts, and records a naturally scheduled Nature-cast resumption after expiry when the boss remains alive. It does not modify combat-store state.
|
||||
|
||||
`node --check scripts/playtest-vow-live-final.cjs` and `npm run release:check` passed. The browser run completed with no page errors; the only console error was the local preview's missing optional favicon. No build, pretest, full test suite, loot action, or readiness action was run by this playtest subprocess. These results cover Boss Testing only and do not claim a Wailing Caverns campaign clear.
|
||||
@@ -0,0 +1,27 @@
|
||||
# Vow of Silence and Lady Anacondra — 2026-10-04
|
||||
|
||||
## Finding
|
||||
|
||||
The full-fight record shows a successful Vow of Silence action against Lady Anacondra at `1791081712932`, but the matching cast remained active. The cast identity is `attackId: spell-9532`, `startedAt: 1791081712018`, `completesAt: 1791081713518`; the action occurred 914 ms after its start with 586 ms remaining. The result records `interruptObserved: false` and `sourceCastEndedBeforeScheduledCompletion: false`. The source cast after the action still has the same ID and timestamps. Vow resolves as an Arcane, zero-amount utility event, so that event is not evidence of a damage resistance or miss.
|
||||
|
||||
The failure was a false source immunity. The pinned AzerothCore `creature_template.sql` schema stores `CreatureImmunitiesId`, a row reference, rather than a literal mechanic bitmask. The importer had treated that negative row ID as a mask. At runtime, `applyStatus` rejects Silence and Interrupt when those names appear in `mob.mechanicImmunities`, which prevented both Vow effects from reaching the active cast.
|
||||
|
||||
## Source correction
|
||||
|
||||
The import source is AzerothCore commit `4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3`, recorded by `azerothCoreSourceLock.json`. The additional source is `data/sql/base/db_world/creature_immunities.sql`, SHA-256 `aee81a1d8b99986f8498a2b4c51b64eaf4b9095a0d1a12bbf3705d9588a90a13` (70,706 bytes, 456 rows), preserved byte-for-byte under `dungeon-pipeline/source-fixtures/azerothcore-4d9d1d4b5723e819c5c390f6ca1177283dbfb8e3/` with its lock metadata.
|
||||
|
||||
Lady Anacondra (template 3671) references immunity row `-93`. That row has `SchoolMask=0` and `MechanicsMask=16777248` (`0x01000020`); its source comment identifies Fear and Horror as `mech=0x800010`. The source mechanic mask uses the enum's bit positions, while the established imported/runtime template mask uses the adjacent lower positions. The importer normalizes the source mechanic mask one bit right to `0x00800010`, then decodes exactly `fear` and `horror`. It imports the row's SchoolMask separately. This removes the invented Silence and Interrupt immunities without weakening any immunity declared by source. For example, row `-377` explicitly lists both Silence and Interrupt and still imports both.
|
||||
|
||||
The importer only loads the FK table when the parsed template schema declares `CreatureImmunitiesId`; older schemas continue to use literal `mechanic_immune_mask` and `spell_school_immune_mask` values. A nonzero FK missing from the source table fails closed. The generated reference changes only immunity fields: 646 of 1,671 creature templates have corrected mechanic immunity fields, and 30 also receive their FK-backed school immunity fields. Other template fields and counts are unchanged.
|
||||
|
||||
## Runtime check and limits
|
||||
|
||||
Vow of Silence is modeled as an 8.4-second Silence aura followed by an Interrupt effect; the player-target aura duration is 4.2 seconds. Applying Silence cancels a live nonphysical cast. Because that clears the cast before the following Interrupt effect runs, the effect sequence does not create a separate per-school lockout for the canceled Nature cast. The active Silence status itself suppresses new spell attacks during its duration. The regression therefore checks cast cancellation and the live Silence window, not a Nature school-lock timestamp.
|
||||
|
||||
The focused regression registers Lady through template 3671, stages the exact `spell-9532` cast with its source start/completion times, verifies cancellation, and advances through the original release time while checking the cast count does not increase. Other focused cases cover a RoM physical Trample against a player target, the generated companion path against a WoW Lightning Bolt, and an NPC whose source row really grants Silence and Interrupt immunity. That immune NPC keeps its cast and receives no Silence.
|
||||
|
||||
This is a source/import correction and focused runtime verification. The recorded historical full fight was not replayed after the change, and this report does not claim a new browser fight result.
|
||||
|
||||
## Validation
|
||||
|
||||
The focused Vitest selection passed 40/40 tests across `src/game/romPriestChampionRuntime.test.ts`, `src/game/wailingCavernsParity.test.ts`, `src/game/enemyCasting.test.ts`, `src/game/enemyDamageTypes.integration.test.ts`, and `src/game/enemySmartAiRuntime.test.ts`; the final revised Vow test file was rerun alone and passed 8/8. The importer regression file `scripts/dungeon-pipeline/import-azerothcore-world.test.mjs` passed 5/5 Node tests, and `node --check scripts/dungeon-pipeline/import-azerothcore-world.mjs` passed. The app TypeScript check and final build passed after the runtime-test edits. No full test suite or all-class sweep was run.
|
||||
@@ -0,0 +1,25 @@
|
||||
# WoW Killing Spree audit — 2026-10-04
|
||||
|
||||
## Finding
|
||||
|
||||
The `combatRotation.test.ts` failure was a stale generic effect-shape expectation, not a missing player strike handler. Its representative-signature assertion required every class's chosen action to expose a non-utility effect. Killing Spree's local 51690 row is a periodic-dummy aura and target selector; the catalog therefore exposes a `class-script` utility marker for the dedicated Rogue path instead of fabricating a generic direct-damage effect. The catalog unit test already checks this marker and its 2,000-ms duration. The representative test now requires that exact shape for Killing Spree while retaining the direct-effect requirement for every other signature.
|
||||
|
||||
The audit also found a separate source-backed runtime defect: the player class script created a +1% damage aura, although Killing Spree's linked source child provides +20% damage. The runtime now applies +20% for the 2-second duration, and the Rogue mechanic regression checks the aura together with the existing ten strike events.
|
||||
|
||||
## Source evidence
|
||||
|
||||
HealerMan's generated local ability data identifies Killing Spree as talent node `talent-2076`. Rank spell 51690 has a 500-ms periodic aura, a 10-yard hostile target-selection effect, a 2-second duration, and a description whose damage token references child 61851.
|
||||
|
||||
The read-only local 3.3.5 Spell.dbc at `F:/Projects/wow-pvt-server-backups-2/build/bin/RelWithDebInfo/data/dbc/Spell.dbc` resolves child 61851 Effect 2 to AuraType 79 (`SPELL_AURA_MOD_DAMAGE_PERCENT_DONE`), 20 base points, and the all-schools mask. The local `spell_linked_spell.sql` links 51690 to 61851; `spell_script_names.sql` binds 51690 to `spell_rog_killing_spree`. The historical AzerothCore-derived [`spell_rogue.cpp`](F:/Projects/wow-pvt-server-backups-2/azerothcore-wotlk/src/server/scripts/Spells/spell_rogue.cpp) applies that buff and, on each periodic tick, chooses a valid target, teleports, and triggers the weapon-damage child. This server source corroborates the effect linkage and scripted shape; it is not claimed as pristine stock-core behavior.
|
||||
|
||||
## Player and companion boundary
|
||||
|
||||
The player `combatStore` path has a dedicated Killing Spree class-script branch. It emits five two-hand assaults and moves the player behind the last selected target. `wow335RogueMechanics.test.ts` verifies that both weapons produce ten damage events against a reachable target; it now also verifies the 20% aura modifier and duration.
|
||||
|
||||
`partyRuntime.executePartyAbility` has no Killing Spree branch. Its companion effect resolver handles other named scripts, but does not turn this utility marker into weapon strikes. Companion Killing Spree therefore remains unsupported; this pass makes no player/NPC parity claim and does not extend the companion runtime. The Combat Rogue policy naming Killing Spree does not establish that a party actor can resolve its scripted attacks.
|
||||
|
||||
The player implementation is still a simulator approximation. It resolves the five assaults immediately on cast rather than at the source's 500-ms periodic cadence, selects candidate targets deterministically rather than using the source script's random choice, and applies a local weapon formula instead of executing the complete 57841/57842 child chain. Source teleport and cast-interruption timing are not modeled per assault. This audit fixes the stale catalog-shape expectation and the independently verified buff amount; it does not certify complete Killing Spree timing, target-selection, interruption, or damage parity.
|
||||
|
||||
## Validation
|
||||
|
||||
`npx vitest run src/game/combatRotation.test.ts src/game/wow335AbilityCatalog.test.ts src/game/wow335RogueMechanics.test.ts` passed 81 tests across three files. The rotation test retains exact talent-node gating, rank/resource/cooldown checks, and a mechanism-specific class-script assertion for Killing Spree. The existing Rogue runtime test still requires all ten strikes; its added check asserts the source-backed +20% aura for 2 seconds. No broad class sweep, balance run, readiness change, loot wiring, cap change, or NPC behavior change was made.
|
||||
@@ -0,0 +1,32 @@
|
||||
# WoW Killing Spree player and companion parity — 2026-10-04
|
||||
|
||||
## Implemented behavior
|
||||
|
||||
Player and generated Rogue companions now share the timed Killing Spree window in `src/game/wow335RogueKillingSpreeRuntime.ts` and the owner-keyed scheduler in `src/game/combatStore.ts`. The local 51690 data gives the aura a 500-ms interval, a 2,000-ms duration, and `SPELL_ATTR5_EXTRA_INITIAL_PERIOD`; the modeled assaults therefore occur at cast time and at +500, +1,000, +1,500, and +2,000 ms. Each owner's window records its own target pool, weapon snapshots, and cooldown-backed ability identity. Irregular simulation advances process each due assault at its scheduled timestamp.
|
||||
|
||||
Both paths capture targets once when the cast starts. The player captures living, positioned targets in the local 10-yard area; party Rogue selection captures engaged targets in that range with line of sight. Later arrivals do not join the window. At each assault, dead, missing, stealthed, or invisible targets are pruned, then the simulator selects from the remaining list with replacement. Selection is deterministic and seeded for repeatable local combat; the historical script uses random selection.
|
||||
|
||||
The linked 61851 aura applies +20% damage for the two-second window. The simulator retains it through the scheduled final assault at exactly +2,000 ms, then removes it before the advance returns. An internal +1-ms expiration allowance preserves that event ordering without leaving the damage bonus available to subsequent actions at the boundary. Player pulses update `GameStore` relocation; companion pulses queue a one-shot combat relocation that `PartyPopulation` applies to the actor and snaps to a nearby navigation surface when one is available.
|
||||
|
||||
The companion AI can select its learned Combat Rogue action through the narrow rotation-semantics exception for local WoW progression spell 51690. Cooldowns remain attached to the casting actor. Windows are canceled with their owner's damage aura when the player dies or resets, or when a companion dies or leaves the party roster. A missing or invalid target is pruned independently and does not cancel the other actor's window.
|
||||
|
||||
## Evidence and authority
|
||||
|
||||
The static spell data inspected is the read-only snapshot at `../wow-pvt-server-backups-2/build/bin/RelWithDebInfo/data/dbc/Spell.dbc`; HealerMan's generated local catalog identifies 51690 as the Combat Rogue talent at `talent-2076`. In that DBC, 51690 has the 500-ms periodic dummy effect, 2-second duration, 10-yard hostile selection, and extra initial period. Linked spell 61851 is AuraType 79 (`SPELL_AURA_MOD_DAMAGE_PERCENT_DONE`) with 20 base points and all schools. The backup SQL row `../wow-pvt-server-backups-2/azerothcore-wotlk/data/sql/base/db_world/spell_linked_spell.sql` links 51690 to 61851; `spell_script_names.sql` binds 51690 to `spell_rog_killing_spree`.
|
||||
|
||||
The corresponding backup script is `../wow-pvt-server-backups-2/azerothcore-wotlk/src/server/scripts/Spells/spell_rogue.cpp` (Killing Spree aura and spell scripts around lines 304–420). It adds the initial spell-area targets to the aura script, applies the linked damage buff, and on each periodic callback chooses a retained target at random, removes invalid/stealth/invisible targets, casts teleport spell 57840, and triggers weapon damage spell 57841. Its target list is not expanded as later mobs arrive. `FilterTargets` rejects an empty list, vehicle use, and rooted casters, and removes existing auras marked for cast or spell-attack interruption before the spell proceeds. `HandleRemove` removes linked 61851.
|
||||
|
||||
This source is a local AzerothCore-derived server snapshot and includes fork-specific comments/behavior; it is evidence for that snapshot, not a claim about pristine stock AzerothCore or Blizzard server code. Extending the script's `ToPlayer()` teleport assumption to generated NPCs is HealerMan simulator behavior.
|
||||
|
||||
## Known simulator approximations and gaps
|
||||
|
||||
- The local simulator snapshots one hit per equipped hand per pulse and uses its existing weapon/AP estimate. It records hand-specific child identifiers 57841/57842, but it does not reproduce every triggered-child damage, proc, and combat-roll detail from the server's spell chain. Exact damage parity is not claimed.
|
||||
- Target choice is stable seeded selection instead of the script's random choice. Party target capture also restricts the pool to engaged hostiles, matching HealerMan's companion encounter policy rather than asserting server-equivalent NPC targeting.
|
||||
- The server invokes spell 57840 for teleport. The simulator approximates the result as 1.5 yards behind target orientation (or caster-facing fallback); companion landings additionally use HealerMan navigation-surface snapping. Exact teleport coordinates and collision behavior are not claimed.
|
||||
- The source script's explicit interruption handling removes pre-existing auras with cast/spell-attack interrupt flags before the cast. The available 61851 data and script do not establish a separate stun or movement cancellation rule for the two-second periodic aura, so this simulator does not invent one. The precise semantics of control effects during the active window remain unverified.
|
||||
|
||||
The earlier [Killing Spree audit](WOW_KILLING_SPREE_AUDIT_2026-10-04.md) documents the prior immediate-player-strike gap; this parity note supersedes that section with the current shared timed implementation while retaining its original audit history.
|
||||
|
||||
## Validation
|
||||
|
||||
`npx vitest run src/game/wow335RogueMechanics.test.ts src/game/partyRuntime.test.ts src/game/partyRuntimeRegistry.test.ts` passed 71 tests. Coverage includes cast-time versus later target arrival, immediate and irregularly caught-up ticks, the boosted final pulse before aura removal, player relocation, companion-owned targets/cooldowns/relocation, and player death/reset plus companion removal cleanup. Ready-five and the combined application build/release checks are left to the parent task's final integration pass.
|
||||
Reference in new issue
Block a user