您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Quality of Life tweaks for Diamond Hunt 2
// ==UserScript== // @name DH2QoL // @namespace https://greasyfork.org/ // @version 0.1.9 // @description Quality of Life tweaks for Diamond Hunt 2 // @author John // @match http://*.diamondhunt.co/game.php // @match https://*.diamondhunt.co/game.php // @run-at document-idle // @grant none // ==/UserScript== (function() { 'use strict'; const DEFAULT_CONFIG = { bool : { enhancedNotifications : { text : "Use persistent notifications with enhanced functionality?", value : true }, enableRightClickFurnaceRepeat : { text : "Enable right clicking bound furnace to repeat last action?", value : true }, enableBatchCommands : { text : "Enable batch commands (right click to cook all, eat all, brew all, craft all, etc)?", value : true }, disableUnequipInCombat : { text : "Disable unequip in combat?", value : true }, disableLeftClickSellGems : { text : "Disable selling gems on left click?", value : true }, disableLeftClickSellCraftingSupplies : { text : "Disable selling crafting supplies on left click?", value : true }, stardustMonitor : { text : "Use stardust monitor?", value : true }, updateOilTimer : { text : "Add oil timer & oil gains/consumption info?", value : true }/*, linkify : { text : "Make chat links clickable?", value : true }*/ }, enablePotionMonitor : true, enablePotionHelper : true, monitoredPotions : ["stardustPotion", "superStardustPotion"], }; const CONFIG = JSON.parse(window.localStorage.getItem("dh2qol-config")) || DEFAULT_CONFIG; const SMELTING = { lastCurrentAmount : -1, lastTimer : -1, lastRealTime : -1 }; const TREES = { "1" : { "id" : "1", "variable" : "tree", "name" : "Tree", "growTime" : 10800 // 3 hours }, "2" : { "id" : "2", "variable" : "oakTree", "name" : "Oak Tree", "growTime" : 21600 // 6 hours }, "3" : { "id" : "3", "variable" : "willowTree", "name" : "Willow Tree", "growTime" : 28800 // 8 hours }, "4" : { "id" : 4, "variable" : "mapleTree", "name" : "Maple Tree", "growTime" : 43200 // 12 hours }, "5" : { "id" : "5", "variable" : "stardustTree", "name" : "Stardust Tree", "growTime" : 57600 // 16 hours }, "6" : { "id" : 6, "variable" : "essenceTree", "name" : "Essence Tree", "growTime" : 72000 // 20 hours } }; const MONITORED_POTIONS = ["stardustPotion", "superStardustPotion"]; const STARDUST_MONITOR = { lastStardust : -1, monitorTicks : 0 }; (function init(triesLeft) { // Thanks /u/TheZorbing if (triesLeft > 0 && (!window.hasOwnProperty("webSocket") || window.webSocket.readyState !== WebSocket.OPEN || window.firstLoadGame === true)) { setTimeout(() => { init(--triesLeft); }, 100); return; } if (window.hasOwnProperty("webSocket") && window.webSocket.readyState === WebSocket.OPEN && !window.firstLoadGame) { console.log(`Launching DH2QoL. Welcome ${window.username}! Thanks for using DH2QoL`); processDormantTabsOnLoad(); try { if (CONFIG.bool.enableBatchCommands) { enableRightClickFurnaceRepeat(); //enableRightClickBrewAllPotion(); enableRightClickCookAllFood(); //enableRightClickEatAllFood(); //enableRightClickCraftAll(); } if (CONFIG.bool.disableUnequipInCombat) //disableUnequipInCombat(); if (CONFIG.bool.disableLeftClickSellCraftingSupplies) disableLeftClickSellCraftingSupplies(); if (CONFIG.bool.disableLeftClickSellGems) disableLeftClickSellGems(); } catch (e) { console.log("DH2QoL: Failed to implement some left and right click functionality to certain elements:"); console.log(e); } try { // Interface delight updateStyleSheets(); //addSettingsElement(); addNotificationElements(); addOilTimerElements(); addStardustMonitorElement(); } catch (e) { console.log("DH2QoL: Failed update the stylesheet and document with new notifications:"); console.log(e); } try { // Proxies proxyWebSocketOnMessage(); proxyAddToChatBox(); proxyConfirmDialogue(); proxyProcessWoodcuttingTab(); replaceDHNativeFormatTime(); } catch(e) { console.log("DH2QoL: Failed to proxy some functions:"); console.log(e); } } else { console.log(`Something went wrong, DH2QoL Failed to initialize. WebSockets: ${(window.hasOwnProperty("webSocket") && window.webSocket.readyState === WebSocket.OPEN)} First Load: ${window.firstLoadGame}`); } return; })(100); /* Actions performed following any game tick */ function postGameTick() { try {estimateSmeltingTimer();} catch (e) {console.log(e);} // This must come before smelting notification & timer updates try {updateNotificationElements();} catch (e) {console.log(e);} try { updateSmeltingTimer(); updateWoodcuttingTimers(); } catch (e) {console.log(e);} try {updateStardustMonitor();} catch (e) {console.log(e);} try {updateOilTimer()} catch (e) {console.log(e);} } /* Adds the DH2QoL settings button to the profile & settings page */ function addSettingsElement() { let node = document.getElementById("profile-toggleTable"); if (node && node.parentNode) { let span = document.createElement("span"); span.id = "dh2qol-settingsLink"; span.style.cursor = "pointer"; span.style.color = "white"; span.textContent = "Open DH2QoL Settings"; span.onclick = openSettings; node.parentNode.appendChild(document.createElement("br")); node.parentNode.appendChild(span); node.parentNode.appendChild(document.createElement("br")); } } function openSettings() { let newWindow = window.open(); newWindow.CONFIG = CONFIG; newWindow.document.title = "DH2QoL Settings"; newWindow.document.body.style.backgroundColor = "black"; newWindow.document.body.style.color = "white"; newWindow.document.body.innerHTML = `\<div> \<span style='font-size:22;'>DH2QoL Settings\</span>\<br> \<span>\<p>Most settings changes will require that Diamond Hunt be refreshed before taking effect. Clearing browser cache will reset settings to their default.\<p>\</span> \</div> \<div>`; const KEYS = Object.keys(newWindow.CONFIG.bool); KEYS.forEach((key) => { newWindow.document.body.innerHTML += `\<p> \<input type="checkbox" id="checkbox-${key}" checked="${newWindow.CONFIG.bool[key].value}" onchange="changeBoolSetting('${key}', this.checked);"> \<label for="checkbox-${key}">${newWindow.CONFIG.bool[key].text}\</label> \</p>` }); newWindow.document.body.innerHTML += `\</div>`; newWindow.changeBoolSetting = function(settingPropertyName, val) { if (newWindow.CONFIG && newWindow.CONFIG.bool[settingPropertyName]) { newWindow.CONFIG.bool[settingPropertyName].value = val; } }; newWindow.saveSettings = function() { newWindow.close(); }; } /* Loads initial data for unopened tabs */ function processDormantTabsOnLoad() { window.processCraftingTab(); window.processBrewingTab(); } /* Update the game-main-style.css styleSheet Delete then update the span.notif-box rule, and add our dhqol-notif-ready rule */ function updateStyleSheets() { for (let styleSheet of document.styleSheets) { if (styleSheet.href && styleSheet.href.indexOf("game-main-style.css") !== -1) { if (styleSheet.cssRules) { for (let index in styleSheet.cssRules) { let cssRule = styleSheet.cssRules[index]; if (cssRule.selectorText && cssRule.selectorText.indexOf("span.notif-box") !== -1) { styleSheet.deleteRule(index); // Delete the original span.notif-box rule styleSheet.insertRule(`span.notif-box { display:inline-block; margin:5px 5px 5px 0px; color:white; border:1px solid silver; padding:5px 10px; font-size:12pt; background: -webkit-linear-gradient(#801A00, #C15033); /* For Safari 5.1 to 6.0 */ background: -o-linear-gradient(#801A00, #C15033); /* For Opera 11.1 to 12.0 */ background: -moz-linear-gradient(#801A00, #C15033); /* For Firefox 3.6 to 15 */ background: linear-gradient(#801A00, #C15033); /* Standard syntax */ }`, 0); styleSheet.insertRule(`span.dhqol-notif-ready { display:inline-block; margin:5px 5px 5px 0px; color:white; border:1px solid silver; padding:5px 5px; font-size:12pt; cursor:pointer; background: -webkit-linear-gradient(#801A00, #C15033); background: -o-linear-gradient(#801A00, #C15033); background: -moz-linear-gradient(#801A00, #C15033); background: linear-gradient(#161618, #48ab32); }`, 0); } } } break; } } } /* Create and add our custom DH2QoL persistent notification elements to the document */ function addNotificationElements() { const SPAN = document.createElement("span"); SPAN.className = "dhqol-notif-ready"; SPAN.style = "display:inline-block"; SPAN.appendChild(document.createElement("img")); SPAN.children[0].className = "image-icon-50"; SPAN.appendChild(document.createElement("span")); let notificationNode = document.getElementById("notifaction-area"); let refNode = notificationNode.children[0] || null; // Create our new notification span elements let furnaceElement = SPAN.cloneNode(true); furnaceElement.id = "dhqol-notif-furnace"; furnaceElement.children[0].setAttribute("src", "images/silverFurnace.png"); let woodCuttingElement = SPAN.cloneNode(true); woodCuttingElement.id = "dhqol-notif-woodcutting"; woodCuttingElement.children[0].setAttribute("src", "images/icons/woodcutting.png"); let farmingElement = SPAN.cloneNode(true); farmingElement.id = "dhqol-notif-farming"; farmingElement.children[0].setAttribute("src", "images/icons/watering-can.png"); let combatElement = SPAN.cloneNode(true); combatElement.id = "dhqol-notif-combat"; combatElement.children[0].setAttribute("src", "images/icons/combat.png"); let rowBoatElement = SPAN.cloneNode(true); rowBoatElement.id = "dhqol-notif-rowboat"; rowBoatElement.children[0].setAttribute("src", "images/rowBoat.png"); let canoeElement = SPAN.cloneNode(true); canoeElement.id = "dhqol-notif-canoe"; canoeElement.children[0].setAttribute("src", "images/canoe.png"); let vialElement = SPAN.cloneNode(true); vialElement.id = "dhqol-notif-vial"; vialElement.children[0].setAttribute("src", "images/vialOfWater.png"); vialElement.setAttribute("onclick", "window.openTab('brewing');"); /* vialElement.oncontextmenu = function() { drinkMonitoredPotions(); return false; }; */ // Insert our new elements into the document notificationNode.insertBefore(furnaceElement, refNode); notificationNode.insertBefore(woodCuttingElement, refNode); notificationNode.insertBefore(farmingElement, refNode); notificationNode.insertBefore(combatElement, refNode); notificationNode.insertBefore(rowBoatElement, refNode); notificationNode.insertBefore(canoeElement, refNode); notificationNode.insertBefore(vialElement, refNode); } function updateNotificationElements() { // Hide native DH2 notifications const NOTIFICATION_IDS = ["notification-static-farming", "notification-static-woodcutting", "notification-static-combat", "notif-smelting", "notif-rowBoatTimer", "notif-canoeTimer"]; NOTIFICATION_IDS.forEach((id) => { let node = document.getElementById(id); if (node) node.style.display = "none"; }); // Update DH2QoL Custom notifications based on gamestate let furnaceElement = document.getElementById("dhqol-notif-furnace"); furnaceElement.style.display = window.craftingUnlocked == 1 ? "inline-block" : "none"; if (window.smeltingBarType == 0) { furnaceElement.className = "dhqol-notif-ready"; furnaceElement.children[0].setAttribute("src", "images/silverFurnace.png"); furnaceElement.children[1].textContent = ""; furnaceElement.onclick = function() { window.openTab("crafting"); if (getBoundFurnace() !== "") { window.openFurnaceDialogue(getBoundFurnace()); } }; furnaceElement.oncontextmenu = function() { furnaceRepeat(); return false; }; } else { furnaceElement.className = "notif-box"; furnaceElement.children[0].setAttribute("src", `images/${window.getBarFromId(window.smeltingBarType)}.png`); furnaceElement.children[1].textContent = `${formatTime(SMELTING.lastTimer / 1000)} (${window.smeltingPerc}%)`; furnaceElement.setAttribute("onclick", ""); } let woodCuttingElement = document.getElementById("dhqol-notif-woodcutting"); woodCuttingElement.style.display = window.woodcuttingUnlocked == 1 ? "inline-block;" : "none"; if (window.treeStage1 == 4 || window.treeStage2 == 4 || window.treeStage3 == 4 || window.treeStage4 == 4 || window.treeStage5 == 4 || window.treeStage6 == 4) { woodCuttingElement.className = "dhqol-notif-ready"; woodCuttingElement.children[1].textContent = ""; woodCuttingElement.setAttribute("onclick", "window.openTab('woodcutting')"); /* woodCuttingElement.oncontextmenu = function() { harvestTrees(); return false; }; */ } else { let gt = getSoonestWoodcuttingTimer(); woodCuttingElement.className = "notif-box"; woodCuttingElement.children[1].textContent = gt === null ? "" : formatTime(gt); woodCuttingElement.setAttribute("onclick", ""); } let farmingElement = document.getElementById("dhqol-notif-farming"); farmingElement.style.display = window.farmingUnlocked == 1 ? "inline-block" : "none"; if (window.farmingPatchStage1 == 0 || window.farmingPatchStage1 == 4 || window.farmingPatchStage2 == 0 || window.farmingPatchStage2 == 4 || window.farmingPatchStage3 == 0 || window.farmingPatchStage3 == 4 || window.farmingPatchStage4 == 0 || window.farmingPatchStage4 == 4 || (window.donorFarmingPatch >= window.currentTimeMillis && (window.farmingPatchStage5 == 0 || window.farmingPatchStage5 == 4 || window.farmingPatchStage6 == 0 || window.farmingPatchStage6 == 4))) { farmingElement.className = "dhqol-notif-ready"; farmingElement.setAttribute("onclick", "openTab('farming')"); farmingElement.children[1].textContent = ""; farmingElement.oncontextmenu = function() { if (window.planter == 1) { window.openFarmingPatchDialogue(-1); return false; } }; } else { farmingElement.className = "notif-box"; farmingElement.setAttribute("onclick", ""); farmingElement.children[1].textContent = formatTime(getSoonestFarmingTimer()); } let combatElement = document.getElementById("dhqol-notif-combat"); combatElement.style.display = window.combatUnlocked == 1 ? "inline-block" : "none"; if (window.combatGlobalCooldown == 0) { combatElement.className = "dhqol-notif-ready"; combatElement.children[1].innerHTML = '<img src="images/steak.png" style="" class="image-icon-15">' + parseInt(window.energy, 10).toLocaleString("en-US"); combatElement.setAttribute("onclick", "window.openTab('combat'); window.openFightMenu()"); } else { combatElement.className = "notif-box"; combatElement.children[1].innerHTML = formatTime(window.combatGlobalCooldown); combatElement.setAttribute("onclick", ""); } let rowBoatElement = document.getElementById("dhqol-notif-rowboat"); let canoeElement = document.getElementById("dhqol-notif-canoe"); // Only display one notification if a boat is at sea since you can only send out 1 boat rowBoatElement.style.display = window.boundRowBoat == 0 ? "none" : window.boundCanoe == 0 || window.canoeTimer == 0 ? "inline-block" : "none"; canoeElement.style.display = window.boundCanoe == 0 ? "none" : window.boundRowBoat == 0 || window.rowBoatTimer == 0 ? "inline-block" : "none"; if (window.rowBoatTimer == 0) { rowBoatElement.className = "dhqol-notif-ready"; rowBoatElement.children[1].innerHTML = '<img class="image-icon-15" src="images/fishingBait.png">' + window.fishingBait; rowBoatElement.setAttribute("onclick", "window.clicksBoat('rowBoat')"); } else { rowBoatElement.className = "notif-box"; rowBoatElement.children[1].innerHTML = formatTime(window.rowBoatTimer); rowBoatElement.setAttribute("onclick", "w"); } if (window.canoeTimer == 0) { canoeElement.className = "dhqol-notif-ready"; canoeElement.children[1].innerHTML = '<img class="image-icon-15" src="images/fishingBait.png">' + window.fishingBait; canoeElement.setAttribute("onclick", "window.clicksBoat('canoe')"); } else { canoeElement.className = "notif-box"; canoeElement.children[1].innerHTML = formatTime(window.canoeTimer); canoeElement.setAttribute("onclick", ""); } processPotionHelper(); } function processPotionHelper() { let potions = getMonitoredPotionsToDrink(); let vialElement = document.getElementById("dhqol-notif-vial"); vialElement.style.display = (window.brewingUnlocked == 1 ? (potions.length > 0 ? "inline-block" : "none") : "none"); } function getMonitoredPotionsToDrink() { let potions = []; MONITORED_POTIONS.forEach((monitoredPotion) => { if (window[monitoredPotion] > 0 && (window[monitoredPotion + "Timer"] !== undefined && window[monitoredPotion + "Timer"] == 0)) { potions.push(monitoredPotion); } }); return potions; } function drinkMonitoredPotions() { let timeout = 0; MONITORED_POTIONS.forEach((monitoredPotion) => { if (window[monitoredPotion] > 0 && (window[monitoredPotion + "Timer"] !== undefined && window[monitoredPotion + "Timer"] == 0)) { setTimeout(() => { if (window[monitoredPotion + "Timer"] !== undefined && window[monitoredPotion + "Timer"] == 0) window.sendBytes("DRINK=" + monitoredPotion); }, timeout * 500); timeout++; } }); } function addStardustMonitorElement() { let sdNode = document.querySelector("[data-item-display=stardust]"); if (sdNode) { let parentNode = sdNode.parentNode; if (parentNode) { let newNode = document.createElement("span"); newNode.id = "dh2qol-stardustMonitor"; newNode.style.color = "orange"; parentNode.appendChild(newNode); } } } function updateStardustMonitor() { let node = document.getElementById("dh2qol-stardustMonitor"); if (node) { if (STARDUST_MONITOR.lastStardust !== -1 && window.stardust > STARDUST_MONITOR.lastStardust) { node.textContent = `(+${window.stardust - STARDUST_MONITOR.lastStardust})`; STARDUST_MONITOR.lastStardust = window.stardust; STARDUST_MONITOR.monitorTicks = 5; } else if (STARDUST_MONITOR.lastStardust == window.stardust && STARDUST_MONITOR.monitorTicks > 0) { STARDUST_MONITOR.monitorTicks--; } else { node.textContent = ""; STARDUST_MONITOR.lastStardust = window.stardust; } } } function harvestTrees() { for (let i = 1; i <= 6; i++) { if (window["treeStage" + i] == 4) { setTimeout(() => { window.sendBytes("CHOP_TREE=" + i); }, i * 250); } } window.processWoodcuttingTab(); } function enableRightClickFurnaceRepeat() { let nodes = document.querySelectorAll("[onclick^=openFurnaceDialogue]"); nodes.forEach((node) => { if (node instanceof Node) { node.oncontextmenu = function() { let amt = document.getElementById("input-smelt-bars-amount").value; if (window.smeltingBarType == 0 && amt > 0 && window.selectedBar !== "none") { window.smelt(amt); } return false; }; } }); } function furnaceRepeat() { let amt = document.getElementById("input-smelt-bars-amount").value; if (window.smeltingBarType == 0 && amt > 0 && window.selectedBar !== "none") { window.smelt(amt); } } function enableRightClickBrewAllPotion() { const KEYS = Object.keys(window.brewingRecipes); KEYS.forEach((key) => { if (key === "stardustCrystalPotion") { return; } let recipe = window.brewingRecipes[key]; let node = document.getElementById("brewing-" + key); if (node) { node.oncontextmenu = () => { let vials = window.vialOfWater; let total = vials; for (let i = 0; i < recipe.recipe.length; i++) { total = (total <= Math.floor(window[recipe.recipe[i]] / recipe.recipeCost[i])) ? total : Math.floor(window[recipe.recipe[i]] / recipe.recipeCost[i]); } if (total > 0) { window.sendBytes(`BREW=${recipe.itemName}~${total}`); // Adds existing left click functionality to right click of the element window.processBrewingTab(); } return false; }; } }); } function enableRightClickCookAllFood() { document.querySelectorAll("[onclick^=cookFoodDialogue]").forEach((foodNode) => { let food = foodNode.id.indexOf("item-box-") != -1 && foodNode.id.split("item-box-")[1]; if (food !== -1) { foodNode.oncontextmenu = function() { let amt = Math.min(Math.floor(window.ovenHeat/window.getHeatNeeded(food)), window[food]); if (amt > 0) { window.cook(food, amt); } return false; }; } }); } function enableRightClickEatAllFood() { document.querySelectorAll("[onclick^=eatFood]").forEach((foodNode) => { let food = foodNode.id.indexOf("item-box-") != -1 && foodNode.id.split("item-box-")[1]; if (food !== -1) { foodNode.oncontextmenu = function() { window.sendBytes(`CONSUME=${food}~${window[food]}`); // Adds existing left click functionality to right click of the element return false; }; } }); } function enableRightClickCraftAll() { let node = document.getElementById("crafting-vialOfWater"); if (node) { node.oncontextmenu = function() { let amt = Math.floor(window.glass / 5); if (amt > 0) { window.sendBytes("MULTI_CRAFT=vialOfWater~" + amt); } return false; }; } } function disableLeftClickSellGems() { document.getElementById("item-box-sapphire").onclick = null; document.getElementById("item-box-emerald").onclick = null; document.getElementById("item-box-ruby").onclick = null; document.getElementById("item-box-diamond").onclick = null; document.getElementById("item-box-bloodDiamond").onclick = null; } function disableLeftClickSellCraftingSupplies() { let node = document.getElementById("tab-sub-container-crafting"); if (node) { node.querySelectorAll("[onclick^=openSellNPCDialogue]").forEach((n) => { n.onclick = null; }); } } function disableUnequipInCombat() { let node = document.querySelector("[class=imageHero]"); if (node && node.parentNode) { node.parentNode.onclick = function() { if (!window.isInCombat()) { window.sendBytes("UEQUIP_H"); // This is just overwriting existing functionality with the same functionality but with added restrictions (cannot be in combat) } }; } } function getBoundFurnace() { let furnace = ""; [].slice.call(document.querySelectorAll("[onclick^=openFurnaceDialogue]")).some((node) => { let boundFurnace = node.id.indexOf("item-box-bound") !== -1 && node.id.split("item-box-")[1]; if (window[boundFurnace] > 0) { furnace = boundFurnace; return true; } return false; }); return furnace; } function getOilCapacity() { return window.maxOil; } function getCurrentOil() { return window.oil; } function getNetOilConsumption() { return window.oilIn - window.oilOut; } /***** * * F U N C T I O N P R O X I E S * *****/ function proxyWebSocketOnMessage() { const PROXY = window.webSocket.onmessage; window.webSocket.onmessage = function(e) { PROXY.apply(this, arguments); postGameTick(); }; } function proxyAddToChatBox() { const PROXY = window.addToChatBox; window.addToChatBox = function(username, icon, tag, message, isPM) { //arguments[3] = linkify(arguments[3]); PROXY.apply(this, arguments); }; } function proxyConfirmDialogue() { const PROXY = window.confirmDialogue; window.confirmDialogue = function(width, bodyText, buttonText1, buttonText2, sendBytes) { PROXY.apply(this, arguments); }; } function proxyProcessWoodcuttingTab() { const PROXY = window.processWoodcuttingTab; window.processWoodcuttingTab = function() { PROXY.apply(this, arguments); // Immediately updates woodcutting timers upon opening/processing the tab to prevent sudden change of format a second after opening the tab updateWoodcuttingTimers(); }; } /***** * * T I M E R S & F O R M A T I N G * *****/ /* Check if a string of text can be a URL */ function isLink(text) { return text.test(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig); } /* Make links clickable No longer needed as it is finally DH Native */ /*function linkify(text) { return text.replace(/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig, "<a href='$1' target='_blank'>$1</a>"); }*/ function padLeft(value, padChar, length) { value = value.toString(); padChar = padChar.toString(); return value.length < length ? padLeft(padChar + value, padChar, length) : value; } /* Formats a time (in seconds) as hh:mm:ss or mm:ss if no hours */ function formatTime(secs) { let seconds = Math.round(secs % 60); let minutes = Math.floor((secs % 3600) / 60); let hours = Math.floor(secs / 3600); return `${hours > 0 ? padLeft(hours, 0, 2) + ":" : ""}${padLeft(minutes, 0, 2)}:${padLeft(seconds, 0, 2)}`; } /* Overwrite Diamond Hunt 2's native formatTime functions with our own to achieve nicely formatted timers with no hassle */ function replaceDHNativeFormatTime() { window.formatTime = formatTime; window.formatTimeShort = formatTime; window.formatTimeShort2 = formatTime; } /* Adds and updates a smelting timer */ function updateSmeltingTimer() { let node = document.getElementById("notif-smelting"); if (node && node.children.length > 1) node.children[1].textContent = `${formatTime(SMELTING.lastTimer / 1000)} (${window.smeltingPerc}%)`; } /* Tries to estimate smelting time remaining based on the time it takes to smelt a bar and the real time elapsed between each barType Times are converted to milliseconds for increased accuracy */ function estimateSmeltingTimer() { let smeltingTotalAmount = window.smeltingTotalAmount; let smeltingCurrentAmount = window.smeltingAmount; let smeltingTotalTime = window.smeltingPercD * 1000; let barType = window.smeltingBarType; let now = Date.now(); if (barType > 0) { let barTime = window.getTimerPerBar(window.getBarFromId(barType)); let roughTimeElapsed = (smeltingCurrentAmount * barTime) * 1000; if (SMELTING.lastCurrentAmount === smeltingCurrentAmount) { // Number of bars smelted hasn't changed so we'll use time-based estimations SMELTING.lastTimer = SMELTING.lastTimer - (now - SMELTING.lastRealTime); SMELTING.lastRealTime = now; } else { // Number of bars smelted HAS changed so we'll use a rough estimate of time remaining based on time to smelt each bar SMELTING.lastCurrentAmount = smeltingCurrentAmount; SMELTING.lastTimer = Math.max(smeltingTotalTime - roughTimeElapsed, 0); SMELTING.lastRealTime = now; } } else { // Reset everything since nothing is being smelted SMELTING.lastCurrentAmount = -1; SMELTING.lastTimer = -1; SMELTING.lastRealTime = -1; } } /* Adds and updates a woodcutting timers */ function updateWoodcuttingTimers() { // Update DH2 native woodcutting timers for (let i = 1; i <= 6; i++) { let node = document.getElementById("wc-div-tree-lbl-" + i); if (node) { if (window["treeUnlocked" + i] === 0) { node.style.color = "brown"; node.textContent = "(Locked)"; } else { node.textContent = window["treeStage" + i] == 0 ? "Waiting for tree to spawn..." : (window["treeStage" + i] == 4 ? `Ready To Harvest ${getTreeGrowingName(i)}!` : `${getTreeGrowingName(i)}: ${formatTime(getTreeGrowingTimer(i))}`); } } } } function getTreeGrowingTimer(patch) { let treeId = window["treeId" + patch]; return Math.max(window.TREE_GROW_TIME[(treeId-1)] - window["treeGrowTimer" + patch], 0); } function getTreeGrowingName(patch) { let treeId = window["treeId" + patch]; return (TREES[treeId] && TREES[treeId].name) || window.getTreeName(treeId); } /* Returns the first upcoming woodcutting timer */ function getSoonestWoodcuttingTimer() { let timer = null; for (let i = 1; i <= 6; i++) { if (window["treeId" + i] != 0 && TREES[window["treeId" + i]] !== undefined) { let gt = TREES[window["treeId" + i]].growTime - window["treeGrowTimer" + i]; timer = timer === null ? gt : gt < timer ? gt : timer; } } return timer; } /* Returns the first upcoming farming timer */ function getSoonestFarmingTimer() { let timer = null; for (let i = 1; i <= (window.donorFarmingPatch > currentTimeMillis ? 6 : 4); i++) { let gt = window["farmingPatchGrowTime" + i] - window["farmingPatchTimer" + i]; timer = timer === null ? gt : gt < timer ? gt : timer; } return timer; } /* Adds an oil timer & net oil consumption element */ function addOilTimerElements() { let oilFlowNode = document.getElementById("oil-flow-values"); let netConsumptionNode = document.createElement("SPAN"); netConsumptionNode.id = "dh2qol-oilNetConsumption"; netConsumptionNode.style.color = "yellow"; let oilTimerNode = document.createElement("SPAN"); oilTimerNode.id = "dh2qol-oilTimer"; oilTimerNode.style.color = "orange"; if (oilFlowNode && oilFlowNode.parentNode) { let parent = oilFlowNode.parentNode; parent.appendChild(netConsumptionNode); parent.appendChild(oilTimerNode); } } /* Updates the oil timer & net oil consumption elements */ function updateOilTimer() { let netConsumptionNode = document.getElementById("dh2qol-oilNetConsumption"); let oilTimerNode = document.getElementById("dh2qol-oilTimer"); if (netConsumptionNode && oilTimerNode) { netConsumptionNode.textContent = ` (${getNetOilConsumption() > 0 ? "+" + getNetOilConsumption() : getNetOilConsumption()})`; oilTimerNode.textContent = getOilTimer(); } } /* Calculates and formats an oilTimer based on oil, capacity, and consumption */ function getOilTimer() { let consumption = getNetOilConsumption(); let capacity = getOilCapacity(); let oil = getCurrentOil(); if (consumption == 0) { return ``; } else if (consumption > 0) { // Despite the poorly labeled variable, consumption greater than 0 means we're producing a net positive amount of oil return ` (${formatTime((capacity - oil) / consumption)})`; } else { // Consuming more than producing consumption = Math.abs(consumption); return ` (${formatTime(oil / consumption)})`; } } })(); /* function proxyWebsocketSend() { const PROXY = window.webSocket.send; window.webSocket.send = function send() { console.log(send.caller); PROXY.apply(this, arguments); }; } */ /* //For the future function Command() { let fncCaller; const PROXY = window.webSocket.send; window.webSocket.send = function send() { // If we attempt to load the market tab, log the function that calls WebSocket#send if (arguments[0] === "OPEN_MARKET_TAB") { fncCaller = send.caller; // We got it boys! return; // Don't actually send the command to the server because 'muh automation' } PROXY.apply(this, arguments); // Pretend like nothing ever happened } // Probe the playermarket to trigger a legitimate server call (but we won't actually send it!) and log the calling function window.processTab("playermarket"); // Return WebSocket#send to normal window.webSocket.send = PROXY; this.send = fncCaller || webSocket.send; this.chopTree; } */