您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Estimates inventory crafting xp
// ==UserScript== // @name IMCraftingSum // @namespace http://tamper.net/ // @version 0.10 // @description Estimates inventory crafting xp // @author Holychikenz // @match *://*.idlescape.com/* // @run-at document-end // ==/UserScript== function printCraftingXP() { // This is meant to give an idea of the exact crafting xp in inventory, this includes // the discrete nature of crafting (with the enchant) as resources spent smithing and cooking. // At the end intuition food and dono buff are assumed. // Verbose option for debugging, can be disabled, though it just prints to console. let verbose = false; // Set to true to see some extra print outs in the console function vp(text){ if( verbose ) console.log(text); } // Internal Helper Functions for styling the message function sxp(xp, p=1, w=100){ return `<b style="color:#66ccff;display:inline-block;width:${w}px;">${dnum(xp,p)} xp</b>` } function sgold(gold, p=1, w=100){ return `<b style="color:#ffc107;display:inline-block;width:${w}px;">${dnum(gold,p)} gp</b>` } function lbar(key){ return `<img src="/images/smithing/${key.toLowerCase()}_bar.png" style="display:inline;height:1em;">` } function lgem(key){ return `<img src="/images/mining/${key.toLowerCase().replace(/ /g,"_")}.png" style="display:inline;height:1em;">` } let spn = `<span style="display: inline-block; width: 300px;">` // Default enchants assumed here, edit these if they do not apply let efficiency = 8; // gloves: Applies to smithing and Cooking let crafting = 6; let maplesInsteadOfPyreYews = false; let eMod = 1+0.01*efficiency; let cMod = 1-0.02*crafting; let buff = 1.3; // donation + intuition // Get the player inventory (or stash if that's open instead) var inventory = getInventory(); var totalXP = 0; var totalHeat = 0; // Required to complete operations let msg = "<hr><h5>Crafting XP Report</h5><hr>"; // Fert and branches, move above, also for ore need to save some logs // Lets assume sand is always the missing part, so lets just count sand // ****************************** // Misc (Fert, Branch, Oil, Sage) // ****************************** msg += `<div style="margin-left: 20px;">`; let fertCount = Math.floor(get(inventory, "Sand", 0) / 10 / cMod ); let fertXP = fertCount * 20 * buff; msg += `${spn}${fertCount} fertilizer </span>${sxp(fertXP)}<br/>`; totalXP += fertXP; let branchCraft = Math.floor(get(inventory, "Branch", 0) / 20 / cMod ) let branchXP = branchCraft * 10 * buff msg += `${spn}${branchCraft} branches </span>${sxp(branchXP)} <br/>`; vp(`Starting with ${inventory['Log']} logs`) // If no logs, set logs to zero inventory["Log"] = "Log" in inventory ? inventory["Log"] : 0; inventory["Oak Log"] = "Oak Log" in inventory ? inventory["Oak Log"] : 0; inventory["Willow Log"] = "Willow Log" in inventory ? inventory["Willow Log"] : 0; inventory["Maple Log"] = "Maple Log" in inventory ? inventory["Maple Log"] : 0; inventory["Yew Log"] = "Yew Log" in inventory ? inventory["Yew Log"] : 0; inventory['Log'] += branchCraft; vp(`Crafting ${branchCraft} branches brings us to ${inventory['Log']} logs`) let sageCount = Math.floor(get(inventory, "Sageberry Bush Seed", 0) / cMod) let sageXP = sageCount * 5000 * buff; msg += `${spn}${sageCount} sage </span>${sxp(sageXP)}<br/>`; totalXP += sageXP; // ********************** // Smithing Tools // ********************** let barxp = 0; let barcost = 0; // Save Styg and Rune, sell the rest, lets also account for used logs // Btw we assume pyro ring but no food (heat is infinite for IM race through pyres) let bardata = { "Bronze": {"Ores":1, "Heat": 1, "XP": 130, "gp":800, "craftcount":40, "logtype":"Log", "logs":20}, "Iron": {"Ores":3, "Heat": 3, "XP": 480, "gp":6000, "craftcount":75, "logtype":"Oak Log", "logs":35}, "Mithril": {"Ores":5, "Heat": 25, "XP": 2893, "gp":52000, "craftcount":130, "logtype":"Willow Log", "logs":65}, "Adamantite": {"Ores":10, "Heat": 50, "XP": 8600, "gp":480000, "craftcount":200, "logtype":"Maple Log", "logs":100}, "Runite": {"Ores":15, "Heat": 100, "XP": 22013, "gp":7200*0, "craftcount":270, "logtype":"Yew Log", "logs":55}, "Stygian": {"Ores":25, "Heat": 250, "XP": 63000, "gp":9600*0, "craftcount":350, "logtype":"Ichor", "logs":175} } let daggerdata = { "Bronze": {"Ores":1, "Heat": 1, "XP": 58, "gp":400, "craftcount":20, "logtype":"Log", "logs":5}, "Iron": {"Ores":3, "Heat": 3, "XP": 280, "gp":4000, "craftcount":50, "logtype":"Oak Log", "logs":10}, "Mithril": {"Ores":5, "Heat": 25, "XP": 2113, "gp":52000, "craftcount":100, "logtype":"Willow Log", "logs":25}, "Adamantite": {"Ores":10, "Heat": 50, "XP": 6580, "gp":480000, "craftcount":160, "logtype":"Maple Log", "logs":30}, "Runite": {"Ores":15, "Heat": 100, "XP": 18338, "gp":7200*0, "craftcount":225, "logtype":"Yew Log", "logs":45}, "Stygian": {"Ores":25, "Heat": 250, "XP": 50400, "gp":9600*0, "craftcount":300, "logtype":"Ichor", "logs":60} } msg += `</div><h6 style='margin-top:4px;margin-bottom:0px;'>Tools [Dagger, Hoe]</h6><div style="margin-left: 20px;">`; for( let key in bardata ){ // First smelt the bars (subtracting needed heat), then craft and report remainders let value = bardata[key]; let current_bars = get(inventory, `${key} Bar`, 0); let current_ore = get(inventory, `${key} Ore`, 0); current_ore = (key == "Bronze") ? Math.min( get(inventory, "Copper Ore", 0), get(inventory, "Tin Ore", 0) ) : current_ore; let new_bars = Math.floor(current_ore / value.Ores); let req_heat = new_bars * value.Heat; new_bars = Math.floor(new_bars * eMod) vp(` Smith ${current_ore} ${key} into ${new_bars} bars using ${req_heat} heat`) // Split between daggers and hoes efficiently let dagger = daggerdata[key]; let daggerCost = Math.ceil(dagger.craftcount*cMod); let hoeCost = Math.ceil(value.craftcount*cMod); let dagHoe = daggersAndHoes(new_bars+current_bars, daggerCost, hoeCost); let nDaggers = dagHoe[0]; let nHoes = dagHoe[1]; let barCost = nDaggers*daggerCost + nHoes*hoeCost; let woodCost = nDaggers*Math.ceil(dagger.logs*cMod) + nHoes*Math.ceil(value.logs*cMod); let bar_gold = nDaggers*dagger.gp + nHoes*value.gp // Do we have enough logs? //let logs_used = realLogCost * craftAttempts; if( woodCost > get(inventory, value.logtype, 0) ){ msg += `<b style="color: red;">!! Need more ${value.logtype} for ${key} tools ${woodCost} > ${get(inventory, value.logtype, 0)} !!</b><br>`; } inventory[value.logtype] = inventory[value.logtype] - woodCost let leftOvers = (new_bars + current_bars) - barCost// realCraftCost*craftAttempts let dagHoeXP = nDaggers*dagger.XP*buff + nHoes*value.XP*buff //msg += `${spn}[${nDaggers},${nHoes}] ${key} tools (${leftOvers} excess)</span>${sxp(dagHoeXP)}${sgold(bar_gold)}<br/>` msg += `${spn}${lbar(key)} ${nDaggers} daggers, and ${nHoes} hoes (${leftOvers} excess)</span>${sxp(dagHoeXP)}${sgold(bar_gold)}<br/>` totalXP += dagHoeXP; barxp += dagHoeXP; barcost += bar_gold; totalHeat += req_heat; } vp(`Used ${totalHeat} heat for smithing (mith and up)`) // ********************** // Jewelry + Gold Bars // ********************** // Loop through gems to count max rings and compare with rings from gold msg += `</div><h6 style='margin-top:4px;margin-bottom:0px;'>Jewelry</h6><div style="margin-left: 20px;">`; let gemdata = { "Black Opal": {"XP": 6600, "gp":1500000}, "Diamond": {"XP": 5600, "gp":300000}, "Ruby": {"XP": 4600, "gp":200000}, "Emerald": {"XP": 3600, "gp":140000}, "Sapphire": {"XP": 2600, "gp":120000} } // How much gold do we have actually?? let jew_gold = 0; let gold_bar_count = get(inventory, "Gold Bar", 0); let gold_ore = get(inventory, "Gold Ore", 0); let new_gold_bars = Math.floor( gold_ore / 10 ); let gold_heat = new_gold_bars * 10; new_gold_bars = Math.floor( new_gold_bars * eMod ); totalHeat += gold_heat; vp(`Up to ${totalHeat} heat used after gold`) //msg += `Smith ${new_gold_bars} Gold bars using ${gold_heat} heat<br>`; gold_bar_count += new_gold_bars; // let nrings = Math.floor( gold_bar_count / 150 / cMod ); // corrected by Kugan // With infinite gems, what is the maximum ring outcome? let finalRealRings = Math.floor( gold_bar_count / (50*cMod + 100*cMod**2) ); let craftedRings = Math.ceil( finalRealRings * cMod ) msg += `<i>Prepare ${craftedRings} gold rings to make ${finalRealRings} jewelry</i><br/>` // Gems time for( let key in gemdata ){ let value = gemdata[key]; let ngems = get(inventory, key, 0); if( craftedRings >= ngems ){ let realGems = Math.floor( ngems / cMod ); let gemxp = value.XP * realGems*buff; jew_gold += value.gp * realGems; totalXP += gemxp; craftedRings -= ngems; //msg += `${spn}${realGems} ${key} rings</span>${sxp(gemxp)}${sgold(value.gp*realGems)}<br>` msg += `${spn}${lgem(key)} ${realGems} rings</span>${sxp(gemxp)}${sgold(value.gp*realGems)}<br>` } else { let realGems = Math.floor( craftedRings / cMod ); let gemxp = value.XP * realGems*buff; jew_gold += value.gp * realGems; totalXP += gemxp; msg += `${spn}${lgem(key)} ${realGems} rings</span>${sxp(gemxp)}${sgold(value.gp*realGems)}<br>` craftedRings = 0; } } msg += `</div><h6 style='margin-top:4px;margin-bottom:0px;'>Oils</h6><div style="margin-left: 20px;">`; // Lets make some pyres if we have fish oil let fishdata = { "Raw Shrimp": {"Heat": 5, "Oil": 0.05}, "Raw Anchovy": {"Heat": 5, "Oil": 0.05}, "Raw Trout": {"Heat": 10, "Oil": 0.1}, "Raw Salmon": {"Heat": 10, "Oil": 0.1}, "Raw Lobster": {"Heat": 15, "Oil": 0.15}, "Raw Tuna": {"Heat": 15, "Oil": 0.15}, "Raw Shark": {"Heat": 20, "Oil": 0.20} } let fish_oil = get(inventory, "Fish Oil", 0); for( let key in fishdata ){ let value = fishdata[key]; let current_fish = get(inventory, key, 0); let new_oil = Math.floor(value.Oil * current_fish * eMod); let req_heat = value.Heat * new_oil / value.Oil; totalHeat += req_heat; fish_oil += new_oil; //msg += `Cook ${key} for ${new_oil} oil, using ${req_heat} heat<br>`; } vp(`now at ${totalHeat} heat from cooking fish`) // Logs let logs = get(inventory, "Log", 0); let oaks = get(inventory, "Oak Log", 0); let willows = get(inventory, "Willow Log", 0); let maples = get(inventory, "Maple Log", 0); let yews = get(inventory, "Yew Log", 0); vp(`new log count is ${logs}`) // Do we have enough yews? if( maplesInsteadOfPyreYews ){ if( maples/10 < fish_oil/4 ){ msg += `<b style="color: red;">!! Need ${ fish_oil*4 - 10*maples } more Maple Logs for Pyres !!</b><br>`; } else { let pyreCount = Math.floor( fish_oil / 4 / cMod ); maples -= Math.ceil( pyreCount * 10 * cMod ); totalXP += pyreCount * 200 * buff let burnHeat = 800 * pyreCount totalHeat -= burnHeat //msg += `Craft ${pyreCount} pyre yew logs gaining ${burnHeat} heat<br>` msg += `${spn}${pyreCount} pyre maples</span>${sxp(pyreCount*200*buff)}</br>` } } else { if( yews < 2*fish_oil ){ msg += `<b style="color: red;">!! Need ${ fish_oil*2 - yews } more Yew Logs for Pyres !!</b><br>`; } else { let pyreCount = Math.floor( fish_oil / 5 / cMod ); yews -= Math.ceil( pyreCount * 10 * cMod ); totalXP += pyreCount * 250 * buff let burnHeat = 3000 * pyreCount totalHeat -= burnHeat //msg += `Craft ${pyreCount} pyre yew logs gaining ${burnHeat} heat<br>` msg += `${spn}${pyreCount} pyre yews</span>${sxp(pyreCount*250*buff)}</br>` } } vp(`burning pyre brings the heat required to ${totalHeat}`) msg += `</div><h6 style='margin-top:4px;margin-bottom:0px;'>Ashes</h6><div style="margin-left: 20px;">`; // Finally ash some logs, takes 100 heat per try let inventory_heat = get(inventory, "Heat", 0) - totalHeat; //inventory_heat = 100e6 - totalHeat; // Infinite heat can help with pyre estimates vp(`Inventory - required heat: ${inventory_heat}`) // Check if we even have enough Yew logs to pay our heat debt if( inventory_heat + yews*200 <= 0 ){ let k = Math.ceil( Math.abs(inventory_heat + yews*100)/100 ) msg += `<b style="color: red;">!! Need ${ k } more Yew Logs to pay heat debt !!</b><br>`; } let ashxp = 0; let logAsh = Math.floor(logs / 30 / cMod); let oakAsh = Math.floor(oaks / 25 / cMod); let willowAsh = Math.floor(willows / 20 / cMod); let mapleAsh = Math.floor(maples / 15 / cMod); let currentAsh = logAsh + oakAsh + willowAsh + mapleAsh let ashHeat = Math.ceil( currentAsh * 100 * cMod ) inventory_heat -= ashHeat vp(`Burn ${ashHeat} heat for ashing up to maple, bring us to ${inventory_heat}`) //msg += `Craft ${currentAsh} ash (up to Maple) using ${ashHeat} heat<br>` let burntYews = 0 if( inventory_heat < 0 ){ let burnYews = Math.ceil(Math.abs(inventory_heat/100)) if( burnYews > yews ){ msg += `<b style="color: red;">!! Need ${ burnYews - yews } more Yew Logs to pay heat debt !!</b><br>`; } else { //msg += `>> Need to quickly burn ${burnYews} yew logs for heat<br>` } yews -= burnYews; vp(`Need to burn ${burnYews} to keep up`) inventory_heat += burnYews*200; } // Yews are tricky, it takes 10.5 per to pay the heat, unless we ALREADY have enough heat, then just 10 per, so start with those let remainingAshHeat = Math.floor(inventory_heat / 100 / cMod) let firstYewAsh = Math.min(remainingAshHeat, Math.floor(yews/10/cMod)) vp(`with ${remainingAshHeat} ashes, we can make ${firstYewAsh}`) // Remaining yews if( yews > 0 ){ let yewAsh = Math.floor(yews/10 / cMod) //burntYews += Math.ceil(yewAsh / 2 * cMod) //msg += `Craft ${yewAsh} ash from Yews, burning ${burntYew} yew logs for heat<br>` currentAsh += yewAsh } ashxp = currentAsh * 50 * buff; totalXP += ashxp; msg += `${spn}${currentAsh} ashes </span>${sxp(ashxp)}<br>` msg += `</div>` msg += `<hr><div style="margin-left:20px;">${spn}<b>New Resources</b></span>${sxp( totalXP, 3)}${sgold(jew_gold + barcost, 3)}</div>` // Include current xp and gold let currentCraftXP = parseFloat( getSkills()["Crafting"] ); let currentGold = getGold(); msg += `<div style="margin-left:20px;">${spn}<b>Total</b></span>${sxp( totalXP+currentCraftXP, 3)}${sgold(currentGold + jew_gold + barcost, 3)}</div><hr>` let d = document.createElement("div"); d.className = "chat-message" //d.innerHTML = `>> Crafting XP: ${totalXP.toFixed(0)}`; d.innerHTML = msg; document.getElementsByClassName("css-y1c0xs")[1].append(d); } // Maybe we could do something real quick here with cooking as well function printCookingXP(IMRace=true){ // Two ways to do this: // 1. Calculate all possible cooking (skip important veggies though) // 2. Optimize for the IM race. // Could optimize a lot more if we knew the burn chance formula // IMPORTANT: Due to the nature of the cooking time formula, the optimal cook weight is 14.38 // so recipes after ~15 start to get penalized. Time per ingredient is stable between 10-20, below // 10 it goes up dramatically, so avoid that region. // RECIPES (sweet spot is 70 or 80 with salt) // 1. 4 ichor (salt required) // 2. 4 ash 1 ichor // 3. 4 tuna + (salmon | trout | anchovy | shrimp) // 4. 2 tuna 2 shark // 5. 1 banana 4 apple } function CookChance(xp, elvl, clvl=0){ return Math.max(0, Math.min(1, (100 - 3*(xp/5)**(5/2)/elvl + 4*clvl)/100)); } function CookTime(size){ return 4**(0.95 + 0.05*size); } function daggersAndHoes(bars, dag, hoe) { // Assumption, Hoes are best, but only just, so we try for hoes // before daggers, but favor minimizing remaining bars over all else. let maxBig = Math.floor(bars/hoe); let hoeNots = 0 let left = 1e6 for( let s=0; s < maxBig+1; s++ ){ let leftovers = bars - hoe*(maxBig - s); let final = leftovers%dag if( final < left ){ left = final hoeNots = s } } let hoes = maxBig - hoeNots let daggers = Math.floor((bars - hoes*hoe)/dag) return [daggers, hoes] } // Helper functions to grab inventory function getReactInstance(dom) { for( let key in dom ) { if( key.startsWith("__reactInternalInstance$") ) { return dom[key]; } } return null; } function getReactHandler(dom) { for( let key in dom ){ if( key.startsWith("__react") ){ return dom[key]; } } return null; } function get(object, key, default_value) { var result = object[key]; return (typeof result !== "undefined") ? result : default_value; } function getSkills(){ let skills = ["miningHeader", "foragingHeader", "fishingHeader", "farmingHeader", "enchantingHeader", "runecraftingHeader", "smithingHeader", "craftingHeader", "cookingHeader", "constitutionHeader", "attackHeader", "strengthHeader", "defenseHeader"]; let skdict = {}; try { for(let sk=0; sk<skills.length; sk++){ let skill = document.getElementById(skills[sk]); let spans = skill.getElementsByTagName("span"); let name = spans[0].getElementsByTagName("b")[0].innerHTML; let xp = spans[2].innerHTML.replace(/\D/g,''); skdict[name] = xp; } } catch(err) {} return skdict; } function getInventory() { let inventory_set = document.getElementsByClassName("inventory-container-all-items")[0]; let dict = {}; try{ let inventory = inventory_set.getElementsByClassName("item"); for(let i=0; i<inventory.length; i++) { let itemdiv = inventory[i]; try { let k = getReactInstance(itemdiv); let item = k.return.pendingProps.item; let quant = k.return.pendingProps.quantity; dict[item.name] = quant; } catch(err){} } dict = sortObjectByKeys(dict); // Add heat and gold dict.Gold = getGold(); dict.Heat = getHeat(); let xp = getSkills(); for(let k in xp) { dict[k] = xp[k]; } dict.time = Date.now(); } catch(err){} return dict; } function dnum(num, p) { let snum = "" if( num > 1000000 ){ snum = `${(num/1e6).toFixed(p)} M` } else if( num > 1000 ){ snum = `${(num/1e3).toFixed(p)} k` } else{ snum = `${num}` } return snum } function numberWithCommas(x) { return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } function getGold(){ try { return parseInt(document.getElementById("gold-tooltip").getElementsByTagName("span")[0].innerHTML.replace(/,/g, "").replace(/\./g, "")); } catch(err){ return 0; } } function getHeat(){ try{ return parseInt(document.getElementById("heat-tooltip").getElementsByTagName("span")[0].innerHTML.replace(/,/g, "").replace(/\./g, "")); } catch(err){ return 0; } } function sortObjectByKeys(o){ return Object.keys(o).sort().reduce((r,k) => (r[k] = o[k], r), {}); } // Modal Settings (function() { var modal_css = document.createElement("style"); modal_css.innerHTML = ` .ps_settings { display: none; position: fixed; z-index: 9999; left: 0; top: 0; width: 100%; height: 100%; overflow: auto; background-color: rgb(0, 0, 0); background-color: rgba(0, 0, 0, 0.4); } .ps_settings_content { background-color: rgba(25, 66, 100, 0.90); border-radius: 5px; margin: 15% auto; padding: 20px; border: 1px solid #888; width: 80%; } .close_ps_settings { color: #aaa; float: right; font-size: 28px; font-weight: bold; } .close_ps_settings:hover, close_ps_settings:focus { color: black; text-decoration: none; cursor: pointer; } .ps_button { background-color:transparent; border-radius:4px; border:2px solid #7f7f7f; display:inline-block; cursor:pointer; color:#ffffff; padding:7px 25px; text-decoration:none; text-shadow:0px 1px 0px #e1e2ed; } .ps_button:hover { background-color:rgba(255,255,255,0); } .ps_button:active { position:relative; top:1px; } ` document.body.appendChild(modal_css); // Crafting button var craft_button = document.createElement("BUTTON"); craft_button.id = "craftingbtn"; craft_button.setAttribute("style", "position: absolute; top: 5px; left: 20%;"); craft_button.zIndex = "7000"; craft_button.className = "ps_button"; craft_button.innerHTML = "CraftXP"; craft_button.onclick = () => printCraftingXP(); document.body.appendChild(craft_button); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址