您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows time remaining for completing a task with your current resources. Takes into account Mastery Levels and other bonuses.
当前为
// ==UserScript== // @name Melvor TimeRemaining // @namespace http://tampermonkey.net/ // @version 0.2.4 // @description Shows time remaining for completing a task with your current resources. Takes into account Mastery Levels and other bonuses. // @author Breindahl#2660 // @match https://*.melvoridle.com/* // @grant none // ==/UserScript== // Loading console.log('Loading Breindahl TimeRemaining'); // Function to send notifications function notify(msg) { One.helpers('notify', { type: 'dark', from: 'bottom', align: 'center', message: msg }); } // Funtion to check if task is complete function taskComplete() { if (window.timeLeftLast > 1 && window.timeLeftGlobal === 0) { notify("Task Done"); console.log('task done'); new Audio("https://www.myinstants.com/media/sounds/ding-sound-effect.mp3").play(); } } // Create containers document.getElementById("smith-item-have").outerHTML += '<br><small id ="timeLeftSmithing" class="js-tooltip-enabled timeLeftSmithingOffline" data-toggle="tooltip" data-placement="top" data-html="true" title="" data-original-title="">'+''+'<small>'; document.getElementById("fletch-item-have").outerHTML += '<br><small id ="timeLeftFletching" class="js-tooltip-enabled timeLeftFletchingOffline" data-toggle="tooltip" data-placement="top" data-html="true" title="" data-original-title="">'+''+'<small>'; document.getElementById("runecraft-item-have").outerHTML += '<br><small id ="timeLeftRunecrafting" class="js-tooltip-enabled timeLeftRunecraftingOffline" data-toggle="tooltip" data-placement="top" data-html="true" title="" data-original-title="">'+''+'<small>'; document.getElementById("craft-item-have").outerHTML += '<br><small id ="timeLeftCrafting" class="js-tooltip-enabled timeLeftCraftingOffline" data-toggle="tooltip" data-placement="top" data-html="true" title="" data-original-title="">'+''+'<small>'; document.getElementById("herblore-item-have").outerHTML += '<br><small id ="timeLeftHerblore" class="js-tooltip-enabled timeLeftHerbloreOffline" data-toggle="tooltip" data-placement="top" data-html="true" title="" data-original-title="">'+''+'<small>'; //Funtion to get unformatted number for Qty function getQtyUnformat(itemID) { let qty = 0; for (let i = 0; i < bank.length; i++) { if (bank[i].id === itemID) { qty += bank[i].qty; } } return qty; } // Convert seconds to hours/minutes/seconds function secondsToHms(d) { d = Number(d); var h = Math.floor(d / 3600); var m = Math.floor(d % 3600 / 60); var s = Math.floor(d % 3600 % 60); var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : ""; var mDisplay = m > 0 ? m + (m == 1 ? " minute" : " minutes") + (s === "" ? "" : ", ") : ""; var hDisplay = h > 0 ? h + (h == 1 ? " hour" : " hours") + ((s === "" && m === "") ? "" : ", ") : ""; return hDisplay + mDisplay + sDisplay; } // Main function function timeRemaining(item,currentSkill){ //console.log("Current Skill is "+currentSkill); //console.log("ItemID"+item); // Reset variables var skillInterval = null; // Update interval of skill var skillID = null; // skillID of item (this is different than itemID) var skillMastery = null; // Current amount of Mastery experience var containerID = ""; // Field for generating HTML var skillReq = []; // Needed items for craft and their quantities var masteryLim = [6,14,23,32,42,54,66,80,96,113,132,152,175,200,228,259,293,331,372,418,468,524,585,653,728,810,902,1002,1113,1236,1371,1520,1685,1867,2067,2289,2534,2804,3102,3430,3794,4194,4637,5126,5665,6260,6917,7643,8444,9328,10305,11382,12572,13886,15336,16937,18705,20657,22811,25190,27817,30716,33917,37452,41354,45662,50419,55670,61468,67870,74938,82741,91356,100868,111370,122965,135766,149900,165505,182734,201757,222759,245947,271549,299816,331024,365481,403524,445527,491902,543104,599635,662051,730963,807048,891052,983800,1086202, Infinity]; // This array contain the thresholds at which a new chanceToKeep comes into effect var chanceToKeep = [0.0000,0.0025,0.0050,0.0075,0.0100,0.0125,0.0150,0.0175,0.0200,0.0225,0.0250,0.0275,0.0300,0.0325,0.0350,0.0375,0.0400,0.0425,0.0450,0.0475,0.0500,0.0525,0.0550,0.0575,0.0600,0.0625,0.0650,0.0675,0.0700,0.0725,0.0750,0.0775,0.0800,0.0825,0.0850,0.0875,0.0900,0.0925,0.0950,0.0975,0.1000,0.1025,0.1050,0.1075,0.1100,0.1125,0.1150,0.1175,0.1200,0.1225,0.1250,0.1275,0.1300,0.1325,0.1350,0.1375,0.1400,0.1425,0.1450,0.1475,0.1500,0.1525,0.1550,0.1575,0.1600,0.1625,0.1650,0.1675,0.1700,0.1725,0.1750,0.1775,0.1800,0.1825,0.1850,0.1875,0.1900,0.1925,0.1950,0.1975,0.2000,0.2025,0.2050,0.2075,0.2100,0.2125,0.2150,0.2175,0.2200,0.2225,0.2250,0.2275,0.2300,0.2325,0.2350,0.2375,0.2400,0.2425,0.2450]; //Percentage chance of keeping item var itemCraft = []; // Amount of items craftable for each resource requirement var recordCraft = Infinity; // Amount of craftable items for limiting resource // Set current skill and pull match variables from game with script if (currentSkill == "Smithing") { skillInterval = smithInterval; skillID = smithingItems[selectedSmith].smithingID; skillMastery = smithingMastery[skillID].masteryXP; containerID = "timeLeftSmithing"; for (let i of items[item].smithReq) { skillReq.push(i); } masteryLim = [372,3102,22811,165505,Infinity]; //Smithing Mastery limiters chanceToKeep = [0,0.1,0.2,0.3,0.4]; //Smithing Mastery bonus percentages } if (currentSkill == "Fletching") { skillInterval = fletchInterval; skillID = fletchingItems[selectedFletch].fletchingID; skillMastery = fletchingMastery[skillID].masteryXP; containerID = "timeLeftFletching"; for (let i of items[item].fletchReq) { skillReq.push(i); } //Special Case for Arrow Shafts if (item == 276) { if (selectedFletchLog === undefined) {selectedFletchLog = 0;} skillReq = [skillReq[selectedFletchLog]]; } } if (currentSkill == "Runecrafting") { skillInterval = runecraftInterval; skillID = runecraftingItems[selectedRunecraft].runecraftingID; skillMastery = runecraftingMastery[skillID].masteryXP; containerID = "timeLeftRunecrafting"; for (let i of items[item].runecraftReq) { skillReq.push(i); } masteryLim = [Infinity]; //Runecrafting has no Mastery chanceToKeep = [0]; //Thus gives no bonus } if (currentSkill == "Crafting") { skillInterval = craftInterval; skillID = craftingItems[selectedCraft].craftingID; skillMastery = craftingMastery[skillID].masteryXP; containerID = "timeLeftCrafting"; for (let i of items[item].craftReq) { skillReq.push(i); } } if (currentSkill == "Herblore") { skillInterval = herbloreInterval; skillID = herbloreItems[selectedHerblore].id; skillMastery = herbloreMastery[skillID].masteryXP; containerID = "timeLeftHerblore"; for (let i of items[item].herbloreReq) { skillReq.push(i); } } // Get Item Requirements and Current Requirements for (let i = 0; i < skillReq.length; i++) { var itemReq; //Special Case: Check for Smithing Cape if (equippedItems[CONSTANTS.equipmentSlot.Cape] === CONSTANTS.item.Smithing_Skillcape && skillReq[i].id == 48) { itemReq = Math.floor(skillReq[i].qty / 2); } else { itemReq = skillReq[i].qty; } //Check how many of required resourse in Bank var itemQty = getQtyUnformat(skillReq[i].id); // Calculate max items you can craft for each itemReq itemCraft[i] = Math.floor(itemQty/itemReq); // Calculate limiting factor and set new record if(itemCraft[i] < recordCraft) { recordCraft = itemCraft[i]; } } //Return the chanceToKeep for any mastery EXP function masteryChance(masteryEXP){ if (masteryEXP >= masteryLim[0]) { for (let i = 0; i < masteryLim.length; i++) { if (masteryLim[i] <= masteryEXP && masteryEXP < masteryLim[i+1]) {return chanceToKeep[i+1];} } } else {return chanceToKeep[0];} } // Function made by Xhaf#6478 // Calculates expected time, taking into account Mastery Level advancements during the craft function expectedTime(resources, resourcesPerAction, timePerAction, currentMastery, masteryLim){ //this function finds the required items to get expToLvl more exp, considering expPerItem and resource preservation due to mastery var expectedActions = Math.floor(resources/resourcesPerAction/(1-masteryChance(currentMastery))); //nr of actions if we do not reach new masteryLim var currentMastery_lim = masteryLim.find(element => element > currentMastery); //this many actions can be taken until we reach a new mastery threshold var finalResult; var resourcesLeft if (expectedActions <= currentMastery_lim-currentMastery){ finalResult = expectedActions resourcesLeft = 0 } else { finalResult = (currentMastery_lim - currentMastery); //finalResult will be updated to keep track of actions resourcesLeft = (resources - finalResult*resourcesPerAction*(1-masteryChance(currentMastery))); //remaining resources after we reach new mastery level } currentMastery = currentMastery_lim; //prepare for loop while (Math.floor(resourcesLeft/resourcesPerAction) > 0) { //continue iterating through new chanceToKeep levels until we're out of resources currentMastery_lim = masteryLim.find(element => element > currentMastery); //nr of actions from next chanceToKeep expectedActions = Math.floor(resourcesLeft/resourcesPerAction/(1-masteryChance(currentMastery))); //how many actions we can do with the remaining resources at the new mastery level if (expectedActions <= currentMastery_lim - currentMastery) { //if this is the final mastery level, add the nr of actions to finalResult and stop iterating finalResult += expectedActions; break } else { //if we will reach a new mastery level, set the new remainder and add the items required to reach the new mastery level to final_result resourcesLeft -= (currentMastery_lim-currentMastery)*(1-masteryChance(currentMastery)); finalResult += currentMastery_lim-currentMastery; } currentMastery = currentMastery_lim; } return finalResult*timePerAction; } //Time left if online (with Mastery progression) var timeLeft = Math.floor(expectedTime(recordCraft,1,skillInterval/1000, skillMastery,masteryLim)); console.log("timeLeft: "+timeLeft); //Time left if offline (no Mastery progression) var timeLeftOffline = Math.floor(recordCraft * smithInterval / 1000 /(1-masteryChance(skillMastery))); //Global variables to keep track of when a craft is complete window.timeLeftLast = window.timeLeftGlobal; window.timeLeftGlobal = timeLeft; //Inject HTML var elementToChange = document.getElementById(containerID); if (timeLeft !== 0) { if(elementToChange !== null) { elementToChange.innerHTML = secondsToHms(timeLeft) + " remaining"; // Tooltip with time left if offline $('.'+containerID+'Offline').attr('data-original-title', 'Offline: '+secondsToHms(timeLeftOffline)); // Refreshes tooltip if hovering if ($('.'+containerID+'Offline').attr('aria-describedby') !== undefined) { $('.'+containerID+'Offline').tooltip('show'); } } } else { if(elementToChange !== null) { elementToChange.innerHTML = ""; $('.'+containerID+'Offline').attr('data-original-title', ''); } } } // ## SMITHING ## var selectSmithRef = selectSmith; window.selectSmith = function(smithingID) { selectSmithRef(smithingID); timeRemaining(smithingItems[selectedSmith].itemID,"Smithing"); }; var startSmithingRef = startSmithing; window.startSmithing = function() { startSmithingRef(true); timeRemaining(smithingItems[selectedSmith].itemID,"Smithing"); taskComplete(); }; // ## FLETCHING ## var selectFletchRef = selectFletch; window.selectFletch = function(fletchingID, log, update = false) { selectFletchRef(fletchingID, log, update = false); timeRemaining(fletchingItems[selectedFletch].itemID,"Fletching"); }; var startFletchingRef = startFletching; window.startFletching = function() { startFletchingRef(true); timeRemaining(fletchingItems[selectedFletch].itemID,"Fletching"); taskComplete(); }; // ## RUNECRAFTING ## var selectRunecraftRef = selectRunecraft; window.selectRunecraft = function(runecraftingID, update = false) { selectRunecraftRef(runecraftingID, update = false); timeRemaining(runecraftingItems[selectedRunecraft].itemID,"Runecrafting"); }; var startRunecraftingRef = startRunecrafting; window.startRunecrafting = function() { startRunecraftingRef(true); timeRemaining(runecraftingItems[selectedRunecraft].itemID,"Runecrafting"); taskComplete(); }; // ## CRAFTING ## var selectCraftRef = selectCraft; window.selectCraft = function(craftingID, update = false) { selectCraftRef(craftingID, update = false); timeRemaining(craftingItems[selectedCraft].itemID,"Crafting"); }; var startCraftingRef = startCrafting; window.startCrafting = function() { startCraftingRef(true); timeRemaining(craftingItems[selectedCraft].itemID,"Crafting"); taskComplete(); }; // ## HERBLORE ## var selectHerbloreRef = selectHerblore; window.selectHerblore = function(herbloreID, update = false) { selectHerbloreRef(herbloreID, update = false); timeRemaining(herbloreItemData[selectedHerblore].itemID[getHerbloreTier(selectedHerblore)],"Herblore"); }; var startHerbloreRef = startHerblore; window.startHerblore = function() { startHerbloreRef(true); timeRemaining(herbloreItemData[selectedHerblore].itemID[getHerbloreTier(selectedHerblore)],"Herblore"); taskComplete(); };
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址