您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improve Diamond Hunt 2
当前为
// ==UserScript== // @name DH2 Fixed // @namespace FileFace // @description Improve Diamond Hunt 2 // @version 0.41.0 // @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) { if (window[key] === newValue) { return false; } const oldValue = window[key]; window[key] = newValue; (observedKeys.get(key) || []).forEach(fn => fn(key, oldValue, newValue)); return true; } /** * global constants */ const tierLevels = ['empty', 'sapphire', 'emerald', 'ruby', 'diamond']; const tierNames = ['Standard', 'Sapphire', 'Emerald', 'Ruby', 'Diamond']; const tierItemList = ['pickaxe', 'shovel', 'hammer', 'axe', 'rake', 'fishingRod']; const furnaceLevels = ['stone', 'bronze', 'iron', 'silver', 'gold']; const furnaceCapacity = [10, 30, 75, 150, 300]; const ovenLevels = ['bronze', 'iron', 'silver', 'gold']; const maxOilStorageLevel = 4; // 7 const oilStorageSize = [10e3, 50e3, 100e3, 300e3]; /** * 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'); } const timeSteps = [ { threshold: 1 , name: 'second' , short: 'sec' , padp: 0 } , { threshold: 60 , name: 'minute' , short: 'min' , padp: 0 } , { threshold: 3600 , name: 'hour' , short: 'h' , padp: 1 } , { threshold: 86400 , name: 'day' , short: 'd' , padp: 2 } ]; function formatTime2NearestUnit(time, long = false) { let step = timeSteps[0]; for (let i = timeSteps.length-1; i > 0; i--) { if (time >= timeSteps[i].threshold) { step = timeSteps[i]; break; } } const factor = Math.pow(10, step.padp); const num = Math.round(time / step.threshold * factor) / factor; const unit = long ? step.name + (num === 1 ? '' : 's') : step.short; return num + ' ' + unit; } /** * hide crafting recipes of lower tiers or of maxed machines */ function setRecipeVisibility(key, visible) { const recipeRow = document.getElementById('crafting-' + key); if (recipeRow) { recipeRow.style.display = visible ? '' : 'none'; } } function hideLeveledRecipes(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); } setRecipeVisibility(key, level > maxLevel); } if (init) { observe(keys2Observe, () => hideLeveledRecipes(max, getKey, false)); } } function hideToolRecipe(key, init) { const emptyKey = getTierKey(key, 0); const keys2Observe = [emptyKey]; let hasTool = window[emptyKey] > 0; for (let i = 0; i < tierLevels.length; i++) { const boundKey = getBoundKey(getTierKey(key, i)); hasTool = hasTool || window[boundKey] > 0; keys2Observe.push(boundKey); } setRecipeVisibility(emptyKey, !hasTool); if (init) { observe(keys2Observe, () => hideToolRecipe(key, 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); setRecipeVisibility(key, (bound + unbound) < maxValue); if (init) { observe([key, boundKey], () => hideRecipe(key, max, false)); } } function hideCraftedRecipes() { function processRecipes(init) { // furnace hideLeveledRecipes( furnaceLevels.length , i => furnaceLevels[i] + 'Furnace' , init ); // oil storage hideLeveledRecipes( 7 , i => 'oilStorage' + (i+1) , init ); // oven recipes hideLeveledRecipes( ovenLevels.length , i => ovenLevels[i] + 'Oven' , init ); // tools hideToolRecipe('axe', init); hideToolRecipe('hammer', init); hideToolRecipe('shovel', init); hideToolRecipe('pickaxe', init); hideToolRecipe('fishingRod', init); // drills hideRecipe('drills', 10, init); // crushers hideRecipe('crushers', 10, init); // oil pipe hideRecipe('oilPipe', 1, init); // boats hideRecipe('rowBoat', 1, init); hideRecipe('canoe', 1, init); } processRecipes(true); const _processCraftingTab = window.processCraftingTab; window.processCraftingTab = () => { const reinit = !!window.refreshLoadCraftingTable; _processCraftingTab(); 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); hideNumberInItemBox('planter', true); for (let tierItem of tierItemList) { for (let i = 0; i < tierLevels.length; i++) { const key = getTierKey(tierItem, i); const toolKey = tierItem == 'rake' ? key : getBoundKey(key); const tierSpan = addSpan2ItemBox(toolKey); tierSpan.className = 'tier'; tierSpan.textContent = tierNames[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 _addToChatBox = 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 target="_blank" href="$1">$1</a>'); _addToChatBox(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 _processCraftingTab = window.processCraftingTab; window.processCraftingTab = () => { const reinit = !!window.refreshLoadCraftingTable; _processCraftingTab(); 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 burn rate of ovens window.getOvenBurnRate = () => { if (boundBronzeOven == 1) { return .5; } else if (boundIronOven == 1) { return .4; } else if (boundSilverOven == 1) { return .3; } else if (boundGoldOven == 1) { return .2; } return 1; }; // fix grow time of some seeds const seeds = { 'limeLeafSeeds': '1 hour and 30 minutes' , 'greenLeafSeeds': '45 minutes' }; for (let seedName in seeds) { const tooltip = document.getElementById('tooltip-' + seedName); tooltip.lastElementChild.lastChild.textContent = seeds[seedName]; } // fix exhaustion timer and updating brewing recipes const _clientGameLoop = window.clientGameLoop; window.clientGameLoop = () => { _clientGameLoop(); if (document.getElementById('tab-container-combat').style.display != 'none') { window.combatNotFightingTick(); } if (currentOpenTab == 'brewing') { window.processBrewingTab(); } }; // fix elements of scrollText (e.g. when joining the game and receiving xp at that moment) const textEls = document.querySelectorAll('div.scroller'); for (let i = 0; i < textEls.length; i++) { const scroller = textEls[i]; if (scroller.style.position != 'absolute') { scroller.style.display = 'none'; } } // fix style of tooltips addStyle(` body > div.tooltip > h2:first-child { margin-top: 0; font-size: 20pt; font-weight: normal; } `); } /** * improve timer */ function improveTimer() { window.formatTime = (seconds) => { return formatTimer(seconds); }; window.formatTimeShort2 = (seconds) => { return formatTimer(seconds); }; addStyle(` #notif-smelting > span:not(.timer) { display: none; } `); const smeltingNotifBox = document.getElementById('notif-smelting'); const smeltingTimerEl = document.createElement('span'); smeltingTimerEl.className = 'timer'; smeltingNotifBox.appendChild(smeltingTimerEl); function updateSmeltingTimer() { const totalTime = parseInt(window.smeltingPercD, 10); const elapsedTime = parseInt(window.smeltingPercN, 10); smeltingTimerEl.textContent = formatTimer(Math.max(totalTime - elapsedTime, 0)); } observe('smeltingPercD', () => updateSmeltingTimer()); observe('smeltingPercN', () => updateSmeltingTimer()); updateSmeltingTimer(); // add tree grow timer const treeInfo = { 1: { name: 'Normal tree' // 3h = 10800s , growTime: 3 * 60 * 60 } , 2: { name: 'Oak tree' // 6h = 21600s , growTime: 6 * 60 * 60 } , 3: { name: 'Willow tree' // 8h = 28800s , growTime: 8 * 60 * 60 } }; function updateTreeInfo(place, nameEl, timerEl, init) { const idKey = 'treeId' + place; const growTimerKey = 'treeGrowTimer' + place; const lockedKey = 'treeUnlocked' + place; const info = treeInfo[window[idKey]]; if (!info) { const isLocked = place > 4 && window[lockedKey] == 0; nameEl.textContent = isLocked ? 'Locked' : 'Empty'; timerEl.textContent = ''; } else { nameEl.textContent = info.name; const remainingTime = info.growTime - parseInt(window[growTimerKey], 10); timerEl.textContent = remainingTime > 0 ? '(' + formatTimer(remainingTime) + ')' : 'Fully grown'; } if (init) { observe( [idKey, growTimerKey, lockedKey] , () => updateTreeInfo(place, nameEl, timerEl, false) ); } } for (let i = 0; i < 6; i++) { const treePlace = i+1; const treeContainer = document.getElementById('wc-div-tree-' + treePlace); treeContainer.style.position = 'relative'; const infoEl = document.createElement('div'); infoEl.setAttribute('style', 'position: absolute; top: 0; left: 0; right: 0; pointer-events: none; margin-top: 5px; color: white;'); const treeName = document.createElement('div'); treeName.style.fontSize = '1.2rem'; infoEl.appendChild(treeName); const treeTimer = document.createElement('div'); infoEl.appendChild(treeTimer); treeContainer.appendChild(infoEl); updateTreeInfo(treePlace, treeName, treeTimer, true); } } /** * improve smelting dialog */ const smeltingRequirements = { 'glass': { sand: 1 , oil: 10 } , 'bronzeBar': { copper: 1 , tin: 1 , oil: 10 } , 'ironBar': { iron: 1 , oil: 100 } , 'silverBar': { silver: 1 , oil: 300 } , 'goldBar': { gold: 1 , oil: 1e3 } }; function improveSmelting() { const amountInput = document.getElementById('input-smelt-bars-amount'); amountInput.type = 'number'; amountInput.min = 0; amountInput.step = 5; function onValueChange(event) { smeltingValue = null; window.selectBar('', '', amountInput, document.getElementById('smelting-furnace-capacity').value); } amountInput.addEventListener('mouseup', onValueChange); amountInput.addEventListener('keyup', onValueChange); amountInput.setAttribute('onkeyup', ''); const _selectBar = window.selectBar; let smeltingValue = null; window.selectBar = (bar, inputElement, inputBarsAmountEl, capacity) => { const requirements = smeltingRequirements[bar]; let maxAmount = capacity; for (let key in requirements) { maxAmount = Math.min(Math.floor(window[key] / requirements[key]), maxAmount); } const value = parseInt(amountInput.value, 10); if (value > maxAmount) { smeltingValue = value; amountInput.value = maxAmount; } else if (smeltingValue != null) { amountInput.value = Math.min(smeltingValue, maxAmount); if (smeltingValue <= maxAmount) { smeltingValue = null; } } return _selectBar(bar, inputElement, inputBarsAmountEl, capacity); }; const _openFurnaceDialogue = window.openFurnaceDialogue; window.openFurnaceDialogue = (furnace) => { if (smeltingBarType == 0) { amountInput.max = getFurnaceCapacity(furnace); } return _openFurnaceDialogue(furnace); }; } /** * add chance to time calculator */ /** * calculates the number of seconds until the event with the given chance happened at least once with the given * probability p (in percent) */ function calcSecondsTillP(chancePerSecond, p) { return Math.round(Math.log(1 - p/100) / Math.log(1 - chancePerSecond)); } function addChanceTooltip(headline, chancePerSecond, elId, targetEl) { // ensure element existence const tooltipElId = 'tooltip-chance-' + elId; let tooltipEl = document.getElementById(tooltipElId); if (!tooltipEl) { tooltipEl = document.createElement('div'); tooltipEl.id = tooltipElId; tooltipEl.style.display = 'none'; document.getElementById('tooltip-list').appendChild(tooltipEl); } // set elements content const percValues = [1, 10, 20, 50, 80, 90, 99]; let percRows = ''; for (let p of percValues) { percRows += ` <tr> <td>${p}%</td> <td>${formatTime2NearestUnit(calcSecondsTillP(chancePerSecond, p), true)}</td> </tr>`; } tooltipEl.innerHTML = `<h2>${headline}</h2> <table class="chance"> <tr> <th>Probability</th> <th>Time</th> </tr> ${percRows} </table> `; // ensure binded events to show the tooltip if (targetEl.dataset.tooltipId == null) { targetEl.setAttribute('data-tooltip-id', tooltipElId); window.$(targetEl).bind({ mousemove: window.changeTooltipPosition , mouseenter: window.showTooltip , mouseleave: window.hideTooltip }); } } function chance2TimeCalculator() { addStyle(` table.chance { border-spacing: 0; } table.chance th { border-bottom: 1px solid gray; } table.chance td:first-child { border-right: 1px solid gray; text-align: center; } table.chance th, table.chance td { padding: 4px 8px; } table.chance tr:nth-child(2n) td { background-color: white; } `); const _clicksShovel = window.clicksShovel; window.clicksShovel = () => { _clicksShovel(); const shovelChance = document.getElementById('dialogue-shovel-chance'); const titleEl = shovelChance.parentElement; const chance = 1/window.getChanceOfDiggingSand(); addChanceTooltip('One sand every:', chance, 'shovel', titleEl); }; // depends on fishingXp const _clicksFishingRod = window.clicksFishingRod; window.clicksFishingRod = () => { _clicksFishingRod(); const fishList = ['shrimp', 'sardine', 'tuna', 'swordfish', 'shark']; for (let fish of fishList) { const rawFish = 'raw' + fish[0].toUpperCase() + fish.substr(1); const row = document.getElementById('dialogue-fishing-rod-tr-' + rawFish); const chance = row.cells[4].textContent .replace(/[^\d\/]/g, '') .split('/') .reduce((p, c) => p / parseInt(c, 10), 1) ; addChanceTooltip(`One raw ${fish} every:`, chance, rawFish, row); } }; } /** * add notification boxes */ function addNotifBox(id, icon) { const notificationArea = document.getElementById('notifaction-area'); const notifBox = document.createElement('span'); notifBox.className = 'notif-box'; notifBox.id = 'notif-' + id; notifBox.innerHTML = `<img src="images/${icon}" class="image-icon-50" id="notif-${id}-img">`; notificationArea.appendChild(notifBox); return notifBox; } function addClickableNotifBox(id, icon, tabName) { const notifBox = addNotifBox(id, icon); notifBox.style.cursor = 'pointer'; notifBox.addEventListener('click', () => window.openTab(tabName)); return notifBox; } function showStageNotification(stagePrefix, notifBox, init) { const keys2Observe = []; let show = false; for (let i = 1; i <= 6; i++) { const key = stagePrefix + 'Stage' + i; keys2Observe.push(key); show = show || window[key] == 4; } notifBox.style.display = show ? '' : 'none'; if (init) { observe(keys2Observe, () => showStageNotification(stagePrefix, notifBox, false)); } } function addNotificationBoxes() { // tree / wood cutting notification const treeNotifBox = addClickableNotifBox('woodCutter', 'icons/woodcutting.png', 'woodcutting'); treeNotifBox.title = 'There is some wood to chop'; window.$(treeNotifBox).tooltip(); showStageNotification('tree', treeNotifBox, true); // farming notification const harvestNotifBox = addClickableNotifBox('farming', 'icons/watering-can.png', 'farming'); harvestNotifBox.title = 'Some plants are ready for harvest'; window.$(harvestNotifBox).tooltip(); showStageNotification('farmingPatch', harvestNotifBox, true); // combat cooldown timer const combatNotifBox = addNotifBox('combatCooldown', 'icons/combat.png'); // const combatNotifBox = addNotifBox('combatCooldown', 'icons/hourglass.png'); const combatTimer = document.createElement('span'); combatNotifBox.appendChild(combatTimer); function updateCombatTimer() { const cooldown = parseInt(window.combatGlobalCooldown, 10); const show = cooldown > 0; combatNotifBox.style.display = show ? '' : 'none'; combatTimer.textContent = formatTimer(cooldown); } observe('combatGlobalCooldown', () => updateCombatTimer()); updateCombatTimer(); } /** * add tooltips for recipes */ function updateRecipeTooltips(recipeKey, recipes) { const table = document.getElementById('table-' + recipeKey + '-recipe'); const rows = table.rows; for (let i = 1; i < rows.length; i++) { const row = rows[i]; const key = row.id.replace(recipeKey + '-', ''); const recipe = recipes[key]; const requirementCell = row.cells[3]; requirementCell.title = recipe.recipe .map((name, i) => { return formatNumber(recipe.recipeCost[i]) + ' ' + name.replace(/[A-Z]/g, (match) => ' ' + match.toLowerCase()) ; }) .join(' + ') ; window.$(requirementCell).tooltip(); } } function addRecipeTooltips() { const _processCraftingTab = window.processCraftingTab; window.processCraftingTab = () => { const reinit = !!window.refreshLoadCraftingTable; _processCraftingTab(); if (reinit) { updateRecipeTooltips('crafting', window.craftingRecipes); } }; const _processBrewingTab = window.processBrewingTab; window.processBrewingTab = () => { const reinit = !!window.refreshLoadBrewingTable; _processBrewingTab(); if (reinit) { updateRecipeTooltips('brewing', window.brewingRecipes); } } const _processMagicTab = window.processMagicTab; window.processMagicTab = () => { const reinit = !!window.refreshLoadCraftingTable; _processMagicTab(); if (reinit) { updateRecipeTooltips('magic', window.magicRecipes); } } } /** * fix formatting of numbers */ function prepareRecipeForTable(recipe) { // create a copy of the recipe to prevent requirement check from failing const newRecipe = JSON.parse(JSON.stringify(recipe)); newRecipe.recipeCost = recipe.recipeCost.map(cost => formatNumber(cost)); newRecipe.xp = formatNumber(recipe.xp); return newRecipe; } function fixNumberFormat() { const _addRecipeToBrewingTable = window.addRecipeToBrewingTable; window.addRecipeToBrewingTable = (brewingRecipe) => { _addRecipeToBrewingTable(prepareRecipeForTable(brewingRecipe)); }; const _addRecipeToMagicTable = window.addRecipeToMagicTable; window.addRecipeToMagicTable = (magicRecipe) => { _addRecipeToMagicTable(prepareRecipeForTable(magicRecipe)); }; } /** * style tweaks */ function addTweakStyle(setting, style) { const prefix = 'body.' + setting; addStyle( style .replace(/(^\s*|,\s*|\}\s*)([^\{\},]+)(,|\s*\{)/g, '$1' + prefix + ' $2$3') ); document.body.classList.add(setting); } function tweakStyle() { // tweak oil production/consumption addTweakStyle('tweak-oil', ` span#oil-flow-values { position: relative; margin-left: .5em; } #oil-flow-values > span { font-size: 0px; position: absolute; top: -0.75rem; visibility: hidden; } #oil-flow-values > span > span { font-size: 1rem; visibility: visible; } #oil-flow-values > span:last-child { top: 0.75rem; } #oil-flow-values span[data-item-display="oilIn"]::before { content: '+'; } #oil-flow-values span[data-item-display="oilOut"]::before { content: '-'; } `); addTweakStyle('no-select', ` table.tab-bar, span.item-box, div.farming-patch, div.farming-patch-locked, div.tab-sub-container-combat, table.top-links a { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } `); } /** * init */ function init() { temporaryFixes(); hideCraftedRecipes(); improveItemBoxes(); fixWoodcutting(); fixChat(); improveTimer(); improveSmelting(); chance2TimeCalculator(); addNotificationBoxes(); addRecipeTooltips(); fixNumberFormat(); tweakStyle(); } document.addEventListener('DOMContentLoaded', () => { const _doCommand = 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('~'); if (updateValue(key, newValue)) { itemArray.push(key); } } window.refreshItemValues(itemArray, false); if (window.firstLoadGame) { window.loadInitial(); window.firstLoadGame = false; init(); } else { window.clientGameLoop(); } return; } return _doCommand(data); }; }); /** * fix web socket errors */ function webSocketLoaded(event) { if (window.webSocket == null) { console.error('no webSocket instance found!'); return; } const messageQueue = []; const _onMessage = webSocket.onmessage; webSocket.onmessage = (event) => messageQueue.push(event); document.addEventListener('DOMContentLoaded', () => { messageQueue.forEach(event => onMessage(event)); webSocket.onmessage = _onMessage; }); const commandQueue = []; const _sendBytes = window.sendBytes; window.sendBytes = (command) => commandQueue.push(command); const _onOpen = webSocket.onopen; webSocket.onopen = (event) => { window.sendBytes = _sendBytes; commandQueue.forEach(command => window.sendBytes(command)); return _onOpen(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(); // fix scrollText (e.g. when joining the game and receiving xp at that moment) window.mouseX = window.innerWidth / 2; window.mouseY = window.innerHeight / 2; })();