MediaWiki:MaxHitCalc.js

From Roat Pkz
Revision as of 00:56, 6 August 2026 by ThroatPDiddy (talk | contribs) (add hit calc)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Note: After publishing, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer / Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Press Ctrl-F5.
// 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 5 + floor(level*0.22) -> +26 at 99 strength (125 total, per update notes "5-26 levels").

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 5 + Math.floor(level * 0.22); } }
    };

    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 (Scythe of Vitur / Sanguine Scythe)</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;">Salve</td>' +
        '<td style="padding:8px; border-bottom:1px solid #596e96; border-left:1px solid #596e96; background:#313e59;">' +
        '<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:#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). ' +
        '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] (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 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 salveMax = salve ? Math.floor(maxHit * 1.20) : maxHit;
        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)";
        } 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("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);

    update();
});