Melvor Bank Menu

Adds a menu to bank items and modifies tooltips to include item stats

// ==UserScript==
// @name         Melvor Bank Menu
// @namespace    http://tampermonkey.net/
// @version      0.0.1
// @description  Adds a menu to bank items and modifies tooltips to include item stats
// @author       NotCorgan#1234
// @match        https://melvoridle.com/*
// @match        https://www.melvoridle.com/*
// @match        https://test.melvoridle.com/*
// @exclude      https://melvoridle.com/update/*
// @exclude      https://www.melvoridle.com/update/*
// @exclude      https://test.melvoridle.com/update/*
// @grant        none
// @noframes
// ==/UserScript==

// Made for version 0.19.1

(function () {
    function injectScript(main) {
        var script = document.createElement('script');
        script.textContent = `try {(${main})();} catch (e) {console.log(e);}`;
        document.body.appendChild(script).parentNode.removeChild(script);
    }

    function script() {
        // Loading script
        let addMenuItem = function(title, el, cb, instance, shouldHide) {
            let li = document.createElement('li');
            li.className = 'nav-main-item';
            li.addEventListener('click', function(instance, cb, shouldHide = true, event) {
                instance.shouldHide = shouldHide;
                cb.call(li, event);
                instance.hide();
            }.bind(li, instance, cb, shouldHide));

            let mainLink = document.createElement('div');
            mainLink.className = 'nav-main-link pointer-enabled';
            mainLink.style.setProperty('font-size', '.6rem', 'important');
            mainLink.style.setProperty('min-height', '1.5rem', 'important');
            mainLink.style.setProperty('padding-top', '.10rem', 'important');
            mainLink.style.setProperty('padding-bottom', '.10rem', 'important');

            let span = document.createElement('span');
            span.className = 'nav-main-link-name';
            $(span).html(title);
            mainLink.appendChild(span);

            li.appendChild(mainLink);
            el.appendChild(li);
            return li;
        }

        let showMenu = function(id, instance, event) {
            selectBankItem(id);
            let item = items[id];
            event.preventDefault();

            instance.setProps({
                interactive: true,
                getReferenceClientRect: () => ({
                    width: 0,
                    height: 0,
                    top: event.clientY,
                    bottom: event.clientY,
                    left: event.clientX,
                    right: event.clientX,
                }),
            });

            let content = document.createElement('div');
            content.className = 'content-side';
            content.style.setProperty('padding-top', '.25rem', 'important');
            content.style.setProperty('text-align', 'center', 'important');
            let ul = document.createElement('div');
            ul.className = 'nav-main';
            ul.style.width = '225px';
            content.appendChild(ul);
            let li = document.createElement('li');
            li.className = 'nav-main-heading';
            $(li).html(item.name);
            li.style.setProperty('padding-top', '0', 'important');

            ul.appendChild(li);

            if(item.equipmentSlot !== undefined) {
                let li = addMenuItem('Equip Item', ul, function(id, event) { equipItem(id, (items[id].equipmentSlot == CONSTANTS.equipmentSlot.Quiver ? bank[getBankId(id)].qty : 1), -1); }.bind(null, id), instance);

                let small = document.createElement('small');
                small.style.setProperty('position', 'absolute');
                small.style.setProperty('right', '0');
                small.style.setProperty('top', '0');

                let btn = document.createElement('button');
                btn.className = 'btn m-1 btn-success';
                btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                btn.style.setProperty('font-size', '.6rem', 'important');
                btn.style.setProperty('min-height', '1rem', 'important');
                btn.appendChild(document.createTextNode('1'));
                btn.addEventListener('click', function(instance, event) {
                    instance.shouldHide = true;
                    equipItem(id, 1, 0);
                    instance.hide();
                    event.stopPropagation();
                    return false;
                }.bind(li, instance), true)
                small.appendChild(btn);

                if (playerModifiers.increasedEquipmentSets >= 1) {
                    btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('2'));
                    btn.addEventListener('click', function(instance, event) {
                        instance.shouldHide = true;
                        equipItem(id, 1, 1);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, instance), true)
                    small.appendChild(btn);
                }

                if (playerModifiers.increasedEquipmentSets >= 2) {
                    btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('3'));
                    btn.addEventListener('click', function(instance, event) {
                        instance.shouldHide = true;
                        equipItem(id, 1, 2);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, instance), true)
                    small.appendChild(btn);
                }

                li.firstChild.firstChild.appendChild(small);
            }
            if(item.equipmentSlot !== undefined && items[id].isPassiveItem) {
                let li = addMenuItem('Equip Passive', ul, function(id, event) { equipItem(id, 1, -1, false, true); }.bind(null, id), instance);

                let small = document.createElement('small');
                small.style.setProperty('position', 'absolute');
                small.style.setProperty('right', '0');
                small.style.setProperty('top', '0');

                let btn = document.createElement('button');
                btn.className = 'btn m-1 btn-success';
                btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                btn.style.setProperty('font-size', '.6rem', 'important');
                btn.style.setProperty('min-height', '1rem', 'important');
                btn.appendChild(document.createTextNode('1'));
                btn.addEventListener('click', function(instance, event) {
                    instance.shouldHide = true;
                    equipItem(id, 1, 0, false, true);
                    instance.hide();
                    event.stopPropagation();
                    return false;
                }.bind(li, instance), true)
                small.appendChild(btn);

                if (equipmentSetCount >= 1) {
                    btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('2'));
                    btn.addEventListener('click', function(instance, event) {
                        instance.shouldHide = true;
                        equipItem(id, 1, 1, false, true);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, instance), true)
                    small.appendChild(btn);
                }

                if (equipmentSetCount >= 2) {
                    btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('3'));
                    btn.addEventListener('click', function(instance, event) {
                        instance.shouldHide = true;
                        equipItem(id, 1, 2, false, true);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, instance), true)
                    small.appendChild(btn);
                }

                li.firstChild.firstChild.appendChild(small);
            }
            if(item.equipmentSlot !== undefined)
                addMenuItem('View Item Stats', ul, function(event) { viewItemStats(-1); }, instance)

            if (item.canUpgrade) {
                let li = addMenuItem('Upgrade', ul,  function(event) { upgradeItem(); }, instance);

                let upgradeItemID = items[id].trimmedItemID;
                let upgradeCheck = [];
                for (let i = 0; i < items[upgradeItemID].itemsRequired.length; i++) {
                    upgradeCheck.push(true);
                    let checkBankForItem = getBankId(items[upgradeItemID].itemsRequired[i][0]);
                    if (checkBankForItem >= 0 && bank[checkBankForItem] !== undefined) {
                        if (bank[checkBankForItem].qty < items[upgradeItemID].itemsRequired[i][1]) {
                            upgradeCheck[i] = false;
                        }
                    } else
                        upgradeCheck[i] = false;
                }

                let gpCost = items[upgradeItemID].trimmedGPCost;
                if(gp < gpCost)
                    upgradeCheck.push(false);

                if (items[upgradeItemID].isPotion) {
                    let masteryID = items[upgradeItemID].masteryID[1];
                    if (getMasteryLevel(CONSTANTS.skill.Herblore, masteryID) < masteryTiers[items[upgradeItemID].potionTier]) {
                        upgradeCheck.push(false);
                    }
                }

                if(upgradeCheck.includes(false)) {
                    li.firstChild.firstChild.classList.add('text-danger');
                } else {
                    let small = document.createElement('small');
                    small.style.setProperty('position', 'absolute');
                    small.style.setProperty('right', '0');
                    small.style.setProperty('top', '0');

                    let btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('1'));
                    btn.addEventListener('click', function(id, upgradeItemID, instance, event) {
                        instance.shouldHide = true;
                        confirmUpgradeItem(id, upgradeItemID);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, id, upgradeItemID, instance), true)
                    small.appendChild(btn);

                    btn = document.createElement('button');
                    btn.className = 'btn m-1 btn-success';
                    btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
                    btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
                    btn.style.setProperty('font-size', '.6rem', 'important');
                    btn.style.setProperty('min-height', '1rem', 'important');
                    btn.appendChild(document.createTextNode('All'));
                    btn.addEventListener('click', function(id, upgradeItemID, instance, event) {
                        instance.shouldHide = true;
                        confirmUpgradeItemAll(id, upgradeItemID);
                        instance.hide();
                        event.stopPropagation();
                        return false;
                    }.bind(li, id, upgradeItemID, instance), true)
                    small.appendChild(btn);

                    li.firstChild.firstChild.appendChild(small);
                }
            }

            if (item.canOpen) {
                addMenuItem('View Contents', ul,  function(event) { viewItemContents(); }, instance);
                addMenuItem('Open All', ul,  function(id, event) { openItemQty = bank[getBankId(id)].qty; openBankItem(); }.bind(window, id), instance);
            }

            if (item.prayerPoints !== undefined)
                addMenuItem('Bury All', ul,  function(id, event) { buryItemQty = bank[getBankId(id)].qty; buryItem(); }.bind(window, id), instance);

            if (item.isToken)
                addMenuItem('Claim All', ul,  function(id, event) {
                    claimTokenQty = bank[getBankId(id)].qty;
                    if(id === CONSTANTS.item.Bank_Slot_Token) {
                        claimBankToken();
                    } else {
                        claimToken();
                    }
                }.bind(window, id), instance);

            if (item.canRead)
                addMenuItem('Read', ul,  function(event) { readItem(id) }.bind(window, id), instance);

            if (item.healsFor !== undefined)
                addMenuItem('Equip All', ul,  function(id, event) { equipFoodQty = bank[getBankId(id)].qty; equipFood(); }.bind(window, id), instance);



            addMenuItem('Toggle Lock', ul, function(instance, event) {
                lockItem();
                let li = instance.popper.querySelector('.sell-all');

                let bankID = getBankId(selectedBankItem);
                if (bank[bankID].locked) {
                    li.firstChild.firstChild.classList.add('text-danger');
                } else {
                    li.firstChild.firstChild.classList.remove('text-danger');
                }
            }.bind(window, instance), instance, false)

            li = addMenuItem('Sell All -1', ul,  function(id, event) {
                let bankID = getBankId(selectedBankItem);
                if (!bank[bankID].locked) {
                    updateSellQty(1)
                    sellItem();
                }
            }.bind(window, id), instance);
            li.classList.add('sell-all');

            let small = document.createElement('small');
            small.style.setProperty('position', 'absolute');
            small.style.setProperty('right', '0');
            small.style.setProperty('top', '0');

            let btn = document.createElement('button');
            btn.className = 'btn m-1 btn-success';
            btn.style.setProperty('margin', '0.05rem 0.1rem', 'important');
            btn.style.setProperty('padding', '0.15rem 0.35rem', 'important');
            btn.style.setProperty('font-size', '.6rem', 'important');
            btn.style.setProperty('min-height', '1rem', 'important');
            btn.appendChild(document.createTextNode('All'));
            btn.addEventListener('click', function(id, instance, event) {
                instance.shouldHide = true;
                let bankID = getBankId(selectedBankItem);
                if (!bank[bankID].locked) {
                    updateSellQty(0)
                    sellItem();
                }
                instance.hide();
                event.stopPropagation();
                return false;
            }.bind(li, id, instance), true)
            small.appendChild(btn);

            li.firstChild.firstChild.appendChild(small);

            if (bank[getBankId(selectedBankItem)].locked)
                li.firstChild.firstChild.classList.add('text-danger');

            instance.setContent(content);

            instance.show();
        }

        let bankTips = [];
        setInterval(function() {
            let bankItems = document.querySelectorAll('.bank-item');
            bankItems.forEach((item) => {
                let id = parseInt(item.id.split('-')[3]);
                let instance = bankTips[id];
                if(instance) {
                    if (instance.reference !== item) {
                        instance.destroy();
                        instance = false;
                    }
                }
                if(!instance) {
                    instance = tippy(item, {
                        placement: 'right-start',
                        trigger: 'manual',
                        interactive: true,
                        arrow: false,
                        allowHTML: true,
                        sticky: true,
                        onHide(instance) {
                            if(instance.shouldHide === true) {
                                instance.shouldHide = false;
                                return true;
                            } else {
                                return false
                            }
                        },
                        onClickOutside(instance) {
                            instance.shouldHide = true;
                        }
                    });
                    bankTips[id] = instance;
                    item.addEventListener('contextmenu', showMenu.bind(item, id, instance));
                }
            });
        }, 1000)

        let tooltips = [];

        let generateTooltip = function(bankItemID) {
            let itemDesc = [];
            let itemStat = [];
            let item = items[bankItemID];
            if (item.isPotion)
                itemDesc.push("<small class='text-warning'>" + item.potionCharges + " Potion Charges</small>");
            if (item.description !== undefined)
                itemDesc.push("<small class='text-info'>" + item.description + "</small>");
            if (item.hasSpecialAttack)
                itemDesc.push("<small class='text-success'>SPECIAL ATTACK<br><span class='text-danger'>" + playerSpecialAttacks[item.specialAttackID].name + " (" + playerSpecialAttacks[item.specialAttackID].chance + "%): </span><span class='text-warning'>" + playerSpecialAttacks[item.specialAttackID].description + "</span></small>");
            if(item.equipmentSlot !== undefined) {
                if (item.attackBonus[0] > 0)
                    itemStat.push('<span class="text-success">+' + item.attackBonus[0] + " Melee Stab Bonus</span>");
                if (item.attackBonus[0] < 0)
                    itemStat.push('<span class="text-danger">' + item.attackBonus[0] + " Melee Stab Bonus</span>");
                if (item.attackBonus[1] > 0)
                    itemStat.push('<span class="text-success">+' + item.attackBonus[1] + " Melee Slash Bonus</span>");
                if (item.attackBonus[1] < 0)
                    itemStat.push('<span class="text-danger">' + item.attackBonus[1] + " Melee Slash Bonus</span>");
                if (item.attackBonus[2] > 0)
                    itemStat.push('<span class="text-success">+' + item.attackBonus[2] + " Melee Block Bonus</span>");
                if (item.attackBonus[2] < 0)
                    itemStat.push('<span class="text-danger">' + item.attackBonus[2] + " Melee Block Bonus</span>");
                if (item.strengthBonus != undefined && item.strengthBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.strengthBonus + " Melee Strength Bonus</span>");
                if (item.strengthBonus != undefined && item.strengthBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.strengthBonus + " Melee Strength Bonus</span>");
                if (item.rangedStrengthBonus != undefined && item.rangedStrengthBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.rangedStrengthBonus + " Ranged Strength Bonus</span>");
                if (item.rangedStrengthBonus != undefined && item.rangedStrengthBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.rangedStrengthBonus + " Ranged Strength Bonus</span>");
                if (item.defenceBonus != undefined && item.defenceBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.defenceBonus + " Melee Defence Bonus</span>");
                if (item.defenceBonus != undefined && item.defenceBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.defenceBonus + " Melee Defence Bonus</span>");
                if (item.rangedAttackBonus != undefined && item.rangedAttackBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.rangedAttackBonus + " Ranged Attack Bonus</span>");
                if (item.rangedAttackBonus != undefined && item.rangedAttackBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.rangedAttackBonus + " Ranged Attack Bonus</span>");
                if (item.rangedDefenceBonus != undefined && item.rangedDefenceBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.rangedDefenceBonus + " Ranged Defence Bonus</span>");
                if (item.rangedDefenceBonus != undefined && item.rangedDefenceBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.rangedDefenceBonus + " Ranged Defence Bonus</span>");
                if (item.magicAttackBonus != undefined && item.magicAttackBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.magicAttackBonus + " Magic Attack Bonus</span>");
                if (item.magicAttackBonus != undefined && item.magicAttackBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.magicAttackBonus + " Magic Attack Bonus</span>");
                if (item.magicDefenceBonus != undefined && item.magicDefenceBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.magicDefenceBonus + " Magic Defence Bonus</span>");
                if (item.magicDefenceBonus != undefined && item.magicDefenceBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.magicDefenceBonus + " Magic Defence Bonus</span>");
                if (item.magicDamageBonus != undefined && item.magicDamageBonus > 0)
                    itemStat.push('<span class="text-success">+' + item.magicDamageBonus + "% Magic Damage Bonus</span>");
                if (item.magicDamageBonus != undefined && item.magicDamageBonus < 0)
                    itemStat.push('<span class="text-danger">' + item.magicDamageBonus + "% Magic Damage Bonus</span>");
                if (item.damageReduction != undefined && item.damageReduction > 0)
                    itemStat.push('<span class="text-success">+' + item.damageReduction + "% Damage Reduction</span>");
                if (item.damageReduction != undefined && item.damageReduction < 0)
                    itemStat.push('<span class="text-danger">' + item.damageReduction + "% Damage Reduction</span>");
                if(itemStat.length > 0)
                    itemDesc.push("<small>" + itemStat.join("</br>") + "</small>");
            }
            itemDesc.push("<img class='skill-icon-xs' src='" + CDNDIR + "assets/media/main/coins.svg'> " + item.sellsFor);

            if (item.canEat)
                itemDesc[itemDesc.length-1] += "<img class='skill-icon-xs ml-2' src='" + CDNDIR + "assets/media/skills/hitpoints/hitpoints.svg'><span class='text-success'>+" + getFoodHealValue(bankItemID) + "</span>";

            if (item.isPassiveItem !== undefined) {
                if (item.isPassiveItem && dungeonCompleteCount[CONSTANTS.dungeon.Into_the_Mist] > 0)
                    itemDesc.push('<small class="text-success">Passive Slot Compatible</small>');
            }
            itemDesc = itemDesc.join("</br>");
            let bankTooltip = "<div class='text-center'><div class='media d-flex align-items-center push'><div class='mr-3'><img class='bank-img m-1' src='" + getItemMedia(bankItemID) + "'></div><div class='media-body'><div class='font-w600'>" + item.name + "</div>" + itemDesc + "</div></div></div>";


            const tInstance = tippy("#bank-item-button-" + bankItemID, {
                content: bankTooltip,
                placement: "top",
                allowHTML: true,
                interactive: false,
                animation: false,
                touch: "hold",
                hideOnClick: false
            });
            tooltipInstances.bank = tooltipInstances.bank.concat(tInstance);
        }

        let updateBankTooltips = function() {
            let diff = tooltipInstances.bank.filter(x => !tooltips.includes(x))
            diff.forEach((instance) => {
                let id = parseInt(instance.reference.id.split('-')[3]);
                instance.destroy();
                generateTooltip(id);
            });
            tooltips = tooltipInstances.bank;
        }

        let __createBankItem = createBankItem;
        createBankItem = function() {
            __createBankItem.apply(window, arguments);
            updateBankTooltips();
        }
        updateBankTooltips();

        console.log('Melvor Bank Menu Loaded');
    }

    function loadScript() {
        if ((window.isLoaded && !window.currentlyCatchingUp) || (typeof unsafeWindow !== 'undefined' && unsafeWindow.isLoaded && !unsafeWindow.currentlyCatchingUp)) { // Only load script after game has opened
            clearInterval(scriptLoader);
            injectScript(script);
        }
    }

    const scriptLoader = setInterval(loadScript, 200);
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址