From 7ce28410fca8c4e94f8c4fa2a916630c1652cd51 Mon Sep 17 00:00:00 2001 From: Jan Bader Date: Tue, 16 Jun 2026 20:43:22 +0200 Subject: [PATCH] Remove direct upgrade recommendations --- README.md | 20 ++++++++------------ app.js | 41 +++-------------------------------------- index.html | 4 ---- styles.css | 2 +- 4 files changed, 12 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 1e6f2d7..6406fe9 100644 --- a/README.md +++ b/README.md @@ -54,20 +54,14 @@ Mount and pet base stats remain editable, and each has separate damage and healt ## Optimizer goals -The app lets you enter the current state of all equipment and then recommends: +The app lets you enter the current state of all equipment and then evaluates: -1. **What to increase next** - - Prioritizes effects by actual DPS gain for the selected combat style. - - Accounts for each effect's remaining room to grow before cap. - - Shows the DPS gain from the next `+1%` and from upgrading to cap. - - Crit damage has no DPS value until crit chance is above `0%`. - -2. **What is best to sacrifice instead** +1. **What is best to sacrifice instead** - Scores every equipped piece from its base stat and effects. - Identifies the lowest-value pieces as likely sacrifice candidates. - - Explains why a piece is weak, such as missing effects, low base stat, or low-impact effects. + - Explains why a piece is weak, such as low base stat or low-impact effects. -3. **Overall build summary** +2. **Overall build summary** - Totals base damage and health. - Totals effect percentages across all items, mount, and pets. - Shows calculated DPS and estimated regen to compare save slots. @@ -80,12 +74,14 @@ The app calculates DPS from entered base damage and offensive effects: DPS = base damage * (1 + damage%) * (1 + selected style damage%) - * (1 + attack speed%) + * ((1 + attack speed%) / 2) * (1 + double chance%) * (1 + crit chance% * crit damage%) * skill cooldown multiplier, only for Skill style ``` +The attack speed term assumes the base `100%` attack speed is about one hit every two seconds, or `0.5` hits per second. + The selected combat style controls which specialized damage bonus is used: - Melee uses melee damage. @@ -94,7 +90,7 @@ The selected combat style controls which specialized damage bonus is used: All additive bonuses are evaluated against the current total. For example, if the build already has `+100% melee damage`, adding another `+50% melee damage` increases the melee multiplier from `2.0x` to `2.5x`, which is an actual `+25%` DPS increase rather than `+50%`. -Each item effect row displays its actual current DPS contribution and the marginal DPS gain from the next `+1%` upgrade. +Each item effect row displays its actual current DPS contribution. Direct effect upgrading is not modeled because players roll replacement items rather than adjust an existing effect in-place. The effect totals panel also shows what adding one more maximum-roll effect would do right now. For example, if the build already has `+100% melee damage`, another max `+50% melee damage` changes the multiplier from `2.0x` to `2.5x`, so it displays `+25% DPS`. diff --git a/app.js b/app.js index 730a3f2..702228a 100644 --- a/app.js +++ b/app.js @@ -236,7 +236,6 @@ function updateAnalysis() { updateEffectImpactHints(totals, dps); renderEffectTotals(totals, dps, survivability); - renderUpgrades(profile, totals, dps); renderSacrifices(pieceScores); saveDraft(); } @@ -263,7 +262,7 @@ function calculateDamageDetails(totals, combatStyle = "melee") { const globalDamage = 1 + effects.damage / 100; const styleDamage = 1 + getStyleDamageBonus(effects, combatStyle) / 100; const singleHit = baseDamage * globalDamage * styleDamage; - const attackSpeed = 1 + effects.attackSpeed / 100; + const attacksPerSecond = (1 + effects.attackSpeed / 100) / 2; const doubleHit = 1 + effects.doubleChance / 100; const critChance = effects.critChance / 100; const critDamage = effects.critDamage / 100; @@ -273,7 +272,7 @@ function calculateDamageDetails(totals, combatStyle = "melee") { return { singleHit, critHit, - dps: singleHit * attackSpeed * doubleHit * crit * cooldown, + dps: singleHit * attacksPerSecond * doubleHit * crit * cooldown, }; } @@ -404,45 +403,11 @@ function updateEffectImpactHints(totals, currentDps) { const current = clampEffectValue(effect.type, Number(effect.value)); const withoutThis = calculateDps(cloneTotalsWithEffectDelta(totals, effect.type, -current), state.combatStyle); const currentGain = percentChange(withoutThis, currentDps); - const remaining = Math.max(0, def.cap - current); - const plusOne = Math.min(1, remaining); - const plusOneGain = plusOne > 0 - ? percentChange(currentDps, calculateDps(cloneTotalsWithEffectDelta(totals, effect.type, plusOne), state.combatStyle)) - : 0; - hint.textContent = `Cap: ${def.cap}%. Actual now: ${fmt(currentGain)}% DPS. Next +${fmt(plusOne)}%: ${fmt(plusOneGain)}% DPS.`; + hint.textContent = `Actual: ${fmt(currentGain)}% DPS`; }); }); } -function renderUpgrades(profile, totals, currentDps) { - const upgrades = []; - for (const piece of state.pieces) { - for (const effect of piece.effects) { - if (!effect.type) continue; - const def = effectById(effect.type); - const current = clampEffectValue(effect.type, Number(effect.value)); - const remaining = def.cap - current; - if (remaining <= 0) continue; - const plusOne = Math.min(1, remaining); - const onePointDps = calculateDps(cloneTotalsWithEffectDelta(totals, effect.type, plusOne), state.combatStyle); - const capDps = calculateDps(cloneTotalsWithEffectDelta(totals, effect.type, remaining), state.combatStyle); - const onePointGain = percentChange(currentDps, onePointDps); - const capGain = percentChange(currentDps, capDps); - const fallback = profile.weights[effect.type] * 0.001; - const efficiency = capGain || onePointGain || fallback; - upgrades.push({ piece, def, current, remaining, efficiency, onePointGain, capGain }); - } - } - - upgrades.sort((a, b) => b.efficiency - a.efficiency); - const count = state.recommendationCount; - $("#upgradeList").innerHTML = upgrades.slice(0, count).map((item) => ` -
  • ${item.def.label} on ${escapeHtml(item.piece.name || item.piece.title)} - ${fmt(item.current)}% now, ${fmt(item.remaining)}% room to cap. Next +1% gives ${fmt(item.onePointGain)}% DPS; to cap gives ${fmt(item.capGain)}% DPS. -
  • - `).join("") || "
  • No upgradeable effects entered yet.
  • "; -} - function renderSacrifices(pieceScores) { const weakest = pieceScores .filter(({ piece }) => !piece.noEffects) diff --git a/index.html b/index.html index b1323af..03405cd 100644 --- a/index.html +++ b/index.html @@ -78,10 +78,6 @@
    -
    -

    Best upgrades

    -
      -

      Best sacrifice candidates

        diff --git a/styles.css b/styles.css index a04f4b7..e4913b5 100644 --- a/styles.css +++ b/styles.css @@ -175,7 +175,7 @@ h3 { margin-bottom: 0; } .metric strong { font-size: 1.8rem; } .metric small { display: block; margin-top: 0.4rem; color: var(--muted); line-height: 1.35; } -.results { grid-template-columns: repeat(2, minmax(0, 1fr)); margin-bottom: 1rem; } +.results { grid-template-columns: 1fr; margin-bottom: 1rem; } .recommendation-list { display: grid; gap: 0.75rem; padding-left: 1.5rem; } .recommendation-list li { padding-left: 0.25rem; } .recommendation-list strong { color: var(--accent); }