funorb

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

function fowAchTableSort() {
  var results = document.evaluate("id('Ach_OrderHeader')/a", document, null, XPathResult.ANY_TYPE, null);
  var aResult;
  if (aResult = results.iterateNext()) {
    aResult.onclick();
    return aResult;
  }
  return null;
}

function fowAchTableSortSetup() {
  var aResult = fowAchTableSort();
  if (aResult) {
    var tbl = aResult;
    while (tbl.nodeName.toLowerCase() != "table") {
      tbl = tbl.parentNode;
      if (tbl == null) return;
    }
    var p = document.createElement('p');
    p.appendChild(document.createTextNode('['));
    var btn = document.createElement('a');
    btn.setAttribute("onclick", "fowAchTableSort();return false;");
    btn.setAttribute("href", "#");
    btn.appendChild(document.createTextNode("Default order"));
    p.appendChild(btn);
    p.appendChild(document.createTextNode(']'));
    tbl.parentNode.insertBefore(p, tbl);
  }
}
addOnloadHook(fowAchTableSortSetup);

function dacalc_roll(stat1, stat2) {
    var n = parseInt(stat1);
    if (n < 0) n = 0;
    var d = n + parseInt(stat2);
    if (d <= n) return 1;
    return n / d;
}

function attackSuccess(a, d, s, h, H) {
    if (H == -1) return 1;
    if (h == -1) return 0;
    var r1 = a * attackSuccess(a, d, false, h, H-1);
    var r2 = (1-d) * attackSuccess(a, d, true, h-1, H);
    if (s) return (r1 + (1-a) * r2) / (1 - (1-a) * d);
    return (d * r1 + r2) / (1 - (1-a) * d);
}

function dacalc_simple(statname1, stat1, statname2, stat2) {return statname1 + " " + stat1 + " vs " + statname2 + " " + stat2 + ": success probability " + dacalc_roll(stat1, stat2);}

function dacalc() {
    // Attack, defence, dodge, sneak, special
    var raiderStats = document.getElementById("dacalcRaider").value.split(":");
    // Attack, defence, snare, detect, type, special
    var roomStats = document.getElementById("dacalcRoom").value.split(":");
    if (roomStats[4] == "M") {
        var res = new Array();
        var s = dacalc_roll(raiderStats[3], roomStats[3]);
        if (raiderStats[4] == "B") { // Berserker
            res.push("Berserker has First Strike");
            s = 1;
        }
        else res.push(dacalc_simple("Sneak", raiderStats[3], "detect", roomStats[3]));
        for (charge = 0; charge < 2; charge++) {
            res.push("<br /><br />");
            if (charge == 0) res.push("Advance:");
            else res.push("Charge:");
            var a = dacalc_roll(raiderStats[0] + charge, roomStats[1]);
            // There's a subtlety here: is the probability of the raider successfully defending against
            // an attack equal to dacalc_roll(raiderStats[1], roomStats[0]) or
            // 1 - dacalc_roll(roomStats[0], raiderStats[1])? This matters for 0 vs 0 and for asymmetric
            // formulae.
            var d = dacalc_roll(raiderStats[1], roomStats[0]);
            if (d == 1 && a == 0) return "Both raider and room have attack 0. Raider always wins."; // Based on Talk:Dungeon Assault

            // Handle multiple attacks / defences.
            var h = 0;
            var H = 0;
            if (roomStats[5] == "SG") H = 1;
            if (raiderStats[4] == "KN") h = 1;
            var p1 = attackSuccess(a, d, true, h, H);
            var p2 = attackSuccess(a, d, false, h, H);

            // The Ranger of the North's special ability is a bit complicated. We assume h == 0.
            if (raiderStats[4] == "RN") {
                var special_a = dacalc_roll(2 * (raiderStats[0] + charge), roomStats[1]);
                p1 = special_a * attackSuccess(a, d, false, h, H-1) + (1 - special_a) * p2;
                p2 = d * p1;
            }

            if (s != 0) {
                if (roomStats[5] == "CS") {
                    if (s == 1) res.push("<br/>Raider");
                    else res.push("<br/>If sneak successful, raider");
                    res.push(" sneaks past Corrosive Slime without the need for combat.");
                    p1 = 1;
                }
                else {
                    if (s == 1) res.push("<br/>Raider attacks first with success probability ");
                    else res.push("<br/>If sneak successful, raider attacks first with success probability ");
                    res.push(p1);
                }
            }

            if (s != 1) {
                if (s == 0) res.push("<br/>Raider defends first with success probability ");
                else res.push("<br/>Otherwise raider defends first with success probability ");
                res.push(p2);
            }

            res.push("<br/>Overall success probability: ");
            res.push(s * p1 + (1 - s) * p2);
        }
        return res.join("");
    }
    else if (roomStats[4] == "T") {
        // Special case(s)
        if (raiderStats[4] == "SS" && roomStats[5] == "Pit") return "Pit Immunity: success is certain";

        var s = dacalc_roll(raiderStats[3], roomStats[3]);
        var res = new Array();
        res.push(dacalc_simple("Sneak", raiderStats[3], "detect", roomStats[3]));
        res.push("<br/>If that fails, ");
        res.push(dacalc_simple("dodge", raiderStats[2], "snare" , roomStats[2]));
        res.push("<br/>Combined success probability: ");
        res.push(s + dacalc_roll(raiderStats[2], roomStats[2]) * (1 - s));
        return res.join("");
    }
    else if (roomStats[4] == "G") {
        // Depends on which stat the room has
        if (roomStats[3] != 0) return dacalc_simple("Sneak", raiderStats[3], "detect", roomStats[3]);
        else return dacalc_simple("Dodge", raiderStats[2], "snare" , roomStats[2]);
    }
}

function setupDACalc() {
    var thediv = document.getElementById('dacalc');
    if (thediv) {
        var dacalcHTML = new Array();
        // Version allows to check that the script has been refreshed.
        dacalcHTML.push('Dungeon Assault probability calculator, version 0.2.7T<br/>');
        dacalcHTML.push('<select id="dacalcRaider">');
        dacalcHTML.push('  <option value="1:1:1:1:">Goblin Runt</option>');
        dacalcHTML.push('  <option value="2:1:2:1:">Goblin Cleaver</option>');
        dacalcHTML.push('  <option value="2:2:1:1:">Orc Warrior</option>');
        dacalcHTML.push('  <option value="1:1:3:2:">Saurus Spawn</option>');
        dacalcHTML.push('  <option value="3:4:1:0:">Ogre Thug</option>');
        dacalcHTML.push('  <option value="1:3:3:1:SS">Saurus Slink</option>');
        dacalcHTML.push('  <option value="4:1:1:3:">Beastman</option>');
        dacalcHTML.push('  <option value="2:3:2:3:">Witch</option>');
        dacalcHTML.push('  <option value="1:3:2:4:">Dryad</option>');
        dacalcHTML.push('  <option value="4:4:2:0:">Cave Troll</option>');
        dacalcHTML.push('  <option value="1:4:5:2:">Goblin Scout</option>');
        dacalcHTML.push('  <option value="3:3:4:4:">Saurus Warrior</option>');
        dacalcHTML.push('  <option value="5:3:4:1:">Orc Shaman</option>');
        dacalcHTML.push('  <option value="6:5:1:1:">Mercenary Knight</option>');
        dacalcHTML.push('  <option value="7:1:1:5:">Orc Blademaster</option>');
        dacalcHTML.push('  <option value="3:3:6:5:">Thief</option>');
        dacalcHTML.push('  <option value="6:7:1:0:">Ogre Brute</option>');
        dacalcHTML.push('  <option value="5:5:3:3:">Priest</option>');
        dacalcHTML.push('  <option value="3:4:2:2:">Dwarf Renegade</option>');
        dacalcHTML.push('  <option value="5:7:5:0:">Minotaur</option>');
        dacalcHTML.push('  <option value="2:3:8:8:">Spy</option>');
        dacalcHTML.push('  <option value="1:6:4:6:">Enchantress</option>');
        dacalcHTML.push('  <option value="8:2:7:0:">Zealot</option>');
        dacalcHTML.push('  <option value="4:7:7:5:RN">Ranger of the North</option>');
        dacalcHTML.push('  <option value="10:0:0:0:B">Berserker</option>');
        dacalcHTML.push('  <option value="8:9:4:1:KN">Black Knight</option>');
        dacalcHTML.push('  <option value="8:5:5:9:">Dark Elf Assassin</option>');
        dacalcHTML.push('  <option value="7:6:2:2:">Sorceress</option>');
        dacalcHTML.push('  <option value="6:6:9:9:">Daemonette</option>');
        dacalcHTML.push('  <option value="10:10:10:10:">Chaos Champion</option>');
        dacalcHTML.push('</select>');

        dacalcHTML.push('<select id="dacalcRoom">');
        dacalcHTML.push('  <optgroup label="Monsters">');
        dacalcHTML.push('    <option value="1:1:1:1:M:">Giant Rats</option>');
        dacalcHTML.push('    <option value="1:1:0:2:M:">Rot Worms</option>');
        dacalcHTML.push('    <option value="2:2:1:1:M:">Troglodytes</option>');
        dacalcHTML.push('    <option value="2:1:1:3:M:">Imp</option>');
        dacalcHTML.push('    <option value="2:3:1:1:M:">Giant Snake</option>');
        dacalcHTML.push('    <option value="2:3:1:3:M:">Vampire Bats</option>');
        dacalcHTML.push('    <option value="2:3:4:1:M:">Giant Spider</option>');
        dacalcHTML.push('    <option value="2:4:0:3:M:">Skeleton Sentinels</option>');
        dacalcHTML.push('    <option value="2:2:2:5:M:">Spectre</option>');
        dacalcHTML.push('    <option value="5:4:6:2:M:">Banshee</option>');
        dacalcHTML.push('    <option value="6:6:0:2:M:">Pit Demon</option>');
        dacalcHTML.push('    <option value="6:8:0:5:M:CS">Corrosive Slime</option>');
        dacalcHTML.push('    <option value="4:8:0:7:M:SG">Stone Golem</option>');
        dacalcHTML.push('    <option value="7:7:1:1:M:">Razor Construct</option>');
        dacalcHTML.push('    <option value="5:4:4:7:M:">Vampire Lord</option>');
        dacalcHTML.push('    <option value="9:5:5:8:M:">Hell Beast</option>');
        dacalcHTML.push('    <option value="10:6:5:1:M:">Demon Lord</option>');
        dacalcHTML.push('  </optgroup>');

        dacalcHTML.push('  <optgroup label="Traps">');
        dacalcHTML.push('    <option value="0:0:1:1:T:">Snakes</option>');
        dacalcHTML.push('    <option value="0:0:1:4:T:Pit">Pit</option>');
        dacalcHTML.push('    <option value="0:0:2:2:T:">Nails</option>');
        dacalcHTML.push('    <option value="0:0:3:6:T:Pit">Hidden Pit</option>');
        dacalcHTML.push('    <option value="0:0:4:3:T:">Teleport</option>');
        dacalcHTML.push('    <option value="0:0:3:4:T:">Hidden Nails</option>');
        dacalcHTML.push('    <option value="0:0:7:3:T:">Crusher</option>');
        dacalcHTML.push('    <option value="6:0:4:6:T:">Hidden Darts</option>');
        dacalcHTML.push('    <option value="0:0:7:7:T:">Whirling Blades</option>');
        dacalcHTML.push('    <option value="0:0:4:8:T:Pit">Bottomless Pit</option>');
        dacalcHTML.push('    <option value="0:0:8:6:T:">Poisonous Gas</option>');
        dacalcHTML.push('  </optgroup>');

        dacalcHTML.push('  <optgroup label="Guardians">');
        dacalcHTML.push('    <option value="0:0:0:2:G:">Tripwire Bell</option>');
        dacalcHTML.push('    <option value="0:0:6:0:G:">Hall of Glass</option>');
        dacalcHTML.push('  </optgroup>');
        dacalcHTML.push('</select>');

        dacalcHTML.push('<br />Kills (Vampire Lord only):<br />');
        dacalcHTML.push('<input type="text" value="0" id="VL_Kills"/>');

        dacalcHTML.push('<br />Attack Decrease:');
        dacalcHTML.push('<input type="text" value="0" id="AttackDown"/>');

        dacalcHTML.push('<br />Defence Decrease:');
        dacalcHTML.push('<input type="text" value="0" id="DefenceDown"/>');

        dacalcHTML.push('<input type="button" onClick="document.getElementById(');
        dacalcHTML.push("'dacalcResult'");
        dacalcHTML.push(').innerHTML = dacalc();" value="Calculate"/>');

        dacalcHTML.push('<div id="dacalcResult">Click the button to update the result.</div>');

        thediv.innerHTML = dacalcHTML.join('');
    }
}

addOnloadHook(setupDACalc);

username = "Zehnstein";