Crafted item fixes, configurable gems/enchants/Folio, and absolute HPS reporting - #1787
Open
DIzosimov wants to merge 4 commits into
Open
Crafted item fixes, configurable gems/enchants/Folio, and absolute HPS reporting#1787DIzosimov wants to merge 4 commits into
DIzosimov wants to merge 4 commits into
Conversation
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
…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
This was referenced Aug 28, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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:getItemEffectOptionsoffered 7 embellishments and excludedFinger/Neckoutright, so jewellery embellishments could never be attached. Now derived fromEmbellishmentDBvia newapplicable/slotsmetadata.Sunfire Silk Liningimported but couldn't be added manually;Adorned Fangwas the reverse.effectblock inItemDBand simmed as plain gear.Itemnow attaches those fromEmbellishmentDB.setItems, so an ItemDB gap can't silently drop them again.unmodelledand withheld rather than silently scoring zero. A test fails if a formula lands and the flag isn't removed.Weapons:
buildNewWepCombosonly 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.
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.masterywhile assigning tobonus_stats.hastefor 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.jsfails 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 onenchantItems.3. Absolute HPS, Fine Tuning and joint optimisation
hardScoreis an intellect-equivalent ranking number, so the report could only show relative differences — and the alternatives list was labelling ahardScoredelta as "HPS".setHPS, shown on the stat panel with an upgrade percentage over currently-equipped gear, and per alternative alongside the healing and percentage given up.baseHPSthere is a hardcoded placeholder, and that path pre-applies raid buffs the cast models also apply internally.+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
Automaticand 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
getSettingreturns0for 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).createTopGearWorkermoved to its own module soTopGearEngineSharedis importable from tests without tripping overimport.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.