infinite retail smasher

plays BvS infinite retail (poorly)

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        infinite retail smasher
// @namespace   [email protected]
// @description plays BvS infinite retail (poorly)
// @include     http://*animecubed.com/billy/bvs/shop-retail.html
// @include     https://*animecubedgaming.com/billy/bvs/shop-retail.html
// @version     3.5
// @grant       none
// ==/UserScript==

// returns true if on the main page and an appropriate level is checked
var preflightCheck = function() {
    // Check that infinite is actually unlocked
    var infinite = document.querySelector('#diff9');
    var multiplier = document.querySelector('[name="rtmultiplier"]');
    if (multiplier) {
        multiplier.value = 5;
    }
    if (infinite) {
        infinite.checked = true;
        var difficultyinput = document.querySelector('[name=bfrilvl]');
        if (multiplier) {
            multiplier.value = 1;
        }
        if (difficultyinput.value >= 11) {
            difficultyinput.value = 11;
            if (multiplier) {
                multiplier.value = 5;
            }
        }
        return true;
    } else {
        var tier8 = document.querySelector('#diff8');
        if (tier8) {
            tier8.checked = true;
            return true;
        } else {
            var tier7 = document.querySelector('#diff7');
            if (tier7) {
                tier7.checked = true;
                return true;
            }
        }
    }
    return false;
};

// returns false if recommended actions are set; otherwise
// selects recommended actions and returns true.
var setActions = function() {
    if (!document.suppressrt) return;
    var barge = document.querySelector('#supK1');
    var deathstare = document.querySelector('#supN6');
    var newrelease = document.querySelector('#supM1');
    var boot = document.querySelector('#supI');
    var bogo = document.querySelector('#supH1');
    var entice = document.querySelector('#supJ1');
    var waifu = document.querySelector('#supV2');
    var upsell = document.querySelector('#supV4');
    var hey = document.querySelector('#supV5');
    var trapdoor = document.querySelector('#supK6');
    var hype = document.querySelector('#supK9');
    var voice = document.querySelector('#supK7');
    var submanager = document.querySelector('select[name="pick_subm"]');
    var changed = false;
    if (!barge.checked) { barge.checked = true; changed = true; }
    if (!deathstare.checked) { deathstare.checked = true; changed = true; }
    if (newrelease.checked) { newrelease.checked = false; changed = true; }
    if (boot.checked) { boot.checked = false; changed = true; }
    if (!bogo.checked) { bogo.checked = true; changed = true; }
    if (!entice.checked) { entice.checked = true; changed = true; }
    if (waifu.checked) { waifu.checked = false; changed = true; }
    if (!upsell.checked) { upsell.checked = true; changed = true; }
    if (hey.checked) { hey.checked = false; changed = true; }
    if (!hype.checked) { hype.checked = true; changed = true; }
    if (trapdoor && trapdoor.checked) { trapdoor.checked = false; changed = true; }
    if (voice && voice.checked) { voice.checked = false; changed = true;}
    if (submanager.value != 3) { submanager.value = 3; changed = true; }
    if (changed) { console.log('Not using recommended actions!'); }
    return changed;
};

var Customer = function Customer(name, splusl, bounty, RPT, status, select) {
    this.isEmpty = !name;
    if (this.isEmpty) return;
    this.name = name;
    this.splusl = splusl;
    this.bounty = bounty;
    this.RPT = RPT;
    this.status = status;

    // function to select this customer
    this.select = select;
};

var hypeDamage = function(customer) {
    if (customer.isEmpty) {
        return 0;
    }
    // TODO: improve this heuristic?
    if (customer.status == 'Hyped') {
        // TODO: this should probably just be return normalDamage(customer, 4)
        if (customer.splusl > 6) {
            return 4 * customer.RPT / 2;
        } else if (customer.splusl > 2) {
            return (customer.splusl) * customer.RPT / 2;
        } else {
            return 0;
        }
    }
    if (customer.splusl <= 6) {
        return (customer.splusl + 1) * customer.RPT;
    }
    var damage = (customer.splusl + 6) / 2;
    if (customer.status == 'Annoying') {
        return damage * (customer.RPT-1) + customer.splusl + 1 ;
    }
    return damage * customer.RPT;
};

var normalDamage = function(customer, amount) {
    if (customer.isEmpty) {
        return 0;
    }

    if (customer.status == 'Hyped') {
        // TODO: improve this heuristic?
        if (customer.splusl > amount + 2) {
            return (amount) * customer.RPT / 2;
        } else if (customer.splusl > 2) {
            return (customer.splusl) * customer.RPT / 2;
        } else {
            return 0;
        }
    } else {
        if (amount >= customer.splusl) {
            amount = customer.splusl;
        } else if (amount >= customer.splusl - 3) {
            amount = customer.splusl - 3;
        } else if (amount >= customer.splusl - 6) {
            amount = customer.splusl - 6;
        }
        if (customer.splusl > amount) {
            return amount * customer.RPT;
        } else {
            return (customer.splusl + 1) * customer.RPT;
        }
    }
};

var customerRPT = {
    // These are my current guesses on average rage/turn
    'Fanboy': 2/9,
    'Fangirl': 2/3,

    'Bad Haggler': 1/2,
    'Buffet': 1/3,
    'Ghost Michelle': 4/3,
    'Hater': 1,
    'One-Up': 2/3,
    'Shipper': 1/2,
    'Skimmer': 1/3,
    'Soft Talker': 1,
    'Wanderer': 1/4,
    'Umm': 1,

    'Clumsy Cosplayer': 3/4,
    'Model': 2/3,

    'Cardrat': 1,
    'Bender': 1,
    'Cropduster': 5000,
    'Fighter': 3/2,

    'Childswarm': 2/3,
    'MeowMeow': 1,  // 100% act
    // Other customers omitted for irrelevance in infinite
};

var parseCustomer = function(text, select) {
    var empty = /Empty/.test(text);
    if (empty) { return new Customer(); }

    var loaf = /Loaf: ([0-9]+)/.exec(text);
    var stingy = /S.: ([0-9]+)/.exec(text);
    var annoying = /Annoying/.test(text);
    var hyped = /Hyped/.test(text);
    var stinky = /Stinky/.test(text);
    var bounty = /\(\+([0-9]+)\)/.exec(text);

    var splusl = 0;
    if (loaf) splusl += parseInt(loaf[1],10);
    if (stingy) splusl += parseInt(stingy[1],10);

    var customerType =
        /(Fanboy|Fangirl|Bad Haggler|Buffet|Ghost Michelle|Hater|One-Up|Shipper|Skimmer|Soft Talker|Wanderer|Umm|Clumsy Cosplayer|Model|Cardrat|Bender|Cropduster|Fighter|Childswarm|MeowMeow|Tsk)/.exec(text);
    if (!customerType) {
        // console.log('Assuming that customer is shadow player...')
        customerType = ['', 'Shadow Player'];
    }
    var RPT = customerRPT[customerType[1]];
    if (customerType[1] == 'Tsk') {
        var dirtyLevel = /Dirty Store \(Level ([0-9]+)\)/.exec(document.body.textContent);
        if (dirtyLevel) {
            RPT = parseInt(dirtyLevel[1],10) * 0.4;
        } else {
            RPT = 0;
        }
    } else if (customerType[1] == 'Shadow Player') {
        RPT = -1/3;
   }
    if (annoying) {
        RPT += 1;
    }
    return new Customer(customerType[1], splusl, bounty ? bounty[1] : 0, RPT, hyped ? 'Hyped' : stinky ? 'Stinky' : annoying ? 'Annoying' : '', select);
};

var storeParser = function() {
    // Always answer the phone immediately; suboptimal, but who cares
    var phone = document.querySelector('input[value="PHONE"]');
    if (phone) {
        phone.checked = true;
        return;
    }

    // Is the store empty?
    var grumble = document.querySelector('input[value="S"]');
    if (grumble) {
        var opm = document.querySelector('input[value="F"]');
        if (opm) {
            opm.checked = true;
        } else {
            grumble.checked = true;
        }
        return;
    }



    var store = document.querySelectorAll('table[cellpadding="0"]')[4];
    var storeTable = store.children[0];
    var rows = storeTable.children;
    var topRow = rows[0].children;
    var bottomRow = rows[1].children;

    var parsedTopRow = [];
    var parsedBottomRow = [];
    // Now we try to parse the store >_>
    for (var col = 0; col < 7; col++) {
        var thingy = topRow[col].querySelector('span[onclick]');
        if (col === 0 || col == 3 || col == 6) {
            parsedTopRow.push(new Customer());
        } else { parsedTopRow.push(parseCustomer(topRow[col].textContent, thingy ? thingy.onclick : null)); }

        thingy = bottomRow[col].querySelector('span[onclick]');
        if (col == 2 || col == 4 || col == 5) {
            parsedBottomRow.push(new Customer());
        } else { parsedBottomRow.push(parseCustomer(bottomRow[col].textContent, thingy ? thingy.onclick : null)); }
    }
    var highestHypeDamage = 0;
    var selectHype = function() { alert('Something has gone wrong(selectHype)'); };
    // console.log(parsedTopRow);
    // console.log(parsedBottomRow);
    for (var i = 0; i < 7; ++i) {
        // console.log(parsedTopRow[i]);
        if (hypeDamage(parsedTopRow[i]) > highestHypeDamage) {
            highestHypeDamage = hypeDamage(parsedTopRow[i]);
            selectHype = parsedTopRow[i].select || selectHype;
        }
        // console.log(parsedBottomRow[i]);
        if (hypeDamage(parsedBottomRow[i]) > highestHypeDamage) {
            highestHypeDamage = hypeDamage(parsedBottomRow[i]);
            selectHype = parsedBottomRow[i].select || selectHype;
        }
    }
    console.log('Best hype damage: ' + highestHypeDamage);
    if (highestHypeDamage <= 0) {
        // Nothing for us to do here
        // Select any customer, nobody cares
        document.querySelector('select[name="actiontarget"]').value = 'custid1';
        fallback();
        return;
    }

    var highestNormalDamage = 0;
    var selectNormal = function() { alert('Something has gone wrong(selectNormal)'); };
    for (i = 0; i < 7; ++i) {
        if (normalDamage(parsedTopRow[i], 5) > highestNormalDamage) {
            highestNormalDamage = normalDamage(parsedTopRow[i], 5);
            selectNormal = parsedTopRow[i].select || selectNormal;
        }
        if (normalDamage(parsedBottomRow[i], 5) > highestNormalDamage) {
            highestNormalDamage = normalDamage(parsedBottomRow[i],5);
            selectNormal = parsedBottomRow[i].select || selectNormal;
        }
    }
    console.log('Best Savings Punch (5X) damage: ' + highestNormalDamage);

    var leftSide = [parsedTopRow[1], parsedTopRow[2], parsedBottomRow[0], parsedBottomRow[1]];
    var leftDamage = leftSide.map(function(c) { return normalDamage(c,3); }).reduce(function(s,e) { return s+e; });
    console.log ('Left Pitch damage: ' + leftDamage);

    var rightSide = [parsedTopRow[4], parsedTopRow[5], parsedBottomRow[3], parsedBottomRow[6]];
    var rightDamage = rightSide.map(function(c) { return normalDamage(c,3); }).reduce(function(s,e) { return s+e; });
    console.log ('Right Pitch damage: ' + rightDamage);

    var selectPitch = function() { alert ('Something has gone wrong(selectPitch)'); };
    if (leftDamage > rightDamage) {
        if (leftDamage <= 0) {
            selectPitch = leftSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; }) || rightSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; });
        } else {
            selectPitch = leftSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; }) || selectPitch;
        }
    } else {
        selectPitch = rightSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; }) || selectPitch;
    }

    var ckDamageTopRow = parsedTopRow.map(function(c) { return normalDamage(c,4); });
    var ckDamageBottomRow = parsedBottomRow.map(function(c) { return normalDamage(c,4); });

    var figuresDamage = ckDamageTopRow[1] + ckDamageTopRow[2];
    console.log('Figures Coupon Kick damage: ' + figuresDamage);

    var mangaDamage = ckDamageBottomRow[0] + ckDamageBottomRow[1];
    console.log('Manga Coupon Kick damage: ' + mangaDamage);

    var keyChainsDamage = ckDamageTopRow[4] + ckDamageTopRow[5];
    console.log('Key Chains Coupon Kick damage: ' + keyChainsDamage);

    var entrywayDamage = ckDamageBottomRow[6];
    console.log('Entryway Coupon Kick damage: ' + entrywayDamage);

    var registerDamage = ckDamageBottomRow[3];
    console.log('Register Coupon Kick damage: ' + registerDamage);

    var maxCkDamage = Math.max(figuresDamage, mangaDamage, keyChainsDamage, entrywayDamage, registerDamage);

    var selectCk = function() { alert ('Something has gone wrong(selectCk)'); };
    if (maxCkDamage <= 0) {
        selectCk = function() {
            leftSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; }) || rightSide.map(function(c) { return c.select; }).reduce(function(s,e) { return s || e; });
        };
    }

    if (figuresDamage == maxCkDamage) {
        selectCk = parsedTopRow[1].select || parsedTopRow[2].select || selectCk;
    } else if (mangaDamage == maxCkDamage) {
        selectCk = parsedBottomRow[0].select || parsedBottomRow[1].select || selectCk;
    } else if (keyChainsDamage == maxCkDamage) {
        selectCk = parsedTopRow[4].select || parsedTopRow[5].select || selectCk;
    } else if (entrywayDamage == maxCkDamage) {
        selectCk = parsedBottomRow[6].select || selectCk;
    } else {
        selectCk = parsedBottomRow[3].select || selectCk;
    }


    var maxPitchDamage = Math.max(leftDamage, rightDamage);
    var damages = [highestHypeDamage, highestNormalDamage, maxCkDamage, maxPitchDamage];
    console.log(damages);
    damages.sort(function(a, b) { return b - a; });
    var maxDamage = damages[0];
    console.log(damages);

    var triedHype = false;
    var triedPitch = false;
    var triedCk = false;
    var triedNormal = false;
    while (damages.length) {
        console.log(damages);
        if (damages[0] <= 0) {
            break;  // Too lazy to write proper fallback code; just check out the good customer
        }
        if ((!triedHype) && (highestHypeDamage == damages[0])) {
            if (tryHype()) {
                console.log('Recommended action: Hype');
                selectHype();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryFreeShuffle()) {
                console.log('Recommended action: shuffle');
                // TODO: select target better
                selectHype();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryThinkFast()) {
                console.log('Recommended action: Think Fast');
                return;
            } else {
                // Since there's no way to get to hype, throw it away and try the rest
                console.log('Giving up on Hype');
                triedHype = true;
                damages.shift();
                continue;
            }
        } else if ((!triedPitch) && (maxPitchDamage == damages[0])) {
            if (tryPitch()) {
                console.log('Recommended action: Pitch');
                selectPitch();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryFreeShuffle()) {
                console.log('Recommended action: shuffle');
                selectHype();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryThinkFast()) {
                console.log('Recommended action: Think Fast');
                return;
            } else {
                // Since there's no way to get to pitch, throw it away and try the rest
                console.log('Giving up on Pitch');
                triedPitch = true;
                damages.shift();
                continue;
            }
        } else if ((!triedCk) && (maxCkDamage == damages[0])) {
            if (tryCk()) {
                console.log('Recommended action: Coupon Kick');
                selectCk();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryFreeShuffle()) {
                console.log('Recommended action: shuffle');
                selectHype();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryThinkFast()) {
                console.log('Recommended action: Think Fast');
                return;
            } else {
                // Since there's no way to get to CK, throw it away and try the rest
                console.log('Giving up on Coupon Kick');
                triedCk = true;
                damages.shift();
                continue;
            }
        } else if (!triedNormal) {
            if (tryNormal()) {
                console.log('Recommended action: Savings Punch');
                selectNormal();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryFreeShuffle()) {
                console.log('Recommended action: shuffle');
                selectHype();
                return;
            } else if ((damages.length == 1 || damages[0] > damages[1] + 1) && tryThinkFast()) {
                console.log('Recommended action: Think Fast');
                return;
            } else {
                // Since there's no way to get to sp, throw it away and try the rest
                console.log('Giving up on Savings Punch');
                triedNormal = true;
                damages.shift();
                continue;
            }
        }
    }
    document.querySelector('select[name="actiontarget"]').value = 'custid1';
    fallback(maxDamage > 1);
};

var tryHype = function() {
    var hype = document.querySelector('input[value="12"]');
    if (hype) {
        hype.checked = true;
        return true;
    }
    return false;
};

var tryPitch = function() {
    var pitch = document.querySelector('input[value="3"][type="radio"]');
    if (pitch) {
        pitch.checked = true;
        return true;
    }
    return false;
};

var tryCk = function() {
    var coupon = document.querySelector('input[value="2"][type="radio"]');
    if (coupon) {
        coupon.checked = true;
        return true;
    }
    return false;
};

var tryNormal = function() {
    var savings = document.querySelector('input[value="1"][type="radio"]');
    if (savings) {
        savings.checked = true;
        return true;
    }
    return false;
};

var tryFreeShuffle = function() {
    var bogo = document.querySelector('input[value="11"]');
    if (bogo) {
        bogo.checked = true;
        return true;
    }
    var barge = document.querySelector('input[value="5"]');
    if (barge) {
        barge.checked = true;
        return true;
    }
    return false;
};

var tryThinkFast = function() {
    var thinkfast = document.querySelector('input[value="6"]');
    if (thinkfast) {
        thinkfast.checked = true;
        return true;
    }
    return false;
};

var fallback = function(freeshuffle) {
    var hype = document.querySelector('input[value="12"]');
    if (hype) {
        hype.checked = true;
        return;
    }

    var savings = document.querySelector('input[value="1"][type="radio"]');
    if (savings) {
        savings.checked = true;
        return;
    }

    var coupon = document.querySelector('input[value="2"][type="radio"]');
    if (coupon) {
        coupon.checked = true;
        return;
    }

    var pitch = document.querySelector('input[value="3"][type="radio"]');
    if (pitch) {
        pitch.checked = true;
        return;
    }

    var barge = document.querySelector('input[value="5"]');
    if (barge) {
        barge.checked = true;
        return;
    }

    if (freeshuffle) {
    var freebies = document.querySelector('input[value="Q"]');
    if (freebies) {
        freebies.checked = true;
        return;
    }
    }
    /*
// TODO: logic on whether to do this, it's not a good action if there are hypes
  var deodorant = document.querySelector('input[value="L"]');
  if (deodorant) {
    deodorant.checked = true;
    return;
  }
  */
    var deathstare = document.querySelector('input[value="8"]');
    if (deathstare) {
        deathstare.checked = true;
        return;
    }

    var thinkfast = document.querySelector('input[value="6"]');
    if (thinkfast) {
        thinkfast.checked = true;
        return;
    }

    var wutever = document.querySelector('input[type="radio"]');
    wutever.checked = true;
    return;
};

var main = function() {
    if (document.enterretail) {
        document.addEventListener('keyup', function(e) {
            if (e.code != 'KeyD') return;
            document.enterretail.submit();
        }, false);
        return;
    }

    if (preflightCheck()) {
        console.log('Stand by for takeoff');
        var recommendedActions = setActions();
        var acted = false;
        document.addEventListener('keyup', function(e) {
            if (e.code != 'KeyD') return;
            if (acted) return;
            acted = true;
            if (!recommendedActions) {
                if (document.querySelector('a[href="javascript:document.startgame.submit();"]')) {
                    document.startgame.submit();
                } else {
                    alert('no shifts left!');
                }
            } else {
                document.suppressrt.submit();
            }
        }, false);
    } else if (document.makeaction) {
        // We're in the store! Let's play.
        storeParser();
        document.addEventListener('keyup', function(e) {
            if (e.code != 'KeyD') return;
            if (acted) return;
            acted = true;
            document.makeaction.submit();
        });
    } else if (document.movingon) {
        document.addEventListener('keyup', function(e) {
            if (acted) return;
            acted = true;
            if (e.code != 'KeyD') return;
            document.movingon.submit();
        });
    } else {
        console.log('You want the script? You can\'t handle the script!');
    }
};

main();