// ==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;
}
*/