您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Quality of Life changes for Diamond Hunt Online
当前为
// ==UserScript== // @name DHQoL // @namespace http://tampermonkey.net/ // @version 1.6 // @description Quality of Life changes for Diamond Hunt Online // @author John / WhoIsYou // @match http://*.diamondhunt.co/game.php // @match https://*.diamondhunt.co/game.php // @run-at document-idle // @grant none // ==/UserScript== /* jshint -W097 */ 'use strict'; /** FEATURES: - Clickable links in chat! Very simple regex pattern that won't catch ALL links, but it will catch the majority / common formats - Market exclusion list, to filter out users you don't like or don't want to see (such as justanoob) - Serves little purpose now do to recent updates - Market clutter remover, only shows the 5 first/cheapest listings for any single item, not counting your own items - Market inclusion list, doesn't count any offers by these users in the 5 offer limit per item (always shows these people's items) - Rocket timer that's fairly accurate (though RNG based) based on average distances traveled per second found via logging - Furnace timer (accurate) in addition to the percentage. Bar type text removed and iron furnace image replaced with current item being smelted - Improved timers for large fishing boat, fishing boat, rocket, robot, furnace, exploring, potions, farming (only if you have the donor perk), spells, and ancient crystal in the HH:MM:SS format - Farming, Furnace, and Exploring timers factor in the donor perks if you have them, giving much more accurate timers than the default (though farming is still slightly RNG based) - Prevents the selling of brewing ingredients in the brewing tab - Added indicators that let you know when you have Explorer's Potions or Artifact Potions active - Improved functionality for converting your coins to plat and plat to coins (left click them) - Removed binding of equal or lower tier furnaces and ovens if you have promethium or higher bound - Added the ability to craft multiple rocket fuel barrels, activate with 200m+ oil if you have an oil refinery, or 100m+ without, otherwise it crafts 1 per click like normal - Wealth Evaluator found under key items, click it to evaluate the value of all of your tradable items based on market prices - Added the ability to use "k" or "b" in market prices when listing an item as shorthand for "thousands" and "billions" respectively ("m" for millions exists) - Chat spam filter, filters out spammers, and automatically mutes and reports the worst offenders - PM viewing mode for the chatbox so you don't have to scroll up to see old PMs - Spoiler tagged answers for treasure maps - Market min and max prices in item tooltips - Limits the amount of items sold to the NPC shop in one go to prevent accidentally selling over max coins worth **/ /** CHANGELOG: v1.6 (Aug 29 2016) - Updated spam filter, it is slightly less forgiving, should now properly reports spammers, and alerts you when it mutes a player - Added market min and max prices to the tooltips of all tradable items - Added (spoiler tagged) answers to treasure maps - Selling items to the NPC shop (left or right click) will limit the amount sold up to max coins worth (2147483647) to prevent accidental loss of wealth - Fixed oven binding to account for tier changes, added runite furnace - Updated timers for engineering potions and super excavators spell - Added timer formatting for the large fishing boat - Fixed farming timer to no longer calculate the donor gardener perk since it has been changed to apply at plant time - Removed obsolete features (using "m" in market prices added to the game) v1.5 (Feb 22 2016) - Removed chatbox darkmode for now, since GM storage messes up FireFox support v1.4 (Feb 20 2016) - Added a wealth evaluator, accessible from your key items - Added a spam filter to the chat - Improved furnace timer to take the donator perk into account more accurately - Delay for multiple rocket fuel barrel crafting doubled to avoid issues - Added the ability to use "k" or "b" in market prices when listing an item as shorthand for "thousands" and "billions" respectively ("m" for millions exists) - Added a toggleable darkmode to the chatbox - Added a tab to the chatbox that only displays private messages, sent and received - Market exclusion list cleared as it no longer serves a purpose v1.3b: (Feb 1 2016) - Fixed FireFox support by switching to @grant none, instead of unsafeWindow v1.3: (Feb 1 2016) - Improved coin swapping functionality, left click coins to convert to plat, left click plat to convert to coins - Dialog asking how many rocket fuel barrels you would like to craft if you're above a certain oil threshold, otherwise it crafts one like normal - Removed the ability to bind equal or lower tier ovens and furnaces if you have promethium or higher bound - Added users "faggots" and "nogresh" to the market exclusions list (they don't seem to play anymore) - Added formatting for magic spell timers - Added formatting for ancient crystal timer - Restructured some code v1.2a: (Jan 13 2016) - Updated code structure a little (not done yet) - Added timer formatting for the new fishing boat - Made items in the brewing tab unsellable on left click (req: https://redd.it/40uw3m) v1.1a: (Jan 8 2016) - Fixed furnace timer, no longer performs additional calculations for donator perk (this was default behaviour!) v1.0: (Jan 8 2016) - Release **/ var config = { ENABLE_LOGGING : true }; // Array of potions that use timers var TIMED_POTION_LIST = ["starDustPotion", "seedPotion", "smeltingPotion", "oilPotion", "miningPotion", "superStarDustPotion", "coinPotion", "compost", "engineeringPotion", "fishingPotion", "essencePotion", "fastFurnacePotion", "superOilPotion", "megaStarDustPotion", "whaleFishingPotion", "megaOilPotion"]; // Array of spells that use timers var TIMED_SPELL_LIST = ["superDrills", "superGemFinder", "smallSips", "superPirate", "superCrushers", "sparklingCompostPotion", "superGiantDrills", "fastVendor", "superRoadHeaders", "animatedAxe", "superExcavatorsTimer"]; // Users to be excluded from the market listing var MARKET_EXCLUSION_LIST = []; // Users to always be included in the market listing, useful if you have a habit of trading with a specific person var MARKET_INCLUSION_LIST = ["whoisyou"]; // Because I can // Chatbox darkmode variables var chatboxDarkModeEnabled = false //GM_getValue("chatboxDarkModeEnabled", false); // Defaults to false if not set var modChatColor = "#669999"; var modChatDarkModeColor = "#44b9dc"; // Chat filter object, dynamically stores info on all chatting players to be checked against our spam filter var chatFilter = { }; // Immediately-invoked function expression (IIFE), runs once on page load (function() { cLog("Launching DH QoL! Welcome, " + window.username + "."); // Create new notification boxes for artifact and explorer's potions createNotificationBoxes(); // Disable the selling of brewing items disableBrewingItemSelling(); // Improve the coin swapping functionality when clicking on coin icons improveCoinSwap(); // Adds the ability to craft multiple rocket fuel barrels setCraftMultipleRocketFuel(); // Adds the wealth evaluator to key items addWealthEvaluator(); // Make the new private chat tab in the chat makePrivateChatTab(); // Create the chatbox darkmode toggle button and set the chatbox to darkmode if the setting is saved as on /*createDarkModeToggleButton(); if (chatboxDarkModeEnabled === true) { setChatboxDarkMode(); }*/ // Update tooltips updateTooltips(); // Remove the ability to bind furnaces and ovens if you have higher tier ones setTimeout(disableBindFurnacesAndOvens, 3000); // 3 second delay after page loads so our variables (such as bound items) can load from ajax requests })(); /* --- Market --- */ /* Make changes to #loadOffers to filter out unwanted market items from the market table Filters out any users in our MARKET_EXCLUSION_LIST and filters out all but the cheapest 5 offers for any item (your own items do not count towards this limit) Items in the MARKET_INCLUSION_LIST will always be shown even if they are not among the cheapest 5 */ window.loadOffers = function(unparsedData) { var lastItem = ""; var lastItemCount = ""; var dataArray = unparsedData.split("~"); var table = document.getElementById("market-buy-table"); resetGEBox(1); resetGEBox(2); resetGEBox(3); table.innerHTML = "<tr class='table-th'><th>Player</th><th>Item</th><th>Icon</th><th>Amount</th><th>Price each</th></tr>"; for(var i = 0; i < dataArray.length; i++) { var playerId = dataArray[i]; i++; var playerUsername = dataArray[i]; i++; var item = dataArray[i];i++; var total = dataArray[i];i++; var pricePer = dataArray[i];i++; var collect = dataArray[i];i++; var slot = dataArray[i];i++; var isPlatinum = dataArray[i];i++; var category = dataArray[i]; // Loads the items we're selling into our collection boxes if(playerUsername == username) { loadGEBoxSelling(item + "~" + total + "~" + pricePer + "~" + collect, slot); } // Adds offers to the market table as long as they're not in the excluded users list // Keeps tracks of how many offers exist for each individual type of item and only displays the first (cheapest) five not counting our own items if(total > 0 && MARKET_EXCLUSION_LIST.indexOf(playerUsername) < 0) { if (window.username != playerUsername && MARKET_INCLUSION_LIST.indexOf(playerUsername) < 0) { if (item == lastItem) { if (lastItemCount >= 5) { continue; } else { lastItemCount += 1; } } else { lastItem = item; lastItemCount = 1; } } // Adds any items that made it through the filter to the market table applyToBuyingTable(playerId, playerUsername, item, total, pricePer, slot, isPlatinum, category); } } };; /* Allows you to use "k" in the item price as an assignment for thousands *** OBSOLETE Allows you to use "m" in the item price as an assignment for thousands *** OBSOLETE Allows you to use "b" in the item price as an assignment for billions */ /* var originalSellOnGE = window.sellOnGE; window.sellOnGE = function(amount, pricePer) { //pricePer = (pricePer.indexOf("k") >= 0 ? (pricePer.replace("k", "") * 1000).toString() : pricePer.toString()); //pricePer = (pricePer.indexOf("m") >= 0 ? (pricePer.replace("m", "") * 1000000).toString() : pricePer.toString()); pricePer = (pricePer.indexOf("b") >= 0 ? (pricePer.replace("b", "") * 1000000000).toString() : pricePer.toString()); originalSellOnGE(amount, pricePer); }; */ /* Updates the quickSell (right click an item) function to only sell up to max coins worth of the item to prevent loss */ window.quickSell = function(id) { var itemName = id.split("-")[1]; var price = getItemPrice(itemName); var amount = price > 0 ? Math.min(Math.floor(2147483647/price), window[itemName]) : 0; send("SELL=" + itemName + ";" + amount); } /* Updates the sell top NPC shop function to only sell up to max coins worth of the item to prevent loss */ window.sell = function(itemName, amount) { var price = getItemPrice(itemName); var amt = price > 0 ? Math.min(Math.floor(2147483647/price), window[itemName]) : amount; send("SELL=" + itemName + ";" + amt); } /* --- Chat --- */ /* Hold the original #refreshChat function before any changes are made to it */ var originalRefreshChat = window.refreshChat; /* Make links in chat clickable, not 100% perfect regex pattern but it gets the job done */ function linkify(text) { text = text || ""; var pattern = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; text = text.replace(pattern, "<a href='$1' target='_blank'>$1</a>"); return text; } /* Allows you to click a player's name in chat to autofill "/pm username " in the text box Additionally, highlights your name in chat as red so you can easily find your own messages *********Unused, interferes with other name formatting (mods and such) */ function setClickNameToPM(text) { var indices = [text.indexOf("~"), text.indexOf(" ")]; var iconSplit = text.split("~"); if (iconSplit.length > 1) { var nameSplit = iconSplit[1].split(" "); if (nameSplit.length > 1) { var playerName = nameSplit[0]; console.log(text); console.log(playerName); // Strips additional tags from playernames if (playerName.startsWith("!!!yell")) { playerName = playerName.slice(7); } if (playerName.startsWith("!!!smitty")) { playerName.slice(3); } if (playerName.startsWith("|") || playerName.startsWith("*")) { playerName = playerName.slice(1); } // Adds our new element around playernames, including highlighting for your own name, and autofill PM on click for others var span = ""; if (playerName === window.username) { span = "<span style='color:red;'>" + playerName + "</span>"; } else { span = "<span onclick='\ var node = document.getElementById(\"textbox-chat\");\ if (node) {node.value = \"/pm " + playerName +" \";}'>" + playerName + "</span>"; } text = text.replace(playerName, span); } } return text; } /* Creates a private chat tab in the chatbox, and a new button to toggle it */ function makePrivateChatTab() { // Make the private chat tab var node = document.getElementById("chat-area-div"); if (node) { var newNode = node.cloneNode("false"); newNode.id = "chat-area-pm-div"; newNode.innerHTML = "[PM Mode] Thanks for using Diamond Hunt QoL by WhoIsYou!<br><br>"; newNode.style.display = "none"; var parentNode = node.parentNode; parentNode.insertBefore(newNode, node); } // Make the private chat toggle button var node = document.getElementById("chat-box-area"); var buttons = node.querySelectorAll("[type='button']"); if (buttons.length > 1) { var lastButton = buttons[buttons.length - 2]; var newButton = lastButton.cloneNode(false); newButton.setAttribute("value", "Toggle PM Mode"); newButton.removeAttribute("onclick"); newButton.addEventListener("click", function() { var node1 = document.getElementById("chat-area-div"); var node2 = document.getElementById("chat-area-pm-div"); if (node1 && node2) { node1.style.display == "none" ? node1.style.display = "block" : node1.style.display = "none"; node2.style.display == "none" ? node2.style.display = "block" : node2.style.display = "none"; } }); lastButton.parentNode.insertBefore(newButton, lastButton.nextSibling); } } /* Adds chat private messages to the new PM tab */ function addPmToPmTab(text) { if (text.startsWith("<span style='color:purple'>Private Message from") || text.startsWith("<span style='color:purple'>Sent to")) { var node = document.getElementById("chat-area-pm-div"); if (node) { if (window.showTimestamps === true) { var date = new Date(); var time = "[" + ("00" + date.getHours()).slice(-2) + ":" + ("00" + date.getMinutes()).slice(-2) + "] " text = time + text; } node.innerHTML += text + "<br>"; // Autoscroll the PM tab if (window.isAutoScrolling) { node.scrollTop = node.scrollHeight; } } } } /* Adjusts the PM chatbox height to match the normal chatbox height when the resize buttons are pressed */ var originalChatBoxZoom = window.chatBoxZoom; window.chatBoxZoom = function(zoom) { originalChatBoxZoom(zoom); var node1 = document.getElementById("chat-area-div"); var node2 = document.getElementById("chat-area-pm-div"); if (node1 && node2) { node2.style.height = node1.style.height; } } /* Changes the latest mod-colored text to an orange */ function outputDarkmodeChat() { var modText = document.querySelectorAll("[style='color:" + modChatColor +";']"); if (modText.length > 0) { var node = modText[modText.length - 1]; if (node) { node.style.color = modChatDarkModeColor; } } } /* Add the new functionality to the #refreshChat function, while maintaining the original functionality Adds URL linkification and darkmode output */ window.refreshChat = function(data) { if (spamCheck(data) === true) { // Linkify URLs data = linkify(data); // Add private messages to the private message tab addPmToPmTab(data); // Run the original #refreshChat originalRefreshChat(data); // Change the output to darkmode if darkmode is enabled /*if (chatboxDarkModeEnabled === true) { outputDarkmodeChat(); }*/ } } /* Spam filter, if it returns false, the message is not rendered in chat */ function spamCheck(messageString) { // If the message isn't from smitty or the server (~ is filtered out serverside so this is fairly safe) if (messageString.indexOf("~!!!") === -1) { var playerName = ""; var message = ""; // Regex pattern, matches the sender's name (matches[1]), and the message (matches[2]); // First pattern is for normal messages, second pattern checks for private messages var matches = messageString.match(/~\*?\|?(.*) \([0-9]+\)\: (.*)/) || messageString.match(/<span style='color:purple'>Private Message from <b>(.*)<\/b>\: (.*)<\/span>/); if (matches !== null && matches.length >= 3) { if (window.username.toLowerCase() == matches[1].toLowerCase()) { // If it's us speaking, we won't spam check to avoid issues and confusion return true; } playerName = matches[1].replace(/ /g, "_"); // Replaces spaces in a player's name with underscores to be variable and report friendly message = matches[2]; // Create a new object within the chatFilter object for the talking player if one doesn't exist, otherwise check for spam if (!chatFilter.hasOwnProperty(playerName)) { chatFilter[playerName] = { filterTime : Date.now(), messageTime : Date.now(), messageCount : 1, lastMessage : message, isReported : false }; } else { // Player is already muted and reported, no additional steps are necessary if (chatFilter[playerName].isReported === true) { return false; } // Get the current time var time = Date.now(); // Calculate the time since the user's last message var timeSinceLastMessage = time - chatFilter[playerName].messageTime; var timeSinceFilter = time - chatFilter[playerName].filterTime; // Reset a player's filter time, and message count, if their last message was 2.1+ seconds ago or the filter started 4.4+ seconds ago if (timeSinceLastMessage >= 2100 || timeSinceFilter >= 4400) { chatFilter[playerName].filterTime = time; chatFilter[playerName].messageCount = 0; } // Increment the player's message count by 1 for talking chatFilter[playerName].messageCount++; // If a player's message count hits 3, reset their filter to "keep an eye" on them as a potential spammer but show this message regardless if (chatFilter[playerName].messageCount == 3) { chatFilter[playerName].filterTime = time; } else if (chatFilter.messageCount >= 5) { // If they've now sent at least 5 messages without a single 2.2 second pause, continue resetting their filter until they do so and no longer display their message if (chatFilter[playerName].messageCount == 10) { // If they reach a messagecount of 10, automatically mute and report the player //console.log("Muting and reporting player: " + playerName + " for message: " + message + " (" + chatFilter[playerName].messageCount + ")"); window.sendChat("/mute " + playerName); window.messageBox(playerName + " muted by DHQoL"); window.sendChat("/report " + playerName + " Automated spam report by DHQoL please PM Wh0IsY0u on reddit if this becomes a problem"); chatFilter[playerName].isReported = true; } chatFilter[playerName].filterTime = time; chatFilter[playerName].lastMessage = message; chatFilter[playerName].messageTime = time; return false; } // If the message is over 30 characters but does not contain a space, it is likely spam // If the player's current message is the same as their last message then we don't need to see it // If the player's last message was sent less than 150 milliseconds ago, it is likely spam if ((message.length >= 30 && message.indexOf(" ") == -1) || (timeSinceLastMessage <= 150) || (chatFilter[playerName].lastMessage.toLowerCase() === message.toLowerCase())) { // Sets the player's last message sent to the current message and last message time to now chatFilter[playerName].lastMessage = message; chatFilter[playerName].messageTime = time; return false; // Message was considered spam //console.log("Spam message: " + playerName + " for message: " + message + " (" + chatFilter[playerName].messageCount + ")"); } // Sets the player's last message sent to the current message and last message time to now chatFilter[playerName].lastMessage = message; chatFilter[playerName].messageTime = time; } } } return true; // Message is okay to go through } /* Toggles the chatbox between darkmode and normal */ function toggleChatboxColorMode() { if (chatboxDarkModeEnabled === false) { setChatboxDarkMode(); } else if (chatboxDarkModeEnabled === true) { resetChatboxMode(); } } /* Sets the chatbox to "darkmode" */ function setChatboxDarkMode() { var node = document.getElementById("chat-area-div"); var node2 = document.getElementById("chat-area-pm-div"); // DH QoL custom PM tab if (node) { // Set the chatbox background to grey node.style.backgroundColor = "#484848"; // Set the MOTD to black since it is normally grey node.getElementsByTagName("span")[0].style.color = "black"; // Replace ALL existing mod text with our new color var modText = document.getElementsByClassName("chat-tag-mod"); for (var i = 0; i < modText.length; i++) { var parent = modText[i].parentNode; parent.style.color = modChatDarkModeColor; } // Change the darkmode flag to true chatboxDarkModeEnabled = true; GM_setValue("chatboxDarkModeEnabled", true); // Set PM tab to dark mode if (node2) { node2.style.backgroundColor = "#484848"; } } } /* Resets the chatbox to the original mode */ function resetChatboxMode() { var node = document.getElementById("chat-area-div"); var node2 = document.getElementById("chat-area-pm-div"); if (node) { // Remove the custom background color (back to white) node.style.backgroundColor = ""; // Replace ALL existing mod text with the original color var modText = document.getElementsByClassName("chat-tag-mod"); for (var i = 0; i < modText.length; i++) { var parent = modText[i].parentNode; parent.style.color = modChatColor; } // Change the darkmode flag to false chatboxDarkModeEnabled = false; GM_setValue("chatboxDarkModeEnabled", false); // Set PM tab to dark mode if (node2) { node2.style.backgroundColor = ""; } } } /* Creates a button that toggles chatbox darkmode on and off and adds it to the chatbox header */ function createDarkModeToggleButton() { var node = document.getElementById("chat-box-area"); var buttons = node.querySelectorAll("[type='button']"); if (buttons.length > 1) { var lastButton = buttons[buttons.length - 2]; var newButton = lastButton.cloneNode(false); newButton.setAttribute("value", "Toggle Darkmode"); newButton.removeAttribute("onclick"); newButton.addEventListener("click", function() { toggleChatboxColorMode(); }); lastButton.parentNode.insertBefore(newButton, lastButton.nextSibling); } } /* --- Misc --- */ /* Removes the left click to sell item functionality from all brewing-tab items since you'd almost never want to sell these */ function disableBrewingItemSelling() { var brewingTabDoc = document.getElementById("brewing-tab"); if (brewingTabDoc) { var sellableItems = brewingTabDoc.getElementsByClassName("item-box-spot")[0].querySelectorAll("[onclick=\"sellDailog(this.id)\"]"); for (var i = 0; i < sellableItems.length; i++) { sellableItems[i].removeAttribute("onclick"); } } } /* Removes the default right and left click functionality when clicking on your money Left clicking your coins icon will convert up to 2B coins to plat Left clicking your plat icon will convert plat to coins until you're carrying up to 2B */ function improveCoinSwap() { var moneyDocList = document.querySelectorAll("[oncontextmenu=\"send('COINS_TO_PLATINUM='+parseInt(coins/1000000));return false;\"]"); if (moneyDocList.length > 0) { var moneyDoc = moneyDocList[0]; moneyDoc.removeAttribute("oncontextmenu"); moneyDoc.removeAttribute("onclick"); var coinsElement = moneyDoc.childNodes[0]; var platElement = document.getElementById("platinum-coins-status-bar-span").childNodes[0]; coinsElement.onclick = function() { var convert = Math.min(Math.floor(parseInt(window.coins / 1000000)), 2000); if (convert > 0 ) { window.send("COINS_TO_PLATINUM=" + convert); } }; platElement.onclick = function() { var convert = Math.min(parseInt(window.platinumCoins), Math.max(2000 - Math.floor(parseInt(window.coins / 1000000)), 0)); if (convert > 0 ) { window.send("PLATINUM_TO_COINS=" + convert); } } } } /* Allows you to craft more than one rocket fuel at a time if you're above a certain amount of oil, otherwise it crafts just one like normal */ function setCraftMultipleRocketFuel() { var node = document.getElementById("craft-rocketFuel"); var dialogNode = document.getElementById("dialog-craft-multi"); if (node && dialogNode) { var dialogConfirmButton = dialogNode.querySelectorAll("[type='button']")[0]; if (dialogConfirmButton) { // Add the craft multiple dialog to the rocket fuel crafting node.removeAttribute("onclick"); node.addEventListener("click", function() { var requiredOil = (bindedOilRefinery == 0 ? 100000000 : 200000000); if (oil >= requiredOil) { craftMultipleItem("rocketFuel"); } else { craftItem("rocketFuel"); } }); // Craft in a loop since #craftMultiple doesn't allow rocket fuel crafting for some reason dialogConfirmButton.removeAttribute("onclick"); dialogConfirmButton.addEventListener("click", function(){ if (document.getElementById('craft-multiple-item-hidden').value == "rocketFuel") { var amount = document.getElementById('craftMulti-amount-txt').value; var delay = 0; $(this).closest('.ui-dialog-content').dialog('close'); for (var i = 0; i < amount; i++) { setTimeout(function() { if (oil >= 50000000) { craftItem("rocketFuel"); } }, delay); delay += 100; } } else { craftMultiple(document.getElementById('craft-multiple-item-hidden').value, document.getElementById('craftMulti-amount-txt').value);$(this).closest('.ui-dialog-content').dialog('close') } }); } } } /* Removes the ability to left click / bind equal or lower tier furnaces and ovens if you have promethium/ancient or higher */ function disableBindFurnacesAndOvens() { var furnaceIds = ["item-stoneFurnace-box", "item-bronzeFurnace-box", "item-ironFurnace-box", "item-silverFurnace-box", "item-goldFurnace-box", "item-ancientFurnace-box", "item-promethiumFurnace-box", "item-runiteFurnace-box"]; var ovenIds = ["item-bronzeOven-box", "item-ironOven-box", "item-silverOven-box", "item-goldOven-box", "item-ancientOven-box", "item-promethiumOven-box", "item-runiteOven-box"]; if (window.bindedFurnaceLevel >= 7) { // Remove the option to left click / bind prom or lower furnaces if we have a prom or higher furnace bound for (var i = 0; i < furnaceIds.length; i++) { var node = document.getElementById(furnaceIds[i]); if (node) { node.removeAttribute("onclick"); } } } if (window.bindedPromOven == 1 || window.bindedAncientOven == 1 || window.bindedRuniteOven == 1) { var boundOvenLevel = (window.bindedRuniteOven == 1 ? ovenIds.length : (window.bindedAncientOven == 1 ? ovenIds.length - 2 : ovenIds.length - 1)); for (i = 0; i < boundOvenLevel; i++) { var node = document.getElementById(ovenIds[i]); if (node) { node.removeAttribute("onclick"); } } } } /* Adds the wealth evaluator to the key items (clones the tutorial key item, edits, and appends it) */ function addWealthEvaluator() { var keyItemTabNode = document.getElementById("key-items-tab"); if (keyItemTabNode) { var keyItemTutorialNode = keyItemTabNode.querySelector("[tooltip='Click to read']"); if (keyItemTutorialNode) { var newNode = keyItemTutorialNode.cloneNode(true); newNode.setAttribute("tooltip", "Click me to evaluate your wealth!"); newNode.childNodes[0].id = "key-item-wealth-evaluator"; newNode.childNodes[0].onclick = ""; newNode.childNodes[0].addEventListener("click", function() { evaluateWealth(); }); var boxTitleNode = newNode.childNodes[0].querySelector(".item-box-title"); var boxImageNode = newNode.querySelector("[src]"); boxTitleNode.innerHTML = "Wealth Evaluator"; boxImageNode.src = "images/pic_coin.png"; newNode.childNodes[0].innerHTML = newNode.childNodes[0].innerHTML.replace("Click to Read", ""); // Append the new node to the document keyItemTabNode.appendChild(newNode); } } } /* Evaluates all of your tradable items and gives their total value based on the mininmum market price, maximum market price, and the average of the two Does not account for untradables, your platinum and coins, bound items, equipped items, or items currently listed on the market */ function evaluateWealth() { var networthMin = 0; var networthMax = networthMin; for (var i = 0; i < window.tradableItems.length; i++) { var itemData = window.tradableItems[i].split("~"); var item = itemData[0]; var minPrice = parseFloat(itemData[1]); var maxPrice = parseFloat(itemData[2]); if (window[item]) { networthMin += (window.platinumTradables.indexOf(item) >= 0 ? window[item] * minPrice * 1000000 : window[item] * minPrice); networthMax += (window.platinumTradables.indexOf(item) >= 0 ? window[item] * maxPrice * 1000000 : window[item] * maxPrice); } } window.alert("This is an evaluation of the value of your tradable items.\n\ Items that cannot be traded are not valued.\n\ Bound items, equipped items, coins/plat, and items currently listed on the market place are not valued.\n\n\ Your tradable items at minimum market price are worth: " + networthMin.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + "\n\ Your tradable items at maximum market price are worth: " + networthMax.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + "\n\ For an average of: " + ((networthMin + networthMax) / 2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')); } /* Updates the tooltips for all (or most, dependant on consistency in the code) tradable items to include their min and max market prices */ function updateTooltips() { // Add a new rule to the stylesheet, allowing CSS tooltips to have line breaks (we'll be using \x0A for linebreaks) document.styleSheets[1].insertRule(".tooltip{white-space: pre-wrap;}", 0); // Iterate over every tradable item and look for an item box with the same name to update for (var i in window.tradableItems) { var data = window.tradableItems[i].split("~"); var item = data[0]; var low = data[1].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (window.isPlatinumTradable(item) ? " (P)" : ""); var max = data[2].toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',') + (window.isPlatinumTradable(item) ? " (P)" : ""); var node = document.getElementById("item-" + item + "-box"); if (node) { var parentNode = node.parentNode; var tooltip = parentNode.getAttribute("tooltip"); parentNode.setAttribute("tooltip", tooltip + "\x0ALow price: " + low + "\x0AMax price: " + max); } } } /* Updates treasure map hint interface to include the actual answer to the treasure map Answers are "spoiler tagged" and require the user to click to reveal the answer */ window.openTreasureMapHint = function() { var val = "Solve this clue to get a treasure chest:<br /><br />"; switch (treasureMap) { case "1": openDialogue("Hint",val + "<div class='activate-tooltip' tooltip='test' style='color:cyan;background-color:black;border:1px solid yellow;padding:7px 15px 7px 15px;'><u>Au</u> to the store.\ <span style='color: red; font-size: 60%;'><br />DHQoL: <span onclick='this.innerHTML = \"Sell 1 gold ore to the NPC shop.\";'>Click To Reveal Answer</span></span></div>",""); break; case "2": openDialogue("Hint",val + "<div style='color:cyan;background-color:black;border:1px solid yellow;padding:7px 15px 7px 15px;'>Let me put my <u>glass</u>es on before I read the lable on this.\ <span style='color: red; font-size: 60%;'><br />DHQoL: <span onclick='this.innerHTML = \"Craft 1 vial.\";'>Click To Reveal Answer</span></span></div>",""); break; case "3": openDialogue("Hint",val + "<div style='color:cyan;background-color:black;border:1px solid yellow;padding:7px 15px 7px 15px;'>Shop needs some help to build his wall in exchange for 1 coin.\ <span style='color: red; font-size: 60%;'><br />DHQoL: <span onclick='this.innerHTML = \"Sell 1 stone to the NPC shop.\";'>Click To Reveal Answer</span></span></div>",""); break; case "4": openDialogue("Hint",val + "<div style='color:cyan;background-color:black;border:1px solid yellow;padding:7px 15px 7px 15px;'>It is earth day, off they go.\ <span style='color: red; font-size: 60%;'><br />DHQoL: <span onclick='this.innerHTML = \"Turn off all of your machines.\";'>Click To Reveal Answer</span></span></div>",""); break; case "5": openDialogue("Hint",val + "<div style='color:cyan;background-color:black;border:1px solid yellow;padding:7px 15px 7px 15px;'>Fael dettod a mraf.\ <span style='color: red; font-size: 60%;'><br />DHQoL: <span onclick='this.innerHTML = \"Plant and harvest 1 dotted leaf.\";'>Click To Reveal Answer</span></span></div>",""); break; default: break; } } /* --- Timers --- */ /* Format seconds into HH:MM:SS format */ function formatTime(seconds) { var hours = Math.floor(seconds / 3600); var mins = Math.floor((seconds % 3600) / 60); var secs = Math.round(seconds % 60); var hourString = ("00" + hours.toString()).slice(-2) + ":"; var minString = ("00" + mins.toString()).slice(-2) + ":"; var secString = ("00" + secs.toString()).slice(-2); return hourString + minString + secString } /* Roughly calculate the time remaining until the rocket journey completes. Uses averages gathered so it may vary slightly. Rocket info (found from logging) that we need to know Rocket lifts off at a speed of 0-10km/s (averaging 5km/s) until there is about 383401km left in the trip The majority of the trip (~383100-~383125) is traveled at 25-75km/s (averaging 50km/s) At ~275-300km remaining the rocket slows down to 0-10km/s (averagig 5km/s) At ~30km remaining the rocket slows down to a constant 1km/s */ function getRocketTimer() { var totalDistanceRemaining = window.rocketTimer; var liftoffDistanceRemaining = Math.max((totalDistanceRemaining-383401), 0); var mainTravelDistanceRemaining = Math.max((totalDistanceRemaining-liftoffDistanceRemaining-300), 0); var endSlowdownDistanceRemaining = (totalDistanceRemaining > 300) ? 300-30 : Math.max((totalDistanceRemaining-30), 0); var landingDistanceRemaining = (totalDistanceRemaining > 30) ? 30 : totalDistanceRemaining; var averageSecondsRemaining = Math.ceil(liftoffDistanceRemaining/5) + Math.ceil(mainTravelDistanceRemaining/50) + Math.ceil(endSlowdownDistanceRemaining/5) + landingDistanceRemaining; return averageSecondsRemaining; } // Make changes to the document to replace our rocket timer, giving us an estimate time until completion based on average times to travel each kilometer (depending on the distance remaining) function replaceRocketTimer() { document.getElementById("notification-timer-span-rocket").innerHTML = formatTime(getRocketTimer()); } /* Calculates the time left until your furnace is done smelting the current load and formats the time into a string Attempts to more accurately display the time remaining when you have the furnace timer donor perk */ function getfurnaceTimer() { var timeRemaining = (window.furnaceTimer == "1" ? ((window.furnaceTotalTimer * 0.75) - ((window.furnaceCurrentTimer * 0.75))) : window.furnaceTotalTimer - window.furnaceCurrentTimer); return timeRemaining; } // Returns an image path based on the "furnaceBarId" variable (item you're currently smelting) function getProductImageByFurnaceId(id) { switch (window.furnaceBarId) { case "1": return "images/minerals/bronzeBar.png" case "2": return "images/minerals/ironBar.png" case "3": return "images/minerals/silverBar.png" case "4": return "images/minerals/goldBar.png" case "5": return "images/minerals/glass.png" case "6": return "images/minerals/promethiumBar.png" default: return "images/crafting/ironfurnace.gif" } } // Make changes to the document to replace our furnace timer with a new image and a time rather than just a percentage function replaceFurnaceTimer() { var furnaceNode = document.getElementById("furnace-timer"); var imageNode = document.getElementById("furnace-timer").childNodes[1]; var newImagePath = getProductImageByFurnaceId(window.furnaceBarId); if (imageNode.getAttribute("src") != newImagePath) { imageNode.setAttribute("src", newImagePath); } document.getElementById("notification-timer-span-furnace").innerHTML = formatTime(getfurnaceTimer()) + " (" + window.furnacePerc + "%)"; } // Loops through all potions which can have a timer (TIMED_POTION_LIST) and returns an array with timer variable name of those which are currently active function getActivePotionTimers() { var activePotions = []; for (var i = 0; i < TIMED_POTION_LIST.length; i++) { var potionTimer = TIMED_POTION_LIST[i] + "Timer"; if (window[potionTimer] > 0) { activePotions.push(TIMED_POTION_LIST[i]); } } return activePotions; } // Replaces the timers for all active potions with new timers formated as HH:MM:SS function replaceActivePotionTimers(activePotions) { for (var i = 0; i < activePotions.length; i++) { var activePotion = activePotions[i]; document.getElementById("notification-timer-span-" + activePotion).innerHTML = formatTime(window[activePotion + "Timer"]); } } // Loops through all spells which can have a timer (TIMED_SPELL_LIST) and returns an array with timer variable name of those which are currently active function getActiveSpellTimers() { var activeSpells = []; for (var i = 0; i < TIMED_SPELL_LIST.length; i++) { var spellTimer = TIMED_SPELL_LIST[i] + "Timer"; if (window[spellTimer] > 0) { activeSpells.push(TIMED_SPELL_LIST[i]); } } return activeSpells; } // Replaces the timers for all active spells with new timers formated as HH:MM:SS function replaceActiveSpellTimers(activeSpells) { for (var i = 0; i < activeSpells.length; i++) { var activeSpell = activeSpells[i]; document.getElementById("notification-timer-span-" + activeSpell).innerHTML = formatTime(window[activeSpell + "Timer"]); } } // Creates two new notification boxes, one for explorer's potions, and one for artifact potions. These are initially hidden until you have one active. function createNotificationBoxes() { // A little bit of voodoo to get the correct element to edit since it has no ID (smitty pls add ID). // This is prone to breaking fairly easily if any center tags are added or removed in the wrong order, but it's not a difficult fix. var mainGameElement = document.getElementById("main-game"); if (mainGameElement) { var centerElements = mainGameElement.getElementsByTagName("center"); if (centerElements && centerElements.length > 1) { var notificationElement = centerElements[1].getElementsByTagName("div"); if (notificationElement && notificationElement.length > 0) { var doc = notificationElement[0]; if (doc.innerHTML.indexOf("<!-- timer box -->")) { // Backslashes allow you to break lines in JS, neat thing to keep in mind doc.innerHTML += '\ <!-- (DH QOL) Explorer\'s Potion Notification -->\ <span class="notification-timer-box-potion" id="explorersPotion-notification-box" style="display: none;">\ <img width="30px" height="40px" style="vertical-align: middle;padding:5px 0px 5px 0px;" src="images/brewing/explorersPotion.png" title="Explorer\'s Potion">\ <span id="notification-span-explorersPotion"></span>\ </span>\ <!-- (DH QOL) End Notification -->\ \ <!-- (DH QOL) Artifact Potion Notification -->\ <span class="notification-timer-box-potion" id="artifactPotion-notification-box" style="display: none;">\ <img width="30px" height="40px" style="vertical-align: middle;padding:5px 0px 5px 0px;" src="images/brewing/artifactPotion.png" title="Artifact Potion">\ <span id="notification-span-artifactPotion"></span>\ </span>\ <!-- (DH QOL) End Notification -->\ '; } } } } } // Show or hide our custom potion notifications depending on whether or not those potions are active function updateCustomPotionNotification() { var explorerNotificationElement = document.getElementById("explorersPotion-notification-box"); var artifactNotificationElement = document.getElementById("artifactPotion-notification-box"); if (explorerNotificationElement) { if (window.explorersPotionOn > 0) { document.getElementById("notification-span-explorersPotion").innerHTML = window.explorersPotionOn + " Active"; explorerNotificationElement.style.display = "inline-block"; } else { explorerNotificationElement.style.display = "none"; } } if (artifactNotificationElement) { if (window.artifactPotionIsActivated > 0) { document.getElementById("notification-span-artifactPotion").innerHTML = window.artifactPotionIsActivated + " Active"; artifactNotificationElement.style.display = "inline-block"; } else { artifactNotificationElement.style.display = "none"; } } } // Get & format our robot timer function getRobotTimer() { var robotTime = window.robotTimer; var mins = Math.floor(robotTime / 60); var secs = Math.round(robotTime % 60); var minString = ("00" + mins.toString()).slice(-2) + ":"; var secString = ("00" + secs.toString()).slice(-2); return minString + secString } // Make changes to the document to replace our robot timer to be formatted in minutes and seconds rather than just seconds function replaceRobotTimer() { document.getElementById("notification-timer-span-robot").innerHTML = "Returns in " + getRobotTimer(); } // Get & format our fishing boat timer function getFishingBoatTimer() { return formatTime(window.fishingBoatTimer); } // Make changes to the document to replace our fishing boat timer to be formatted in HH:MM:SS rather than the default function replaceFishingBoatTimer() { document.getElementById("notification-timer-span-fishingBoat").innerHTML = getFishingBoatTimer(); } // Get & format our large fishing boat timer function getLargeFishingBoatTimer() { return formatTime(window.largeFishingBoatTimer); } // Make changes to the document to replace our large fishing boat timer to be formatted in HH:MM:SS rather than the default function replaceLargeFishingBoatTimer() { document.getElementById("notification-timer-span-largeFishingBoat").innerHTML = getLargeFishingBoatTimer(); } // Get & format our exploring timer, takes donor perk into account function getExploringTimer() { var exploringTime = (window.explorerTimer > 0) ? Math.round(window.exploringTimer * 0.8) : window.exploringTimer; return formatTime(exploringTime) } // Make changes to the document to replace our exploring timer to be formatted in HH:MM:SS rather than the default function replaceExploringTimer() { document.getElementById("notification-timer-span-exploring").innerHTML = getExploringTimer(); } // Get & format our magic cooldown timer function getMagicCooldown() { var mcd = window.magicCoolDown; return formatTime(mcd) } // Make changes to the document to replace our magic cooldown timer to be formatted in HH:MM:SS rather than the default function replaceMagicCooldownTimer() { document.getElementById("notification-timer-span-magicCoolDown").innerHTML = getMagicCooldown(); } // Format the ancient crystal timer in HH:MM:SS function replaceAncientCrystalTimer() { if (window.bindedAncientCrystal > 0 && window.ancientCrystalCooldown > 0) { var node = document.getElementById("ancientCrystalChargesSpan"); if (node) { node.innerHTML = formatTime(window.ancientCrystalCooldown); } } } // Replaces diamondhunt's "loadMiscVariabled()" function with a new one that updates our many timers to be more fancy var oldLoadMiscVariables = window.loadMiscVariables; window.loadMiscVariables = function() { oldLoadMiscVariables(); replaceRocketTimer(); replaceFurnaceTimer(); replaceRobotTimer(); replaceFishingBoatTimer(); replaceLargeFishingBoatTimer(); replaceExploringTimer(); replaceMagicCooldownTimer(); replaceAncientCrystalTimer(); } // Replaces diamondhunt's "loadPotionTimers()" function with a new one that updates our potion timers to be more fancy // Also adds a notification for explorer's potions and artifact potions (#updateCustomePotionNotifications()) var oldLoadPotionTimers = window.loadPotionTimers; window.loadPotionTimers = function() { oldLoadPotionTimers(); replaceActivePotionTimers(getActivePotionTimers()); updateCustomPotionNotification() } /* Replaces Diamond Hunt's #loadNotifSpells function with a new one that formats our magic timers */ var oldLoadNotifSpells = window.loadNotifSpells; window.loadNotifSpells = function() { oldLoadNotifSpells(); replaceActiveSpellTimers(getActiveSpellTimers()); } // Replace the farming timers with new timers formated in HH:MM:SS, also more accurately estimates the time if you have the Gardener donor perk // Farming has slight RNG to it though, so it may not tick correctly every second function replaceFarmingTimers() { if (window.farmingTimer == 1) { var patchIDs = ["1", "2", "3", "4"]; (window.hasFarmingPatch5) ? patchIDs.push("5") : patchIDs; (window.hasFarmingPatch6) ? patchIDs.push("6") : patchIDs; for (var i = 0; i < patchIDs.length; i++) { var matches = document.getElementById("farming-patch-status-"+patchIDs[i]).innerHTML.match(/>(.* min remaining)/); if (matches != null) { var match = matches.pop(); // Gardener donor perk has been adjusted to calculate the reduction when planting rather than speeding up the timer // var timeRemaining = window.gardenerTimer == "0" ? window["farmingPatchTimer"+patchIDs[i]] : Math.round(window["farmingPatchTimer"+patchIDs[i]] * 0.8); var timeRemaining = window["farmingPatchTimer"+patchIDs[i]]; document.getElementById("farming-patch-status-"+patchIDs[i]).innerHTML = document.getElementById("farming-patch-status-"+patchIDs[i]).innerHTML.replace(match, formatTime(timeRemaining)); } } } } // Replaces diamondhunt's "refreshFarmingPatch()" function with a new one that updates our farming timers to be more fancy var oldRefreshFarmingPatch = window.refreshFarmingPatch; window.refreshFarmingPatch = function(patchId, seedId, seedName, deadCropImg) { oldRefreshFarmingPatch(patchId, seedId, seedName, deadCropImg); replaceFarmingTimers(); } /* --- Other --- */ /* Set and forget, logging that can be enabled or disabled through config */ function cLog(l) { if (config.ENABLE_LOGGING === true) { var date = new Date(); console.log(("00" + date.getHours()).slice(-2) + ":" + ("00" + date.getMinutes()).slice(-2) + ":" + ("00" + date.getSeconds()).slice(-2) + ": " + l); } }
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址