Skip to content

Crafted item fixes, configurable gems/enchants/Folio, and absolute HPS reporting - #1787

Open
DIzosimov wants to merge 4 commits into
Voulk:devfrom
DIzosimov:crafted-embellishments-and-absolute-hps
Open

Crafted item fixes, configurable gems/enchants/Folio, and absolute HPS reporting#1787
DIzosimov wants to merge 4 commits into
Voulk:devfrom
DIzosimov:crafted-embellishments-and-absolute-hps

Conversation

@DIzosimov

@DIzosimov DIzosimov commented Aug 28, 2026

Copy link
Copy Markdown

Three related pieces of work. Every behavioural default is preserved — the new settings all default to Automatic, which reproduces the previous hardcoded pick exactly.


1. Crafted items and embellishments

Embellishments were driven by three separate hardcoded lists that had drifted apart from each other and from EmbellishmentDB, so items were silently dropped rather than scored:

  • getItemEffectOptions offered 7 embellishments and excluded Finger/Neck outright, so jewellery embellishments could never be attached. Now derived from EmbellishmentDB via new applicable / slots metadata.
  • The SimC importer matched incoming spell names against an allowlist of eight names and discarded everything else — an imported item lost its embellishment and scored as a plain stat stick, with no error. Now resolves against the same DB. The two entry points also disagreed: Sunfire Silk Lining imported but couldn't be added manually; Adorned Fang was the reverse.
  • Crafted items carrying an embellishment inherently (Axe-Flingin' Bands, the World Tender's set) have no effect block in ItemDB and simmed as plain gear. Item now attaches those from EmbellishmentDB.setItems, so an ItemDB gap can't silently drop them again.
  • Multi-piece embellishment sets are counted once, only when enough pieces are worn, and consume embellishment slots correctly.
  • Embellishments with no formula are flagged unmodelled and withheld rather than silently scoring zero. A test fails if a formula lands and the flag isn't removed.

Weapons: buildNewWepCombos only emitted a one-hander when it could pair it with an offhand. With no offhand the weapon was invisible to Top Gear — and if it was the only weapon there were zero combos, zero sets, and an empty report. Unpaired one-handers are now offered alone, with report advice noting the offhand slot is scored as empty.

Embellishment cap: exceeding two embellishments makes every set fail verifySet. Correct, but silent — the item was dropped from all results, or the whole report came back empty. Now reported, warned next to the Go button when it makes a set impossible, and explained in the report.

2. Configurable gems, enchants, consumables and Omnium Folio

Previously the only player choice was the flask.

  • Omnium Folio slots 1, 4 and 5 (slots 2 and 3 have a single rune each, so aren't offered).
  • Ring and weapon enchants. The weapon choice is a real trade-off — the secondary enchants are budgeted higher than the intellect one.
  • Meta gem and stat gem pairing, chosen independently.
  • Food, weapon oil and Vantus Rune, which were applied unconditionally with no way to disable them.

Only options with real modelled values are offered. There is no food or enchant data beyond a single hardcoded entry per slot, so those dropdowns are deliberately limited rather than invented.

Bug fixed: the weapon enchant read bonus_stats.mastery while assigning to bonus_stats.haste for Discipline Priest and Restoration Druid, discarding their accumulated haste and replacing it with their mastery.

Bug fixed: settings are grouped by category, but the panel rendered a hardcoded category list — a setting in a new category was stored, wired to the engine, and never drawn, with no error anywhere. The list now lives in one exported place, and SettingsCategories.test.js fails if any category with settings is missing from it, or if any setting lacks a title/tooltip. That check caught a pre-existing empty tooltip on enchantItems.

3. Absolute HPS, Fine Tuning and joint optimisation

hardScore is an intellect-equivalent ranking number, so the report could only show relative differences — and the alternatives list was labelling a hardScore delta as "HPS".

  • Sets evaluated through a cast model or ramp sim now carry setHPS, shown on the stat panel with an upgrade percentage over currently-equipped gear, and per alternative alongside the healing and percentage given up.
  • The stat-weight path deliberately reports nothing rather than a fabricated number: baseHPS there is a hardcoded placeholder, and that path pre-applies raid buffs the cast models also apply internally.
  • The panel no longer shows +0.00% when the best set is simply the player's current gear, which read like the comparison had failed.

Fine Tuning tab prices every gem, enchant, flask and Folio rune against the player's equipped gear by re-running the set with only that setting changed — so the numbers include diminishing returns and the cast model rather than being flat stat-weight estimates. The current pick is identified by what the setting resolved to, since settings normally read Automatic and would otherwise never match an option. Groups where every option prices identically are flagged as unmodelled instead of shown as a real tie (several Folio runes have empty formulas).

Joint optimisation (off by default, since it changes which set wins): the axes interact through diminishing returns, so the best gems depend on the gear and a set ranked second with default gems can win once optimally gemmed. The full cross product is ~27k configurations per set, so this walks coordinate ascent at ~95 evaluations per set instead. Validated against brute force on a real set — identical result, 0.0000% gap. Leading sets are each optimised and re-ranked, then alternatives are re-scored under the winning configuration so they stay comparable.

Also

Two latent crashes where getSetting returns 0 for a missing setting and the result was used as a string (darkmoonHuntStat, flaskChoice — the latter would take out an entire Top Gear run on stale settings). createTopGearWorker moved to its own module so TopGearEngineShared is importable from tests without tripping over import.meta.

Testing

48 suites / 308 tests passing, production build compiles. Adds ~120 tests across six new suites covering the embellishment DB contract, the SimC import path, weapon combinations, the absolute HPS pipeline, settings reachability, and the optimiser (including the brute-force validation).

Verified after merging current dev, not just before.

DIzosimov and others added 3 commits August 28, 2026 12:31
Embellishments were driven by three separate hardcoded lists that had drifted
apart from each other and from EmbellishmentDB, so items were silently dropped:

- getItemEffectOptions offered 7 embellishments and excluded jewellery outright.
  It now derives options from EmbellishmentDB via new applicable/slots metadata.
- The SimC importer matched incoming spell names against an allowlist of eight
  names and discarded everything else, so an imported item lost its embellishment
  and scored as a plain stat stick. It now resolves against the same DB.
- Crafted items that carry an embellishment inherently (Axe-Flingin' Bands, the
  World Tender's set) had no effect block in ItemDB and simmed as plain gear.
  Item now attaches those from EmbellishmentDB.setItems.
- Multi-piece embellishment sets are counted once, only when enough pieces are
  worn, and respect the two embellishment cap.
- Embellishments with no formula are flagged unmodelled and withheld from the
  dropdown rather than silently scoring zero.
- The crafted stat picker is hidden on items whose secondaries are already fixed,
  where choosing stats did nothing.

Weapons: buildNewWepCombos only emitted a one hander when it could pair it with
an offhand. With no offhand the weapon was invisible to Top Gear, and if it was
the only weapon there were zero combos, zero sets and an empty report. Unpaired
one handers are now offered alone, with report advice noting the empty offhand.

Embellishment cap: exceeding two embellishments made every set fail verification.
Top Gear returned null with no explanation. It now reports the error, warns next
to the Go button when the cap makes a set impossible, and explains in the report
when a selected embellished item could not be used.

Absolute HPS: hardScore is an intellect-equivalent ranking number, so the report
could only show relative differences. Sets evaluated through a cast model or ramp
sim now carry setHPS, surfaced on the stat panel with an upgrade percentage over
currently equipped gear, and per alternative alongside the healing and percentage
given up. The stat weight path reports nothing rather than a fabricated number.

Also fixes two latent crashes where getSetting returns 0 for a missing setting
and the result was used as a string (darkmoonHuntStat, flaskChoice), and moves
createTopGearWorker into its own module so TopGearEngineShared is importable
from tests without tripping over import.meta.

45 suites / 252 tests passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5STi454aLVN1cAsYyba3J
# Conflicts:
#	src/Databases/EmbellishmentDB.ts
#	src/General/Modules/TopGear/Engine/TopGearEngine.ts
…nd optimise them jointly

Previously the only thing a player could choose was their flask. Gems, enchants, the Folio runes and the rest of
the consumables were hardcoded per spec, so there was no way to try a different stat setup.

Configurable now, each defaulting to "Automatic" which reproduces the previous hardcoded pick exactly:

- Omnium Folio slots 1, 4 and 5. Slots 2 and 3 have a single rune each so they aren't offered.
- Ring and weapon enchants. The weapon choice is a real trade off, since the secondary enchants are budgeted
  higher than the intellect one.
- Meta gem and the stat gem pairing, chosen independently - the current tier has a complete matrix of each
  secondary as the major stat paired with each other as the minor.
- Food, weapon oil and Vantus Rune, which were applied unconditionally with no way to turn them off.

Only options with real modelled values are offered. There is no food or enchant data beyond a single hardcoded
entry per slot, so those dropdowns are deliberately limited rather than invented.

Fixes a bug in the weapon enchant where Discipline Priest and Restoration Druid read bonus_stats.mastery while
assigning to bonus_stats.haste, discarding their accumulated haste and replacing it with their mastery.

Settings are grouped by category but the panel rendered a hardcoded category list, so a setting in a new category
was stored, wired to the engine, and never drawn - with no error anywhere. The list now lives in one exported
place and SettingsCategories.test.js fails if any category with settings is missing from it, or if any setting
lacks a title and tooltip.

Fine Tuning tab: prices every gem, enchant, flask and Folio rune against the player's currently equipped gear by
re-running the set with only that setting changed, so the numbers include diminishing returns and the cast model
rather than being flat stat weight estimates. The current pick is identified by what the setting actually
resolved to, since settings normally read "Automatic" and would otherwise never match an option. Groups where
every option prices identically are flagged as unmodelled instead of being shown as a real tie - several Folio
runes have empty formulas.

Joint optimisation (off by default): the axes interact through diminishing returns, so the best gems depend on
the gear and a set ranked second with default gems can win once optimally gemmed. The full cross product is
~27k configurations per set, so this walks coordinate ascent instead at ~95 evaluations per set. Validated
against brute force on a real set: identical result, 0.0000% gap. The leading sets are each optimised and
re-ranked, then every alternative is re-scored under the winning configuration so they stay comparable.

Also stops the stat panel showing "+0.00%" when the best set is simply the player's current gear, which read
like the comparison had failed.

48 suites / 308 tests passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5STi454aLVN1cAsYyba3J
@DIzosimov DIzosimov changed the title Fix crafted item / embellishment handling and report absolute HPS Crafted item fixes, configurable gems/enchants/Folio, and absolute HPS reporting Aug 28, 2026
…Tuning figures don't add up

Mastery effectiveness was hardcoded at 0.9 inside scoreEvokerSet, overwriting whatever was passed in. Preservation
mastery scales with how injured the target is, so its real effectiveness varies a lot by content - Resto Shaman
already exposed this as a setting and Evoker now does too. Absent settings keep the previous 0.9 so existing
results are unchanged.

The settings panel writes number inputs back as strings (e.target.value), so this reads the value with Number()
rather than a typeof check. A strict typeof === "number" check worked on the reducer's initial value and then
silently fell back to the default the moment the player edited the box, which looked exactly like the setting
doing nothing. The Resto Shaman equivalent avoids this only because it divides by 100 and gets coerced. Test
covers the string case specifically, since that is the shape the UI actually produces.

Also notes on the Fine Tuning tab that its figures are single-axis and don't sum. Stats share diminishing returns,
so two options that each look like a gain can be competing for the same headroom, and the best row in a card is
not always part of the best overall setup - the joint optimiser can and does disagree with it. Measured on a real
character the table recommends crit/haste gems while the optimiser picks mastery/crit, and the optimiser is right
because it accounts for the crit already taken by the flask, ring enchant and Folio rune.

48 suites / 313 tests passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5STi454aLVN1cAsYyba3J
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant