您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Improve Diamond Hunt Online and fix some inconsistencies
当前为
// ==UserScript== // @name DHO Fixed // @namespace FileFace // @description Improve Diamond Hunt Online and fix some inconsistencies // @version 0.54.6 // @author Zorbing // @grant none // @run-at document-start // @include http://www.diamondhunt.co/game.php // ==/UserScript== /** * TODO: * - restyle tabs (allow sub-tabs) * - add activity log (intercepting the dialog and log some messages) * - add new item style for mining engineer * - hide browser notifications if the corresponding tab is opened */ (function () { 'use strict'; const settings = { reorderFarming: { title: 'Set seed orders coherent' , defaultValue: true } , applyNewItemStyle: { title: 'Apply a new item style' , defaultValue: true } , applyNewKeyItemStyle: { title: 'Apply a new key item and machinery style' , defaultValue: true } , improveDialogBtns: { title: 'Improve button captions in dialogs' , defaultValue: true } , improveMachineryDialog: { title: 'Improve the machinery dialog' , defaultValue: true } , hideSomeCraftRecipes: { title: 'Hide some crafting recipes' , defaultValue: true } , hideMaxRecipes: { title: 'Hide recipes of maxed machines' , defaultValue: true } , expandEquipment: { title: 'Expand crafting recipes of equipment' , defaultValue: true } , hideEquipment: { title: 'Hide inferiour equipment (only up to gold)' , defaultValue: true } , hideUnnecessaryPrice: { title: 'Hide unnecessary prices' , defaultValue: true } , useFastLevelCalculation: { title: 'Use fast level calculation' , defaultValue: true } , showNotifications: { title: 'Show notifications for events' , defaultValue: true } , useNewChat: { title: 'Use the new chat with local history' , defaultValue: true } }; let fullyLoaded = false; let notify = () => Promise.reject('Notifications disabled'); /** * global constants */ const maxLevel = 100; const maxLevelVirtual = 1000; const furnaceLevels = ['', 'stone', 'bronze', 'iron', 'silver', 'gold', 'ancient', 'promethium', 'runite', 'dragon']; const ovenLevels = ['bronze', 'iron', 'silver', 'gold', 'ancient', 'promethium', 'runite', 'dragon']; const barTypes = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite']; const oilConsumption = { 'drill': 1 , 'crusher': 15 , 'giantDrill': 30 , 'roadHeader': 50 , 'bucketWheelExcavator': 150 , 'giantBWE': 500 , 'sandCollector': 5 }; const machineNames = { 'drill': 'Mining Drill' , 'crusher': 'Crusher' , 'giantDrill': 'Giant Drill' , 'roadHeader': 'Road Header' , 'bucketWheelExcavator': 'Excavator' , 'giantBWE': 'Mega Excavator' , 'sandCollector': 'Sand Collector' }; /** * observer stuff */ 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 initObservable() { const oldLoadGlobals = window.loadGlobals; window.loadGlobals = (key, newValue) => { if (key === undefined) { return; } const oldValue = window[key]; const ret = oldLoadGlobals(key, newValue); if (oldValue !== newValue) { (observedKeys.get(key) || []).forEach(fn => fn(key, oldValue, newValue)); } return ret; }; } /** * settings */ function getSetting(key) { if (!settings.hasOwnProperty(key)) { return; } const name = 'setting.' + key; return localStorage.hasOwnProperty(name) ? JSON.parse(localStorage.getItem(name)) : settings[key].defaultValue; } function setSetting(key, value) { if (!settings.hasOwnProperty(key)) { return; } localStorage.setItem('setting.' + key, JSON.stringify(value)); } function initSettings() { if (!localStorage.hasOwnProperty('setSoundToggleDefault')) { const defaultSound = 'off'; localStorage.setItem('soundToggle', defaultSound); localStorage.setItem('setSoundToggleDefault', true); document.getElementById('sound-toggle').innerHTML = defaultSound; } const table = document.getElementById('settings-tab').querySelector('table'); if (!table) { return; } const headerRow = table.insertRow(-1); headerRow.innerHTML = `<th style="background-color:black;color:orange"> Userscript "DHO Fixed"<br> <span style="font-size: 0.9rem;">(changes require reloading the tab)</span> </th>`; for (let key in settings) { let value = getSetting(key); const row = table.insertRow(-1); row.innerHTML = `<td id="fake-link-top"> ${settings[key].title}: <span style="color:cyan;" id="userscript-${key}">${value ? 'on' : 'off'}</span> </td>`; const indicator = document.getElementById('userscript-' + key);; row.addEventListener('click', () => { value = !value; setSetting(key, value); indicator.textContent = value ? 'on' : 'off'; }); } const settingLink = document.querySelector('.top-menu td[onclick^="openTab"]'); settingLink.addEventListener('click', function () { const activeTab = document.querySelector('#tab-tr td[style^="background: linear-gradient(rgb"]'); if (activeTab) { activeTab.style.background = 'linear-gradient(black, grey)'; } }); } /** * fix key items */ function fixKeyItems() { // remove unnecessary br element const oilPump = document.getElementById('key-item-handheldOilPump-box'); let br = oilPump && oilPump.nextElementSibling; if (!br) { br = document.createElement('br'); } // add br element after img in oil pipe element const oilPipe = document.getElementById('key-item-bindedOilPipe-box'); let img = oilPipe && oilPipe.children[0]; img = img && img.children[0]; img.parentNode.insertBefore(br, img.nextSibling); } /** * fix farming */ const seedOrder = ['bloodLeafSeeds', 'redMushroomSeeds', 'dottedGreenLeafSeeds', 'potatoSeeds', 'strawberrySeeds', 'greenLeafSeeds', 'redMushroomTreeSeeds', 'wheatSeeds', 'blewitMushroomSeeds', 'limeLeafSeeds', 'blewitMushroomTreeSeeds', 'snapeGrassSeeds', 'starDustSeeds', 'appleTreeSeeds', 'iceBerrySeeds', 'goldLeafSeeds', 'starDustTreeSeeds', 'stripedLeafSeeds', 'essenceSeeds', 'crystalLeafSeeds', 'megaDottedGreenLeafSeeds', 'megaRedMushroomSeeds', 'essenceTreeSeeds', 'megaGreenLeafSeeds', 'stripedCrystalLeafSeeds', 'megaBlewitMushroomSeeds', 'megaLimeLeafSeeds']; const seeds = { bloodLeafSeeds: { title: 'Blood Leaf Seed' , level: 1 , diesUntil: 0 , time: 5 , xp: 1e6 } , redMushroomSeeds: { title: 'Red Mushroom Seed' , level: 1 , diesUntil: 0 , time: 15 , xp: 100 } , dottedGreenLeafSeeds: { title: 'Green Dotted Leaf Seed' , level: 1 , diesUntil: 15 , time: 30 , xp: 250 } , potatoSeeds: { title: 'Potato' , level: 5 , diesUntil: 0 , time: 15 , xp: 35 } , strawberrySeeds: { title: 'Strawberry Seed' , level: 10 , diesUntil: 0 , time: 30 , xp: 85 } , greenLeafSeeds: { title: 'Green Leaf Seed' , level: 10 , diesUntil: 25 , time: 60 , xp: 500 } , redMushroomTreeSeeds: { title: 'Red Mushroom Tree Seed' , level: 10 , diesUntil: 30 , time: 8*60 , xp: 2e3 } , wheatSeeds: { title: 'Wheat Seed' , level: 15 , diesUntil: 0 , time: 15 , xp: 95 } , blewitMushroomSeeds: { title: 'Blewit Mushroom Seed' , level: 15 , diesUntil: 0 , time: 20 , xp: 200 } , limeLeafSeeds: { title: 'Lime Leaf Seed' , level: 20 , diesUntil: 40 , time: 1.5*60 , xp: 1500 } , blewitMushroomTreeSeeds: { title: 'Blewit Mushroom Tree Seed' , level: 20 , diesUntil: 40 , time: 10*60 , xp: 4e3 } , snapeGrassSeeds: { title: 'Snape Grass Seed' , level: 25 , diesUntil: 0 , time: 30 , xp: 300 } , starDustSeeds: { title: 'Stardust Seed' , level: 30 , diesUntil: 0 , time: 30 , xp: 750 } , appleTreeSeeds: { title: 'Apple Tree Seed' , level: 30 , diesUntil: 45 , time: 8*60 , xp: 5e3 } , iceBerrySeeds: { title: 'Ice Berry Seed' , level: 35 , diesUntil: 0 , time: 60 , xp: 450 } , goldLeafSeeds: { title: 'Gold Leaf Seed' , level: 40 , diesUntil: 55 , time: 4*60 , xp: 10e3 } , starDustTreeSeeds: { title: 'Stardust Tree Seed' , level: 40 , diesUntil: 55 , time: 5*60 , xp: 15e3 } , stripedLeafSeeds: { title: 'Striped Gold Leaf Seed' , level: 55 , diesUntil: 70 , time: 7*60 , xp: 25e3 } , essenceSeeds: { title: 'Essence Seed' , level: 60 , diesUntil: 0 , time: 3*60 , xp: 30e3 } , crystalLeafSeeds: { title: 'Crystal Leaf Seed' , level: 70 , diesUntil: 85 , time: 10*60 , xp: 40e3 } , megaDottedGreenLeafSeeds: { title: 'Mega Dotted Green Leaf Seed' , level: 70 , diesUntil: 0 , time: 16*60 , xp: 12500 } , megaRedMushroomSeeds: { title: 'Mega Red Mushroom Seed' , level: 70 , diesUntil: 0 , time: 16*60 , xp: 20500 } , essenceTreeSeeds: { title: 'Essence Tree Seed' , level: 80 , diesUntil: 90 , time: 12*60 , xp: 50500 } , megaGreenLeafSeeds: { title: 'Mega Green Leaf Seed' , level: 80 , diesUntil: 0 , time: 20*60 , xp: 21e3 } , stripedCrystalLeafSeeds: { title: 'Striped Crystal Leaf Seed' , level: 85 , diesUntil: 95 , time: 15*60 , xp: 90e3 } , megaBlewitMushroomSeeds: { title: 'Mega Blewit Mushroom Seed' , level: 85 , diesUntil: 0 , time: 20*60 , xp: 21500 } , megaLimeLeafSeeds: { title: 'Mega Lime Leaf Seed' , level: 85 , diesUntil: 0 , time: 23*60 , xp: 32e3 } }; function fixFarming() { const inputs = document.querySelectorAll('#dialog-planter input[type="image"]'); for (let i = inputs.length-1; i >= 0; i--) { const input = inputs[i]; const key = input.id.replace('planter-input-img-', ''); const seed = seeds[key]; input.title = seed.title; } if (!getSetting('reorderFarming')) { return; } let planterEl = inputs[0]; const planterParent = planterEl.parentNode; let boxEl = document.querySelector('#farming-tab .inventory-item-box-farming').parentNode; const boxParent = boxEl.parentNode; const btnParent = document.getElementById('seed-menu-popup'); let btnEl = btnParent.firstElementChild; for (let i = seedOrder.length-1; i >= 0; i--) { const key = seedOrder[i]; const input = document.getElementById('planter-input-img-' + key); if (input) { planterParent.insertBefore(input, planterEl); planterParent.insertBefore(document.createTextNode(' '), planterEl); planterEl = input; } const box = document.getElementById('item-' + key + '-box'); if (box) { boxParent.insertBefore(box.parentNode, boxEl); boxParent.insertBefore(document.createTextNode(' '), boxEl); boxEl = box.parentNode; } const btn = document.getElementById('btn-' + key); if (btn) { btn.title = btn.title.replace('dieing', 'dying'); btnParent.insertBefore(btn, btnEl); btnParent.insertBefore(document.createTextNode(' '), btnEl); btnEl = btn; } } } /** * fix server message */ function fixServerMsg() { const serverMsgEl = document.querySelector('#server-inner-msg'); if (!serverMsgEl) { return; } const serverMsg = serverMsgEl.textContent; const close = document.querySelector('#server-top-msg > *:last-child'); if (localStorage.getItem('closedServerMsg') == serverMsg) { close.click(); return; } close.addEventListener('click', function () { localStorage.setItem('closedServerMsg', serverMsg); }); } /** * highlight requirements */ const highlightBgColor = 'hsla(0, 100%, 90%, 1)'; const imgSrc2Key = { 'bronzebar': 'bronzeBar' , 'ironbar': 'ironBar' , 'silverbar': 'silverBar' , 'goldbar': 'goldBar' , 'stonefurnace': 'stoneFurnace' , 'bronzefurnace': 'bronzeFurnace' , 'ironfurnace': 'ironFurnace' , 'silverfurnace': 'silverFurnace' , 'goldfurnace': 'goldFurnace' , 'pic_coin': 'coins' , 'stardust': 'starDust' , 'treasureKey': 'treasureChestKey' , 'dottedgreenleaf': 'dottedGreenLeaf' , 'redmushroom': 'redMushroom' , 'greenleaf': 'greenLeaf' , 'limeleaf': 'limeLeaf' , 'blewitmushroom': 'blewitMushroom' , 'goldleaf': 'goldLeaf' , 'pureWater': 'pureWaterPotion' , 'snapegrass': 'snapeGrass' , 'crystalleaf': 'crystalLeaf' , 'starDustConverter': 'starGemPotion' , 'superStargemPotion': 'superStarGemPotion' , 'superoilpotion': 'superOilPotion' , 'wooden_slave': 'miners' , 'fishingRodFarmer': 'fishingRod' , 'goldenStriper': 'goldenStriperPotion' , 'orb': 'orbOfTransformation' , 'anyorb': 'emptyBlueOrb' , 'anyorb2': 'emptyGreenOrb' , 'upgradedOrb': 'superOrbOfTransformation' }; const imgSrc2LevelKey = { 'watering-can': 'merchanting' , 'cookingskill': 'cooking' , 'archaeology': 'exploring' , 'wizardHatIcon': 'magic' }; function amount2Int(str) { return parseInt(str.replace(/M/i, '000000').replace(/B/i, '000000000').replace(/\D/g, ''), 10); } function checkRequirements(row, xpKey, init = true) { const isRed = row.style.backgroundColor == 'rgb(255, 128, 128)'; let everythingFulfilled = true; let keys2Observe = []; const levelEl = row.cells[2]; const neededLevel = parseInt(levelEl.textContent, 10); const levelHighEnough = neededLevel <= window.getLevel(window[xpKey]); levelEl.style.color = levelHighEnough ? '' : 'red'; everythingFulfilled = everythingFulfilled && levelHighEnough; keys2Observe.push(xpKey); const reqEl = row.cells[3]; const children = reqEl.children; // check for each requirement if it is fulfilled for (let i = 0; i < children.length; i++) { const el = children[i]; if (el.tagName != 'IMG') { continue; } const imgKey = el.src.replace(/^.+images\/.*?([^\/]+)\..+$/, '$1'); const key = imgSrc2Key[imgKey] || imgKey; // wrap the amount with a span element let valueSpan = el.nextSibling; if (valueSpan.nodeType == Node.TEXT_NODE) { const valueTextNode = valueSpan; valueSpan = document.createElement('span'); valueTextNode.parentNode.insertBefore(valueSpan, valueTextNode); valueSpan.appendChild(valueTextNode); const text = valueTextNode.textContent; if (/^\s?\d[\d',\.]*$/.test(text)) { valueTextNode.textContent = ' ' + formatNumber(text.replace(/\D/g, '')); } } const amount = amount2Int(valueSpan.textContent); const has = parseInt(window[key] || '0', 10); const isSkill = imgSrc2LevelKey.hasOwnProperty(key); let fulfilled = has >= amount; if (isSkill) { const xpKey = imgSrc2LevelKey[key] + 'Xp'; fulfilled = window.getLevel(window[xpKey]) >= amount; keys2Observe.push(xpKey); } else if (key == 'gem') { fulfilled = window.sapphire >= amount || window.emerald >= amount || window.ruby >= amount || window.diamond >= amount; keys2Observe.push('sapphire', 'emerald', 'ruby', 'diamond'); } else if (/furnace/i.test(key)) { const furnaceLevel = furnaceLevels.indexOf(key.replace(/furnace/i, '')); fulfilled = fulfilled || parseInt(window.bindedFurnaceLevel, 10) >= furnaceLevel; keys2Observe.push(key, 'bindedFurnaceLevel'); } else if (key == 'anybar') { const amountArray = valueSpan.parentNode.getAttribute('tooltip').replace(/\D*$/, '').split('/') .map(str => amount2Int(str)); fulfilled = false; for (let i = 0; i < barTypes.length; i++) { const bar = barTypes[i]; fulfilled = fulfilled || window[bar + 'Bar'] >= amountArray[i]; keys2Observe.push(bar); } } else if (/(?:wand|staff)$/i.test(key)) { const bindedKey = 'binded' + key[0].toUpperCase() + key.substr(1); fulfilled = fulfilled || window[bindedKey] > 0; keys2Observe.push(key, bindedKey); } else { if (!window.hasOwnProperty(imgKey) && !imgSrc2Key.hasOwnProperty(imgKey)) { console.debug('missing key handling:', key, el); } keys2Observe.push(key); } valueSpan.style.color = fulfilled ? '' : 'red'; everythingFulfilled = everythingFulfilled && (isSkill || fulfilled); } levelEl.style.backgroundColor = everythingFulfilled ? '' : highlightBgColor; reqEl.style.backgroundColor = everythingFulfilled ? '' : highlightBgColor; row.style.backgroundColor = everythingFulfilled ? 'rgb(194, 255, 133)' : 'rgb(255, 128, 128)'; if (init) { observe(keys2Observe, () => checkRequirements(row, xpKey, false)); } } function highlightRequirements() { const craftingTables = { 'crafting': { tabId: 'crafting' , xp: 'crafting' } , 'brewing': { tabId: 'brewing' , xp: 'brewing' } , 'achCraft': { tabId: 'archaeology-crafting' , xp: 'crafting' } , 'cooking': { tabId: 'cooking' , xp: 'cooking' } , 'magicCraft': { tabId: 'magiccrafting' , xp: 'crafting' } , 'spellbook': { tabId: 'spellbook' , xp: 'magic' } }; for (let key in craftingTables) { const info = craftingTables[key]; const xpName = info.xp + 'Xp'; const table = document.querySelector('#' + info.tabId + '-tab table.table-stats'); const rows = table.rows; for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (row.getElementsByTagName('th').length > 0 || row.id == 'craft-ghostKey') { continue; } checkRequirements(row, xpName, true); } } // hightlight mining level for mining table function highlightMiningLevel() { const miningLevel = window.getLevel(window.miningXp); const table = document.querySelector('#mining-tab table.table-stats'); const rows = table.rows; for (let i = 2; i < rows.length; i++) { const row = rows[i]; const level = parseInt(row.cells[2].textContent, 10); const tooLow = level > miningLevel; row.cells[2].style.color = tooLow ? 'red' : ''; row.style.backgroundColor = tooLow ? 'hsla(0, 100%, 90%, 1)' : ''; } } highlightMiningLevel(); observe('miningXp', () => highlightMiningLevel()); const oldLoadGhostPirates = window.loadGhostPirates; const ghostKeyRow = document.getElementById('craft-ghostKey'); window.loadGhostPirates = () => { oldLoadGhostPirates(); if (ghostEssenceTimer > 0) { // this method is called once per second, so there is no need for observing any values checkRequirements(ghostKeyRow, 'craftingXp', false); } }; function highlightFarmingLevel() { const farmingLevel = window.getLevel(window.merchantingXp); const seedBtns = document.querySelectorAll('#seed-menu-popup > div.dialogue-seed-btn'); for (let i = 0; i < seedBtns.length; i++) { const seedBtn = seedBtns[i]; const table = seedBtn.firstElementChild; const levelCell = table.rows[0].cells[1]; const level = parseInt(levelCell.textContent.replace(/\D/g, ''), 10); const tooLow = level > farmingLevel; seedBtn.style.backgroundColor = tooLow ? 'hsla(0, 50%, 75%, 1)' : ''; levelCell.style.color = tooLow ? 'red' : ''; levelCell.style.textShadow = tooLow ? '0 0 5px white' : ''; } } highlightFarmingLevel(); observe('merchantingXp', () => highlightFarmingLevel()); // achievement upgrades function highlightAchievementUpgrades() { const points = parseInt(window.achPoints, 10); const spans = document.querySelectorAll('span[id^="cost-ach-"][id$="AchUpgrade"]'); for (let i = 0; i < spans.length; i++) { const span = spans[i]; const notEnough = parseInt(span.textContent, 10) > points; span.style.setProperty('color', notEnough ? 'red' : '', 'important'); span.style.fontWeight = notEnough ? 'bold' : ''; } } highlightAchievementUpgrades(); observe('achPoints', () => highlightAchievementUpgrades()); } /** * fix market */ function fixMarket() { // create an observer instance const observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { // hide duplicate orb var orbs = mutation.target.querySelectorAll('input[alt="upgradeEnchantedRake"]'); if (orbs.length > 1) { orbs[1].style.display = 'none'; } }); }); // configuration of the observer: const config = { childList: true }; const table = document.getElementById('selling-tradable-table'); observer.observe(table, config); // fix loading icons const loadingImgs = document.querySelectorAll('[src="images/loading_statique.png"]'); for (var i = 0; i < loadingImgs.length; i++) { loadingImgs[i].src = 'images/loading.gif'; } const oldFilterBuyables = window.filterBuyables; let lastFilterText = null; window.filterBuyables = (text) => { lastFilterText = text; return oldFilterBuyables(text); }; const oldApplyToBuyingTable = window.applyToBuyingTable; window.applyToBuyingTable = (...args) => { const ret = oldApplyToBuyingTable(...args); if (lastFilterText != null) { window.filterBuyables(lastFilterText); } return ret; }; // add "clear search"-button const searchInput = document.querySelector('input[onkeyup^="filterBuyables"]'); searchInput.id = 'market-search'; const tmpWrapper = document.createElement('templateWrapper'); tmpWrapper.innerHTML = `<input type="button" value="Clear search" style="float: left; margin-left: 10px;" onclick="$('#market-search').val('').keyup()">`; const parent = searchInput.parentNode; const el = searchInput.nextSibling; const childNodes = tmpWrapper.childNodes; for (let i = 0; i < childNodes.length; i++) { parent.insertBefore(childNodes[i], el); } // fix icon paths const oldGetImagePath = window.getImagePath; window.getImagePath = (itemVar) => { if (itemVar == 'dragonFurnace') { return 'images/crafting/dragonFurnace.gif'; } return oldGetImagePath(itemVar); }; // auto focus the search input const oldSelectItemToTradeDialog = window.selectItemToTradeDialog; window.selectItemToTradeDialog = (sellOrBuy, slot) => { oldSelectItemToTradeDialog(sellOrBuy, slot); window.$('#id_search').focus(); }; } /** * improve level calculation */ let levelXp = new Array(maxLevelVirtual+1); function calcLevelXp(level) { return level > 0 ? Math.round(Math.pow((level-1), 3 + ((level-1) / 200))) : 0; } function getLevelXp(level) { return levelXp[level-1] || calcLevelXp(level); } const getDynamicLevel = (function () { const size = Math.pow(2, Math.ceil(Math.log2(maxLevel))); let xpTree = new Array(size); let levelTree = new Array(size); const sizeVirtual = Math.pow(2, Math.ceil(Math.log2(maxLevelVirtual))); let xpTreeVirtual = new Array(sizeVirtual); let levelTreeVirtual = new Array(sizeVirtual); createNode(xpTree, levelTree, 1, maxLevel, 0); createNode(xpTreeVirtual, levelTreeVirtual, 1, maxLevelVirtual, 0); function createNode(xpArray, levelArray, start, end, i) { const current = start + Math.pow(2, Math.floor(Math.log2(end - start + 1))) - 1; xpArray[i] = getLevelXp(current); levelArray[i] = current; if (current - start > 0) { createNode(xpArray, levelArray, start, current-1, 2*i + 1); } if (end - current > 0) { createNode(xpArray, levelArray, current+1, end, 2*i + 2); } } function getDynamicLevel(playerXP, useVirtual = false) { const isVirtual = window.virtualLevelsOn !== 0 && useVirtual === true; const xpArray = isVirtual ? xpTreeVirtual : xpTree; const levelArray = isVirtual ? levelTreeVirtual : levelTree; let i = 0; let level = 0; while (xpArray[i] != null) { if (playerXP == xpArray[i]) { return levelArray[i]; } else if (playerXP < xpArray[i]) { i = 2*i+1; } else if (playerXP > xpArray[i]) { level = levelArray[i]; i = 2*i+2; } } return level; } return getDynamicLevel; })(); function getLevel(playerXP) { return getDynamicLevel(playerXP, false); } function getVirtualLevel(playerXP) { return getDynamicLevel(playerXP, true); } function getGlobalLevel() { return getDynamicGlobalLevel(false); } function getDynamicGlobalLevel(useVirtual = false) { return Math.floor(getDynamicLevel(parseInt(window.miningXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.craftingXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.brewingXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.merchantingXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.exploringXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.cookingXp, 10), useVirtual)) + Math.floor(getDynamicLevel(parseInt(window.magicXp, 10), useVirtual)) ; } function improveLevelCalculation() { if (!getSetting('useFastLevelCalculation')) { return; } for (var i = 1; i < maxLevelVirtual; i++) { levelXp[i-1] = calcLevelXp(i); } window.getLevel = getLevel; window.getVirtualLevel = getVirtualLevel; window.getGlobalLevel = getGlobalLevel; } /** * fix inventory */ function fixInventory() { if (!getSetting('hideUnnecessaryPrice')) { return; } const tab = document.getElementById('gatherings-tab'); const coinImgs = tab.querySelectorAll('span[id^="item-"][id$="-box"] img[src="images/pic_coin.png"]'); for (let i = 0; i < coinImgs.length; i++) { const coinImg = coinImgs[i]; const price = coinImg.nextSibling; if (price.nodeType == Node.TEXT_NODE && !/\d/.test(price.textContent)) { const parent = coinImg.parentNode; parent.removeChild(coinImg); parent.removeChild(price); } } } /** * fix machinery */ function getMachineCount(machine) { return window['binded' + machine[0].toUpperCase() + machine.substr(1)]; } function getOilValueFromMachine(machine) { return (oilConsumption[machine] || 0) * getMachineCount(machine); } function updateRepairCost(machine) { const input = document.getElementById('machineryChosenPopup'); const repairCost = document.getElementById('repair-price-dialog'); if (!input || !repairCost) { return; } machine = machine || input.value; const percent = window[machine + 'Repair']; const cost = window.getRepairCost(machine, percent); repairCost.textContent = formatNumber(cost); } function openOilDialogue(varname) { const gearOnPath = 'images/spinning-gear.gif'; const gearOffPath = 'images/spinning-gear-off.gif'; const oilArea = document.getElementById('oilUsage-area'); const oilValue = document.getElementById('oilUsage-value'); const repairArea = document.getElementById('machinery-repair-area'); let machine = varname.replace(/key-item-binded([^-]+)-box/, '$1'); machine = machine[0].toLowerCase() + machine.substr(1); // machine name + count const name = machineNames[machine]; const count = getMachineCount(machine); const max = 10; // don't know if there is a machine with a different limit... let title = document.getElementById('machinery-name'); if (!title) { title = document.createElement('h3'); title.style.marginTop = 0; title.id = 'machinery-name'; const parent = document.getElementById('machinery-dialog'); parent.insertBefore(title, parent.firstChild); } title.innerHTML = `${name} <span style="float: right;font-size: 1.2rem;">${count}<span style="font-weight: normal;">/${max}</span><span></span></span>`; // PROGRESS BAR var hasRepair = window.bindedPromethiumWrench > 0; if (machine == 'sandCollector') { // hide repair part (ensure, it is hidden) repairArea.setAttribute('style', 'padding: 0; width: 0px; height: 0px; overflow: hidden; border: 0;'); } else { // show repair part if available repairArea.setAttribute('style', 'display: ' + (hasRepair ? 'block' : 'none') + ';'); const progressBar = document.getElementById('progress-bar-repair-opened'); const percent = window[machine + 'Repair']; const bgColor = percent < 20 ? 'yellow' : (percent >= 50 ? 'lime' : 'yellow'); progressBar.style.backgroundColor = bgColor; progressBar.style.width = percent + '%'; let repairButton = document.getElementById('repair-current-machine'); if (!repairButton) { repairButton = document.createElement('button'); repairButton.id = 'repair-current-machine'; repairButton.style.lineHeight = '24px'; repairButton.style.margin = '10px 5% 0'; repairButton.style.width = '90%'; repairButton.style.position = 'relative'; repairButton.innerHTML = `<img id="bindedPromethiumWrenchOrb-img" src="images/crafting/promethiumWrench.png" alt="workers" width="23px" height="23px" style="position: absolute; top: 3px; left: 13px;">Repair for <span id="repair-price-dialog"></span><img src="images/pic_coin.png" width="25px" height="25px" style="vertical-align: middle;">`; repairButton.onclick = () => { const machine = document.getElementById('machineryChosenPopup').value; window.send('REPAIR_MACHINERY=' + machine); }; const parent = document.getElementById('machinery-repair-area'); parent.appendChild(repairButton); } updateRepairCost(machine); } // END PROGRESS BAR oilValue.innerHTML = window.getOilValueFromMachine(machine); document.getElementById('machineryChosenPopup').value = machine; const isOn = window[machine + 'AreOn'] == 1; document.getElementById('myonoffswitch').checked = isOn; document.getElementById('myonoffswitch-gear').src = isOn ? gearOnPath : gearOffPath; oilArea.style.display = isOn ? '' : 'none'; window.$('#machinery-dialog').dialog( { width: 400 }); } function fixMachinery() { const oldChangeSmeltingValue = window.changeSmeltingValue; window.changeSmeltingValue = () => { window.setSmeltingBarAgain( window.barTypeSelectedToSmeltGlobal , document.getElementById('smeltingAmountRequested') ); }; const oldOpenFurnaceDialogue = window.openFurnaceDialogue; window.openFurnaceDialogue = () => { const ret = oldOpenFurnaceDialogue(); if (furnacePerc == 0) { window.changeSmeltingValue(); } return ret; }; const oldRapairMachinery = window.rapairMachinery; window.rapairMachinery = () => { oldRapairMachinery(); document.getElementById('perc-all-cost').innerHTML = window.getRepairCost('all', 0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); }; const furnaceCapacaties = [0, 10, 30, 75, 150, 300, 500, 750, 1000, 1250]; function upgradeFurnaceOrb() { if (window.bindedUpgradeFurnaceOrb != 1) { return; } for (let i = 1; i < furnaceLevels.length; i++) { let furnaceType = furnaceLevels[i]; furnaceType = furnaceType[0].toUpperCase() + furnaceType.substr(1); const capacity = 1.5 * furnaceCapacaties[i]; const box = document.getElementById('key-item-binded' + furnaceType + 'Furnace-box'); let textNode = box.lastChild; if (textNode.nodeType !== Node.TEXT_NODE) { textNode = textNode.lastChild; } textNode.textContent = ' ' + formatNumber(capacity); } } upgradeFurnaceOrb(); observe('bindedUpgradeFurnaceOrb', () => upgradeFurnaceOrb()); if (!getSetting('improveMachineryDialog')) { return; } window.getOilValueFromMachine = getOilValueFromMachine; window.openOilDialogue = openOilDialogue; observe(['drillRepair', 'crusherRepair', 'giantDrillRepair', 'roadHeaderRepair', 'bucketWheelExcavatorRepair', 'giantBWERepair'], () => updateRepairCost()); } /** * fix brewing */ const potionRequirements = { 'seedPotion': { level: 5 , dottedGreenLeaf: 5 , redMushroom: 100 , greenLeaf: 1 } }; let oldCanBrewItem; function canBrewItem(command) { var requirements = potionRequirements[command]; if (!requirements) { return oldCanBrewItem(command); } for (var key in requirements) { if (key == 'level') { if (getLevel(brewingXp) < requirements.level) { return false; } } else if (window[key] < requirements[key]) { return false; } } return true; } function fixBrewing() { oldCanBrewItem = window.canBrewItem; window.canBrewItem = canBrewItem; const marginFix = '5px 20px'; const potionItems = document.querySelectorAll('#brewing-tab [id$="Potion-box"] img.item-box-img'); for (let i = 0; i < potionItems.length; i++) { potionItems[i].style.margin = marginFix; } const smallImgItems = ['vial','enchantedVial','compost']; for (let item of smallImgItems) { document.querySelector('#item-' + item + '-box img.item-box-img').style.margin = marginFix; } } /** * fix tabs */ const tabs2Fix = { repair: { name: 'Machinery' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/machinery' } , store: { name: 'Market' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market' } , 'npc-store': { name: 'Game Shop' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/game' } , 'donor-store': { name: 'Donor Shop' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/donor' } , 'player-store': { name: 'Player Market' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/player' } , stats: { name: 'Leaderboards' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/stats' } , coop: { name: 'Group Tasks' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/coop' } , collectables: { name: 'Collectables' } , miningEngineer: { name: 'Mining Engineer' } , 'ach-explore': { name: 'Exploring — Equipment' , url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/exploration#wiki_equipment' } }; function tabTitleLink2Span(title) { const span = title.parentNode; span.appendChild(title.firstChild); span.removeChild(title); span.setAttribute('tooltip', ''); span.style.color = 'gold'; span.style.fontSize = '24pt'; } function fixTabs() { function removeElement(el) { el.parentNode.removeChild(el); } /** * some special treatment */ const achievementTitle = document.querySelector('#ach-tab a'); tabTitleLink2Span(achievementTitle); const npcH1 = document.querySelector('#npc-store-tab h1'); removeElement(npcH1); const vendorBr = document.querySelector('#vendor-tab > br:first-child'); removeElement(vendorBr); const vendorTitle = document.querySelector('#vendor-tab a'); tabTitleLink2Span(vendorTitle); const wizardBr = document.querySelector('#wizard-tab > br:first-child'); removeElement(wizardBr); const achTitle = document.querySelector('#archaeology-tab a'); achTitle.title = ''; const achCraftTitle = document.querySelector('#archaeology-crafting-tab a'); achCraftTitle.textContent = 'Exploring — Crafting'.toUpperCase(); tabTitleLink2Span(achCraftTitle); const cookingTitle = document.querySelector('#cooking-tab a'); cookingTitle.textContent = 'Exploring — Cooking'.toUpperCase(); cookingTitle.title = ''; cookingTitle.parentNode.setAttribute('tooltip', 'Open Wiki'); const magicSpellbookTitle = document.querySelector('#spellbook-tab a'); magicSpellbookTitle.textContent = 'Magic — spellbook'.toUpperCase(); const magicCraftTitle = document.querySelector('#magiccrafting-tab a'); magicCraftTitle.textContent = 'Magic — Crafting'.toUpperCase(); tabTitleLink2Span(magicCraftTitle); removeElement(document.querySelector('#repair-tab > br:last-child')); removeElement(document.querySelector('#repair-tab > br:last-child')); removeElement(document.querySelector('#miningEngineer-tab br')); removeElement(document.querySelector('#brewing-tab br')); removeElement(document.querySelector('#archaeology-tab br')); removeElement(document.querySelector('#ach-explore-tab br')); removeElement(document.querySelector('#ach-explore-tab br')); const archCraftBr = document.querySelector('#archaeology-crafting-tab br'); archCraftBr.parentNode.insertBefore(document.createElement('br'), archCraftBr); removeElement(document.querySelector('#cooking-tab br')); removeElement(document.querySelector('#cooking-tab br')); removeElement(document.querySelector('#cooking-tab br')); removeElement(document.querySelector('#magic-tab br')); removeElement(document.querySelector('#magiccrafting-tab br')); removeElement(document.querySelector('#magiccrafting-tab br')); for (let i = 0; i < 10; i++) { removeElement(document.querySelector('#magiccrafting-tab > span + br')); } removeElement(document.querySelector('#store-tab br')); removeElement(document.querySelector('#player-store-tab br')); removeElement(document.querySelector('#stats-tab br')); removeElement(document.querySelector('#stats-tab br')); removeElement(document.querySelector('#grouptasks-createorjoin br')); removeElement(document.querySelector('#grouptasks-notstarted br')); removeElement(document.querySelector('#grouptasks-notstarted br')); removeElement(document.querySelector('#grouptasks-started br')); for (let key in tabs2Fix) { const tab = tabs2Fix[key]; const tabEl = document.getElementById(key + '-tab'); const tmpEl = document.createElement('tmpWrapper'); let html = '<center>'; if (tab.url) { html += `<span class="activate-tooltip"> <a class="title-link" href="${tab.url}" target="_blank" title="Open Wiki">${tab.name.toUpperCase()}</a> </span>`; } else { html += `<span class="activate-tooltip" style="color: gold; font-size: 24pt;"> ${tab.name.toUpperCase()} </span>`; } html += '</center><br>'; tmpEl.innerHTML = html; let el = tabEl.firstElementChild; for (let i = tmpEl.children.length-1; i >= 0; i--) { const child = tmpEl.children[i]; tabEl.insertBefore(child, el); el = child; } } } /** * hide crafting recipes */ const recipes = { shovel: ['shovel'] , promethiumWrench: ['promethiumWrench', 'bindedPromethiumWrench'] , glassBlowingPipe: ['glassBlowingPipe', 'bindedGlassBlowingPipe'] , oilPipe: ['oilPipe', 'bindedOilPipe'] , planter: ['planter', 'bindedPlanter'] , trowel: ['trowel', 'bindedTrowel'] , shootingStarCrystal: ['shootingStarCrystal', 'bindedShootingStarCrystal'] , brewingKit: ['brewingKit', 'brewingKitBinded'] , rocket: ['rocket', 'bindedRocket'] , redPumpJack: ['redPumpJack', 'bindedRedPumpJack'] , explorersBrush: ['explorersBrush', 'bindedExplorersBrush'] , oilFactory: ['oilFactory', 'bindedOilFactory'] , robot: ['robot', 'bindedRobot'] , oilRefinery: ['oilRefinery', 'bindedOilRefinery'] , superRobot: ['superRobot', 'bindedSuperRobot'] // , fishingRod: ['bronzeRod', 'ironRod', 'goldRod', 'promethiumRod', 'fishingRod', 'dragonFishingRod', 'bindedDragonFishingRod'] , fishingRod: ['fishingRod', 'dragonFishingRod', 'bindedDragonFishingRod'] , fishingBoat: ['fishingBoat', 'bindedFishingBoat'] , largeFishingBoat: ['largeFishingBoat', 'bindedLargeFishingBoat'] }; function hideCraftingRecipes() { if (!getSetting('hideSomeCraftRecipes')) { return; } (function hideFurnaceRecipes(init = false) { let maxFurnaceLevel = parseInt(window.bindedFurnaceLevel, 10); let keys2Observe = ['bindedFurnaceLevel']; for (let i = furnaceLevels.length-1; i >= 0; i--) { const varName = furnaceLevels[i] + 'Furnace'; if (window[varName] > 0) { maxFurnaceLevel = Math.max(maxFurnaceLevel, i); } const row = document.getElementById('craft-' + furnaceLevels[i] + 'Furnace'); if (row) { const hide = i <= maxFurnaceLevel; row.style.display = hide ? 'none' : ''; keys2Observe.push(varName); } } if (init) { observe(keys2Observe, () => hideFurnaceRecipes(false)); } })(true); function hideRecipe(key, nameList, init = false) { const hide = nameList.some(name => window[name] != 0); document.getElementById('craft-' + key).style.display = hide ? 'none' : ''; if (init) { observe(nameList, () => hideRecipe(key, nameList, false)); } } for (let key in recipes) { hideRecipe(key, recipes[key], true); } // exploring - crafting (function hideOvenRecipes(init = false) { let maxOvenLevel = -1; let keys2Observe = []; for (let i = ovenLevels.length-1; i >= 0; i--) { const type = ovenLevels[i]; const ovenName = type + 'Oven'; const bindedOvenName = 'binded' + ovenName[0].toUpperCase() + ovenName.substr(1); if (window[ovenName] > 0 || window[bindedOvenName] > 0) { maxOvenLevel = Math.max(maxOvenLevel, i); } const row = document.getElementById('craft-' + type + 'Oven'); if (row) { const hide = maxOvenLevel >= i; row.style.display = hide ? 'none' : ''; keys2Observe.push(ovenName, bindedOvenName); } } if (init) { observe(keys2Observe, () => hideOvenRecipes(false)); } })(true); // exploring - equipment function hideEquipmentRecipe(key, type, init = false) { let highestLevel = parseInt(window[key + 'SlotId'], 10) - 1; for (let i = barTypes.length-1; i >= 0; i--) { const bar = barTypes[i]; if (window[bar + type] > 0) { highestLevel = Math.max(highestLevel, i); } const row = document.getElementById('craft-' + bar + type); if (row && highestLevel >= i) { row.style.display = 'none'; } } if (init) { observe(key + 'SlotId', () => hideEquipmentRecipe(key, type, false)); for (let i = barTypes.length-1; i >= 0; i--) { const bar = barTypes[i]; observe(bar + type, () => hideEquipmentRecipe(key, type, false)); } } } const equipmentTypes = { 'weapon': 'Sword' , 'helmet': 'Helmet' , 'body': 'Body' , 'leg': 'Legs' }; for (let key in equipmentTypes) { hideEquipmentRecipe(key, equipmentTypes[key], true); } // magic - crafting const magicRodTypes = ['gold', 'promethium', 'runite', 'dragon']; (function hideWandRecipe(init = false) { let maxWandLevel = -1; let keys2Observe = []; for (let i = magicRodTypes.length-1; i >= 0; i--) { const type = magicRodTypes[i]; const wandName = type + 'Wand'; const bindedWandName = 'binded' + wandName[0].toUpperCase() + wandName.substr(1); if (window[wandName] > 0 || window[bindedWandName] > 0) { maxWandLevel = Math.max(maxWandLevel, i); } const wandRow = document.getElementById('craft-' + type + 'Wand'); if (wandRow) { const hide = maxWandLevel >= i; wandRow.style.display = hide ? 'none' : ''; keys2Observe.push(wandName, bindedWandName); } } if (init) { observe(keys2Observe, () => hideWandRecipe(false)); } })(true); (function hideStaffRecipe(init = false) { let maxStaffLevel = -1; let keys2Observe = []; for (let i = magicRodTypes.length-1; i >= 0; i--) { const type = magicRodTypes[i]; const staffName = type + 'Staff'; const bindedStaffName = 'binded' + staffName[0].toUpperCase() + staffName.substr(1); if (window[staffName] > 0 || window[bindedStaffName] > 0) { maxStaffLevel = Math.max(maxStaffLevel, i); } const staffRow = document.getElementById('craft-' + type + 'Staff'); if (staffRow) { const hide = maxStaffLevel >= i; staffRow.style.display = hide ? 'none' : ''; keys2Observe.push(staffName, bindedStaffName); } } if (init) { observe(keys2Observe, () => hideWandRecipe(false)); } })(true); } /** * hide equipment */ const equipmentId2Type = { general: ['', 'Bronze', 'Iron', 'Silver', 'Gold', 'Promethium', 'Runite', 'Dragon'] , amulet: ['', 'Amulet of the Sea', 'Moonstone Amulet'/*??? TBD*/, 'Enchanted Amulet of the Sea', 'Dragon Amulet'] , shield: ['', 'Ancient Shield'] , ring: ['', 'Coin Ring', 'Pure Water Ring', 'Lava Ring'] , secondRing: ['', 'Looting Gloves'] }; const equipmentTypes = { 'weapon': 'Sword' , 'helmet': 'Helmet' , 'body': 'Body' , 'leg': 'Legs' }; const equipmentTypeList = ['helmet', 'amulet', 'weapon', 'body', 'shield', 'ring', 'leg', 'secondRing']; const equipmentLevels = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite', 'dragon']; const equipmentType2Name = { 'weapon': 'sword' , 'leg': 'legs' }; function setEquippedList(listCell, init) { let keys2Observe = []; let list = []; for (let type of equipmentTypeList) { const id = parseInt(window[type + 'SlotId'], 10); keys2Observe.push(type + 'SlotId'); type = equipmentType2Name[type] || type; if (!equipmentId2Type.hasOwnProperty(type)) { list.push(equipmentId2Type.general[id] + ' ' + type[0].toUpperCase() + type.substr(1)); } else { list.push(equipmentId2Type[type][id]); } } listCell.textContent = list.filter(str => str != '').join(', '); if (init) { for (let key of keys2Observe) { observe(key, () => setEquippedList(listCell, false)); } } } function examineEquipmentRecipes(key, type, init = false) { const currentLevel = parseInt(window[key + 'SlotId'], 10); // hide not more than gold equipment for (let i = 0; i < equipmentLevels.length; i++) { const el = document.getElementById('item-' + equipmentLevels[i] + type + '-box'); const hide = i < 4 && i < currentLevel; if (el) { el.parentNode.style.display = hide ? 'none' : ''; } } if (init) { observe(key + 'SlotId', () => examineEquipmentRecipes(key, type, false)); } } function hideEquipment() { const table = document.querySelector('#ach-explore-tab table.equipement-area-table'); const row = table.insertRow(-1); row.style.borderTop = '1px dashed'; const nameCell = row.insertCell(-1); nameCell.style.verticalAlign = 'top'; nameCell.textContent = 'Equipped:'; const listCell = row.insertCell(-1); listCell.colSpan = 2; listCell.textContent = ''; setEquippedList(listCell, true); if (!getSetting('hideEquipment')) { return; } for (let key in equipmentTypes) { examineEquipmentRecipes(key, equipmentTypes[key], true); } } /** * improve dialog buttons */ function improveDialogBtns() { if (!getSetting('improveDialogBtns')) { return; } const oldOpenDialogue = window.openDialogue; window.openDialogue = (title, message, yesButtonVal) => { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); // restore default state const empty = yesButtonVal == null || yesButtonVal == ''; okBtn.style.display = empty ? 'none' : ''; okBtn.value = 'OK'; cancelBtn.value = empty ? 'Close' : 'Cancel'; if (/stardust/i.test(title)) { okBtn.value = 'Smash it'; } else if (/bind/i.test(title)) { okBtn.value = 'Bind'; } else if (/drink/i.test(title)) { okBtn.value = 'Drink'; } else if (/^EXPLORE/.test(yesButtonVal)) { okBtn.value = 'Start expedition'; } return oldOpenDialogue(title, message, yesButtonVal); }; const oldOpenDialogueWidth = window.openDialogueWidth; window.openDialogueWidth = (title, message, yesButtonVal, widthWanted) => { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); // restore default state const empty = yesButtonVal == null || yesButtonVal == ''; okBtn.style.display = empty ? 'none' : ''; okBtn.value = 'OK'; cancelBtn.value = empty ? 'Close' : 'Cancel'; return oldOpenDialogueWidth(title, message, yesButtonVal, widthWanted); }; const oldClicksKeyItem = window.clicksKeyItem; window.clicksKeyItem = (varname) => { oldClicksKeyItem(varname); if (varname == 'key-item-bindedRocket-box' && rocketTimer == 0) { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); okBtn.value = 'Start rocket'; const textEl = document.querySelector('#dialog #dialog-text'); textEl.removeChild(textEl.lastChild); textEl.removeChild(textEl.lastChild); textEl.removeChild(textEl.lastChild); } }; const oldOpenFurnaceDialogue = window.openFurnaceDialogue; window.openFurnaceDialogue = () => { oldOpenFurnaceDialogue(); if (furnacePerc > 0) { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); okBtn.value = 'Cancel smelting'; cancelBtn.value = 'Close'; } }; const oldOpenAreaDialogue = window.openAreaDialogue; window.openAreaDialogue = () => { oldOpenAreaDialogue(); if (parseInt(exploringTimer) > 0) { const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]'); okBtn.value = 'Cancel trip'; cancelBtn.value = 'Close'; } }; } /** * expand equipment */ function expandEquipment() { if (!getSetting('expandEquipment')) { return; } const equipmentRows = document.querySelectorAll('tr[onclick^="openCraftSwordDialogue"]'); const rowParent = equipmentRows[0].parentNode; let newRows = []; for (let i = 0; i < equipmentRows.length; i++) { const row = equipmentRows[i]; const type = row.getAttribute('onclick').replace(/openCraftSwordDialogue\('([^']+)'\);/, '$1'); const levels = row.cells[2].textContent.split('/'); const barCosts = row.cells[3].getAttribute('tooltip').replace(/\D*$/, '').split('/'); for (let i = 0; i < barTypes.length; i++) { const bar = barTypes[i]; const newRow = row.cloneNode(true); newRow.id = 'craft-' + bar + type; newRow.setAttribute('onclick', ''); newRow.cells[0].textContent = bar[0].toUpperCase() + bar.substr(1) + ' ' + type; newRow.cells[1].firstElementChild.src = 'images/exploring/equipement/' + bar + type + '.png'; newRow.cells[2].textContent = levels[i]; newRow.cells[3].firstElementChild.src = 'images/minerals/' + bar + 'Bar.png'; newRow.cells[3].lastChild.textContent = ' ' + barCosts[i]; ((item) => { newRow.addEventListener('click', () => window.craftItem(item)); })(bar + type); newRows.push({ level: parseInt(levels[i], 10) , row: newRow }); } rowParent.removeChild(row); } newRows = newRows.sort((a, b) => a.level - b.level); // insert new rows into table const rows = rowParent.rows; let idx = 0; for (let i = 0; i < rows.length && idx < newRows.length; i++) { const row = rows[i]; if (row.getElementsByTagName('th').length > 0) { continue; } const thisLevel = parseInt(row.cells[2].textContent, 10); while (newRows[idx] && newRows[idx].level < thisLevel) { rowParent.insertBefore(newRows[idx].row, row); idx++; } } for (; idx < newRows.length; idx++) { rowParent.appendChild(newRows[idx].row); } } /** * apply new item style */ function applyNewItemStyle() { if (!getSetting('applyNewItemStyle')) { return; } // change how the items are styled const style = document.createElement('style'); style.innerHTML = ` span[class^="inventory-item-box"], #vendor-tab span.shop-box, #ach-tab span.shop-box-ach, div[id$="-store-tab"] span.shop-box, span.shop-box-ach { position: relative; } span[class^="inventory-item-box"] img.item-box-img, #vendor-tab img[id^="vendor-item-img"], #ach-tab span.shop-box-ach img:first-of-type, div[id$="-store-tab"] span.shop-box img:first-of-type, #grp-shop-tab span.shop-box-ach img:first-of-type { position: absolute; margin: 0 !important; } img.item-box-img[height="30px"] { top: 52.5px; } img.item-box-img[height="55px"] { top: 40px; } img.item-box-img[height="60px"] { top: 37.5px; } img.item-box-img[height="70px"] { top: 32.5px; } img.item-box-img[height="75px"] { top: 30px; } img.item-box-img[height="80px"] { top: 27.5px; } img.item-box-img[height="85px"] { top: 25px; } img.item-box-img[height="90px"] { top: 20px; } img.item-box-img[height="100px"] { top: 9px; } span[id^="item-binded"] > img.item-box-img[height="100px"] { top: 17.5px; } img.item-box-img[height="110px"] { top: 12.5px; } img.item-box-img[width="55px"] { left: 42.5px; } img.item-box-img[width="60px"] { left: 40px; } img.item-box-img[width="70px"] { left: 35px; } img.item-box-img[width="75px"] { left: 32.5px; } img.item-box-img[width="80px"] { left: 30px; } img.item-box-img[width="90px"] { left: 25px; } img.item-box-img[width="100px"] { left: 20px; } img.item-box-img[width="110px"] { left: 15px; } img.item-box-img[width="120px"] { left: 10px; } span[class^="inventory-item-box"] img.item-box-img[height="60px"][width="60px"] { transform: scale(1.2); } span[class^="inventory-item-box"] img.item-box-img[height="70px"][width="80px"] { transform: scale(1.2); } /* this is a special case (converting items into stardust) */ #wizard-tab img.item-box-img[height="50px"] { top: 22px; } #wizard-tab img.item-box-img[width="50px"] { left: 45px; } #vendor-tab img[id^="vendor-item-img"] { transform: scale(1.1); } /* height: 155px */ img[id^="vendor-item-img"][height="85x"] { top: 35px; } /* width: 150px (110px + 40px) */ img[id^="vendor-item-img"][width="80px"] { left: 35px; } span[class^="inventory-item-box"] span[id$="mount"], #ancientCrystalChargesSpan, #vendor-tab span.box-title, #ach-tab span[id^="cost-ach-"][id$="AchUpgrade"], div[id$="-store-tab"] span[id$="-cost"], #grp-shop-tab span[id$="-cost"] { background-color: black; border-top: 1px solid rgba(255, 255, 255, 0.5); color: white !important; font-weight: normal; margin: 0 !important; padding: 3px; text-align: center; position: absolute; bottom: 0; left: 0; right: 0; } span[class^="inventory-item-box"] span[id$="mount"]:not(#energy-amount), #vendor-tab span.box-title { padding-right: 9px; } span[class^="inventory-item-box"] span[id$="mount"]:not(#energy-amount)::before, #vendor-tab span.box-title::before { content: '${String.fromCharCode(215)}'; margin-right: 3px; } #fishfarmer-img { top: 18px; } #hasMapOfTheSea-fishermen { position: absolute; bottom: 3px; left: 3px; } span[class^="inventory-item-box"] span[id$="-price"], #vendor-tab span[id^="vendor-item-cost"] { font-weight: normal; padding-left: 20px; position: relative; top: 1px; } #vendor-tab span[id^="vendor-item-cost"] { font-size: inherit !important; } span[class^="inventory-item-box"] span[id$="-price"]:empty, #sandstone-price, #moonStone-price, #glass-price, #brewingKitBinded-price, #stripedLeaf-price, #greenMushroom-price, #whaleTooth-price, #snapeGrass-price, #strangeLeaf-price, #pureWaterPotion-price, #cactusWater-price, #ghostRemains-price, span[id$="Potion-price"] { visibility: hidden; } span[class^="inventory-item-box"] span[id$="-price"]::before, #vendor-tab span[id^="vendor-item-cost"]::before, div[id$="-store-tab"] span[id$="-cost"]::before, #grp-shop-tab span[id$="-cost"]::before { content: ''; display: inline-block; width: 20px; height: 20px; position: absolute; left: 0; background-image: url('images/pic_coin.png'); background-size: 20px 20px; } #shop-ghostPirates-cost::before { background-image: url('images/pic_coin2.png'); } #grp-shop-tab span[id$="-cost"]::before { background-image: url('images/icons/groupTaskTokens.png'); } #grp-shop-tab #grp-chests-badge-cost::before { background-image: url('images/icons/groupTaskBadge4.png'); } span[class^="inventory-item-box"] img[src="images/pic_coin.png"], #vendor-tab img[src="images/pic_coin.png"], #npc-store-tab img[src^="images/pic_coin"], #npc-store-tab img[src="images/icons/stats.png"], #npc-store-tab img[src="images/crafting/anyOrb.png"], #npc-store-tab img[src="images/spinning-gear-off.gif"], #donor-store-tab img ~ img[src="images/donor_coin.png"], #donor-store-tab span[id$="-cost"] img[src="images/donor_coin.png"], #grp-shop-tab img[src^="images/icons/groupTask"][id^="group-"], #grp-shop-tab #grp-shop-badge-price-img { display: none; } #ach-tab span[id^="cost-ach-"][id$="AchUpgrade"]::before { content: ''; display: inline-block; width: 20px; height: 20px; position: absolute; top: 2px; left: 4px; background-image: url('images/shop/ach.png'); background-size: 20px 20px; } #ach-tab span.box-title { font-size: 14pt; font-weight: normal; position: relative; top: 4px; } #ach-tab span.shop-box-ach img:first-of-type[height="60px"] { top: 47.5px; } #ach-tab span.shop-box-ach img:first-of-type[height="80px"] { top: 37.5px; } #ach-tab span.shop-box-ach img:first-of-type[width="55px"] { left: 47.5px; } #ach-tab span.shop-box-ach img:first-of-type[width="80px"] { left: 35px; } #ach-tab span.shop-box-ach img[src="images/shop/ach.png"] { display: none; } #ach-tab span.shop-box-ach img[src="images/division/check.png"], #grp-shop-tab img[src="images/division/check.png"] { position: absolute; bottom: 5px; left: calc(50% - 10px); } #npc-store-tab span.box-title, #donor-store-tab span.box-title, #grp-shop-tab span.box-title { font-size: 1.1rem; font-weight: bold; margin: 0; padding: 4px; position: absolute; left: 0; right: 0; } #donor-store-tab span.box-title { font-size: 1.02rem; } #shop-coop-level-cost, #shop-miningEngineer-machines-cost, #grp-shop-tab #grp-chests-badge-cost { bottom: 26px; } #shop-coop-level-cost::before { background-image: url('images/icons/stats.png'); left: 1px; } #shop-wizard-cost::before { background-image: url('images/crafting/anyOrb.png'); } #shop-miningEngineer-machines-cost::before { background-color: white; background-image: url('images/spinning-gear-off.gif'); } #npc-store-tab img:first-of-type[height="60px"] { top: 47.5px; } #npc-store-tab img:first-of-type[height="65px"] { top: 45px; } #npc-store-tab img:first-of-type[height="70px"] { top: 42.5px; } #npc-store-tab img:first-of-type[height="80px"] { top: 37.5px; } #npc-store-tab img:first-of-type[height="85x"] { top: 35px; } #npc-store-tab img:first-of-type[height="100x"] { top: 27.5px; } #npc-store-tab img:first-of-type[width="60px"] { left: 45px; } #npc-store-tab img:first-of-type[width="65px"] { left: 42.5px; } #npc-store-tab img:first-of-type[width="80px"] { left: 35px; } #npc-store-tab img:first-of-type[width="100px"] { left: 25px; } #donor-store-tab img:first-of-type[height="80px"] { top: 37.5px; } #donor-store-tab img:first-of-type[width="80px"] { left: 35px; } #donor-store-tab span[id$="-cost"]::before { background-image: url('images/donor_coin.png'); } #grp-shop-tab img[id^="grp-shop-"][height="80px"] { top: 37.5px; } #grp-shop-tab img[id^="grp-shop-"][width="80px"] { left: 35px; } #grp-shop-tab img[id^="grp-shop-"][width="90px"] { left: 30px; } #grp-shop-tab img[src="images/division/check.png"] + span { display: none; } `; document.head.appendChild(style); // remove line breaks const brs = document.querySelectorAll( '[class^="inventory-item-box"] br' + ', span.shop-box br' + ', #ach-tab span.shop-box-ach br' + ', #grp-shop-tab span.shop-box-ach br' ); let i = 0; while (brs[i] != null) { brs[i++].parentNode && brs[--i].parentNode.removeChild(brs[i]); } // give the emerald image the correct class name const emeraldAmount = document.getElementById('emeraldAmount'); const previous = emeraldAmount && emeraldAmount.previousElementSibling; previous && previous.classList.add('item-box-img'); // wrap some requirements in npc-shop const shopBoxes = document.querySelectorAll('div[id$="-store-tab"] span.shop-box'); for (let i = 0; i < shopBoxes.length; i++) { const box = shopBoxes[i]; const children = box.childNodes; let foundImg = false; let wrapper; const idList = { 'shop-coopUnlocked-box': ['shop-coop-cost', 'shop-coop-level-cost'] , 'shop-hasVendor-box': ['shop-vendor-cost'] , 'shop-wizard-box': ['shop-wizard-cost'] , 'shop-achShop-box': ['shop-achShop-cost'] , 'shop-miningEngineer-box': ['shop-miningEngineer-cost', 'shop-miningEngineer-machines-cost'] , 'donor-shop-hasExtraOfflineTimer-box': ['shop-extraOfflineTimer-cost'] , '': ['shop-offlineTimer-cost'] }[box.id] || []; for (let j = 0; j < children.length; j++) { const child = children[j]; if (!foundImg && child.tagName == 'IMG') { foundImg = true; } else if (foundImg && child.nodeType == Node.TEXT_NODE) { wrapper = document.createElement('span'); wrapper.id = idList.shift() || ''; box.insertBefore(wrapper, child); wrapper.appendChild(child); } else if (foundImg && wrapper != null) { wrapper.appendChild(child); j--; } } } // wrap some requirements in group shop const grpBoxes = document.querySelectorAll('#grp-shop-tab span.shop-box-ach'); const idList = ['grp-badge-cost', 'grp-more-points-cost', 'grp-eels-cost', 'grp-promethium-cost', 'grp-chests-cost', 'grp-chests-badge-cost', 'grp-gloves-cost']; for (let i = 0; i < grpBoxes.length; i++) { const box = grpBoxes[i]; const children = box.childNodes; let foundImg = false; let wrapper; for (let j = 0; j < children.length; j++) { const child = children[j]; if (!foundImg && child.tagName == 'IMG') { foundImg = true; } else if (foundImg && wrapper == null) { wrapper = document.createElement('span'); wrapper.id = idList.shift(); box.insertBefore(wrapper, child); wrapper.appendChild(child); } else if (foundImg && wrapper != null) { if (child.nodeName == 'IMG') { box.insertBefore(child, wrapper); wrapper = null; } else { wrapper.appendChild(child); j--; } } } } } /** * apply new key item style */ function applyNewKeyItemStyle() { if (!getSetting('applyNewKeyItemStyle')) { return; } // change how key items and machinery is styled const style = document.createElement('style'); style.innerHTML = ` span[class$="-inventory-item-box"] { position: relative; } span.item-box-title { color: blue; font-weight: bold; padding: 4px 8px; position: absolute; top: 0; left: 0; right: 0; z-index: 10; } span.item-box-title > img[src="images/oil.png"] { display: block; margin: 0 auto; } span.item-box-title > img[src^="images/spinning-gear"] { margin-right: 3px; margin-left: -10px; } span[class$="-inventory-item-box"] > img { position: absolute; } /* heights */ span[class$="-inventory-item-box"] > img[height="80px"] { top: 60px; } span[class$="-inventory-item-box"] > img[height="90px"] { top: 55px; } span[class$="-inventory-item-box"] > img[height="100px"] { top: 50px; } span[class$="-inventory-item-box"] > img[height="110px"] { top: 45px; } span[class$="-inventory-item-box"] > img[height="120px"] { top: 40px; } span[class$="-inventory-item-box"] > img[height="130px"] { top: 35px; } span[class$="-inventory-item-box"] > img[height="140px"] { top: 30px; } /* widths */ span[class$="-inventory-item-box"] > img[width="70px"] { left: 35px; } span[class$="-inventory-item-box"] > img[width="80px"] { left: 30px; } span[class$="-inventory-item-box"] > img[width="90px"] { left: 25px; } span[class$="-inventory-item-box"] > img[width="100px"] { left: 20px; } span[class$="-inventory-item-box"] > img[width="110px"] { left: 15px; } span[class$="-inventory-item-box"] > img[width="120px"] { left: 10px; } #key-item-bindedGlassBlowingPipe-box img { top: 75px; } span.ghostPipe-wrapper { display: flex; flex-wrap: wrap; position: absolute; top: 66px; left: 19px; width: 102px; } span.ghostPipe-wrapper > img { box-shadow: 0 0 2px black; margin: 2px; } span.text-wrapper { background-color: black; border-top: 1px solid rgba(255, 255, 255, 0.5); color: white; font-weight: normal; line-height: 22px; position: absolute; bottom: 0; left: 0; right: 0; } span.text-wrapper span[id$="Amount"], #level-global-4 { font-weight: bold; } #key-item-handheldOilPump-box span.text-wrapper { display: none; } span.text-wrapper img { margin-right: 3px; } span.text-wrapper .small-perc-bar { background-color: black; border: 0; margin: 0; padding: 0; position: absolute; top: -11px; left: 0; right: 0; width: auto; } span.text-wrapper .small-perc-bar-inner { background-color: rgba(0, 210, 0, 1) !important; } `; document.head.appendChild(style); const brs = document.querySelectorAll('span[class$="-inventory-item-box"] br'); let i = 0; while (brs[i] != null) { const br = brs[i]; const parent = br.parentNode; if (!parent) { i++; continue; } if (parent.classList.contains('item-box-title')) { parent.insertBefore(document.createTextNode(' '), br); } parent.removeChild(br); } const spans = document.querySelectorAll('span[class$="-inventory-item-box"]'); let ghostWrapper; for (let i = 0; i < spans.length; i++) { const span = spans[i]; const childs = span.childNodes; let wrapper; let foundImg = false; for (let j = 0; j < childs.length; j++) { const child = childs[j]; if (!foundImg && child.tagName == 'IMG') { if (/ghostPipeHolder/.test(child.id)) { if (!ghostWrapper) { ghostWrapper = document.createElement('span'); ghostWrapper.className = 'ghostPipe-wrapper'; child.parentNode.insertBefore(ghostWrapper, child); j++; } ghostWrapper.appendChild(child); j--; if (child.id == 'ghostPipeHolder6') { foundImg = true; } } else { foundImg = true; } } else if (foundImg) { if (!wrapper) { wrapper = document.createElement('span'); wrapper.className = 'text-wrapper'; span.insertBefore(wrapper, child); j++; } wrapper.appendChild(child); j--; } } if (wrapper && wrapper.textContent == '') { wrapper.parentNode.removeChild(wrapper); } } } /** * hide recipes of maxed machinery */ function hideMaxRecipes() { if (!getSetting('hideMaxRecipes')) { return; } function hideMachineRecipe(key, max, init) { const bindedKey = 'binded' + key[0].toUpperCase() + key.substr(1); const row = document.getElementById('craft-' + key); if (row) { const amount = parseInt(window[key], 10) + parseInt(window[bindedKey], 10); const hide = amount >= max(); row.style.display = hide ? 'none' : ''; if (init) { observe(key, () => hideMachineRecipe(key, max, false)); observe(bindedKey, () => hideMachineRecipe(key, max, false)); } } } const machinery = ['drill', 'crusher', 'giantDrill', 'sandCollector', 'roadHeader', 'bucketWheelExcavator', 'giantBWE']; for (let key of machinery) { hideMachineRecipe(key, () => 10, true); } // handle pump jacks with its upgrades function calcPumpjackMax() { let maxPumpjacks = 10; if (window.bindedUpgradePumpJackOrb == 1) { maxPumpjacks += 5; } if (window.bindedGreenPumpjackOrb == 1) { maxPumpjacks += 10; } return maxPumpjacks; } hideMachineRecipe('pumpJack', calcPumpjackMax, true); observe('bindedUpgradePumpJackOrb', () => hideMachineRecipe('pumpJack', calcPumpjackMax, false)); observe('bindedGreenPumpjackOrb', () => hideMachineRecipe('pumpJack', calcPumpjackMax, false)); } /** * fix magic */ const essenceMultiplier = { mineral: { stone: 20e6 , copper: 10e6 , tin: 10e6 , iron: 5e6 , silver: 2e6 , gold: 1e6 , quartz: 100e3 , flint: 50e3 , marble: 10e3 , titanium: 5e3 , promethium: 100 , runite: 2 } , oil: { oil: 5e7 , rocketFuel: 1 } , nature: { dottedGreenRoots: 18 , greenRoots: 13 , limeRoots: 6 , goldRoots: 3 , stripedGoldRoots: 1 , crystalRoots: v => parseInt(v / 2) + 1 , stripedCrystalRoots: v => parseInt(v / 4) + 1 } , metallic: { bronzeBar: 1000 , ironBar: 700 , silverBar: 500 , goldBar: 300 , promethiumBar: 25 , runiteBar: 1 } , energy: { shrimp: 50 , sardine: 20 , tuna: 4 , swordfish: 1 , shark: v => parseInt(v / 3) + 1 , whale: v => parseInt(v / 6) + 1 } , orb: { blue: 3 , green: 1 , red: v => parseInt(v / 3) + 1 } , gem: { sapphire: 8 , emerald: 3 , ruby: 1 , diamond: v => parseInt(v / 5) + 1 } }; const essenceObserver = new Map(); function essenceCellStyle(cell, fulfilled) { cell.style.backgroundColor = fulfilled ? '' : 'red'; cell.style.color = fulfilled ? '' : 'white'; } function essenceSetFulfilled(key, value, el) { const fulfilled = window[key] >= value; essenceCellStyle(el.previousElementSibling, fulfilled); essenceCellStyle(el, fulfilled); essenceCellStyle(el.nextElementSibling, fulfilled); } function essenceRequirements(amount, type) { if (essenceObserver.has(type)) { essenceObserver.get(type).forEach((fn, key) => { unobserve(key, fn); }); } const observerMap = new Map(); const makeString = 'make' + type[0].toUpperCase() + type.substr(1) + 'Essence'; for (let key in essenceMultiplier[type]) { const elId = makeString + key[0].toUpperCase() + key.substr(1) + '-needed'; const el = document.getElementById(elId); const mult = essenceMultiplier[type][key]; const value = amount == 0 ? 0 : (typeof mult === 'function' ? mult(amount) : amount * mult); el.textContent = formatNumber(value); const windowKey = type == 'orb' ? 'empty' + key[0].toUpperCase() + key.substr(1) + 'Orb' : key; essenceSetFulfilled(windowKey, value, el); const observeFn = observe(windowKey, () => essenceSetFulfilled(windowKey, value, el)); observerMap.set(windowKey, observeFn); } essenceObserver.set(type, observerMap); } function fixMagic() { // move roots to magic panel const parent = document.getElementById('magic-tab'); const roots = document.querySelectorAll('[id$="Roots-box"]'); for (let i = 0; i < roots.length; i++) { const el = roots[i].parentNode; el.setAttribute('tooltip', el.getAttribute('tooltip').replace(/ \(Used in the magic skill\)$/, '')); parent.appendChild(el); } const style = document.createElement('style'); style.innerHTML = ` #magic-tab .inventory-item-box-farming { float: left; } `; document.head.appendChild(style); // improve tooltip of spell book const magicBook = document.getElementById('item-magicBook-box').parentNode; function updateTooltip() { const pages = []; for (let i = 1; i <= 6; i++) { if (window['bindedMagicPage' + i] == '1') { pages.push(i); } } const pagesString = pages.length === 0 ? '-' : pages.join(', '); magicBook.setAttribute('tooltip', `Spell Book (binded pages: ${pagesString})`); } updateTooltip(); observe([ 'bindedMagicPage1' , 'bindedMagicPage2' , 'bindedMagicPage3' , 'bindedMagicPage4' , 'bindedMagicPage5' , 'bindedMagicPage6' ], () => updateTooltip()); const oldEmptyEssenceDialogue2 = window.emptyEssenceDialogue2; window.emptyEssenceDialogue2 = (type) => { oldEmptyEssenceDialogue2(type); if (type == 'nature') { const input = document.querySelector( '#emptyEssence2-dialog-nature table.table-stats tr:last-child > td:last-child input' ); if (input && input.style.display != 'none') { input.style.display = 'none'; const inputCell = input.parentNode; inputCell.style.border = 0; const neededCell = inputCell.previousElementSibling; neededCell.style.border = 0; const imgCell = neededCell.previousElementSibling; imgCell.style.border = 0; } } }; window.refreshOresValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'mineral'); }; window.refreshOilValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'oil'); }; window.refreshSeedsValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'nature'); }; window.refreshBarValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'metallic'); }; window.refreshFoodValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'energy'); }; window.refreshOrbValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'orb'); }; window.refreshGemValuesWhenMakingEssences = (amount) => { essenceRequirements(amount, 'gem'); }; } /** * fix number format */ function formatNumber(num) { // return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); return parseFloat(num).toLocaleString('en'); } function fixNumberFormat() { // fix achievements const achievementFixes = { 'achABiggerWall': 'Sell excactly ' + formatNumber(1e7) + ' stone to the shop.' , 'ach1000Potions': 'Drink a total of ' + formatNumber(1e3) + ' potions. ' , 'achMaxInt': 'Have a total of ' + formatNumber(Math.pow(2, 31)-1) + ' ores in your inventory. ' , 'achSmelter': 'Smelt a total of ' + formatNumber(5e5) + ' bars. ' }; for (let id in achievementFixes) { const row = document.getElementById(id); row.cells[1].firstChild.textContent = achievementFixes[id]; } const oldLoadAchievements = window.loadAchievements; window.loadAchievements = () => { oldLoadAchievements(); document.getElementById('total-potions-drank').innerHTML = formatNumber(window.totalPotionsDrank) + ' potions drank'; document.getElementById('total-bars-smelted').innerHTML = formatNumber(window.totalBarsSmelted) + ' bars smelted'; document.getElementById('statVendor2').innerHTML = formatNumber(window.statVendor); document.getElementById('total-spellsCasted-ach').innerHTML = formatNumber(window.spellsCasted); }; function checkAchievementRow(row) { if (window[row.id] != 1) { return false; } const pinkSpan = row.cells[1].children[0]; if (pinkSpan) { pinkSpan.style.color = 'blue'; } return true; } const table = document.querySelector('#ach-tab table.table-stats'); const rows = table.rows; for (let i = 0; i < rows.length; i++) { const row = rows[i]; if (row.id && !checkAchievementRow(row)) { observe(row.id, () => checkAchievementRow(row)); } } // fix explorers energy const oldExplorerTick = window.explorerTick; window.explorerTick = () => { oldExplorerTick(); const energyElement = document.getElementById('energy-amount'); energyElement.innerHTML = 'Energy: ' + formatNumber(window.energy); }; // fix leveling up in crafting window.setConvertBarToXpOnKeyDown = (amount) => { var starDustCounter = window.bindedUpgradeEnchantedHammer >= 1 ? 10 : 13; document.getElementById('enchantedHammer-XP-hint-box').style.display = 'block'; document.getElementById('enchantedHammer-XP-earned').innerHTML = '+' + formatNumber(getXPEarnedWhenConvertingBar(barToConvertToXpType) * amount.value); document.getElementById('enchantedHammer-XP-total-stardust-cost').innerHTML = '-' + formatNumber(getXPEarnedWhenConvertingBar(barToConvertToXpType) * amount.value * starDustCounter); }; // fix blue coins const oldLoadCoins = window.loadCoins; window.loadCoins = () => { oldLoadCoins(); document.getElementById('platinumCoinsAmount-statusbar').innerHTML = formatNumber(window.platinumCoins); }; // fix xp in "select a seed" dialog const seedButtons = document.querySelectorAll('#seed-menu-popup > div[id^="btn-"]'); for (let i = 0; i < seedButtons.length; i++) { const cells = seedButtons[i].children[0].rows[0].cells; const xpNode = cells[cells.length-1].lastChild; const text = xpNode.textContent.replace(/(\d)\D+(?=\d)/g, '$1'); const xp = parseInt(text, 10); xpNode.textContent = text.replace(xp.toString(10), formatNumber(xp)); } // fix oil const oldLoadMiscVariables = window.loadMiscVariables; window.loadMiscVariables = () => { oldLoadMiscVariables(); document.getElementById('span-oilPerSecond').innerHTML = formatNumber(window.oilPerSeconds); document.getElementById('span-oilLosePerSecond').innerHTML = '-' + formatNumber(oilLosePerSeconds); }; // fix artifact star dust calculation const artifactInput = document.getElementById('amount-to-convert-artifact'); artifactInput.onkeyup = function () { const xpRate = document.getElementById('artifact-xp-rate').value; const sdRate = window.bindedExploringOrb == 1 ? 22 : 26; document.getElementById('artifact-xp-earned').innerHTML = formatNumber(xpRate * this.value); document.getElementById('artifact-stardust-needed').innerHTML = formatNumber(xpRate * this.value * 22); }; const oldOpenArtifactDialogue = window.openArtifactDialogue; window.openArtifactDialogue = (artifact, xp) => { oldOpenArtifactDialogue(artifact, xp); artifactInput.onkeyup(null); }; } /** * initialize notifications */ function observeTimer(k, onComplete, zero = 0) { observe(k, (key, oldValue, newValue) => { if (oldValue > zero && newValue == zero) { onComplete(key); } }); } function notifyCoop(msg) { window.send('OPEN_TAB=COOP'); return notify('Group Task', { body: msg.replace(/!$/, '.') , icon: 'images/icons/coop.png' }).then((n) => { n.onclick = () => { window.focus(); window.openTab('coop'); n.close(); }; return n; }); } function notifyVendor() { /* "I have changed my items, come check them out."<br><br><img src="images/shop/vendor.png" width="120px" height="140px"> */ return notify('Vendor', { body: 'The vendor changed his items.' , icon: 'images/shop/vendor.png' }) .then((n) => { n.onclick = () => { window.focus(); window.openTab('vendor'); n.close(); }; return n; }) ; } function notifyBoat(msg) { /* <b>Your boat brings back:</b><br><br><span class="exploring-norm-loot"><img class="small-img" src="images/exploring/rawSardine.png"> 2</span> <span class="exploring-norm-loot"><img class="small-img" src="images/exploring/rawTuna.png"> 1</span> */ const tmp = document.createElement('templateWrapper'); tmp.innerHTML = msg; const loot = []; const lootEls = tmp.querySelectorAll('.exploring-norm-loot'); for (let i = 0; i < lootEls.length; i++) { const el = lootEls[i]; const num = parseInt(el.textContent, 10); const match = el.innerHTML.match(/\/([^\/]+)\.png"/); if (match) { const itemName = match[1].replace(/([a-z])([A-Z])/, (wholeMatch, m1, m2) => { return m1 + ' ' + m2.toLowerCase(); }); loot.push(num + ' ' + itemName); } else { loot.push(el.innerHTML); } } return notify('Fishing boat returns', { body: 'Your boat brings back: ' + loot.join(', ') , icon: 'images/exploring/fishingBoat.png' }) .then((n) => { n.onclick = () => { window.focus(); window.openTab('archaeology'); n.close(); }; return n; }) ; } function notifyAchievement() { /* You have completed an achievement */ return notify('Achievement got', { body: 'You have completed an achievement.' , icon: 'images/shop/ach.png' }) .then((n) => { n.onclick = () => { window.focus(); window.openTab('ach'); n.close(); }; return n; }) ; } function notifyMsg(msg) { if (msg === 'You have completed your group task!' || / has completed his group task\.$/.test(msg)) { return notifyCoop(msg); } else if (/I have changed my items, come check them out/.test(msg)) { return notifyVendor(); } else if (/Your boat brings back:/.test(msg)) { notifyBoat(msg); } else if (msg === 'You have completed an achievement') { notifyAchievement(); } else if (document.hidden || !document.hasFocus()) { /* Your account has been running for 234 Minutes */ notify('Message from server', { body: msg // , icon: 'images/minerals/diamond.png' }).then((n) => { n.onclick = () => { window.focus(); n.close(); }; }); } return Promise.reject(); } function initNotifications() { if (!getSetting('showNotifications')) { return; } notify = (title, options) => { if (!("Notification" in window) || Notification.permission === 'denied') { console.info('notification:', title, options); return Promise.reject('Notification permission denied'); } if (Notification.permission === 'granted') { return Promise.resolve(new Notification(title, options)); } return Notification.requestPermission().then(() => notify(title, options)); }; Notification.requestPermission().then(function (result) { if (result == 'denied') { console.error('Permission to show notifications has been denied by the user.'); } }); // don't send TAB_OFF window.checkIfTabIsOpen = () => { if (window.tabOn == 0) { window.send('TAB_ON'); window.tabOn = 1; } }; function addClickListener(n, tabName) { n.onclick = () => { window.focus(); window.openTab(tabName); n.close(); }; return n; } let lastFarmingNotification; observeTimer(['farmingPatchTimer1', 'farmingPatchTimer2', 'farmingPatchTimer3', 'farmingPatchTimer4', 'farmingPatchTimer5', 'farmingPatchTimer6'], (key) => { const now = (new Date).getTime(); const timeDiff = now - (lastFarmingNotification || 0); if (timeDiff < 10e3) { return; } lastFarmingNotification = now; notify('Harvest', { body: 'One or more of your crops is ready for harvest.' , icon: 'images/icons/watering-can.png' }).then((n) => addClickListener(n, 'farming')); }, 1); observeTimer('exploringTimer', (key) => { notify('Explorer ready', { body: 'Your explorer is back.' , icon: 'images/icons/archaeology.png' }).then((n) => addClickListener(n, 'archaeology')); }); observeTimer('furnaceCurrentTimer', (key) => { notify('Furnace ready', { body: 'Your smelting has finished.' , icon: 'images/crafting/' + furnaceLevels[window.bindedFurnaceLevel] + 'Furnace.gif' }).then((n) => addClickListener(n, 'repair')); }); observeTimer('rocketTimer', (key) => { notify('Rocket ready', { body: 'You landed on the moon.' , icon: 'images/crafting/rocket.png' }).then((n) => addClickListener(n, 'repair')); }); observeTimer('robotTimer', (key) => { notify('Robot ready', { body: 'Your robot is back.' , icon: 'images/crafting/robot.png' }).then((n) => addClickListener(n, 'repair')); }); observeTimer('fishingBoatTimer', (key) => { notify('Fishing boat ready', { body: 'Your fishing boat is back.' , icon: 'images/exploring/fishingBoat.png' }).then((n) => addClickListener(n, 'archaeology')); }); observeTimer('largeFishingBoatTimer', (key) => (key) => { notify('Large fishing boat ready', { body: 'Your large fishing boat is back.' , icon: 'images/exploring/largeFishingBoat.png' }).then((n) => addClickListener(n, 'archaeology')); }); /* // potions 'starDustPotionTimer' 'coinPotionTimer' 'seedPotionTimer' 'smeltingPotionTimer' 'oilPotionTimer' 'miningPotionTimer' 'superStarDustPotionTimer' 'fastFurnacePotionTimer' 'superCompostPotionTimer' 'megaStarDustPotionTimer' 'superOilPotionTimer' 'whaleFishingPotionTimer' 'fishingPotionTimer' 'essencePotionTimer' 'megaOilPotionTimer' 'superEssencePotionTimer' 'sparklingCompostPotionTimer' 'engineeringPotionTimer' // magic effects 'superDrillsTimer' 'superGemFinderTimer' 'smallSipsTimer' 'superPirateTimer' 'superCrushersTimer' 'superGiantDrillsTimer' 'fastVendorTimer' 'superRoadHeadersTimer' 'animatedAxeTimer' 'superExcavatorsTimer' // ? 'compostTimer' 'eatingTimer' 'exploringTimeReductionPerc' 'ghostEssenceTimer' */ } /** * fix level bar */ function fixLevelBar() { // size changing: 1267x65 -> 1256x105 document.getElementById('level-status-up').style.lineHeight = '102px'; const style = document.createElement('style'); style.innerHTML = ` tr[id^="level-status-row"] > td > img:first-child[width="40px"] { margin: 0 5px; } #level-status-row2 > td > img:first-child { height: 50px; } .unlock-skill-btn { margin-left: 5px; } span[id^="progress-percentage-"][id$="-small"] { height: calc(90% + 2px); margin: 0; } #fishingBoat-timer > img:first-child { width: 53px; height: 40px; } `; document.head.appendChild(style); } /** * fix message box */ function fixMsgBox() { const oldDialogFn = window.$.fn.dialog; window.$.fn.dialog = function (...args) { if (args[0] != 'close') { $('.ui-widget-header').show(); } return oldDialogFn.apply(this, args); }; const oldMessageBox = window.messageBox; let timeout; window.messageBox = (msg) => { const $el = $('#dialog-timer'); if ($el.hasClass('ui-dialog-content')) { $el.dialog('destroy'); } document.getElementById('dialog-text-timer').innerHTML = msg; $el.dialog( { create: function (event, ui) { $('.ui-widget-header').hide(); } , width: 550 , height: 100 , show: { effect: 'fade' , duration: 50 } , hide: { effect: 'fade' , delay: 1000 , duration: 1000 } }).dialog('close'); }; } /** * add a notification box (like the harvest one) for coop events */ function addCoopNotificationBox() { const notifBox = document.createElement('span'); notifBox.id = 'coop-notif'; notifBox.classList.add('notification-timer-box'); notifBox.style.width = 'auto'; notifBox.style.cursor = 'pointer'; notifBox.style.display = 'none'; notifBox.style.padding = '0 10px'; notifBox.onclick = () => { window.openTab('coop'); window.send('OPEN_TAB=COOP'); }; notifBox.innerHTML = `<span class="activate-tooltip" title="Group task is finished"> <img width="46px" height="40px" style="vertical-align: middle; padding: 5px 0px 5px 0px;" src="images/icons/coop.png"> <span class="progress"></span> </span>`; document.getElementById('farming-notif').parentNode.appendChild(notifBox); const coopProgress = notifBox.querySelector('span.progress'); const oldLoadCoop = window.loadCoop; window.loadCoop = (data) => { const dataArray = data == 'none' ? [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] : data.split('~'); const player = [ dataArray[0] , dataArray[1] , dataArray[2] , dataArray[3] ]; const task_id = [ dataArray[4] , dataArray[5] , dataArray[6] , dataArray[7] ]; const task_value = [ dataArray[8] , dataArray[9] , dataArray[10] , dataArray[11] ]; const task_neededValue = [ dataArray[12] , dataArray[13] , dataArray[14] , dataArray[15] ]; function isPlayer(i) { return player[i] !== 'none' && player[i] !== 'claimed'; } const started = task_id.every((id, i) => !isPlayer(i) || id != 0); const totalNum = player.filter((name, i) => isPlayer(i)).length; const finishedNum = task_value.filter((value, i) => isPlayer(i) && value == task_neededValue[i]).length; const showBox = started && finishedNum > 0; notifBox.style.display = showBox ? '' : 'none'; coopProgress.textContent = finishedNum == totalNum ? '' : finishedNum + '/' + totalNum; const i = player.indexOf(window.username); const thisFinished = started && task_value[i] == task_neededValue[i]; coopProgress.style.color = thisFinished ? 'lime' : ''; for (let j = 1; j <= 4; j++) { const row = document.getElementById('started-row-p' + j); if (row) { row.style.backgroundColor = j == (i+1) ? 'lightblue' : ''; } } return oldLoadCoop(data); }; window.send('OPEN_TAB=COOP'); } /** * fix chat */ const chatHistoryKey = 'chatHistory'; const maxChatHistoryLength = 100; const reloadedChatData = { timestamp: 0 , username: '' , userlevel: 0 , sigil: 0 , tag: 0 , type: -1 , msg: '[...]' }; let chatHistory = []; function add2ChatHistory(data) { const splitArray = data.split('~'); data = { timestamp: (new Date()).getTime() , username: splitArray[0] , userlevel: parseInt(splitArray[1], 10) , sigil: parseInt(splitArray[3], 10) , tag: parseInt(splitArray[2], 10) , type: parseInt(splitArray[5], 10) , msg: splitArray[4] }; if (data.type == 2) { data.userlevel = window.getGlobalLevel(); } chatHistory.push(data); chatHistory = chatHistory.slice(-maxChatHistoryLength); localStorage.setItem(chatHistoryKey, JSON.stringify(chatHistory)); return data; } function getChatTab(username) { const chatTabs = document.getElementById('chat-tabs'); let tab = chatTabs.querySelector('div.chat-tab[data-username="' + username + '"]'); if (!tab) { tab = document.createElement('div'); tab.className = 'chat-tab'; tab.dataset.username = username; tab.dataset.new = 0; const filler = chatTabs.querySelector('.filler'); if (filler) { chatTabs.insertBefore(tab, filler); } else { chatTabs.appendChild(tab); } } return tab; } function getChatDiv(username) { const id = 'chat-' + (username == '' ? 'area-div' : 'pm-' + username); let div = document.getElementById(id); if (!div) { div = document.createElement('div'); div.setAttribute('disabled', 'disabled'); div.id = 'chat-pm-' + username; div.className = 'chat-area-div'; const height = document.getElementById('chat-area-div').style.height; div.style.height = height; const generalChat = document.getElementById('chat-area-div'); generalChat.parentNode.insertBefore(div, generalChat); } return div; } function changeChatTab(oldTab, newTab) { const oldChatDiv = getChatDiv(oldTab.dataset.username); oldChatDiv.classList.remove('selected'); const newChatDiv = getChatDiv(newTab.dataset.username); newChatDiv.classList.add('selected'); const toUsername = newTab.dataset.username; const newTextPlaceholder = toUsername == '' ? window.username + ':' : 'PM to ' + toUsername + ':'; document.getElementById('textbox-chat').placeholder = newTextPlaceholder; if (window.isAutoScrolling) { setTimeout(() => newChatDiv.scrollTop = newChatDiv.scrollHeight); } } const chatSigils = [ null , { key: 'maxLevel', title: 'Maxed Skills' } , { key: 'maxMining', title: 'Master in Mining' } , { key: 'maxCrafting', title: 'Master in Crafting' } , { key: 'maxBrewing', title: 'Master in Brewing' } , { key: 'maxFarming', title: 'Master in Farming' } , { key: 'hardcore', title: 'Hardcore Account' } , { key: 'halloween2015', title: 'Halloween 2015' } , { key: 'maxExploring', title: 'Master in Exploring' } , { key: 'christmas2015', title: 'Chirstmas 2015' } , { key: 'maxMagic', title: 'Master in Magic' } , { key: 'easter2016', title: 'Holiday' } , { key: 'coop', title: 'COOP' } , { key: 'maxCooking', title: 'Master in Cooking' } , { key: 'halloween2016', title: 'Halloween 2016' } , { key: 'christmas2016', title: 'Chirstmas 2016' } ]; const chatTags = [ null , { key: 'donor', name: '' } , { key: 'contributor', name: 'Contributor' } , null , { key: 'mod', name: 'Moderator' } , { key: 'dev', name: 'Dev' } ]; const linkParseRegex = /(^|\s)(https?:\/\/\S+|\S*www\.|\S+\.(?:com|ca|co|net|us))(\s|$)/; function isPM(data) { return data.type == 1 || data.type == 2; } const locale = 'en-US'; const localeOptions = { hour12: false , year: 'numeric' , month: 'long' , day: 'numeric' , hour: '2-digit' , minute: '2-digit' , second: '2-digit' }; function newRefreshChat(data) { // username is 3-12 characters long let chatbox = document.getElementById('chat-area-div'); if (mutedPeople.some((name) => name == data.username)) { return; } const isThisPm = isPM(data); const msgUsername = data.type == 2 ? window.username : data.username; const historyIndex = chatHistory.indexOf(data); const dataBefore = historyIndex != -1 && chatHistory.slice(0, historyIndex).reverse().find((d) => { return isThisPm && isPM(d) || !isThisPm && !isPM(d); }) ; let isSameUser = false; let isSameTime = false; if (dataBefore) { const beforeUsername = dataBefore.type == 2 ? window.username : dataBefore.username; isSameUser = beforeUsername === msgUsername; isSameTime = Math.floor(data.timestamp / 1000 / 60) - Math.floor(dataBefore.timestamp / 1000 / 60) === 0; } const d = new Date(data.timestamp); const hour = (d.getHours() < 10 ? '0' : '') + d.getHours(); const minute = (d.getMinutes() < 10 ? '0' : '') + d.getMinutes(); const sigil = chatSigils[data.sigil] || { key: '', title: '' }; const tag = chatTags[data.tag] || { key: '', name: '' }; const formattedMsg = data.msg.replace(new RegExp(linkParseRegex, 'g'), (wholeMatch, before, link, after) => { if (/%22|%27|%3E|%3C|>|<|;|~|\\"|<|>|javascript:|window|document|cookie/.test(link)) { return wholeMatch; } link = (link.startsWith('http') ? '' : 'http://') + link; return before + `<a href="${link}" target="_blank">${link}</a>` + after; }); const msgTitle = data.type == -1 ? 'Chat loaded on ' + d.toLocaleString(locale, localeOptions) : ''; let chatSegment = `<span class="chat-msg" data-type="${data.type}" data-tag="${tag.key}">` + `<span class="timestamp" data-hour="${hour}" data-minute="${minute}" title="${d.toLocaleString(locale, localeOptions)}" data-same-time="${isSameTime}"></span>` + `<span class="user" data-name="${data.username}" data-same-user="${isSameUser}">` + `<span class="sigil ${sigil.key}" title="${sigil.title}"></span>` + `<span class="tag chat-tag-${tag.key}">${tag.name}</span>` + `<span class="name" data-level="${data.userlevel}" oncontextmenu="searchPlayerHicores('${msgUsername}');return false;" onclick="preparePM('${msgUsername}')">${msgUsername}</span>` + `</span>` + `<span class="msg" title="${msgTitle}">${formattedMsg}</span>` + `</span>`; const chatTab = getChatTab(isThisPm ? data.username : ''); if (!chatTab.classList.contains('selected')) { chatTab.dataset.new = parseInt(chatTab.dataset.new, 10) + 1; } if (isThisPm) { window.lastPMFrom = data.username; chatbox = getChatDiv(data.username); } const tmp = document.createElement('templateWrapper'); tmp.innerHTML = chatSegment; while (tmp.childNodes.length > 0) { chatbox.appendChild(tmp.childNodes[0]); } if (window.isAutoScrolling) { setTimeout(() => chatbox.scrollTop = chatbox.scrollHeight); } } function applyChatStyle() { const style = document.createElement('style'); style.innerHTML = ` span.chat-msg { display: flex; margin-bottom: 1px; } .chat-msg .timestamp::before { color: hsla(0, 0%, 50%, 1); font-size: .9rem; } .chat-msg .timestamp[data-same-time="true"]::before { } #chat-toggleTimestamps:checked ~ div[id^="chat-"] .chat-msg:not([data-type="-1"]) .timestamp::before { content: attr(data-hour) ':' attr(data-minute); display: inline-block; margin: 0 5px; width: 2.5rem; } .chat-msg[data-type="1"] { color: purple; } .chat-msg[data-type="2"] { color: purple; } .chat-msg[data-type="3"] { color: blue; } .chat-msg[data-tag="contributor"] { color: green; } .chat-msg[data-tag="mod"] { color: #669999; } .chat-msg[data-tag="dev"] { color: #666600; } .chat-msg .user { margin-right: 5px; white-space: nowrap; } .chat-msg .user[data-same-user="true"]:not([data-name="none"]) { opacity: .3; } .chat-msg .user .name:not([data-level=""])::after { content: ' (' attr(data-level) '):'; } .chat-msg .user .sigil:not([class$=" "])::before { background-size: 20px 20px; content: ''; display: inline-block; margin-right: 1px; width: 20px; height: 20px; vertical-align: middle; } .chat-msg .user .sigil.maxLevel::before { background-image: url('images/icons/stats.png'); } .chat-msg .user .sigil.maxCrafting::before { background-image: url('images/icons/anvil.png'); } .chat-msg .user .sigil.maxMining::before { background-image: url('images/icons/pickaxe.png'); } .chat-msg .user .sigil.maxBrewing::before { background-image: url('images/brewing/vialofwater_chat.png'); } .chat-msg .user .sigil.maxFarming::before { background-image: url('images/icons/watering-can.png'); } .chat-msg .user .sigil.maxExploring::before { background-image: url('images/icons/archaeology.png'); } .chat-msg .user .sigil.maxCooking::before { background-image: url('images/icons/cookingskill.png'); } .chat-msg .user .sigil.maxMagic::before { background-image: url('images/magic/wizardHatIcon.png'); } .chat-msg .user .sigil.hardcore::before { background-image: url('images/icons/hardcoreIcon.png'); } .chat-msg .user .sigil.coop::before { background-image: url('images/icons/groupTaskBadge5.png'); } .chat-msg .user .sigil.halloween2015::before { background-image: url('images/icons/halloween2015.png'); } .chat-msg .user .sigil.christmas2015::before { background-image: url('images/sigils/christmas2015.png'); } .chat-msg .user .sigil.easter2016::before { background-image: url('images/sigils/easter2016.png'); } .chat-msg .user .sigil.halloween2016::before { background-image: url('images/sigils/halloween2016.png'); } .chat-msg .user .sigil.christmas2016::before { background-image: url('images/sigils/christmas2016.png'); } .chat-msg .user .tag { margin-right: 3px; } .chat-msg .user .tag.chat-tag- { display: none; } .chat-msg .user .tag.chat-tag-donor::before { background-image: url('images/icons/donor-icon.gif'); background-size: 20px 20px; content: ''; display: inline-block; height: 20px; width: 20px; vertical-align: middle; } .chat-msg .user .name { color: rgba(0, 0, 0, 0.7); } .chat-msg[data-type="-1"] .user > *, .chat-msg[data-type="1"] .user > .sigil, .chat-msg[data-type="1"] .user > .tag, .chat-msg[data-type="2"] .user > .sigil, .chat-msg[data-type="2"] .user > .tag, .chat-msg[data-type="3"] .user > * { display: none; } .chat-msg[data-type="3"] .user::before { background: -webkit-linear-gradient(#004747, #00FFFF); background: -o-linear-gradient(#004747, #00FFFF); background: -moz-linear-gradient(#004747, #00FFFF); background: linear-gradient(#004747, #00FFFF); border: 1px solid black; color: white; content: 'Server Message'; font-family: Comic Sans MS, "Times New Roman", Georgia, Serif; font-size: 9pt; padding: 0px 5px 2px 5px; } .chat-msg .msg { word-wrap: break-word; min-width: 0; } #chat-box-area .chat-area-div { width: 100%; height: 130px; display: none; } #chat-box-area .chat-area-div.selected { display: block; } #chat-tabs { background-color: hsla(0, 0%, 90%, 1); display: flex; margin: 10px -10px -10px; flex-wrap: wrap; } #chat-tabs .chat-tab { background-color: gray; border-top: 1px solid black; border-right: 1px solid black; cursor: pointer; display: inline-block; font-weight: normal; padding: 0.3rem .6rem; } #chat-tabs .chat-tab.selected { background-color: silver; border-top-color: silver; } #chat-tabs .chat-tab.filler { background-color: transparent; border-right: 0; box-shadow: inset 5px 5px 5px -5px rgba(0, 0, 0, 0.5); color: transparent; cursor: default; flex-grow: 1; } #chat-tabs .chat-tab::before { content: attr(data-username); } #chat-tabs .chat-tab:not(.filler)[data-username=""]::before { content: 'Server'; } #chat-tabs .chat-tab::after { content: '(' attr(data-new) ')'; font-size: .9rem; font-weight: bold; margin-left: .4rem; } #chat-tabs .chat-tab[data-new="0"]::after { font-weight: normal; } `; document.head.appendChild(style); } function fixChat() { if (!getSetting('useNewChat')) { return; } const chatBoxArea = document.getElementById('chat-box-area'); const toggles = chatBoxArea.querySelectorAll('input[value^="Toggle"]'); for (let i = 0; i < toggles.length; i++) { const toggle = toggles[i]; const parent = toggle.parentNode; const toggleWhat = toggle.value.replace('Toggle ', ''); const id = 'chat-toggle' + toggleWhat; const checkbox = document.createElement('input'); checkbox.type = 'checkbox'; checkbox.id = id; checkbox.checked = ['Autoscroll', 'Timestamps'].includes(toggleWhat); parent.insertBefore(checkbox, toggle); const label = document.createElement('label'); label.htmlFor = id; label.textContent = toggleWhat; parent.insertBefore(label, toggle); toggle.style.display = 'none'; checkbox.addEventListener('change', () => { if (toggleWhat == 'Autoscroll') { window.isAutoScrolling = !window.isAutoScrolling; } else if (toggleWhat == 'Timestamps') { window.showTimestamps = !window.showTimestamps; } else { toggle.click(); } }); } // add chat tabs const chatTabs = document.createElement('div'); chatTabs.id = 'chat-tabs'; chatTabs.addEventListener('click', (event) => { const newTab = event.target; if (!newTab.classList.contains('chat-tab') || newTab.classList.contains('filler')) { return; } const oldTab = chatTabs.querySelector('.chat-tab.selected'); if (newTab == oldTab) { return; } oldTab.classList.remove('selected'); newTab.classList.add('selected'); newTab.dataset.new = 0; changeChatTab(oldTab, newTab); }); chatBoxArea.appendChild(chatTabs); const generalTab = getChatTab(''); generalTab.classList.add('selected'); const generalChatDiv = getChatDiv(''); generalChatDiv.classList.add('selected'); // works only if username length of 1 isn't allowed const fillerTab = getChatTab('f'); fillerTab.classList.add('filler'); const oldSendChat = window.sendChat; window.sendChat = (msg) => { const selectedTab = document.querySelector('.chat-tab.selected'); if (selectedTab.dataset.username != '') { msg = '/pm ' + selectedTab.dataset.username + ' ' + msg; } oldSendChat(msg); }; const oldChatBoxZoom = window.chatBoxZoom; window.chatBoxZoom = (zoom) => { oldChatBoxZoom(zoom); const height = document.getElementById('chat-area-div').style.height; const chatDivs = chatBoxArea.querySelectorAll('div[id^="chat-pm-"]'); for (let i = 0; i < chatDivs.length; i++) { chatDivs[i].style.height = height; } }; chatHistory = JSON.parse(localStorage.getItem(chatHistoryKey) || JSON.stringify(chatHistory)); const lastNotPM = chatHistory.slice(0).reverse().find((d) => { return d.type != 1 && d.type != 2; }); if (lastNotPM && lastNotPM.type != -1) { reloadedChatData.timestamp = (new Date()).getTime(); chatHistory.push(reloadedChatData); } chatHistory.forEach(d => newRefreshChat(d)); // reset the new counter for all tabs const tabs = document.querySelectorAll('.chat-tab'); for (let i = 0; i < tabs.length; i++) { tabs[i].dataset.new = 0; } applyChatStyle(); const oldRefreshChat = window.refreshChat; window.refreshChat = (data) => { data = add2ChatHistory(data); return newRefreshChat(data); }; } /** * fix crafting */ function fixCrafting() { // show selection for the bar type const oldSetConvertBarToXpAgain = window.setConvertBarToXpAgain; window.setConvertBarToXpAgain = (barType, amount) => { oldSetConvertBarToXpAgain(barType, amount); const selector = (bar = '') => `#enchanted-hammer-boxes input[type="image"][src$="${bar}bar.png"]`; const barImages = document.querySelectorAll(selector()); for (let i = 0; i < barImages.length; i++) { barImages[i].style.backgroundColor = ''; } const img = document.querySelector(selector(barType)); img.style.backgroundColor = 'red'; }; } /** * activity log */ const activityLogKey = 'activityLog'; const maxActivityLogLength = 200; let activityLog = []; function add2ActivityLog(cmd) { const split = cmd.split('='); const data = { type: split[0] , msg: split.slice(1).join('=') , read: false }; activityLog.push(data); activityLog = activityLog.slice(-maxActivityLogLength); localStorage.setItem(activityLogKey, JSON.stringify(activityLog)); return data; } function updateActivity(data) { const activityLogEl = document.getElementById('activity-log'); data.read = activityLogEl.classList.contains('open'); } function initActivityLog() { activityLog = JSON.parse(localStorage.getItem(activityLogKey) || JSON.stringify(activityLog)); activityLog.forEach(d => updateActivity(d)); } /** * init */ function init() { console.info('[%s] "DHO Fixed" up and running!', (new Date).toLocaleTimeString()); initObservable(); initSettings(); initActivityLog(); initNotifications(); fixKeyItems(); fixFarming(); fixServerMsg(); applyNewItemStyle(); applyNewKeyItemStyle(); expandEquipment(); highlightRequirements(); fixMarket(); improveLevelCalculation(); fixInventory(); fixMachinery(); fixBrewing(); fixTabs(); hideCraftingRecipes(); hideEquipment(); improveDialogBtns(); hideMaxRecipes(); fixMagic(); fixNumberFormat(); fixLevelBar(); fixMsgBox(); fixChat(); addCoopNotificationBox(); fixCrafting(); } document.addEventListener('DOMContentLoaded', () => { const oldLoadCommand = window.loadCommand; const msgPrefix = 'MESSAGE='; const msgBoxPrefix = 'MSG_BOX='; window.loadCommand = (cmd) => { if (!fullyLoaded && cmd.startsWith('ITEMS_DATA=')) { const ret = oldLoadCommand(cmd); fullyLoaded = true; init(); return ret; } if (!/^(?:ITEMS_DATA|SET_TRADABLE_ITEMS|REFRESH_OFFER_TRADE|REFRESH_CHAT|PLAY_SOUND|COOP|MESSAGE|MSG_BOX)=/.test(cmd)) { console.debug('new cmd:', cmd); } // add some activity log here! if (/^(?:QUESTION|MESSAGE|MSG_BOX)=/.test(cmd)) { const data = add2ActivityLog(cmd); updateActivity(data); } if (cmd === msgBoxPrefix + 'You have completed an achievement') { const msg = cmd.substr(msgBoxPrefix.length); notifyMsg(msg) .catch(() => oldLoadCommand(cmd)) ; return; } else if (cmd.startsWith(msgPrefix)) { const msg = cmd.substr(msgPrefix.length); notifyMsg(msg) .catch(() => oldLoadCommand(cmd)) ; return; } return oldLoadCommand(cmd); }; }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址