您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improve Diamond Hunt 2
当前为
// ==UserScript== // @name DH2 Fixed // @namespace FileFace // @description Improve Diamond Hunt 2 // @version 0.20.2 // @author Zorbing // @grant none // @run-at document-start // @include http://www.diamondhunt.co/game.php // ==/UserScript== (function () { 'use strict'; /** * observer */ let observedKeys = new Map(); /** * Observes the given key for change * * @param {string} key The name of the variable * @param {Function} fn The function which is called on change */ function observe(key, fn) { if (key instanceof Array) { for (let k of key) { observe(k, fn); } } else { if (!observedKeys.has(key)) { observedKeys.set(key, new Set()); } observedKeys.get(key).add(fn); } return fn; } function unobserve(key, fn) { if (key instanceof Array) { let ret = []; for (let k of key) { ret.push(unobserve(k, fn)); } return ret; } if (!observedKeys.has(key)) { return false; } return observedKeys.get(key).delete(fn); } function updateValue(key, newValue) { const oldValue = window[key]; window[key] = newValue; if (oldValue !== newValue) { (observedKeys.get(key) || []).forEach(fn => fn(key, oldValue, newValue)); } } /** * global constants */ const tierLevels = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond']; const furnaceLevels = ['stone', 'bronze', 'iron', 'silver', 'gold']; const furnaceCapacity = [10, 30, 75, 150, 300]; const ovenLevels = ['bronze', 'iron', 'silver', 'gold']; const maxOilStorageLevel = 3; // 7 const oilStorageSize = [10e3, 50e3, 100e3]; /** * general functions */ let styleElement = null; function addStyle(styleCode) { if (styleElement === null) { styleElement = document.createElement('style'); document.head.appendChild(styleElement); } styleElement.innerHTML += styleCode; } function getBoundKey(key) { return 'bound' + key[0].toUpperCase() + key.substr(1); } function getTierKey(key, tierLevel) { return tierLevels[tierLevel] + key[0].toUpperCase() + key.substr(1); } function formatNumber(num) { return parseFloat(num).toLocaleString('en'); } function formatNumbersInText(text) { return text.replace(/\d(?:[\d',\.]*\d)?/g, (numStr) => { return formatNumber(parseInt(numStr.replace(/\D/g, ''), 10)); }); } function now() { return (new Date()).getTime(); } function padLeft(num, padChar) { return (num < 10 ? padChar : '') + num; } function formatTimer(timer) { timer = parseInt(timer, 10); const hours = Math.floor(timer / 3600); const minutes = Math.floor((timer % 3600) / 60); const seconds = timer % 60; return padLeft(hours, '0') + ':' + padLeft(minutes, '0') + ':' + padLeft(seconds, '0'); } /** * hide crafting recipes of lower tiers or of maxed machines */ function hideTierRecipes(max, getKey, init) { const keys2Observe = []; let maxLevel = 0; for (let i = max-1; i >= 0; i--) { const level = i+1; const key = getKey(i); const boundKey = getBoundKey(key); keys2Observe.push(key); keys2Observe.push(boundKey); if (window[key] > 0 || window[boundKey] > 0) { maxLevel = Math.max(maxLevel, level); } const recipeRow = document.getElementById('crafting-' + key); if (recipeRow) { const hide = level <= maxLevel; recipeRow.style.display = hide ? 'none' : ''; } } if (init) { observe(keys2Observe, () => hideTierRecipes(max, getKey, false)); } } function hideRecipe(key, max, init) { const maxValue = typeof max === 'function' ? max() : max; const boundKey = getBoundKey(key); const unbound = parseInt(window[key], 10); const bound = parseInt(window[boundKey], 10); const recipeRow = document.getElementById('crafting-' + key); if (recipeRow) { const hide = (bound + unbound) >= maxValue; recipeRow.style.display = hide ? 'none' : ''; } if (init) { observe([key, boundKey], () => hideRecipe(key, max, false)); } } function hideCraftedRecipes() { function processRecipes(init) { // furnace hideTierRecipes( furnaceLevels.length , i => furnaceLevels[i] + 'Furnace' , init ); // oil storage hideTierRecipes( 7 , i => 'oilStorage' + (i+1) , init ); // oven recipes hideTierRecipes( ovenLevels.length , i => ovenLevels[i] + 'Oven' , init ); // drills hideRecipe('drills', 10, init); // crushers hideRecipe('crushers', 10, init); // oil pipe hideRecipe('oilPipe', 1, init); // row boat hideRecipe('rowBoat', 1, init); } processRecipes(true); const oldProcessCraftingTab = window.processCraftingTab; window.processCraftingTab = () => { const reinit = !!window.refreshLoadCraftingTable; oldProcessCraftingTab(); if (reinit) { processRecipes(true); } }; } /** * improve item boxes */ function hideNumberInItemBox(key, setVisibility) { const itemBox = document.getElementById('item-box-' + key); const numberElement = itemBox.lastElementChild; if (setVisibility) { numberElement.style.visibility = 'hidden'; } else { numberElement.style.display = 'none'; } } function addSpan2ItemBox(key) { hideNumberInItemBox(key); const itemBox = document.getElementById('item-box-' + key); const span = document.createElement('span'); itemBox.appendChild(span); return span; } function setOilPerSecond(span, oil) { span.innerHTML = `+ ${formatNumber(oil)} L/s <img src="images/oil.png" class="image-icon-20" style="margin-top: -2px;">`; } function improveItemBoxes() { // show capacity of furnace for (let i = 0; i < furnaceLevels.length; i++) { const key = furnaceLevels[i] + 'Furnace'; const capacitySpan = addSpan2ItemBox(getBoundKey(key)); capacitySpan.className = 'capacity'; capacitySpan.textContent = 'Capacity: ' + formatNumber(furnaceCapacity[i]); } // show oil cap of oil storage for (let i = 0; i < maxOilStorageLevel; i++) { const key = 'oilStorage' + (i+1); const capSpan = addSpan2ItemBox(getBoundKey(key)); capSpan.className = 'oil-cap'; capSpan.textContent = 'Oil cap: ' + formatNumber(oilStorageSize[i]); } // show oil per second const handheldOilSpan = addSpan2ItemBox('handheldOilPump'); setOilPerSecond(handheldOilSpan, 1*window.miner); observe('miner', () => setOilPerSecond(handheldOilSpan, 1*window.miner)); const oilPipeSpan = addSpan2ItemBox('boundOilPipe'); setOilPerSecond(oilPipeSpan, 50); // show current tier hideNumberInItemBox('emptyAnvil', true); hideNumberInItemBox('farmer', true); const tierItemList = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'fishingRod']; for (let tierItem of tierItemList) { for (let i = 0; i < tierLevels.length; i++) { const key = getTierKey(tierItem, i); const tierSpan = addSpan2ItemBox(tierItem == 'rake' ? key : getBoundKey(key)); tierSpan.className = 'tier'; tierSpan.textContent = 'Tier: ' + i; } } // show boat progress function setTransitText(span, isInTransit) { span.textContent = isInTransit ? 'In transit' : 'Ready'; } const boatSpan = addSpan2ItemBox('boundRowBoat'); setTransitText(boatSpan, window.rowBoatTimer > 0); observe('rowBoatTimer', () => setTransitText(boatSpan, window.rowBoatTimer > 0)); const canoeSpan = addSpan2ItemBox('boundCanoe'); setTransitText(canoeSpan, window.canoeTimer > 0); observe('canoeTimer', () => setTransitText(canoeSpan, window.canoeTimer > 0)); } /** * fix wood cutting */ function fixWoodcutting() { addStyle(` img.woodcutting-tree-img { border: 1px solid transparent; } `); } /** * fix chat */ const lastMsg = new Map(); function isMuted(user) { // return window.mutedPeople.some((name) => user.indexOf(name) > -1); return window.mutedPeople.includes(user); } function isSpam(user, msg) { return lastMsg.has(user) && lastMsg.get(user).msg == msg && // last message in the last 30 seconds? (now() - lastMsg.get(user).time) < 30e3; } function handleSpam(user, msg) { const msgObj = lastMsg.get(user); msgObj.time = now(); msgObj.repeat++; // a user is allowed to repeat a message twice (write it 3 times in total) if (msgObj.repeat > 1) { window.mutedPeople.push(user); } } function fixChat() { const oldAddToChatBox = window.addToChatBox; window.addToChatBox = (userChatting, iconSet, tagSet, msg, isPM) => { if (isMuted(userChatting)) { return; } if (isSpam(userChatting, msg)) { return handleSpam(userChatting, msg); } lastMsg.set(userChatting, { time: now() , msg: msg , repeat: 0 }); // add clickable links msg = msg.replace(/(https?:\/\/[^\s]+)/g, '<a href="$1">$1</a>'); oldAddToChatBox(userChatting, iconSet, tagSet, msg, isPM); }; // add checkbox instead of button for toggling auto scrolling const btn = document.querySelector('input[value="Toggle Autoscroll"]'); const checkboxId = 'chat-toggle-autoscroll'; // create checkbox const toggleCheckbox = document.createElement('input'); toggleCheckbox.type = 'checkbox'; toggleCheckbox.id = checkboxId; toggleCheckbox.checked = true; // create label const toggleLabel = document.createElement('label'); toggleLabel.htmlFor = checkboxId; toggleLabel.textContent = 'Autoscroll'; btn.parentNode.insertBefore(toggleCheckbox, btn); btn.parentNode.insertBefore(toggleLabel, btn); btn.style.display = 'none'; toggleCheckbox.addEventListener('change', function () { window.isAutoScrolling = this.checked; window.scrollText('none', this.checked ? 'lime' : 'red', (this.checked ? 'En' : 'Dis') + 'abled'); }); } /** * hopefully only temporary fixes */ function temporaryFixes() { // fix recipe of oil storage 3 const oldProcessCraftingTab = window.processCraftingTab; window.processCraftingTab = () => { const reinit = !!window.refreshLoadCraftingTable; oldProcessCraftingTab(); if (reinit) { // 200 instead of 100 gold bars window.craftingRecipes['oilStorage3'].recipeCost[2] = 200; document.getElementById('recipe-cost-oilStorage3-2').textContent = 200; window.showMateriesNeededAndLevelLabels('oilStorage3'); } }; // fix magic tab const els = document.querySelectorAll('img[src="images/essence"], img[src="images/stardust"]'); for (let i = 0; i < els.length; i++) { els[i].src = els[i].src + '.png'; } const oldAddRecipeToMagicTable = window.addRecipeToMagicTable; window.addRecipeToMagicTable = (magicRecipe) => { console.log('addRecipeToMagicTable'); const itemName = magicRecipe.itemName; let htmlCode = `<tr id="magic-${itemName}">` + `<td>${getItemName(itemName)}</td>` + `<td><img src="images/hero/spells/${itemName}.png" style="margin-top:3px;border:1px solid black;" class="image-icon-40" /></td>` + `<td id="magic-recipe-level-req-${itemName}">${magicRecipe.levelReq}</td>` ; //mats htmlCode += `<td>`; const recipeParts = magicRecipe.recipe; for (let i = 0; i < recipeParts.length; i++) { // important part here: add ".png" to image src after recipe part htmlCode += `<img src="images/${recipeParts[i]}.png" class="image-icon-30" /> ` + `<span id="magic-recipe-cost-${itemName}-${i}">${magicRecipe.recipeCost[i]}</span>` + `<br />` ; } //special cases switch (itemName) { } //spanItemAmount.setAttribute("data-item-display", itemName); htmlCode += `</td>`; htmlCode += `<td>${magicRecipe.description}</td>` + `<td>" + magicRecipe.xp + "</td>` + `<td id='magic-charges-" + itemName + "'>0</td>` ; window.$('#table-magic-recipe tr:last').after(htmlCode); window.$('#table-magic-recipe tr:last').click(() => { window.sendBytes("SPELL_CHARGE=" + itemName); }); } } /** * improve timer */ function improveTimer() { window.formatTime = (seconds) => { return formatTimer(seconds); }; window.formatTimeShort2 = (seconds) => { return formatTimer(seconds); }; const barInfo = { 1: { name: 'bronze' , timePerBar: 1 } , 2: { name: 'iron' , timePerBar: 5 } , 3: { name: 'silver' , timePerBar: 10 } , 4: { name: 'gold' , timePerBar: 30 } , 5: { name: 'glass' , timePerBar: 1 } }; const smeltingPercEl = document.querySelector('span[data-item-display="smeltingPerc"]'); const smeltingTimerEl = document.createElement('span'); smeltingPercEl.style.display = 'none'; smeltingPercEl.parentNode.lastElementChild.style.display = 'none'; smeltingPercEl.parentNode.appendChild(smeltingTimerEl); let interval = null; let barName = ''; let remainingTime = 0; function setRemainingTime() { smeltingTimerEl.textContent = formatTimer(Math.max(remainingTime, 0)); } function updateSmeltingPerc() { const info = barInfo[window.smeltingBarType]; if (info) { const totalTime = info.timePerBar * window.smeltingTotalAmount; const time = Math.round(totalTime * (1 - window.smeltingPerc / 100)); if (interval == null || barName != info.name) { barName = info.name; remainingTime = time; interval = window.setInterval(() => { remainingTime--; setRemainingTime(); }, 1000); setRemainingTime(); } // tolerate up to 2 seconds deviation (to make it smoother for the user) else if (Math.abs(remainingTime - time) > 2) { remainingTime = time; setRemainingTime(); } } else if (interval) { window.clearInterval(interval); barName = ''; interval = null; } } observe('smeltingPerc', () => updateSmeltingPerc()); updateSmeltingPerc(); } /** * init */ function init() { temporaryFixes(); hideCraftedRecipes(); improveItemBoxes(); fixWoodcutting(); fixChat(); improveTimer(); } document.addEventListener('DOMContentLoaded', () => { const oldDoCommand = window.doCommand; window.doCommand = (data) => { if (data.startsWith('REFRESH_ITEMS=')) { const itemDataValues = data.split('=')[1].split(';'); const itemArray = []; for (var i = 0; i < itemDataValues.length; i++) { const [key, newValue] = itemDataValues[i].split('~'); itemArray.push(key); updateValue(key, newValue); } window.refreshItemValues(itemArray, false); if (window.firstLoadGame) { window.loadInitial(); window.firstLoadGame = false; init(); } else { window.clientGameLoop(); } return; } return oldDoCommand(data); }; }); /** * fix web socket errors */ function webSocketLoaded(event) { if (window.webSocket == null) { console.error('no webSocket instance found!'); return; } const messageQueue = []; const oldOnMessage = webSocket.onmessage; webSocket.onmessage = (event) => messageQueue.push(event); document.addEventListener('DOMContentLoaded', () => { messageQueue.forEach(event => onMessage(event)); webSocket.onmessage = oldOnMessage; }); const commandQueue = []; const oldSendBytes = window.sendBytes; window.sendBytes = (command) => commandQueue.push(command); const oldOnOpen = webSocket.onopen; webSocket.onopen = (event) => { window.sendBytes = oldSendBytes; commandQueue.forEach(command => window.sendBytes(command)); return oldOnOpen(event); }; } function isWebSocketScript(script) { return script.src.includes('socket.js'); } function fixWebSocketScript() { if (!document.head) { return; } const scripts = document.head.querySelectorAll('script'); let found = false; for (let i = 0; i < scripts.length; i++) { if (isWebSocketScript(scripts[i])) { // does this work? scripts[i].onload = webSocketLoaded; return; } } // create an observer instance const mutationObserver = new MutationObserver((mutationList) => { mutationList.forEach((mutation) => { if (mutation.addedNodes.length === 0) { return; } for (let i = 0; i < mutation.addedNodes.length; i++) { const node = mutation.addedNodes[i]; if (node.tagName == 'SCRIPT' && isWebSocketScript(node)) { mutationObserver.disconnect(); node.onload = webSocketLoaded; return; } } }); }); mutationObserver.observe(document.head, { childList: true }); } fixWebSocketScript(); })();