MediaWiki:MaxHitCalc.js: Difference between revisions

From Roat Pkz
Jump to navigation Jump to search
(add hit calc)
 
(add boss scroll, use smelling salts for div ovl)
 
(2 intermediate revisions by the same user not shown)
Line 17: Line 17:
// Sanguine 2x2 max 15 -> 15-7-7, max 10 -> 10-5-5; 1x1 max 8 -> 8-4-4-2.
// Sanguine 2x2 max 15 -> 15-7-7, max 10 -> 10-5-5; 1x1 max 8 -> 8-4-4-2.
//
//
// Divine Overload estimate: assumed 5 + floor(level*0.22) -> +26 at 99 strength (125 total, per update notes "5-26 levels").
// Divine Overload estimate: assumed 11 + floor(level*0.16) (smelling salts style) -> +26 at 99 strength (125 total).


mw.hook('wikipage.content').add(function () {
mw.hook('wikipage.content').add(function () {
Line 29: Line 29:
         "super-combat":    { label: "Super Combat Potion",                  boost: function (level) { return 5 + Math.floor(level * 0.15); } },
         "super-combat":    { label: "Super Combat Potion",                  boost: function (level) { return 5 + Math.floor(level * 0.15); } },
         "cox-overload":    { label: "Smouldering Heart/CoX Overload",            boost: function (level) { return 6 + Math.floor(level * 0.16); } },
         "cox-overload":    { label: "Smouldering Heart/CoX Overload",            boost: function (level) { return 6 + Math.floor(level * 0.16); } },
         "divine-overload": { label: "Divine Overload estimate", boost: function (level) { return 5 + Math.floor(level * 0.22); } }
         "divine-overload": { label: "Divine Overload estimate", boost: function (level) { return 11 + Math.floor(level * 0.16); } }
     };
     };


Line 87: Line 87:
         '<span id="mhWeaponHint" style="display:none; color:#9aa5b5; font-size:12px;"></span></td></tr>' +
         '<span id="mhWeaponHint" style="display:none; color:#9aa5b5; font-size:12px;"></span></td></tr>' +


         '<tr id="mhSizeRow" style="display:none;"><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">NPC size (Scythe of Vitur / Sanguine Scythe)</td>' +
         '<tr id="mhSizeRow" style="display:none;"><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">NPC size</td>' +
         '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
         '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
         '<select id="mhSize">' +
         '<select id="mhSize">' +
Line 107: Line 107:
         '</select></td></tr>' +
         '</select></td></tr>' +


         '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Salve</td>' +
         '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Boss Scroll</td>' +
         '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
         '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<input type="checkbox" id="mhBossScroll"> +10% damage, applied first</td></tr>' +
        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">Salve</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
         '<input type="checkbox" id="mhSalve"> +20% vs undead, applied before Royal/Divine zone</td></tr>' +
         '<input type="checkbox" id="mhSalve"> +20% vs undead, applied before Royal/Divine zone</td></tr>' +


Line 137: Line 141:
         '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Salve Amulet (ei) vs undead (+20%)</td><td id="mhBSalve" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Salve Amulet (ei) vs undead (+20%)</td><td id="mhBSalve" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Royal/Divine zone (+10%)</td><td id="mhBZone" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Royal/Divine zone (+10%)</td><td id="mhBZone" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Boss Scroll (+10%)</td><td id="mhBBossScroll" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Scythe hits</td><td id="mhBHits" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Scythe hits</td><td id="mhBHits" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#222e45;">Total damage</td><td id="mhBTotal" style="padding:6px 12px; background:#313e59; border-left:1px solid #596e96;">&ndash;</td></tr>' +
         '<tr><td style="padding:6px 12px; background:#222e45;">Total damage</td><td id="mhBTotal" style="padding:6px 12px; background:#313e59; border-left:1px solid #596e96;">&ndash;</td></tr>' +
Line 148: Line 153:
         'Super Combat = 5 + floor(level &times; 0.15); Smouldering Heart/CoX Overload = 6 + floor(level &times; 0.16); ' +
         'Super Combat = 5 + floor(level &times; 0.15); Smouldering Heart/CoX Overload = 6 + floor(level &times; 0.16); ' +
         'Divine Overload = 5 + floor(level &times; 0.22) (estimate). ' +
         'Divine Overload = 5 + floor(level &times; 0.22) (estimate). ' +
        'Boss Scroll: +10%, applied first. ' +
         'Royal/Divine zone: +10%, applied last. ' +
         'Royal/Divine zone: +10%, applied last. ' +
         'Salve Amulet (ei): +20% vs undead, applied before the zone. ' +
         'Salve Amulet (ei): +20% vs undead, applied before the zone. ' +
         'Scythe of Vitur: 1 hit (small), [max, max/2] (medium), [max, max/2, max/4] (large), each hit rounded down. ' +
         'Scythe of Vitur: 1 hit (small), [max, max/2] (medium), [max, max/2, max/4] (large), each hit rounded down. ' +
         'Sanguine Scythe of Vitur: [max, max/2, max/2, max/4] on all NPC sizes; 2x2 is BUGGED, only 3 hits [max, max/2, max/2] (in-game verified). ' +
         'Sanguine Scythe of Vitur: [max, max/2, max/2, max/4] on all NPC sizes; 2x2 is BUGGED, only 3 hits [max, max/2, max/2]; +5% damage vs NPCs (in-game verified). ' +
         'Holy Scythe of Vitur: [max, max/2, max/4] on all NPC sizes.' +
         'Holy Scythe of Vitur: [max, max/2, max/4] on all NPC sizes.' +
         '</p>';
         '</p>';
Line 175: Line 181:
         var salve = document.getElementById("mhSalve").checked;
         var salve = document.getElementById("mhSalve").checked;
         var zone = document.getElementById("mhZone").checked;
         var zone = document.getElementById("mhZone").checked;
        var boss = document.getElementById("mhBossScroll").checked;


         var boostedStr = Math.floor(level + potionBoost);
         var boostedStr = Math.floor(level + potionBoost);
Line 180: Line 187:
         var effectiveStr = Math.floor(baseEff * prayer);
         var effectiveStr = Math.floor(baseEff * prayer);
         var maxHit = Math.floor(effectiveStr * (strBonus + 64) / 640);
         var maxHit = Math.floor(effectiveStr * (strBonus + 64) / 640);
         var salveMax = salve ? Math.floor(maxHit * 1.20) : maxHit;
        var bossMax = boss ? Math.floor(maxHit * 1.10) : maxHit; // Boss Scroll applies first
        var sangMax = (weapon === "sanguine") ? Math.floor(bossMax * 1.05) : bossMax; // sanguine +5% vs NPCs
         var salveMax = salve ? Math.floor(sangMax * 1.20) : sangMax;
         var zoneMax = zone ? Math.floor(salveMax * 1.10) : salveMax;
         var zoneMax = zone ? Math.floor(salveMax * 1.10) : salveMax;


Line 192: Line 201:
         if (weapon === "sanguine") {
         if (weapon === "sanguine") {
             hint.style.display = "";
             hint.style.display = "";
             hint.textContent = "4 hits on all NPC sizes — 2×2 is bugged (only 3 hits)";
             hint.textContent = "4 hits on all NPC sizes — 2×2 is bugged (only 3 hits) · +5% damage vs NPCs";
         } else if (weapon === "holy") {
         } else if (weapon === "holy") {
             hint.style.display = "";
             hint.style.display = "";
Line 225: Line 234:
         document.getElementById("mhBSalve").textContent = salve ? "×1.20 → " + salveMax : "off (" + maxHit + ")";
         document.getElementById("mhBSalve").textContent = salve ? "×1.20 → " + salveMax : "off (" + maxHit + ")";
         document.getElementById("mhBZone").textContent = zone ? "×1.10 → " + zoneMax : "off (" + salveMax + ")";
         document.getElementById("mhBZone").textContent = zone ? "×1.10 → " + zoneMax : "off (" + salveMax + ")";
        document.getElementById("mhBBossScroll").textContent = boss ? "×1.10 → " + bossMax : "off (" + maxHit + ")";
         document.getElementById("mhBHits").textContent = hits.join(" – ");
         document.getElementById("mhBHits").textContent = hits.join(" – ");
         document.getElementById("mhBTotal").textContent = total;
         document.getElementById("mhBTotal").textContent = total;
Line 238: Line 248:
     document.getElementById("mhSalve").addEventListener("change", update);
     document.getElementById("mhSalve").addEventListener("change", update);
     document.getElementById("mhZone").addEventListener("change", update);
     document.getElementById("mhZone").addEventListener("change", update);
    document.getElementById("mhBossScroll").addEventListener("change", update);


     update();
     update();
});
});

Latest revision as of 17:12, 15 August 2026

// Formula mirrors OSRS (https://oldschool.runescape.wiki/w/Maximum_melee_hit):
//   boostedStr    = floor(strength + potionBoost)
//   baseEff       = boostedStr + styleBonus + 8
//   effectiveStr  = floor(baseEff * prayerMultiplier)
//   maxHit        = floor(effectiveStr * (strengthBonus + 64) / 640)
//
// Scythe of Vitur (OSRS): splits by NPC size, each hit rounds down:
//   Small  -> [max]
//   Medium -> [max, floor(max/2)]
//   Large  -> [max, floor(max/2), floor(max/4)]
// Sanguine Scythe of Vitur: intended 4 hits on ALL NPC sizes —
//   2x2 is BUGGED and only deals 3 hits:
//   [max, floor(max/2), floor(max/2), floor(max/4)]  (2x2 bugged: [max, floor(max/2), floor(max/2)])
// Holy Scythe of Vitur: 3 hits on all NPC sizes:
//   [max, floor(max/2), floor(max/4)]
// Example (max 51): Sanguine 51-25-25-12, OSRS scythe 51-25-12.
// Sanguine 2x2 max 15 -> 15-7-7, max 10 -> 10-5-5; 1x1 max 8 -> 8-4-4-2.
//
// Divine Overload estimate: assumed 11 + floor(level*0.16) (smelling salts style) -> +26 at 99 strength (125 total).

mw.hook('wikipage.content').add(function () {

    if (mw.config.get('wgPageName') !== "DPS_calculator") return;
    var container = document.getElementById("maxHitCalcContainer");
    if (!container) return;

    var BOOSTS = {
        "none":            { label: "None",                                  boost: function (level) { return 0; } },
        "super-combat":    { label: "Super Combat Potion",                   boost: function (level) { return 5 + Math.floor(level * 0.15); } },
        "cox-overload":    { label: "Smouldering Heart/CoX Overload",            boost: function (level) { return 6 + Math.floor(level * 0.16); } },
        "divine-overload": { label: "Divine Overload estimate", boost: function (level) { return 11 + Math.floor(level * 0.16); } }
    };

    function scytheHits(weapon, npcSize, max) {
        switch (weapon) {
            case "scythe": // OSRS rules
                if (npcSize === "small") return [max];
                if (npcSize === "medium") return [max, Math.floor(max / 2)];
                return [max, Math.floor(max / 2), Math.floor(max / 4)];
            case "sanguine": // intended 4 hits on all sizes; 2x2 BUGGED → 3 hits
                if (npcSize === "medium") return [max, Math.floor(max / 2), Math.floor(max / 2)];
                return [max, Math.floor(max / 2), Math.floor(max / 2), Math.floor(max / 4)];
            case "holy": // 3 hits on all NPC sizes
                return [max, Math.floor(max / 2), Math.floor(max / 4)];
            default:
                return [max];
        }
    }

    container.innerHTML =
        '<table style="border-collapse:collapse; border:1px solid #596e96; background:#222e45; color:#fff;">' +
        '<tbody>' +
        '<tr><th colspan="2" style="padding:8px; text-align:left; border-bottom:1px solid #596e96; background:#222e45;">Max Hit Calculator</th></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">Strength level</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
        '<input type="number" id="mhLevel" value="99" min="1" max="99" style="width:70px;"> (1&ndash;99)</td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Prayer</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<select id="mhPrayer">' +
        '<option value="1">None</option>' +
        '<option value="1.05">Burst of Strength (&times;1.05)</option>' +
        '<option value="1.10">Superhuman Strength (&times;1.10)</option>' +
        '<option value="1.15">Ultimate Strength (&times;1.15)</option>' +
        '<option value="1.18">Chivalry (&times;1.18)</option>' +
        '<option value="1.23" selected>Piety (&times;1.23)</option>' +
        '</select></td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">Boost</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
        '<select id="mhBoost">' +
        '<option value="none">None</option>' +
        '<option value="super-combat" selected>Super Combat Potion</option>' +
        '<option value="cox-overload">Smouldering Heart/CoX Overload</option>' +
        '<option value="divine-overload">Divine Overload estimate</option>' +
        '</select></td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Weapon</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<select id="mhWeapon">' +
        '<option value="none" selected>Normal</option>' +
        '<option value="scythe">Scythe of Vitur</option>' +
        '<option value="sanguine">Sanguine Scythe of Vitur</option>' +
        '<option value="holy">Holy Scythe of Vitur</option>' +
        '</select>' +
        '<span id="mhWeaponHint" style="display:none; color:#9aa5b5; font-size:12px;"></span></td></tr>' +

        '<tr id="mhSizeRow" style="display:none;"><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">NPC size</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
        '<select id="mhSize">' +
        '<option value="small">Small (1&times;1) &ndash; 1 hit</option>' +
        '<option value="medium" selected>Medium (2&times;2) &ndash; 2 hits</option>' +
        '<option value="large">Large (3&times;3+) &ndash; 3 hits</option>' +
        '</select></td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Strength bonus</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<input type="number" id="mhStrBonus" value="0" min="0" style="width:80px;"> (visible gear stat)</td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">Attack style</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
        '<select id="mhStyle">' +
        '<option value="3" selected>Aggressive (+3)</option>' +
        '<option value="1">Controlled (+1)</option>' +
        '<option value="0">Accurate / Defensive (+0)</option>' +
        '</select></td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#222e45;">Boss Scroll</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<input type="checkbox" id="mhBossScroll"> +10% damage, applied first</td></tr>' +

        '<tr><td style="padding:8px; border-bottom:1px solid #596e96; background:#313e59;">Salve</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#222e45;">' +
        '<input type="checkbox" id="mhSalve"> +20% vs undead, applied before Royal/Divine zone</td></tr>' +

        '<tr><td style="padding:8px; background:#222e45;">In Royal/Divine zone</td>' +
        '<td style="padding:8px; border-left:1px solid #596e96; background:#313e59;">' +
        '<input type="checkbox" id="mhZone"> +10% damage, applied last</td></tr>' +
        '</tbody>' +
        '</table>' +

        '<p style="margin:14px 0 4px; font-size:16px;">' +
        'Max hit: <strong id="mhMaxHit" style="font-size:26px; color:#7ec850;">&ndash;</strong>' +
        '</p>' +
        '<div id="mhHits" style="display:none; margin-bottom:4px;"></div>' +

        '<details>' +
        '<summary style="cursor:pointer; color:#f5b942;">Calculation breakdown</summary>' +
        '<table style="border-collapse:collapse; border:1px solid #596e96; margin-top:8px; color:#fff;">' +
        '<tbody>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Strength level</td><td id="mhBLevel" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Potion boost</td><td id="mhBPotion" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Boosted strength</td><td id="mhBBoosted" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Style bonus</td><td id="mhBStyle" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Base effective strength (boosted + style + 8)</td><td id="mhBBase" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Prayer multiplier</td><td id="mhBPrayer" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Effective strength (after prayer, floored)</td><td id="mhBEffective" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Strength bonus (gear)</td><td id="mhBGear" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Max hit (base)</td><td id="mhBFinal" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Salve Amulet (ei) vs undead (+20%)</td><td id="mhBSalve" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Royal/Divine zone (+10%)</td><td id="mhBZone" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96;">Boss Scroll (+10%)</td><td id="mhBBossScroll" style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#313e59; border-bottom:1px solid #596e96;">Scythe hits</td><td id="mhBHits" style="padding:6px 12px; background:#222e45; border-bottom:1px solid #596e96; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '<tr><td style="padding:6px 12px; background:#222e45;">Total damage</td><td id="mhBTotal" style="padding:6px 12px; background:#313e59; border-left:1px solid #596e96;">&ndash;</td></tr>' +
        '</tbody>' +
        '</table>' +
        '</details>' +

        '<p style="font-size:12px; color:#9aa5b5; margin-top:12px;">' +
        'Formula (OSRS): maxHit = floor(effectiveStr &times; (strBonus + 64) / 640), ' +
        'effectiveStr = floor((floor(level + potionBoost) + styleBonus + 8) &times; prayer). ' +
        'Super Combat = 5 + floor(level &times; 0.15); Smouldering Heart/CoX Overload = 6 + floor(level &times; 0.16); ' +
        'Divine Overload = 5 + floor(level &times; 0.22) (estimate). ' +
        'Boss Scroll: +10%, applied first. ' +
        'Royal/Divine zone: +10%, applied last. ' +
        'Salve Amulet (ei): +20% vs undead, applied before the zone. ' +
        'Scythe of Vitur: 1 hit (small), [max, max/2] (medium), [max, max/2, max/4] (large), each hit rounded down. ' +
        'Sanguine Scythe of Vitur: [max, max/2, max/2, max/4] on all NPC sizes; 2x2 is BUGGED, only 3 hits [max, max/2, max/2]; +5% damage vs NPCs (in-game verified). ' +
        'Holy Scythe of Vitur: [max, max/2, max/4] on all NPC sizes.' +
        '</p>';

    function update() {
        var level = parseInt(document.getElementById("mhLevel").value, 10);
        if (isNaN(level)) level = 99;
        level = Math.min(99, Math.max(1, level));

        var prayer = parseFloat(document.getElementById("mhPrayer").value) || 1;

        var boostKey = document.getElementById("mhBoost").value;
        var potionBoost = BOOSTS[boostKey].boost(level);

        var strBonus = parseInt(document.getElementById("mhStrBonus").value, 10);
        if (isNaN(strBonus)) strBonus = 0;
        strBonus = Math.max(0, strBonus);

        var styleBonus = parseInt(document.getElementById("mhStyle").value, 10) || 0;

        var weapon = document.getElementById("mhWeapon").value;
        var npcSize = document.getElementById("mhSize").value;
        var salve = document.getElementById("mhSalve").checked;
        var zone = document.getElementById("mhZone").checked;
        var boss = document.getElementById("mhBossScroll").checked;

        var boostedStr = Math.floor(level + potionBoost);
        var baseEff = boostedStr + styleBonus + 8;
        var effectiveStr = Math.floor(baseEff * prayer);
        var maxHit = Math.floor(effectiveStr * (strBonus + 64) / 640);
        var bossMax = boss ? Math.floor(maxHit * 1.10) : maxHit; // Boss Scroll applies first
        var sangMax = (weapon === "sanguine") ? Math.floor(bossMax * 1.05) : bossMax; // sanguine +5% vs NPCs
        var salveMax = salve ? Math.floor(sangMax * 1.20) : sangMax;
        var zoneMax = zone ? Math.floor(salveMax * 1.10) : salveMax;

        var hits = scytheHits(weapon, npcSize, zoneMax);
        var total = 0;
        for (var i = 0; i < hits.length; i++) total += hits[i];

        // show/hide scythe-only UI
        document.getElementById("mhSizeRow").style.display = (weapon === "scythe" || weapon === "sanguine") ? "" : "none";
        var hint = document.getElementById("mhWeaponHint");
        if (weapon === "sanguine") {
            hint.style.display = "";
            hint.textContent = "4 hits on all NPC sizes — 2×2 is bugged (only 3 hits) · +5% damage vs NPCs";
        } else if (weapon === "holy") {
            hint.style.display = "";
            hint.textContent = "3 hits on all NPC sizes";
        } else {
            hint.style.display = "none";
        }

        document.getElementById("mhMaxHit").textContent = zoneMax;
        var hitsDiv = document.getElementById("mhHits");
        if (weapon === "none") {
            hitsDiv.style.display = "none";
        } else {
            hitsDiv.style.display = "";
            var weaponLabel;
            if (weapon === "sanguine") weaponLabel = "Sanguine Scythe of Vitur (" + npcSize.charAt(0).toUpperCase() + npcSize.slice(1) + ")";
            else if (weapon === "holy") weaponLabel = "Holy Scythe of Vitur";
            else weaponLabel = "Scythe of Vitur (" + npcSize.charAt(0).toUpperCase() + npcSize.slice(1) + ")";
            hitsDiv.innerHTML = weaponLabel + " hits: " + hits.join(" – ") +
                ' — <strong style="color:#7ec850;">Total: ' + total + '</strong>';
        }

        document.getElementById("mhBLevel").textContent = level;
        document.getElementById("mhBPotion").textContent = "+" + potionBoost + " (" + BOOSTS[boostKey].label + ")";
        document.getElementById("mhBBoosted").textContent = boostedStr;
        document.getElementById("mhBStyle").textContent = "+" + styleBonus;
        document.getElementById("mhBBase").textContent = baseEff;
        document.getElementById("mhBPrayer").textContent = "×" + prayer;
        document.getElementById("mhBEffective").textContent = effectiveStr;
        document.getElementById("mhBGear").textContent = strBonus;
        document.getElementById("mhBFinal").textContent = maxHit;
        document.getElementById("mhBSalve").textContent = salve ? "×1.20 → " + salveMax : "off (" + maxHit + ")";
        document.getElementById("mhBZone").textContent = zone ? "×1.10 → " + zoneMax : "off (" + salveMax + ")";
        document.getElementById("mhBBossScroll").textContent = boss ? "×1.10 → " + bossMax : "off (" + maxHit + ")";
        document.getElementById("mhBHits").textContent = hits.join(" – ");
        document.getElementById("mhBTotal").textContent = total;
    }

    document.getElementById("mhLevel").addEventListener("input", update);
    document.getElementById("mhPrayer").addEventListener("change", update);
    document.getElementById("mhBoost").addEventListener("change", update);
    document.getElementById("mhWeapon").addEventListener("change", update);
    document.getElementById("mhSize").addEventListener("change", update);
    document.getElementById("mhStrBonus").addEventListener("input", update);
    document.getElementById("mhStyle").addEventListener("change", update);
    document.getElementById("mhSalve").addEventListener("change", update);
    document.getElementById("mhZone").addEventListener("change", update);
    document.getElementById("mhBossScroll").addEventListener("change", update);

    update();
});